RetroPie forum home
    • Recent
    • Tags
    • Popular
    • Home
    • Docs
    • Register
    • Login

    Script: SoftPatchSelector

    Scheduled Pinned Locked Moved Ideas and Development
    scriptrom hacktoolgamelistclean
    4 Posts 2 Posters 479 Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • E
      EctoOne
      last edited by EctoOne

      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
      
      
      1 Reply Last reply Reply Quote 1
      • E
        EctoOne
        last edited by

        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.
        N 1 Reply Last reply Reply Quote 1
        • N
          NIGHTKILLER05 @EctoOne
          last edited by

          @EctoOne Sounds very interesting, thank you man!! by the way, which other games/patches do you suggest to use with your script?

          E 1 Reply Last reply Reply Quote 0
          • E
            EctoOne @NIGHTKILLER05
            last edited by

            @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.

            1 Reply Last reply Reply Quote 1
            • First post
              Last post

            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.