{ stdenv, lib, pkgs, fetchurl, fetchpatch, nix, pkgsCross, installDir ? "$HOME/.local/starcitizen", launcherCache ? "$HOME/.local/share", prefixBaseDir ? "$HOME/.winenix", binName ? "starcitizen", launcherArgs ? [ "--use-gl=osmesa" ], vulkanDrivers ? [ ], dxvkPatches ? [ ], dxvkAsync ? false, winePackage ? pkgs.wineWowPackages.unstable, wineSrc ? null, wineGlobalEnv ? [ "DXVK_STATE_CACHE=0" ], winePatches ? [], applyReccomendedWinePatches ? true, virtualDesktop ? null, registryFiles ? [ ], captureMouse ? true, enableGameScope ? false, gameScopeArgs ? [ "-W 2560" "-H 1440" "-b" ], }: #check wether string is two positive integers separated by x assert virtualDesktop == null || (lib.strings.toInt(lib.strings.concatStrings(lib.strings.splitString "x" virtualDesktop))) > 0; #check whether paths are not terminated with a / assert !(builtins.any (lib.strings.hasSuffix "/") [ installDir launcherCache prefixBaseDir ]); let wineReccomendedPatches = [ (fetchpatch { name = "joyaxis.patch"; url = "https://raw.githubusercontent.com/snatella/wine-runner-sc/5e48a6fb974da9f1585043a236026c7c57272e67/patches/6.4/joyaxis.patch"; sha256 = "18f87anf0rkvbkjhgm9j6n2cccp1wl82a12vhzr7a4p7bc025yrz"; }) (fetchpatch { name = "StorageDeviceSeekPenalty.patch"; url = "https://raw.githubusercontent.com/Frogging-Family/community-patches/f96b11b79d6aada264838d780dfd5a14f85cced0/wine-tkg-git/star-citizen-StorageDeviceSeekPenaltyProperty.mypatch"; sha256 = "01ilxhl90ib05jwsqy0iajqixdvd571ad803z1qj3lgjk3siff13"; }) ]; winePkg = winePackage.overrideAttrs (attrs: { patches = (if wineSrc == null then attrs.patches else []) ++ winePatches ++ lib.optional applyReccomendedWinePatches wineReccomendedPatches; src = if wineSrc != null then wineSrc else attrs.src; }); dxvk = (pkgsCross.mingwW64.callPackage ./dxvk.nix { async = dxvkAsync; }).overrideAttrs ( attrs: { patches = attrs.patches ++ dxvkPatches; }); dxvkAsyncEnv = "DXVK_ASYNC=1" ; gamescope = "${pkgs.callPackage ./gamescope.nix {}}/bin/gamescope"; vulkanDriverPaths = { radeon = "${pkgs.mesa_drivers.drivers}/share/vulkan/icd.d/radeon_icd.x86_64.json"; intel = "${pkgs.mesa_drivers.drivers}/share/vulkan/icd.d/intel_icd.x86_64.json"; amdvlk = "${pkgs.amdvlk}/share/vulkan/icd.d/amd_icd64.json"; }; vkIcd = lib.strings.concatStringsSep ":" (lib.attrsets.attrVals vulkanDrivers vulkanDriverPaths); fonts = pkgs.callPackage ./fonts.nix {}; rsiInstaller = fetchurl { url = "https://install.robertsspaceindustries.com/star-citizen/RSI-Setup-1.4.11.exe"; sha256 = "1afc4b36dd1e22d75df8da2ecb925833f9b10327c991be20e138503cde627022"; }; vcrun2019 = fetchurl { url = "https://aka.ms/vs/16/release/vc_redist.x86.exe"; sha256 = "1p22ibzx80zn2gxavmcsz7adkr5672smmlwgapfvx6a04f9n7a7k"; }; win10Reg = pkgs.writeTextFile { name = "win10.reg"; text = ./win10.reg; }; captureMouseReg = pkgs.writeTextFile { name = "captureMouse.reg"; text = ./captureMouse.reg; }; helpText = pkgs.writeTextFile { name = "scHelptext"; text = ./helpText.txt; }; wine64 = "${winePkg}/bin/wine64"; wineMulti = "${winePkg}/bin/wine"; regEdit = "${wine64} regedit"; reg = "${wine64} reg"; script = pkgs.writeShellScriptBin binName '' #sane bash set -eo pipefail function installPrefix () { if [ ! -d "$WINEPREFIX" ]; then ${winePkg}/bin/wineboot -i #set win 10 ${regEdit} ${win10Reg} #install dxvk for library in ${dxvk}/bin/*.dll ; do cp $library "$WINEPREFIX/drive_c/windows/system32" local libraryFile=$(basename $library) ${reg} add 'HKEY_CURRENT_USER\Software\Wine\DllOverrides' /v ''${libraryFile/\.dll/} /d native /f done #install fonts cp ${fonts}/share/fonts/*.TTF "$WINEPREFIX/drive_c/windows/Fonts" ${regEdit} ${fonts}/share/regs/fonts.reg #install vcrun2019 ${wineMulti} ${vcrun2019} /q #symlink persistent game and launcher binaries into prefix. gameBinariesPers="${installDir}/Roberts Space Industries" gameBinariesLinkDest="$WINEPREFIX/drive_c/Program Files/" mkdir -p "$gameBinariesPers" "$gameBinariesLinkDest" ln -s "$gameBinariesPers" "$gameBinariesLinkDest" #symlink launcher cache launcherCachePers="${launcherCache}/rsilauncher" mkdir -p "$launcherCachePers" "$WINEPREFIX/drive_c/users/$USER/AppData/Roaming/" ln -s "$launcherCachePers" "$WINEPREFIX/drive_c/users/$USER/AppData/Roaming/" ${lib.optionalString captureMouse "${regEdit} ${captureMouseReg.text}"} #apply custom user registry files ${lib.concatMapStrings (x: "${regEdit} " + x + "\n") registryFiles} fi } function installLauncher () { installPrefix #install the launcher echo "Install with default parameters, launcherArgs won't be used when you launch the launcher from the setup" ${winePkg}/bin/wine ${rsiInstaller} } function runGame () { installPrefix #install the launcher conditionally here and not in the launcher to allow force reinstalls. if [ ! -f "${installDir}/Roberts Space Industries/RSI Launcher/RSI Launcher.exe" ]; then installLauncher fi ${lib.optionalString enableGameScope "${gamescope} ${builtins.concatStringsSep " " gameScopeArgs} --\\" } ${wineMulti} \ ${lib.optionalString (virtualDesktop != null) "explorer /desktop=${binName},${virtualDesktop}"} \ "$WINEPREFIX/drive_c/Program Files/Roberts Space Industries/RSI Launcher/RSI Launcher.exe" \ ${lib.concatStringsSep " " launcherArgs} } function printPrefix () { echo "$WINEPREFIX" } function clean () { find "${prefixBaseDir}" -maxdepth 1 -type d -name ????????????????????????????????-"${binName}" -and -not -wholename "$WINEPREFIX" -exec rm -rf {} \; } function removePrefix () { #Good thing the GPL contains a no warranty clause rm -rf "$WINEPREFIX" } function help () { cat ${helpText.text} } function wine () { installPrefix ${winePkg}/bin/"$@" } #base setup if [ ! -d "${installDir}" ]; then mkdir -p "${installDir}/Roberts Space Industries" fi #create base dir for nix installs if [ ! -d ${prefixBaseDir} ]; then mkdir -p "${prefixBaseDir}" fi #core idea: Generate UUID from storage path of this script, ensure #new prefix for any changes. Needs fast prefix installs and state outside. uuid=$(basename $(${pkgs.nix}/bin/nix path-info "$(readlink -f $BASH_SOURCE)")) export WINEPREFIX="${prefixBaseDir}/$uuid" export WINEARCH=win64 #optionally export vulkan drivers: #The following line might be empty in the resulting script. ${lib.optionalString (vulkanDrivers != []) "export VK_ICD_FILENAMES=${vkIcd}"} #export all global env vars ${lib.concatMapStrings (x: "export " + x + "\n") (wineGlobalEnv ++ lib.lists.optional dxvkAsync dxvkAsyncEnv )} #parse input case "$@" in --install-prefix) installPrefix ;; --install-launcher) installLauncher ;; --clean) clean ;; --remove-prefix) removePrefix ;; --run-game|"") runGame ;; --print-prefix) printPrefix ;; --help) help ;; --wine*) shift wine "$@" ;; *) help exit 1 esac ''; in script