mirror of
https://github.com/NuclearPowered/Reactor.git
synced 2026-10-19 15:51:54 +00:00
Use Reactor.OxygenFilter.MSBuild
This commit is contained in:
34 files changed
+301
-2796
No files matched your search
@@ -4,4 +4,3 @@ obj/
|
||||
riderModule.iml
|
||||
/_ReSharper.Caches/
|
||||
.idea
|
||||
work
|
||||
@@ -1,3 +0,0 @@
|
||||
[submodule "lib/Il2CppAssemblyUnhollower"]
|
||||
path = lib/Il2CppAssemblyUnhollower
|
||||
url = https://github.com/NuclearPowered/Il2CppAssemblyUnhollower
|
||||
+8
-72
@@ -1,78 +1,14 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<TargetGamePlatform>Steam</TargetGamePlatform>
|
||||
<Mappings>NuclearPowered/Mappings:0.1.0-alpha.1</Mappings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!-- Among Us -->
|
||||
<Reference Include="Assembly-CSharp">
|
||||
<HintPath>$(AmongUs)\BepInEx\unhollowed\Assembly-CSharp.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Hazel">
|
||||
<HintPath>$(AmongUs)\BepInEx\unhollowed\Hazel.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
|
||||
<!-- BepInEx -->
|
||||
<Reference Include="0Harmony">
|
||||
<HintPath>$(AmongUs)\BepInEx\core\0Harmony.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="BepInEx">
|
||||
<HintPath>$(AmongUs)\BepInEx\core\BepInEx.Core.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="BepInEx.IL2CPP">
|
||||
<HintPath>$(AmongUs)\BepInEx\core\BepInEx.IL2CPP.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="SemVer">
|
||||
<HintPath>$(AmongUs)\BepInEx\core\SemVer.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
|
||||
<!-- IL2CPP Unhollower -->
|
||||
<Reference Include="UnhollowerBaseLib">
|
||||
<HintPath>$(AmongUs)\BepInEx\core\UnhollowerBaseLib.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Il2Cppmscorlib">
|
||||
<HintPath>$(AmongUs)\BepInEx\unhollowed\Il2Cppmscorlib.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Il2CppSystem.Core">
|
||||
<HintPath>$(AmongUs)\BepInEx\unhollowed\Il2CppSystem.Core.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
|
||||
<!-- UnityEngine -->
|
||||
<Reference Include="UnityEngine">
|
||||
<HintPath>$(AmongUs)\BepInEx\unhollowed\UnityEngine.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.CoreModule">
|
||||
<HintPath>$(AmongUs)\BepInEx\unhollowed\UnityEngine.CoreModule.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.InputLegacyModule">
|
||||
<HintPath>$(AmongUs)\BepInEx\unhollowed\UnityEngine.InputLegacyModule.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.IMGUIModule">
|
||||
<HintPath>$(AmongUs)\BepInEx\unhollowed\UnityEngine.IMGUIModule.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.UI">
|
||||
<HintPath>$(AmongUs)\BepInEx\unhollowed\UnityEngine.UI.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.UIModule">
|
||||
<HintPath>$(AmongUs)\BepInEx\unhollowed\UnityEngine.UIModule.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<PackageReference Include="Reactor.OxygenFilter.MSBuild" Version="0.1.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="Copy" AfterTargets="Build">
|
||||
<ItemGroup>
|
||||
<OutputFiles Include="$(OutputPath)$(AssemblyName).dll" />
|
||||
</ItemGroup>
|
||||
<Copy SourceFiles="@(OutputFiles)" DestinationFolder="$(AmongUs)/BepInEx/plugins/" Condition="'$(Configuration)' == 'Debug'" />
|
||||
<Target Name="Copy" AfterTargets="Reobfuscate">
|
||||
<Copy SourceFiles="$(OutputPath)reobfuscated/$(AssemblyName).dll" DestinationFolder="$(AmongUs)/BepInEx/plugins/" Condition="'$(Configuration)' == 'Debug'" />
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -1,165 +0,0 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
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.
|
||||
@@ -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
|
||||
@@ -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<MappedType> 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<MappedMember> members, List<MappedMember> 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(@"{{(?<expression>[\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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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?;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<int> Main(string[] args)
|
||||
{
|
||||
var rootCommand = new RootCommand
|
||||
{
|
||||
new Option<bool>("steam"),
|
||||
new Option<bool>("itch"),
|
||||
};
|
||||
|
||||
rootCommand.Handler = CommandHandler.Create<bool, bool>(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<Mappings>(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<object>)?.Count() > 0;
|
||||
}
|
||||
}
|
||||
|
||||
return property;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AngleSharp" Version="0.14.0" />
|
||||
<PackageReference Include="DepotDownloader.Library" Version="0.1.2" />
|
||||
<PackageReference Include="Iced" Version="1.6.0" />
|
||||
<PackageReference Include="Mono.Cecil" Version="0.11.3" />
|
||||
<PackageReference Include="System.CommandLine" Version="2.0.0-beta1.20478.1" />
|
||||
<ProjectReference Include="..\Reactor.OxygenFilter\Reactor.OxygenFilter.csproj" />
|
||||
<Reference Include="Il2CppDumper">
|
||||
<HintPath>..\lib\Il2CppDumper.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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<string, string>("csrf_token", ((IHtmlInputElement) csrfDocument.QuerySelector("input[name=csrf_token]")).Value),
|
||||
new KeyValuePair<string, string>("username", Username),
|
||||
new KeyValuePair<string, string>("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<IHtmlScriptElement>()
|
||||
.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<DownloadResponse>(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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<string>
|
||||
{
|
||||
"GameAssembly.dll"
|
||||
};
|
||||
ContentDownloader.Config.FilesToDownloadRegex = new List<Regex>
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
]
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
2020.12.9.json
|
||||
@@ -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<System.String>",
|
||||
"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<System.Int32>"
|
||||
},
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,199 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Reactor.OxygenFilter
|
||||
{
|
||||
public class Mappings
|
||||
{
|
||||
public List<MappedType> Types { get; set; } = new List<MappedType>();
|
||||
|
||||
public MappedType Find(string name, Func<MappedType, string> 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<OriginalDescriptor>
|
||||
{
|
||||
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<OriginalDescriptor>(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<string> Parameters { get; set; } = new List<string>();
|
||||
|
||||
public MappedMethod()
|
||||
{
|
||||
}
|
||||
|
||||
public MappedMethod(OriginalDescriptor original, string mapped) : base(original, mapped)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class MappedType : MappedMember
|
||||
{
|
||||
public List<MappedMember> Properties { get; set; } = new List<MappedMember>();
|
||||
public List<MappedMember> Fields { get; set; } = new List<MappedMember>();
|
||||
public List<MappedMethod> Methods { get; set; } = new List<MappedMethod>();
|
||||
|
||||
public List<MappedType> Nested { get; set; } = new List<MappedType>();
|
||||
|
||||
public MappedType()
|
||||
{
|
||||
}
|
||||
|
||||
public MappedType(OriginalDescriptor original, string mapped) : base(original, mapped)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<Mappings>(File.ReadAllText(file.FullName));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net472;netstandard2.0</TargetFrameworks>
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Mono.Cecil" Version="0.11.3" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
-16
@@ -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
|
||||
|
||||
@@ -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<CoroutineTuple> _ourCoroutinesStore = new List<CoroutineTuple>();
|
||||
private static readonly List<IEnumerator> _ourNextFrameCoroutines = new List<IEnumerator>();
|
||||
private static readonly List<IEnumerator> _ourWaitForFixedUpdateCoroutines = new List<IEnumerator>();
|
||||
private static readonly List<IEnumerator> _ourWaitForEndOfFrameCoroutines = new List<IEnumerator>();
|
||||
|
||||
private static readonly List<IEnumerator> _tempList = new List<IEnumerator>();
|
||||
|
||||
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<IEnumerator> 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<ReactorPlugin>.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<Il2CppSystem.Collections.IEnumerator>();
|
||||
if (nextAsEnumerator != null) // il2cpp IEnumerator also handles CustomYieldInstruction
|
||||
next = new Il2CppEnumeratorWrapper(nextAsEnumerator);
|
||||
else
|
||||
PluginSingleton<ReactorPlugin>.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<CustomStringName> _list = new List<CustomStringName>();
|
||||
|
||||
public static IReadOnlyList<CustomStringName> 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<Il2CppSystem.Object>))]
|
||||
private static class GetStringPatch
|
||||
{
|
||||
public static bool Prefix([HarmonyArgument(0)] StringNames stringId, [HarmonyArgument(1)] Il2CppReferenceArray<Il2CppSystem.Object> parts, ref string __result)
|
||||
{
|
||||
var customStringName = (CustomStringName) stringId;
|
||||
|
||||
if (customStringName != null)
|
||||
{
|
||||
__result = string.Format(customStringName.Value, parts);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fully read <paramref name="input"/> stream, can be used as workaround for il2cpp streams.
|
||||
/// </summary>
|
||||
public static byte[] ReadFully(this Stream input)
|
||||
{
|
||||
using (var ms = new MemoryStream())
|
||||
@@ -77,5 +82,20 @@ namespace Reactor.Extensions
|
||||
return ms.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends <see cref="UnityWebRequest"/> and return task that finishes on <paramref name="request"/> completion.
|
||||
/// </summary>
|
||||
public static Task SendAsync(this UnityWebRequest request)
|
||||
{
|
||||
var task = new TaskCompletionSource<object>();
|
||||
|
||||
request.Send().m_completeCallback = (Action<AsyncOperation>) (x =>
|
||||
{
|
||||
task.SetResult(null);
|
||||
});
|
||||
|
||||
return task.Task;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using BepInEx;
|
||||
using BepInEx.IL2CPP;
|
||||
using HarmonyLib;
|
||||
@@ -26,7 +27,7 @@ namespace Reactor
|
||||
ClassInjector.RegisterTypeInIl2Cpp<Unstrip.Patches.GUIWordWrapSizer>();
|
||||
|
||||
var gameObject = new GameObject(nameof(ReactorPlugin)).DontDestroy();
|
||||
gameObject.AddComponent<ReactorComponent>();
|
||||
gameObject.AddComponent<ReactorComponent>().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<Camera>(OnPostRenderM)
|
||||
: Il2CppSystem.Delegate.Combine(Camera.onPostRender, Il2CppSystem.Delegate.CreateDelegate(GetIl2CppType(), GetIl2CppType().GetMethod(nameof(OnPostRenderM), Il2CppSystem.Reflection.BindingFlags.Static | Il2CppSystem.Reflection.BindingFlags.Public))).Cast<Camera.CameraCallback>();
|
||||
}
|
||||
|
||||
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<ReactorPlugin>.Instance.RegionInfoWatcher;
|
||||
if (watcher.Reload)
|
||||
Coroutines.Process();
|
||||
|
||||
if (Plugin.RegionInfoWatcher.Reload)
|
||||
{
|
||||
watcher.Reload = false;
|
||||
Plugin.RegionInfoWatcher.Reload = false;
|
||||
ServerManager.Instance.LoadServers();
|
||||
PluginSingleton<ReactorPlugin>.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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-6
@@ -7,11 +7,8 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Cake.Frosting" Version="1.0.0-rc0002" />
|
||||
<PackageReference Include="DepotDownloader.Library" Version="0.1.2" />
|
||||
<Reference Include="Il2CppDumper">
|
||||
<HintPath>..\lib\Il2CppDumper.dll</HintPath>
|
||||
</Reference>
|
||||
<ProjectReference Include="..\Reactor.OxygenFilter\Reactor.OxygenFilter.csproj" />
|
||||
<ProjectReference Include="..\lib\Il2CppAssemblyUnhollower\AssemblyUnhollower\AssemblyUnhollower.csproj" />
|
||||
<ProjectReference Include="..\lib\Il2CppAssemblyUnhollower\UnhollowerBaseLib\UnhollowerBaseLib.csproj" />
|
||||
<PackageReference Include="Reactor.OxygenFilter" Version="0.1.0" />
|
||||
<PackageReference Include="js6pak.Il2CppDumper" Version="6.4.20" />
|
||||
<PackageReference Include="NuclearPowered.AssemblyUnhollower" Version="0.4.12" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -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<BuildContext>
|
||||
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;
|
||||
|
||||
Submodule lib/Il2CppAssemblyUnhollower deleted from 0d7585fa90.
Binary file not shown.
Reference in new issue
Block a user