diff --git a/.gitignore b/.gitignore index 19ee5f3..4867c4e 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,3 @@ obj/ riderModule.iml /_ReSharper.Caches/ .idea -work \ No newline at end of file diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 822bf2e..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "lib/Il2CppAssemblyUnhollower"] - path = lib/Il2CppAssemblyUnhollower - url = https://github.com/NuclearPowered/Il2CppAssemblyUnhollower diff --git a/AmongUs.props b/AmongUs.props index 1936a08..8d64e39 100644 --- a/AmongUs.props +++ b/AmongUs.props @@ -1,78 +1,14 @@ + + Steam + NuclearPowered/Mappings:0.1.0-alpha.1 + + - - - $(AmongUs)\BepInEx\unhollowed\Assembly-CSharp.dll - False - - - $(AmongUs)\BepInEx\unhollowed\Hazel.dll - False - - - - - $(AmongUs)\BepInEx\core\0Harmony.dll - False - - - $(AmongUs)\BepInEx\core\BepInEx.Core.dll - False - - - $(AmongUs)\BepInEx\core\BepInEx.IL2CPP.dll - False - - - $(AmongUs)\BepInEx\core\SemVer.dll - False - - - - - $(AmongUs)\BepInEx\core\UnhollowerBaseLib.dll - False - - - $(AmongUs)\BepInEx\unhollowed\Il2Cppmscorlib.dll - False - - - $(AmongUs)\BepInEx\unhollowed\Il2CppSystem.Core.dll - False - - - - - $(AmongUs)\BepInEx\unhollowed\UnityEngine.dll - False - - - $(AmongUs)\BepInEx\unhollowed\UnityEngine.CoreModule.dll - False - - - $(AmongUs)\BepInEx\unhollowed\UnityEngine.InputLegacyModule.dll - False - - - $(AmongUs)\BepInEx\unhollowed\UnityEngine.IMGUIModule.dll - False - - - $(AmongUs)\BepInEx\unhollowed\UnityEngine.UI.dll - False - - - $(AmongUs)\BepInEx\unhollowed\UnityEngine.UIModule.dll - False - + - - - - - + + diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 0a04128..0000000 --- a/LICENSE +++ /dev/null @@ -1,165 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - You may place library facilities that are a work based on the -Library side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. diff --git a/README.md b/README.md index c7bbc74..6f84f17 100644 --- a/README.md +++ b/README.md @@ -7,12 +7,3 @@ Featuring amazing features like: - modded handshake - *partially* unstripped IMGUI and UI - a lot of utility methods - -## Reactor.OxygenFilter - -Library for mapping output of Il2cppDumper, used in -[NuclearPowered/Il2CppAssemblyUnhollower](https://github.com/NuclearPowered/Il2CppAssemblyUnhollower) - -## Reactor.Greenhouse - -Standalone program which generates mappings for OxygenFilter diff --git a/Reactor.Greenhouse/Compiler.cs b/Reactor.Greenhouse/Compiler.cs deleted file mode 100644 index 4d22319..0000000 --- a/Reactor.Greenhouse/Compiler.cs +++ /dev/null @@ -1,199 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Text.RegularExpressions; -using Mono.Cecil; -using Reactor.OxygenFilter; - -namespace Reactor.Greenhouse -{ - public static class Compiler - { - public static void Apply(this Mappings current, Mappings mappings) - { - static void ApplyType(List types, MappedType newType) - { - var type = types.SingleOrDefault(x => newType.Equals(x)); - if (type == null) - { - types.Add(newType); - } - else - { - type.Mapped = newType.Mapped; - - void ApplyMembers(List members, List newMembers) - { - foreach (var newMember in newMembers) - { - var member = members.SingleOrDefault(x => newMember.Equals(x, false)); - - if (member == null) - { - members.Add(newMember); - } - else - { - member.Mapped = newMember.Mapped; - member.Original = newMember.Original; - } - } - } - - ApplyMembers(type.Fields, newType.Fields); - ApplyMembers(type.Properties, newType.Properties); - - foreach (var newMember in newType.Methods) - { - var member = type.Methods.SingleOrDefault(x => newMember.Equals(x, false)); - - if (member == null) - { - type.Methods.Add(newMember); - } - else - { - member.Mapped = newMember.Mapped; - member.Original = newMember.Original; - member.Parameters = newMember.Parameters; - } - } - - foreach (var nestedType in newType.Nested) - { - ApplyType(type.Nested, nestedType); - } - } - } - - foreach (var newType in mappings.Types) - { - ApplyType(current.Types, newType); - } - } - - private static Regex Regex { get; } = new Regex(@"{{(?[\w\.]+)}}", RegexOptions.Compiled); - - public static string MapSignature(this OriginalDescriptor original, Mappings mappings) - { - var signature = original.Signature; - - var matches = Regex.Matches(signature); - foreach (Match match in matches) - { - var group = match.Groups["expression"]; - if (group.Success) - { - signature = signature.Replace(match.Value, mappings.FindByMapped(group.Value).Original.Name); - } - } - - return signature; - } - - private static bool TestField(MappedMember field, TypeDefinition typeDef, FieldDefinition fieldDef, Mappings mappings) - { - return (field.Original.Name == null || field.Original.Name == fieldDef.Name) && - (field.Original.Index == null || field.Original.Index == typeDef.Fields.IndexOf(fieldDef)) && - (field.Original.Signature == null || field.Original.MapSignature(mappings) == fieldDef.GetSignature()) && - (field.Original.Const == null || !typeDef.IsEnum && field.Original.Const.Value.Equals(fieldDef.Constant)); - } - - private static bool TestMethod(MappedMember method, TypeDefinition typeDef, MethodDefinition methodDef, Mappings mappings) - { - return (method.Original.Index == null || method.Original.Index == typeDef.Methods.IndexOf(methodDef)) && - (method.Original.Signature == null || method.Original.MapSignature(mappings) == methodDef.GetSignature()) && - (method.Original.Name == null || method.Original.Name == methodDef.Name); - } - - private static bool TestProperty(MappedMember property, TypeDefinition typeDef, PropertyDefinition propertyDef, Mappings mappings) - { - return (property.Original.Name == null || property.Original.Name == propertyDef.Name) && - (property.Original.Index == null || property.Original.Index == typeDef.Properties.IndexOf(propertyDef)) && - (property.Original.Signature == null || property.Original.MapSignature(mappings) == propertyDef.GetSignature()); - } - - private static bool TestType(MappedType type, TypeDefinition typeDef, Mappings mappings) - { - return (type.Original.Name == null || type.Original.Name == typeDef.Name) && - type.Methods.All(method => typeDef.Methods.Any(m => TestMethod(method, typeDef, m, mappings))) && - type.Fields.All(field => typeDef.Fields.Any(f => TestField(field, typeDef, f, mappings))) && - type.Properties.All(property => typeDef.Properties.Any(p => TestProperty(property, typeDef, p, mappings))); - } - - private static void Compile(this MappedType type, TypeDefinition typeDef, Mappings mappings) - { - type.Original = new OriginalDescriptor { Name = typeDef.Name }; - - foreach (var nested in type.Nested) - { - var nestedDef = typeDef.NestedTypes.Single(t => - TestType(type, t, mappings) && - nested.Original.Index == null || typeDef.NestedTypes.IndexOf(t) == nested.Original.Index - ); - - nested.Compile(nestedDef, mappings); - } - - foreach (var property in type.Properties) - { - try - { - var propertyDef = typeDef.Properties.Single(p => TestProperty(property, typeDef, p, mappings)); - - property.Original = new OriginalDescriptor { Name = propertyDef.Name }; - } - catch (Exception e) - { - throw new Exception($"Compilation of {property} failed", e); - } - } - - foreach (var field in type.Fields) - { - try - { - var fieldDef = typeDef.Fields.Single(f => TestField(field, typeDef, f, mappings)); - - field.Original = new OriginalDescriptor { Name = fieldDef.Name }; - } - catch (Exception e) - { - throw new Exception($"Compilation of {field} failed", e); - } - } - - foreach (var method in type.Methods) - { - try - { - var methodDef = typeDef.Methods.Single(m => TestMethod(method, typeDef, m, mappings)); - - method.Original = new OriginalDescriptor { Name = methodDef.Name, Signature = methodDef.GetSignature() }; - } - catch (Exception e) - { - throw new Exception($"Compilation of {method} failed", e); - } - } - } - - public static void Compile(this Mappings mappings, ModuleDefinition moduleDef) - { - foreach (var type in mappings.Types) - { - try - { - var typeDef = moduleDef.Types.Single(t => TestType(type, t, mappings)); - - type.Compile(typeDef, mappings); - } - catch (Exception e) - { - throw new Exception($"Compilation of {type} failed", e); - } - } - } - } -} diff --git a/Reactor.Greenhouse/Extensions.cs b/Reactor.Greenhouse/Extensions.cs deleted file mode 100644 index 0b75195..0000000 --- a/Reactor.Greenhouse/Extensions.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System.Linq; -using Mono.Cecil; - -namespace Reactor.Greenhouse -{ - public static class Extensions - { - public static CustomAttribute GetCustomAttribute(this ICustomAttributeProvider cap, string attribute) - { - if (!cap.HasCustomAttributes) - { - return null; - } - - return cap.CustomAttributes.FirstOrDefault(attrib => attrib.AttributeType.FullName == attribute); - } - - public static uint? GetOffset(this MethodDefinition methodDef) - { - var attribute = methodDef.GetCustomAttribute("Il2CppDummyDll.AddressAttribute"); - if (attribute == null) - return null; - - var offset = attribute.Fields.Single(x => x.Name == "Offset"); - return new System.ComponentModel.UInt32Converter().ConvertFrom(offset) as uint?; - } - } -} diff --git a/Reactor.Greenhouse/Generator.cs b/Reactor.Greenhouse/Generator.cs deleted file mode 100644 index e3ffde1..0000000 --- a/Reactor.Greenhouse/Generator.cs +++ /dev/null @@ -1,138 +0,0 @@ -using System.Linq; -using Mono.Cecil; -using Reactor.OxygenFilter; - -namespace Reactor.Greenhouse -{ - public static class Generator - { - public static Mappings Generate(ModuleDefinition old, ModuleDefinition latest) - { - var result = new Mappings(); - - foreach (var oldType in old.Types) - { - if (oldType.Name.StartsWith("<") || oldType.Namespace.StartsWith("GoogleMobileAds")) - continue; - - void AddType(TypeDefinition type) - { - var mapped = new MappedType(new OriginalDescriptor { Name = type.Name }, oldType.Name); - - var i = 0; - foreach (var field in type.Fields) - { - var j = 0; - var i1 = i; - var oldFields = oldType.Fields.Where(x => j++ == i1 && x.GetSignature().ToString() == field.GetSignature().ToString()).ToArray(); - if (oldFields.Length == 1) - { - var oldField = oldFields.First(); - if (oldField.Name == field.Name || !field.Name.IsObfuscated()) - continue; - - mapped.Fields.Add(new MappedMember(new OriginalDescriptor { Index = i1 }, oldField.Name)); - } - - i++; - } - - foreach (var method in type.Methods) - { - if (!method.HasParameters || method.IsSetter || method.IsGetter) - { - continue; - } - - var oldMethods = oldType.Methods.Where(x => x.Name == method.Name && x.Parameters.Count == method.Parameters.Count).ToArray(); - if (oldMethods.Length != 1) - { - continue; - } - - var oldMethod = oldMethods.Single(); - - var oldParameters = oldMethod.Parameters.Select(x => x.Name).ToList(); - - if (method.Parameters.Select(x => x.Name).SequenceEqual(oldParameters)) - { - continue; - } - - mapped.Methods.Add(new MappedMethod(new OriginalDescriptor { Name = method.Name, Signature = method.GetSignature() }, null) - { - Parameters = oldParameters - }); - } - - if (type.Name == oldType.Name || (!type.Name.IsObfuscated() && !mapped.Fields.Any() && !mapped.Methods.Any())) - { - return; - } - - result.Types.Add(mapped); - } - - var exact = latest.Types.FirstOrDefault(x => x.FullName == oldType.FullName); - if (exact != null) - { - AddType(exact); - continue; - } - - if (oldType.IsEnum) - { - var first = oldType.Fields.Select(x => x.Name).ToArray(); - var type = latest.Types.SingleOrDefault(x => x.IsEnum && x.Fields.Select(f => f.Name).SequenceEqual(first)); - if (type != null) - { - AddType(type); - } - - continue; - } - - static bool Test(TypeReference typeReference) - { - return typeReference.IsGenericParameter || typeReference.Namespace != string.Empty || !typeReference.Name.IsObfuscated(); - } - - var methods = oldType.Methods.Where(x => Test(x.ReturnType) && x.Parameters.All(p => Test(p.ParameterType))).Select(x => x.GetSignature()).ToArray(); - var fields = oldType.Fields.Where(x => Test(x.FieldType) && (!x.FieldType.HasGenericParameters || x.FieldType.GenericParameters.All(Test))).Select(x => x.GetSignature()).ToArray(); - var properties = oldType.Properties.Select(x => x.Name).ToArray(); - - var types = latest.Types - .Where(t => t.Attributes == oldType.Attributes) - .ToArray(); - - TypeDefinition winner = null; - var winnerPoints = -1; - - foreach (var t in types) - { - var points = 0; - points += t.Properties.Count(p => properties.Contains((p.GetMethod?.Name ?? p.SetMethod.Name).Substring(4))); - points += fields.Count(s => t.Fields.Any(f => f.GetSignature().ToString() == s.ToString())); - points += methods.Count(s => t.Methods.Any(m => m.GetSignature().ToString() == s.ToString())); - - if (points > winnerPoints) - { - winnerPoints = points; - winner = t; - } - else if (points == winnerPoints) - { - winner = null; - } - } - - if (winner != null && winnerPoints > 0) - { - AddType(winner); - } - } - - return result; - } - } -} diff --git a/Reactor.Greenhouse/Program.cs b/Reactor.Greenhouse/Program.cs deleted file mode 100644 index a29a8ed..0000000 --- a/Reactor.Greenhouse/Program.cs +++ /dev/null @@ -1,109 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.CommandLine; -using System.CommandLine.Invocation; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Threading.Tasks; -using Mono.Cecil; -using Newtonsoft.Json; -using Newtonsoft.Json.Serialization; -using Reactor.Greenhouse.Setup; -using Reactor.OxygenFilter; - -namespace Reactor.Greenhouse -{ - internal static class Program - { - private static Task Main(string[] args) - { - var rootCommand = new RootCommand - { - new Option("steam"), - new Option("itch"), - }; - - rootCommand.Handler = CommandHandler.Create(GenerateAsync); - - return rootCommand.InvokeAsync(args); - } - - private static async Task GenerateAsync(bool steam, bool itch) - { - var gameManager = new GameManager(); - await gameManager.SetupAsync(steam, itch); - - JsonConvert.DefaultSettings = () => new JsonSerializerSettings - { - NullValueHandling = NullValueHandling.Ignore, - DefaultValueHandling = DefaultValueHandling.Ignore, - ReferenceLoopHandling = ReferenceLoopHandling.Ignore, - ContractResolver = ShouldSerializeContractResolver.Instance, - }; - - Console.WriteLine($"Generating mappings from {gameManager.PreObfuscation.Name} ({gameManager.PreObfuscation.Version})"); - using var old = ModuleDefinition.ReadModule(File.OpenRead(gameManager.PreObfuscation.Dll)); - - if (steam) - { - await GenerateAsync(gameManager.Steam, old); - } - - if (itch) - { - await GenerateAsync(gameManager.Itch, old); - } - } - - private static async Task GenerateAsync(Game game, ModuleDefinition old) - { - Console.WriteLine($"Compiling mappings for {game.Name} ({game.Version})"); - - using var moduleDef = ModuleDefinition.ReadModule(File.OpenRead(game.Dll)); - var version = game.Version; - var postfix = game.Postfix; - - var generated = Generator.Generate(old, moduleDef); - - await File.WriteAllTextAsync(Path.Combine("work", version + postfix + ".generated.json"), JsonConvert.SerializeObject(generated, Formatting.Indented)); - - Apply(generated, Path.Combine("mappings", version + ".json")); - Apply(generated, Path.Combine("mappings", version + postfix + ".json")); - - generated.Compile(moduleDef); - - await File.WriteAllTextAsync(Path.Combine("work", version + postfix + ".json"), JsonConvert.SerializeObject(generated)); - } - - private static void Apply(Mappings generated, string file) - { - if (File.Exists(file)) - { - var mappings = JsonConvert.DeserializeObject(File.ReadAllText(file)); - generated.Apply(mappings); - } - } - - public class ShouldSerializeContractResolver : CamelCasePropertyNamesContractResolver - { - public static ShouldSerializeContractResolver Instance { get; } = new ShouldSerializeContractResolver(); - - protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) - { - var property = base.CreateProperty(member, memberSerialization); - - if (property.PropertyType != null && property.PropertyType != typeof(string)) - { - if (property.PropertyType.GetInterface(nameof(IEnumerable)) != null) - { - property.ShouldSerialize = instance => (instance?.GetType().GetProperty(property.UnderlyingName!)!.GetValue(instance) as IEnumerable)?.Count() > 0; - } - } - - return property; - } - } - } -} diff --git a/Reactor.Greenhouse/Reactor.Greenhouse.csproj b/Reactor.Greenhouse/Reactor.Greenhouse.csproj deleted file mode 100644 index 89afe54..0000000 --- a/Reactor.Greenhouse/Reactor.Greenhouse.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - Exe - net5.0 - true - - - - - - - - - - - ..\lib\Il2CppDumper.dll - - - diff --git a/Reactor.Greenhouse/Setup/Game.cs b/Reactor.Greenhouse/Setup/Game.cs deleted file mode 100644 index 6ce2ef4..0000000 --- a/Reactor.Greenhouse/Setup/Game.cs +++ /dev/null @@ -1,88 +0,0 @@ -using System; -using System.IO; -using System.Security.Cryptography; -using System.Text; -using System.Threading.Tasks; -using Il2CppDumper; -using Reactor.Greenhouse.Setup.Provider; -using IOPath = System.IO.Path; - -namespace Reactor.Greenhouse.Setup -{ - public class Game - { - public BaseProvider Provider { get; } - public string Name { get; } - public char Postfix { get; } - public string Path { get; } - public string Dll { get; } - public string Version { get; private set; } - - public Game(BaseProvider provider, string name, string path) - { - Provider = provider; - provider.Game = this; - Name = name; - Postfix = char.ToLowerInvariant(name[0]); - Path = path; - Dll = IOPath.Combine(Path, "DummyDll", "Assembly-CSharp.dll"); - } - - public async Task DownloadAsync() - { - Provider.Setup(); - await Provider.DownloadAsync(); - UpdateVersion(); - } - - public void UpdateVersion() - { - if (Version != null) - return; - - Version = GameVersionParser.Parse(System.IO.Path.Combine(Path, "Among Us_Data", "globalgamemanagers")); - } - - public void Dump() - { - Console.WriteLine($"Dumping {Name}"); - - var hash = ComputeHash(IOPath.Combine(Path, "GameAssembly.dll")); - var hashFile = IOPath.Combine(Path, "Assembly-CSharp.dll.md5"); - - if (File.Exists(hashFile) && File.ReadAllText(hashFile) == hash) - { - return; - } - - if (!Il2CppDumper.Il2CppDumper.PerformDump( - IOPath.Combine(Path, "GameAssembly.dll"), - IOPath.Combine(Path, "Among Us_Data", "il2cpp_data", "Metadata", "global-metadata.dat"), - Path, - new Config - { - RequireAnyKey = false, - GenerateScript = false, - DumpProperty = true, - DumpAttribute = true - }, - Console.WriteLine - )) - { - throw new Exception("Il2CppDumper failed"); - } - - File.WriteAllText(hashFile, hash); - } - - private static string ComputeHash(string file) - { - using var md5 = MD5.Create(); - using var assemblyStream = File.OpenRead(file); - - var hash = md5.ComputeHash(assemblyStream); - - return Encoding.UTF8.GetString(hash); - } - } -} diff --git a/Reactor.Greenhouse/Setup/GameManager.cs b/Reactor.Greenhouse/Setup/GameManager.cs deleted file mode 100644 index f899e6e..0000000 --- a/Reactor.Greenhouse/Setup/GameManager.cs +++ /dev/null @@ -1,86 +0,0 @@ -using System; -using System.IO; -using System.Threading.Tasks; -using DepotDownloader; -using Reactor.Greenhouse.Setup.Provider; - -namespace Reactor.Greenhouse.Setup -{ - public class GameManager - { - public string WorkPath { get; } - - public Game PreObfuscation { get; } - public Game Steam { get; } - public Game Itch { get; } - - public GameManager() - { - WorkPath = Path.GetFullPath("work"); - PreObfuscation = new Game(new SteamProvider(true), "preobfuscation", Path.Combine(WorkPath, "preobfuscation")); - Steam = new Game(new SteamProvider(false), "steam", Path.Combine(WorkPath, "steam")); - Itch = new Game(new ItchProvider(), "itch", Path.Combine(WorkPath, "itch")); - } - - public async Task SetupAsync(bool setupSteam, bool setupItch) - { - var preObfuscation = PreObfuscation.Provider.IsUpdateNeeded(); - var steam = setupSteam && Steam.Provider.IsUpdateNeeded(); - var itch = setupItch && Itch.Provider.IsUpdateNeeded(); - - if (preObfuscation || steam || itch) - { - ContentDownloader.ShutdownSteam3(); - - if (preObfuscation) - { - await PreObfuscation.DownloadAsync(); - Console.WriteLine($"Downloaded {nameof(PreObfuscation)} ({PreObfuscation.Version})"); - } - - if (steam) - { - await Steam.DownloadAsync(); - Console.WriteLine($"Downloaded {nameof(Steam)} ({Steam.Version})"); - } - - if (itch) - { - await Itch.DownloadAsync(); - Console.WriteLine($"Downloaded {nameof(Itch)} ({Itch.Version})"); - } - } - - ContentDownloader.ShutdownSteam3(); - - PreObfuscation.UpdateVersion(); - - if (setupSteam) - { - Steam.UpdateVersion(); - } - - if (setupItch) - { - Itch.UpdateVersion(); - } - - if (PreObfuscation.Version != "2020.9.9") - { - throw new ArgumentException("Pre obfuscation version is invalid"); - } - - PreObfuscation.Dump(); - - if (setupSteam) - { - Steam.Dump(); - } - - if (setupItch) - { - Itch.Dump(); - } - } - } -} diff --git a/Reactor.Greenhouse/Setup/GameVersionParser.cs b/Reactor.Greenhouse/Setup/GameVersionParser.cs deleted file mode 100644 index 283446d..0000000 --- a/Reactor.Greenhouse/Setup/GameVersionParser.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.IO; -using System.Linq; -using System.Text; - -namespace Reactor.Greenhouse.Setup -{ - public static class GameVersionParser - { - public static int IndexOf(this byte[] source, byte[] pattern) - { - for (var i = 0; i < source.Length; i++) - { - if (source.Skip(i).Take(pattern.Length).SequenceEqual(pattern)) - { - return i; - } - } - - return -1; - } - - public static string Parse(string file) - { - var bytes = File.ReadAllBytes(file); - - var pattern = Encoding.UTF8.GetBytes("public.app-category.games"); - var index = bytes.IndexOf(pattern) + pattern.Length + 127; - - return Encoding.UTF8.GetString(bytes.Skip(index).TakeWhile(x => x != 0).ToArray()); - } - } -} diff --git a/Reactor.Greenhouse/Setup/Provider/BaseProvider.cs b/Reactor.Greenhouse/Setup/Provider/BaseProvider.cs deleted file mode 100644 index b552ab7..0000000 --- a/Reactor.Greenhouse/Setup/Provider/BaseProvider.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Threading.Tasks; - -namespace Reactor.Greenhouse.Setup.Provider -{ - public abstract class BaseProvider - { - public Game Game { get; internal set; } - - public abstract void Setup(); - public abstract Task DownloadAsync(); - public abstract bool IsUpdateNeeded(); - } -} diff --git a/Reactor.Greenhouse/Setup/Provider/ItchProvider.cs b/Reactor.Greenhouse/Setup/Provider/ItchProvider.cs deleted file mode 100644 index d151c5e..0000000 --- a/Reactor.Greenhouse/Setup/Provider/ItchProvider.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.IO.Compression; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using AngleSharp.Html.Dom; -using AngleSharp.Html.Parser; -using DepotDownloader; -using Newtonsoft.Json; - -namespace Reactor.Greenhouse.Setup.Provider -{ - public class ItchProvider : BaseProvider - { - private HttpClient HttpClient { get; } = new HttpClient(new HttpClientHandler - { - CookieContainer = new CookieContainer() - }); - - public string Username { get; set; } - public string Password { get; set; } - - public override void Setup() - { - Console.Write("itch.io username: "); - Username = Console.ReadLine(); - - Console.Write("itch.io password: "); - Password = Util.ReadPassword(); - - Console.WriteLine(); - } - - public override async Task DownloadAsync() - { - var htmlParser = new HtmlParser(); - - var csrfResponse = await HttpClient.GetAsync("https://itch.io/login"); - - var csrfDocument = htmlParser.ParseDocument(await csrfResponse.Content.ReadAsStreamAsync()); - - var loginResponse = await HttpClient.PostAsync("https://itch.io/login", new FormUrlEncodedContent(new[] - { - new KeyValuePair("csrf_token", ((IHtmlInputElement) csrfDocument.QuerySelector("input[name=csrf_token]")).Value), - new KeyValuePair("username", Username), - new KeyValuePair("password", Password) - })); - - if (!loginResponse.IsSuccessStatusCode || (await loginResponse.Content.ReadAsStringAsync()).Contains("Errors")) - { - throw new Exception("itch.io authentication failed"); - } - - Console.WriteLine("Logged into itch.io"); - - var pageDocument = htmlParser.ParseDocument(await HttpClient.GetStringAsync("https://innersloth.itch.io/among-us")); - var downloadPageUrl = ((IHtmlAnchorElement) pageDocument.QuerySelector("a[class=button]")).Href; - - var downloadDocument = htmlParser.ParseDocument(await HttpClient.GetStringAsync(downloadPageUrl)); - var uploadId = ((IHtmlAnchorElement) downloadDocument.QuerySelector("a[class='button download_btn']")).Dataset["upload_id"]; - - var keyRegex = new Regex("key\":\"(.+)\","); - var key = downloadDocument.QuerySelectorAll("script[type='text/javascript']") - .Cast() - .Select(x => keyRegex.Match(x.InnerHtml)) - .Single(x => x.Success) - .Groups[1].Value; - - var json = await HttpClient.PostAsync($"https://innersloth.itch.io/among-us/file/{uploadId}?key={key}", null); - var response = JsonConvert.DeserializeObject(await json.Content.ReadAsStringAsync()); - - Console.WriteLine($"Downloading {response.Url}"); - - var files = new[] { "GameAssembly.dll", "global-metadata.dat", "globalgamemanagers" }; - using var zipArchive = new ZipArchive(await HttpClient.GetStreamAsync(response.Url), ZipArchiveMode.Read); - foreach (var entry in zipArchive.Entries) - { - if (files.Contains(entry.Name)) - { - var path = Path.Combine("work", "itch", entry.FullName.Substring(entry.FullName.IndexOf("/", StringComparison.Ordinal) + 1)); - - Directory.GetParent(path)!.Create(); - entry.ExtractToFile(path, true); - } - } - } - - public override bool IsUpdateNeeded() - { - return !Directory.Exists(Game.Path); - } - - public class DownloadResponse - { - public string Url { get; set; } - public bool External { get; set; } - } - } -} diff --git a/Reactor.Greenhouse/Setup/Provider/SteamProvider.cs b/Reactor.Greenhouse/Setup/Provider/SteamProvider.cs deleted file mode 100644 index 543e323..0000000 --- a/Reactor.Greenhouse/Setup/Provider/SteamProvider.cs +++ /dev/null @@ -1,109 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using DepotDownloader; -using SteamKit2; - -namespace Reactor.Greenhouse.Setup.Provider -{ - public class SteamProvider : BaseProvider - { - private const uint AppId = 945360; - private const uint DepotId = 945361; - private const ulong PreObfuscationManifest = 3596575937380717449; - - public bool IsPreObfuscation { get; } - - public SteamProvider(bool isPreObfuscation) - { - IsPreObfuscation = isPreObfuscation; - } - - public override bool IsUpdateNeeded() - { - DepotConfigStore.LoadFromFile(Path.Combine(Game.Path, ".DepotDownloader", "depot.config")); - if (DepotConfigStore.Instance.InstalledManifestIDs.TryGetValue(DepotId, out var installedManifest)) - { - if (IsPreObfuscation) - { - if (installedManifest == PreObfuscationManifest) - { - return false; - } - } - else - { - if (ContentDownloader.steam3 == null) - { - ContentDownloader.InitializeSteam3(); - } - - ContentDownloader.steam3!.RequestAppInfo(AppId); - - var depots = ContentDownloader.GetSteam3AppSection(AppId, EAppInfoSection.Depots); - if (installedManifest == depots[DepotId.ToString()]["manifests"][ContentDownloader.DEFAULT_BRANCH].AsUnsignedLong()) - { - return false; - } - } - } - - return true; - } - - public override void Setup() - { - if (ContentDownloader.steam3 != null && ContentDownloader.steam3.bConnected) - { - return; - } - - AccountSettingsStore.LoadFromFile("account.config"); - - var environmentVariable = Environment.GetEnvironmentVariable("STEAM"); - - if (environmentVariable != null) - { - var split = environmentVariable.Split(":"); - ContentDownloader.InitializeSteam3(split[0], split[1]); - } - else - { - ContentDownloader.Config.RememberPassword = true; - - Console.Write("Steam username: "); - var username = Console.ReadLine(); - - string password = null; - - if (!AccountSettingsStore.Instance.LoginKeys.ContainsKey(username)) - { - Console.Write("Steam password: "); - password = ContentDownloader.Config.SuppliedPassword = Util.ReadPassword(); - Console.WriteLine(); - } - - ContentDownloader.InitializeSteam3(username, password); - } - - ContentDownloader.Config.UsingFileList = true; - ContentDownloader.Config.FilesToDownload = new List - { - "GameAssembly.dll" - }; - ContentDownloader.Config.FilesToDownloadRegex = new List - { - new Regex("^Among Us_Data/il2cpp_data/Metadata/global-metadata.dat$".Replace("/", "[\\\\|/]"), RegexOptions.Compiled | RegexOptions.IgnoreCase), - new Regex("^Among Us_Data/globalgamemanagers$".Replace("/", "[\\\\|/]"), RegexOptions.Compiled | RegexOptions.IgnoreCase) - }; - } - - public override Task DownloadAsync() - { - ContentDownloader.Config.InstallDirectory = Game.Path; - return ContentDownloader.DownloadAppAsync(AppId, DepotId, IsPreObfuscation ? PreObfuscationManifest : ContentDownloader.INVALID_MANIFEST_ID); - } - } -} diff --git a/Reactor.Greenhouse/mappings.schema.json b/Reactor.Greenhouse/mappings.schema.json deleted file mode 100644 index 23fade5..0000000 --- a/Reactor.Greenhouse/mappings.schema.json +++ /dev/null @@ -1,112 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://reactor.gg/schemas/mappings.schema.json", - "title": "Reactor.OxygenFilter - Mappings", - "type": "object", - "definitions": { - "member": { - "type": "object", - "properties": { - "original": { - "anyOf": [ - { - "type": "object", - "properties": { - "index": { - "type": "number" - }, - "signature": { - "type": "string" - }, - "name": { - "type": "string" - }, - "const": { - "type": "object", - "properties": { - "value": { - }, - "type": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "type": "string" - }, - { - "type": "number" - } - ] - }, - "mapped": { - "type": "string" - }, - "notes": { - "type": "string" - }, - "additionalProperties": false - }, - "required": [ - "original" - ], - "additionalProperties": false - }, - "type": { - "type": "object", - "$ref": "#/definitions/member", - "properties": { - "nested": { - "type": "array", - "items": { - "$ref": "#/definitions/type" - } - }, - "fields": { - "type": "array", - "items": { - "$ref": "#/definitions/member" - } - }, - "properties": { - "type": "array", - "items": { - "$ref": "#/definitions/member" - } - }, - "methods": { - "type": "array", - "items": { - "$ref": "#/definitions/member", - "properties": { - "parameters": { - "type": "array", - "items": { - "type": "string" - } - } - } - } - } - } - } - }, - "properties": { - "types": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/type" - }, - "required": [ - "original" - ] - } - }, - "required": [ - "types" - ] -} \ No newline at end of file diff --git a/Reactor.Greenhouse/mappings/2020.11.17.json b/Reactor.Greenhouse/mappings/2020.11.17.json deleted file mode 120000 index d0b2a1e..0000000 --- a/Reactor.Greenhouse/mappings/2020.11.17.json +++ /dev/null @@ -1 +0,0 @@ -2020.12.9.json \ No newline at end of file diff --git a/Reactor.Greenhouse/mappings/2020.12.9.json b/Reactor.Greenhouse/mappings/2020.12.9.json deleted file mode 100644 index 90c79aa..0000000 --- a/Reactor.Greenhouse/mappings/2020.12.9.json +++ /dev/null @@ -1,809 +0,0 @@ -{ - "$schema": "../mappings.schema.json", - "types": [ - { - "original": "^", - "mapped": "Constants", - "methods": [ - { - "original": { - "signature": "System.Byte[] ()" - }, - "mapped": "GetBroadcastVersion" - } - ], - "fields": [ - { - "original": 0, - "mapped": "GamePlayPort" - }, - { - "original": 1, - "mapped": "AnnouncementPort" - }, - { - "original": 2, - "mapped": "ShipOnlyMask" - }, - { - "original": 3, - "mapped": "ShipAndObjectsMask" - }, - { - "original": 4, - "mapped": "ShipAndAllObjectsMask" - }, - { - "original": 5, - "mapped": "NotShipMask" - }, - { - "original": 6, - "mapped": "Usables" - }, - { - "original": 7, - "mapped": "PlayersOnlyMask" - }, - { - "original": 8, - "mapped": "ShadowMask" - }, - { - "original": 9, - "mapped": "CompatVersions" - }, - { - "original": 10, - "mapped": "Year" - }, - { - "original": 11, - "mapped": "Month" - }, - { - "original": 12, - "mapped": "Day" - }, - { - "original": 13, - "mapped": "Revision" - }, - { - "original": 14, - "mapped": "field_14" - }, - { - "original": 15, - "mapped": "LocalNetAddress" - }, - { - "original": 16, - "mapped": "InfinitySymbol" - } - ] - }, - { - "original": {}, - "mapped": "SaveManager", - "fields": [ - { - "original": { - "signature": "System.Collections.Generic.HashSet`1", - "index": 23 - }, - "mapped": "purchases" - } - ], - "properties": [ - { - "mapped": "LastAnnouncement", - "original": 0 - }, - { - "mapped": "BoughtNoAds", - "original": 1 - }, - { - "mapped": "VSync", - "original": 2 - }, - { - "mapped": "CensorChat", - "original": 3 - }, - { - "mapped": "ShowAdsScreen", - "original": 4 - }, - { - "mapped": "ShowMinPlayerWarning", - "original": 6 - }, - { - "mapped": "ShowOnlineHelp", - "original": 7 - }, - { - "mapped": "SfxVolume", - "original": 8 - }, - { - "mapped": "MusicVolume", - "original": 9 - }, - { - "mapped": "TouchConfig", - "original": 10 - }, - { - "mapped": "JoystickSize", - "original": 11 - }, - { - "mapped": "PlayerName", - "original": 12 - }, - { - "mapped": "LastPet", - "original": 13 - }, - { - "mapped": "LastHat", - "original": 14 - }, - { - "mapped": "LastSkin", - "original": 15 - }, - { - "mapped": "LastLanguage", - "original": 16 - }, - { - "mapped": "BodyColor", - "original": 17 - }, - { - "mapped": "GameHostOptions", - "original": 18 - }, - { - "mapped": "GameSearchOptions", - "original": 19 - } - ] - }, - { - "original": "^", - "mapped": "InnerNetClient", - "methods": [ - { - "original": { - "signature": "System.Byte[] ()" - }, - "mapped": "GetConnectionData" - }, - { - "original": { - "signature": "System.Void ({{GameOverReason}},System.Boolean)" - }, - "mapped": "OnGameEnd" - } - ] - }, - { - "original": "^", - "mapped": "GameOptionsData", - "fields": [ - { - "original": 22, - "mapped": "isDefaults" - }, - { - "original": 23, - "mapped": "ConfirmEjects" - }, - { - "original": 24, - "mapped": "VisualTasks" - }, - { - "original": 25, - "mapped": "TaskBarUpdate" - }, - { - "original": 26, - "mapped": "AnonymousVotes" - }, - { - "original": 27, - "mapped": "RecommendedKillCooldown" - }, - { - "original": 28, - "mapped": "RecommendedImpostors" - }, - { - "original": 29, - "mapped": "MaxImpostors" - }, - { - "original": 30, - "mapped": "MinPlayers" - } - ] - }, - { - "original": {}, - "mapped": "VersionShower", - "methods": [ - { - "original": { - "name": "Start", - "signature": "System.Void ()" - } - } - ], - "fields": [ - { - "original": { - "index": 0, - "name": "text" - } - } - ] - }, - { - "original": {}, - "mapped": "PingTracker", - "methods": [ - { - "original": { - "name": "Update", - "signature": "System.Void ()" - } - } - ], - "fields": [ - { - "original": { - "index": 0, - "name": "text" - } - } - ] - }, - { - "original": "^", - "mapped": "GameStartManager", - "fields": [ - { - "original": 3, - "mapped": "LastPlayerCount" - }, - { - "original": 12, - "mapped": "startState" - }, - { - "original": 13, - "mapped": "countDownTimer" - } - ], - "nested": [ - { - "original": 0, - "mapped": "StartingStates" - } - ] - }, - { - "original": "^", - "mapped": "GameData", - "nested": [ - { - "original": 1, - "mapped": "PlayerInfo", - "fields": [ - { - "original": 0, - "mapped": "PlayerId" - }, - { - "original": 1, - "mapped": "PlayerName" - }, - { - "original": 2, - "mapped": "ColorId" - }, - { - "original": 3, - "mapped": "HatId" - }, - { - "original": 4, - "mapped": "PetId" - }, - { - "original": 5, - "mapped": "SkinId" - }, - { - "original": 6, - "mapped": "Disconnected" - }, - { - "original": 7, - "mapped": "Tasks" - }, - { - "original": 8, - "mapped": "IsImpostor" - }, - { - "original": 9, - "mapped": "IsDead" - }, - { - "original": 10, - "mapped": "_object" - } - ], - "properties": [ - { - "original": 0, - "mapped": "Object" - } - ] - } - ] - }, - { - "original": {}, - "mapped": "RegionInfo", - "fields": [ - { - "original": { - "index": 0, - "signature": "System.String" - }, - "mapped": "Name" - }, - { - "original": { - "index": 1, - "signature": "System.String" - }, - "mapped": "PingServer" - }, - { - "original": { - "index": 2, - "signature": "{{ServerInfo}}[]" - }, - "mapped": "Servers" - } - ] - }, - { - "original": "^", - "mapped": "PlayerPhysics", - "fields": [ - { - "original": { - "signature": "UnityEngine.Rigidbody2D" - }, - "mapped": "body" - } - ] - }, - { - "original": "^", - "mapped": "PlayerControl", - "fields": [ - { - "original": { - "signature": "UnityEngine.SpriteRenderer" - }, - "mapped": "myRend" - } - ] - }, - { - "original": {}, - "mapped": "MapBehaviour", - "methods": [ - { - "original": { - "name": "ShowInfectedMap", - "signature": "System.Void ()" - } - } - ] - }, - { - "original": {}, - "mapped": "IntroCutscene", - "nested": [ - { - "original": 0, - "mapped": "CoBegin__d" - } - ], - "fields": [ - { - "original": { - "name": "IntroStinger", - "signature": "UnityEngine.AudioClip" - } - } - ] - }, - { - "original": {}, - "mapped": "GameOptionsMenu", - "fields": [ - { - "original": 2, - "mapped": "Children" - }, - { - "original": { - "name": "ResetButton", - "signature": "UnityEngine.GameObject" - } - } - ] - }, - { - "original": {}, - "mapped": "GameSettingMenu", - "fields": [ - { - "original": { - "name": "HideForOnline", - "signature": "UnityEngine.Transform[]" - } - } - ] - }, - { - "original": "^", - "mapped": "AmongUsClient", - "nested": [ - { - "original": 0, - "mapped": "CoStartGame__d" - } - ] - }, - { - "original": {}, - "mapped": "Minigame", - "methods": [ - { - "original": { - "name": "ForceClose", - "signature": "System.Void ()" - } - } - ] - }, - { - "original": {}, - "mapped": "KeyboardJoystick", - "methods": [ - { - "original": "Update" - }, - { - "original": "get_Delta" - } - ] - }, - { - "original": {}, - "mapped": "PlayerVoteArea", - "methods": [ - { - "original": { - "name": "CoAnimateOverlay", - "signature": "System.Collections.IEnumerator ()" - } - } - ] - }, - { - "original": "^", - "mapped": "PlayerTab", - "fields": [ - { - "original": { - "signature": "System.Collections.Generic.HashSet`1" - }, - "mapped": "AvailableColors" - } - ], - "nested": [ - { - "original": 0, - "mapped": "OnEnable__0" - } - ] - }, - { - "original": "^", - "mapped": "MeetingHud", - "nested": [ - { - "original": 0, - "mapped": "VoteStates" - } - ], - "fields": [ - { - "original": 0, - "mapped": "ResultsTime" - }, - { - "original": 1, - "mapped": "Depth" - }, - { - "original": 7, - "mapped": "CounterOrigin" - }, - { - "original": 8, - "mapped": "CounterOffsets" - }, - { - "original": 10, - "mapped": "playerStates" - }, - { - "original": 19, - "mapped": "state" - }, - { - "original": 23, - "mapped": "exiledPlayer" - }, - { - "original": 24, - "mapped": "wasTie" - }, - { - "original": 27, - "mapped": "reporterId" - }, - { - "original": 28, - "mapped": "amDead" - }, - { - "original": 29, - "mapped": "resultsStartedAt" - }, - { - "original": 30, - "mapped": "lastSecond" - } - ] - }, - { - "original": "^", - "mapped": "MessageExtensions", - "methods": [ - { - "original": 0, - "mapped": "WriteNetObject" - }, - { - "original": 1, - "mapped": "ReadNetObject" - } - ] - }, - { - "original": "^", - "mapped": "PhysicsHelpers", - "methods": [ - { - "original": { - "signature": "System.Boolean (UnityEngine.Vector2,UnityEngine.Vector2,System.Single,System.Int32)" - }, - "mapped": "AnyNonTriggersBetween" - } - ] - }, - { - "original": "^", - "mapped": "AspectPosition", - "nested": [ - { - "original": 0, - "mapped": "EdgeAlignments" - } - ] - }, - { - "original": "^", - "mapped": "GameCode", - "methods": [ - { - "original": 0, - "mapped": "IntToGameName" - }, - { - "original": 1, - "mapped": "GameNameToInt" - }, - { - "original": 2, - "mapped": "CreateGameId" - }, - { - "original": 3, - "mapped": "IntToGameNameV2" - } - ] - }, - { - "original": "^", - "mapped": "Effects", - "methods": [ - { - "original": { - "signature": "System.Collections.IEnumerator (System.Single,UnityEngine.Transform,System.Single,System.Single)" - }, - "mapped": "Bloop" - } - ] - }, - { - "original": {}, - "mapped": "StringOption", - "fields": [ - { - "original": { - "name": "Values", - "signature": "StringNames[]" - } - } - ] - }, - { - "original": {}, - "mapped": "PlainShipRoom", - "fields": [ - { - "original": { - "index": 0, - "name": "RoomId" - } - }, - { - "original": { - "index": 1, - "name": "survCamera" - } - }, - { - "original": { - "index": 2, - "name": "roomArea" - } - } - ] - }, - { - "original": "^", - "mapped": "CooldownHelpers", - "methods": [ - { - "original": { - "index": 0, - "signature": "System.Void (UnityEngine.SpriteRenderer)" - }, - "mapped": "SetCooldownNormalizedUvs" - } - ] - }, - { - "original": {}, - "mapped": "WinningPlayerData", - "fields": [ - { - "original": { - "index": 0, - "signature": "System.String" - }, - "mapped": "Name" - }, - { - "original": { - "index": 1, - "signature": "System.Boolean" - }, - "mapped": "IsDead" - }, - { - "original": { - "index": 2, - "signature": "System.Boolean" - }, - "mapped": "IsImpostor" - }, - { - "original": { - "index": 3, - "signature": "System.Int32" - }, - "mapped": "ColorId" - }, - { - "original": { - "index": 4, - "signature": "System.UInt32" - }, - "mapped": "SkinId" - }, - { - "original": { - "index": 5, - "signature": "System.UInt32" - }, - "mapped": "HatId" - }, - { - "original": { - "index": 6, - "signature": "System.UInt32" - }, - "mapped": "PetId" - }, - { - "original": { - "index": 7, - "signature": "System.Boolean" - }, - "mapped": "IsYou" - } - ] - }, - { - "original": {}, - "mapped": "TempData", - "methods": [ - { - "original": { - "index": 0, - "signature": "System.Boolean ({{GameOverReason}})" - }, - "mapped": "DidHumansWin" - } - ], - "fields": [ - { - "original": 0, - "mapped": "LastDeathReason" - }, - { - "original": 1, - "mapped": "EndReason" - }, - { - "original": 2, - "mapped": "showAd" - }, - { - "original": 3, - "mapped": "winners" - } - ] - } - ] -} \ No newline at end of file diff --git a/Reactor.Greenhouse/mappings/2020.12.9s.json b/Reactor.Greenhouse/mappings/2020.12.9s.json deleted file mode 100644 index 106a694..0000000 --- a/Reactor.Greenhouse/mappings/2020.12.9s.json +++ /dev/null @@ -1,134 +0,0 @@ -{ - "$schema": "../mappings.schema.json", - "types": [ - { - "original": "^", - "mapped": "MeetingHud", - "methods": [ - { - "notes": "MeetingHud#CastVote", - "original": "EIGGEKBEOEA", - "mapped": "CheckForEndVoting" - }, - { - "notes": "void (byte[], GameData.PlayerInfo, bool)", - "original": "KGIPOIOFBJH", - "mapped": "VotingComplete" - }, - { - "notes": "MeetingHud#VotingComplete", - "original": "FBNKEAEKKJE", - "mapped": "PopulateResults" - }, - { - "notes": "MeetingHud#VotingComplete", - "original": "ECLBANBAFCN", - "mapped": "SetupProceedButton" - } - ] - }, - { - "original": "^", - "mapped": "ShipStatus", - "methods": [ - { - "notes": "ShipStatus#FixedUpdate", - "original": "ECNNLBKGIKE", - "mapped": "CheckEndCriteria" - }, - { - "notes": "CheckEndCriteria", - "original": "PLBGOMIEONF", - "mapped": "RpcEndGame" - }, - { - "original": "NJOJCFDGEAE", - "mapped": "SelectInfected" - } - ] - }, - { - "original": "^", - "mapped": "ServerManager", - "methods": [ - { - "notes": "Last call in ServerManager#Awake", - "original": "BBIDOJKFGPM", - "mapped": "LoadServers" - } - ] - }, - { - "original": {}, - "mapped": "StatsManager", - "properties": [ - { - "notes": "Second call in *GameButton#OnClick", - "original": "IDEHLLDOODH", - "mapped": "AmBanned" - } - ], - "fields": [ - { - "original": { - "const": { - "type": "System.Byte", - "value": 3 - } - }, - "mapped": "StatsVersion" - }, - { - "original": { - "const": { - "type": "System.Int32", - "value": 2 - } - }, - "mapped": "PointsUntilBanStarts" - }, - { - "original": { - "const": { - "type": "System.Int32", - "value": 5 - } - }, - "mapped": "MinutesPerBanPoint" - } - ] - }, - { - "original": "^", - "mapped": "PlayerControl", - "methods": [ - { - "notes": "Only method with [CallerCount(2)] and PlayerControl ()", - "original": "OAFBLFBAOJJ", - "mapped": "FindClosestTarget" - }, - { - "notes": "first call in CmdReportDeadBody", - "original": "MKAIDPJOJFP", - "mapped": "ReportDeadBody" - }, - { - "notes": "Only method with [CallerCount(1)] and void (byte[])", - "original": "OJPCECLPCCF", - "mapped": "SetInfected" - } - ] - }, - { - "original": "^", - "mapped": "EndGameManager", - "methods": [ - { - "notes": "first call in EndGameManager#Start", - "original": "MFIBPNBCMKM", - "mapped": "SetEverythingUp" - } - ] - } - ] -} \ No newline at end of file diff --git a/Reactor.OxygenFilter/Extensions.cs b/Reactor.OxygenFilter/Extensions.cs deleted file mode 100644 index 33dfcca..0000000 --- a/Reactor.OxygenFilter/Extensions.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System.Linq; -using System.Text; -using Mono.Cecil; - -namespace Reactor.OxygenFilter -{ - public static class Extensions - { - public static bool IsObfuscated(this string text) - { - return text.Length == 11 && text.All(char.IsUpper); - } - - public static string GetSignature(this MethodDefinition methodDefinition) - { - var sb = new StringBuilder(); - - sb.Append(methodDefinition.ReturnType.FullName); - sb.Append(" "); - - sb.Append("("); - if (methodDefinition.HasParameters) - { - for (var i = 0; i < methodDefinition.Parameters.Count; i++) - { - var parameterType = methodDefinition.Parameters[i].ParameterType; - - if (i > 0) - sb.Append(","); - - if (parameterType is SentinelType) - sb.Append("...,"); - - sb.Append(parameterType.FullName); - } - } - - sb.Append(")"); - - return sb.ToString(); - } - - public static string GetSignature(this FieldDefinition fieldDefinition) - { - return fieldDefinition.FieldType.FullName; - } - - public static string GetSignature(this PropertyDefinition propertyDefinition) - { - return propertyDefinition.PropertyType.FullName; - } - } -} diff --git a/Reactor.OxygenFilter/Mappings.cs b/Reactor.OxygenFilter/Mappings.cs deleted file mode 100644 index 5282e9d..0000000 --- a/Reactor.OxygenFilter/Mappings.cs +++ /dev/null @@ -1,199 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Newtonsoft.Json; - -namespace Reactor.OxygenFilter -{ - public class Mappings - { - public List Types { get; set; } = new List(); - - public MappedType Find(string name, Func predicate) - { - var split = name.Split('.').SelectMany(x => x.Split('+')).ToArray(); - - if (split.Length > 1) - { - MappedType type = null; - - foreach (var s in split) - { - if (type == null) - { - type = Find(s, predicate); - } - else - { - type = type.Nested.SingleOrDefault(x => predicate(x) == s); - } - } - - return type; - } - - return Types.SingleOrDefault(x => predicate(x) == name); - } - - public MappedType FindByMapped(string name) - { - return Find(name, x => x.Mapped); - } - - public MappedType FindByOriginal(string name) - { - return Find(name, x => x.Original.Name); - } - } - - public class OriginalDescriptor - { - public string Name { get; set; } - public int? Index { get; set; } - public string Signature { get; set; } - public Constant Const { get; set; } - - public bool Equals(OriginalDescriptor obj) - { - return Name == obj.Name && Index == obj.Index && Signature == obj.Signature && Const == obj.Const; - } - - public bool IsEmpty() - { - return Name == null && Index == null; - } - - public override string ToString() - { - return Name ?? Index?.ToString(); - } - - public class Constant - { - private object _value; - - public object Value - { - get => Convert.ChangeType(_value, Type); - set => _value = value; - } - - public Type Type { get; set; } - } - } - - public class OriginalDescriptorConverter : JsonConverter - { - public override void WriteJson(JsonWriter writer, OriginalDescriptor value, JsonSerializer serializer) - { - if (value.Name != null && value.Index == null && value.Signature == null) - { - writer.WriteValue(value.Name); - } - else if (value.Index != null && value.Name == null && value.Signature == null) - { - writer.WriteValue(value.Index); - } - else - { - serializer.Serialize(writer, value); - } - } - - public override OriginalDescriptor ReadJson(JsonReader reader, Type objectType, OriginalDescriptor existingValue, bool hasExistingValue, JsonSerializer serializer) - { - if (reader.Value is string name) - { - return new OriginalDescriptor { Name = name }; - } - - if (reader.Value is long index) - { - return new OriginalDescriptor { Index = (int?) index }; - } - - if (reader.TokenType == JsonToken.StartObject) - { - return serializer.Deserialize(reader); - } - - throw new JsonSerializationException(); - } - } - - public class MappedMember - { - [JsonProperty(Order = -3)] - [JsonConverter(typeof(OriginalDescriptorConverter))] - public OriginalDescriptor Original { get; set; } - - [JsonProperty(Order = -2)] - public string Mapped { get; set; } - - public override string ToString() - { - var result = Original.ToString(); - - if (Mapped != null) - { - result += $" (name: {Mapped})"; - } - - return result; - } - - public MappedMember() - { - } - - public MappedMember(OriginalDescriptor original, string mapped) - { - Original = original; - - if (original.Name != mapped) - { - Mapped = mapped; - } - } - - public bool Equals(MappedMember obj, bool compareOriginal = true) - { - if (obj == null) - { - return false; - } - - return Mapped == obj.Mapped && (!compareOriginal || (Original.Name == "^" && obj.Mapped != null) || Original.Equals(obj.Original)); - } - } - - public class MappedMethod : MappedMember - { - public List Parameters { get; set; } = new List(); - - public MappedMethod() - { - } - - public MappedMethod(OriginalDescriptor original, string mapped) : base(original, mapped) - { - } - } - - public class MappedType : MappedMember - { - public List Properties { get; set; } = new List(); - public List Fields { get; set; } = new List(); - public List Methods { get; set; } = new List(); - - public List Nested { get; set; } = new List(); - - public MappedType() - { - } - - public MappedType(OriginalDescriptor original, string mapped) : base(original, mapped) - { - } - } -} diff --git a/Reactor.OxygenFilter/ObfuscationMapper.cs b/Reactor.OxygenFilter/ObfuscationMapper.cs deleted file mode 100644 index 1c2ead6..0000000 --- a/Reactor.OxygenFilter/ObfuscationMapper.cs +++ /dev/null @@ -1,237 +0,0 @@ -using System; -using System.IO; -using System.Linq; -using Mono.Cecil; -using Newtonsoft.Json; -using Newtonsoft.Json.Serialization; - -namespace Reactor.OxygenFilter -{ - public class ObfuscationMapper - { - public ModuleDefinition ModuleDef { get; } - public Mappings Mappings { get; private set; } - - public ObfuscationMapper(ModuleDefinition moduleDef) - { - ModuleDef = moduleDef; - } - - public void Map() - { - var mappedAttribute = new TypeDefinition("", "MappedAttribute", TypeAttributes.Public, ModuleDef.ImportReference(typeof(Attribute))) - { - Attributes = TypeAttributes.Class & TypeAttributes.Public - }; - - ModuleDef.Types.Add(mappedAttribute); - - var mappedAttributeCtor = new MethodReference(".ctor", ModuleDef.ImportReference(typeof(void)), mappedAttribute) - { - HasThis = true, - Parameters = { new ParameterDefinition(ModuleDef.ImportReference(typeof(string))) } - }; - - void MapMember(ICustomAttributeProvider attributes, string mapped) - { - attributes.CustomAttributes.Add(new CustomAttribute(mappedAttributeCtor) - { - ConstructorArguments = { new CustomAttributeArgument(ModuleDef.ImportReference(typeof(string)), mapped) } - }); - } - - // beebyte 1 iq? - foreach (var propertyDef in ModuleDef.Types.SelectMany(x => x.NestedTypes.Prepend(x)).SelectMany(x => x.Properties)) - { - const string getPrefix = "get_"; - const string setPrefix = "set_"; - - var getName = propertyDef.GetMethod != null && propertyDef.GetMethod.Name.StartsWith(getPrefix) ? propertyDef.GetMethod.Name.Substring(getPrefix.Length) : null; - var setName = propertyDef.SetMethod != null && propertyDef.SetMethod.Name.StartsWith(setPrefix) ? propertyDef.SetMethod.Name.Substring(setPrefix.Length) : null; - - if (getName != null && setName != null && getName != setName) - { - throw new Exception($"{propertyDef.FullName} has 2 different accessor names"); - } - - if (getName != null || setName != null) - { - var name = getName ?? setName; - - MapMember(propertyDef, name); - - if (propertyDef.GetMethod != null) - MapMember(propertyDef.GetMethod, "get_" + name); - - if (propertyDef.SetMethod != null) - MapMember(propertyDef.SetMethod, "set_" + name); - } - } - - void MapType(MappedType type, TypeDefinition typeDef) - { - if (typeDef == null) - { - throw new NullReferenceException($"Type {type} was not found!"); - } - - if (type.Mapped != null) - { - MapMember(typeDef, type.Mapped); - } - - foreach (var property in type.Properties) - { - var propertyDef = typeDef.Properties.SingleOrDefault(x => x.Name == property.Original.Name); - - if (propertyDef == null) - { - throw new NullReferenceException($"Property {property} was not found in {type}!"); - } - - if (property.Mapped != null) - { - MapMember(propertyDef, property.Mapped); - - if (propertyDef.GetMethod != null) - MapMember(propertyDef.GetMethod, "get_" + property.Mapped); - - if (propertyDef.SetMethod != null) - MapMember(propertyDef.SetMethod, "set_" + property.Mapped); - } - } - - foreach (var field in type.Fields) - { - var fieldDef = typeDef.Fields.SingleOrDefault(x => x.Name == field.Original.Name); - - if (fieldDef == null) - { - throw new NullReferenceException($"Field {field} was not found in {type}!"); - } - - if (field.Mapped != null) - { - MapMember(fieldDef, field.Mapped); - } - } - - foreach (var method in type.Methods) - { - var methodDef = typeDef.Methods - .SingleOrDefault(x => x.Name == method.Original.Name && (method.Original.Signature == null || x.GetSignature().ToString() == method.Original.Signature)); - - if (methodDef == null) - { - throw new NullReferenceException($"Method {method} was not found in {type}!"); - } - - foreach (var methodDef2 in ModuleDef.Types - .Where(x => x.BaseType == typeDef) - .Select(x => x.Methods.SingleOrDefault(m => m.Name == method.Original.Name && (method.Original.Signature == null || m.GetSignature().ToString() == method.Original.Signature))) - .Where(x => x != null) - .Prepend(methodDef) - ) - { - if (method.Mapped != null) - { - MapMember(methodDef2, method.Mapped); - } - - for (var i = 0; i < method.Parameters.Count; i++) - { - MapMember(methodDef2.Parameters.ElementAt(i), method.Parameters[i]); - } - } - } - - foreach (var nested in type.Nested) - { - MapType(nested, typeDef.NestedTypes.SingleOrDefault(x => x.Name == nested.Original.Name)); - } - } - - foreach (var type in Mappings.Types) - { - MapType(type, ModuleDef.GetType(type.Original.Name)); - } - - foreach (var typeDef in ModuleDef.Types) - { - var i = 0; - - foreach (var member in typeDef.Properties) - { - if (member.Name.IsObfuscated() && member.CustomAttributes.All(x => x.AttributeType != mappedAttribute)) - { - MapMember(member, $"Property_{i}"); - } - - i++; - } - - i = 0; - - foreach (var member in typeDef.Fields) - { - if (member.Name.IsObfuscated() && member.CustomAttributes.All(x => x.AttributeType != mappedAttribute)) - { - MapMember(member, $"Field_{i}"); - } - - i++; - } - - i = 0; - - foreach (var member in typeDef.Methods) - { - if (member.Name.IsObfuscated() && member.CustomAttributes.All(x => x.AttributeType != mappedAttribute)) - { - MapMember(member, $"Method_{i}"); - } - - var j = 0; - foreach (var parameter in member.Parameters) - { - if (parameter.Name.IsObfuscated() && parameter.CustomAttributes.All(x => x.AttributeType != mappedAttribute)) - { - MapMember(parameter, $"Parameter_{j}"); - } - - j++; - } - - i++; - } - - i = 0; - - foreach (var member in typeDef.NestedTypes) - { - if (member.Name.IsObfuscated() && member.CustomAttributes.All(x => x.AttributeType != mappedAttribute)) - { - MapMember(member, $"Nested_{i}"); - } - - i++; - } - } - } - - public void LoadMappings(FileInfo file) - { - if (!file.Exists) - { - throw new FileNotFoundException(); - } - - JsonConvert.DefaultSettings = () => new JsonSerializerSettings - { - ContractResolver = new CamelCasePropertyNamesContractResolver() - }; - - Mappings = JsonConvert.DeserializeObject(File.ReadAllText(file.FullName)); - } - } -} diff --git a/Reactor.OxygenFilter/OxygenFilter.cs b/Reactor.OxygenFilter/OxygenFilter.cs deleted file mode 100644 index 1cd5ec4..0000000 --- a/Reactor.OxygenFilter/OxygenFilter.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.IO; -using Mono.Cecil; - -namespace Reactor.OxygenFilter -{ - public class OxygenFilter - { - public void Start(FileInfo mappingsFile, FileInfo dumpedDll, FileInfo outputDll) - { - using var inputStream = dumpedDll.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.Read); - using var outputStream = dumpedDll == outputDll ? inputStream : dumpedDll.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.Read); - - var resolver = new DefaultAssemblyResolver(); - resolver.AddSearchDirectory(dumpedDll.DirectoryName); - - using var module = ModuleDefinition.ReadModule(inputStream, new ReaderParameters(ReadingMode.Immediate) { AssemblyResolver = resolver }); - var mapper = new ObfuscationMapper(module); - mapper.LoadMappings(mappingsFile); - mapper.Map(); - module.Dispose(); - module.Write(outputStream); - } - } -} diff --git a/Reactor.OxygenFilter/Reactor.OxygenFilter.csproj b/Reactor.OxygenFilter/Reactor.OxygenFilter.csproj deleted file mode 100644 index bffc4eb..0000000 --- a/Reactor.OxygenFilter/Reactor.OxygenFilter.csproj +++ /dev/null @@ -1,10 +0,0 @@ - - - net472;netstandard2.0 - latest - - - - - - \ No newline at end of file diff --git a/Reactor.sln b/Reactor.sln index b98aa3a..cb0d764 100644 --- a/Reactor.sln +++ b/Reactor.sln @@ -1,20 +1,12 @@ Microsoft Visual Studio Solution File, Format Version 12.00 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Reactor", "Reactor\Reactor.csproj", "{91906039-9753-472B-ACC3-12C0561FFAD8}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Reactor.OxygenFilter", "Reactor.OxygenFilter\Reactor.OxygenFilter.csproj", "{154C08E6-8F9F-43A3-86C3-A3A606316D2B}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Reactor.Debugger", "Reactor.Debugger\Reactor.Debugger.csproj", "{68589B4D-9EF5-40DD-8D6D-10977ED07259}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Reactor.Greenhouse", "Reactor.Greenhouse\Reactor.Greenhouse.csproj", "{00BF8959-652F-46B8-AA0F-891B4DA1112B}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Build", "build\Build.csproj", "{58AC4924-AC3D-45EA-80D7-E9F860FD1DD2}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{E2F4DAFA-E98C-4A7D-BA47-AAB0271A769D}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssemblyUnhollower", "lib/Il2CppAssemblyUnhollower\AssemblyUnhollower\AssemblyUnhollower.csproj", "{64ABFD11-CE06-4220-A626-55B39AB85B62}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnhollowerBaseLib", "lib/Il2CppAssemblyUnhollower\UnhollowerBaseLib\UnhollowerBaseLib.csproj", "{17B4E6AE-EA5A-43BE-9184-5BBB6594C5E7}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -25,18 +17,10 @@ Global {91906039-9753-472B-ACC3-12C0561FFAD8}.Debug|Any CPU.Build.0 = Debug|Any CPU {91906039-9753-472B-ACC3-12C0561FFAD8}.Release|Any CPU.ActiveCfg = Release|Any CPU {91906039-9753-472B-ACC3-12C0561FFAD8}.Release|Any CPU.Build.0 = Release|Any CPU - {154C08E6-8F9F-43A3-86C3-A3A606316D2B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {154C08E6-8F9F-43A3-86C3-A3A606316D2B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {154C08E6-8F9F-43A3-86C3-A3A606316D2B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {154C08E6-8F9F-43A3-86C3-A3A606316D2B}.Release|Any CPU.Build.0 = Release|Any CPU {68589B4D-9EF5-40DD-8D6D-10977ED07259}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {68589B4D-9EF5-40DD-8D6D-10977ED07259}.Debug|Any CPU.Build.0 = Debug|Any CPU {68589B4D-9EF5-40DD-8D6D-10977ED07259}.Release|Any CPU.ActiveCfg = Release|Any CPU {68589B4D-9EF5-40DD-8D6D-10977ED07259}.Release|Any CPU.Build.0 = Release|Any CPU - {00BF8959-652F-46B8-AA0F-891B4DA1112B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {00BF8959-652F-46B8-AA0F-891B4DA1112B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {00BF8959-652F-46B8-AA0F-891B4DA1112B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {00BF8959-652F-46B8-AA0F-891B4DA1112B}.Release|Any CPU.Build.0 = Release|Any CPU {58AC4924-AC3D-45EA-80D7-E9F860FD1DD2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {58AC4924-AC3D-45EA-80D7-E9F860FD1DD2}.Debug|Any CPU.Build.0 = Debug|Any CPU {58AC4924-AC3D-45EA-80D7-E9F860FD1DD2}.Release|Any CPU.ActiveCfg = Release|Any CPU diff --git a/Reactor/Coroutines.cs b/Reactor/Coroutines.cs new file mode 100644 index 0000000..301617f --- /dev/null +++ b/Reactor/Coroutines.cs @@ -0,0 +1,157 @@ +// https://github.com/HerpDerpinstine/MelonLoader/blob/master/MelonLoader.Support.Il2Cpp/MelonCoroutines.cs + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using UnhollowerBaseLib; +using UnityEngine; + +namespace Reactor +{ + public static class Coroutines + { + private struct CoroutineTuple + { + public object WaitCondition; + public IEnumerator Coroutine; + } + + private static readonly List _ourCoroutinesStore = new List(); + private static readonly List _ourNextFrameCoroutines = new List(); + private static readonly List _ourWaitForFixedUpdateCoroutines = new List(); + private static readonly List _ourWaitForEndOfFrameCoroutines = new List(); + + private static readonly List _tempList = new List(); + + public static object Start(IEnumerator routine) + { + if (routine != null) ProcessNextOfCoroutine(routine); + return routine; + } + + public static void Stop(IEnumerator enumerator) + { + if (_ourNextFrameCoroutines.Contains(enumerator)) // the coroutine is running itself + { + _ourNextFrameCoroutines.Remove(enumerator); + } + else + { + var coroutineTupleIndex = _ourCoroutinesStore.FindIndex(c => c.Coroutine == enumerator); + if (coroutineTupleIndex != -1) // the coroutine is waiting for a subroutine + { + var waitCondition = _ourCoroutinesStore[coroutineTupleIndex].WaitCondition; + if (waitCondition is IEnumerator waitEnumerator) + { + Stop(waitEnumerator); + } + + _ourCoroutinesStore.RemoveAt(coroutineTupleIndex); + } + } + } + + private static void ProcessCoroutineList(List target) + { + if (target.Count == 0) return; + + // use a temp list to make sure waits made during processing are not handled by same processing invocation + // additionally, a temp list reduces allocations compared to an array + _tempList.AddRange(target); + target.Clear(); + foreach (var enumerator in _tempList) ProcessNextOfCoroutine(enumerator); + _tempList.Clear(); + } + + internal static void Process() + { + for (var i = _ourCoroutinesStore.Count - 1; i >= 0; i--) + { + var tuple = _ourCoroutinesStore[i]; + if (tuple.WaitCondition is WaitForSeconds waitForSeconds) + { + if ((waitForSeconds.m_Seconds -= Time.deltaTime) <= 0) + { + _ourCoroutinesStore.RemoveAt(i); + ProcessNextOfCoroutine(tuple.Coroutine); + } + } + } + + ProcessCoroutineList(_ourNextFrameCoroutines); + } + + internal static void ProcessWaitForFixedUpdate() => ProcessCoroutineList(_ourWaitForFixedUpdateCoroutines); + + internal static void ProcessWaitForEndOfFrame() => ProcessCoroutineList(_ourWaitForEndOfFrameCoroutines); + + private static void ProcessNextOfCoroutine(IEnumerator enumerator) + { + try + { + if (!enumerator.MoveNext()) // Run the next step of the coroutine. If it's done, restore the parent routine + { + var indices = _ourCoroutinesStore.Select((it, idx) => (idx, it)).Where(it => it.it.WaitCondition == enumerator).Select(it => it.idx).ToList(); + for (var i = indices.Count - 1; i >= 0; i--) + { + var index = indices[i]; + _ourNextFrameCoroutines.Add(_ourCoroutinesStore[index].Coroutine); + _ourCoroutinesStore.RemoveAt(index); + } + + return; + } + } + catch (Exception e) + { + PluginSingleton.Instance.Log.LogError(e.ToString()); + Stop(FindOriginalCoroutine(enumerator)); // We want the entire coroutine hierarchy to stop when an error happen + } + + var next = enumerator.Current; + switch (next) + { + case null: + _ourNextFrameCoroutines.Add(enumerator); + return; + case WaitForFixedUpdate _: + _ourWaitForFixedUpdateCoroutines.Add(enumerator); + return; + case WaitForEndOfFrame _: + _ourWaitForEndOfFrameCoroutines.Add(enumerator); + return; + case WaitForSeconds _: + break; // do nothing, this one is supported in Process + case Il2CppObjectBase il2CppObjectBase: + var nextAsEnumerator = il2CppObjectBase.TryCast(); + if (nextAsEnumerator != null) // il2cpp IEnumerator also handles CustomYieldInstruction + next = new Il2CppEnumeratorWrapper(nextAsEnumerator); + else + PluginSingleton.Instance.Log.LogWarning($"Unknown coroutine yield object of type {il2CppObjectBase} for coroutine {enumerator}"); + break; + } + + _ourCoroutinesStore.Add(new CoroutineTuple { WaitCondition = next, Coroutine = enumerator }); + + if (next is IEnumerator nextCoroutine) + ProcessNextOfCoroutine(nextCoroutine); + } + + private static IEnumerator FindOriginalCoroutine(IEnumerator enumerator) + { + var index = _ourCoroutinesStore.FindIndex(ct => ct.WaitCondition == enumerator); + return index == -1 ? enumerator : FindOriginalCoroutine(_ourCoroutinesStore[index].Coroutine); + } + + private class Il2CppEnumeratorWrapper : IEnumerator + { + private readonly Il2CppSystem.Collections.IEnumerator _il2CPPEnumerator; + + public Il2CppEnumeratorWrapper(Il2CppSystem.Collections.IEnumerator il2CppEnumerator) => _il2CPPEnumerator = il2CppEnumerator; + public bool MoveNext() => _il2CPPEnumerator.MoveNext(); + public void Reset() => _il2CPPEnumerator.Reset(); + public object Current => _il2CPPEnumerator.Current; + } + } +} diff --git a/Reactor/CustomStringName.cs b/Reactor/CustomStringName.cs new file mode 100644 index 0000000..285b379 --- /dev/null +++ b/Reactor/CustomStringName.cs @@ -0,0 +1,54 @@ +using System.Collections.Generic; +using System.Linq; +using HarmonyLib; +using UnhollowerBaseLib; + +namespace Reactor +{ + public class CustomStringName + { + private static int _lastId = -1; + + private static readonly List _list = new List(); + + public static IReadOnlyList List => _list.AsReadOnly(); + + public static CustomStringName Register(string value) + { + var customStringName = new CustomStringName(_lastId--, value); + _list.Add(customStringName); + + return customStringName; + } + + public int Id { get; } + + public string Value { get; } + + private CustomStringName(int id, string value) + { + Id = id; + Value = value; + } + + public static implicit operator StringNames(CustomStringName name) => (StringNames) name.Id; + public static explicit operator CustomStringName(StringNames name) => List.SingleOrDefault(x => x.Id == (int) name); + + [HarmonyPatch(typeof(TranslationController), nameof(TranslationController.GetString), typeof(StringNames), typeof(Il2CppReferenceArray))] + private static class GetStringPatch + { + public static bool Prefix([HarmonyArgument(0)] StringNames stringId, [HarmonyArgument(1)] Il2CppReferenceArray parts, ref string __result) + { + var customStringName = (CustomStringName) stringId; + + if (customStringName != null) + { + __result = string.Format(customStringName.Value, parts); + return false; + } + + return true; + } + } + } +} diff --git a/Reactor/Extensions/Extensions.cs b/Reactor/Extensions/Extensions.cs index eedf8b2..f0ecf6c 100644 --- a/Reactor/Extensions/Extensions.cs +++ b/Reactor/Extensions/Extensions.cs @@ -2,8 +2,10 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Threading.Tasks; using UnityEngine; using UnityEngine.Events; +using UnityEngine.Networking; using UnityEngine.SceneManagement; using Object = UnityEngine.Object; @@ -69,6 +71,9 @@ namespace Reactor.Extensions return ((Color32) color).ToHtmlStringRGBA(); } + /// + /// Fully read stream, can be used as workaround for il2cpp streams. + /// public static byte[] ReadFully(this Stream input) { using (var ms = new MemoryStream()) @@ -77,5 +82,20 @@ namespace Reactor.Extensions return ms.ToArray(); } } + + /// + /// Sends and return task that finishes on completion. + /// + public static Task SendAsync(this UnityWebRequest request) + { + var task = new TaskCompletionSource(); + + request.Send().m_completeCallback = (Action) (x => + { + task.SetResult(null); + }); + + return task.Task; + } } } diff --git a/Reactor/Reactor.csproj b/Reactor/Reactor.csproj index f86f109..644e1af 100644 --- a/Reactor/Reactor.csproj +++ b/Reactor/Reactor.csproj @@ -13,4 +13,4 @@ - \ No newline at end of file + diff --git a/Reactor/ReactorPlugin.cs b/Reactor/ReactorPlugin.cs index bf78186..a2097c8 100644 --- a/Reactor/ReactorPlugin.cs +++ b/Reactor/ReactorPlugin.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using BepInEx; using BepInEx.IL2CPP; using HarmonyLib; @@ -26,7 +27,7 @@ namespace Reactor ClassInjector.RegisterTypeInIl2Cpp(); var gameObject = new GameObject(nameof(ReactorPlugin)).DontDestroy(); - gameObject.AddComponent(); + gameObject.AddComponent().Plugin = this; Harmony.PatchAll(); ReactorVersionShower.Initialize(); @@ -42,19 +43,72 @@ namespace Reactor public class ReactorComponent : MonoBehaviour { + public ReactorPlugin Plugin { get; internal set; } + public ReactorComponent(IntPtr ptr) : base(ptr) { } + public void Start() + { + Camera.onPostRender = Camera.onPostRender == null + ? new Action(OnPostRenderM) + : Il2CppSystem.Delegate.Combine(Camera.onPostRender, Il2CppSystem.Delegate.CreateDelegate(GetIl2CppType(), GetIl2CppType().GetMethod(nameof(OnPostRenderM), Il2CppSystem.Reflection.BindingFlags.Static | Il2CppSystem.Reflection.BindingFlags.Public))).Cast(); + } + + public static Camera OnPostRenderCam { get; private set; } + + private static void OnPostRenderM(Camera camera) + { + if (OnPostRenderCam == null) + { + OnPostRenderCam = camera; + } + + if (OnPostRenderCam == camera) + { + Coroutines.ProcessWaitForEndOfFrame(); + } + } + private void Update() { - var watcher = PluginSingleton.Instance.RegionInfoWatcher; - if (watcher.Reload) + Coroutines.Process(); + + if (Plugin.RegionInfoWatcher.Reload) { - watcher.Reload = false; + Plugin.RegionInfoWatcher.Reload = false; ServerManager.Instance.LoadServers(); - PluginSingleton.Instance.Log.LogInfo("Region file reloaded"); + Plugin.Log.LogInfo("Region file reloaded"); } + + if (Input.GetKeyDown(KeyCode.F5)) + { + Plugin.Log.LogInfo("Reloading all configs"); + + foreach (var pluginInfo in Preloader.Chainloader.Plugins.Values) + { + var config = ((BasePlugin) pluginInfo.Instance).Config; + if (!config.Any()) + { + continue; + } + + try + { + config.Reload(); + } + catch (Exception e) + { + Plugin.Log.LogWarning($"Exception occured during reload of {pluginInfo.Metadata.Name}: {e}"); + } + } + } + } + + private void FixedUpdate() + { + Coroutines.ProcessWaitForFixedUpdate(); } } } diff --git a/build/Build.csproj b/build/Build.csproj index 01bdca4..380df88 100644 --- a/build/Build.csproj +++ b/build/Build.csproj @@ -7,11 +7,8 @@ - - ..\lib\Il2CppDumper.dll - - - - + + + - \ No newline at end of file + diff --git a/build/Program.cs b/build/Program.cs index 1c0c84b..9dd793b 100644 --- a/build/Program.cs +++ b/build/Program.cs @@ -11,7 +11,6 @@ using Cake.Common.Tools.DotNetCore.Run; using Cake.Core; using Cake.Frosting; using DepotDownloader; -using Reactor.OxygenFilter; public static class Program { @@ -81,20 +80,6 @@ public sealed class GenerateProxyAssemblyTask : FrostingTask context.TempPath, dumperConfig, context.Debug ); - context.Information("Executing Reactor.Greenhouse"); - - context.DotNetCoreRun(".", "steam", new DotNetCoreRunSettings - { - WorkingDirectory = "Reactor.Greenhouse" - }); - - context.Information("Executing Reactor.OxygenFilter"); - - var oxygenFilter = new OxygenFilter(); - - var dumpedDll = new FileInfo(Path.Combine(context.TempPath, "DummyDll", "Assembly-CSharp.dll")); - oxygenFilter.Start(new FileInfo(Path.Combine("Reactor.Greenhouse", "work", "2020.12.9s.json")), dumpedDll, dumpedDll); - context.Information("Executing Il2CppUnhollower generator"); UnhollowerBaseLib.LogSupport.InfoHandler += context.Information; diff --git a/lib/Il2CppAssemblyUnhollower b/lib/Il2CppAssemblyUnhollower deleted file mode 160000 index 0d7585f..0000000 --- a/lib/Il2CppAssemblyUnhollower +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 0d7585fa90844fe0887e13c2828ecd2e4f84784d diff --git a/lib/Il2CppDumper.dll b/lib/Il2CppDumper.dll deleted file mode 100644 index 8d77743..0000000 Binary files a/lib/Il2CppDumper.dll and /dev/null differ