public static void ExeLoaded(this InstallerWindow ins, string path) { ins.ExePathBox.Text = path; Task.Run(delegate() { ins.ExeSelected(path, " [saved]"); }); }
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); }); }