mirror of
https://github.com/gensokyo-zone/infrastructure.git
synced 2026-02-09 04:19:19 -08:00
fix(steam): better data management and setup
This commit is contained in:
parent
81bd1a1a15
commit
475273692d
5 changed files with 822 additions and 284 deletions
|
|
@ -5,12 +5,25 @@
|
|||
pkgs,
|
||||
...
|
||||
}: let
|
||||
inherit (inputs.self.lib.lib) userIs;
|
||||
inherit (inputs.self.lib.lib) mkWinPath userIs;
|
||||
inherit (lib.options) mkOption mkEnableOption;
|
||||
inherit (lib.modules) mkIf mkMerge mkDefault mkOptionDefault;
|
||||
inherit (lib.attrsets) filterAttrs mapAttrsToList listToAttrs nameValuePair;
|
||||
inherit (lib.lists) singleton;
|
||||
inherit (lib.strings) removePrefix;
|
||||
cfg = config.services.steam.accountSwitch;
|
||||
machineModule = { config, name, ... }: {
|
||||
options = with lib.types; {
|
||||
name = mkOption {
|
||||
type = str;
|
||||
default = name;
|
||||
};
|
||||
owner = mkOption {
|
||||
type = str;
|
||||
default = "admin";
|
||||
};
|
||||
};
|
||||
};
|
||||
in {
|
||||
options.services.steam.accountSwitch = with lib.types; {
|
||||
enable = mkEnableOption "steam-account-switch";
|
||||
|
|
@ -52,6 +65,10 @@ in {
|
|||
users = mkOption {
|
||||
type = listOf str;
|
||||
};
|
||||
machines = mkOption {
|
||||
type = attrsOf (submodule machineModule);
|
||||
default = { };
|
||||
};
|
||||
};
|
||||
|
||||
config = let
|
||||
|
|
@ -76,8 +93,7 @@ in {
|
|||
inherit owner;
|
||||
inherit (shared) group mode;
|
||||
};
|
||||
setupFiles =
|
||||
singleton {
|
||||
setupFiles = singleton {
|
||||
${cfg.rootDir} = toplevel;
|
||||
${cfg.binDir} = toplevel;
|
||||
${cfg.binDir + "/users"} = shared;
|
||||
|
|
@ -85,14 +101,15 @@ in {
|
|||
${cfg.sharedDataDir} = shared;
|
||||
${cfg.workingDir} = toplevel;
|
||||
${cfg.sharedWorkingDir} = shared;
|
||||
}
|
||||
++ map (owner: {
|
||||
} ++ map (owner: {
|
||||
${cfg.dataDir + "/${owner}"} = personal owner;
|
||||
${cfg.workingDir + "/${owner}"} = personal owner;
|
||||
})
|
||||
cfg.users;
|
||||
userBinFiles = listToAttrs (map (user:
|
||||
nameValuePair "${cfg.binDir}/users/${user}.bat" {
|
||||
}) cfg.users
|
||||
++ mapAttrsToList (_: machine: {
|
||||
${cfg.dataDir + "/${machine.name}"} = personal machine.owner;
|
||||
${cfg.workingDir + "/${machine.name}"} = personal machine.owner;
|
||||
}) cfg.machines;
|
||||
userBinFiles = listToAttrs (map (user: nameValuePair "${cfg.binDir}/users/${user}.bat" {
|
||||
inherit (toplevel) owner group;
|
||||
mode = "0755";
|
||||
type = "copy";
|
||||
|
|
@ -103,8 +120,7 @@ in {
|
|||
setx GENSO_STEAM_USER ${user}
|
||||
'';
|
||||
};
|
||||
})
|
||||
cfg.users);
|
||||
}) cfg.users);
|
||||
in {
|
||||
enable = mkIf (cfg.enable || cfg.setup) true;
|
||||
files = mkMerge [
|
||||
|
|
@ -112,5 +128,18 @@ in {
|
|||
(mkIf cfg.enable userBinFiles)
|
||||
];
|
||||
};
|
||||
lib.steam = {
|
||||
mkSharePathWith = {
|
||||
path,
|
||||
winRoot ? "%GENSO_SMB_SHARED_MOUNT%",
|
||||
}: mkWinPath (
|
||||
winRoot
|
||||
+ "/${cfg.sharePath}"
|
||||
+ "/${removePrefix (cfg.rootDir + "/") path}"
|
||||
);
|
||||
mkSharePath = path: config.lib.steam.mkSharePathWith {
|
||||
inherit path;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,35 +5,304 @@
|
|||
inputs,
|
||||
...
|
||||
}: let
|
||||
inherit (inputs.self.lib.lib) mkWinPath userIs;
|
||||
inherit (inputs.self.lib.lib) userIs;
|
||||
inherit (config.lib.steam) mkSharePath;
|
||||
inherit (lib.options) mkOption mkEnableOption;
|
||||
inherit (lib.modules) mkIf mkMerge mkDefault mkOptionDefault;
|
||||
inherit (lib.strings) removePrefix replaceStrings;
|
||||
inherit (lib.attrsets) filterAttrs mapAttrs' mapAttrsToList listToAttrs nameValuePair;
|
||||
inherit (lib.lists) concatMap head singleton;
|
||||
inherit (lib.meta) getExe;
|
||||
inherit (lib.strings) hasSuffix replaceStrings optionalString concatStringsSep escapeShellArg makeBinPath versionOlder;
|
||||
inherit (lib.attrsets) attrValues filterAttrs mapAttrs mapAttrs' mapAttrsToList listToAttrs nameValuePair;
|
||||
inherit (lib.lists) concatMap head last filter sort singleton;
|
||||
inherit (config.services.steam) accountSwitch;
|
||||
cfg = config.services.steam.beatsaber;
|
||||
versionModule = {
|
||||
config,
|
||||
name,
|
||||
...
|
||||
}: {
|
||||
sortedVersions = sort (a: b: versionOlder a.version b.version) (attrValues cfg.versions);
|
||||
prevVersionFor = version: let
|
||||
olderVersions = filter (v: versionOlder v.version version) sortedVersions;
|
||||
in if olderVersions != [] then last olderVersions else null;
|
||||
versionModule = { config, name, ... }: {
|
||||
options = with lib.types; {
|
||||
version = mkOption {
|
||||
type = str;
|
||||
default = name;
|
||||
};
|
||||
previousVersion = mkOption {
|
||||
type = nullOr str;
|
||||
};
|
||||
__toString = mkOption {
|
||||
type = functionTo str;
|
||||
};
|
||||
};
|
||||
config = {
|
||||
__toString = mkOptionDefault (
|
||||
config: config.version
|
||||
);
|
||||
previousVersion = mkOptionDefault (
|
||||
prevVersionFor config.version
|
||||
);
|
||||
};
|
||||
};
|
||||
fileModule = { config, name, ... }: {
|
||||
options = with lib.types; {
|
||||
relativePath = mkOption {
|
||||
type = str;
|
||||
default = name;
|
||||
};
|
||||
type = mkOption {
|
||||
type = enum [ "file" "directory" ];
|
||||
default = "file";
|
||||
};
|
||||
versioned = mkOption {
|
||||
type = bool;
|
||||
default = false;
|
||||
};
|
||||
target = mkOption {
|
||||
type = enum [ "user" "shared" "game" ];
|
||||
default = "user";
|
||||
};
|
||||
mode = {
|
||||
file = mkOption {
|
||||
type = str;
|
||||
default = if hasSuffix ".exe" config.relativePath || hasSuffix ".dll" config.relativePath then "775" else "664";
|
||||
};
|
||||
dir = mkOption {
|
||||
type = str;
|
||||
default = "2775";
|
||||
};
|
||||
};
|
||||
ownerFor = mkOption {
|
||||
type = functionTo str;
|
||||
};
|
||||
srcPathFor = mkOption {
|
||||
type = functionTo path;
|
||||
};
|
||||
srcStyle = mkOption {
|
||||
type = enum [ "empty" "copy" "symlink" "symlink-shallow" ];
|
||||
default = "symlink";
|
||||
};
|
||||
workingPathFor = mkOption {
|
||||
type = functionTo path;
|
||||
};
|
||||
init = mkOption {
|
||||
type = nullOr path;
|
||||
};
|
||||
initFor = mkOption {
|
||||
type = functionTo (nullOr path);
|
||||
};
|
||||
initStyle = mkOption {
|
||||
type = enum [ "none" "copy" "symlink" "symlink-shallow" ];
|
||||
default = "copy";
|
||||
};
|
||||
setup = {
|
||||
shared = mkOption {
|
||||
type = functionTo lines;
|
||||
internal = true;
|
||||
};
|
||||
script = mkOption {
|
||||
type = functionTo lines;
|
||||
internal = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
config = let
|
||||
versionPathFor = version: optionalString config.versioned "/${version}";
|
||||
in {
|
||||
init = mkOptionDefault (
|
||||
if config.target == "game" then null
|
||||
else if config.type == "directory" then "${emptyDir}"
|
||||
else if hasSuffix ".json" config.relativePath then "${emptyJson}"
|
||||
else if hasSuffix ".dll" config.relativePath || hasSuffix ".exe" config.relativePath then "${emptyExecutable}"
|
||||
else "${emptyFile}"
|
||||
);
|
||||
initFor = mkOptionDefault (
|
||||
{ user, version }: config.init
|
||||
);
|
||||
ownerFor = mkOptionDefault (user:
|
||||
if config.target == "user" then user else "admin"
|
||||
);
|
||||
srcPathFor = mkOptionDefault ({ user, version }:
|
||||
{
|
||||
shared = cfg.sharedDataDir + versionPathFor version;
|
||||
user = cfg.dataDirFor user + versionPathFor version;
|
||||
game = cfg.gameDirFor version;
|
||||
}.${config.target} or (throw "unsupported target")
|
||||
+ "/${config.relativePath}"
|
||||
);
|
||||
workingPathFor = mkOptionDefault ({ user, version }:
|
||||
cfg.workingDirFor { inherit user version; }
|
||||
+ "/${config.relativePath}"
|
||||
);
|
||||
# TODO: setup.shared and do inits seperately!
|
||||
setup.script = { user, version }@args: let
|
||||
owner = config.ownerFor user;
|
||||
srcPath = config.srcPathFor args;
|
||||
workingPath = config.workingPathFor args;
|
||||
initPath = config.initFor args;
|
||||
parentWorkingPath = dirOf workingPath;
|
||||
mkdir = dest: ''
|
||||
if [[ -L ${escapeShellArg dest} ]]; then
|
||||
rm -f ${escapeShellArg dest}
|
||||
fi
|
||||
if [[ ! -d ${escapeShellArg dest} ]]; then
|
||||
mkdir -m${config.mode.dir} ${escapeShellArg dest}
|
||||
else
|
||||
chmod ${config.mode.dir} ${escapeShellArg dest}
|
||||
fi
|
||||
chown ${owner}:${cfg.group} ${escapeShellArg dest}
|
||||
'';
|
||||
mkStyle = { style, src }: if style != "none" && src == {
|
||||
file = "${emptyFile}";
|
||||
directory = "${emptyDir}";
|
||||
}.${config.type} then "empty" else style;
|
||||
doInit = { style, src, dest }: {
|
||||
none = "true";
|
||||
copy = {
|
||||
file = ''
|
||||
if [[ -L ${escapeShellArg dest} ]]; then
|
||||
rm -f ${escapeShellArg dest}
|
||||
elif [[ -e ${escapeShellArg dest} ]]; then
|
||||
echo ERR: something is in the way of copying ${escapeShellArg dest} >&2
|
||||
exit 1
|
||||
fi
|
||||
cp -TP --no-preserve=all ${escapeShellArg src} ${escapeShellArg dest}
|
||||
chmod ${config.mode.file} ${escapeShellArg dest}
|
||||
chown ${owner}:${cfg.group} ${escapeShellArg dest}
|
||||
'';
|
||||
directory = ''
|
||||
${mkdir dest}
|
||||
cp -rTP --no-preserve=all ${escapeShellArg src} ${escapeShellArg dest}
|
||||
chown -R ${owner}:${cfg.group} ${escapeShellArg dest}
|
||||
find ${escapeShellArg dest} -type f -exec chmod -m${config.mode.file} "{}" \;
|
||||
'';
|
||||
}.${config.type};
|
||||
empty = {
|
||||
directory = ''
|
||||
${mkdir dest}
|
||||
'';
|
||||
file = ''
|
||||
touch ${escapeShellArg dest}
|
||||
chmod ${config.mode.file} ${escapeShellArg dest}
|
||||
chown ${owner}:${cfg.group} ${escapeShellArg dest}
|
||||
'';
|
||||
}.${config.type};
|
||||
symlink = ''
|
||||
if [[ -e ${escapeShellArg dest} && ! -L ${escapeShellArg dest} ]]; then
|
||||
echo ERR: something is in the way of linking ${escapeShellArg dest} >&2
|
||||
exit 1
|
||||
fi
|
||||
ln -sfT ${escapeShellArg src} ${escapeShellArg dest}
|
||||
'';
|
||||
symlink-shallow = {
|
||||
directory = ''
|
||||
${mkdir dest}
|
||||
ln -sf ${escapeShellArg src}/* ${escapeShellArg dest}/
|
||||
'';
|
||||
}.${config.type};
|
||||
}.${mkStyle { inherit style src; }};
|
||||
doSetup = { style, src, dest }: rec {
|
||||
none = "true";
|
||||
copy = {
|
||||
file = ''
|
||||
${empty}
|
||||
'';
|
||||
directory = ''
|
||||
${empty}
|
||||
if [[ ${escapeShellArg dest}/* != ${escapeShellArg dest}/\* ]]; then
|
||||
chmod -m${config.mode.file} ${escapeShellArg dest}/*
|
||||
fi
|
||||
'';
|
||||
}.${config.type};
|
||||
empty = {
|
||||
directory = ''
|
||||
chmod ${config.mode.dir} ${escapeShellArg dest}
|
||||
chown ${owner}:${cfg.group} ${escapeShellArg dest}
|
||||
'';
|
||||
file = ''
|
||||
chmod ${config.mode.file} ${escapeShellArg dest}
|
||||
chown ${owner}:${cfg.group} ${escapeShellArg dest}
|
||||
'';
|
||||
}.${config.type};
|
||||
symlink = "true";
|
||||
symlink-shallow = {
|
||||
directory = ''
|
||||
${mkdir.directory}
|
||||
'';
|
||||
}.${config.type};
|
||||
}.${mkStyle { inherit style src; }};
|
||||
init = doInit {
|
||||
style = config.initStyle;
|
||||
src = initPath;
|
||||
dest = srcPath;
|
||||
};
|
||||
setup = doSetup {
|
||||
style = config.initStyle;
|
||||
src = initPath;
|
||||
dest = srcPath;
|
||||
};
|
||||
src = doInit {
|
||||
style = config.srcStyle;
|
||||
src = srcPath;
|
||||
dest = workingPath;
|
||||
};
|
||||
checkFlag = {
|
||||
file = {
|
||||
none = "e";
|
||||
copy = "f";
|
||||
symlink = "L";
|
||||
}.${config.initStyle};
|
||||
directory = {
|
||||
none = "e";
|
||||
copy = "d";
|
||||
symlink-shallow = "d";
|
||||
symlink = "L";
|
||||
}.${config.initStyle};
|
||||
}.${config.type};
|
||||
checkParent = ''
|
||||
if [[ ! -d ${escapeShellArg parentWorkingPath} ]]; then
|
||||
echo ERR: parent of ${escapeShellArg workingPath} does not exist >&2
|
||||
exit 1
|
||||
fi
|
||||
'';
|
||||
check = if initPath != null then ''
|
||||
if [[ ! -${checkFlag} ${escapeShellArg srcPath} ]]; then
|
||||
${init}
|
||||
else
|
||||
${setup}
|
||||
fi
|
||||
'' else ''
|
||||
if [[ ! -${checkFlag} ${escapeShellArg srcPath} ]]; then
|
||||
echo ERR: src ${escapeShellArg srcPath} for ${escapeShellArg workingPath} does not exist >&2
|
||||
exit 1
|
||||
fi
|
||||
'';
|
||||
in ''
|
||||
${checkParent}
|
||||
${check}
|
||||
${src}
|
||||
'';
|
||||
};
|
||||
};
|
||||
emptyFile = pkgs.writeText "empty.txt" "";
|
||||
emptyJson = pkgs.writeText "empty.json" "{}";
|
||||
emptyDir = pkgs.runCommand "empty" { } ''
|
||||
mkdir $out
|
||||
'';
|
||||
emptyExecutable = pkgs.writeTextFile {
|
||||
name = "empty.exe";
|
||||
executable = true;
|
||||
text = "";
|
||||
};
|
||||
|
||||
mkSharePath = path:
|
||||
mkWinPath (
|
||||
"%GENSO_SMB_SHARED_MOUNT%"
|
||||
+ "/${accountSwitch.sharePath}"
|
||||
+ "/${removePrefix (accountSwitch.rootDir + "/") path}"
|
||||
);
|
||||
vars = ''
|
||||
bsdata = "Beat Saber_Data";
|
||||
|
||||
vars = let
|
||||
bsUserData = mkSharePath (cfg.dataDirFor "%GENSO_STEAM_USER%");
|
||||
bsWorkingData = mkSharePath (cfg.workingDirFor {
|
||||
user = "%GENSO_STEAM_USER%";
|
||||
version = "%GENSO_STEAM_BS_VERSION%";
|
||||
});
|
||||
in ''
|
||||
if "%GENSO_STEAM_MACHINE%" == "" set "GENSO_STEAM_MACHINE=%COMPUTERNAME%"
|
||||
if "%GENSO_STEAM_LOCAL_DATA%" == "" set "GENSO_STEAM_LOCAL_DATA=C:\Program Files\GensokyoZone"
|
||||
if "%GENSO_STEAM_LOCAL_DATA_BS%" == "" set "GENSO_STEAM_LOCAL_DATA_BS=%GENSO_STEAM_LOCAL_DATA%\${cfg.dirName}"
|
||||
if "%GENSO_STEAM_INSTALL%" == "" set "GENSO_STEAM_INSTALL=C:\Program Files (x86)\Steam"
|
||||
if "%GENSO_STEAM_LIBRARY_BS%" == "" set "GENSO_STEAM_LIBRARY_BS=%GENSO_STEAM_INSTALL%"
|
||||
if "%GENSO_STEAM_BS_VERSION%" == "" set "GENSO_STEAM_BS_VERSION=${cfg.defaultVersion}"
|
||||
|
|
@ -41,9 +310,16 @@
|
|||
if "%GENSO_SMB_SHARED_MOUNT%" == "" set "GENSO_SMB_SHARED_MOUNT=\\%GENSO_SMB_HOST%\shared"
|
||||
set "STEAM_BS_LIBRARY=%GENSO_STEAM_LIBRARY_BS%\steamapps\common\Beat Saber"
|
||||
set "STEAM_BS_APPDATA=%USERPROFILE%\AppData\LocalLow\Hyperbolic Magnetism\Beat Saber"
|
||||
set "STEAM_USER_DATA=${mkSharePath accountSwitch.dataDir}\%GENSO_STEAM_USER%"
|
||||
set "STEAM_WORKING_DATA=${mkSharePath accountSwitch.workingDir}\%GENSO_STEAM_USER%"
|
||||
set "STEAM_BINDIR=${mkSharePath accountSwitch.binDir}"
|
||||
set "STEAM_BS_LOCAL_DATA=%GENSO_STEAM_LOCAL_DATA_BS%\%GENSO_STEAM_BS_VERSION%"
|
||||
set "STEAM_BS_USER_DATA=${bsUserData}"
|
||||
set "STEAM_BS_WORKING_DATA=${bsWorkingData}"
|
||||
if "%GENSO_STEAM_BS_LOCAL%" == "1" (
|
||||
set "STEAM_BS_LAUNCH=%STEAM_BS_LOCAL_DATA%"
|
||||
set "STEAM_BS_LAUNCH_APPDATA=%STEAM_BS_LOCAL_DATA%\AppData"
|
||||
) else (
|
||||
set "STEAM_BS_LAUNCH=%STEAM_BS_WORKING_DATA%"
|
||||
set "STEAM_BS_LAUNCH_APPDATA=%STEAM_BS_USER_DATA%\AppData"
|
||||
)
|
||||
if "%GENSO_STEAM_USER%" == "" goto NOUSER
|
||||
'';
|
||||
eof = ''
|
||||
|
|
@ -54,10 +330,18 @@
|
|||
'';
|
||||
mount = ''
|
||||
rmdir "%STEAM_BS_APPDATA%"
|
||||
mklink /D "%STEAM_BS_APPDATA%" "%STEAM_USER_DATA%\BeatSaber\AppData"
|
||||
mklink /D "%STEAM_BS_APPDATA%" "%STEAM_BS_LAUNCH_APPDATA%"
|
||||
|
||||
rmdir "%STEAM_BS_LIBRARY%"
|
||||
mklink /D "%STEAM_BS_LIBRARY%" "%STEAM_WORKING_DATA%\BeatSaber\%GENSO_STEAM_BS_VERSION%"
|
||||
mklink /D "%STEAM_BS_LIBRARY%" "%STEAM_BS_LAUNCH%"
|
||||
'';
|
||||
setup = ''
|
||||
rmdir "%STEAM_BS_APPDATA%"
|
||||
rmdir "%STEAM_BS_LIBRARY%"
|
||||
|
||||
mkdir "%GENSO_STEAM_LOCAL_DATA_BS%"
|
||||
move /Y "%STEAM_BS_LIBRARY%" "%GENSO_STEAM_LOCAL_DATA_BS%\Vanilla"
|
||||
move /Y "%STEAM_BS_APPDATA%" "%GENSO_STEAM_LOCAL_DATA_BS%\Vanilla\AppData"
|
||||
'';
|
||||
mountbeatsaber = ''
|
||||
${vars}
|
||||
|
|
@ -73,43 +357,56 @@
|
|||
'';
|
||||
fpfcbeatsaber = ''
|
||||
${vars}
|
||||
${mount}
|
||||
cd /d "%STEAM_BS_LIBRARY%"
|
||||
"%STEAM_BS_LIBRARY%\Beat Saber.exe" fpfc
|
||||
${eof}
|
||||
'';
|
||||
|
||||
mkbeatsabersh = pkgs.writeShellScriptBin "mkbeatsaber.sh" ''
|
||||
source ${./mkbeatsaber.sh}
|
||||
setupbeatsaber = ''
|
||||
${vars}
|
||||
${setup}
|
||||
pause
|
||||
${eof}
|
||||
'';
|
||||
mkbeatsaber = pkgs.writeShellScriptBin "mkbeatsaber" ''
|
||||
localbeatsaber-mount = ''
|
||||
set GENSO_STEAM_BS_LOCAL=1
|
||||
${vars}
|
||||
${mount}
|
||||
if NOT "%GENSO_STEAM_BS_VERSION%" == "Vanilla" (
|
||||
rmdir "%STEAM_BS_LIBRARY%\UserData"
|
||||
mklink /D "%STEAM_BS_LIBRARY%\UserData" "%STEAM_BS_WORKING_DATA%\UserData"
|
||||
)
|
||||
${eof}
|
||||
'';
|
||||
localbeatsaber-vanilla = ''
|
||||
set GENSO_STEAM_BS_VERSION=Vanilla
|
||||
set GENSO_STEAM_BS_LOCAL=1
|
||||
${vars}
|
||||
${mount}
|
||||
${eof}
|
||||
'';
|
||||
localbeatsaber-launch = ''
|
||||
set GENSO_STEAM_BS_LOCAL=1
|
||||
${vars}
|
||||
${mount}
|
||||
cd /d "%STEAM_BS_LIBRARY%"
|
||||
"%STEAM_BS_LIBRARY%\Beat Saber.exe"
|
||||
${eof}
|
||||
'';
|
||||
vanilla = ''
|
||||
setx GENSO_STEAM_BS_VERSION Vanilla
|
||||
'';
|
||||
|
||||
mksetupbeatsaber = { user, version }: let
|
||||
setupFiles = mapAttrsToList (_: file: file.setup.script { inherit user version; }) cfg.files;
|
||||
in pkgs.writeShellScript "setupbeatsaber-${user}-${version}" ''
|
||||
set -eu
|
||||
|
||||
ARG_GAME_VERSION=$1
|
||||
shift
|
||||
if [[ $# -gt 0 ]]; then
|
||||
ARG_USER=$1
|
||||
shift
|
||||
else
|
||||
ARG_USER=$(${pkgs.coreutils}/bin/id -un)
|
||||
fi
|
||||
|
||||
cd ${accountSwitch.workingDir}
|
||||
mkdir -m2775 -p "$ARG_USER/BeatSaber/$ARG_GAME_VERSION"
|
||||
chown "$ARG_USER" "$ARG_USER" "$ARG_USER/BeatSaber"
|
||||
cd "$ARG_USER/BeatSaber/$ARG_GAME_VERSION"
|
||||
${getExe mkbeatsabersh} \
|
||||
"${accountSwitch.gamesDir}/BeatSaber" \
|
||||
"$ARG_GAME_VERSION" \
|
||||
"${accountSwitch.sharedDataDir}/BeatSaber" \
|
||||
"${accountSwitch.dataDir}/$ARG_USER/BeatSaber"
|
||||
export PATH="$PATH:${makeBinPath [ pkgs.coreutils ]}"
|
||||
${concatStringsSep "\n" setupFiles}
|
||||
'';
|
||||
in {
|
||||
options.services.steam.beatsaber = with lib.types; {
|
||||
enable = mkEnableOption "beatsaber scripts";
|
||||
setup =
|
||||
mkEnableOption "beatsaber data"
|
||||
// {
|
||||
setup = mkEnableOption "beatsaber data" // {
|
||||
default = accountSwitch.setup;
|
||||
};
|
||||
group = mkOption {
|
||||
|
|
@ -121,41 +418,297 @@ in {
|
|||
};
|
||||
versions = mkOption {
|
||||
type = attrsOf (submodule versionModule);
|
||||
default = {};
|
||||
default = { };
|
||||
};
|
||||
setupServiceNames = mkOption {
|
||||
type = listOf str;
|
||||
readOnly = true;
|
||||
};
|
||||
files = mkOption {
|
||||
type = attrsOf (submodule fileModule);
|
||||
default = { };
|
||||
};
|
||||
users = mkOption {
|
||||
type = listOf str;
|
||||
};
|
||||
dirName = mkOption {
|
||||
type = str;
|
||||
default = "BeatSaber";
|
||||
};
|
||||
binDir = mkOption {
|
||||
type = path;
|
||||
default = accountSwitch.binDir + "/beatsaber";
|
||||
};
|
||||
gamesDir = mkOption {
|
||||
type = path;
|
||||
default = accountSwitch.gamesDir + "/${cfg.dirName}";
|
||||
};
|
||||
gameDirFor = mkOption {
|
||||
type = functionTo path;
|
||||
default = version: cfg.gamesDir + "/${version}";
|
||||
};
|
||||
sharedDataDir = mkOption {
|
||||
type = path;
|
||||
default = accountSwitch.sharedDataDir + "/${cfg.dirName}";
|
||||
};
|
||||
userDataDir = mkOption {
|
||||
type = path;
|
||||
default = accountSwitch.dataDir;
|
||||
};
|
||||
dataDirFor = mkOption {
|
||||
type = functionTo path;
|
||||
default = user: cfg.userDataDir + "/${user}/${cfg.dirName}";
|
||||
};
|
||||
userWorkingDir = mkOption {
|
||||
type = path;
|
||||
default = accountSwitch.workingDir;
|
||||
};
|
||||
userWorkingDirFor = mkOption {
|
||||
type = functionTo path;
|
||||
default = user: cfg.userWorkingDir + "/${user}/${cfg.dirName}";
|
||||
};
|
||||
workingDirFor = mkOption {
|
||||
type = functionTo path;
|
||||
default = { user, version }: cfg.userWorkingDirFor user + "/${version}";
|
||||
};
|
||||
};
|
||||
|
||||
config = let
|
||||
in {
|
||||
config = {
|
||||
services.steam.beatsaber = let
|
||||
bsUsers = filterAttrs (_: userIs cfg.group) config.users.users;
|
||||
allVersions = mapAttrsToList (_: version: version.version) cfg.versions;
|
||||
gameFiles = {
|
||||
"Beat Saber.exe" = { };
|
||||
"UnityCrashHandler64.exe" = { };
|
||||
"UnityPlayer.dll" = { };
|
||||
"MonoBleedingEdge".type = "directory";
|
||||
};
|
||||
sharedFiles = {
|
||||
DynamicOpenVR = {
|
||||
type = "directory";
|
||||
versioned = true;
|
||||
};
|
||||
IPA = {
|
||||
type = "directory";
|
||||
versioned = true;
|
||||
};
|
||||
Libs = {
|
||||
type = "directory";
|
||||
versioned = true;
|
||||
};
|
||||
Plugins = {
|
||||
type = "directory";
|
||||
versioned = true;
|
||||
};
|
||||
Logs = {
|
||||
type = "directory";
|
||||
versioned = true;
|
||||
};
|
||||
"BeatSaberVersion.txt" = {
|
||||
versioned = true;
|
||||
initFor = { version, ... }: pkgs.writeText "BeatSaberVersion-${version}.txt" version;
|
||||
};
|
||||
"IPA.exe".versioned = true;
|
||||
"IPA.exe.config".versioned = true;
|
||||
"IPA.runtimeconfig.json".versioned = true;
|
||||
"winhttp.dll".versioned = true;
|
||||
${bsdata} = {
|
||||
type = "directory";
|
||||
versioned = true;
|
||||
#initStyle = "symlink-shallow";
|
||||
#initFor = { version, ... }: cfg.gameDirFor version + "/${bsdata}";
|
||||
initStyle = "none";
|
||||
srcPathFor = { version, ... }: cfg.gameDirFor version + "/${bsdata}";
|
||||
srcStyle = "symlink-shallow";
|
||||
};
|
||||
"${bsdata}/Managed" = {
|
||||
type = "directory";
|
||||
versioned = true;
|
||||
initFor = { version, ... }: cfg.gameDirFor version + "/${bsdata}/Managed";
|
||||
};
|
||||
# TODO: remove this to use multiple folders
|
||||
"${bsdata}/CustomLevels" = {
|
||||
type = "directory";
|
||||
initStyle = "none";
|
||||
srcPathFor = { ... }: cfg.sharedDataDir + "/CustomLevels";
|
||||
};
|
||||
CustomAvatars = {
|
||||
type = "directory";
|
||||
initStyle = "none";
|
||||
};
|
||||
CustomNotes = {
|
||||
type = "directory";
|
||||
initStyle = "none";
|
||||
};
|
||||
CustomPlatforms = {
|
||||
type = "directory";
|
||||
initStyle = "none";
|
||||
};
|
||||
CustomSabers = {
|
||||
type = "directory";
|
||||
initStyle = "none";
|
||||
};
|
||||
CustomWalls = {
|
||||
type = "directory";
|
||||
initStyle = "none";
|
||||
};
|
||||
Playlists = {
|
||||
type = "directory";
|
||||
initStyle = "none";
|
||||
};
|
||||
"UserData/ScoreSaber/Replays" = {
|
||||
type = "directory";
|
||||
initStyle = "none";
|
||||
srcPathFor = { ... }: cfg.sharedDataDir + "/Replays";
|
||||
};
|
||||
"UserData/Beat Saber IPA.json".versioned = true;
|
||||
"UserData/SongCore/" = {
|
||||
versioned = true;
|
||||
relativePath = "UserData/SongCore";
|
||||
type = "directory";
|
||||
srcStyle = "empty";
|
||||
};
|
||||
"UserData/SongCore/folders.xml" = {
|
||||
versioned = true;
|
||||
};
|
||||
"UserData/SongCore/SongCoreExtraData.dat" = {
|
||||
versioned = true;
|
||||
init = "${emptyJson}";
|
||||
};
|
||||
"UserData/SongCore/SongDurationCache.dat" = {
|
||||
versioned = true;
|
||||
init = "${emptyJson}";
|
||||
};
|
||||
"UserData/SongCore/SongHashData.dat" = {
|
||||
versioned = true;
|
||||
init = "${emptyJson}";
|
||||
};
|
||||
"UserData/Chroma".type = "directory";
|
||||
"UserData/Nya".type = "directory";
|
||||
"UserData/SongRankedBadge".type = "directory";
|
||||
"UserData/DrinkWater".type = "directory";
|
||||
"UserData/Enhancements".type = "directory";
|
||||
"UserData/HitScoreVisualizer" = {
|
||||
type = "directory";
|
||||
# TODO: initStyle = "symlink"; init = "${myhitscorejsons}";
|
||||
};
|
||||
"UserData/Saber Factory/" = {
|
||||
relativePath = "UserData/Saber Factory";
|
||||
type = "directory";
|
||||
srcStyle = "empty";
|
||||
};
|
||||
"UserData/Saber Factory/Cache".type = "directory";
|
||||
"UserData/Saber Factory/Textures".type = "directory";
|
||||
"UserData/BeatSaverDownloader.ini" = { };
|
||||
"UserData/BeatSaverUpdater.json" = { };
|
||||
"UserData/SongDetailsCache.proto".versioned = true;
|
||||
"UserData/SongDetailsCache.proto.Direct.etag".versioned = true;
|
||||
};
|
||||
userFiles = {
|
||||
"UserData" = {
|
||||
type = "directory";
|
||||
versioned = true;
|
||||
srcStyle = "empty";
|
||||
};
|
||||
"UserData/Camera2".type = "directory";
|
||||
"UserData/Saber Factory" = {
|
||||
type = "directory";
|
||||
srcStyle = "empty";
|
||||
};
|
||||
"UserData/Saber Factory/Presets".type = "directory";
|
||||
"UserData/Saber Factory/TrailConfig.json" = { };
|
||||
"UserData/SongCore" = {
|
||||
type = "directory";
|
||||
versioned = true;
|
||||
srcStyle = "empty";
|
||||
};
|
||||
"UserData/SongCore/SongCore.json" = {
|
||||
versioned = true;
|
||||
};
|
||||
"UserData/ScoreSaber" = {
|
||||
type = "directory";
|
||||
versioned = true;
|
||||
srcStyle = "empty";
|
||||
};
|
||||
"UserData/ScoreSaber/ScoreSaber.json" = {
|
||||
versioned = true;
|
||||
};
|
||||
"UserData/Disabled Mods.json".versioned = true;
|
||||
"UserData/modprefs.ini".versioned = true;
|
||||
"UserData/JDFixer.json".versioned = true;
|
||||
};
|
||||
userDataFiles = [
|
||||
"modprefs.ini" "Disabled Mods.json"
|
||||
"AutoPauseStealth.json"
|
||||
"BeatSaberMarkupLanguage.json"
|
||||
"BeatSaviorData.ini"
|
||||
"BetterSongList.json"
|
||||
"BetterSongSearch.json"
|
||||
"bookmarkedSongs.json" "votedSongs.json"
|
||||
"Chroma.json"
|
||||
"Cinema.json"
|
||||
"CountersPlus.json"
|
||||
"CustomAvatars.CalibrationData.dat" "CustomAvatars.json" "CustomNotes.json" "Custom Platforms.json" "CustomWalls.json"
|
||||
"DrinkWater.json"
|
||||
"EasyOffset.json"
|
||||
"Enhancements.json"
|
||||
"FasterScroll.json"
|
||||
"FastFail.json"
|
||||
"Fifth Anniversary Mod.json"
|
||||
"Gotta Go Fast.json"
|
||||
"Heck.json"
|
||||
"HitScoreVisualizer.json"
|
||||
"HitsoundTweaks.json"
|
||||
"Intro Skip.json"
|
||||
"JDFixer.json"
|
||||
"ModelDownloader.json"
|
||||
"Music Spatializer.json"
|
||||
"Nya.json"
|
||||
"ParticleOverdrive.ini"
|
||||
"PerformanceMeter.json"
|
||||
"PlayFirst.json"
|
||||
"PlaylistManager.json"
|
||||
"PracticePlugin.json"
|
||||
"Saber Factory.json"
|
||||
"SaberTailor.json"
|
||||
"ScorePercentage.json"
|
||||
"SiraUtil.json"
|
||||
"SmoothCamPlus.json"
|
||||
"SongChartVisualizer.json"
|
||||
"SongPlayData.json"
|
||||
"SongPlayHistory.json"
|
||||
"SongRankedBadge.json"
|
||||
"Technicolor.json"
|
||||
"Tweaks55.json"
|
||||
"UITweaks.json"
|
||||
];
|
||||
mapSharedFile = file: file // {
|
||||
target = "shared";
|
||||
};
|
||||
mapGameFile = file: file // {
|
||||
target = "game";
|
||||
};
|
||||
mapUserDataFile = file: nameValuePair "UserData/${file}" {
|
||||
target = "user";
|
||||
};
|
||||
in {
|
||||
defaultVersion = mkIf (allVersions != []) (mkOptionDefault (
|
||||
defaultVersion = mkIf (allVersions != [ ]) (mkOptionDefault (
|
||||
head allVersions
|
||||
));
|
||||
users = mkOptionDefault (
|
||||
mapAttrsToList (_: user: user.name) bsUsers
|
||||
);
|
||||
};
|
||||
environment = mkIf cfg.enable {
|
||||
systemPackages = [
|
||||
mkbeatsaber
|
||||
mkbeatsabersh
|
||||
setupServiceNames = mkOptionDefault (
|
||||
map (user: "steam-setup-beatsaber-${user}.service") cfg.users
|
||||
);
|
||||
files = mkMerge [
|
||||
userFiles
|
||||
(listToAttrs (map mapUserDataFile userDataFiles))
|
||||
(mapAttrs (_: mapGameFile) gameFiles)
|
||||
(mapAttrs (_: mapSharedFile) sharedFiles)
|
||||
];
|
||||
};
|
||||
systemd.services = mkIf cfg.setup (listToAttrs (map (user:
|
||||
nameValuePair "steam-setup-beatsaber-${user}" {
|
||||
script = mkMerge (mapAttrsToList (_: version: ''
|
||||
${getExe mkbeatsaber} ${version.version} ${user}
|
||||
'')
|
||||
cfg.versions);
|
||||
path = [
|
||||
pkgs.coreutils
|
||||
];
|
||||
systemd.services.steam-setup-beatsaber = mkIf cfg.setup {
|
||||
wantedBy = [
|
||||
"multi-user.target"
|
||||
];
|
||||
|
|
@ -163,11 +716,15 @@ in {
|
|||
"tmpfiles.service"
|
||||
];
|
||||
serviceConfig = {
|
||||
Type = mkOptionDefault "oneshot";
|
||||
RemainAfterExit = mkOptionDefault true;
|
||||
User = mkOptionDefault user;
|
||||
ExecStart = mkMerge (map (user:
|
||||
(mapAttrsToList (_: version:
|
||||
"${mksetupbeatsaber { inherit user; inherit (version) version; }}"
|
||||
) cfg.versions)
|
||||
) cfg.users);
|
||||
};
|
||||
};
|
||||
})
|
||||
cfg.users));
|
||||
services.tmpfiles = let
|
||||
toplevel = {
|
||||
owner = mkDefault "admin";
|
||||
|
|
@ -194,45 +751,37 @@ in {
|
|||
"CustomPlatforms"
|
||||
"CustomSabers"
|
||||
"CustomWalls"
|
||||
"Playlists"
|
||||
"Replays"
|
||||
"AppData"
|
||||
"UserData"
|
||||
];
|
||||
setupFiles =
|
||||
[
|
||||
setupFiles = [
|
||||
{
|
||||
"${accountSwitch.sharedDataDir}/BeatSaber" = toplevel;
|
||||
"${accountSwitch.binDir}/beatsaber" = shared;
|
||||
${cfg.sharedDataDir} = toplevel;
|
||||
${cfg.binDir} = shared;
|
||||
}
|
||||
(listToAttrs (
|
||||
map (
|
||||
folder:
|
||||
nameValuePair "${accountSwitch.sharedDataDir}/BeatSaber/${folder}" shared
|
||||
)
|
||||
sharedFolders
|
||||
map (folder:
|
||||
nameValuePair "${cfg.sharedDataDir}/${folder}" shared
|
||||
) sharedFolders
|
||||
))
|
||||
]
|
||||
++ concatMap (
|
||||
owner:
|
||||
] ++ concatMap (owner:
|
||||
singleton {
|
||||
"${accountSwitch.dataDir}/${owner}/BeatSaber" = personal owner;
|
||||
"${accountSwitch.dataDir}/${owner}/BeatSaber/AppData" = personal owner;
|
||||
"${accountSwitch.dataDir}/${owner}/BeatSaber/UserData" = personal owner;
|
||||
}
|
||||
${cfg.dataDirFor owner} = personal owner;
|
||||
"${cfg.dataDirFor owner}/AppData" = personal owner;
|
||||
"${cfg.dataDirFor owner}/UserData" = personal owner;
|
||||
} ++ mapAttrsToList (_: version: {
|
||||
"${cfg.dataDirFor owner}/${version.version}" = personal owner;
|
||||
${cfg.userWorkingDirFor owner} = personal owner;
|
||||
${cfg.workingDirFor { user = owner; inherit (version) version; }} = personal owner;
|
||||
}) cfg.versions
|
||||
) cfg.users
|
||||
++ mapAttrsToList (_: version: {
|
||||
"${accountSwitch.dataDir}/${owner}/BeatSaber/${version.version}" = personal owner;
|
||||
})
|
||||
cfg.versions
|
||||
)
|
||||
accountSwitch.users
|
||||
++ mapAttrsToList (_: version: {
|
||||
"${accountSwitch.sharedDataDir}/BeatSaber/${version.version}" = shared;
|
||||
})
|
||||
cfg.versions;
|
||||
versionBinFiles =
|
||||
mapAttrs' (
|
||||
_: version:
|
||||
nameValuePair
|
||||
"${accountSwitch.binDir}/beatsaber/${replaceStrings ["."] ["_"] version.version}.bat"
|
||||
"${cfg.sharedDataDir}/${version.version}" = shared;
|
||||
}) cfg.versions;
|
||||
versionBinFiles = mapAttrs' (_: version: nameValuePair
|
||||
"${cfg.binDir}/${replaceStrings [ "." ] [ "_" ] version.version}.bat"
|
||||
{
|
||||
inherit (bin) owner group mode type;
|
||||
src = pkgs.writeTextFile {
|
||||
|
|
@ -243,11 +792,9 @@ in {
|
|||
'';
|
||||
};
|
||||
}
|
||||
)
|
||||
cfg.versions;
|
||||
binFiles =
|
||||
{
|
||||
"${accountSwitch.binDir}/beatsaber/mount.bat" = {
|
||||
) cfg.versions;
|
||||
binFiles = {
|
||||
"${cfg.binDir}/mount.bat" = {
|
||||
inherit (bin) owner group mode type;
|
||||
src = pkgs.writeTextFile {
|
||||
name = "beatsaber-mount.bat";
|
||||
|
|
@ -255,7 +802,7 @@ in {
|
|||
text = mountbeatsaber;
|
||||
};
|
||||
};
|
||||
"${accountSwitch.binDir}/beatsaber/launch.bat" = {
|
||||
"${cfg.binDir}/launch.bat" = {
|
||||
inherit (bin) owner group mode type;
|
||||
src = pkgs.writeTextFile {
|
||||
name = "beatsaber-launch.bat";
|
||||
|
|
@ -263,7 +810,7 @@ in {
|
|||
text = launchbeatsaber;
|
||||
};
|
||||
};
|
||||
"${accountSwitch.binDir}/beatsaber/fpfc.bat" = {
|
||||
"${cfg.binDir}/fpfc.bat" = {
|
||||
inherit (bin) owner group mode type;
|
||||
src = pkgs.writeTextFile {
|
||||
name = "beatsaber-fpfc.bat";
|
||||
|
|
@ -271,24 +818,61 @@ in {
|
|||
text = fpfcbeatsaber;
|
||||
};
|
||||
};
|
||||
"${accountSwitch.binDir}/beatsaber/ModAssistant.exe" = {
|
||||
inherit (toplevel) owner group;
|
||||
mode = "0755";
|
||||
type = "copy";
|
||||
"${cfg.binDir}/setup.bat" = {
|
||||
inherit (bin) owner group mode type;
|
||||
src = pkgs.writeTextFile {
|
||||
name = "beatsaber-setup.bat";
|
||||
executable = true;
|
||||
text = setupbeatsaber;
|
||||
};
|
||||
};
|
||||
"${cfg.binDir}/local-launch.bat" = {
|
||||
inherit (bin) owner group mode type;
|
||||
src = pkgs.writeTextFile {
|
||||
name = "beatsaber-local-launch.bat";
|
||||
executable = true;
|
||||
text = localbeatsaber-launch;
|
||||
};
|
||||
};
|
||||
"${cfg.binDir}/local-mount.bat" = {
|
||||
inherit (bin) owner group mode type;
|
||||
src = pkgs.writeTextFile {
|
||||
name = "beatsaber-local-mount.bat";
|
||||
executable = true;
|
||||
text = localbeatsaber-mount;
|
||||
};
|
||||
};
|
||||
"${cfg.binDir}/local-vanilla.bat" = {
|
||||
inherit (bin) owner group mode type;
|
||||
src = pkgs.writeTextFile {
|
||||
name = "beatsaber-local-vanilla.bat";
|
||||
executable = true;
|
||||
text = localbeatsaber-vanilla;
|
||||
};
|
||||
};
|
||||
"${cfg.binDir}/vanilla.bat" = {
|
||||
inherit (bin) owner group mode type;
|
||||
src = pkgs.writeTextFile {
|
||||
name = "beatsaber-version-vanilla.bat";
|
||||
executable = true;
|
||||
text = vanilla;
|
||||
};
|
||||
};
|
||||
"${cfg.binDir}/ModAssistant.exe" = {
|
||||
inherit (bin) owner group mode type;
|
||||
src = pkgs.fetchurl {
|
||||
url = "https://github.com/Assistant/ModAssistant/releases/download/v1.1.32/ModAssistant.exe";
|
||||
hash = "sha256-ozu2gYFiz+2BjptqL80DmUopbahbyGKFO1IPd7BhVPM=";
|
||||
executable = true;
|
||||
};
|
||||
};
|
||||
}
|
||||
// versionBinFiles;
|
||||
} // versionBinFiles;
|
||||
in {
|
||||
enable = mkIf (cfg.enable || cfg.setup) true;
|
||||
files = mkMerge [
|
||||
(mkIf cfg.setup (mkMerge setupFiles))
|
||||
(mkIf cfg.enable binFiles)
|
||||
];
|
||||
enable = mkIf cfg.setup true;
|
||||
files = mkIf cfg.setup (mkMerge (
|
||||
singleton binFiles
|
||||
++ setupFiles
|
||||
));
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,83 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
|
||||
ARG_GAME_SRC=$1
|
||||
ARG_GAME_VERSION=$2
|
||||
ARG_SHARED_DATA=$3
|
||||
ARG_USER_DATA=$4
|
||||
shift 4
|
||||
|
||||
if ! [[ -e "$ARG_GAME_SRC/$ARG_GAME_VERSION/Beat Saber.exe" ]]; then
|
||||
echo unexpected game src >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ln -srf "$ARG_GAME_SRC/$ARG_GAME_VERSION/"*.{exe,dll} ./
|
||||
ln -srf "$ARG_GAME_SRC/$ARG_GAME_VERSION/"{MonoBleedingEdge,Plugins} ./
|
||||
rm "Beat Saber.exe"
|
||||
cp "$ARG_GAME_SRC/$ARG_GAME_VERSION/Beat Saber.exe" ./
|
||||
chmod 0775 "Beat Saber.exe"
|
||||
|
||||
BSDATA="Beat Saber_Data"
|
||||
mkdir -pm2775 "$BSDATA"
|
||||
ln -srf "$ARG_GAME_SRC/$ARG_GAME_VERSION/$BSDATA/"* "$BSDATA/" || true
|
||||
ln -srf "$ARG_SHARED_DATA/CustomLevels" "$BSDATA/"
|
||||
rm -f "$BSDATA/Managed"
|
||||
|
||||
mkdir -pm2775 UserData
|
||||
|
||||
ln -srf "$ARG_SHARED_DATA/"{CustomAvatars,CustomNotes,CustomPlatforms,CustomSabers,CustomWalls,Playlists} ./
|
||||
for shareddir in DynamicOpenVR IPA Libs Logs Plugins "$BSDATA/Managed" UserData/SongCore; do
|
||||
shareddirsrc="$ARG_SHARED_DATA/$ARG_GAME_VERSION/$shareddir"
|
||||
if [[ ! -e $shareddirsrc ]]; then
|
||||
mkdir -pm2775 "$shareddirsrc"
|
||||
if [[ $shareddir = */Managed ]]; then
|
||||
cp "$ARG_GAME_SRC/$ARG_GAME_VERSION/$BSDATA/Managed/"* "$shareddirsrc/" || true
|
||||
chmod 0775 "$shareddirsrc/"*.dll || true
|
||||
fi
|
||||
fi
|
||||
ln -srf "$shareddirsrc" "./$(dirname "$shareddir")"
|
||||
done
|
||||
for sharedfile in IPA.exe IPA.exe.config IPA.runtimeconfig.json winhttp.dll; do
|
||||
sharedfilesrc="$ARG_SHARED_DATA/$ARG_GAME_VERSION/$sharedfile"
|
||||
if [[ ! -e "$sharedfilesrc" ]]; then
|
||||
mkdir -pm2775 "$(dirname "$sharedfilesrc")"
|
||||
if [[ $sharedfile = *.json ]]; then
|
||||
echo '{}' > "$sharedfilesrc"
|
||||
else
|
||||
touch "$sharedfilesrc"
|
||||
fi
|
||||
chmod 0775 "$sharedfilesrc" || true
|
||||
fi
|
||||
ln -f "$sharedfilesrc" ./
|
||||
done
|
||||
|
||||
for sharedfile in "Beat Saber IPA.json"; do
|
||||
sharedfilesrc="$ARG_SHARED_DATA/$ARG_GAME_VERSION/UserData/$sharedfile"
|
||||
if [[ ! -e "$sharedfilesrc" ]]; then
|
||||
mkdir -pm2775 "$(dirname "$sharedfilesrc")"
|
||||
if [[ $sharedfile = *.json ]]; then
|
||||
echo '{}' > "$sharedfilesrc"
|
||||
else
|
||||
touch "$sharedfilesrc"
|
||||
fi
|
||||
fi
|
||||
ln -f "$sharedfilesrc" "UserData/$(dirname "$sharedfile")"
|
||||
done
|
||||
ln -f "$ARG_SHARED_DATA/UserData/"*.{json,ini,proto,etag} UserData/
|
||||
ln -srf "$ARG_SHARED_DATA/UserData/"{ScoreSaber,Chroma,Nya,SongRankedBadge,HitScoreVisualizer}/ UserData/
|
||||
|
||||
SFDATA="UserData/Saber Factory"
|
||||
mkdir -pm2775 "$SFDATA"
|
||||
ln -srf "$ARG_SHARED_DATA/$SFDATA/"*/ "$SFDATA/"
|
||||
ln -srf "$ARG_USER_DATA/$SFDATA/"*/ "$SFDATA/"
|
||||
ln -f "$ARG_USER_DATA/$SFDATA/"*.json "$SFDATA/"
|
||||
|
||||
for userdir in Camera2 DrinkWater Enhancements; do
|
||||
userdirsrc="$ARG_USER_DATA/UserData/$userdir"
|
||||
if [[ ! -e $userdirsrc ]]; then
|
||||
mkdir -pm3775 "$userdirsrc"
|
||||
fi
|
||||
ln -srf "$userdirsrc" UserData/
|
||||
done
|
||||
ln -f "$ARG_USER_DATA/UserData/"*.{json,ini,dat} UserData/
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
inherit (lib.modules) mkIf mkMerge mkDefault;
|
||||
inherit (lib.strings) removePrefix;
|
||||
inherit (lib.attrsets) listToAttrs nameValuePair;
|
||||
inherit (config.services.steam) accountSwitch;
|
||||
inherit (config.services.steam) accountSwitch beatsaber;
|
||||
cfg = config.kyuuto;
|
||||
in {
|
||||
options.kyuuto = with lib.types; {
|
||||
|
|
@ -106,11 +106,15 @@ in {
|
|||
enable = mkIf cfg.setup true;
|
||||
files = mkMerge [
|
||||
(mkIf cfg.setup (mkMerge setupFiles))
|
||||
(mkIf accountSwitch.enable {
|
||||
(mkIf (accountSwitch.enable || beatsaber.setup) {
|
||||
${accountSwitch.gamesDir} = {
|
||||
type = "bind";
|
||||
bindReadOnly = true;
|
||||
src = cfg.gameLibraryDir + "/PC";
|
||||
systemd.mountSettings = rec {
|
||||
wantedBy = mkIf beatsaber.setup beatsaber.setupServiceNames;
|
||||
before = wantedBy;
|
||||
};
|
||||
};
|
||||
})
|
||||
];
|
||||
|
|
|
|||
|
|
@ -3,5 +3,9 @@
|
|||
in {
|
||||
services.steam.accountSwitch = {
|
||||
enable = mkDefault true;
|
||||
machines = {
|
||||
hourai.owner = "arc";
|
||||
chen.owner = "kat";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue