Decompiled source of SilksongPrepatcher v1.0.2
patchers/SilksongPrepatcher.dll
Decompiled 6 days agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Logging; using Microsoft.CodeAnalysis; using Mono.Cecil; using Mono.Cecil.Cil; using Mono.Cecil.Rocks; using Mono.Collections.Generic; using MonoMod.Cil; using MonoMod.Utils; using SilksongPrepatcher.Patchers; using SilksongPrepatcher.Patchers.PlayerDataPatcher; using SilksongPrepatcher.Utils; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("SilksongPrepatcher")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.2.0")] [assembly: AssemblyInformationalVersion("1.0.2+a22d0b9cfde457406fae294d2fcf0c7a234d839d")] [assembly: AssemblyProduct("SilksongPrepatcher")] [assembly: AssemblyTitle("SilksongPrepatcher")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.2.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace SilksongPrepatcher { public static class AssemblyNames { public const string Assembly_CSharp = "Assembly-CSharp.dll"; public const string PlayMaker = "PlayMaker.dll"; public const string TeamCherry_NestedFadeGroup = "TeamCherry.NestedFadeGroup.dll"; public const string TeamCherry_SharedUtils = "TeamCherry.SharedUtils.dll"; public const string Newtonsoft_Json_UnityConverters = "Newtonsoft.Json.UnityConverters.dll"; } public abstract class BasePrepatcher { protected ManualLogSource Log { get; private set; } public string Name { get; private set; } public BasePrepatcher() : this(null) { } public BasePrepatcher(string? name) { if (name == null) { name = GetType().Name; } Name = name; Log = Logger.CreateLogSource(name); } public abstract void PatchAssembly(AssemblyDefinition asm); } public static class SilksongPrepatcher { private static readonly List<(string assemblyName, BasePrepatcher patcher)> patcherData = GetPatcherData(); private static ManualLogSource Log { get; } = Logger.CreateLogSource("SilksongPrepatcher"); internal static string PatchCacheDir { get { string text = Path.Combine(Paths.CachePath, "SilksongPrepatcher"); Directory.CreateDirectory(text); return text; } } public static IEnumerable<string> TargetDLLs => patcherData.Select<(string, BasePrepatcher), string>(((string assemblyName, BasePrepatcher patcher) pair) => pair.assemblyName).Distinct(); private static List<(string assemblyName, BasePrepatcher patcher)> GetPatcherData() { BasePrepatcher item = new MethodReplacer((MethodReference mr) => ((MemberReference)((MemberReference)mr).DeclaringType).Name == "Assembly" && ((MemberReference)mr).Name == "GetTypes", typeof(AssemblyExtensions).GetMethod("GetTypesSafelyIgnoreMMHook", new Type[1] { typeof(Assembly) })); BasePrepatcher item2 = new MethodReplacer((MethodReference mr) => ((MemberReference)((MemberReference)mr).DeclaringType).Name == "Type" && ((MemberReference)mr).Name == "IsAssignableFrom", typeof(AssemblyExtensions).GetMethod("TypeAssignableFromSafe", new Type[2] { typeof(Type), typeof(Type) })); return new List<(string, BasePrepatcher)> { ("TeamCherry.NestedFadeGroup.dll", item), ("PlayMaker.dll", item), ("PlayMaker.dll", new ReflectionUtilsPatcher()), ("Assembly-CSharp.dll", new PlayerDataPatcher()), ("TeamCherry.SharedUtils.dll", new VariableExtensionsPatcher()), ("Newtonsoft.Json.UnityConverters.dll", item2) }; } public static void Patch(AssemblyDefinition assembly) { string assemblyName = ((AssemblyNameReference)assembly.Name).Name + ".dll"; List<BasePrepatcher> list = (from pair in patcherData where pair.assemblyName == assemblyName select pair.patcher).ToList(); Log.LogInfo((object)("Patching " + assemblyName + ": " + string.Join(", ", list.Select((BasePrepatcher x) => x.Name)))); foreach (BasePrepatcher item in list) { item.PatchAssembly(assembly); } } } } namespace SilksongPrepatcher.Utils { public static class AssemblyExtensions { public static Type[] GetTypesSafely(this Assembly asm) { try { return asm.GetTypes(); } catch (ReflectionTypeLoadException ex) { return ex.Types.Where((Type x) => (object)x != null).ToArray(); } } public static Type[] GetTypesSafelyIgnoreMMHook(Assembly asm) { if (asm.GetName().Name.StartsWith("MMHOOK")) { return Array.Empty<Type>(); } return asm.GetTypesSafely(); } public static bool TypeAssignableFromSafe(Type self, Type other) { try { return self.IsAssignableFrom(other); } catch { return false; } } } public static class CecilUtils { [CompilerGenerated] private sealed class <GetMethodDefinitions>d__2 : IEnumerable<MethodDefinition>, IEnumerable, IEnumerator<MethodDefinition>, IEnumerator, IDisposable { private int <>1__state; private MethodDefinition <>2__current; private int <>l__initialThreadId; private ModuleDefinition mod; public ModuleDefinition <>3__mod; private IEnumerator<TypeDefinition> <>7__wrap1; private Enumerator<MethodDefinition> <>7__wrap2; MethodDefinition IEnumerator<MethodDefinition>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <GetMethodDefinitions>d__2(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { //IL_003c: Unknown result type (might be due to invalid IL or missing references) int num = <>1__state; if ((uint)(num - -4) <= 1u || num == 1) { try { if (num == -4 || num == 1) { try { } finally { <>m__Finally2(); } } } finally { <>m__Finally1(); } } <>7__wrap1 = null; <>7__wrap2 = default(Enumerator<MethodDefinition>); <>1__state = -2; } private bool MoveNext() { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) try { int num = <>1__state; if (num != 0) { if (num != 1) { return false; } <>1__state = -4; goto IL_0089; } <>1__state = -1; <>7__wrap1 = GetTypeDefinitions(mod).GetEnumerator(); <>1__state = -3; goto IL_00a8; IL_0089: if (<>7__wrap2.MoveNext()) { MethodDefinition current = <>7__wrap2.Current; <>2__current = current; <>1__state = 1; return true; } <>m__Finally2(); <>7__wrap2 = default(Enumerator<MethodDefinition>); goto IL_00a8; IL_00a8: if (<>7__wrap1.MoveNext()) { TypeDefinition current2 = <>7__wrap1.Current; <>7__wrap2 = current2.Methods.GetEnumerator(); <>1__state = -4; goto IL_0089; } <>m__Finally1(); <>7__wrap1 = null; return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<>7__wrap1 != null) { <>7__wrap1.Dispose(); } } private void <>m__Finally2() { <>1__state = -3; ((IDisposable)<>7__wrap2).Dispose(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator<MethodDefinition> IEnumerable<MethodDefinition>.GetEnumerator() { <GetMethodDefinitions>d__2 <GetMethodDefinitions>d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; <GetMethodDefinitions>d__ = this; } else { <GetMethodDefinitions>d__ = new <GetMethodDefinitions>d__2(0); } <GetMethodDefinitions>d__.mod = <>3__mod; return <GetMethodDefinitions>d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<MethodDefinition>)this).GetEnumerator(); } } [CompilerGenerated] private sealed class <GetTypeDefinitions>d__1 : IEnumerable<TypeDefinition>, IEnumerable, IEnumerator<TypeDefinition>, IEnumerator, IDisposable { private int <>1__state; private TypeDefinition <>2__current; private int <>l__initialThreadId; private ModuleDefinition mod; public ModuleDefinition <>3__mod; private Enumerator<TypeDefinition> <>7__wrap1; private IEnumerator<TypeDefinition> <>7__wrap2; TypeDefinition IEnumerator<TypeDefinition>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <GetTypeDefinitions>d__1(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { //IL_0035: Unknown result type (might be due to invalid IL or missing references) int num = <>1__state; if ((uint)(num - -4) <= 1u || num == 1) { try { if (num == -4 || num == 1) { try { } finally { <>m__Finally2(); } } } finally { <>m__Finally1(); } } <>7__wrap1 = default(Enumerator<TypeDefinition>); <>7__wrap2 = null; <>1__state = -2; } private bool MoveNext() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) try { int num = <>1__state; if (num != 0) { if (num != 1) { return false; } <>1__state = -4; goto IL_008a; } <>1__state = -1; <>7__wrap1 = mod.Types.GetEnumerator(); <>1__state = -3; goto IL_00a4; IL_008a: if (<>7__wrap2.MoveNext()) { TypeDefinition current = <>7__wrap2.Current; <>2__current = current; <>1__state = 1; return true; } <>m__Finally2(); <>7__wrap2 = null; goto IL_00a4; IL_00a4: if (<>7__wrap1.MoveNext()) { TypeDefinition current2 = <>7__wrap1.Current; <>7__wrap2 = GetTypesRecursive(current2).GetEnumerator(); <>1__state = -4; goto IL_008a; } <>m__Finally1(); <>7__wrap1 = default(Enumerator<TypeDefinition>); return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; ((IDisposable)<>7__wrap1).Dispose(); } private void <>m__Finally2() { <>1__state = -3; if (<>7__wrap2 != null) { <>7__wrap2.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator<TypeDefinition> IEnumerable<TypeDefinition>.GetEnumerator() { <GetTypeDefinitions>d__1 <GetTypeDefinitions>d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; <GetTypeDefinitions>d__ = this; } else { <GetTypeDefinitions>d__ = new <GetTypeDefinitions>d__1(0); } <GetTypeDefinitions>d__.mod = <>3__mod; return <GetTypeDefinitions>d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<TypeDefinition>)this).GetEnumerator(); } } [CompilerGenerated] private sealed class <GetTypesRecursive>d__0 : IEnumerable<TypeDefinition>, IEnumerable, IEnumerator<TypeDefinition>, IEnumerator, IDisposable { private int <>1__state; private TypeDefinition <>2__current; private int <>l__initialThreadId; private bool includeSelf; public bool <>3__includeSelf; private TypeDefinition type; public TypeDefinition <>3__type; private Enumerator<TypeDefinition> <>7__wrap1; private IEnumerator<TypeDefinition> <>7__wrap2; TypeDefinition IEnumerator<TypeDefinition>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <GetTypesRecursive>d__0(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { //IL_0035: Unknown result type (might be due to invalid IL or missing references) int num = <>1__state; if ((uint)(num - -4) <= 1u || num == 2) { try { if (num == -4 || num == 2) { try { } finally { <>m__Finally2(); } } } finally { <>m__Finally1(); } } <>7__wrap1 = default(Enumerator<TypeDefinition>); <>7__wrap2 = null; <>1__state = -2; } private bool MoveNext() { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; if (includeSelf) { <>2__current = type; <>1__state = 1; return true; } goto IL_0050; case 1: <>1__state = -1; goto IL_0050; case 2: { <>1__state = -4; goto IL_00be; } IL_0050: <>7__wrap1 = type.NestedTypes.GetEnumerator(); <>1__state = -3; goto IL_00d8; IL_00d8: if (<>7__wrap1.MoveNext()) { TypeDefinition current = <>7__wrap1.Current; <>7__wrap2 = GetTypesRecursive(current).GetEnumerator(); <>1__state = -4; goto IL_00be; } <>m__Finally1(); <>7__wrap1 = default(Enumerator<TypeDefinition>); return false; IL_00be: if (<>7__wrap2.MoveNext()) { TypeDefinition current2 = <>7__wrap2.Current; <>2__current = current2; <>1__state = 2; return true; } <>m__Finally2(); <>7__wrap2 = null; goto IL_00d8; } } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; ((IDisposable)<>7__wrap1).Dispose(); } private void <>m__Finally2() { <>1__state = -3; if (<>7__wrap2 != null) { <>7__wrap2.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator<TypeDefinition> IEnumerable<TypeDefinition>.GetEnumerator() { <GetTypesRecursive>d__0 <GetTypesRecursive>d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; <GetTypesRecursive>d__ = this; } else { <GetTypesRecursive>d__ = new <GetTypesRecursive>d__0(0); } <GetTypesRecursive>d__.type = <>3__type; <GetTypesRecursive>d__.includeSelf = <>3__includeSelf; return <GetTypesRecursive>d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<TypeDefinition>)this).GetEnumerator(); } } [IteratorStateMachine(typeof(<GetTypesRecursive>d__0))] public static IEnumerable<TypeDefinition> GetTypesRecursive(TypeDefinition type, bool includeSelf = true) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <GetTypesRecursive>d__0(-2) { <>3__type = type, <>3__includeSelf = includeSelf }; } [IteratorStateMachine(typeof(<GetTypeDefinitions>d__1))] public static IEnumerable<TypeDefinition> GetTypeDefinitions(ModuleDefinition mod) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <GetTypeDefinitions>d__1(-2) { <>3__mod = mod }; } [IteratorStateMachine(typeof(<GetMethodDefinitions>d__2))] public static IEnumerable<MethodDefinition> GetMethodDefinitions(ModuleDefinition mod) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <GetMethodDefinitions>d__2(-2) { <>3__mod = mod }; } } } namespace SilksongPrepatcher.Patchers { public class MethodReplacer : BasePrepatcher { [CompilerGenerated] private Func<MethodReference, bool> <predicate>P; [CompilerGenerated] private MethodInfo <newMethodInfo>P; public MethodReplacer(Func<MethodReference, bool> predicate, MethodInfo newMethodInfo) { <predicate>P = predicate; <newMethodInfo>P = newMethodInfo; base..ctor("MethodReplacer -> " + <newMethodInfo>P.Name); } public override void PatchAssembly(AssemblyDefinition asm) { //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Expected O, but got Unknown //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Expected O, but got Unknown //IL_00ae: Unknown result type (might be due to invalid IL or missing references) MethodReference operand = asm.MainModule.ImportReference((MethodBase)<newMethodInfo>P); foreach (TypeDefinition typeDefinition in CecilUtils.GetTypeDefinitions(asm.MainModule)) { foreach (MethodDefinition item in ((IEnumerable<MethodDefinition>)typeDefinition.Methods).Where((MethodDefinition m) => m.HasBody)) { ILContext val = new ILContext(item); try { ILCursor val2 = new ILCursor(val); while (val2.TryGotoNext(new Func<Instruction, bool>[1] { delegate(Instruction i) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) if (i.OpCode == OpCodes.Call || i.OpCode == OpCodes.Callvirt) { object operand2 = i.Operand; MethodReference val3 = (MethodReference)((operand2 is MethodReference) ? operand2 : null); if (val3 != null) { return <predicate>P(val3); } } return false; } })) { base.Log.LogInfo((object)("Patching " + ((MemberReference)typeDefinition).FullName + " : " + ((MemberReference)item).FullName)); val2.Next.OpCode = OpCodes.Call; val2.Next.Operand = operand; } } finally { ((IDisposable)val)?.Dispose(); } } } } } public class ReflectionUtilsPatcher : BasePrepatcher { public override void PatchAssembly(AssemblyDefinition assembly) { TypeDefinition val = ((IEnumerable<TypeDefinition>)assembly.MainModule.Types).FirstOrDefault((Func<TypeDefinition, bool>)((TypeDefinition t) => ((MemberReference)t).Name == "ReflectionUtils")); if (val == null) { base.Log.LogInfo((object)("Could not find type ReflectionUtils in " + ((AssemblyNameReference)assembly.Name).Name)); return; } MethodDefinition val2 = ((IEnumerable<MethodDefinition>)val.Methods).FirstOrDefault((Func<MethodDefinition, bool>)((MethodDefinition m) => m.IsStatic && m.IsConstructor && m.IsSpecialName)); if (val2 == null) { base.Log.LogInfo((object)"Could not find static constructor"); } else { InjectTypeLookup(assembly.MainModule, val, val2); } } private void InjectTypeLookup(ModuleDefinition module, TypeDefinition typeDef, MethodDefinition cctor) { //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) FieldDefinition val = ((IEnumerable<FieldDefinition>)typeDef.Fields).FirstOrDefault((Func<FieldDefinition, bool>)((FieldDefinition f) => ((MemberReference)f).Name == "typeLookup" && f.IsStatic)); if (val == null) { return; } MethodReference val2 = module.ImportReference((MethodBase)typeof(Type).GetMethod("GetType", new Type[1] { typeof(string) })); MethodInfo method = typeof(Dictionary<, >).MakeGenericType(typeof(string), typeof(Type)).GetMethod("set_Item"); MethodReference val3 = module.ImportReference((MethodBase)method); ILProcessor iLProcessor = cctor.Body.GetILProcessor(); Instruction val4 = ((IEnumerable<Instruction>)cctor.Body.Instructions).Last(); if (val4.OpCode != OpCodes.Ret) { val4 = ((IEnumerable<Instruction>)cctor.Body.Instructions).Reverse().FirstOrDefault((Func<Instruction, bool>)((Instruction i) => i.OpCode == OpCodes.Ret)); if (val4 == null) { return; } } iLProcessor.InsertBefore(val4, iLProcessor.Create(OpCodes.Ldsfld, (FieldReference)(object)val)); iLProcessor.InsertBefore(val4, iLProcessor.Create(OpCodes.Ldstr, "TMProOldOld.TextAlignmentOptions")); iLProcessor.InsertBefore(val4, iLProcessor.Create(OpCodes.Ldstr, "TMProOld.TextAlignmentOptions, Assembly-CSharp")); iLProcessor.InsertBefore(val4, iLProcessor.Create(OpCodes.Call, val2)); iLProcessor.InsertBefore(val4, iLProcessor.Create(OpCodes.Callvirt, val3)); MethodBodyRocks.OptimizeMacros(cctor.Body); base.Log.LogInfo((object)"Patch successfully applied"); } } } namespace SilksongPrepatcher.Patchers.PlayerDataPatcher { public class PatchedMethodCache { private static readonly ManualLogSource Log = Logger.CreateLogSource("PatchedMethodCache"); public Dictionary<string, List<string>> PatchedMethods { get; set; } = new Dictionary<string, List<string>>(); public void Add(string typeName, string methodName) { if (!PatchedMethods.TryGetValue(typeName, out List<string> value)) { List<string> list2 = (PatchedMethods[typeName] = new List<string>()); value = list2; } value.Add(methodName); } public static string GetMetadataString() { string arg = typeof(PatchedMethodCache).Assembly.GetName().Version.ToString(); DateTime lastWriteTimeUtc = File.GetLastWriteTimeUtc(Path.Combine(Paths.ManagedPath, "Assembly-CSharp.dll")); return $"{arg} // {lastWriteTimeUtc}"; } public void Serialize(string filePath) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("X " + GetMetadataString()); foreach (var (text2, list2) in PatchedMethods) { stringBuilder.AppendLine("T " + text2); foreach (string item in list2) { stringBuilder.AppendLine("M " + item); } stringBuilder.AppendLine("E "); } File.WriteAllText(filePath, stringBuilder.ToString()); } public static PatchedMethodCache? Deserialize(string filePath) { if (!File.Exists(filePath)) { Log.LogDebug((object)"Failed to deserialize: no method cache found in cache dir."); return null; } bool flag = false; PatchedMethodCache patchedMethodCache = new PatchedMethodCache(); try { string[] array = File.ReadAllLines(filePath); string text = null; List<string> list = new List<string>(); string[] array2 = array; foreach (string text2 in array2) { if (text2.StartsWith("X ")) { if (!(text2.Substring(2) == GetMetadataString())) { Log.LogDebug((object)"Failed to deserialize: metadata mismatch."); return null; } flag = true; } else if (text2.StartsWith("T ")) { text = text2.Substring(2); } else if (text2.StartsWith("M ")) { list.Add(text2.Substring(2)); } else if (text2.StartsWith("E ")) { if (text == null) { throw new Exception("Key null on write"); } patchedMethodCache.PatchedMethods[text] = list; text = null; list = new List<string>(); } } } catch (Exception ex) { Log.LogError((object)("Failed to deserialize:\n" + ex)); return null; } if (!flag) { Log.LogInfo((object)"Failed to deserialize: no metadata found."); return null; } return patchedMethodCache; } } internal class PatchingContext { public enum AccessMethodType { Default, Generic } public static readonly HashSet<string> DefaultAccessMethods = new HashSet<string> { "Bool", "String", "Float", "Int", "Vector3" }; public ModuleDefinition MainModule { get; } public TypeDefinition PDType { get; } public MethodDefinition GenericGetMethod { get; } public MethodDefinition GenericSetMethod { get; } public Dictionary<TypeReference, MethodDefinition> DefaultGetMethods { get; } public Dictionary<TypeReference, MethodDefinition> DefaultSetMethods { get; } public PatchingContext(AssemblyDefinition asm) { MainModule = asm.MainModule; PDType = ((IEnumerable<TypeDefinition>)MainModule.Types).First((TypeDefinition t) => ((MemberReference)t).Name == "PlayerData"); DefaultGetMethods = ((IEnumerable<MethodDefinition>)PDType.Methods).Where((MethodDefinition m) => ((MemberReference)m).Name.StartsWith("Get") && DefaultAccessMethods.Contains(((MemberReference)m).Name.Substring(3))).ToDictionary((MethodDefinition m) => ((MethodReference)m).ReturnType); DefaultSetMethods = ((IEnumerable<MethodDefinition>)PDType.Methods).Where((MethodDefinition m) => ((MemberReference)m).Name.StartsWith("Set") && DefaultAccessMethods.Contains(((MemberReference)m).Name.Substring(3)) && ((MethodReference)m).Parameters.Count == 2).ToDictionary((MethodDefinition m) => ((ParameterReference)((MethodReference)m).Parameters[1]).ParameterType); TypeDefinition type = AssemblyDefinition.ReadAssembly(Path.Combine(Paths.ManagedPath, "TeamCherry.SharedUtils.dll")).MainModule.GetType("TeamCherry.SharedUtils.VariableExtensions"); GenericGetMethod = TypeDefinitionRocks.GetMethods(type).First((MethodDefinition x) => ((MemberReference)x).Name == "GetVariable" && ((MemberReference)x).ContainsGenericParameter && ((MethodReference)x).Parameters.Count == 2); GenericSetMethod = TypeDefinitionRocks.GetMethods(type).First((MethodDefinition x) => ((MemberReference)x).Name == "SetVariable" && ((MemberReference)x).ContainsGenericParameter && ((MethodReference)x).Parameters.Count == 3); } public MethodReference CreateGenericGetMethod(TypeReference fieldType) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown GenericInstanceMethod val = new GenericInstanceMethod(MainModule.ImportReference((MethodReference)(object)GenericGetMethod)); val.GenericArguments.Add(fieldType); return (MethodReference)val; } public void GetGetMethod(TypeReference fieldType, out MethodReference accessMethod, out AccessMethodType accessType) { if (DefaultGetMethods.TryGetValue(fieldType, out MethodDefinition value)) { accessMethod = MainModule.ImportReference((MethodReference)(object)value); accessType = AccessMethodType.Default; } else { accessMethod = CreateGenericGetMethod(fieldType); accessType = AccessMethodType.Generic; } } public MethodReference CreateGenericSetMethod(TypeReference fieldType) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown GenericInstanceMethod val = new GenericInstanceMethod(MainModule.ImportReference((MethodReference)(object)GenericSetMethod)); val.GenericArguments.Add(fieldType); return (MethodReference)val; } public void GetSetMethod(TypeReference fieldType, out MethodReference accessMethod, out AccessMethodType accessType) { if (DefaultSetMethods.TryGetValue(fieldType, out MethodDefinition value)) { accessMethod = MainModule.ImportReference((MethodReference)(object)value); accessType = AccessMethodType.Default; } else { accessMethod = CreateGenericSetMethod(fieldType); accessType = AccessMethodType.Generic; } } } public class PlayerDataPatcher : BasePrepatcher { private static string CacheFilePath => Path.Combine(SilksongPrepatcher.PatchCacheDir, "PlayerDataPatcher_cache.txt"); public override void PatchAssembly(AssemblyDefinition asm) { PatchingContext ctx = new PatchingContext(asm); PatchedMethodCache patchedMethodCache = PatchedMethodCache.Deserialize(CacheFilePath); if (patchedMethodCache == null) { ReplaceFieldAccesses(ctx); } else { ReplaceFieldAccessesFromCache(ctx, patchedMethodCache); } } private void ReplaceFieldAccessesFromCache(PatchingContext ctx, PatchedMethodCache cache) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) int num = 0; int num2 = 0; Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); foreach (KeyValuePair<string, List<string>> patchedMethod in cache.PatchedMethods) { patchedMethod.Deconstruct(out var key, out var value); string text = key; List<string> list = value; TypeDefinition type = ctx.MainModule.GetType(text); new HashSet<string>(list); Enumerator<MethodDefinition> enumerator2 = type.Methods.GetEnumerator(); try { while (enumerator2.MoveNext()) { MethodDefinition current = enumerator2.Current; if (list.Contains(((MemberReference)current).FullName)) { if (!PatchMethod(current, ctx, out var replaced, out var missed)) { throw new Exception("Failed to patch " + text + " " + ((MemberReference)current).FullName); } num += replaced; num2 += missed; } } } finally { ((IDisposable)enumerator2).Dispose(); } } stopwatch.Stop(); base.Log.LogInfo((object)$"Patched {num} accesses from cache in {stopwatch.ElapsedMilliseconds} ms"); } private void ReplaceFieldAccesses(PatchingContext ctx) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) int num = 0; int num2 = 0; PatchedMethodCache patchedMethodCache = new PatchedMethodCache(); Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); foreach (TypeDefinition typeDefinition in CecilUtils.GetTypeDefinitions(ctx.MainModule)) { Enumerator<MethodDefinition> enumerator2 = typeDefinition.Methods.GetEnumerator(); try { while (enumerator2.MoveNext()) { MethodDefinition current2 = enumerator2.Current; if (current2.HasBody && (current2.DeclaringType != ctx.PDType || (!(((MemberReference)current2).Name == "SetupNewPlayerData") && !(((MemberReference)current2).Name == "SetupExistingPlayerData") && !((MemberReference)current2).Name.Contains(".ctor")))) { if (PatchMethod(current2, ctx, out var replaced, out var missed)) { patchedMethodCache.Add(((MemberReference)typeDefinition).FullName, ((MemberReference)current2).FullName); } num += replaced; num2 += missed; } } } finally { ((IDisposable)enumerator2).Dispose(); } } stopwatch.Stop(); base.Log.LogInfo((object)$"Patched {num} accesses in {stopwatch.ElapsedMilliseconds} ms"); base.Log.LogInfo((object)$"Missed {num2} accesses"); patchedMethodCache.Serialize(CacheFilePath); } private bool PatchMethod(MethodDefinition method, PatchingContext ctx, out int replaced, out int missed) { //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0270: Unknown result type (might be due to invalid IL or missing references) //IL_0275: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) PatchingContext ctx2 = ctx; MethodDefinition method2 = method; Dictionary<TypeReference, VariableReference> addedVariables = new Dictionary<TypeReference, VariableReference>(); replaced = 0; missed = 0; MethodBodyRocks.SimplifyMacros(method2.Body); ILProcessor iLProcessor = method2.Body.GetILProcessor(); for (int num = iLProcessor.Body.Instructions.Count - 1; num >= 0; num--) { Instruction val = iLProcessor.Body.Instructions[num]; object operand = val.Operand; FieldReference val2 = (FieldReference)((operand is FieldReference) ? operand : null); if (val2 != null && !(((MemberReference)((MemberReference)val2).DeclaringType).FullName != ((MemberReference)ctx2.PDType).FullName) && !val2.Resolve().IsPrivate && !((IEnumerable<CustomAttribute>)val2.Resolve().CustomAttributes).Any((CustomAttribute ca) => ((MemberReference)ca.AttributeType).FullName == "System.NonSerializedAttribute")) { if (val.OpCode == OpCodes.Ldfld) { ctx2.GetGetMethod(val2.FieldType, out MethodReference accessMethod, out PatchingContext.AccessMethodType accessType); OpCode val3 = ((accessType == PatchingContext.AccessMethodType.Default) ? OpCodes.Callvirt : OpCodes.Call); Instruction[] array = (Instruction[])(object)new Instruction[2] { iLProcessor.Create(OpCodes.Ldstr, ((MemberReference)val2).Name), iLProcessor.Create(val3, accessMethod) }; val.OpCode = array[0].OpCode; val.Operand = array[0].Operand; iLProcessor.InsertAfter(val, array[1]); replaced++; } else if (val.OpCode == OpCodes.Stfld) { ctx2.GetSetMethod(val2.FieldType, out MethodReference accessMethod2, out PatchingContext.AccessMethodType accessType2); OpCode val4 = ((accessType2 == PatchingContext.AccessMethodType.Default) ? OpCodes.Callvirt : OpCodes.Call); VariableReference val5 = GetOrAddLocal(val2.FieldType); Instruction[] array2 = (Instruction[])(object)new Instruction[4] { Extensions.Create(iLProcessor, OpCodes.Stloc, (object)val5), iLProcessor.Create(OpCodes.Ldstr, ((MemberReference)val2).Name), Extensions.Create(iLProcessor, OpCodes.Ldloc, (object)val5), iLProcessor.Create(val4, accessMethod2) }; val.OpCode = array2[0].OpCode; val.Operand = array2[0].Operand; iLProcessor.InsertAfter(val, array2[1]); iLProcessor.InsertAfter(array2[1], array2[2]); iLProcessor.InsertAfter(array2[2], array2[3]); replaced++; } else if (val.OpCode == OpCodes.Ldflda) { if (TryPatchRefAccess(iLProcessor, val, method2, ctx2, GetOrAddLocal)) { replaced++; } else { missed++; } } } } MethodBodyRocks.OptimizeMacros(method2.Body); return replaced > 0; VariableReference GetOrAddLocal(TypeReference td) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown TypeReference val6 = ctx2.MainModule.ImportReference(td); if (!addedVariables.ContainsKey(val6)) { VariableDefinition val7 = new VariableDefinition(val6); method2.Body.Variables.Add(val7); addedVariables.Add(val6, (VariableReference)(object)val7); } return addedVariables[val6]; } } private bool TryPatchRefAccess(ILProcessor il, Instruction instr, MethodDefinition method, PatchingContext ctx, Func<TypeReference, VariableReference> getOrAddLocal) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) Instruction next = instr.Next; if (next.OpCode == OpCodes.Call) { object operand = next.Operand; MethodReference val = (MethodReference)((operand is MethodReference) ? operand : null); if (val != null && ((MemberReference)val.ReturnType).FullName == "System.Void" && val.Parameters.Count == 1) { object operand2 = instr.Operand; FieldReference val2 = (FieldReference)((operand2 is FieldReference) ? operand2 : null); if (val2 != null) { VariableReference val3 = getOrAddLocal(val2.FieldType); ctx.GetGetMethod(val2.FieldType, out MethodReference accessMethod, out PatchingContext.AccessMethodType accessType); OpCode val4 = ((accessType == PatchingContext.AccessMethodType.Default) ? OpCodes.Callvirt : OpCodes.Call); ctx.GetSetMethod(val2.FieldType, out MethodReference accessMethod2, out PatchingContext.AccessMethodType accessType2); OpCode val5 = ((accessType2 == PatchingContext.AccessMethodType.Default) ? OpCodes.Callvirt : OpCodes.Call); Instruction[] array = (Instruction[])(object)new Instruction[9] { il.Create(OpCodes.Dup), il.Create(OpCodes.Ldstr, ((MemberReference)val2).Name), il.Create(val4, accessMethod), Extensions.Create(il, OpCodes.Stloc, (object)val3), Extensions.Create(il, OpCodes.Ldloca, (object)val3), next, il.Create(OpCodes.Ldstr, ((MemberReference)val2).Name), Extensions.Create(il, OpCodes.Ldloc, (object)val3), il.Create(val5, accessMethod2) }; il.InsertBefore(instr, array[0]); instr.OpCode = array[1].OpCode; instr.Operand = array[1].Operand; il.InsertAfter(instr, array[2]); il.InsertAfter(array[2], array[3]); il.InsertAfter(array[3], array[4]); il.InsertAfter(next, array[6]); il.InsertAfter(array[6], array[7]); il.InsertAfter(array[7], array[8]); return true; } } } return false; } } public class VariableExtensionsPatcher : BasePrepatcher { public override void PatchAssembly(AssemblyDefinition asm) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) ModuleDefinition mainModule = asm.MainModule; string text = "TeamCherry.SharedUtils.VariableExtensions"; TypeDefinition type = mainModule.GetType(text); MethodDefinition val = null; Enumerator<MethodDefinition> enumerator = type.Methods.GetEnumerator(); try { while (enumerator.MoveNext()) { MethodDefinition current = enumerator.Current; if (!(((MemberReference)current).Name != "GetVariables")) { TypeReference parameterType = ((ParameterReference)((MethodReference)current).Parameters[1]).ParameterType; GenericInstanceType val2 = (GenericInstanceType)(object)((parameterType is GenericInstanceType) ? parameterType : null); if (val2 != null && !(((MemberReference)val2).Name != "Func`2") && !(((MemberReference)((TypeReference)val2).Resolve()).FullName != "System.Func`2")) { val = current; break; } } } } finally { ((IDisposable)enumerator).Dispose(); } MethodDefinition val3 = null; enumerator = type.Methods.GetEnumerator(); try { while (enumerator.MoveNext()) { MethodDefinition current2 = enumerator.Current; if (!(((MemberReference)current2).Name != "GetVariable") && ((MethodReference)current2).Parameters.Count == 2 && ((MemberReference)current2).ContainsGenericParameter) { val3 = current2; break; } } } finally { ((IDisposable)enumerator).Dispose(); } if (val != null && val3 != null) { PatchGetVariablesMethod(val, val3, mainModule); } } private void PatchGetVariablesMethod(MethodDefinition method, MethodDefinition getVariableMethod, ModuleDefinition mod) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_0226: Unknown result type (might be due to invalid IL or missing references) base.Log.LogInfo((object)("Found method " + ((MemberReference)method).FullName)); GenericParameter val = ((MethodReference)method).GenericParameters[0]; GenericInstanceMethod val2 = new GenericInstanceMethod((MethodReference)(object)getVariableMethod); val2.GenericArguments.Add((TypeReference)(object)val); MethodBodyRocks.SimplifyMacros(method.Body); method.Body.GetILProcessor(); Instruction val3 = null; Enumerator<Instruction> enumerator = method.Body.Instructions.GetEnumerator(); try { while (enumerator.MoveNext()) { Instruction current = enumerator.Current; if (current.OpCode == OpCodes.Callvirt) { object operand = current.Operand; MethodReference val4 = (MethodReference)((operand is MethodReference) ? operand : null); if (val4 != null && ((MemberReference)val4).Name == "GetValue" && ((MemberReference)((MemberReference)val4).DeclaringType).FullName == "System.Reflection.FieldInfo") { val3 = current; break; } } } } finally { ((IDisposable)enumerator).Dispose(); } if (val3 == null) { throw new Exception("Could not find call to FieldInfo::GetValue."); } Instruction[] array = (Instruction[])(object)new Instruction[4] { val3.Previous.Previous, val3.Previous, val3, val3.Next }; OpCode opCode = array[0].OpCode; if (!((OpCode)(ref opCode)).Name.ToLower().StartsWith("ldloc")) { throw new Exception("First instruction not Ldloc"); } opCode = array[1].OpCode; if (!((OpCode)(ref opCode)).Name.ToLower().StartsWith("ldarg")) { throw new Exception("Second instruction not Ldarg"); } opCode = array[3].OpCode; if (!((OpCode)(ref opCode)).Name.ToLower().StartsWith("unbox")) { throw new Exception("Fourth instruction not unbox"); } OpCode opCode2 = array[1].OpCode; object operand2 = array[1].Operand; array[1].OpCode = array[0].OpCode; array[1].Operand = array[0].Operand; array[0].OpCode = opCode2; array[0].Operand = operand2; MethodInfo getMethod = typeof(FieldInfo).GetProperty("Name").GetGetMethod(); MethodReference operand3 = mod.ImportReference((MethodBase)getMethod); array[2].OpCode = OpCodes.Callvirt; array[2].Operand = operand3; array[3].OpCode = OpCodes.Call; array[3].Operand = val2; MethodBodyRocks.OptimizeMacros(method.Body); } } }
plugins/PrepatcherPlugin.dll
Decompiled 6 days agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Logging; using Microsoft.CodeAnalysis; using MonoMod.RuntimeDetour; using TeamCherry.SharedUtils; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("PrepatcherPlugin")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.2.0")] [assembly: AssemblyInformationalVersion("1.0.2+a22d0b9cfde457406fae294d2fcf0c7a234d839d")] [assembly: AssemblyProduct("PrepatcherPlugin")] [assembly: AssemblyTitle("PrepatcherPlugin")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/silksong-modding/Silksong.Prepatcher")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.2.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace BepInEx { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] internal sealed class BepInAutoPluginAttribute : Attribute { public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace BepInEx.Preloader.Core.Patching { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] internal sealed class PatcherAutoPluginAttribute : Attribute { public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace PrepatcherPlugin { internal static class Extensions { public static MethodInfo GetMethodOrThrow(this Type type, string name) { MethodInfo? method = type.GetMethod(name); if (method == null) { throw new MissingMemberException(type.FullName, name); } return method; } } internal static class Hooks { private static List<Hook>? hooks = null; private static readonly Dictionary<Type, Func<PlayerData, string, object, object>> GenericGetMethodCache = new Dictionary<Type, Func<PlayerData, string, object, object>>(); private static readonly Dictionary<Type, Func<PlayerData, string, object, object>> GenericSetMethodCache = new Dictionary<Type, Func<PlayerData, string, object, object>>(); internal static void EnsureHooked() { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Expected O, but got Unknown //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Expected O, but got Unknown //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Expected O, but got Unknown //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Expected O, but got Unknown //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Expected O, but got Unknown //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Expected O, but got Unknown //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Expected O, but got Unknown //IL_0249: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Expected O, but got Unknown //IL_02a2: Unknown result type (might be due to invalid IL or missing references) //IL_02ac: Expected O, but got Unknown //IL_02fb: Unknown result type (might be due to invalid IL or missing references) //IL_0305: Expected O, but got Unknown if (hooks == null) { hooks = new List<Hook>(12) { new Hook((MethodBase)typeof(PlayerData).GetMethodOrThrow("GetBool"), (Delegate)new Func<Func<PlayerData, string, bool>, PlayerData, string, bool>(ModifyGetBool)), new Hook((MethodBase)typeof(PlayerData).GetMethodOrThrow("SetBool"), (Delegate)new Action<Action<PlayerData, string, bool>, PlayerData, string, bool>(ModifySetBool)), new Hook((MethodBase)typeof(PlayerData).GetMethodOrThrow("GetInt"), (Delegate)new Func<Func<PlayerData, string, int>, PlayerData, string, int>(ModifyGetInt)), new Hook((MethodBase)typeof(PlayerData).GetMethodOrThrow("SetInt"), (Delegate)new Action<Action<PlayerData, string, int>, PlayerData, string, int>(ModifySetInt)), new Hook((MethodBase)typeof(PlayerData).GetMethodOrThrow("GetString"), (Delegate)new Func<Func<PlayerData, string, string>, PlayerData, string, string>(ModifyGetString)), new Hook((MethodBase)typeof(PlayerData).GetMethodOrThrow("SetString"), (Delegate)new Action<Action<PlayerData, string, string>, PlayerData, string, string>(ModifySetString)), new Hook((MethodBase)typeof(PlayerData).GetMethodOrThrow("GetFloat"), (Delegate)new Func<Func<PlayerData, string, float>, PlayerData, string, float>(ModifyGetFloat)), new Hook((MethodBase)typeof(PlayerData).GetMethodOrThrow("SetFloat"), (Delegate)new Action<Action<PlayerData, string, float>, PlayerData, string, float>(ModifySetFloat)), new Hook((MethodBase)typeof(PlayerData).GetMethodOrThrow("GetVector3"), (Delegate)new Func<Func<PlayerData, string, Vector3>, PlayerData, string, Vector3>(ModifyGetVector3)), new Hook((MethodBase)typeof(PlayerData).GetMethodOrThrow("SetVector3"), (Delegate)new Action<Action<PlayerData, string, Vector3>, PlayerData, string, Vector3>(ModifySetVector3)), new Hook((MethodBase)typeof(VariableExtensions).GetMethods().First((MethodInfo m) => m.Name == "GetVariable" && !m.IsGenericMethod), (Delegate)new Func<Func<IIncludeVariableExtensions, string, Type, object>, IIncludeVariableExtensions, string, Type, object>(ModifyGetVariable)), new Hook((MethodBase)typeof(VariableExtensions).GetMethods().First((MethodInfo m) => m.Name == "SetVariable" && !m.IsGenericMethod), (Delegate)new Action<Action<IIncludeVariableExtensions, string, object, Type>, IIncludeVariableExtensions, string, object, Type>(ModifySetVariable)) }; } } private static bool ModifyGetBool(Func<PlayerData, string, bool> orig, PlayerData self, string boolName) { bool current = orig(self, boolName); return PlayerDataVariableEvents<bool>.ModifyGetVariable(self, boolName, current); } private static void ModifySetBool(Action<PlayerData, string, bool> orig, PlayerData self, string boolName, bool value) { bool arg = PlayerDataVariableEvents<bool>.ModifySetVariable(self, boolName, value); orig(self, boolName, arg); } private static int ModifyGetInt(Func<PlayerData, string, int> orig, PlayerData self, string intName) { int current = orig(self, intName); return PlayerDataVariableEvents<int>.ModifyGetVariable(self, intName, current); } private static void ModifySetInt(Action<PlayerData, string, int> orig, PlayerData self, string intName, int value) { int arg = PlayerDataVariableEvents<int>.ModifySetVariable(self, intName, value); orig(self, intName, arg); } private static string ModifyGetString(Func<PlayerData, string, string> orig, PlayerData self, string stringName) { string current = orig(self, stringName); return PlayerDataVariableEvents<string>.ModifyGetVariable(self, stringName, current); } private static void ModifySetString(Action<PlayerData, string, string> orig, PlayerData self, string stringName, string value) { string arg = PlayerDataVariableEvents<string>.ModifySetVariable(self, stringName, value); orig(self, stringName, arg); } private static float ModifyGetFloat(Func<PlayerData, string, float> orig, PlayerData self, string floatName) { float current = orig(self, floatName); return PlayerDataVariableEvents<float>.ModifyGetVariable(self, floatName, current); } private static void ModifySetFloat(Action<PlayerData, string, float> orig, PlayerData self, string floatName, float value) { float arg = PlayerDataVariableEvents<float>.ModifySetVariable(self, floatName, value); orig(self, floatName, arg); } private static Vector3 ModifyGetVector3(Func<PlayerData, string, Vector3> orig, PlayerData self, string vector3Name) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) Vector3 current = orig(self, vector3Name); return PlayerDataVariableEvents<Vector3>.ModifyGetVariable(self, vector3Name, current); } private static void ModifySetVector3(Action<PlayerData, string, Vector3> orig, PlayerData self, string vector3Name, Vector3 value) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) Vector3 arg = PlayerDataVariableEvents<Vector3>.ModifySetVariable(self, vector3Name, value); orig(self, vector3Name, arg); } private static object ModifyGetVariable(Func<IIncludeVariableExtensions, string, Type, object> orig, IIncludeVariableExtensions obj, string fieldName, Type type) { object obj2 = orig(obj, fieldName, type); PlayerData val = (PlayerData)(object)((obj is PlayerData) ? obj : null); if (val == null) { return obj2; } if (!GenericGetMethodCache.TryGetValue(type, out Func<PlayerData, string, object, object> value)) { MethodInfo method = typeof(PlayerDataVariableEvents<>).MakeGenericType(type).GetMethod("ModifyGetVariableNonGeneric", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); value = (Func<PlayerData, string, object, object>)Delegate.CreateDelegate(typeof(Func<PlayerData, string, object, object>), method); GenericGetMethodCache[type] = value; } return value(val, fieldName, obj2); } private static void ModifySetVariable(Action<IIncludeVariableExtensions, string, object, Type> orig, IIncludeVariableExtensions obj, string fieldName, object value, Type type) { PlayerData val = (PlayerData)(object)((obj is PlayerData) ? obj : null); if (val == null) { orig(obj, fieldName, value, type); return; } if (!GenericSetMethodCache.TryGetValue(type, out Func<PlayerData, string, object, object> value2)) { MethodInfo method = typeof(PlayerDataVariableEvents<>).MakeGenericType(type).GetMethod("ModifySetVariableNonGeneric", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); value2 = (Func<PlayerData, string, object, object>)Delegate.CreateDelegate(typeof(Func<PlayerData, string, object, object>), method); GenericSetMethodCache[type] = value2; } object arg = value2(val, fieldName, value); orig(obj, fieldName, arg, type); } } public static class PlayerDataVariableEvents<T> { public delegate T PlayerDataVariableHandler(PlayerData pd, string fieldName, T current); private static readonly ManualLogSource Log = Logger.CreateLogSource("PlayerDataVariableEvents"); private static PlayerDataVariableHandler? _onGetVariable; private static PlayerDataVariableHandler? _onSetVariable; public static event PlayerDataVariableHandler? OnGetVariable { add { Hooks.EnsureHooked(); _onGetVariable = (PlayerDataVariableHandler)Delegate.Combine(_onGetVariable, value); } remove { _onGetVariable = (PlayerDataVariableHandler)Delegate.Remove(_onGetVariable, value); } } public static event PlayerDataVariableHandler? OnSetVariable { add { Hooks.EnsureHooked(); _onSetVariable = (PlayerDataVariableHandler)Delegate.Combine(_onSetVariable, value); } remove { _onSetVariable = (PlayerDataVariableHandler)Delegate.Remove(_onSetVariable, value); } } internal static T ModifyGetVariable(PlayerData pd, string fieldName, T current) { if (_onGetVariable == null) { return current; } foreach (PlayerDataVariableHandler item in _onGetVariable.GetInvocationList().Cast<PlayerDataVariableHandler>()) { try { current = item(pd, fieldName, current); } catch (Exception ex) { Log.LogError((object)("Error invoking ModifyGetVariable, " + typeof(T).Name + "\n" + ex)); } } return current; } internal static object? ModifyGetVariableNonGeneric(PlayerData pd, string fieldName, object current) { T current2; try { current2 = (T)current; } catch (Exception) { Log.LogWarning((object)string.Format("Failed to cast fieldname {0}, object {1} to type {2} in {3}", fieldName, current, typeof(T), "ModifySetVariableNonGeneric")); current2 = default(T); } return ModifyGetVariable(pd, fieldName, current2); } internal static T ModifySetVariable(PlayerData pd, string fieldName, T current) { if (_onSetVariable == null) { return current; } Delegate[] invocationList = _onSetVariable.GetInvocationList(); for (int i = 0; i < invocationList.Length; i++) { PlayerDataVariableHandler playerDataVariableHandler = (PlayerDataVariableHandler)invocationList[i]; try { current = playerDataVariableHandler(pd, fieldName, current); } catch (Exception ex) { Log.LogError((object)("Error invoking ModifyGetVariable, " + typeof(T).Name + "\n" + ex)); } } return current; } internal static object? ModifySetVariableNonGeneric(PlayerData pd, string fieldName, object current) { T current2; try { current2 = (T)current; } catch (Exception) { Log.LogWarning((object)string.Format("Failed to cast fieldname {0}, object {1} to type {2} in {3}", fieldName, current, typeof(T), "ModifySetVariableNonGeneric")); return current; } return ModifySetVariable(pd, fieldName, current2); } } public static class PlayerDataVariableEvents { public static event PlayerDataVariableEvents<bool>.PlayerDataVariableHandler? OnGetBool { add { PlayerDataVariableEvents<bool>.OnGetVariable += value; } remove { PlayerDataVariableEvents<bool>.OnGetVariable -= value; } } public static event PlayerDataVariableEvents<bool>.PlayerDataVariableHandler? OnSetBool { add { PlayerDataVariableEvents<bool>.OnSetVariable += value; } remove { PlayerDataVariableEvents<bool>.OnSetVariable -= value; } } public static event PlayerDataVariableEvents<int>.PlayerDataVariableHandler? OnGetInt { add { PlayerDataVariableEvents<int>.OnGetVariable += value; } remove { PlayerDataVariableEvents<int>.OnGetVariable -= value; } } public static event PlayerDataVariableEvents<int>.PlayerDataVariableHandler? OnSetInt { add { PlayerDataVariableEvents<int>.OnSetVariable += value; } remove { PlayerDataVariableEvents<int>.OnSetVariable -= value; } } public static event PlayerDataVariableEvents<string>.PlayerDataVariableHandler? OnGetString { add { PlayerDataVariableEvents<string>.OnGetVariable += value; } remove { PlayerDataVariableEvents<string>.OnGetVariable -= value; } } public static event PlayerDataVariableEvents<string>.PlayerDataVariableHandler? OnSetString { add { PlayerDataVariableEvents<string>.OnSetVariable += value; } remove { PlayerDataVariableEvents<string>.OnSetVariable -= value; } } public static event PlayerDataVariableEvents<float>.PlayerDataVariableHandler? OnGetFloat { add { PlayerDataVariableEvents<float>.OnGetVariable += value; } remove { PlayerDataVariableEvents<float>.OnGetVariable -= value; } } public static event PlayerDataVariableEvents<float>.PlayerDataVariableHandler? OnSetFloat { add { PlayerDataVariableEvents<float>.OnSetVariable += value; } remove { PlayerDataVariableEvents<float>.OnSetVariable -= value; } } public static event PlayerDataVariableEvents<Vector3>.PlayerDataVariableHandler? OnGetVector3 { add { PlayerDataVariableEvents<Vector3>.OnGetVariable += value; } remove { PlayerDataVariableEvents<Vector3>.OnGetVariable -= value; } } public static event PlayerDataVariableEvents<Vector3>.PlayerDataVariableHandler? OnSetVector3 { add { PlayerDataVariableEvents<Vector3>.OnSetVariable += value; } remove { PlayerDataVariableEvents<Vector3>.OnSetVariable -= value; } } } [BepInPlugin("org.silksong-modding.prepatcher", "PrepatcherPlugin", "1.0.2")] public class PrepatcherPlugin : BaseUnityPlugin { public const string Id = "org.silksong-modding.prepatcher"; public static string Name => "PrepatcherPlugin"; public static string Version => "1.0.2"; private void Awake() { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Plugin " + Name + " (org.silksong-modding.prepatcher) has loaded!")); } } }