Ejemplo n.º 1
0
        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);
        }