public override DynamicMethodDefinition CopyOriginal() { DynamicMethodDefinition method = Original.ToNewDynamicMethodDefinition(); method.Definition.Name += "_wrapper"; ILContext ilcontext = new ILContext(method.Definition); ILCursor ilcursor = new ILCursor(ilcontext); FieldReference tempfieldreference = null; if (ilcursor.TryGotoNext(x => x.MatchLdsfld(out tempfieldreference), x => x.MatchCall(UnhollowerSupport.IL2CPPType, "il2cpp_object_get_virtual_method"))) { // Virtual method: Replace the sequence // - ldarg.0 // - call native int[UnhollowerBaseLib] UnhollowerBaseLib.IL2CPP::Il2CppObjectBaseToPtr(class [UnhollowerBaseLib] UnhollowerBaseLib.Il2CppObjectBase) // - ldsfld native int SomeClass::NativeMethodInfoPtr_Etc // - call native int[UnhollowerBaseLib] UnhollowerBaseLib.IL2CPP::il2cpp_object_get_virtual_method(native int, native int) ilcursor.Index -= 2; ilcursor.RemoveRange(4); } else if (ilcursor.TryGotoNext(x => x.MatchLdsfld(UnhollowerSupport.MethodBaseToIl2CppFieldInfo(Original)))) { ilcursor.Remove(); } else { MelonLogger.Error("Harmony Patcher could not rewrite Il2Cpp Unhollowed Method. Expect a stack overflow."); return(method); } ilcursor.Emit(Mono.Cecil.Cil.OpCodes.Ldc_I8, copiedMethodInfoPointer.ToInt64()); ilcursor.Emit(Mono.Cecil.Cil.OpCodes.Conv_I); return(method); }
public static void RegisterAssembly(Assembly asm) { if (!MelonUtils.IsGameIl2Cpp()) { return; } IEnumerable <Type> typeTbl = asm.GetValidTypes(); if ((typeTbl == null) || (typeTbl.Count() <= 0)) { return; } foreach (Type type in typeTbl) { object[] attTbl = type.GetCustomAttributes(typeof(RegisterTypeInIl2Cpp), false); if ((attTbl == null) || (attTbl.Length <= 0)) { continue; } RegisterTypeInIl2Cpp att = (RegisterTypeInIl2Cpp)attTbl[0]; if (att == null) { continue; } UnhollowerSupport.RegisterTypeInIl2CppDomain(type, att.LogSuccess); } }
internal static void TryResolve(object sender, PatchManager.PatcherResolverEventArgs args) { if (UnhollowerSupport.IsGeneratedAssemblyType(args.Original.DeclaringType)) { args.MethodPatcher = new HarmonyIl2CppMethodPatcher(args.Original); } }
private static void OnApplicationStart() { if (Imports.IsIl2CppGame()) { Assembly_CSharp = Assembly.Load("Assembly-CSharp"); UnhollowerSupport.Initialize(); } SupportModule.Initialize(); MelonModLogger.Log("------------------------------"); MelonModLogger.Log("Unity " + UnityVersion); MelonModLogger.Log("------------------------------"); MelonModLogger.Log("Name: " + CurrentGameAttribute.GameName); MelonModLogger.Log("Developer: " + CurrentGameAttribute.Developer); MelonModLogger.Log("Type: " + (Imports.IsIl2CppGame() ? "Il2Cpp" : (Imports.IsOldMono() ? "Mono" : "MonoBleedingEdge"))); MelonModLogger.Log("------------------------------"); MelonModLogger.Log("Using v" + BuildInfo.Version + " Open-Beta"); MelonModLogger.Log("------------------------------"); LoadMods(); if (Mods.Count > 0) { for (int i = 0; i < Mods.Count; i++) { MelonMod mod = Mods[i]; if (mod != null) { MelonModLogger.Log(mod.InfoAttribute.Name + (!string.IsNullOrEmpty(mod.InfoAttribute.Version) ? (" v" + mod.InfoAttribute.Version) : "") + (!string.IsNullOrEmpty(mod.InfoAttribute.Author) ? (" by " + mod.InfoAttribute.Author) : "") + (!string.IsNullOrEmpty(mod.InfoAttribute.DownloadLink) ? (" (" + mod.InfoAttribute.DownloadLink + ")") : "") ); if (Imports.IsDebugMode()) { MelonModLogger.Log("Preload: " + mod.IsPreload.ToString()); } MelonModLogger.LogModStatus((mod.GameAttributes.Any()) ? (mod.IsUniversal ? 0 : 1) : 2); MelonModLogger.Log("------------------------------"); } } for (int i = 0; i < Mods.Count; i++) { MelonMod mod = Mods[i]; if (mod != null) { try { mod.OnApplicationStart(); } catch (Exception ex) { MelonModLogger.LogModError(ex.ToString(), mod.InfoAttribute.Name); } } } } else { MelonModLogger.Log("No Mods Loaded!"); MelonModLogger.Log("------------------------------"); } }
private static void ConvertTypeToIl2Cpp(ILGenerator il, Type returnType) { if (returnType == typeof(string)) { il.Emit(OpCodes.Call, UnhollowerSupport.ManagedStringToIl2CppMethod); } else if (!returnType.IsValueType && UnhollowerSupport.IsGeneratedAssemblyType(returnType)) { il.Emit(OpCodes.Call, UnhollowerSupport.Il2CppObjectBaseToPtrMethod); } }
private void WarnIfOriginalMethodIsInlined(string melonName) { int callerCount = UnhollowerSupport.GetIl2CppMethodCallerCount(Original) ?? -1; if ((callerCount > 0) || UnityMagicMethods.IsUnityMagicMethod(Original)) { return; } MelonLogger.ManualWarning(melonName, $"Harmony: Method {Original.FullDescription()} does not appear to get called directly from anywhere, " + "suggesting it may have been inlined and your patch may not be called."); }
private static Type Il2CppTypeForPatchType(Type type) { if (type.IsByRef) { Type element = type.GetElementType(); if (element == typeof(string) || UnhollowerSupport.IsGeneratedAssemblyType(element)) { return(typeof(IntPtr *)); } } else if (type == typeof(string) || UnhollowerSupport.IsGeneratedAssemblyType(type)) { return(typeof(IntPtr)); } return(type); }
private static void OnApplicationStart() { if (!HasGeneratedAssembly) { return; } if (Imports.IsIl2CppGame()) { if (IsVRChat) { Assembly_CSharp = Assembly.Load("Assembly-CSharp"); } UnhollowerSupport.Initialize(); } SupportModule.Initialize(); MelonModLogger.Log("------------------------------"); MelonModLogger.Log("Unity " + UnityVersion); MelonModLogger.Log("------------------------------"); MelonModLogger.Log("Name: " + CurrentGameAttribute.GameName); MelonModLogger.Log("Developer: " + CurrentGameAttribute.Developer); MelonModLogger.Log("Type: " + (Imports.IsIl2CppGame() ? "Il2Cpp" : (Imports.IsOldMono() ? "Mono" : "MonoBleedingEdge"))); MelonModLogger.Log("------------------------------"); MelonModLogger.Log("Using v" + BuildInfo.Version + " Open-Beta"); MelonModLogger.Log("------------------------------"); LoadDLLs(); if (Plugins.Count > 0) { for (int i = 0; i < Plugins.Count; i++) { MelonPlugin plugin = Plugins[i]; if (plugin != null) { MelonModLogger.Log(plugin.InfoAttribute.Name + (!string.IsNullOrEmpty(plugin.InfoAttribute.Version) ? (" v" + plugin.InfoAttribute.Version) : "") + (!string.IsNullOrEmpty(plugin.InfoAttribute.Author) ? (" by " + plugin.InfoAttribute.Author) : "") + (!string.IsNullOrEmpty(plugin.InfoAttribute.DownloadLink) ? (" (" + plugin.InfoAttribute.DownloadLink + ")") : "") ); MelonModLogger.LogDLLStatus(plugin.Compatibility); MelonModLogger.Log("------------------------------"); } } Plugins = TempPlugins; } if (Plugins.Count <= 0) { MelonModLogger.Log("No Plugins Loaded!"); MelonModLogger.Log("------------------------------"); } if (Mods.Count > 0) { for (int i = 0; i < Mods.Count; i++) { MelonMod mod = Mods[i]; if (mod != null) { MelonModLogger.Log(mod.InfoAttribute.Name + (!string.IsNullOrEmpty(mod.InfoAttribute.Version) ? (" v" + mod.InfoAttribute.Version) : "") + (!string.IsNullOrEmpty(mod.InfoAttribute.Author) ? (" by " + mod.InfoAttribute.Author) : "") + (!string.IsNullOrEmpty(mod.InfoAttribute.DownloadLink) ? (" (" + mod.InfoAttribute.DownloadLink + ")") : "") ); MelonModLogger.LogDLLStatus(mod.Compatibility); MelonModLogger.Log("------------------------------"); } } Mods.RemoveAll((MelonMod mod) => (mod.Compatibility >= MelonBase.MelonCompatibility.INCOMPATIBLE)); DependencyGraph <MelonMod> .TopologicalSort(Mods, mod => mod.InfoAttribute.Name); } if (Mods.Count <= 0) { MelonModLogger.Log("No Mods Loaded!"); MelonModLogger.Log("------------------------------"); } if ((Plugins.Count > 0) || (Mods.Count > 0)) { AddUnityDebugLog(); } if (Plugins.Count > 0) { HashSet <MelonPlugin> failedPlugins = new HashSet <MelonPlugin>(); for (int i = 0; i < Plugins.Count; i++) { MelonPlugin plugin = Plugins[i]; if (plugin != null) { try { InitializeModOrPlugin(plugin); } catch (Exception ex) { MelonModLogger.LogDLLError(ex.ToString(), plugin.InfoAttribute.Name); failedPlugins.Add(plugin); } } } Plugins.RemoveAll(plugin => failedPlugins.Contains(plugin)); } if (Mods.Count > 0) { HashSet <MelonMod> failedMods = new HashSet <MelonMod>(); for (int i = 0; i < Mods.Count; i++) { MelonMod mod = Mods[i]; if (mod != null) { try { InitializeModOrPlugin(mod); } catch (Exception ex) { MelonModLogger.LogDLLError(ex.ToString(), mod.InfoAttribute.Name); failedMods.Add(mod); } } } Mods.RemoveAll(mod => failedMods.Contains(mod)); } if ((Plugins.Count <= 0) && (Mods.Count <= 0)) { SupportModule.Destroy(); } }
private HarmonyIl2CppMethodPatcher(MethodBase original) : base(original) { originalMethodInfoPointer = UnhollowerSupport.MethodBaseToIl2CppMethodInfoPointer(Original); copiedMethodInfoPointer = (IntPtr)UnhollowerSupport.CopyMethodInfoStructMethod.Invoke(null, new object[] { originalMethodInfoPointer }); }
private static void ConvertArgument(ILGenerator il, Type paramType, ref LocalBuilder byRefLocal) { if (paramType.IsValueType) { return; } Type currentType = paramType; bool byRef = paramType.IsByRef; if (byRef) { currentType = paramType.GetElementType(); } if (currentType == typeof(string)) { // return Il2CppStringToManaged(ptr); // byRefLocal = Il2CppStringToManaged(*ptr); // return ref byRefLocal; if (byRef) { byRefLocal = il.DeclareLocal(currentType); il.Emit(OpCodes.Ldind_I); } il.Emit(OpCodes.Call, UnhollowerSupport.Il2CppStringToManagedMethod); if (byRef) { il.Emit(OpCodes.Stloc, byRefLocal); il.Emit(OpCodes.Ldloca, byRefLocal); } } else if (UnhollowerSupport.IsGeneratedAssemblyType(currentType)) { // return ptr == 0 ? null : new SomeType(ptr); // byRefLocal = *ptr == 0 ? null : new SomeType(*ptr); // return ref byRefLocal; Label ptrNonZero = il.DefineLabel(); Label done = il.DefineLabel(); if (byRef) { byRefLocal = il.DeclareLocal(currentType); il.Emit(OpCodes.Ldind_I); } il.Emit(OpCodes.Dup); il.Emit(OpCodes.Brtrue_S, ptrNonZero); il.Emit(OpCodes.Pop); if (!byRef) { il.Emit(OpCodes.Ldnull); } il.Emit(OpCodes.Br_S, done); il.MarkLabel(ptrNonZero); il.Emit(OpCodes.Newobj, Il2CppConstuctor(currentType)); if (byRef) { il.Emit(OpCodes.Stloc, byRefLocal); } il.MarkLabel(done); if (byRef) { il.Emit(OpCodes.Ldloca, byRefLocal); } } }