Skip to content

Instantly share code, notes, and snippets.

@ashquarky
Last active March 12, 2023 09:46
Show Gist options
  • Save ashquarky/b032b50501b23d0787712c5296449f4f to your computer and use it in GitHub Desktop.
Save ashquarky/b032b50501b23d0787712c5296449f4f to your computer and use it in GitHub Desktop.
Barebones Riivolution ISO patcher (for Mario Kart Midnight). Must patch .dol seperately.
# to patch:
# wit x RMCP01.wbfs kart/
# python midnight.py riivolution/Mario_Kart_Midnight_1.2.xml P kart/DATA/files/
# cp ISO\ Patcher/Midnight/iso/P/main.dol kart/data/sys/ # borrowed from v1.1 ISO patcher
# nano kart/DATA/setup.txt # change "!part-id = RMCP01" -> "part-id = RMCPMN"
# wit cp --source kart/ RMCPMN.wbfs
import argparse
import os
import shutil
import xml.etree.ElementTree as ET
# Args stuff
def path_is_dir(string):
if os.path.isdir(string):
return string
else:
raise NotADirectoryError(string)
def path_is_file(string):
if os.path.isfile(string):
return string
else:
raise FileNotFoundError(string)
def arg_is_region(string):
if len(string) == 1 and string.isupper():
return string
else:
raise Exception(string)
parser = argparse.ArgumentParser("riivolution_wbfs")
parser.add_argument("xml", help="Path to the main riivolution xml", type=path_is_file)
parser.add_argument("region", help="game's region (P, J, E)", type=arg_is_region)
# parser.add_argument("config", help="Path to the config xml", type=path_is_file)
parser.add_argument("fst", help="Path of an unpacked FST to use", type=path_is_dir)
args = parser.parse_args()
external_path = os.path.realpath(os.curdir)
disc_path = os.path.realpath(args.fst)
# My Stuff (other non-recursive folders) not implemented
blocklist = []
rv_xml = ET.parse(args.xml)
for patch in rv_xml.findall("patch"):
for action in patch:
kind = action.tag
if kind == "file" or kind == "folder":
# don't support non-recursive things yet
if action.attrib.get("recursive", "true") == "false":
blocklist.append(action.attrib["external"])
continue
if "disc" not in action.attrib or action.attrib["external"] in blocklist:
print("WARN: skipping", action.attrib, "(not implemented)")
continue
# strip off the leading / to make os.path.join work.
# presumably huge compatibility problems with some mods but
# I couldn't find a better answer
external = action.attrib["external"][1:].replace("{$__region}", args.region)
disc = action.attrib["disc"][1:]
source = os.path.join(external_path, external)
dest = os.path.join(disc_path, disc)
if not os.path.exists(source):
print("WARN: skipping", external, "(not found)")
continue
print(external, "->", disc)
if kind == "folder":
shutil.copytree(source, dest, dirs_exist_ok=True)
else:
shutil.copy2(source, dest)
elif kind == "memory":
print("WARN: memory patch not supported:", action.attrib)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment