private void onHandleCreated(object sender, EventArgs e)
        {
            HandleCreated -= onHandleCreated;
            GUIThread      = Thread.CurrentThread;

            ETGInstallerSettings.Load();
            ETGInstallerSettings.Save();

            AdvancedAddButton.Click += (object senderObject, EventArgs evArgs) => ETGInstallerSettings.Save();
            AdvancedOfflineCheckbox.CheckedChanged       += (object senderObject, EventArgs evArgs) => ETGInstallerSettings.Save();
            AdvancedAutoRunCheckbox.CheckedChanged       += (object senderObject, EventArgs evArgs) => ETGInstallerSettings.Save();
            AdvancedBinaryWrappedCheckbox.CheckedChanged += (object senderObject, EventArgs evArgs) => ETGInstallerSettings.Save();
            ExePathButton.Click += (object senderObject, EventArgs evArgs) => ETGInstallerSettings.Save();
            for (int i = 0; i < AdvancedRemoveButtons.Count; i++)
            {
                AdvancedRemoveButtons[i].Click += (object senderObject, EventArgs evArgs) => ETGInstallerSettings.Save();
            }

            if (string.IsNullOrWhiteSpace(ExePathBox.Text))
            {
                Task.Run((Action)ETGFinder.FindETG);
            }
            Task.Run((Action)DownloadModsList);
        }
        public InstallerWindow()
        {
            Instance       = this;
            HandleCreated += onHandleCreated;

            OnRobotFrameChangedHandler = new EventHandler(OnRobotFrameChanged);

            OpenExeDialog = new OpenFileDialog()
            {
                Title = "Select " + ETGFinder.MainName,
                AutoUpgradeEnabled = true,
                CheckFileExists    = true,
                CheckPathExists    = true,
                ValidateNames      = true,
                Multiselect        = false,
                ShowReadOnly       = false,
                Filter             = ETGFinder.MainName + "|" + ETGFinder.MainName,
                FilterIndex        = 0
            };
            OpenExeDialog.FileOk += (object senderFileOk, CancelEventArgs eFileOk) => Task.Run(() => this.ExeSelected(OpenExeDialog.FileNames[0]));

            OpenModDialog = new OpenFileDialog()
            {
                Title = "Select ETGMod Backend",
                AutoUpgradeEnabled = true,
                CheckFileExists    = true,
                CheckPathExists    = true,
                ValidateNames      = true,
                Multiselect        = true,
                ShowReadOnly       = false,
                Filter             = "ETGMod DLL|*.mm.dll|ETGMod ZIP|*.zip|All files|*.*",
                FilterIndex        = 0
            };
            OpenModDialog.FileOk += (object senderFileOk, CancelEventArgs eFileOk) => AddManualPathRows(OpenModDialog.FileNames);

            Text = "Mod the Gungeon Installer";
            if (ETGFinder.Platform.HasFlag(ETGPlatform.Unix))
            {
                FormBorderStyle = FormBorderStyle.Sizable;
            }
            else
            {
                FormBorderStyle = FormBorderStyle.FixedDialog;
            }
            ResizeRedraw  = false;
            MaximizeBox   = false;
            MinimizeBox   = true;
            StartPosition = FormStartPosition.CenterScreen;

            //Setting the font doesn't change anything...

            /*PrivateFontCollection pfc = LoadAsset<PrivateFontCollection>("fonts.uni05_53");
             * for (int i = 0; i < pfc.Families.Length; i++) {
             *  Console.WriteLine("Font " + i + ": " + pfc.Families[i]);
             * }
             * GlobalFont = new Font(pfc.Families[0], 8f);*/

            if (GlobalFont == null)
            {
                if (ETGFinder.Platform.HasFlag(ETGPlatform.Windows))
                {
                    GlobalFont = new Font("Segoe UI", 8f, FontStyle.Regular);
                }
                else if (ETGFinder.Platform.HasFlag(ETGPlatform.MacOS))
                {
                    GlobalFont = new Font("Lucida Grande", 8f, FontStyle.Regular); // With Helvetica Neue: Erter Tne Girgeor
                }
                else
                {
                    GlobalFont = new Font("DejaVu Sans", 8f, FontStyle.Regular);
                }
            }

            AllowDrop  = true;
            DragDrop  += onDragDrop;
            DragEnter += delegate(object sender, DragEventArgs e) {
                if (e.Data.GetDataPresent(DataFormats.FileDrop) && VersionTabs.Enabled)
                {
                    e.Effect = DragDropEffects.Copy;
                    VersionTabs.SelectedIndex = 2;
                }
            };
            BackgroundImage       = LoadAsset <Image>("background");
            BackgroundImageLayout = ImageLayout.Center;

            RobotImageIdle       = LoadAsset <Image>("icons.idle");
            RobotImageInstalling = LoadAsset <Image>("icons.installing.gif");
            RobotImageError      = LoadAsset <Image>("icons.error.gif");
            RobotImageFinished   = LoadAsset <Image>("icons.finished.gif");

            Controls.Add(RobotPictureBox = new PictureBox()
            {
                BackColor = Color.Transparent,
                Image     = RobotImageIdle,
                Bounds    = new Rectangle(150, 100, RobotImageIdle.Width, RobotImageIdle.Height)
            });

            //ShuffleIconColors();
            OrigIcon = LoadAsset <Bitmap>("icons.icon");
            Icon     = Icon.FromHandle(OrigIcon.GetHicon());

            ResetSize();
            SizeChanged += ResetSize;

#if !DEBUG
            Version = new Version(Version.Major, Version.Minor, Version.Build);
#endif

            Controls.Add(new Label()
            {
                Bounds    = new Rectangle(448, 338, 308, 16),
                Font      = GlobalFont,
                TextAlign = ContentAlignment.BottomRight,
#if DEBUG
                Text = "DEBUG " + Version.Revision,
#else
                Text = "v" + Version,
#endif
                BackColor = Color.Transparent,
                ForeColor = Color.FromArgb(127, 0, 0, 0)
            });

            Controls.Add(LogBox = new RichTextBox()
            {
                Bounds    = new Rectangle(0, 0, 443, 315),
                Font      = GlobalFont,
                ReadOnly  = true,
                Multiline = true,
                //ScrollBars = System.Windows.Forms.ScrollBars.Vertical,
                DetectUrls       = true,
                ShortcutsEnabled = true,
                BackColor        = Color.Black,
                ForeColor        = Color.White,
                BorderStyle      = BorderStyle.None,
                WordWrap         = true,
                Text             = "ETGMod Installer v" + Version + "\n",
                Visible          = false,
            });

            Controls.Add(ViewLogButton = new Button()
            {
                Text    = "Show log",
                Font    = GlobalFont,
                Bounds  = new Rectangle(0, 316, 442, 40),
                Visible = true
            });

            ViewLogButton.Click += delegate(object sender, EventArgs e) {
                ToggleLog();
            };

            Controls.Add(Progress = new CustomProgress()
            {
                Bounds = new Rectangle(448, 313, 312, 24),
                Font   = GlobalFont,
                Text   = "Idle."
            });

            Add(new Label()
            {
                Font      = GlobalFont,
                TextAlign = ContentAlignment.MiddleCenter,
                Text      = !ETGFinder.Platform.HasFlag(ETGPlatform.MacOS) ? ("Step 1: Select " + ETGFinder.MainName) : ("Step 1: Drag-n-drop EtG_OSX.app here"),
                BackColor = Color.Transparent,
                ForeColor = Color.Black
            });

            Add(ExePathBox = new TextBox()
            {
                Font     = GlobalFont,
                ReadOnly = true
            });
            ExePathBox.Width          -= 32;
            Controls.Add(ExePathButton = new Button()
            {
                Bounds     = new Rectangle(ExePathBox.Bounds.X + ExePathBox.Bounds.Width, ExePathBox.Bounds.Y, 32, ExePathBox.Bounds.Height),
                Font       = GlobalFont,
                Image      = LoadAsset <Image>("icons.open"),
                ImageAlign = ContentAlignment.MiddleCenter
            });
            ExePathButton.Click += (object senderClick, EventArgs eClick) => OpenExeDialog.ShowDialog(this);
            AddOffset           += 2;

            Add(ExeStatusLabel = new Label()
            {
                Font      = GlobalFont,
                TextAlign = ContentAlignment.MiddleCenter,
                Text      = "No " + ETGFinder.MainName + " selected",
                BackColor = Color.FromArgb(127, 255, 63, 63),
                ForeColor = Color.Black
            });

            AddOffset += 2;

            Add(new Label()
            {
                Font      = GlobalFont,
                TextAlign = ContentAlignment.MiddleCenter,
                Text      = "Step 2: Choose your backends",
                BackColor = Color.Transparent,
                ForeColor = Color.Black
            });

            Controls.Add(InstallButton = new Button()
            {
                Bounds    = new Rectangle(448, 313 - 1 - ExePathButton.Size.Height, 312 - 32, ExePathButton.Size.Height),
                Font      = GlobalFont,
                TextAlign = ContentAlignment.MiddleCenter,
                Text      = "Step 3: Install ETGMod",
                Enabled   = false
            });
            InstallButton.Click += (object senderClick, EventArgs eClick) => {
                if (ShowLogOnInstall)
                {
                    ShowLog();
                }
                Task.Run((Action)this.Install);
            };
            Controls.Add(UninstallButton = new Button()
            {
                Bounds     = new Rectangle(InstallButton.Bounds.X + InstallButton.Bounds.Width, InstallButton.Bounds.Y, 32, InstallButton.Bounds.Height),
                Font       = GlobalFont,
                Image      = LoadAsset <Image>("icons.uninstall"),
                ImageAlign = ContentAlignment.MiddleCenter
            });
            UninstallButton.Click += (object senderClick, EventArgs eClick) => Task.Run(delegate() {
                if (ShowLogOnInstall)
                {
                    ShowLog();
                }
                this.Uninstall();
                this.ClearCache();
                this.ExeSelected(ExePathBox.Text, " [just uninstalled]");
                this.SetMainEnabled(true);
            });

            Controls.Add(VersionTabs = new TabControl()
            {
                Bounds    = new Rectangle(448, 4 + 26 * AddIndex + AddOffset, 312, InstallButton.Location.Y - (4 + 26 * AddIndex + AddOffset)),
                Font      = GlobalFont,
                BackColor = Color.Transparent
            });

            if (ETGFinder.Platform.HasFlag(ETGPlatform.MacOS))
            {
                VersionTabs.BackColor = Color.White;
                // Mono's WinForms implementation on macOS just sucks.
                VersionTabs.SelectedIndexChanged += delegate(object sender, EventArgs e) {
                    for (int i = 0; i < VersionTabs.TabPages.Count; i++)
                    {
                        if (i == VersionTabs.SelectedIndex)
                        {
                            VersionTabs.TabPages[i].ShowDeep();
                            continue;
                        }
                        VersionTabs.TabPages[i].HideDeep();
                    }
                    RefreshManualPanel();
                };
            }

            VersionTabs.TabPages.Add(new TabPage("Backends"));
            VersionTabs.TabPages[0].Controls.Add(APIModsList = new ListBox()
            {
                Font          = GlobalFont,
                Dock          = DockStyle.Fill,
                MultiColumn   = true,
                SelectionMode = SelectionMode.MultiExtended
            });
            APIModsList.SelectedValueChanged += delegate(object sender, EventArgs e) {
                if (!RepoHelper.IsOffline && !APIModsList.SelectedIndices.Contains(0))
                {
                    APIModsList.SelectedIndices.Add(0);
                }
            };
            APIModsList.MultiColumn = false;
            APIModsList.DrawMode    = DrawMode.OwnerDrawFixed;
            APIModsList.DrawItem   += APIModsListDrawItem;

            VersionTabs.TabPages.Add(new TabPage("Advanced"));
            VersionTabs.TabPages[1].Controls.Add(AdvancedPanel = new Panel()
            {
                Font       = GlobalFont,
                Dock       = DockStyle.Fill,
                AutoScroll = true
            });

            AdvancedPanel.Controls.Add(AdvancedInfoLabel = new Label()
            {
                Text       = "Note: This isn't where you install mods!",
                ImageAlign = ContentAlignment.MiddleCenter,
                TextAlign  = ContentAlignment.MiddleCenter,
            });
            AdvancedPanel.Controls.Add(AdvancedAddButton = new Button()
            {
                Font       = GlobalFont,
                Image      = LoadAsset <Image>("icons.open"),
                ImageAlign = ContentAlignment.MiddleCenter
            });
            AdvancedAddButton.Click += (object senderClick, EventArgs eClick) => OpenModDialog.ShowDialog(this);
            AdvancedPanel.Controls.Add(AdvancedLabel = new Label()
            {
                Font      = GlobalFont,
                Text      = "or drag-and-drop a folder / .zip here",
                TextAlign = ContentAlignment.MiddleCenter
            });
            AdvancedPanel.Controls.Add(AdvancedAutoRunCheckbox = new CheckBox()
            {
                Font      = GlobalFont,
                Text      = "CLOSE " + ETGFinder.MainName + " && run when mod installed",
                TextAlign = ContentAlignment.MiddleCenter
            });
            if (ETGFinder.Platform.HasFlag(ETGPlatform.MacOS))
            {
                AdvancedAutoRunCheckbox.Text = "CLOSE Gungeon && run when mod installed";
            }
            AdvancedPanel.Controls.Add(AdvancedShowLogOnInstallCheckbox = new CheckBox()
            {
                Font      = GlobalFont,
                Text      = "Automatically show log when installing",
                TextAlign = ContentAlignment.MiddleCenter
            });
            AdvancedShowLogOnInstallCheckbox.CheckedChanged += delegate(object sender, EventArgs e) {
                ETGInstallerSettings.Save();
            };
            AdvancedPanel.Controls.Add(AdvancedOfflineCheckbox = new CheckBox()
            {
                Font      = GlobalFont,
                Text      = "Offline mode - only use the APIs here",
                TextAlign = ContentAlignment.MiddleCenter
            });
            AdvancedOfflineCheckbox.CheckedChanged += delegate(object senderCheck, EventArgs eCheck) {
                ETGModder.IsOffline = RepoHelper.IsOffline = AdvancedOfflineCheckbox.Checked;
                DownloadModsList();
                ETGInstallerSettings.Save();
            };
            AdvancedPanel.Controls.Add(AdvancedBinaryWrappedCheckbox = new CheckBox()
            {
                Font      = GlobalFont,
                Text      = ETGFinder.MainName + " is a wrapper, use EtG.bin",
                TextAlign = ContentAlignment.MiddleCenter
            });
            AdvancedBinaryWrappedCheckbox.CheckedChanged += delegate(object senderCheck, EventArgs eCheck) {
                ETGFinder.IsBinaryWrapped = AdvancedBinaryWrappedCheckbox.Checked;
                ETGFinder.FindETG();
                ETGInstallerSettings.Save();
            };

            RefreshManualPanel();
        }
        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);
            });
        }