#!/bin/sh # Purpose {{{ ## Try to centralize all game's save that respect XDG specifications in order to : ## easily backup all save ## easily restore it ## be able to access it from anywhere ## … all you can do with a Nextcloud (share, versionning,…) ## ## 1. Move save directories of a list of known games from XDG's ## directories to a remote directory (Nextcloud, remote mount,…). ## Then create a symlink in XDG directories to the remote game ## directory. ## ## 2. If a directory doesn't exist, check if a remote one is ## available and symlink it. ## ## KISS : Only manage save directories from XDG. For other paths (Steam, home,…) ## check other scripts. # }}} # Vars {{{ debug=1 ## XDG config {{{ XDG_CONFIG_HOME="${HOME}/.config" xdg_config="$(printf "%s" "${XDG_CONFIG_HOME}" | sed -e "s;${HOME}/;;")" ### List of video games for XDG CONFIG {{{ ### Broforce − unity3d − https://pcgamingwiki.com/wiki/Broforce ### Butcher − unity3d − https://pcgamingwiki.com/wiki/Butcher ### Children of Morta − unity3d − https://www.pcgamingwiki.com/wiki/Children_of_Morta ### Darkwood − unity3d − https://pcgamingwiki.com/wiki/Darkwood ### Deadbolt − deadbolt_game − https://www.pcgamingwiki.com/wiki/Deadbolt ### Enter the Gungeon − unity3d − https://www.pcgamingwiki.com/wiki/Enter_the_Gungeon ### Fez − FEZ − https://www.pcgamingwiki.com/wiki/Fez ### Full Metal Furies − Cellar Door Games − https://pcgamingwiki.com/wiki/Full_Metal_Furies ### Galak-Z The Void − unity3d − https://www.pcgamingwiki.com/wiki/Galak-Z:_The_Dimensional ### Hyper Light Drifter − HyperLightDrifter − https://www.pcgamingwiki.com/wiki/Hyper_Light_Drifter ### Jump Gunners − unity3d − https://pcgamingwiki.com/wiki/Jump_Gunners ### Never Alone − unity3d − https://pcgamingwiki.com/wiki/Never_Alone ### Never Alone (bis) − unity3d − https://pcgamingwiki.com/wiki/Never_Alone ### Nuclear Throne − nuclearthrone − https://pcgamingwiki.com/wiki/Nuclear_Throne ### Overcooked! 2 − unity3d − https://pcgamingwiki.com/wiki/Overcooked!_2 ### Pikuniku − unity3d − https://www.pcgamingwiki.com/wiki/Pikuniku ### Risk of Rain − Risk_of_Rain − https://pcgamingwiki.com/wiki/Risk_of_Rain ### Streets of Rogue − unity3d − https://www.pcgamingwiki.com/wiki/Streets_of_Rogue ### The Dishwasher: Vampire Smile − VampireSmile − https://pcgamingwiki.com/wiki/The_Dishwasher:_Vampire_Smile ### Tricky Towers − unity3d − https://pcgamingwiki.com/wiki/Tricky_Towers ### Ultimate Chicken Horse − unity3d − https://www.pcgamingwiki.com/wiki/Ultimate_Chicken_Horse ### Valheim − unity3d − https://www.pcgamingwiki.com/wiki/Valheim ### Wizard of Legend − unity3d − https://www.pcgamingwiki.com/wiki/Wizard_of_Legend xdg_config_games="unity3d%Cellar Door Games%deadbolt_game%FEZ%HyperLightDrifter%nuclearthrone%Risk_of_Rain%VampireSmile" ### }}} ## }}} ## XDG data {{{ XDG_DATA_HOME="${HOME}/.local/share" xdg_data="$(printf "%s" "${XDG_DATA_HOME}" | sed -e "s;${HOME}/;;")" ### List of video games for XDG DATA {{{ ### Alien: Isolation − feral-interactive − https://www.pcgamingwiki.com/wiki/Alien:_Isolation ### Borderlands: The Pre-Sequel − aspyr-media − https://www.pcgamingwiki.com/wiki/Borderlands:_The_Pre-Sequel ### Borderlands 2 − aspyr-media − https://pcgamingwiki.com/wiki/Borderlands_2 ### Capsized − Capsized − https://pcgamingwiki.com/wiki/Capsized ### Celeste − Celeste − https://www.pcgamingwiki.com/wiki/Celeste ### Dust: An Elysian Tail − DustAET − https://www.pcgamingwiki.com/wiki/Dust:_An_Elysian_Tail ### Full Metal Furies − Cellar Door Games − https://pcgamingwiki.com/wiki/Full_Metal_Furies ### HotlineMiami − HotlineMiami − https://pcgamingwiki.com/wiki/Hotline_Miami ### Mercenary Kings − Tribute Games − https://pcgamingwiki.com/wiki/Mercenary_Kings ### Monaco − Pocketwatch Games − https://www.pcgamingwiki.com/wiki/Monaco:_What%27s_Yours_Is_Mine ### Move or Die − love − https://www.pcgamingwiki.com/wiki/Move_or_Die#Configuration_file.28s.29_location ### N++ − Metanet − https://www.pcgamingwiki.com/wiki/N%2B%2B ### PixelJunk Shooter − PJShooter − https://pcgamingwiki.com/wiki/PixelJunk_Shooter ### Saints Row: The Third − vpltd − https://pcgamingwiki.com/wiki/Saints_Row:_The_Third ### Saints Row IV − vpltd − https://pcgamingwiki.com/wiki/Saints_Row_IV ### The Dishwasher: Vampire Smile − VampireSmile − https://pcgamingwiki.com/wiki/The_Dishwasher:_Vampire_Smile ### The Swapper − Facepalm Games − https://pcgamingwiki.com/wiki/The_Swapper ### TowerFall Ascension − TowerFall − https://pcgamingwiki.com/wiki/TowerFall_Ascension xdg_data_games="feral-interactive%aspyr-media%Capsized%Celeste%DustAET%Cellar Door Games%HotlineMiami%Tribute Games%Pocketwatch Games%love%Metanet%PJShooter%vpltd%VampireSmile%Facepalm Games%TowerFall" ### }}} ## }}} remote_dir="${HOME}/Nextcloud/games/linux.sgl.script" # }}} # Functions {{{ # Move one save game dir {{{ move_game_dir() { _game_name="${1}" _game_dir="${2}" _local_game_path="${HOME}/${_game_dir}/${_game_name}" _remote_game_path="${remote_dir}/${_game_dir}/${_game_name}" ## If a remote directory doesn't already exists for this game if [ ! -d "${_remote_game_path}" ]; then ### Ensure to create tree directories on remote storage mkdir -p -- "$(dirname "${_remote_game_path}")" ### Move data to remote storage mv -- "${_local_game_path}" "${_remote_game_path}" [ "${debug}" -eq "0" ] && printf '\e[1;35m%-6s\e[m\n' "DEBUG : Move game − The data of ${_game_name} − ${_local_game_path} moved to remote storage." ### Then ask to create a symbolic link to local storage symlink_game_dir "${_game_name}" "${_game_dir}" else printf '\e[1;35m%-6s\e[m\n' "Move game − ${_game_name} already have data on remote storage : ${_remote_game_path}. Abort to avoid to override data." exit 5 fi } # }}} # Symlink one save game dir from remote to local {{{ symlink_game_dir() { _game_name="${1}" _game_dir="${2}" _local_game_path="${HOME}/${_game_dir}/${_game_name}" _remote_game_path="${remote_dir}/${_game_dir}/${_game_name}" if [ -d "${_remote_game_path}" ]; then ln -s -- "${_remote_game_path}" "${_local_game_path}" [ "${debug}" -eq "0" ] && printf '\e[1;35m%-6s\e[m\n' "DEBUG : Symlink game — Symlink remote data of ${_game_name} to local storage." return 0 else [ "${debug}" -eq "0" ] && printf '\e[1;35m%-6s\e[m\n' "DEBUG : Symlink game — ${_game_name} doesn't have remote data." return 1 fi } # }}} # }}} # Tests {{{ ## Ensure remote dir exist {{{ if [ ! -d "${remote_dir}" ]; then printf '\e[1;35m%-6s\e[m\n' "The directory for save game doesn't exists : ${remote_dir}" exit 1 fi ## }}} ## Ensure XDG directories exist {{{ for xdg_dir in "${xdg_config}" "${xdg_data}"; do local_xdg_path="${HOME}/${xdg_dir}" if [ ! -d "${local_xdg_path}" ]; then printf '\e[1;35m%-6s\e[m\n' "The XDG directory − ${xdg_dir} doesn't exists yet… Should it must be create (for restoration,…) [Y/n] ?" read -r create_local_xdg if [ "${create_local_xdg}" = "" ] || [ "${create_local_xdg}" = "Y" ] || [ "${create_local_xdg}" = "y" ]; then mkdir -p -- "${local_xdg_path}" else printf '\e[1;35m%-6s\e[m\n' "XDG directory (${xdg_dir}) doesn't exists, abort script." exit 2 fi fi done ## }}} # }}} [ "${debug}" -eq "0" ] && printf '\e[1;35m%-6s\e[m\n' "DEBUG : Run save game script for XDG." # Manage XDG config save game {{{ ## Set "%" as field separator IFS="%" for game_name in ${xdg_config_games}; do local_game_path="${HOME}/${xdg_config}/${game_name}" local_game_path_type="$(ls -ld "${local_game_path}" 2> /dev/null | sed 's/\(^.\).*/\1/')" case ${local_game_path_type} in ## Data is already a symlink "symbolic"|"l") link_name="$(file "${local_game_path}" | sed 's;.* symbolic link to \(.*\);\1;')" [ "${debug}" -eq "0" ] && printf '\e[1;35m%-6s\e[m\n' "DEBUG : XDG CONFIG for loop — The data of ${game_name} are already symlinked to ${link_name} . Skip." ;; ## Data is still a directory "directory"|"d") move_game_dir "${game_name}" "${xdg_config}" ;; ## Data doesn't exist "cannot") [ "${debug}" -eq "0" ] && printf '\e[1;35m%-6s\e[m\n' "DEBUG : XDG CONFIG for loop — The data of ${game_name} − ${local_game_path} doesn't exist. Skip." symlink_game_dir "${game_name}" "${xdg_config}" ;; ## Data can't be managed *) ### Still try to symlink the savegame directory symlink_game_dir "${game_name}" "${xdg_config}" ### If the symlink failed if [ "${?}" != 0 ]; then printf '\e[1;35m%-6s\e[m\n' "Data of ${game_name} (XDG CONFIG) − ${local_game_path} are not managed. Type: ${local_game_path_type}. Abort" exit 3 fi ;; esac done # }}} # Manage XDG data save game {{{ ## Set "%" as field separator IFS="%" for game_name in ${xdg_data_games}; do local_game_path="${HOME}/${xdg_data}/${game_name}" local_game_path_type="$(ls -ld "${local_game_path}" 2> /dev/null | sed 's/\(^.\).*/\1/')" case ${local_game_path_type} in ## Data is already a symlink "symbolic"|"l") link_name="$(file "${local_game_path}" | sed 's;.* symbolic link to \(.*\);\1;')" [ "${debug}" -eq "0" ] && printf '\e[1;35m%-6s\e[m\n' "DEBUG : XDG DATA for loop — The data of ${game_name} are already symlinked to ${link_name} . Skip." ;; ## Data is still a directory "directory"|"d") move_game_dir "${game_name}" "${xdg_data}" ;; ## Data doesn't exist "cannot") [ "${debug}" -eq "0" ] && printf '\e[1;35m%-6s\e[m\n' "DEBUG : XDG DATA for loop — The data of ${game_name} − ${local_game_path} doesn't exist. Skip." symlink_game_dir "${game_name}" "${xdg_data}" ;; ## Data can't be managed *) ### Still try to symlink the savegame directory symlink_game_dir "${game_name}" "${xdg_data}" ### If the symlink failed if [ "${?}" != 0 ]; then printf '\e[1;35m%-6s\e[m\n' "Data of ${game_name} (XDG DATA) − ${local_game_path} are not managed. Type: ${local_game_path_type}. Abort" exit 3 fi ;; esac done # }}} exit 0