public static void ExeLoaded(this InstallerWindow ins, string path)
 {
     ins.ExePathBox.Text = path;
     Task.Run(delegate() {
         ins.ExeSelected(path, " [saved]");
     });
 }
Beispiel #2
0
        private static void Install_(this InstallerWindow ins)
        {
            ins
            .Invoke(() => ExePath = ins.ExePathBox.Text)
            .Invoke(() => AutoRun = ins.AdvancedAutoRunCheckbox.Checked)
            .Invoke(ETGInstallerSettings.Save)
            .SetMainEnabled(false)
            .Wait();

            if (ETGFinder.IsBinaryWrapped)
            {
                ExePath = Path.Combine(Directory.GetParent(ExePath).FullName, ETGFinder.MainName);
            }

            Directory.SetCurrentDirectory(ins.MainModDir);

            if (AutoRun)
            {
                string    etg       = ETGFinder.ProcessName;
                Process[] processes = Process.GetProcesses(".");
                for (int i = 0; i < processes.Length; i++)
                {
                    Process p = processes[i];
                    try {
                        if (p.ProcessName != etg)
                        {
                            p.Dispose();
                            continue;
                        }
                        p.Kill();
                        p.Dispose();
                        Thread.Sleep(250);
                    } catch (Exception) {
                        //probably the service acting up or a process quitting
                        p.Dispose();
                    }
                }
            }

            ins.LogLine("Entering the Modgeon");

            //Clean the game from any previous installation
            if (ETGFinder.Version != ETGFinder.VersionLastRun && ETGFinder.VersionLastRun != null)
            {
                ins.ClearBackup();
            }
            else
            {
                ins.Uninstall();
            }

            // We need to reload the main dependencies anyway.
            // As they've been patched, Assembly-CSharp.dll will otherwise refer to the .mm assemblies.
            // And as their dependencies get patched, we need to actually unload their symbol readers here.
            ins.MainMod?.Dispose();

            ins.Backup("UnityEngine.dll");
            ins.Backup("Assembly-CSharp.dll");
            ins.BackupETG();

            ins.PrepareDeobfuscator();
            ins.Deobfuscate("Assembly-CSharp.dll");

            //Setup the files and MonoMod instances
            int mi = -1;

            if (OverridePaths == null && !IsOffline)
            {
                mi = 0;
                ins.LogLine("Mod #0: Base");
                //Check if the revision online is newer
                RepoHelper.RevisionFile = Path.Combine(ins.MainModDir, "ModCache", "ETGMOD_REVISION.txt");
                int revisionOnline = RepoHelper.RevisionOnline;
                if (RepoHelper.Revision < revisionOnline)
                {
                    string cachedPath = Path.Combine(ins.MainModDir, "ModCache", "ETGMOD.zip");
                    if (File.Exists(cachedPath))
                    {
                        File.Delete(cachedPath);
                    }
                }
                if (!IsOffline && !ins.UnzipMod(ins.DownloadCached(RepoHelper.ETGModURL, "ETGMOD.zip")))
                {
                    OnInstalled?.Invoke(false);
                    return;
                }
                RepoHelper.Revision = revisionOnline;
            }


            int[] selectedIndices = null;
            ins.Invoke(delegate() {
                int[] _selectedIndices = new int[ins.APIModsList.SelectedIndices.Count];
                ins.APIModsList.SelectedIndices.CopyTo(_selectedIndices, 0);
                selectedIndices = _selectedIndices;
            });
            while (selectedIndices == null)
            {
                Thread.Sleep(100);
            }

            for (int i = 0; i < selectedIndices.Length; i++)
            {
                Tuple <string, string> t = ins.APIMods[selectedIndices[i]];
                if (string.IsNullOrEmpty(t.Item2))
                {
                    continue;
                }
                ins.Log("Mod #").Log((++mi).ToString()).Log(": ").LogLine(t.Item1);
                if (!ins.UnzipMod(ins.DownloadCached(t.Item2, t.Item1 + ".zip")))
                {
                    OnInstalled?.Invoke(false);
                    return;
                }
            }

            List <string> paths = OverridePaths;

            if (paths == null)
            {
                paths = new List <string>();
                for (int pi = 0; pi < ins.AdvancedPathBoxes.Count; pi++)
                {
                    paths.Add(ins.AdvancedPathBoxes[pi].Text);
                }
            }

            for (int pi = 0; pi < paths.Count; pi++)
            {
                string path = paths[pi];

                if (path.ToLower().EndsWith(".zip"))
                {
                    ins.Log("Mod #").Log((++mi).ToString()).Log(": ZIP: ").LogLine(path);
                    if (!ins.UnzipMod(File.OpenRead(path)))
                    {
                        OnInstalled?.Invoke(false);
                        return;
                    }
                }
                else if (path.ToLower().EndsWith(".mm.dll"))
                {
                    ins.Log("Mod #").Log((++mi).ToString()).Log(": DLL: ").LogLine(path);
                    File.Copy(path, Path.Combine(ins.MainModDir, Path.GetFileName(path)), true);
                    string pdb = Path.ChangeExtension(path, "pdb");
                    string mdb = path + ".mdb";
                    if (File.Exists(pdb))
                    {
                        File.Copy(pdb, Path.Combine(ins.MainModDir, Path.GetFileName(pdb)), true);
                    }
                    else if (File.Exists(mdb))
                    {
                        File.Copy(mdb, Path.Combine(ins.MainModDir, Path.GetFileName(mdb)), true);
                    }
                }
                else
                {
                    ins.Log("Mod #").Log((++mi).ToString()).Log(": Folder: ").LogLine(path);

                    string   pathGame = ins.MainModDir;
                    string[] files    = Directory.GetFiles(path);
                    ins.InitProgress("Copying ETGMod", files.Length);
                    for (int i = 0; i < files.Length; i++)
                    {
                        string file = Path.GetFileName(files[i]);
                        if (!file.Contains(".mm."))
                        {
                            ins.SetProgress("Skipping: " + file, i);
                            continue;
                        }
                        ins.Log("Copying: ").LogLine(file);
                        ins.SetProgress("Copying: " + file, i);
                        string origPath = Path.Combine(pathGame, file);
                        File.Copy(files[i], origPath, true);
                    }
                    ins.EndProgress("Copying ETGMod complete.");
                }
            }

            if (Blacklist.Count != 0)
            {
                ins.LogLine();
                ins.Log(Blacklist.Count.ToString()).LogLine(" mods on the blacklist - removing them!");
                for (int i = 0; i < Blacklist.Count; i++)
                {
                    string blacklisted     = Blacklist[i];
                    string pathGame        = ins.MainModDir;
                    string blacklistedPath = Path.Combine(pathGame, blacklisted);
                    ins.Log(blacklisted).Log(" blacklisted - ");
                    if (!File.Exists(blacklistedPath))
                    {
                        ins.LogLine("Not found though.");
                        continue;
                    }
                    ins.LogLine("BURN THE WITCH!");
                    File.Delete(blacklistedPath);
                }
                ins.LogLine();
            }

            LogPath = Path.Combine(ins.MainModDir, "ETGModInstallLog.txt");
            if (File.Exists(LogPath))
            {
                File.Delete(LogPath);
            }

            ins.LogLine();
            ins.LogLine("Now comes the real \"modding\" / patching process.");
            ins.LogLine("It may seem like the Installer may be stuck sometimes. Go make");
            ins.LogLine("yourself a coffee in the meantime - it doesn't get stuck.");
            ins.LogLine("It may *crash*, though - and in this case, debug stuff appears");
            ins.LogLine("here. Please put that debug stuff onto http://pastebin.com/ and");
            ins.LogLine("send it to the #modding channel in https://discord.gg/etg");
            ins.LogLine();

            ins.PatchExe();

            if (!ins.Mod("UnityEngine.dll"))
            {
                OnInstalled?.Invoke(false);
                return;
            }

            if (!ins.Mod("Assembly-CSharp.dll"))
            {
                OnInstalled?.Invoke(false);
                return;
            }

            ins.EndProgress("Modding complete.");
            ins.LogLine("Back with the coffee? We're done! Look at the top-right!");
            ins.LogLine("You should see [just installed]. Feel free to start EtG.");
            ins.LogLine("If EtG crashes with ETGMod, go to the EtG folder (that one");
            ins.Log("where ").Log(ETGFinder.MainName).LogLine(" is, basically the path at the top-right),");
            ins.LogLine("then go to EtG_Data (that scary folder with many files) and");
            ins.LogLine("upload output_log.txt to #modding in https://discord.gg/etg");
            ins.LogLine("Good luck - Have fun!");
            ins.ExeSelected(ExePath, " [just installed]");

            if (AutoRun)
            {
                Process etg = new Process();
                etg.StartInfo.FileName = ExePath;
                etg.Start();
            }
            OnInstalled?.Invoke(true);
        }
        public static void ExeSelected(this InstallerWindow ins, string path, string suffix = null)
        {
            if (InstallerWindow.InstantClearSymbols != null)
            {
                InstallerWindow.Instance.ClearSymbols(InstallerWindow.InstantClearSymbols);
                InstallerWindow.InstantClearSymbols = null;
            }

            if (string.IsNullOrEmpty(path))
            {
                path = null;
            }

            string origPath = path;

            ins.Invoke(delegate() {
                ins.InstallButton.Enabled = false;
                ins.ExePathBox.Text       = origPath;
                ins.ExeStatusLabel.Text   = "EtG [checking version]";
                if (suffix != null)
                {
                    ins.ExeStatusLabel.Text += suffix;
                }
                ins.ExeStatusLabel.BackColor = Color.FromArgb(127, 255, 255, 63);
            });

            if (path != null && (ins.MainMod == null || ins.MainModIn != path))
            {
                if (!Platform.HasFlag(ETGPlatform.MacOS))
                {
                    path = Path.Combine(Directory.GetParent(path).FullName, "EtG_Data", "Managed", "Assembly-CSharp.dll");
                }
                else
                {
                    path = Path.Combine(Directory.GetParent(path).Parent.Parent.FullName, "Resources", "Data", "Managed", "Assembly-CSharp.dll");
                }
                if (!File.Exists(path))
                {
                    path = null;
                }
            }

            ins.ModVersion = null;
            ins.MainMod?.Dispose();
            if (path == null)
            {
                ins.MainMod = null;
                ins.Invoke(delegate() {
                    ins.ExeStatusLabel.Text      = "No " + MainName + " selected";
                    ins.ExeStatusLabel.BackColor = Color.FromArgb(127, 255, 63, 63);
                    ins.ExePathBox.Text          = "";
                    ins.InstallButton.Enabled    = false;
                    OnExeSelected?.Invoke(false);
                });
                return;
            }
            ins.MainMod = new MonoModder()
            {
                InputPath = ins.MainModIn = path
                                            // Output set when actually patching
            };
            ins.MainMod.SetupETGModder();
            ins.MainModDir = Directory.GetParent(ins.MainModIn).FullName;

            //We want to read the assembly now already. Writing is also handled manually.
            try {
                ins.MainMod.Read(false);
            } catch (BadImageFormatException) {
                //this is not the assembly we need...
                ins.ExeSelected(null);
                return;
            } /* catch (MonoSymbolFileException) {
               * // Mono.Cecil keeps the file handle for itself; We need to restart here.
               * ins.MainMod.Dispose();
               * ins.RestartAndClearSymbols();
               * return;
               * }*/catch (Exception e) {
                //Something went wrong.
                ins.Log("Something went horribly wrong after you've selected ").LogLine(MainName);
                ins.LogLine("Blame Zatherz and send him this log ASAP!");
                ins.Log("PATH: ").LogLine(path);
                ins.Log("DIR: ").LogLine(ins.MainModDir);
                ins.LogLine(e.ToString());
                ins.ExeSelected(null);
                return;
            }

            TypeDefinition ModType = ins.MainMod.Module.GetType("ETGMod");

            if (ModType != null)
            {
                MethodDefinition ModCctor = null;
                for (int i = 0; i < ModType.Methods.Count; i++)
                {
                    if (ModType.Methods[i].IsStatic && ModType.Methods[i].IsConstructor)
                    {
                        ModCctor = ModType.Methods[i];
                        break;
                    }
                }

                /*
                 * .method private hidebysig specialname rtspecialname static
                 *          void .cctor () cil managed
                 *  {
                 *          // Method begins at RVA 0x2d6cec
                 *          // Code size 184 (0xb8)
                 *          .maxstack 3
                 *
                 *          IL_0000: ldc.i4.0
                 *          IL_0001: ldc.i4.1
                 *          IL_0002: ldc.i4.0
                 *          IL_0003: newobj instance void [mscorlib]System.Version::.ctor(int32, int32, int32)
                 *          IL_0008: stsfld class [mscorlib]System.Version ETGMod::BaseVersion
                 *          IL_000d: ldc.i4.0
                 *          IL_000e: stsfld int32 ETGMod::BaseTravisBuild
                 *          IL_0013: ldc.i4.1
                 *          IL_0014: ldstr "debug"
                 *          IL_0019: newobj instance void ETGMod/Profile::.ctor(int32, string)
                 *          IL_001e: stsfld class ETGMod/Profile ETGMod::BaseProfile
                 */
                if (ModCctor != null)
                {
                    string modVersion = "";
                    string modBuild   = "";
                    string modProfile = "";
                    for (int i = 0; i < ModCctor.Body.Instructions.Count; i++)
                    {
                        Instruction instructionField = ModCctor.Body.Instructions[i];
                        if (instructionField.OpCode != OpCodes.Stsfld)
                        {
                            continue;
                        }
                        FieldReference field = (FieldReference)instructionField.Operand;
                        if (field.Name == "BaseVersion")
                        {
                            int count = ((MethodReference)ModCctor.Body.Instructions[i - 1].Operand).Parameters.Count;
                            for (int ii = i - count - 1; ii < i - 1; ii++)
                            {
                                modVersion += ModCctor.Body.Instructions[ii].GetInt();
                                if (ii < i - 2)
                                {
                                    modVersion += ".";
                                }
                            }
                        }
                        if (field.Name == "BaseTravisBuild")
                        {
                            int build = ModCctor.Body.Instructions[i - 1].GetInt();
                            if (build != 0)
                            {
                                modBuild = "-" + build;
                            }
                        }
                        if (field.Name == "BaseProfile")
                        {
                            string profile = ModCctor.Body.Instructions[i - 2].Operand as string;
                            if (!string.IsNullOrEmpty(profile))
                            {
                                modProfile = "-" + profile;
                            }
                        }
                    }
                    ins.ModVersion = modVersion + modBuild + modProfile;
                }
            }

            ins.Invoke(delegate() {
                ins.ExeStatusLabel.Text      = "Enter The Gungeon";
                ins.ExeStatusLabel.BackColor = Color.FromArgb(127, 63, 255, 91);

                if (ins.ModVersion != null)
                {
                    ins.ExeStatusLabel.Text += " [Mod:";
                    ins.ExeStatusLabel.Text += ins.ModVersion;
                    ins.ExeStatusLabel.Text += "]";
                }

                if (suffix != null)
                {
                    ins.ExeStatusLabel.Text += suffix;
                }

                ins.ExePathBox.Text       = origPath;
                ins.InstallButton.Enabled = true;
                ETGInstallerSettings.Save();
                OnExeSelected?.Invoke(true);
            });
        }