Last active
February 23, 2026 04:51
-
-
Save i30817/afe1e0a4e05cce53a13d8ef65c4de384 to your computer and use it in GitHub Desktop.
create rxdelta files from as hack dir to a nointro update dir and move the hacks there (overwriting the old matched rom) to make rhdndat-rn recognize some older softpatch romhacks as the newer nointro roms in new dats
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| display_help() { | |
| cat << EOF | |
| $(basename "$0") - NES Game Patch Processor & Merger | |
| _ | |
| Usage: $(basename "$0") <patch_dir> <clean_zip_dir> <destination_dir> | |
| A utility to identify differences between NES files and compressed | |
| clean ROMs, generating delta patches for modified versions. | |
| It is useful when no-intro updates because the generated rxdelta | |
| makes my other tool rhdndat-rn consider the rom file the same as | |
| the clean rom, because it can be restored with the patch. | |
| I recommend rom hacks be in a different base directory as the clean | |
| roms to make updating easier, so this tool does not support that. | |
| ARGUMENTS: | |
| patch_dir Directory containing subfolders with .nes and .bps/.ips files. | |
| clean_zip_dir Directory containing clean ROMs in .zip format (named matching subfolders). | |
| destination_dir Target directory where successfully processed game folders will be moved. | |
| WHAT THIS SCRIPT DOES: | |
| 1. Validates that all three paths are unique, accessible, and exist. | |
| 2. Scans <patch_dir> for game subfolders with bps or ips files. | |
| 3. Locates a matching ZIP file in <clean_zip_dir> for each subfolder. | |
| 4. Compares the existing .nes file against the clean ZIP content. | |
| 5. If they differ, it uses 'xdelta3' to create a new .rxdelta patch. | |
| 6. Moves matched folders (from 3.) to the <destination_dir>. | |
| 7. Prints a summary of processed games and the total number of patches created. | |
| OPTIONS: | |
| -h, --help Display this help message and exit. | |
| EOF | |
| exit 0 | |
| } | |
| # Check for help flags before running the main logic | |
| if [[ "$1" == "-h" || "$1" == "--help" ]]; then | |
| display_help | |
| fi | |
| process_and_merge_games() { | |
| local patch_root=$(realpath -m "$1") | |
| local clean_root=$(realpath -m "$2") | |
| local dest_root=$(realpath -m "$3") | |
| if [[ ! -d "$patch_root" || ! -d "$clean_root" || ! -d "$dest_root" ]]; then | |
| echo "Error: One or more directories do not exist." | |
| return 1 | |
| fi | |
| if [[ ! -r "$patch_root" || ! -r "$clean_root" || ! -w "$dest_root" ]]; then | |
| echo "Error: Insufficient permissions (Read required for sources, Write for destination)." | |
| return 1 | |
| fi | |
| if [[ "$patch_root" == "$clean_root" ]] || [[ "$patch_root" == "$dest_root" ]] || [[ "$clean_root" == "$dest_root" ]]; then | |
| echo "Error: Source and destination directories must be unique." | |
| return 1 | |
| fi | |
| local processed_dirs=() | |
| local patch_count=0 | |
| for sub_path in "$patch_root"/*; do | |
| [[ -d "$sub_path" ]] || continue | |
| local dir_name=$(basename "$sub_path") | |
| local patch_subdir="$patch_root/$dir_name" | |
| local clean_subzip="$clean_root/$dir_name".zip | |
| # Check if the same named zip exists | |
| if [[ -f "$clean_subzip" ]]; then | |
| local patch_exists=false | |
| # Identify target games via patch files (.bps or .ips) | |
| for patch in "$patch_subdir"/*.bps "$patch_subdir"/*.ips; do | |
| [[ -e "$patch" ]] || continue | |
| patch_exists=true | |
| local base_name=$(basename "${patch%.*}") | |
| local nes_file="$patch_subdir/$base_name.nes" | |
| # If both files exist, we process them | |
| if [[ -f "$nes_file" ]]; then | |
| if ! cmp -s "$nes_file" <(zcat "$clean_subzip"); then | |
| # Files differ: Create the .rxdelta patch | |
| xdelta3 -f -e -s "$nes_file" <(zcat "$clean_subzip") "$patch_subdir/$base_name.rxdelta" ((patch_count++)) | |
| fi | |
| fi | |
| done if [ "$patch_exists" = "true" ]; then processed_dirs+=("$patch_subdir") | |
| if [ "$patch_exists" = "true" ]; then | |
| processed_dirs+=("$patch_subdir") | |
| fi | |
| fi | |
| done | |
| if [[ ${#processed_dirs[@]} -gt 0 ]]; then | |
| mv -t "$dest_root" "${processed_dirs[@]}" | |
| fi | |
| echo -e "\n--- Process Summary ---" | |
| if [[ ${#processed_dirs[@]} -gt 0 ]]; then | |
| echo -e "Processed List:" | |
| for d in "${processed_dirs[@]}"; do echo " - $(basename "$d")"; done | |
| fi | |
| echo "Total .rxdelta patches generated: $patch_count" | |
| } | |
| process_and_merge_games "$1" "$2" "$3" | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment