private bool Inject(Actions action, ModuleDefMD assembly = null, bool save = true) { var assemblyPath = Path.Combine(currentManagedPath, selectedGame.AssemblyName); var backupAssemblyPath = $"{assemblyPath}.backup_"; var originalAssemblyPath = $"{assemblyPath}.original_"; if (File.Exists(assemblyPath)) { if (assembly == null) { try { assembly = ModuleDefMD.Load(File.ReadAllBytes(assemblyPath)); } catch (Exception e) { Log.Print(e.Message); return(false); } } var modManagerType = typeof(UnityModManager); switch (action) { case Actions.Install: try { if (!Utils.ParsePatchTarget(assembly, selectedGame.PatchTarget, out var targetMethod, out var insertionPlace)) { return(false); } Log.Print($"Backup for '{selectedGame.AssemblyName}'."); File.Copy(assemblyPath, backupAssemblyPath, true); if (!IsDirty(assembly)) { File.Copy(assemblyPath, originalAssemblyPath, true); } CopyLibraries(); var modsPath = Path.Combine(currentGamePath, selectedGame.ModsDirectory); if (!Directory.Exists(modsPath)) { Directory.CreateDirectory(modsPath); } var typeInjectorInstalled = assembly.Types.FirstOrDefault(x => x.Name == modManagerType.Name); if (typeInjectorInstalled != null) { if (!Inject(Actions.Remove, assembly, false)) { Log.Print("Installation failed. Can't uninstall the previous version."); return(false); } } Log.Print("Applying patch..."); if (!IsDirty(assembly)) { MakeDirty(assembly); } var modManagerDef = ModuleDefMD.Load(modManagerType.Module); var modManager = modManagerDef.Types.First(x => x.Name == modManagerType.Name); var modManagerModsDir = modManager.Fields.First(x => x.Name == nameof(UnityModManager.modsDirname)); modManagerModsDir.Constant.Value = selectedGame.ModsDirectory; var modManagerModInfo = modManager.Fields.First(x => x.Name == nameof(UnityModManager.infoFilename)); modManagerModInfo.Constant.Value = selectedGame.ModInfo; var modManagerPatchTarget = modManager.Fields.First(x => x.Name == nameof(UnityModManager.patchTarget)); modManagerPatchTarget.Constant.Value = selectedGame.PatchTarget; modManagerDef.Types.Remove(modManager); assembly.Types.Add(modManager); var instr = OpCodes.Call.ToInstruction(modManager.Methods.First(x => x.Name == nameof(UnityModManager.Start))); if (string.IsNullOrEmpty(insertionPlace) || insertionPlace == "after") { targetMethod.Body.Instructions.Insert(targetMethod.Body.Instructions.Count - 1, instr); } else if (insertionPlace == "before") { targetMethod.Body.Instructions.Insert(0, instr); } if (save) { assembly.Write(assemblyPath); Log.Print("Installation was successful."); } installedVersion.Text = currentVersion.Text; btnInstall.Enabled = false; btnRemove.Enabled = true; btnRestore.Enabled = File.Exists(originalAssemblyPath); return(true); } catch (Exception e) { Log.Print(e.Message); if (!File.Exists(assemblyPath)) { RestoreBackup(); } } break; case Actions.Remove: try { var modManagerInjected = assembly.Types.FirstOrDefault(x => x.Name == modManagerType.Name); if (modManagerInjected != null) { Log.Print("Removing patch..."); var patchTarget = selectedGame.PatchTarget; var modManagerPatchTarget = modManagerInjected.Fields.FirstOrDefault(x => x.Name == nameof(UnityModManager.patchTarget)); if (modManagerPatchTarget != null && !string.IsNullOrEmpty((string)modManagerPatchTarget.Constant.Value)) { patchTarget = (string)modManagerPatchTarget.Constant.Value; } if (!Utils.ParsePatchTarget(assembly, patchTarget, out var targetMethod, out var insertionPlace)) { return(false); } var instr = OpCodes.Call.ToInstruction(modManagerInjected.Methods.First(x => x.Name == nameof(UnityModManager.Start))); for (int i = 0; i < targetMethod.Body.Instructions.Count; i++) { if (targetMethod.Body.Instructions[i].OpCode == instr.OpCode && targetMethod.Body.Instructions[i].Operand == instr.Operand) { targetMethod.Body.Instructions.RemoveAt(i); break; } } assembly.Types.Remove(modManagerInjected); if (!IsDirty(assembly)) { MakeDirty(assembly); } if (save) { assembly.Write(assemblyPath); Log.Print("Removal was successful."); } installedVersion.Text = "-"; btnInstall.Enabled = true; btnRemove.Enabled = false; } return(true); } catch (Exception e) { Log.Print(e.Message); if (!File.Exists(assemblyPath)) { RestoreBackup(); } } break; } } else { Log.Print($"'{assemblyPath}' not found."); return(false); } return(false); }