1 { lib, stdenv, fetchurl, makeWrapper, makeDesktopItem
2 , alsa-lib, libpulseaudio, libX11, libXcursor, libXinerama, libXrandr, libXi, libGL
3 , libSM, libICE, libXext, factorio-utils
6 , username ? "", token ? "" # get/reset token at https://factorio.com/profile
7 , experimental ? false # true means to always use the latest branch
10 assert releaseType == "alpha"
11 || releaseType == "headless"
12 || releaseType == "demo";
16 inherit (lib) importJSON;
21 Please ensure you have set the username and token with config.nix, or
22 /etc/nix/nixpkgs-config.nix if on NixOS.
24 Your token can be seen at https://factorio.com/profile (after logging in). It is
25 not as sensitive as your password, but should still be safeguarded. There is a
26 link on that page to revoke/invalidate the token, if you believe it has been
27 leaked or wish to take precautions.
31 packageOverrides = pkgs: {
32 factorio = pkgs.factorio.override {
33 username = "FactorioPlayer1654";
34 token = "d5ad5a8971267c895c0da598688761";
39 Alternatively, instead of providing the username+token, you may manually
40 download the release through https://factorio.com/download , then add it to
45 nix-prefetch-url file://\''$HOME/Downloads/factorio_\''${releaseType}_x64_\''${version}.tar.xz --name factorio_\''${releaseType}_x64-\''${version}.tar.xz
47 Note the ultimate "_" is replaced with "-" in the --name arg!
50 desktopItem = makeDesktopItem {
52 desktopName = "Factorio";
53 comment = "A game in which you build and maintain factories.";
56 categories = [ "Game" ];
59 branch = if experimental then "experimental" else "stable";
61 # NB `experimental` directs us to take the latest build, regardless of its branch;
62 # hence the (stable, experimental) pairs may sometimes refer to the same distributable.
63 versions = importJSON ./versions.json;
64 binDists = makeBinDists versions;
66 actual = binDists.${stdenv.hostPlatform.system}.${releaseType}.${branch} or (throw "Factorio ${releaseType}-${branch} binaries for ${stdenv.hostPlatform.system} are not available for download.");
68 makeBinDists = versions:
69 let f = path: name: value:
70 if builtins.isAttrs value then
71 if value ? "name" then
74 builtins.mapAttrs (f (path ++ [ name ])) value
76 throw "expected attrset at ${toString path} - got ${toString value}";
78 builtins.mapAttrs (f []) versions;
79 makeBinDist = { name, version, tarDirectory, url, sha256, needsAuth }: {
80 inherit version tarDirectory;
83 fetchurl { inherit name url sha256; }
85 (lib.overrideDerivation
87 inherit name url sha256;
90 "--data-urlencode" "username@username"
91 "--data-urlencode" "token@token"
94 (_: { # This preHook hides the credentials from /proc
96 if username != "" && token != "" then ''
97 echo -n "${username}" >username
98 echo -n "${token}" >token
100 # Deliberately failing since username/token was not provided, so we can't fetch.
101 # We can't use builtins.throw since we want the result to be used if the tar is in the store already.
113 use-system-read-write-data-directories=false
115 read-data=$out/share/factorio/data/
122 if [[ -e ~/.factorio/config.cfg ]]; then
123 # Config file exists, but may have wrong path.
124 # Try to edit it. I'm sure this is perfectly safe and will never go wrong.
125 sed -i 's|^read-data=.*|read-data=$out/share/factorio/data/|' ~/.factorio/config.cfg
127 # Config file does not exist. Phew.
128 install -D $out/share/factorio/config-base.cfg ~/.factorio/config.cfg
132 modDir = factorio-utils.mkModDirDrv mods;
134 base = with actual; {
135 pname = "factorio-${releaseType}";
138 preferLocalBuild = true;
142 mkdir -p $out/{bin,share/factorio}
143 cp -a data $out/share/factorio
144 cp -a bin/${tarDirectory}/factorio $out/bin/factorio
146 --set-interpreter $(cat $NIX_CC/nix-support/dynamic-linker) \
150 passthru.updateScript = if (username != "" && token != "") then [
151 ./update.py "--username=${username}" "--token=${token}"
155 description = "A game in which you build and maintain factories";
157 Factorio is a game in which you build and maintain factories.
159 You will be mining resources, researching technologies, building
160 infrastructure, automating production and fighting enemies. Use your
161 imagination to design your factory, combine simple elements into
162 ingenious structures, apply management skills to keep it working and
163 finally protect it from the creatures who don't really like you.
165 Factorio has been in development since spring of 2012, and reached
166 version 1.0 in mid 2020.
168 homepage = "https://www.factorio.com/";
169 sourceProvenance = with lib.sourceTypes; [ binaryNativeCode ];
170 license = lib.licenses.unfree;
171 maintainers = with lib.maintainers; [ Baughn elitak erictapen priegger lukegb ];
172 platforms = [ "x86_64-linux" ];
180 nativeBuildInputs = [ makeWrapper ];
181 buildInputs = [ libpulseaudio ];
183 libPath = lib.makeLibraryPath [
197 installPhase = base.installPhase + ''
198 wrapProgram $out/bin/factorio \
199 --prefix LD_LIBRARY_PATH : /run/opengl-driver/lib:$libPath \
200 --run "$out/share/factorio/update-config.sh" \
202 --add-flags "-c \$HOME/.factorio/config.cfg" \
203 ${if mods!=[] then "--add-flags --mod-directory=${modDir}" else ""}
205 # TODO Currently, every time a mod is changed/added/removed using the
206 # modlist, a new derivation will take up the entire footprint of the
207 # client. The only way to avoid this is to remove the mods arg from the
208 # package function. The modsDir derivation will have to be built
209 # separately and have the user specify it in the .factorio config or
210 # right along side it using a symlink into the store I think i will
211 # just remove mods for the client derivation entirely. this is much
212 # cleaner and more useful for headless mode.
214 # TODO: trying to toggle off a mod will result in read-only-fs-error.
215 # not much we can do about that except warn the user somewhere. In
216 # fact, no exit will be clean, since this error will happen on close
217 # regardless. just prints an ugly stacktrace but seems to be otherwise
218 # harmless, unless maybe the user forgets and tries to use the mod
221 install -m0644 <(cat << EOF
224 ) $out/share/factorio/config-base.cfg
226 install -m0755 <(cat << EOF
229 ) $out/share/factorio/update-config.sh
231 mkdir -p $out/share/icons/hicolor/{64x64,128x128}/apps
232 cp -a data/core/graphics/factorio-icon.png $out/share/icons/hicolor/64x64/apps/factorio.png
233 cp -a data/core/graphics/factorio-icon@2x.png $out/share/icons/hicolor/128x128/apps/factorio.png
234 ln -s ${desktopItem}/share/applications $out/share/
239 installPhase = demo.installPhase + ''
240 cp -a doc-html $out/share/factorio
245 in stdenv.mkDerivation (releases.${releaseType})