diff --git a/Reactor.Greenhouse/BeebyteMappings.cs b/Reactor.Greenhouse/BeebyteMappings.cs new file mode 100644 index 0000000..d5ed64a --- /dev/null +++ b/Reactor.Greenhouse/BeebyteMappings.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Mono.Cecil; +using Mono.Cecil.Rocks; +using Reactor.OxygenFilter; + +namespace Reactor.Greenhouse +{ + public class BeebyteMappings + { + public Dictionary Names { get; } + + public BeebyteMappings(Dictionary names) + { + Names = names; + } + + public string GetOrDefault(string name) + { + if (name.IsObfuscated() && Names.TryGetValue(name, out var value)) + { + return value.Clean(); + } + + return null; + } + + public void Compile(Mappings result, ModuleDefinition module) + { + foreach (var typeDefinition in module.GetAllTypes()) + { + var type = new MappedType(typeDefinition.FullName, GetOrDefault(typeDefinition.Name)); + + foreach (var methodDefinition in typeDefinition.Methods) + { + if (methodDefinition.Name.IsObfuscated() && !Names.ContainsKey(methodDefinition.Name)) + continue; // dead method + + var method = new MappedMethod(methodDefinition, GetOrDefault(methodDefinition.Name)); + + foreach (var parameterDefinition in methodDefinition.Parameters) + { + method.Parameters.Add(GetOrDefault(parameterDefinition.Name) ?? parameterDefinition.Name); + } + + if (!methodDefinition.Name.IsObfuscated() && !method.Parameters.Any()) + continue; + + type.Methods.Add(method); + } + + foreach (var fieldDefinition in typeDefinition.Fields) + { + var field = new MappedMember(fieldDefinition.Name, GetOrDefault(fieldDefinition.Name) ?? fieldDefinition.Name.Clean()); + + if (!fieldDefinition.Name.IsObfuscated() && fieldDefinition.Name == field.Mapped) + continue; + + type.Fields.Add(field); + } + + foreach (var propertyDefinition in typeDefinition.Properties) + { + var field = new MappedMember(propertyDefinition.Name, GetOrDefault(propertyDefinition.Name)); + + if (!propertyDefinition.Name.IsObfuscated()) + continue; + + type.Properties.Add(field); + } + + if (!typeDefinition.Name.IsObfuscated() && !type.Fields.Any() && !type.Methods.Any() && !type.Properties.Any() && !type.Nested.Any()) + continue; + + result.Types.Add(type); + } + } + + public static BeebyteMappings Parse(string[] text) + { + var names = new Dictionary(); + foreach (var line in text) + { + // comment + if (line.StartsWith("#")) + { + continue; + } + + var values = line.Split("⇨"); + if (values.Length != 2) + { + throw new FormatException(); + } + + var preobfuscated = values[1]; + + names.Add(values[0], preobfuscated.Contains("/") ? preobfuscated[(preobfuscated.IndexOf("/", StringComparison.Ordinal) + 1)..] : preobfuscated); + } + + return new BeebyteMappings(names); + } + } +} diff --git a/Reactor.Greenhouse/Extensions.cs b/Reactor.Greenhouse/Extensions.cs index 4c815f5..af64d64 100644 --- a/Reactor.Greenhouse/Extensions.cs +++ b/Reactor.Greenhouse/Extensions.cs @@ -44,5 +44,16 @@ namespace Reactor.Greenhouse Directory.GetParent(destinationFileName)!.Create(); source.ExtractToFile(destinationFileName, true); } + + public static string Clean(this string name) + { + return name switch + { + "<>1__state" => "__state", + "<>2__current" => "__current", + "<>4__this" => "__this", + _ => name.Replace("<", "_").Replace(">", "_") + }; + } } } diff --git a/Reactor.Greenhouse/Generation/Generator.cs b/Reactor.Greenhouse/Generation/Generator.cs index 406dc4d..4e855e1 100644 --- a/Reactor.Greenhouse/Generation/Generator.cs +++ b/Reactor.Greenhouse/Generation/Generator.cs @@ -28,10 +28,8 @@ namespace Reactor.Greenhouse.Generation return scope.Name != "Assembly-CSharp.dll"; } - public static Mappings Generate(GenerationContext context) + public static void Generate(Mappings result, GenerationContext context) { - var result = new Mappings(); - var lookupTypes = Extensions.Time(() => { LookupTypes(context); @@ -76,8 +74,6 @@ namespace Reactor.Greenhouse.Generation result.Types.Add(mappedType); } - - return result; } private static double TestEnum(TypeDefinition cleanType, TypeDefinition obfuscatedType) diff --git a/Reactor.Greenhouse/Generation/TypeContext.cs b/Reactor.Greenhouse/Generation/TypeContext.cs index 8eb64fc..97427fb 100644 --- a/Reactor.Greenhouse/Generation/TypeContext.cs +++ b/Reactor.Greenhouse/Generation/TypeContext.cs @@ -46,14 +46,9 @@ namespace Reactor.Greenhouse.Generation } } - private static string Clean(string name) - { - return name.Replace("<", "_").Replace(">", "_"); - } - public MappedType ToMappedType() { - var mappedType = new MappedType(ObfuscatedType.FullName, Clean(CleanType.Name)); + var mappedType = new MappedType(ObfuscatedType.FullName, CleanType.Name.Clean()); if (!string.IsNullOrEmpty(CleanType.Namespace)) { @@ -76,20 +71,7 @@ namespace Reactor.Greenhouse.Generation if (ObfuscatedType.DeclaringType != null) { - switch (obfuscatedField.Name) - { - case "<>1__state": - mappedType.Fields.Add(new MappedMember(obfuscatedField.Name, "__state")); - continue; - case "<>2__current": - mappedType.Fields.Add(new MappedMember(obfuscatedField.Name, "__current")); - continue; - case "<>4__this": - mappedType.Fields.Add(new MappedMember(obfuscatedField.Name, "__this")); - continue; - } - - var clean = Clean(obfuscatedField.Name); + var clean = obfuscatedField.Name.Clean(); if (clean != obfuscatedField.Name) { @@ -174,7 +156,7 @@ namespace Reactor.Greenhouse.Generation { foreach (var obfuscatedMethod in ObfuscatedType.Methods) { - var clean = Clean(obfuscatedMethod.Name); + var clean = obfuscatedMethod.Name.Clean(); if (clean != obfuscatedMethod.Name) { diff --git a/Reactor.Greenhouse/Program.cs b/Reactor.Greenhouse/Program.cs index 22faa46..926c3ec 100644 --- a/Reactor.Greenhouse/Program.cs +++ b/Reactor.Greenhouse/Program.cs @@ -55,14 +55,26 @@ namespace Reactor.Greenhouse using var moduleDef = ModuleDefinition.ReadModule(File.OpenRead(game.Dll)); - var generated = Generator.Generate(new GenerationContext(cleanModule, moduleDef)); - generated.GameVersion = version.ToString(); - generated.Version = Mappings.CurrentVersion; + var mappings = Read(version.ToString()); + + var generated = new Mappings + { + GameVersion = version.ToString(), + Version = Mappings.CurrentVersion + }; + + if (mappings.Beebyte != null) + { + BeebyteMappings.Parse(await File.ReadAllLinesAsync(mappings.Beebyte)).Compile(generated, moduleDef); + } + + if (mappings.UseGenerator) + { + Generator.Generate(generated, new GenerationContext(cleanModule, moduleDef)); + } await File.WriteAllTextAsync(Path.Combine("work", version + ".generated.json"), JsonConvert.SerializeObject(generated, Formatting.Indented)); - var mappings = Read(version.ToString()); - generated.Apply(mappings, Read); generated.Compile(moduleDef); diff --git a/Reactor.Greenhouse/Setup/Provider/SteamProvider.cs b/Reactor.Greenhouse/Setup/Provider/SteamProvider.cs index b5efdbe..ad00c29 100644 --- a/Reactor.Greenhouse/Setup/Provider/SteamProvider.cs +++ b/Reactor.Greenhouse/Setup/Provider/SteamProvider.cs @@ -18,7 +18,8 @@ namespace Reactor.Greenhouse.Setup.Provider [new GameVersion("2020.12.9s")] = 3306639722673334636, [new GameVersion("2021.3.5s")] = 5200448423569257054, [new GameVersion("2021.3.31s")] = 9177722260012976528, - [new GameVersion("2021.3.31.3s")] = 3941730972865408291 + [new GameVersion("2021.3.31.3s")] = 3941730972865408291, + [new GameVersion("2021.4.12s")] = 2725166875026424465, }; public ulong Manifest { get; } diff --git a/Reactor.OxygenFilter/Mappings.cs b/Reactor.OxygenFilter/Mappings.cs index 52b564a..0a3715d 100644 --- a/Reactor.OxygenFilter/Mappings.cs +++ b/Reactor.OxygenFilter/Mappings.cs @@ -16,6 +16,10 @@ namespace Reactor.OxygenFilter public string[] DependsOn { get; set; } = new string[0]; + public string Beebyte { get; set; } = null; + + public bool UseGenerator { get; set; } = false; + public List Types { get; set; } = new List(); public MappedType Find(string name, Func predicate)