diff --git a/games/README.md b/games/README.md index 8774b48..4e997ef 100644 --- a/games/README.md +++ b/games/README.md @@ -1,5 +1,67 @@ # Save game management +Collection of scripts in order to move all (as much as i can) save of my +video games in one remote place (eg. Nextcloud directory,…). Then a symbolic +link should take place of the directories. This allows me to : +* Have save in the cloud for all games ! +* Easily find my save in one place. +* Easily backup everything (one `tar` to backup them all). +* Synchronize save between Linux hosts. +* Restore save if anything happens to my game computer. +* Everything that Nextcloud allows me to do (access from anywhere, share,…). + +## How-to use + +Run the main script to automatically run the 3 others : + +``` sh +~/repos/gardouille.scripts/games/save.game +``` + +This will run : +- **save.game.steam** : Try to move or symlink saves from 3 Steam's directories, +userdata, common and compatdata. +- **save.game.xdg** : Try to move or symlink save that respect the XDG +specifications (~/.config and ~/.local/share). +- **save.game.home** : Try to move or symlink other saves that the devs have +seen fit to place anywhere else… + +## Currently managed games + +* Borderlands 2 − https://pcgamingwiki.com/wiki/Borderlands_2 +* Broforce − https://pcgamingwiki.com/wiki/Broforce +* Butcher − https://pcgamingwiki.com/wiki/Butcher +* Capsized − https://pcgamingwiki.com/wiki/Capsized +* Castle Crashers − https://pcgamingwiki.com/wiki/Castle_Crashers +* Crypt of the Necrodancer − https://pcgamingwiki.com/wiki/Crypt_of_the_Necrodancer +* Door Kickers: Action Squad − https://pcgamingwiki.com/wiki/Door_Kickers:_Action_Squad +* Duck Game − https://pcgamingwiki.com/wiki/Duck_Game +* Full Metal Furies − https://pcgamingwiki.com/wiki/Full_Metal_Furies +* HotlineMiami − https://pcgamingwiki.com/wiki/Hotline_Miami +* Jump Gunners − https://pcgamingwiki.com/wiki/Jump_Gunners +* Mercenary Kings − https://pcgamingwiki.com/wiki/Mercenary_Kings +* Metal Slug X − https://pcgamingwiki.com/wiki/Metal_Slug_X +* Never Alone − https://pcgamingwiki.com/wiki/Never_Alone +* Nuclear Throne − https://pcgamingwiki.com/wiki/Nuclear_Throne +* Overcooked! 2 − https://pcgamingwiki.com/wiki/Overcooked!_2 +* PixelJunk Shooter − https://pcgamingwiki.com/wiki/PixelJunk_Shooter +* Portal 2 − https://pcgamingwiki.com/wiki/Portal_2 (solo only, multiplayer is on Steam cloud) +* Prey (2017) − https://pcgamingwiki.com/wiki/Prey_(2017) (don't work yet) +* Risk of Rain − https://pcgamingwiki.com/wiki/Risk_of_Rain +* Saints Row IV − https://pcgamingwiki.com/wiki/Saints_Row_IV +* Saints Row: The Third − https://pcgamingwiki.com/wiki/Saints_Row:_The_Third +* Shift Happens − https://pcgamingwiki.com/wiki/Shift_Happens (don't work yet) +* South Park: The Stick of Truth − https://pcgamingwiki.com/wiki/South_Park:_The_Stick_of_Truth +* Steam Screenshots − https://steamdb.info/app/760/ +* The Dishwasher: Vampire Smile − https://pcgamingwiki.com/wiki/The_Dishwasher:_Vampire_Smile +* The Swapper − https://pcgamingwiki.com/wiki/The_Swapper +* TowerFall Ascension − https://pcgamingwiki.com/wiki/TowerFall_Ascension (not managed cause no substree, check $XDG_DATA_HOME) +* Tricky Towers − https://pcgamingwiki.com/wiki/Tricky_Towers +* Trine 2 Complete Story − https://pcgamingwiki.com/wiki/Trine_2 +* Trine Enchanted Edition − https://pcgamingwiki.com/wiki/Trine_Enchanted_Edition + +## How-to add new save + Sources of informations : * Various informations (save path,…) : https://pcgamingwiki.com/wiki * Match steam id and game name : https://steamdb.info/ diff --git a/games/save.game b/games/save.game new file mode 100755 index 0000000..472f9c1 --- /dev/null +++ b/games/save.game @@ -0,0 +1,31 @@ +#!/bin/sh + +# Purpose {{{ +## Run all other save.game.* scripts. +# }}} + +# Vars {{{ +script_wd=$(dirname -- "${0}") + +## List of scripts +home_script="save.game.home" +steam_script="save.game.steam" +xdg_script="save.game.xdg" + +# }}} + +# For all scripts, try to run +for script in "${home_script}" "${steam_script}" "${xdg_script}"; do + + ## If the script doesn't exist + if [ ! -f "${script_wd}/${script}" ]; then + printf '\e[1;35m%-6s\e[m\n' "Loop script − ${script} doesn't seems to exist. Abort." + exit 1 + fi + + ## Run the script + sh "${script_wd}/${script}" + +done + +exit 0 diff --git a/games/save.game.home b/games/save.game.home new file mode 100755 index 0000000..94481ed --- /dev/null +++ b/games/save.game.home @@ -0,0 +1,130 @@ +#!/bin/sh + +# Purpose {{{ +## Try to centralize all game's save that doesn't respect XDG specifications +## or Steam directories 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 homedir (or subdir) +## to a remote directory (Nextcloud, remote mount,…). +## Then create a symlink in home directory 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 home directory (or subdir). +## For other paths (Steam,…) check other scripts. +# }}} + +# Vars {{{ +debug=0 + +## List of video games for homedir {{{ +### Give the relative path from homedir. +### Separate each path with "%" to be able to manage white space, eg : +### .mygame%.first-subtree/save of GAMEX +### ^ +### Overcooked! 2 − Team17 − https://pcgamingwiki.com/wiki/Overcooked!_2 +### Trine Enchanted Edition − .frozenbyte − https://pcgamingwiki.com/wiki/Trine_Enchanted_Edition +### Trine 2 Complete Story − .frozenbyte − https://pcgamingwiki.com/wiki/Trine_2 +games_list="Team17%.frozenbyte" +## }}} + +remote_dir="${HOME}/Nextcloud/games/linux.sgl.script" +home_remote_dir="${remote_dir}/home" + +# }}} + +# 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="${home_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="${home_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." + else + [ "${debug}" -eq "0" ] && printf '\e[1;35m%-6s\e[m\n' "DEBUG : Symlink game — ${_game_name} doesn't have remote data." + 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 +## }}} + +# }}} + + [ "${debug}" -eq "0" ] && printf '\e[1;35m%-6s\e[m\n' "DEBUG : Run save game script for Homedir." + +# Manage save game from homedir {{{ +## Set "%" as field separator +IFS="%" +for game_path in ${games_list}; do + local_game_path="${HOME}/${game_path}" + local_game_path_type="$(ls -ld "${local_game_path}" | sed 's/\(^.\).*/\1/')" + + game_name="$(basename "${game_path}")" + game_dir="$(dirname "${game_path}")" + + 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 : Homedir for loop — The data of ${game_path} are already symlinked to ${link_name} . Skip." + ;; + ## Data is still a directory + "directory"|"d") + move_game_dir "${game_name}" "${game_dir}" + ;; + ## Data doesn't exist + "cannot") + [ "${debug}" -eq "0" ] && printf '\e[1;35m%-6s\e[m\n' "DEBUG : Homedir for loop — The data of ${game_path} − ${local_game_path} doesn't exist. Skip." + symlink_game_dir "${game_name}" "${game_dir}" + ;; + ## Data can't be managed + *) + printf '\e[1;35m%-6s\e[m\n' "Data of ${game_path} (Homedir) − ${local_game_path} are not managed. Type: ${local_game_path_type}. Abort" + exit 3 + ;; + esac + +done +# }}} + +exit 0 diff --git a/games/save.game.steam b/games/save.game.steam index d3f862f..3fd3662 100755 --- a/games/save.game.steam +++ b/games/save.game.steam @@ -157,6 +157,8 @@ done # }}} + [ "${debug}" -eq "0" ] && printf '\e[1;35m%-6s\e[m\n' "DEBUG : Run save game script for Steam." + # Manage Steam userdata save game {{{ for game_id in ${steam_userdata_games}; do local_game_path="${HOME}/${steam_userdata}/${game_id}" diff --git a/games/save.game.xdg b/games/save.game.xdg index 31c04a4..39d7162 100755 --- a/games/save.game.xdg +++ b/games/save.game.xdg @@ -15,8 +15,8 @@ ## 2. If a directory doesn't exist, check if a remote one is ## available and symlink it. ## -## KISS : Only manage save directories from Steam userdata. For other -## paths (Steam,…) check other scripts. +## KISS : Only manage save directories from XDG. For other paths (Steam, home,…) +## check other scripts. # }}} # Vars {{{ @@ -29,7 +29,7 @@ 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 − THD − https://pcgamingwiki.com/wiki/Butcher +### Butcher − unity3d − https://pcgamingwiki.com/wiki/Butcher ### Full Metal Furies − Cellar Door Games − https://pcgamingwiki.com/wiki/Full_Metal_Furies ### Jump Gunners − unity3d − https://pcgamingwiki.com/wiki/Jump_Gunners ### Never Alone − unity3d − https://pcgamingwiki.com/wiki/Never_Alone @@ -38,8 +38,8 @@ xdg_config="$(printf "%s" "${XDG_CONFIG_HOME}" | sed -e "s;${HOME}/;;")" ### Overcooked! 2 − unity3d − https://pcgamingwiki.com/wiki/Overcooked!_2 ### Risk of Rain − Risk_of_Rain − https://pcgamingwiki.com/wiki/Risk_of_Rain ### The Dishwasher: Vampire Smile − VampireSmile − https://pcgamingwiki.com/wiki/The_Dishwasher:_Vampire_Smile -### Tricky Towers − WeirdBeard − https://pcgamingwiki.com/wiki/Tricky_Towers -xdg_config_games="unity3d%THD%Cellar Door Games%nuclearthrone%Risk_of_Rain%VampireSmile%WeirdBeard" +### Tricky Towers − unity3d − https://pcgamingwiki.com/wiki/Tricky_Towers +xdg_config_games="unity3d%Cellar Door Games%nuclearthrone%Risk_of_Rain%VampireSmile" ### }}} ## }}} @@ -49,6 +49,7 @@ xdg_data="$(printf "%s" "${XDG_DATA_HOME}" | sed -e "s;${HOME}/;;")" ### List of video games for XDG DATA {{{ ### Borderlands 2 − aspyr-media − https://pcgamingwiki.com/wiki/Borderlands_2 +### Capsized − Capsized − https://pcgamingwiki.com/wiki/Capsized ### 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 @@ -56,8 +57,9 @@ xdg_data="$(printf "%s" "${XDG_DATA_HOME}" | sed -e "s;${HOME}/;;")" ### 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 -data_games="aspyr-media%Cellar Door Games%HotlineMiami%Tribute Games%PJShooter%vpltd%VampireSmile%TowerFall" +xdg_data_games="aspyr-media%Capsized%Cellar Door Games%HotlineMiami%Tribute Games%PJShooter%vpltd%VampireSmile%Facepalm Games%TowerFall" ### }}} ## }}} @@ -133,19 +135,23 @@ 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}" | sed 's/\(^.\).*/\1/')" case ${local_game_path_type} in ## Data is already a symlink - "symbolic") + "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") + "directory"|"d") move_game_dir "${game_name}" "${xdg_config}" ;; ## Data doesn't exist @@ -155,10 +161,43 @@ for game_name in ${xdg_config_games}; do ;; ## Data can't be managed *) - printf '\e[1;35m%-6s\e[m\n' "Data of ${game_name} (userdata) − ${local_game_path} are not managed. Type: ${local_game_path_type}. Abort" + 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 ;; 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}" | 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 + *) + 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 + ;; + esac + +done +# }}} + +exit 0 diff --git a/games/xdg_data_tree.sample b/games/xdg_data_tree.sample index fba246c..831138b 100644 --- a/games/xdg_data_tree.sample +++ b/games/xdg_data_tree.sample @@ -17,6 +17,9 @@ │   ├── save0005.sav.bak │   ├── save0008.sav │   └── save0008.sav.bak +├── Capsized +│   ├── Config.cfg +│   └── Logs ├── Cellar Door Games │   └── Full Metal Furies │   └── Saves @@ -24,6 +27,21 @@ │   ├── profileData1.brdat │   ├── profileData1.brdat_BACKUP │   └── TEMPprofileData1.brdat +├── Facepalm Games +│   └── The Swapper 1000 +│   ├── CommonSettings.ini +│   ├── CommonSettings.pro +│   ├── CommonSettings.pro.old +│   ├── controller_mappings_user.txt +│   ├── darker.ini +│   ├── darker.ini.old +│   ├── darker.pro +│   ├── darker.pro.old +│   ├── Default.ini +│   ├── gardouill.ini +│   ├── gardouill.pro +│   ├── gardouill.pro.old +│   └── TrueEngineLog.txt ├── HotlineMiami │   ├── debug.log │   ├── hotline.cfg