Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions .github/workflows/python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,14 @@ jobs:
with:
python-version: "3.9"

- name: Install Python packages
run: python -m pip install --upgrade pip build
- name: Install core Python packages
run: python -m pip install --upgrade pip build

- name: Install source python packages
run: python -m pip install -e ".[tooling]"

- name: Fetch the corresponding assembly patches
run: python pull-assembly-patches.py

- name: build
# Ideally, we'd have PYTHONWARNINGS=error here, but
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,7 @@ Running from source:
- Unix-based: `source ./venv/bin/activate`
- Install the project as editable: `pip install -e .`
- Run: `python -m mars_patcher`

Before running the patcher, you want to initialize the required assembly patches into `src/mars_patcher/data/patches/mf_u/asm`.
The easiest way to do that is by running `python pull-assembly-patches.py`, which will fetch the patches from the correct release.
However for development purposes, you may want to create the assembly patches yourself manually and then copy them to that directory.
41 changes: 41 additions & 0 deletions pull-assembly-patches.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import shutil
import tempfile
import urllib.request
from pathlib import Path
from zipfile import ZipFile

import requests

VERSION = "0.1.8"
ASSET_NAME = "Randomizer.Patches.zip"
DESTINATION_ASSEMBLY_PATH = (
Path(__file__)
.parent.resolve()
.joinpath("src", "mars_patcher", "data", "patches", "mf_u", "asm")
)


release_url = f"https://api.github.com/repos/MetroidAdvRandomizerSystem/mars-fusion-asm/releases/tags/{VERSION}"
print(f"Fetching {release_url}")
response = requests.get(release_url).json()


for asset in response["assets"]:
if asset["name"] != ASSET_NAME:
continue

print("Correct release found, initalizing download")
with tempfile.TemporaryDirectory() as temp_ref:
temp_dir = Path(temp_ref)
temp_file = temp_dir.joinpath("cache.zip")
urllib.request.urlretrieve(asset["browser_download_url"], temp_file)
with ZipFile(temp_file, "r") as zip_ref:
zip_ref.extractall(temp_dir)

for file in list(temp_dir.joinpath("bin").iterdir()):
print(f"Moving {file.name}")
shutil.move(file, DESTINATION_ASSEMBLY_PATH.joinpath(file.name))

break

print("Done.")
4 changes: 4 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,17 @@ dependencies = [
]

[project.optional-dependencies]
tooling = [
"requests",
]
test = [
"pytest",
"pytest-cov",
"pytest-mock",
]
typing = [
"mypy",
"types-requests",
"pre-commit"
]

Expand Down
31 changes: 23 additions & 8 deletions src/mars_patcher/misc_patches.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,37 @@
import mars_patcher.constants.game_data as gd
from mars_patcher.constants.reserved_space import ReservedConstants
from mars_patcher.data import get_data_path
from mars_patcher.patching import IpsDecoder
from mars_patcher.patching import BpsDecoder, IpsDecoder
from mars_patcher.rom import Rom


def get_patch_path(rom: Rom, filename: str) -> str:
def _get_patch_path(rom: Rom, subfolder: str, filename: str) -> str:
dir = f"{rom.game.name}_{rom.region.name}".lower()
return get_data_path("patches", dir, filename)
return get_data_path("patches", dir, subfolder, filename)


def apply_patch_in_data_path(rom: Rom, patch_name: str) -> None:
path = get_patch_path(rom, patch_name)
def _internal_apply_ips_patch(rom: Rom, patch_name: str, subfolder: str) -> None:
path = _get_patch_path(rom, subfolder, patch_name)
with open(path, "rb") as f:
patch = f.read()
IpsDecoder().apply_patch(patch, rom.data)


def apply_patch_in_data_path(rom: Rom, patch_name: str) -> None:
_internal_apply_ips_patch(rom, patch_name, "")


def apply_patch_in_asm_path(rom: Rom, patch_name: str) -> None:
_internal_apply_ips_patch(rom, patch_name, "asm")


def apply_base_patch(rom: Rom) -> None:
path = _get_patch_path(rom, "asm", "m4rs.bps")
with open(path, "rb") as f:
patch = f.read()
rom.data = BpsDecoder().apply_patch(patch, rom.data)


def disable_demos(rom: Rom) -> None:
# TODO: Move to patch
# b 0x8087460
Expand Down Expand Up @@ -61,15 +76,15 @@ def change_missile_limit(rom: Rom, limit: int) -> None:


def apply_unexplored_map(rom: Rom) -> None:
apply_patch_in_data_path(rom, "unhidden_map.ips")
apply_patch_in_asm_path(rom, "unhidden_map.ips")


def apply_pbs_without_bombs(rom: Rom) -> None:
apply_patch_in_data_path(rom, "bombless_pbs.ips")
apply_patch_in_asm_path(rom, "bombless_pbs.ips")


def apply_anti_softlock_edits(rom: Rom) -> None:
apply_patch_in_data_path(rom, "anti_softlock.ips")
apply_patch_in_asm_path(rom, "anti_softlock.ips")


def apply_reveal_hidden_tiles(rom: Rom) -> None:
Expand Down
5 changes: 5 additions & 0 deletions src/mars_patcher/patcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from mars_patcher.minimap import apply_minimap_edits
from mars_patcher.misc_patches import (
apply_anti_softlock_edits,
apply_base_patch,
apply_pbs_without_bombs,
apply_reveal_hidden_tiles,
apply_unexplored_map,
Expand Down Expand Up @@ -66,6 +67,10 @@ def patch(
# Load input rom
rom = Rom(input_path)

# Apply base asm patch first
apply_base_patch(rom)

# Softlock edits need to be done early to prevent later patches messing things up.
if patch_data.get("AntiSoftlockRoomEdits"):
apply_anti_softlock_edits(rom)

Expand Down