Added patches for Blues Brothers 2000

Added patches for Blues Brothers 2000 made by meauxdal.
This commit is contained in:
Rikard Bengtsson
2025-12-29 16:46:51 +01:00
parent 194703143f
commit 35813d730b
2 changed files with 192 additions and 1 deletions

View File

@@ -858,7 +858,8 @@ f25ad011df54065768c3a3cabf41d4b3 ntsc|cic6102 # V64Jr Backup Tool by RedBoX (V0.
; Source: https://misterfpga.org/viewtopic.php?t=8078
a5ee8a6c34863e3d0eb8c06ae8668b30 pal|cic7101|rpak|p4:080d0000|p5:5f81bb9d|p1cab0:84020000 # Batman Beyond - Return of the Joker [Batman of the Future - Return of the Joker] (Europe) (En,Fr,De)
a08676124b326b1035b202c83a97468f ntsc|cic6102|rpak|p5:6a8d2e60|pb45f:8c010000 # Batman Beyond - Return of the Joker (USA)
997fd8f79cd6f3cd1c1c1fd21e358717 ntsc|cic6102|cpak|rpak|p4:42008400|p5:2b1d7193|p2778:6120e700 # Blues Brothers 2000 (USA)
31b4a8ed52b48e756b344c9f22736e50 pal|cic7101|cpak|rpak|p16:0140705c75713f86|p43841:e72061|p44549:372b37 # Blues Brothers 2000 (Europe) (En,Fr,De,It,Nl,Es)
997fd8f79cd6f3cd1c1c1fd21e358717 ntsc|cic6102|cpak|rpak|p17:60704ce7364a4b|p40417:e72061|p41125:372b37 # Blues Brothers 2000 (USA)
baaf237e71aa7526c9b2f01c08b68a53 pal|cic7105|flash128k|rpak|p4:85035a65|p5:a06de792|p28043:1f006315|p28047:1b008314|p2804a:1800c314|p2804d:15004004|p2804f:1300401c|p28056:0c006014|p2805c:03006014|p2805f:03004010 # Jet Force Gemini (Europe) (En,Fr,De,Es)
ca28a3645fc7ad969ebd75c5d6506e7a ntsc|cic6105|flash128k|rpak|p4:9a005af5|p5:6f0b382b|p27f57:1f006315|p27f5b:1b008314|p27f5e:1800c314|p27f61:15004004|p27f63:1300401c|p27f6a:0c006014|p27f70:03006014|p27f73:03004010 # Jet Force Gemini [Star Twins] (Japan)
772cc6eab2620d2d3cdc17bbc26c4f68 ntsc|cic6105|flash128k|rpak|p4:853f30b5|p5:2e13d8f9|p27fa7:1f006315|p27fab:1b008314|p27fae:1800c314|p27faf:021b0500|p27fb1:15004004|p27fb3:1300401c|p27fba:0c006014|p27fc0:03006014|p27fc3:03004010 # Jet Force Gemini (USA)

190
patchgen.py Normal file
View File

