From 06801a9a3cd4261a447bbbb1d30c8806d530a47d Mon Sep 17 00:00:00 2001 From: Infinidoge Date: Fri, 26 Jul 2024 20:38:29 -0400 Subject: [PATCH] vendored/steam: init, replacing software/steam --- modules/modules/desktop/gaming.nix | 14 +- modules/modules/software/steam.nix | 174 --------------------- modules/vendored/steam.nix | 239 +++++++++++++++++++++++++++++ 3 files changed, 251 insertions(+), 176 deletions(-) delete mode 100644 modules/modules/software/steam.nix create mode 100644 modules/vendored/steam.nix diff --git a/modules/modules/desktop/gaming.nix b/modules/modules/desktop/gaming.nix index c338a35..d2c7bc7 100644 --- a/modules/modules/desktop/gaming.nix +++ b/modules/modules/desktop/gaming.nix @@ -38,11 +38,21 @@ in (mkIf cfg.lutris.enable cfg.lutris.package) (mkIf cfg.olympus.enable cfg.olympus.package) (mkIf cfg.puzzles.enable cfg.puzzles.package) + (mkIf cfg.steam.enable protonup) + (mkIf cfg.steam.enable wineWowPackages.stable) ]; - modules.software.steam = { + programs.steam = { enable = mkAliasDefinitions opt.steam.enable; - package = mkAliasDefinitions opt.steam.package; + package = cfg.steam.package.override (optionalAttrs config.modules.hardware.gpu.nvidia { + extraProfile = '' + unset VK_ICD_FILENAMES + export VK_ICD_FILENAMES=${config.hardware.nvidia.package}/share/vulkan/icd.d/nvidia_icd.json:${config.hardware.nvidia.package.lib32}/share/vulkan/icd.d/nvidia_icd32.json + ''; + }); + extraCompatPackages = with pkgs; [ + proton-ge-bin + ]; }; } ]; diff --git a/modules/modules/software/steam.nix b/modules/modules/software/steam.nix deleted file mode 100644 index 26ecbd7..0000000 --- a/modules/modules/software/steam.nix +++ /dev/null @@ -1,174 +0,0 @@ -{ config, lib, pkgs, ... }: -with lib; -with lib.our; -let - cfg = config.modules.software.steam; - gamescopeCfg = config.programs.gamescope; - - hw = config.modules.hardware; - - steam-gamescope = - let - exports = builtins.attrValues (builtins.mapAttrs (n: v: "export ${n}=${v}") cfg.gamescopeSession.env); - in - pkgs.writeShellScriptBin "steam-gamescope" '' - ${builtins.concatStringsSep "\n" exports} - gamescope --steam ${toString cfg.gamescopeSession.args} -- steam -tenfoot -pipewire-dmabuf - ''; - - gamescopeSessionFile = - (pkgs.writeTextDir "share/wayland-sessions/steam.desktop" '' - [Desktop Entry] - Name=Steam - Comment=A digital distribution platform - Exec=${steam-gamescope}/bin/steam-gamescope - Type=Application - '').overrideAttrs (_: { passthru.providedSessions = [ "steam" ]; }); -in -{ - options.modules.software.steam = { - enable = mkEnableOption (lib.mdDoc "steam"); - - package = mkOption { - type = types.package; - default = pkgs.steam; - defaultText = literalExpression "pkgs.steam"; - example = literalExpression '' - pkgs.steam-small.override { - extraEnv = { - MANGOHUD = true; - OBS_VKCAPTURE = true; - RADV_TEX_ANISO = 16; - }; - extraLibraries = p: with p; [ - atk - ]; - } - ''; - apply = steam: steam.override (prev: { - extraLibraries = pkgs: - let - prevLibs = if prev ? extraLibraries then prev.extraLibraries pkgs else [ ]; - additionalLibs = with config.hardware.graphics; - if pkgs.stdenv.hostPlatform.is64bit - then [ package ] ++ extraPackages - else [ package32 ] ++ extraPackages32; - in - prevLibs ++ additionalLibs; - } - // (optionalAttrs (cfg.gamescopeSession.enable && gamescopeCfg.capSysNice) { - buildFHSEnv = pkgs.buildFHSEnv.override { - # use the setuid wrapped bubblewrap - bubblewrap = "${config.security.wrapperDir}/.."; - }; - }) - // (optionalAttrs hw.gpu.nvidia { - extraProfile = '' - unset VK_ICD_FILENAMES - export VK_ICD_FILENAMES=${config.hardware.nvidia.package}/share/vulkan/icd.d/nvidia_icd.json:${config.hardware.nvidia.package.lib32}/share/vulkan/icd.d/nvidia_icd32.json - ''; - })); - description = lib.mdDoc '' - The Steam package to use. Additional libraries are added from the system - configuration to ensure graphics work properly. - - Use this option to customise the Steam package rather than adding your - custom Steam to {option}`environment.systemPackages` yourself. - ''; - }; - - remotePlay.openFirewall = mkOption { - type = types.bool; - default = false; - description = lib.mdDoc '' - Open ports in the firewall for Steam Remote Play. - ''; - }; - - dedicatedServer.openFirewall = mkOption { - type = types.bool; - default = false; - description = lib.mdDoc '' - Open ports in the firewall for Source Dedicated Server. - ''; - }; - - gamescopeSession = mkOption { - description = mdDoc "Run a GameScope driven Steam session from your display-manager"; - default = { }; - type = types.submodule { - options = { - enable = mkEnableOption (mdDoc "GameScope Session"); - args = mkOption { - type = types.listOf types.str; - default = [ ]; - description = mdDoc '' - Arguments to be passed to GameScope for the session. - ''; - }; - - env = mkOption { - type = types.attrsOf types.str; - default = { }; - description = mdDoc '' - Environmental variables to be passed to GameScope for the session. - ''; - }; - }; - }; - }; - }; - - config = mkMerge [ - { - assertions = [{ - assertion = if cfg.enable then config.info.graphical else true; - message = "Steam cannot be enabled in a non-graphical environment"; - }]; - } - - (mkIf cfg.enable { - # Taken from the programs.steam option, reimplemented here to move software into userland - hardware.graphics = { - enable = true; - enable32Bit = true; - }; - - hardware.pulseaudio.support32Bit = config.hardware.pulseaudio.enable; - - hardware.steam-hardware.enable = true; - - home.home.packages = [ - cfg.package - cfg.package.run - - pkgs.protonup - pkgs.wineWowPackages.stable - ] ++ lib.optional cfg.gamescopeSession.enable steam-gamescope; - - security.wrappers = mkIf (cfg.gamescopeSession.enable && gamescopeCfg.capSysNice) { - # needed or steam fails - bwrap = { - owner = "root"; - group = "root"; - source = "${pkgs.bubblewrap}/bin/bwrap"; - setuid = true; - }; - }; - - programs.gamescope.enable = mkDefault cfg.gamescopeSession.enable; - services.xserver.displayManager.sessionPackages = mkIf cfg.gamescopeSession.enable [ gamescopeSessionFile ]; - networking.firewall = lib.mkMerge [ - (mkIf cfg.remotePlay.openFirewall { - allowedTCPPorts = [ 27036 ]; - allowedUDPPortRanges = [{ from = 27031; to = 27036; }]; - }) - - (mkIf cfg.dedicatedServer.openFirewall { - allowedTCPPorts = [ 27015 ]; # SRCDS Rcon port - allowedUDPPorts = [ 27015 ]; # Gameplay traffic - }) - ]; - }) - ]; -} diff --git a/modules/vendored/steam.nix b/modules/vendored/steam.nix new file mode 100644 index 0000000..4a73bb3 --- /dev/null +++ b/modules/vendored/steam.nix @@ -0,0 +1,239 @@ +{ config, lib, pkgs, ... }: + +let + cfg = config.programs.steam; + gamescopeCfg = config.programs.gamescope; + + extraCompatPaths = lib.makeSearchPathOutput "steamcompattool" "" cfg.extraCompatPackages; + + steam-gamescope = + let + exports = builtins.attrValues (builtins.mapAttrs (n: v: "export ${n}=${v}") cfg.gamescopeSession.env); + in + pkgs.writeShellScriptBin "steam-gamescope" '' + ${builtins.concatStringsSep "\n" exports} + gamescope --steam ${builtins.toString cfg.gamescopeSession.args} -- steam -tenfoot -pipewire-dmabuf + ''; + + gamescopeSessionFile = + (pkgs.writeTextDir "share/wayland-sessions/steam.desktop" '' + [Desktop Entry] + Name=Steam + Comment=A digital distribution platform + Exec=${steam-gamescope}/bin/steam-gamescope + Type=Application + '').overrideAttrs (_: { passthru.providedSessions = [ "steam" ]; }); +in +{ + disabledModules = [ "programs/steam.nix" ]; + + options.programs.steam = { + enable = lib.mkEnableOption "steam"; + + package = lib.mkOption { + type = lib.types.package; + default = pkgs.steam; + defaultText = lib.literalExpression "pkgs.steam"; + example = lib.literalExpression '' + pkgs.steam-small.override { + extraEnv = { + MANGOHUD = true; + OBS_VKCAPTURE = true; + RADV_TEX_ANISO = 16; + }; + extraLibraries = p: with p; [ + atk + ]; + } + ''; + apply = steam: steam.override (prev: { + extraEnv = (lib.optionalAttrs (cfg.extraCompatPackages != [ ]) { + STEAM_EXTRA_COMPAT_TOOLS_PATHS = extraCompatPaths; + }) // (lib.optionalAttrs cfg.extest.enable { + LD_PRELOAD = "${pkgs.pkgsi686Linux.extest}/lib/libextest.so"; + }) // (prev.extraEnv or { }); + extraLibraries = pkgs: + let + prevLibs = if prev ? extraLibraries then prev.extraLibraries pkgs else [ ]; + additionalLibs = with config.hardware.graphics; + if pkgs.stdenv.hostPlatform.is64bit + then [ package ] ++ extraPackages + else [ package32 ] ++ extraPackages32; + in + prevLibs ++ additionalLibs; + extraPkgs = p: (cfg.extraPackages ++ lib.optionals (prev ? extraPkgs) (prev.extraPkgs p)); + } // lib.optionalAttrs (cfg.gamescopeSession.enable && gamescopeCfg.capSysNice) + { + buildFHSEnv = pkgs.buildFHSEnv.override { + # use the setuid wrapped bubblewrap + bubblewrap = "${config.security.wrapperDir}/.."; + }; + }); + description = '' + The Steam package to use. Additional libraries are added from the system + configuration to ensure graphics work properly. + + Use this option to customise the Steam package rather than adding your + custom Steam to {option}`environment.systemPackages` yourself. + ''; + }; + + extraPackages = lib.mkOption { + type = lib.types.listOf lib.types.package; + default = [ ]; + example = lib.literalExpression '' + with pkgs; [ + gamescope + ] + ''; + description = '' + Additional packages to add to the Steam environment. + ''; + }; + + extraCompatPackages = lib.mkOption { + type = lib.types.listOf lib.types.package; + default = [ ]; + example = lib.literalExpression '' + with pkgs; [ + proton-ge-bin + ] + ''; + description = '' + Extra packages to be used as compatibility tools for Steam on Linux. Packages will be included + in the `STEAM_EXTRA_COMPAT_TOOLS_PATHS` environmental variable. For more information see + https://github.com/ValveSoftware/steam-for-linux/issues/6310. + + These packages must be Steam compatibility tools that have a `steamcompattool` output. + ''; + }; + + fontPackages = lib.mkOption { + type = lib.types.listOf lib.types.package; + # `fonts.packages` is a list of paths now, filter out which are not packages + default = builtins.filter lib.types.package.check config.fonts.packages; + defaultText = lib.literalExpression "builtins.filter lib.types.package.check config.fonts.packages"; + example = lib.literalExpression "with pkgs; [ source-han-sans ]"; + description = '' + Font packages to use in Steam. + + Defaults to system fonts, but could be overridden to use other fonts — useful for users who would like to customize CJK fonts used in Steam. According to the [upstream issue](https://github.com/ValveSoftware/steam-for-linux/issues/10422#issuecomment-1944396010), Steam only follows the per-user fontconfig configuration. + ''; + }; + + remotePlay.openFirewall = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Open ports in the firewall for Steam Remote Play. + ''; + }; + + dedicatedServer.openFirewall = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Open ports in the firewall for Source Dedicated Server. + ''; + }; + + localNetworkGameTransfers.openFirewall = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Open ports in the firewall for Steam Local Network Game Transfers. + ''; + }; + + gamescopeSession = lib.mkOption { + description = "Run a GameScope driven Steam session from your display-manager"; + default = { }; + type = lib.types.submodule { + options = { + enable = lib.mkEnableOption "GameScope Session"; + args = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; + description = '' + Arguments to be passed to GameScope for the session. + ''; + }; + + env = lib.mkOption { + type = lib.types.attrsOf lib.types.str; + default = { }; + description = '' + Environmental variables to be passed to GameScope for the session. + ''; + }; + }; + }; + }; + + extest.enable = lib.mkEnableOption '' + Load the extest library into Steam, to translate X11 input events to + uinput events (e.g. for using Steam Input on Wayland) + ''; + + protontricks = { + enable = lib.mkEnableOption "protontricks, a simple wrapper for running Winetricks commands for Proton-enabled games"; + package = lib.mkPackageOption pkgs "protontricks" { }; + }; + }; + + config = lib.mkIf cfg.enable { + hardware.graphics = { + # this fixes the "glXChooseVisual failed" bug, context: https://github.com/NixOS/nixpkgs/issues/47932 + enable = true; + enable32Bit = true; + }; + + security.wrappers = lib.mkIf (cfg.gamescopeSession.enable && gamescopeCfg.capSysNice) { + # needed or steam fails + bwrap = { + owner = "root"; + group = "root"; + source = "${pkgs.bubblewrap}/bin/bwrap"; + setuid = true; + }; + }; + + programs.steam.extraPackages = cfg.fontPackages; + + programs.gamescope.enable = lib.mkDefault cfg.gamescopeSession.enable; + services.displayManager.sessionPackages = lib.mkIf cfg.gamescopeSession.enable [ gamescopeSessionFile ]; + + # optionally enable 32bit pulseaudio support if pulseaudio is enabled + hardware.pulseaudio.support32Bit = config.hardware.pulseaudio.enable; + + hardware.steam-hardware.enable = true; + + home.home.packages = [ + cfg.package + cfg.package.run + ] ++ lib.optional cfg.gamescopeSession.enable steam-gamescope + ++ lib.optional cfg.protontricks.enable (cfg.protontricks.package.override { inherit extraCompatPaths; }); + + networking.firewall = lib.mkMerge [ + (lib.mkIf (cfg.remotePlay.openFirewall || cfg.localNetworkGameTransfers.openFirewall) { + allowedUDPPorts = [ 27036 ]; # Peer discovery + }) + + (lib.mkIf cfg.remotePlay.openFirewall { + allowedTCPPorts = [ 27036 ]; + allowedUDPPortRanges = [{ from = 27031; to = 27035; }]; + }) + + (lib.mkIf cfg.dedicatedServer.openFirewall { + allowedTCPPorts = [ 27015 ]; # SRCDS Rcon port + allowedUDPPorts = [ 27015 ]; # Gameplay traffic + }) + + (lib.mkIf cfg.localNetworkGameTransfers.openFirewall { + allowedTCPPorts = [ 27040 ]; # Data transfers + }) + ]; + }; + + meta.maintainers = lib.teams.steam.members; +}