From 66b2c599594ffd46413c96da41aeb95555941bf2 Mon Sep 17 00:00:00 2001 From: aszlig Date: Mon, 8 Feb 2016 17:04:35 +0100 Subject: Add support for fetching non-DRM Steam games Thanks to the folks at @SteamRE there is a reverse-engineered Steam library and a downloader for Steam depots. The downloader actually uses mcbyte-it/DepotDownloader@5fa6621 which is a fork that has added proper exit codes. We also patch the downloader to show the latest manifest ID, so we can check whether we're up to date. The reason we're pinning the manifest ID is that we make sure that the SHA256 will always match, no matter whether there is a new upstream version or not. Obviously the whole steam/ namespace is only for Steam games that can run without Steam, which in turn is the entire purpose of it. For a list of Steam games without DRM, have a look at: http://steam.wikia.com/wiki/List_of_DRM-free_games Also if you want to look up the depotId or appId, this is a good resource: https://steamdb.info/ Signed-off-by: aszlig --- default.nix | 2 +- steam/default.nix | 35 +++++++++++++++ steam/fetchsteam/default.nix | 91 +++++++++++++++++++++++++++++++++++++++ steam/fetchsteam/downloader.patch | 34 +++++++++++++++ 4 files changed, 161 insertions(+), 1 deletion(-) create mode 100644 steam/default.nix create mode 100644 steam/fetchsteam/default.nix create mode 100644 steam/fetchsteam/downloader.patch diff --git a/default.nix b/default.nix index 80420a8b..d85bd191 100644 --- a/default.nix +++ b/default.nix @@ -20,6 +20,6 @@ let in ((import ).evalModules { modules = [ (if configuration == null then configFilePath else configuration) - ./base-module.nix ./humblebundle + ./base-module.nix ./humblebundle ./steam ]; }).config.packages diff --git a/steam/default.nix b/steam/default.nix new file mode 100644 index 00000000..84e8669c --- /dev/null +++ b/steam/default.nix @@ -0,0 +1,35 @@ +{ config, lib, pkgs, ... }: + +let + cfg = config.steam; + + self = rec { + callPackage = pkgs.lib.callPackageWith (pkgs // self); + + fetchSteam = callPackage ./fetchsteam { + inherit (config.steam) username password; + }; + }; +in with lib; { + options.steam = { + username = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + User name for your Steam account. + ''; + }; + + password = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Password for your Steam account. + ''; + }; + }; + + config.packages = { + steam = mkIf (cfg.username != null && cfg.password != null) self; + }; +} diff --git a/steam/fetchsteam/default.nix b/steam/fetchsteam/default.nix new file mode 100644 index 00000000..cccddb51 --- /dev/null +++ b/steam/fetchsteam/default.nix @@ -0,0 +1,91 @@ +{ stdenv, runCommand, writeText, fetchFromGitHub, buildDotnetPackage +, username, password +}: + +{ name, appId, depotId, manifestId, sha256, fileList ? [] }: + +let + protobuf-net = buildDotnetPackage rec { + baseName = "protobuf-net"; + version = "2.0.0.668"; + + src = fetchFromGitHub { + owner = "mgravell"; + repo = "protobuf-net"; + rev = "r668"; + sha256 = "1060pihqkbr9pd2z6m01d6fsbc9nj56m6y5a0pch9mqdmviv4896"; + }; + + sourceRoot = "${src.name}/${baseName}"; + }; + + SteamKit2 = buildDotnetPackage rec { + baseName = "SteamKit2"; + version = "1.6.4"; + + src = fetchFromGitHub { + owner = "SteamRE"; + repo = "SteamKit"; + rev = "SteamKit_${version}"; + sha256 = "17d7wi2f396qhp4w9sf37lazvsaqws8x071hfis9gv5llv6s7q46"; + }; + + buildInputs = [ protobuf-net ]; + + xBuildFiles = [ "SteamKit2/SteamKit2.sln" ]; + outputFiles = [ "SteamKit2/SteamKit2/bin/Release/*" ]; + }; + + DepotDownloader = buildDotnetPackage rec { + baseName = "DepotDownloader"; + version = "2.1.1git20160207"; + + src = fetchFromGitHub { + owner = "SteamRE"; + repo = baseName; + rev = "5fa6621d9f9448fcd20c974b427a8bd2cb044cb4"; + sha256 = "0vb566d7x1scd96c8ybq6gdbc2cv5jjq453ld458qcvfy587amfn"; + }; + + patches = [ ./downloader.patch ]; + + postPatch = '' + sed -i \ + -e 's/\(<[Rr]eference *[Ii]nclude="[^", ]\+\)[^"]*/\1/g' \ + -e 's,<[Ss]pecific[Vv]ersion>[Tt]rue,,g' \ + DepotDownloader/DepotDownloader.csproj + sed -i -e 's/ version="[^"]*"//g' DepotDownloader/packages.config + ''; + + buildInputs = [ SteamKit2 protobuf-net ]; + + outputFiles = [ "${baseName}/bin/Release/*" ]; + + # UUUGLY, but I don't want to spend a week trying to get this working + # without that nasty wrapper. + makeWrapperArgs = let + mkMono = name: path: "${path}/lib/dotnet/${name}"; + paths = stdenv.lib.mapAttrsToList mkMono { + inherit SteamKit2 protobuf-net; + }; + monoPath = stdenv.lib.concatStringsSep ":" paths; + in [ "--prefix MONO_PATH : \"${monoPath}\"" ]; + }; + + fileListFile = let + content = stdenv.lib.concatStringsSep "\n" fileList; + in writeText "steam-file-list-${name}.txt" content; + +in with stdenv.lib; runCommand "${name}-src" { + buildInputs = [ DepotDownloader ]; + inherit username password appId depotId manifestId; + outputHashAlgo = "sha256"; + outputHash = sha256; + outputHashMode = "recursive"; +} '' + depotdownloader -app "$appId" -depot "$depotId" -manifest "$manifestId" \ + ${optionalString (fileList != []) "-filelist \"${fileListFile}\""} \ + -username "$username" -password "$password" -dir "$out" + rm -r "$out/.DepotDownloader" + rm "$out/_steam_depot_manifest_$depotId.csv" +'' diff --git a/steam/fetchsteam/downloader.patch b/steam/fetchsteam/downloader.patch new file mode 100644 index 00000000..72e5c473 --- /dev/null +++ b/steam/fetchsteam/downloader.patch @@ -0,0 +1,34 @@ +diff --git a/DepotDownloader/ContentDownloader.cs b/DepotDownloader/ContentDownloader.cs +index 21c317e..81f2a93 100644 +--- a/DepotDownloader/ContentDownloader.cs ++++ b/DepotDownloader/ContentDownloader.cs +@@ -34,7 +34,7 @@ namespace DepotDownloader + public string installDir { get; private set; } + public string contentName { get; private set; } + +- public ulong manifestId { get; private set; } ++ public ulong manifestId { get; set; } + public byte[] depotKey; + + public DepotDownloadInfo(uint depotid, ulong manifestId, string installDir, string contentName) +@@ -198,9 +198,6 @@ namespace DepotDownloader + + static ulong GetSteam3DepotManifest(uint depotId, uint appId, string branch) + { +- if (Config.ManifestId != INVALID_MANIFEST_ID) +- return Config.ManifestId; +- + KeyValue depots = GetSteam3AppSection(appId, EAppInfoSection.Depots); + KeyValue depotChild = depots[depotId.ToString()]; + +@@ -583,6 +580,10 @@ namespace DepotDownloader + ConfigStore.TheConfig.LastManifests[depot.id] = INVALID_MANIFEST_ID; + ConfigStore.Save(); + ++ Console.WriteLine("Latest manifest ID is {0}.", depot.manifestId); ++ if (Config.ManifestId != INVALID_MANIFEST_ID) ++ depot.manifestId = Config.ManifestId; ++ + if (lastManifestId != INVALID_MANIFEST_ID) + { + var oldManifestFileName = Path.Combine(configDir, string.Format("{0}.bin", lastManifestId)); -- cgit 1.4.1