commit e40d15248908d22041dbea7e3f693972a5913c2f Author: Madeleine Sydney Date: Wed Apr 2 09:41:40 2025 -0600 init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e2f5dd2 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +result \ No newline at end of file diff --git a/README.org b/README.org new file mode 100644 index 0000000..fa8944c --- /dev/null +++ b/README.org @@ -0,0 +1,114 @@ +#+title: tf2-nix +#+author: Madeleine Sydney Ślaga + +tf2-nix provides a framework for configuring [[https://en.wikipedia.org/wiki/Team_Fortress_2][Team Fortress 2]] (TF2), a game that not only allows for, but sometimes demands, a surprising amount of hacking to optimise your experience. User customisations includes anything from essential performance tweaks, to aesthetic changes such as UI overhauls, hit-sounds, and animations, to basic scripting. + +For the practical purposes including easy deployment and version-tracking, as well as "the spiritual purity of configuring computers correctly,"[fn:1] tf2-nix was created. This project's goal is to provide complete configuration, package-management, and, when possible, packages themselves, for TF2. + +* Disclaimers + +** This is an alpha status project + +At the moment, this project should mostly be considered a proof of concept. It is usable, I am using it, but it is pretty bare-bones. I hope to gradually expand this project anon. More packages, modules, all the Nix goodness we're accustomed to. + +Further, I'm not the most experienced Nix user. Expect bad code and unidiomatic interfaces. I encourage you to point out said bad code if you spot it. }:) + +** TF2 is a radioactive zigzagging target + +In my experience, TF2 and Valve software in general [[https://github.com/DeerUwU/deerhud-tf2/pull/15][react]] [[https://github.com/flathub/com.valvesoftware.Steam/issues/1218][very]] [[https://github.com/nix-community/impermanence/issues/165#issuecomment-2529954063][dramatically]][fn:2][fn:3] when prodded with even slightly unorthodox setups. Brace yourself before updating TF2, and never be afraid to open an issue here. + +* Usage + +** TL;DR + +*** As a flake + +Bring in the input, and build your TF2 config as a package: + +#+begin_src nix + { + inputs = { + tf2-nix.url = "path:///home/crumb/src/tf2-nix"; + }; + + outputs = { self, ... }@inputs: + let + system = "x86_64-linux"; + pkgs = import inputs.nixpkgs { inherit system; }; + tf2pkgs = inputs.tf2-nix.packages.${system}; + my-tf2-config = tf2pkgs.mergeTf2Configs (with tf2pkgs; [ + # Your chosen packages. + mastercomfig.presets.medium-low + mastercomfig.addons.flat-mouse + mastercomfig.addons.no-tutorial + mastercomfig.addons.null-canceling-movement + improved-crosshairs + loadouts-script + # If you have a directory with the following structure, you can import + # it here to merge it into your config. + # my-existing-config + # ├── cfg + # │   └── ... + # ├── custom + # │   └── ... + # └── maps + # └── ... + ./my-existing-config + ]); + in { + # ... + }; + } +#+end_src + +The tricky part is installing this package. If you use home-manager and *are not an Impermanence user*, you can install it using ~home.file~: + +#+begin_src nix + ### home.nix + let + # Make sure this is actually where your tf dir lives! + tf-dir = ".local/share/Steam/steamapps/common/Team Fortress 2/tf"; + in { + home.file.${tf-dir} = { + source = my-tf2-config; + recursive = true; + }; + } +#+end_src + +Rebuild your system, and rejoice! + +** Library + +TODO! + +** Packages + +TODO! + +* Contributing + +Don't hesitate to open issues not only for "real issues" (bugs, missing features) but for poor UX, bad code, or anything else. + +* To-do list + +- [ ] Generate a package set from [[https://github.com/mastercomfig/hud-db][hud-db]]. +- [ ] Mastercomfig comfig.app wrapper. +- [ ] VPK builder. +- [ ] Configure launch options (Is this feasible?). +- [ ] A higher-level NixOS/Home-manager module. +- [ ] Tests. +- [ ] Figure out installation for Impermanence users. + +* See also + +- [[https://github.com/spiretf/nix][gh:spiretf/nix, a set of tf2-related nix packages]] + +* Footnotes + +[fn:3] [[file:assets/bind-mount.png]] + +[fn:2] [[file:assets/gamescope.png]] + +[fn:1] [[file:assets/spiritual-purity.webp]] + diff --git a/assets/bind-mount.png b/assets/bind-mount.png new file mode 100644 index 0000000..ca00a11 Binary files /dev/null and b/assets/bind-mount.png differ diff --git a/assets/gamescope.png b/assets/gamescope.png new file mode 100644 index 0000000..8c8fbe5 Binary files /dev/null and b/assets/gamescope.png differ diff --git a/assets/spiritual-purity.webp b/assets/spiritual-purity.webp new file mode 100644 index 0000000..3c70210 Binary files /dev/null and b/assets/spiritual-purity.webp differ diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..dca1b19 --- /dev/null +++ b/flake.lock @@ -0,0 +1,27 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1743568003, + "narHash": "sha256-ZID5T65E8ruHqWRcdvZLsczWDOAWIE7om+vQOREwiX0=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "b7ba7f9f45c5cd0d8625e9e217c28f8eb6a19a76", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..0f39b6a --- /dev/null +++ b/flake.nix @@ -0,0 +1,18 @@ +{ + description = "A Nix framework for configuring Team Fortress 2"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + }; + + outputs = { self, ... }@inputs: + let + system = "x86_64-linux"; + pkgs = import inputs.nixpkgs { inherit system; }; + lib = pkgs.lib; + in { + packages.x86_64-linux = import ./tf2/packages { + inherit pkgs lib; + }; + }; +} diff --git a/tf2/mkTf2Config.nix b/tf2/mkTf2Config.nix new file mode 100644 index 0000000..38e993e --- /dev/null +++ b/tf2/mkTf2Config.nix @@ -0,0 +1,30 @@ +{ runCommand, lib }: + +{ pname +, version ? null +, custom ? [] +, cfg ? [] +, maps ? [] +# Extra arguments to pass to stdenv.mkDerivation. +, env ? {} +}@args: + +let + version-suffix = lib.optionalString (version != null) "-${version}"; + name = pname + version-suffix; + + make-output = output: var: + lib.optionalString (var != []) '' + mkdir -p "$out/${output}" + ${lib.toShellVar "outputList_${output}" var} + for i in "''${outputList_${output}[@]}"; do + ln -s "$i" "$out/${output}/$(basename "$i")" + done + ''; +in runCommand name env '' + set -xe + mkdir -p $out + ${make-output "cfg" cfg} + ${make-output "custom" custom} + ${make-output "maps" maps} +'' diff --git a/tf2/packages/default.nix b/tf2/packages/default.nix new file mode 100644 index 0000000..391c003 --- /dev/null +++ b/tf2/packages/default.nix @@ -0,0 +1,42 @@ +{ pkgs, lib }: + +let + mkTf2Config = pkgs.callPackage ../mkTf2Config.nix {}; + + fetchFromGameBanana = + { id + , hash + }: + pkgs.fetchzip { + url = "https://gamebanana.com/dl/${id}"; + extension = "zip"; + inherit hash; + }; + + mkCfg = name: body: + pkgs.runCommand name {} '' + ${lib.toShellVar "name" name} + mkdir -p $out/cfg "$(dirname "$out/cfg/$name")" + tee "$out/cfg/$name.cfg" << SUPER_UNIQUE_EOF + // Generated by tf2.nix + + ${body} + SUPER_UNIQUE_EOF + ''; + + mergeTf2Configs = configs: + pkgs.symlinkJoin { + name = "merged-tf2-config"; + paths = configs; + }; + + extra-args = { + inherit mkTf2Config fetchFromGameBanana mkCfg mergeTf2Configs; + }; +in lib.mergeAttrsList [ + extra-args + { mastercomfig = pkgs.callPackage ./mastercomfig.nix extra-args; } + (pkgs.callPackage ./huds.nix extra-args) + (pkgs.callPackage ./misc.nix extra-args) + (pkgs.callPackage ./scripts.nix extra-args) +] diff --git a/tf2/packages/huds.nix b/tf2/packages/huds.nix new file mode 100644 index 0000000..42a3f25 --- /dev/null +++ b/tf2/packages/huds.nix @@ -0,0 +1,16 @@ +{ fetchFromGitHub, mkTf2Config, ... }: + +{ + deerhud = mkTf2Config { + pname = "deerhud"; + custom = [ + (fetchFromGitHub { + name = "deerhud"; + owner = "DeerUwU"; + repo = "deerhud-tf2"; + rev = "78a24effbc66bc78b4bb557228eaa0195db3270c"; + hash = "sha256-uwKRilkEPHk1snjH/n9u32dMXr3cXjYN06cfthpZe7g="; + }) + ]; + }; +} diff --git a/tf2/packages/mastercomfig.nix b/tf2/packages/mastercomfig.nix new file mode 100644 index 0000000..ff98211 --- /dev/null +++ b/tf2/packages/mastercomfig.nix @@ -0,0 +1,117 @@ +{ fetchurl +, mkTf2Config +, ... +}: + +let + mastercomfigVersion = "9.10.3"; + + releasesUrl = version: + "https://github.com/mastercomfig/mastercomfig/releases/download/${version}"; + + fetchMastercomfig = { version, file, hash }: + fetchurl { + url = "${releasesUrl version}/${file}"; + inherit hash; + }; + + mkMastercomfig = + type: + { name + , hash + , file ? "mastercomfig-${name}-${type}.vpk" + , version ? mastercomfigVersion + }: + mkTf2Config { + pname = "mastercomfig-${name}-${type}"; + inherit version; + custom = [ + (fetchMastercomfig { + inherit version file hash; + }) + ]; + }; + + mkMastercomfigAddon = mkMastercomfig "addon"; + mkMastercomfigPreset = mkMastercomfig "preset"; +in { + addons.disable-pyroland = mkMastercomfigAddon { + name = "disable-pyroland"; + hash = "sha256-cEFaXSXwlHwm7BnkSLmG4vAPYhL1O0XwNG0UpTnDFY8="; + }; + + addons.flat-mouse = mkMastercomfigAddon { + name = "flat-mouse"; + hash = "sha256-v2Url+m8dzXIrs8mz5VZWRqwqSSaxyH7t2vDvT10cdg="; + }; + + presets.high = mkMastercomfigPreset { + name = "high"; + hash = "sha256-704aEg1Gyl5vI6Y6VTmlUEiP70PjrF6/VlxsrkkepWs="; + }; + + presets.low = mkMastercomfigPreset { + name = "low"; + hash = "sha256-CpIbjy1dzNCEa583DthygkIQ5aq7Wp2QOJGANC2IGNs="; + }; + + addons.lowmem = mkMastercomfigAddon { + name = "lowmem"; + hash = "sha256-21iyJ4Zg+p5qES05FP2fMO7/p3YrrIkNp2GM2oEjT4E="; + }; + + presets.medium-high = mkMastercomfigPreset { + name = "medium-high"; + hash = "sha256-pS1KcFxxB/oT9DcopZyu77nr4td6x2mDrEFVNOPmtws="; + }; + + presets.medium-low = mkMastercomfigPreset { + name = "medium-low"; + hash = "sha256-P9Zk9IZVpX1hkAcdpNvKfzP2P+TDPNRwwv4I8uM+WU4="; + }; + + presets.medium = mkMastercomfigPreset { + name = "medium"; + hash = "sha256-yEcxPkU/0vJn7vy3n2ViYdTCBV3O9gX57fMQQZYlm3I="; + }; + + addons.no-footsteps = mkMastercomfigAddon { + name = "no-footsteps"; + hash = "sha256-7WIWwV2PnwRM79I7vOdfRggQi/NUS+6GHkAAyo8ap2I="; + }; + + addons.no-soundscapes = mkMastercomfigAddon { + name = "no-soundscapes"; + hash = "sha256-Qp7QW9zZXpX7zrK+Fmpf428lU7Mc86sMn6+5Syhnxz0="; + }; + + addons.no-tutorial = mkMastercomfigAddon { + name = "no-tutorial"; + hash = "sha256-sA3kN2iNe5bwh+954ef+sV0hjMdMZLs6IPgsHDi5oXE="; + }; + + presets.none = mkMastercomfigPreset { + name = "none"; + hash = "sha256-FQ8o4fxUkIAqlFPZPULScwDBaQjc88NiO579IaFTikA="; + }; + + addons.null-canceling-movement = mkMastercomfigAddon { + name = "null-canceling-movement"; + hash = "sha256-B3pHn80lMRN4q5hF/JSAdzDLTnyh7MNbYzMURrYmXxU="; + }; + + addons.transparent-viewmodels = mkMastercomfigAddon { + name = "transparent-viewmodels"; + hash = "sha256-nsUBSsGHXM+xwecixZvhisbifLqkqSyF7kIkJFmq6ow="; + }; + + presets.ultra = mkMastercomfigPreset { + name = "ultra"; + hash = "sha256-VfSFxRuZtYLuNrtX6X7BEMtL6wMbFyela7zbmZurlCw="; + }; + + presets.very-low = mkMastercomfigPreset { + name = "very-low"; + hash = "sha256-faGnju5aPovl++kAh2HNkkroUoMz9/Fx6kSgb3IBRfg="; + }; +} diff --git a/tf2/packages/misc.nix b/tf2/packages/misc.nix new file mode 100644 index 0000000..12f5da4 --- /dev/null +++ b/tf2/packages/misc.nix @@ -0,0 +1,13 @@ +{ fetchFromGameBanana, mkTf2Config, ... }: + +{ + improved-crosshairs = mkTf2Config { + pname = "improved-crosshairs"; + custom = [ + (fetchFromGameBanana { + id = "1047153"; + hash = "sha256-ULcSfxuiGY1YCE1zQ693183F7ZRC11tYhvDMJKyzL1A="; + }) + ]; + }; +} diff --git a/tf2/packages/scripts.nix b/tf2/packages/scripts.nix new file mode 100644 index 0000000..ee25089 --- /dev/null +++ b/tf2/packages/scripts.nix @@ -0,0 +1,14 @@ +{ fetchurl, mkTf2Config, ... }: + +{ + loadouts-script = mkTf2Config rec { + pname = "tf2-loadouts-script"; + version = "3.1"; + custom = [ + (fetchurl { + url = "https://github.com/jooonior/tf2-loadouts-script/releases/download/v${version}/loadouts.vpk"; + hash = "sha256-qMDQe/lLZz5YdH6kvG7vNKHUxPvId4AMqu/hFqr/Sd8="; + }) + ]; + }; +}