Script: SoftPatchSelector
-
Use it on your own risk
Story behind this script:
I was trying out a lot of Super Metroid hacks lately and it was very tedious to manually patch the Rom and to have a good looking gamelist. It is impossible to find good images for some hacks.
I knew that RetroArch has a way to patch on the fly. But then I had to manage the files manually again. Like renaming/storing the patches/saves.
So I wrote a simple script which could be used to select a patch from a menu and did all the managing for me, but it was only capable of handling a single game. It was obviously possible to have different versions of that script for anyone game, but since I wanted to clean up my gamelist, I wrote a new one (twice, because I accidentally deleted it once) which can handle all the things. And I thought maybe it would be worth to shared it. So, here it is.Features and Issues:
It uses dialog, so it looks the same as the other RetroPie scripts. Its main menu has only two options.
Select Patch: Pretty much was it sounds like. It will let you browse through the systems/games to select a patch.
When a patch is selected the following happens. If there is a save file (srm only, no save states) it will be stored, the selected patch will be copied over and if there is a stored save file for the selected hack, it will also be restored.
Then the script ends and you can just start the Rom the normal way. If everything went correctly, there should be a notification that the patch was applied.
If you want to remove any patch, select "Default (Unpatched)" from the patch list. That is a blank file which will be created when using the "Prepare ROM" option from the menu.
I had some trouble to cancel/go back the patch selection, so I simply disabled it. The menu will show the currently active patch in the menu, so if you accidentally got in the menu, just select the same patch and nothing will change.Prepare ROM: This option uses the dialog file browser to select a ROM.
Sadly it is very bad and requires a Keyboard to actually use. The Space key is needed to select folders/files, and, at least on my GPI CASE 2, it is not mapped to one of the buttons. Using SSH would also be an option to use it. Maybe I will replace it with something better later, but I don't think it's necessary.
Note: Apparently SPACE (and other buttons) are actually mapped to the controller. And it works fine for me now. So I don't have to replace the file selector.Anyway, I highly suggest using this option at least once. Because it will create a folder structure (similar to the default rom folder of RetroPie) with separate folders for saves and patches. And it will create the blank Default patch, which can be used to disable any other patches.
Suggested Setup:
Save the code below in a file without spaces and the suffix .sh
Example:SoftPatchSelector.sh
Create a new folder in home/pi/RetroPie/retropiemenu called SoftPatchSelector
Put the script in that folder.
Restart EmulationStation and it should be available in the RetroPie menu.
Of course any name for the script/folder should be fine. Why I suggest putting it in a subfolder in the retropiemenu directory, is simple. It is available without adding/changing anything else and the subfolder makes it cleaner. If you can live with two extra folders directly in retropiemenu (not in EmulationStation) you can just skip creating them folder and put the script straight into retropiemenu.
Like I said, you should run the script at least once to prepare a rom and the entire folder structure.
Which looks like this PATCHES/System/Game/AnyPatch.ips and SAVES/System/Game/AnyPatch.srm
It is very important that the GAME folder has the exact same name as the rom (without the suffix)! If you're doing this all manually, don't forget to create an empty file called Default (Unpatched).ips in the game folder.
When the folder structure is done, just put your patches in the corresponding game folder. I don't think that there are any restrictions (besides the ones from RetroArch itself) regarding the file names, but I suggest to have a consistent naming convention. I prefer to simply rename a patch to actually patch and gather metadata/images.Well, guess that's it. Hopefully someone finds this useful. I'm certainly no master in scripting and there probably are some issues I missed. Especially since I had to write it twice.
#!/bin/bash SCRIPTNAME="$(basename "${0}" | sed 's/\(.*\)\..*/\1/')" SCRIPTDIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) # Set directorys SOURCE="${SCRIPTDIR}/PATCHES" ROMDIR="${HOME}/RetroPie/roms" #### Enable file reading with spaces SAVEIFS=$IFS IFS=$(echo -en "\n\b") ###### Functions #### Main Menu function do_menu(){ while true; do DOPTIO=(1 "Select Patch" - "\Z1-- -- -- \Zn" 2 "Prepare new ROM") DMENU=$(dialog --clear --title ${SCRIPTNAME} --backtitle ${SCRIPTNAME} --no-collapse --colors --stdout --cancel-label Exit --menu "\nSelect option:" 15 60 18 "${DOPTIO[@]}"); RC=$? case $RC in 1) exit;; 255) exit 1;; esac #0=Ok,1=Cancel,2=Help,3=Extra,4=ItemHelp,255=Escape case $DMENU in 1) timeline;; 2) newrom;; *) ;; esac done } #### Set and get stuff in this order. function timeline(){ #Select System MENUTITLE="Select System:" selector; SYSTEM="$( basename ${PICKED} )" #Select Game MENUTITLE="Select Game:" SOURCE="${SCRIPTDIR}/PATCHES/${SYSTEM}"; selector; GAME="$( basename ${PICKED} )" #Select Patch pre_patch MENUTITLE="Select Patch: [ Current: ${ACTIVEHACK} ]" SOURCE="${SCRIPTDIR}/PATCHES/${SYSTEM}/${GAME}"; selector; PATCH="$( basename ${PICKED} )"; PATCHEXT="${PATCH##*.}" post_patch dialog --clear --title ${SCRIPTNAME} --backtitle ${SCRIPTNAME} --no-collapse --colors --stdout --msgbox "\n Installed: ${ACTIVEHACK}\n\n for: ${GAME}" 9 75 # Restore default file handling. IFS=$SAVEIFS exit } #### Selector function selector(){ let i=0; W=() for ITEM in "${SOURCE}"/*; do let i=$i+1; W+=($i "$( basename ${ITEM} | sed 's/\(.*\)\..*/\1/')") done SELECTION=$(dialog --clear --title ${SCRIPTNAME} --backtitle ${SCRIPTNAME} --no-collapse --colors --stdout --no-cancel --menu "\n${MENUTITLE}" 24 60 15 "${W[@]}") PICKED=$( readlink -f ${SOURCE}/$(ls -1 "${SOURCE}/" | sed -n "`echo "${SELECTION} p" | sed 's/ //'`") ) } #### Pre Patch selection. Get aktive patch and store current save file. function pre_patch(){ # Get aktive patch if [[ -f "${SCRIPTDIR}/SAVES/${SYSTEM}/${GAME}/${GAME}.active" ]]; then ACTIVEHACK="$( tail -1 "${SCRIPTDIR}/SAVES/${SYSTEM}/${GAME}/${GAME}.active" )" else ACTIVEHACK="Default (Unpatched)" fi # Store current save file if [[ -f "${ROMDIR}/${SYSTEM}/${GAME}.srm" ]]; then if [[ "${ROMDIR}/${SYSTEM}/${GAME}.srm" -nt "${SCRIPTDIR}/SAVES/${SYSTEM}/${GAME}/${ACTIVEHACK}.srm" ]]; then cp -f "${ROMDIR}/${SYSTEM}/${GAME}.srm" "${SCRIPTDIR}/SAVES/${SYSTEM}/${GAME}/${ACTIVEHACK}.srm" fi fi } #### Post Patch selection. Set and copy new patch, restore Save if available. function post_patch(){ # Save new selection ACTIVEHACK="$( basename ${PATCH} | sed 's/\(.*\)\..*/\1/' )" echo -n "${ACTIVEHACK}" > "${SCRIPTDIR}/SAVES/${SYSTEM}/${GAME}/${GAME}.active" # Copy new patch cp -f "${PICKED}" "${ROMDIR}/${SYSTEM}/${GAME}.${PATCHEXT}" # Restore Save if available if [[ -f "${SCRIPTDIR}/SAVES/${SYSTEM}/${GAME}/${ACTIVEHACK}.srm" ]]; then cp -f "${SCRIPTDIR}/SAVES/${SYSTEM}/${GAME}/${ACTIVEHACK}.srm" "${ROMDIR}/${SYSTEM}/${GAME}.srm" fi } #### Select new ROM and create folders and default patch function newrom(){ while true; do DFILE=$(dialog --clear --title ${SCRIPTNAME} --backtitle ${SCRIPTNAME} --no-collapse --colors --stdout --fselect "${ROMDIR}/" 10 80 --stdout); RC=$? case $RC in 1) break;; 255) exit 1;; esac if [ -f "${DFILE}" ]; then DIR="$( dirname "${DFILE}" )" SYSTEM="$( basename "${DIR}" )" GAME="$( basename "${DFILE%.*}" )" if [ ! -f "${SCRIPTDIR}/PATCHES/${SYSTEM}/${GAME}/Default (Unpatched).ips" ]; then mkdir ${SCRIPTDIR}/{SAVES,PATCHES}/${SYSTEM}/${GAME} -p touch "${SCRIPTDIR}/PATCHES/${SYSTEM}/${GAME}/Default (Unpatched).ips" dialog --clear --title ${SCRIPTNAME} --backtitle ${SCRIPTNAME} --no-collapse --colors --stdout --msgbox "\n Directory and Default Patch created for:\n\n ${GAME}" 9 60 break fi fi done } do_menu IFS=$SAVEIFS
-
Update:
- Added confirmation text when Preparing a Rom and it goes back to the main menu afterwards.
- Added confirmation text when a Patch is selected.
- Some code clean up.
-
@EctoOne Sounds very interesting, thank you man!! by the way, which other games/patches do you suggest to use with your script?
-
@NIGHTKILLER05 I would say any game that has a lot of patches would be best. Maybe some of the Mario or Pokémon games. If it is just a single patch you want to use for a game, it's probably not worth it. Especially if it's a translation or a color patch for a GameBoy title or something like that.
Contributions to the project are always appreciated, so if you would like to support us with a donation you can do so here.
Hosting provided by Mythic-Beasts. See the Hosting Information page for more information.