diff options
Diffstat (limited to 'pkgs')
-rw-r--r-- | pkgs/games/build-support/default.nix | 1 | ||||
-rw-r--r-- | pkgs/games/build-support/monogame-patcher/default.nix | 31 | ||||
-rw-r--r-- | pkgs/games/build-support/monogame-patcher/patcher.cs | 109 | ||||
-rw-r--r-- | pkgs/games/itch/towerfall-ascension.nix | 100 |
4 files changed, 147 insertions, 94 deletions
diff --git a/pkgs/games/build-support/default.nix b/pkgs/games/build-support/default.nix index 8e227afc..1832f987 100644 --- a/pkgs/games/build-support/default.nix +++ b/pkgs/games/build-support/default.nix @@ -5,4 +5,5 @@ withPulseAudio = config.pulseaudio or true; }; buildUnity = callPackage ./build-unity.nix {}; + monogamePatcher = callPackage ./monogame-patcher {}; } diff --git a/pkgs/games/build-support/monogame-patcher/default.nix b/pkgs/games/build-support/monogame-patcher/default.nix new file mode 100644 index 00000000..fffa6825 --- /dev/null +++ b/pkgs/games/build-support/monogame-patcher/default.nix @@ -0,0 +1,31 @@ +{ lib, runCommand, makeWrapper, fetchNuGet, mono, dotnetPackages }: + +runCommand "monogame-patcher" { + nativeBuildInputs = [ mono makeWrapper ]; + + src = ./patcher.cs; + + cecil = "${fetchNuGet { + baseName = "Mono.Cecil"; + version = "0.10-beta7"; + sha256 = "03bina3llcnylrfrvp5psnwrfn757j7zch5r360rpdn7gmcjjcpl"; + outputFiles = [ "lib/net40/*" ]; + }}/lib/dotnet/Mono.Cecil"; + + cliparser = "${fetchNuGet { + baseName = "CommandLineParser"; + version = "2.2.1"; + sha256 = "0wf8mzr16d2ni008m60rrk738v8ypk74llk6g8mlyx7rrlchnxaf"; + outputFiles = [ "lib/net45/*" ]; + }}/lib/dotnet/CommandLineParser"; + +} '' + mkdir -p "$out/bin" "$out/libexec/monogame-patcher" + mcs "$src" -out:"$out/libexec/monogame-patcher/patcher.exe" \ + -lib:"$cecil" -lib:"$cliparser" \ + -r:Mono.Cecil -r:Mono.Cecil.Rocks -r:CommandLine + + makeWrapper ${lib.escapeShellArg "${mono}/bin/mono"} "$out/bin/$name" \ + --set MONO_PATH "$cecil:$cliparser" \ + --add-flags "$out/libexec/monogame-patcher/patcher.exe" +'' diff --git a/pkgs/games/build-support/monogame-patcher/patcher.cs b/pkgs/games/build-support/monogame-patcher/patcher.cs new file mode 100644 index 00000000..16878831 --- /dev/null +++ b/pkgs/games/build-support/monogame-patcher/patcher.cs @@ -0,0 +1,109 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System; + +using Mono.Cecil.Cil; +using Mono.Cecil.Rocks; +using Mono.Cecil; + +using CommandLine; + +class GenericOptions +{ + [Option('i', "infile", Required=true, HelpText="Input file to transform.")] + public string inputFile { get; set; } + [Option('o', "outfile", HelpText="File to write transformed data to.")] + public string outputFile { get; set; } +} + +class Command { + protected string infile; + protected string outfile; + protected ModuleDefinition module; + + public Command(GenericOptions options) { + if (options.outputFile == null) + this.outfile = options.inputFile; + else + this.outfile = options.outputFile; + this.infile = options.inputFile; + + var rp = new ReaderParameters { + ReadWrite = this.infile == this.outfile + }; + this.module = ModuleDefinition.ReadModule(this.infile, rp); + } + + public void save() { + if (this.outfile == this.infile) + this.module.Write(); + else + this.module.Write(this.outfile); + } +} + +[Verb("fix-filestreams", HelpText="Fix System.IO.FileStream constructors" + +" to open files read-only.")] +class FixFileStreamsCmd : GenericOptions { + [Value(0, Required=true, MetaName = "type", HelpText = "Types to patch.")] + public IEnumerable<string> typesToPatch { get; set; } +}; + +class FixFileStreams : Command { + public FixFileStreams(FixFileStreamsCmd options) : base(options) { + var filtered = this.module.Types + .Where(p => options.typesToPatch.Contains(p.Name)); + + foreach (var toPatch in filtered) + patch_type(toPatch); + + this.save(); + } + + private void patch_method(MethodDefinition md) { + var il = md.Body.GetILProcessor(); + + var fileStreams = md.Body.Instructions + .Where(i => i.OpCode == OpCodes.Newobj) + .Where(i => (i.Operand as MethodReference).DeclaringType + .FullName == "System.IO.FileStream"); + + foreach (Instruction i in fileStreams.ToList()) { + var fileAccessRead = il.Create(OpCodes.Ldc_I4_1); + il.InsertBefore(i, fileAccessRead); + + var ctorType = this.module.AssemblyReferences.Select( + x => new { + type = this.module.AssemblyResolver.Resolve(x) + .MainModule.GetType("System.IO.FileStream") + } + ).Where(x => x.type != null).Select(x => x.type).First(); + + string wantedCtor = "System.Void System.IO.FileStream" + + "::.ctor(System.String," + + "System.IO.FileMode," + + "System.IO.FileAccess)"; + + var newCtor = ctorType.GetConstructors() + .Single(x => x.ToString() == wantedCtor); + + var refCtor = this.module.ImportReference(newCtor); + il.Replace(i, il.Create(OpCodes.Newobj, refCtor)); + } + } + + private void patch_type(TypeDefinition td) { + foreach (var nested in td.NestedTypes) patch_type(nested); + foreach (MethodDefinition md in td.Methods) patch_method(md); + } +} + +public class patcher { + + public static int Main(string[] args) { + Parser.Default.ParseArguments<GenericOptions, FixFileStreamsCmd>(args) + .WithParsed<FixFileStreamsCmd>(opts => new FixFileStreams(opts)); + return 0; + } +} diff --git a/pkgs/games/itch/towerfall-ascension.nix b/pkgs/games/itch/towerfall-ascension.nix index a4ba5abf..21704211 100644 --- a/pkgs/games/itch/towerfall-ascension.nix +++ b/pkgs/games/itch/towerfall-ascension.nix @@ -1,94 +1,11 @@ { stdenv, lib, buildGame, fetchItch, makeWrapper, p7zip, unzip, mono50 -, SDL2, SDL2_image, libGL, libvorbis, openal - -, writeScriptBin, coreutils -, fetchNuGet, writeText +, SDL2, SDL2_image, libGL, libvorbis, openal, monogamePatcher, writeScriptBin +, coreutils , darkWorldExpansion ? true }: -let - cecil = fetchNuGet { - baseName = "Mono.Cecil"; - version = "0.10-beta7"; - sha256 = "03bina3llcnylrfrvp5psnwrfn757j7zch5r360rpdn7gmcjjcpl"; - outputFiles = [ "lib/net40/*" ]; - }; - - # We need to patch a few occurences of System.IO.FileStream which are used - # with the default arguments for FileAccess. The defaults open the file in - # read-write mode and given that all the game data files are in the read-only - # Nix store, we'd get an UnauthorizedAccessException. - patcher = writeText "patcher.cs" '' - using System.Linq; - using System.Collections.Generic; - using Mono.Cecil; - using Mono.Cecil.Cil; - using Mono.Cecil.Rocks; - - public class patcher { - private ModuleDefinition module; - - private patcher(List<string> typesToPatch) { - this.module = ModuleDefinition.ReadModule("TowerFall.exe"); - - var filtered = this.module.Types - .Where(p => typesToPatch.Contains(p.Name)); - - foreach (var toPatch in filtered) { - patch_class(toPatch); - } - - this.module.Write("TowerFallPatched.exe"); - } - - private void patch_method(MethodDefinition md) { - var il = md.Body.GetILProcessor(); - - var fileStreams = md.Body.Instructions - .Where(i => i.OpCode == OpCodes.Newobj) - .Where(i => (i.Operand as MethodReference).DeclaringType - .FullName == "System.IO.FileStream"); - - foreach (Instruction i in fileStreams.ToList()) { - var fileAccessRead = il.Create(OpCodes.Ldc_I4_1); - il.InsertBefore(i, fileAccessRead); - - var ctorType = this.module.AssemblyReferences.Select( - x => new { - type = this.module.AssemblyResolver.Resolve(x) - .MainModule.GetType("System.IO.FileStream") - } - ).Where(x => x.type != null).Select(x => x.type).First(); - - string wantedCtor = "System.Void System.IO.FileStream" - + "::.ctor(System.String," - + "System.IO.FileMode," - + "System.IO.FileAccess)"; - - var newCtor = ctorType.GetConstructors() - .Single(x => x.ToString() == wantedCtor); - - var refCtor = this.module.ImportReference(newCtor); - il.Replace(i, il.Create(OpCodes.Newobj, refCtor)); - } - } - - private void patch_class(TypeDefinition td) { - foreach (var nested in td.NestedTypes) patch_class(nested); - foreach (MethodDefinition md in td.Methods) patch_method(md); - } - - public static void Main() { - var typesToPatch = new List<string>() { - "Texture", "IntroScene", "SFX", "SFXVaried" - }; - new patcher(typesToPatch); - } - } - ''; - -in buildGame rec { +buildGame rec { name = "towerfall-ascension-${version}"; version = "20160723"; @@ -113,16 +30,11 @@ in buildGame rec { ''; patchPhase = '' - { export MONO_PATH=${cecil}/lib/dotnet/Mono.Cecil - mcs ${lib.escapeShellArg patcher} -out:patcher \ - -lib:${cecil}/lib/dotnet/Mono.Cecil \ - -r:Mono.Cecil -r:Mono.Cecil.Rocks - mono patcher - mv TowerFallPatched.exe TowerFall.exe - } + monogame-patcher fix-filestreams -i TowerFall.exe \ + Texture IntroScene SFX SFXVaried ''; - nativeBuildInputs = [ makeWrapper mono50 ]; + nativeBuildInputs = [ makeWrapper mono50 monogamePatcher ]; libdir = if stdenv.system == "x86_64-linux" then "lib64" else "lib"; |