@@ -0,0 +1,190 @@
import sys
import os
import hashlib
import struct
def decode_bps_number(data, offset):
"""Decodes a variable-length integer from BPS data."""
result = 0
shift = 1
while True:
byte = data[offset]
offset += 1
result += (byte & 0x7F) * shift
if byte & 0x80:
return result, offset
shift <<= 7
result += shift
def apply_bps_patch(source_data, patch_data):
"""Applies a BPS patch to source_data and returns the target bytearray."""
if patch_data[:4] != b'BPS1':
raise ValueError("Invalid BPS header.")
offset = 4
source_len, offset = decode_bps_number(patch_data, offset)
target_len, offset = decode_bps_number(patch_data, offset)
metadata_len, offset = decode_bps_number(patch_data, offset)
offset += metadata_len # Skip metadata
target_data = bytearray(target_len)
output_offset = 0
source_offset = 0
target_read_offset = 0
while output_offset < target_len:
action_code, offset = decode_bps_number(patch_data, offset)
action = action_code & 3
length = (action_code >> 2) + 1
if action == 0: # SourceRead
# Copy bytes from source ROM to target ROM
chunk = source_data[output_offset : output_offset + length]
target_data[output_offset : output_offset + length] = chunk
output_offset += length
elif action == 1: # TargetRead
# Read bytes directly from the patch file
chunk = patch_data[offset : offset + length]
target_data[output_offset : output_offset + length] = chunk
output_offset += length
offset += length
elif action == 2: # SourceCopy
# Copy data from anywhere in source
data, offset = decode_bps_number(patch_data, offset)
# Map encoded int to positive/negative shift
shift = (data >> 1)
if data & 1:
shift = -shift
source_offset += shift
chunk = source_data[source_offset : source_offset + length]
target_data[output_offset : output_offset + length] = chunk
output_offset += length
source_offset += length
elif action == 3: # TargetCopy
# Copy data from already written parts of target
data, offset = decode_bps_number(patch_data, offset)
shift = (data >> 1)
if data & 1:
shift = -shift
target_read_offset += shift
# Since we might copy from overlapping regions, we do it byte by byte
# or careful slicing. Python slices create copies, so safe for simple overlaps.
# But specific run-length patterns might require loops.
for i in range(length):
target_data[output_offset + i] = target_data[target_read_offset + i]
output_offset += length
target_read_offset += length
return target_data
def get_xor_diff(source, target, max_diff=256):
"""Compares two bytearrays and returns XOR deltas."""
# Handle size mismatches by padding the shorter one with nulls for comparison
max_len = max(len(source), len(target))
diffs = []
diff_count = 0
i = 0
while i < max_len:
b_src = source[i] if i < len(source) else 0
b_tgt = target[i] if i < len(target) else 0
if b_src != b_tgt:
xor_val = b_src ^ b_tgt
# Start a contiguous block
block_start = i
block_vals = [xor_val]
diff_count += 1
# Look ahead for contiguous differences
j = i + 1
while j < max_len:
b_src_next = source[j] if j < len(source) else 0
b_tgt_next = target[j] if j < len(target) else 0
if b_src_next != b_tgt_next:
block_vals.append(b_src_next ^ b_tgt_next)
diff_count += 1
if diff_count > max_diff:
raise ValueError(f"Too many differences (>{max_diff}). Aborting.")
j += 1
else:
break
# Store the block
diffs.append((block_start, block_vals))
i = j
else:
i += 1
return diffs
def main():
if len(sys.argv) < 3:
print("Usage: python xordiff.py <ROM.z64> <PATCH.bps or MOD.z64>")
sys.exit(1)
rom_path = sys.argv[1]
file2_path = sys.argv[2]
if not os.path.exists(rom_path) or not os.path.exists(file2_path):
print("Error: Input files not found.")
sys.exit(1)
# 1. Load Original ROM
with open(rom_path, 'rb') as f:
source_bytes = bytearray(f.read())
# 2. Calculate MD5 of Original ROM
rom_md5 = hashlib.md5(source_bytes).hexdigest()
# 3. Load File 2 (Check if BPS or ROM)
with open(file2_path, 'rb') as f:
file2_bytes = bytearray(f.read())
target_bytes = None
# Check for BPS Header "BPS1"
if file2_bytes[:4] == b'BPS1':
try:
target_bytes = apply_bps_patch(source_bytes, file2_bytes)
except Exception as e:
print(f"Error applying BPS patch: {e}")
sys.exit(1)
else:
# Assume it's a pre-patched ROM
target_bytes = file2_bytes
# 4. Calculate Differences
try:
diffs = get_xor_diff(source_bytes, target_bytes, max_diff=1024)
except ValueError as e:
print(f"Error: {e}")
sys.exit(1)
# 5. Format Output
# Format: pOFFSET:HEXVAL
output_parts = []
for offset, vals in diffs:
hex_str = "".join(f"{b:02x}" for b in vals)
output_parts.append(f"p{offset}:{hex_str}")
diff_str = "|".join(output_parts)
filename = os.path.basename(rom_path)
print(f"{rom_md5} {diff_str} # {filename}")
if __name__ == "__main__":
main()