Skip to content

Instantly share code, notes, and snippets.

@dotaxis
Last active February 4, 2026 15:44
Show Gist options
  • Select an option

  • Save dotaxis/1ad1c64baa7ad9c1dabcb255ea6257ae to your computer and use it in GitHub Desktop.

Select an option

Save dotaxis/1ad1c64baa7ad9c1dabcb255ea6257ae to your computer and use it in GitHub Desktop.
Memoria Patcher for Linux
#!/bin/bash
echo "WARNING!"
echo "A Steam or GOG (Heroic) copy of FINAL FANTASY IX needs to be installed on this device!"
echo
echo "If you face issues with this installer, please pay us a visit on Discord:"
echo "https://discord.gg/tsunamods-community-277610501721030656"
echo "You can find me (Dot) in the #ff9-linux channel!"
echo
if ! awk --version 2>/dev/null | grep -q "GNU Awk"; then
echo "Error: GNU Awk (gawk) is not the active awk. Please install it before running this script again."
exit 1
fi
echo "Press Enter to continue."
read
getSteamLibrary() {
local app_id="$1"
local steam_dir=""
if [[ -f "${HOME}/.steam/root/steamapps/libraryfolders.vdf" ]]; then
steam_dir="${HOME}/.steam/root"
elif [[ -f "${HOME}/.local/share/Steam/steamapps/libraryfolders.vdf" ]]; then
steam_dir="${HOME}/.local/share/Steam"
elif [[ -f "${HOME}/.var/app/com.valvesoftware.Steam/.steam/root/steamapps/libraryfolders.vdf" ]]; then
steam_dir="${HOME}/.var/app/com.valvesoftware.Steam/.steam/root"
else
echo ""
return 1
fi
local path=$(
awk -v app_id="$app_id" '
/^[[:space:]]*"[0-9]+"$/ {
in_block = 1;
block = $0;
next;
}
in_block {
block = block "\n" $0;
if ($0 ~ /^\s*}/) {
in_block = 0;
if (block ~ app_id) {
match(block, /"path"\s+"([^"]+)"/, arr);
print arr[1];
exit;
}
}
}
' "${steam_dir}/steamapps/libraryfolders.vdf"
)
echo "$path"
}
getHeroicLibrary() {
local app_id=$1
local config_dir=""
if [[ -d "${HOME}/.config/heroic" ]]; then
config_dir="${HOME}/.config/heroic"
elif [[ -d "${HOME}/.var/app/com.heroicgameslauncher.hgl/config/heroic" ]]; then
config_dir="${HOME}/.var/app/com.heroicgameslauncher.hgl/config/heroic"
elif [[ -d "/var/lib/flatpak/app/com.heroicgameslauncher.hgl/current/active/files/config/heroic" ]]; then
config_dir="/var/lib/flatpak/app/com.heroicgameslauncher.hgl/current/active/files/config/heroic"
else
echo "||"
return 1
fi
local runner=$(
awk '
/"bin"[[:space:]]*:[[:space:]]*"/ {
match($0, /"bin"[[:space:]]*:[[:space:]]*"([^"]*)"/, arr)
print arr[1]
exit
}
' "${config_dir}/GamesConfig/${app_id}.json"
)
local prefix=$(
awk '
/"winePrefix"[[:space:]]*:[[:space:]]*"/ {
match($0, /"winePrefix"[[:space:]]*:[[:space:]]*"([^"]*)"/, arr)
print arr[1]
exit
}
' "${config_dir}/GamesConfig/${app_id}.json"
)
local path=$(
awk -v game_id="$app_id" '
/"install_path"[[:space:]]*:[[:space:]]*"/ {
match($0, /"install_path"[[:space:]]*:[[:space:]]*"([^"]*)"/, path)
install = path[1]
}
/"appName"[[:space:]]*:[[:space:]]*"/ {
match($0, /"appName"[[:space:]]*:[[:space:]]*"([^"]*)"/, app)
if (app[1] == game_id) {
print install
exit
}
}
' "${config_dir}/gog_store/installed.json"
)
echo "$runner|$prefix|$path"
}
downloadDependency() {
local REPO=$1
local FILTER=$2
local RETURN_VARIABLE=$3
local RELEASE_URL=$(
curl -s https://api.github.com/repos/"$REPO"/releases/latest \
| grep "browser_download_url.$FILTER" \
| head -1 \
| cut -d : -f 2,3 \
| tr -d \")
local FILENAME="$(basename "$RELEASE_URL")"
if [ -f "$FILENAME" ]; then
echo "$FILENAME is ready to be installed."
else
echo "$FILENAME not found. Downloading..."
curl -#SL -o $FILENAME $RELEASE_URL
fi
eval "${RETURN_VARIABLE}=\"$FILENAME\""
}
IS_STEAM=false
IS_HEROIC=false
# Check for FF9
echo -n "Checking if FF9 is installed in Heroic Games Launcher... "
RESULT=$(getHeroicLibrary 1375008492)
RUNNER=$(echo "$RESULT" | cut -d'|' -f1)
PREFIX=$(echo "$RESULT" | cut -d'|' -f2)
GAMEPATH=$(echo "$RESULT" | cut -d'|' -f3)
if [[ -f "$RUNNER" && -d "$PREFIX" && -d "$GAMEPATH" ]]; then
echo "OK!"
echo "Found FF9 at $GAMEPATH!"
IS_HEROIC=true
else
echo -e "\nNot found! Checking for Steam installation... "
if ! pgrep steam > /dev/null; then nohup steam &> /dev/null; fi
while ! pgrep steam > /dev/null; do sleep 1; done
sleep 5
GAMEPATH=$(LIBRARY=$(getSteamLibrary 377840) && [ -n "$LIBRARY" ] && echo "$LIBRARY/steamapps/common/FINAL FANTASY IX/")
if [ -d "$GAMEPATH" ]; then
echo "OK!"
echo "Found FF9 at $GAMEPATH!"
IS_STEAM=true
else
echo "Error: Couldn't find a Steam or Heroic installation for FF9. Exiting."
exit 1
fi
fi
echo
echo "Downloading Memoria Installer"
downloadDependency "Albeoris/Memoria" "*.exe" MEMORIA
echo
if [[ $IS_STEAM == true ]]; then
if ! command -v protontricks-launch &>/dev/null; then
echo "Installing Protontricks flatpak..."
flatpak remote-add --user --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
flatpak --user install com.github.Matoking.protontricks -y
flatpak override --user --filesystem=host com.github.Matoking.protontricks
protontricks-launch() {
flatpak run --command=protontricks-launch com.github.Matoking.protontricks "$@"
}
else
echo "Using native Protontricks."
fi
echo
echo "Running Memoria Installer"
protontricks-launch --no-bwrap \
--appid 377840 "$MEMORIA" "Z:$GAMEPATH"
elif [[ $IS_HEROIC == true ]]; then
echo "Running Memoria Installer"
STEAM_COMPAT_DATA_PATH="$PREFIX" \
"$RUNNER" runinprefix \
"$MEMORIA" "Z:$GAMEPATH"
else
echo "Error: Couldn't find a Steam or Heroic installation for FF9. Exiting"
exit 1
fi
sleep 5
if [ -f "$MEMORIA" ]; then
cp "$MEMORIA" "$GAMEPATH/"
echo "Cleaning up installer: $MEMORIA"
rm "$MEMORIA"
else
echo "Installer already removed: $MEMORIA"
fi
echo "Installation complete."
@zephyroths
Copy link

if your steam is a flatpak package you need to change the following lines:
${HOME}/.steam/root/steamapps/libraryfolders.vdf to "${HOME}/.steam/data/Steam/steamapps/libraryfolders.vdf"
$HOME/.steam/steam/steamapps/libraryfolders.vdf to $HOME/.steam/data/Steam/steamapps/libraryfolders.vdf
$HOME/.steam/steam/config/libraryfolders.vdf to $HOME/.steam/data/Steam/config/libraryfolders.vdf

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment