From f3e502f0f4bfdc93ac78c345d05a9bdc230f3b75 Mon Sep 17 00:00:00 2001 From: alterNERDtive Date: Thu, 22 Feb 2024 01:09:57 +0100 Subject: [PATCH] feat!: BTRFS snapshot management BREAKING CHANGE: manual setup necessary to work with BTRFS snapshots of the game installation folder. --- README.md | 115 ++++++++++++++++++++++++++++++---------------------- bg3version | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 183 insertions(+), 49 deletions(-) create mode 100755 bg3version diff --git a/README.md b/README.md index 5819998..1ea83af 100644 --- a/README.md +++ b/README.md @@ -7,25 +7,27 @@ manage separate sets of mods in conjunction with a mod manager like [BG3 Mod Manager](https://github.com/LaughingLeader/BG3ModManager) or [Lamp](https://github.com/CHollingworth/Lamp). -Well OK, at this point it’s _kind of_ a mod-manager-like thing for loose files +Well OK, at this point it’s _kind of_ a mod-manager-like thing for loose files mods. Read on :) ## Features * Store an arbitrary amount of profiles. Each of them contains distinct - * "Mods" folders - * "Script Extender" folders - * Mod settings files - * Loose files mods + * "Mods" folders + * "Script Extender" folders + * Mod settings files + * Loose files mods * Create and switch between your profiles via shell script. * Mount loose files mods into your game folder at runtime via overlayfs -* Keep loose files mods separate! No more “which files did that add⁈” when you +* Keep loose files mods separate! No more “which files did that add⁈” when you want to uninstall one of them. +* **(Experimental)** Manage BTRFS snapshots of the game’s installation folder; +keep backups of old patches around! ## Installation -The overlay script depends on `fusermount`/`fuse-overlayfs`, so you will -probably want to install whatever package(s) provide(s) those for your +The overlay script depends on `fusermount`/`fuse-overlayfs`, so you will +probably want to install whatever package(s) provide(s) those for your distribution. Now install the scripts via Basher: @@ -38,8 +40,8 @@ basher install git.alterNERD.tv/alterNERDtive/bg3-mod-profiles or manually: - 1. Clone this repository or grab an archive and extract it somewhere. - 2. Symlink or copy `bg3overlay` and `bg3switch` into your `PATH`. +1. Clone this repository or grab an archive and extract it somewhere. +2. Symlink or copy `bg3overlay` and `bg3switch` into your `PATH`. Next you need to change Baldur’s Gate 3’s launch options in Steam: @@ -51,12 +53,26 @@ Next you need to change Baldur’s Gate 3’s launch options in Steam: You might also have to disable Steam Cloud Sync for the game. -To get started, you need to create at least one mod profile using `bg3switch +To get started, you need to create at least one mod profile using `bg3switch --create PROFILE`. +For the **experimental** snapshot support you will need to make sure beforehand +that your game installation folder is a valid BTRFS snapshot, e.g.: + +```bash +> mv Baldurs\ Gate\ 3 tmpdir +> sudo bfrs sub snap create Baldurs\ Gate\ 3 +> mv tmpdir/* !$ +> rmdir tmpdir +``` + +Set your game to only update on launch, and make sure that you have activated +the snapshot of the current live version before you update your game. Otherwise +you **will** run into issues and have to verify your game files. + ## Configuration -The configuration lives in `$XDG_CONFIG_HOME/bg3-mod-profiles/config` or +The configuration lives in `$XDG_CONFIG_HOME/bg3-mod-profiles/config` or `~/.config/bg3-mod-profiles/config`. | option | default | description | @@ -64,8 +80,8 @@ The configuration lives in `$XDG_CONFIG_HOME/bg3-mod-profiles/config` or | BG3_DATA_DIR | auto-detected for Steam | The game’s “%APPDATA%” folder. | | BG3_INSTALL_DIR | auto-detected for Steam | The game’s installation folder. | -You can also create `bg3overlay.pre` and `bg3overlay.post` files in the -configuration folder. They will be executed before mounting and after unmounting +You can also create `bg3overlay.pre` and `bg3overlay.post` files in the +configuration folder. They will be executed before mounting and after unmounting the overlay, respectively. ## Installing / Updating Mods @@ -81,7 +97,7 @@ the `override` subfolder of your profile. This not only means no accidental mixups between profiles, but also that uninstalling / reinstalling / verifying / updating the game files does not affect your loose files mods in any way. -Alternatively, you can put loose files mods in their own subfolder of +Alternatively, you can put loose files mods in their own subfolder of `profiles//modular-override`: ```bash @@ -92,8 +108,8 @@ Alternatively, you can put loose files mods in their own subfolder of 'Contextual Dialogue Buttons' 'Highlight Prepared Spells' 'Native Camera Tweaks' 'Script Extender' ``` -Priority will be the `override` folder, then the modular overrides in -alphabetical order. I use this e.g. to keep my “Native Camera Mod” configuration +Priority will be the `override` folder, then the modular overrides in +alphabetical order. I use this e.g. to keep my “Native Camera Mod” configuration file in `override` and not have it overwritten by mod updates. Profiles are stored under `%AppData%/Local/Larian Studios` within the game’s @@ -101,90 +117,91 @@ proton prefix. You can easily access it by running `bg3switch --cd`. ## Usage -See [Configuration](#configuration), `bg3switch --help` and `bg3overlay --help`. +See [Configuration](#configuration), `bg3switch --help`, `bg3overlay --help` +and `bg3version --help`. ## How It Works ### Mod Profiles -`bg3switch` creates mod profiles in the `profiles` folder. Each profile consists +`bg3switch` creates mod profiles in the `profiles` folder. Each profile consists of a `Mods` folder, an `override` folder, and a `modsettings.lsx` file. -The `Mods` folder is straight up just what you would usually expect in the +The `Mods` folder is straight up just what you would usually expect in the `Baldur's Gate 3` subfolder and contains all the Mods’ `.pak` files. -The `override` folder contains all lose file mods that you would normally -extract directly into the game’s installation folder. They are overlaid onto it +The `override` folder contains all lose file mods that you would normally +extract directly into the game’s installation folder. They are overlaid onto it at runtime. -The `modular-override` folder contains loose file mods, each in their own -folder. They are _each_ overlaid onto the game’s installation folder at runtime. -The big advantage of using this approach is being able to keep each mod’s files +The `modular-override` folder contains loose file mods, each in their own +folder. They are _each_ overlaid onto the game’s installation folder at runtime. +The big advantage of using this approach is being able to keep each mod’s files separate. Override priority is -1. The `override` folder. Put e.g. your settings file for the native camera mod - here; it will have higher priority than the default file shipped with the mod +1. The `override` folder. Put e.g. your settings file for the native camera mod + here; it will have higher priority than the default file shipped with the mod then. 2. Modular overrides in alphabetical order. -3. Anything you manually change in the game’s installation folder. (Don’t do +3. Anything you manually change in the game’s installation folder. (Don’t do that, please.) -The `modsettings.lsx` file resides inside the same subfolder structure it would -normally (`PlayerProfiles/Public`). This makes zipping up your Mods – including -your modsettings file / load order – easier. Personally I use it for co-op -setups to make updating the mod list easier for the other players. _I_ update +The `modsettings.lsx` file resides inside the same subfolder structure it would +normally (`PlayerProfiles/Public`). This makes zipping up your Mods – including +your modsettings file / load order – easier. Personally I use it for co-op +setups to make updating the mod list easier for the other players. _I_ update everything, I zip it up, they just extract it. -The `Script Extender` folder contains anything you would usually find in -`Baldur's Gate 3/Script Extender`, e.g. the configuration file for [Zerd's Rules +The `Script Extender` folder contains anything you would usually find in +`Baldur's Gate 3/Script Extender`, e.g. the configuration file for [Zerd's Rules As Written (RAW)](https://www.nexusmods.com/baldursgate3/mods/1329) ### Switching Mod Profiles -Switching mod profiles is the most trivial thing here. The `Mods` folder and -`modsettings.lsx` files are symbolically linked from `current` to the `Baldur's +Switching mod profiles is the most trivial thing here. The `Mods` folder and +`modsettings.lsx` files are symbolically linked from `current` to the `Baldur's Gate 3` folder. -`current` is just another symbolic link to the currently active profile. E.g. +`current` is just another symbolic link to the currently active profile. E.g. the link structure for the `Mods` folder looks like this: ```bash > stat -c "%N" -- Baldur\'s\ Gate\ 3/Mods "Baldur's Gate 3/Mods" -> '../current/Mods' -> stat -c "%N" -- current +> stat -c "%N" -- current 'current' -> './profiles/solo' ``` `Baldur's Gate 3/Mods` → `current/Mods` → `profile//Mods` -When switching mod profiles, the `current` symbolic link is updated to point to +When switching mod profiles, the `current` symbolic link is updated to point to the freshly activated / created profile. That’s it! -When you create your first profile, your current configuration is moved to the +When you create your first profile, your current configuration is moved to the profile and the symbolic links are set up automatically. ### Loading Loose File Mods at Runtime -`bg3overlay --enable` will mount an overlayfs to your game’s installation -folder. The folder itself will be temporarily renamed to `bg3base` in order to -be able to mount the overlay into `Baldurs Gate 3`, where Steam expects the +`bg3overlay --enable` will mount an overlayfs to your game’s installation +folder. The folder itself will be temporarily renamed to `bg3base` in order to +be able to mount the overlay into `Baldurs Gate 3`, where Steam expects the game. -The working directory and newly created files (the “upper” directory in +The working directory and newly created files (the “upper” directory in overlayfs terms) reside in `/tmp/bg3/`, which should usually be a RAM disk. -The benefit is that log files and crash dumps will not clutter your `override` -folder. The downside (or additional benefit) is that the files will disappear on +The benefit is that log files and crash dumps will not clutter your `override` +folder. The downside (or additional benefit) is that the files will disappear on a reboot. -`bg3overlay --disable` will unmount the overlay and rename the game’s +`bg3overlay --disable` will unmount the overlay and rename the game’s installation folder back to `Baldurs Gate 3`. ## Troubleshooting -### The game doesn’t start after changing the launch options. +### The game doesn’t start after changing the launch options Double check the launch options match the example. Run `bg3overlay --enable` manually and see if it works. @@ -192,6 +209,6 @@ manually and see if it works. If yes, run `bg3overlay --disable` and start looking elsewhere, because it’s not my fault :) -If not, feel free to [file an +If not, feel free to [file an issue](https://github.com/alterNERDtive/bg3-mod-profiles/issues) and be sure to attach the output. diff --git a/bg3version b/bg3version new file mode 100755 index 0000000..4ca78dd --- /dev/null +++ b/bg3version @@ -0,0 +1,117 @@ +#!/usr/bin/env bash +die() { + echo "${1}" + exit 1 +} + +activate() { + local version="${1:-current}" + check "${_folder}" "bg3.${version}" + + echo "Removing current game folder …" + sudo btrfs sub del "${_folder}" + echo "Creating snapshot of \"bg3.${version}\" …" + sudo btrfs sub snap "bg3.${version}" "${_folder}" +} + +check() { + local dir + for dir in "$@"; do + if ! [ -d "${dir}" ] || [ $(stat --format=%i "${dir}") -ne 256 ] || [ $(stat -f --format=%T "${dir}") != "btrfs" ]; then + die "Folder \"${dir}\" is not a BTRFS snapshot, aborting …" + fi + done +} + +create() { + check "${_folder}" + local version="${1}" + + if [ -z "${version}" ]; then + die "No VERSION given, aborting …" + fi + + echo "Creating snapshot \"bg3.${version}\" …" + sudo btrfs sub snap "${_folder}" "bg3.${version}" +} + +delete() { + local version=$1 + + if [ -z "${version}" ]; then + die "No VERSION given, aborting …" + fi + + check "bg3.${version}" + + echo "Removing snapshot \"bg3.${version}\" …" + sudo btrfs sub del "bg3.${version}" +} + +list() { + ls | tr " " "\n" | grep "bg3." +} + +usage() { + cat <". +EOF +} + +source "$(dirname $(realpath $0))/util/folders.sh" + +CONFIG_FILE="${CONFIG_FILE:-${XDG_CONFIG_HOME:-$HOME/.config}/bg3-mod-profiles/config}" +if [ -f "${CONFIG_FILE}"]; then + while read line; do declare "$line"; done <"${CONFIG_FILE}" +fi + +if [ -z "${BG3_DATA_DIR}" ] || [ -z "${BG3_INSTALL_DIR}" ]; then + _library="$(getBg3Library)" + [ $? -eq 1 ] && echo "Steam library folder for Baldur’s Gate 3 not found! Exiting …" && exit 1 + BG3_DATA_DIR="${_library}/steamapps/compatdata/1086940/pfx/drive_c/users/steamuser/AppData/Local/Larian Studios/Baldur's Gate 3" + BG3_INSTALL_DIR="${_library}/steamapps/common/Baldurs Gate 3" +fi + +cd "$(dirname "${BG3_INSTALL_DIR}")" + +_library="$(getBg3Library)" +[ $? -eq 1 ] && echo "Steam library folder for Baldur’s Gate 3 not found! Exiting …" && exit 1 +_common="${_library}/steamapps/common" +_folder="$(getBg3Folder ${_library})" +[ $? -eq 1 ] && echo "Steam installation folder for Baldur’s Gate 3 not found! Exiting …" && exit 1 + +cd "${_common}" + +case $1 in +--create | --snap) + create "$2" + ;; +--delete) + delete "$2" + ;; +--help) + usage + ;; +--list) + list + ;; +--version) + activate "$2" + ;; +"") + list + ;; +*) + activate "$1" + ;; +esac