private static ISupportModule Initialize() { LogSupport.RemoveAllHandlers(); if (CumConsole.Enabled || Imports.IsDebugMode()) { LogSupport.InfoHandler += CumLogger.Log; } LogSupport.WarningHandler += CumLogger.LogWarning; LogSupport.ErrorHandler += CumLogger.LogError; if (Imports.IsDebugMode()) { LogSupport.TraceHandler += CumLogger.Log; } ClassInjector.DoHook += Imports.Hook; GetUnityVersionNumbers(out var major, out var minor, out var patch); UnityVersionHandler.Initialize(major, minor, patch); // Il2CppSystem.Console.SetOut(new Il2CppSystem.IO.StreamWriter(Il2CppSystem.IO.Stream.Null)); try { var il2CppSystemAssembly = Assembly.Load("Il2Cppmscorlib"); var consoleType = il2CppSystemAssembly.GetType("Il2CppSystem.Console"); var streamWriterType = il2CppSystemAssembly.GetType("Il2CppSystem.IO.StreamWriter"); var streamType = il2CppSystemAssembly.GetType("Il2CppSystem.IO.Stream"); var setOutMethod = consoleType.GetMethod("SetOut", BindingFlags.Static | BindingFlags.Public); var nullStreamField = streamType.GetProperty("Null", BindingFlags.Static | BindingFlags.Public).GetGetMethod(); var streamWriterCtor = streamWriterType.GetConstructor(new[] { streamType }); var nullStream = nullStreamField.Invoke(null, new object[0]); var steamWriter = streamWriterCtor.Invoke(new[] { nullStream }); setOutMethod.Invoke(null, new[] { steamWriter }); } catch (Exception ex) { CumLogger.LogError($"Console cleaning failed: {ex}"); } SetAsLastSiblingDelegateField = IL2CPP.ResolveICall <SetAsLastSiblingDelegate>("UnityEngine.Transform::SetAsLastSibling"); ClassInjector.RegisterTypeInIl2Cpp <CumLoaderComponent>(); CumLoaderComponent.Create(); SceneManager.sceneLoaded = ( (SceneManager.sceneLoaded == null) ? new Action <Scene, LoadSceneMode>(OnSceneLoad) : Il2CppSystem.Delegate.Combine(SceneManager.sceneLoaded, (UnityAction <Scene, LoadSceneMode>) new Action <Scene, LoadSceneMode>(OnSceneLoad)).Cast <UnityAction <Scene, LoadSceneMode> >() ); Camera.onPostRender = ( (Camera.onPostRender == null) ? new Action <Camera>(OnPostRender) : Il2CppSystem.Delegate.Combine(Camera.onPostRender, (Camera.CameraCallback) new Action <Camera>(OnPostRender)).Cast <Camera.CameraCallback>() ); return(new Module()); }
private static IEnumerable <CodeInstruction> UnhollowerTranspiler(MethodBase method, IEnumerable <CodeInstruction> instructionsIn) { List <CodeInstruction> instructions = new List <CodeInstruction>(instructionsIn); PatchInfo patchInfo = HarmonySharedState.GetPatchInfo(method); IntPtr copiedMethodInfo = patchInfo.copiedMethodInfoPointer; bool found = false; int replaceIdx = 0; int replaceCount = 0; for (int i = instructions.Count - 2; i >= 0; --i) { if (instructions[i].opcode != OpCodes.Ldsfld) { continue; } found = true; CodeInstruction next = instructions[i + 1]; if (next.opcode == OpCodes.Call && ((MethodInfo)next.operand).Name == "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) replaceIdx = i - 2; replaceCount = 4; } else { // Everything else: Just replace the static load replaceIdx = i; replaceCount = 1; } break; } if (!found) { CumLogger.LogError("Harmony transpiler could not rewrite Unhollower method. Expect a stack overflow."); return(instructions); } CodeInstruction[] replacement = { new CodeInstruction(OpCodes.Ldc_I8, copiedMethodInfo.ToInt64()), new CodeInstruction(OpCodes.Conv_I) }; instructions.RemoveRange(replaceIdx, replaceCount); instructions.InsertRange(replaceIdx, replacement); return(instructions); }
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) { CumLogger.LogError(e.ToString()); Stop(FindOriginalCoro(enumerator)); // We want the entire coroutine hierachy 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 { CumLogger.LogWarning($"Unknown coroutine yield object of type {il2CppObjectBase} for coroutine {enumerator}"); } break; } ourCoroutinesStore.Add(new CoroTuple { WaitCondition = next, Coroutine = enumerator }); if (next is IEnumerator nextCoro) { ProcessNextOfCoroutine(nextCoro); } }