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; }
private void CheckState() { if (!IsValid(selectedGame)) { InactiveForm(); return; } btnInstall.Text = "Install"; currentGamePath = ""; if (!param.ExtractGamePath(selectedGame.Name, out var result) || !Directory.Exists(result)) { result = FindGameFolder(selectedGame.Folder); if (string.IsNullOrEmpty(result)) { InactiveForm(); btnOpenFolder.ForeColor = System.Drawing.Color.FromArgb(192, 0, 0); btnOpenFolder.Text = "Select Game Folder"; folderBrowserDialog.SelectedPath = null; Log.Print($"Game folder '{selectedGame.Folder}' not found."); return; } Log.Print($"Game folder detected as '{result}'."); param.SaveGamePath(selectedGame.Name, result); } else { Log.Print($"Game folder set as '{result}'."); } currentGamePath = result; btnOpenFolder.ForeColor = System.Drawing.Color.Black; btnOpenFolder.Text = new DirectoryInfo(result).Name; folderBrowserDialog.SelectedPath = currentGamePath; currentManagedPath = FindManagedFolder(currentGamePath); var assemblyPath = Path.Combine(currentManagedPath, selectedGame.AssemblyName); ModuleDefMD assembly = null; var originalAssemblyPath = $"{assemblyPath}.original_"; btnRestore.Enabled = File.Exists(originalAssemblyPath); if (File.Exists(assemblyPath)) { try { assembly = ModuleDefMD.Load(File.ReadAllBytes(assemblyPath)); } catch (Exception e) { InactiveForm(); Log.Print(e.Message); return; } } else { InactiveForm(); Log.Print($"'{selectedGame.AssemblyName}' not found."); return; } tabControl.TabPages[1].Enabled = true; var modManagerType = typeof(UnityModManager); var modManagerDefInjected = assembly.Types.FirstOrDefault(x => x.Name == modManagerType.Name); if (modManagerDefInjected != null) { btnInstall.Text = "Update"; btnInstall.Enabled = false; btnRemove.Enabled = true; var versionString = modManagerDefInjected.Fields.First(x => x.Name == nameof(UnityModManager.version)).Constant.Value.ToString(); var version2 = Utils.ParseVersion(versionString); installedVersion.Text = versionString; if (version != version2) { btnInstall.Enabled = true; } } else { installedVersion.Text = "-"; btnInstall.Enabled = true; btnRemove.Enabled = false; } btnRestore.Enabled = IsDirty(assembly) && btnRestore.Enabled; }