Exemple #1
0
        public static void Main(string[] args)
        {
            Console.WriteLine("Entering the holy realm of FEZMod.");
            Application.EnableVisualStyles();

            Assembly assembly = Assembly.GetExecutingAssembly();

            string[] manifestResourceNames = assembly.GetManifestResourceNames();
            for (int i = 0; i < manifestResourceNames.Length; i++)
            {
                Console.WriteLine("Asset " + i + ": " + manifestResourceNames[i]);
            }

            Application.VisualStyleState = VisualStyleState.ClientAndNonClientAreasEnabled;
            Instance = new InstallerWindow();
            Instance.HandleCreated += Instance.onHandleCreated;

ShowDialog:
            try {
                Instance.ShowDialog();
            } catch (Exception e) {
                //Gonna blame X11.
                Console.WriteLine(e.ToString());
                MessageBox.Show("Your window manager has left the building!\nThis simply means the installer crashed,\nbut your window manager caused it.", "FEZMod Installer");
                goto ShowDialog;
            }
        }
Exemple #2
0
        public static void ClearCache(this InstallerWindow ins)
        {
            if (ins.ExeMod == null)
            {
                return;
            }

            string pathFez   = ins.ExeMod.Dir.FullName;
            string pathCache = Path.Combine(pathFez, "FEZModCache");

            if (!Directory.Exists(pathCache))
            {
                return;
            }

            ins.LogLine("Clearing FEZMod cache...");

            string[] files = Directory.GetFiles(pathCache);
            ins.InitProgress("Clearing FEZMod cache", files.Length + 1);
            for (int i = 0; i < files.Length; i++)
            {
                string file = Path.GetFileName(files[i]);
                ins.Log("Removing: ").LogLine(file);
                ins.SetProgress("Removing: " + file, i);
                File.Delete(files[i]);
            }

            ins.EndProgress("Clearing cache complete.");
        }
Exemple #3
0
 public static void Install(this InstallerWindow ins)
 {
     try {
         ins.Install_();
     } catch (Exception e) {
         ins.LogLine(e.ToString());
     }
 }
Exemple #4
0
        public static byte[] DownloadCached(this InstallerWindow ins, string url, string cached)
        {
            byte[] data = ins.ReadDataFromCache(cached);
            if (data != null)
            {
                return(data);
            }

            data = ins.Download(url);

            ins.WriteDataToCache(cached, data);
            return(data);
        }
Exemple #5
0
 public static bool Mod(this InstallerWindow ins, string file)
 {
     MonoMod.MonoMod monomod = new MonoMod.MonoMod(Path.Combine(ins.ExeMod.Dir.FullName, file));
     monomod.Out = monomod.In;
     using (FileStream fileStream = File.Open(LogPath, FileMode.Append)) {
         using (StreamWriter streamWriter = new StreamWriter(fileStream)) {
             monomod.Logger = (string s) => streamWriter.WriteLine(s);
             try {
                 monomod.AutoPatch(true, true);
                 return(true);
             } catch (Exception e) {
                 ins.LogLine(e.ToString());
                 return(false);
             }
         }
     }
 }
Exemple #6
0
        public static void Uninstall(this InstallerWindow ins)
        {
            if (ins.ExeMod == null)
            {
                return;
            }

            string pathFez    = ins.ExeMod.Dir.FullName;
            string pathBackup = Path.Combine(pathFez, "FEZModBackup");

            if (!Directory.Exists(pathBackup))
            {
                return;
            }

            if (ins.FezModVersion != null)
            {
                ins.Log("Found previous FEZMod installation: ").LogLine(ins.FezModVersion);
                ins.LogLine("Reverting to non-FEZMod backup...");
            }
            else
            {
                ins.LogLine("No previous FEZMod installation found.");
                ins.LogLine("Still reverting to non-FEZMod backup...");
            }

            string[] files = Directory.GetFiles(pathBackup);
            ins.InitProgress("Uninstalling FEZMod", files.Length + 1);
            for (int i = 0; i < files.Length; i++)
            {
                string file = Path.GetFileName(files[i]);
                ins.Log("Reverting: ").LogLine(file);
                ins.SetProgress("Reverting: " + file, i);
                string origPath = Path.Combine(pathFez, file);
                File.Delete(origPath);
                File.Move(files[i], origPath);
            }

            ins.LogLine("Reloading FEZ.exe");
            ins.SetProgress("Reloading FEZ.exe", files.Length);
            ins.ExeMod = new MonoMod.MonoMod(Path.Combine(pathFez, "FEZ.exe"));
            ins.ExeMod.Read(true);
            ins.EndProgress("Uninstalling complete.");
        }
Exemple #7
0
        public static void WriteDataToCache(this InstallerWindow ins, string cached, byte[] data)
        {
            string pathFez   = ins.ExeMod.Dir.FullName;
            string pathCache = Path.Combine(pathFez, "FEZModCache");

            if (!Directory.Exists(pathCache))
            {
                Directory.CreateDirectory(pathCache);
            }

            string cachedPath = Path.Combine(pathCache, cached);

            if (File.Exists(cachedPath))
            {
                File.Delete(cachedPath);
            }

            ins.Log("Writing to cache: ").LogLine(cached);
            File.WriteAllBytes(cachedPath, data);
        }
Exemple #8
0
        public static byte[] ReadDataFromCache(this InstallerWindow ins, string cached)
        {
            string pathFez   = ins.ExeMod.Dir.FullName;
            string pathCache = Path.Combine(pathFez, "FEZModCache");

            if (!Directory.Exists(pathCache))
            {
                Directory.CreateDirectory(pathCache);
            }

            string cachedPath = Path.Combine(pathCache, cached);

            if (!File.Exists(cachedPath))
            {
                return(null);
            }

            ins.Log("Reading from cache: ").LogLine(cached);
            return(File.ReadAllBytes(cachedPath));
        }
Exemple #9
0
        public static bool Mod(this InstallerWindow ins)
        {
            ins.ExeMod.Out = ins.ExeMod.In;
            //We need to reload the FEZ.exe dependencies here.
            //As they've been patched, FEZ.exe will otherwise refer to the .mm assemblies.
            ins.ExeMod.Module = null;
            ins.ExeMod.Dependencies.Clear();

            using (FileStream fileStream = File.Open(LogPath, FileMode.Append)) {
                using (StreamWriter streamWriter = new StreamWriter(fileStream)) {
                    ins.ExeMod.Logger = (string s) => streamWriter.WriteLine(s);
                    try {
                        ins.ExeMod.AutoPatch(true, true);
                        return(true);
                    } catch (Exception e) {
                        ins.LogLine(e.ToString());
                        return(false);
                    }
                }
            }
        }
Exemple #10
0
        public static bool Backup(this InstallerWindow ins, string file)
        {
            string pathFez    = ins.ExeMod.Dir.FullName;
            string pathBackup = Path.Combine(pathFez, "FEZModBackup");

            if (!Directory.Exists(pathBackup))
            {
                Directory.CreateDirectory(pathBackup);
            }

            string origPath = Path.Combine(pathFez, file);

            if (!File.Exists(origPath))
            {
                return(false);
            }

            ins.Log("Backing up: ").LogLine(file);
            File.Copy(origPath,  Path.Combine(pathBackup, file),  true);
            return(true);
        }
Exemple #11
0
        public static void ExeSelected(this InstallerWindow ins, string path, string suffix = null)
        {
            ins.Invoke(delegate() {
                ins.ExeStatusLabel.Text = path == null ? "No FEZ.exe selected" : "FEZ [checking version]";
                if (path != null && suffix != null)
                {
                    ins.ExeStatusLabel.Text += suffix;
                }
                ins.ExeStatusLabel.BackColor = path == null ? Color.FromArgb(127, 255, 63, 63) : Color.FromArgb(127, 255, 255, 63);
                ins.ExePathBox.Text          = path ?? "";
                ins.InstallButton.Enabled    = false;
            });

            if (path != null)
            {
                ins.ExeMod = new MonoMod.MonoMod(path);
            }
            else
            {
                ins.ExeMod        = null;
                ins.FezVersion    = null;
                ins.FezModVersion = null;
                return;
            }

            //We want to read the EXE now already. Writing is also handled manually.
            try {
                ins.ExeMod.Read(true);
            } catch (BadImageFormatException) {
                //this is not FEZ.exe...
                ins.ExeSelected(null);
                return;
            }

            TypeDefinition FezType = ins.ExeMod.Module.GetType("FezGame.Fez");

            if (FezType == null)
            {
                ins.ExeSelected(null);
                return;
            }
            MethodDefinition FezCctor = null;

            for (int i = 0; i < FezType.Methods.Count; i++)
            {
                if (FezType.Methods[i].IsStatic && FezType.Methods[i].IsConstructor)
                {
                    FezCctor = FezType.Methods[i];
                    break;
                }
            }
            if (FezCctor == null)
            {
                ins.ExeSelected(null);
                return;
            }
            ins.FezVersion = null;
            for (int i = 0; i < FezCctor.Body.Instructions.Count; i++)
            {
                if (!(FezCctor.Body.Instructions[i].Operand is FieldReference))
                {
                    continue;
                }
                if (((FieldReference)FezCctor.Body.Instructions[i].Operand).Name == "Version")
                {
                    ins.FezVersion = getString(FezCctor.Body.Instructions, i - 1);
                }
            }

            TypeDefinition FezModType = ins.ExeMod.Module.GetType("FezGame.Mod.FEZMod");

            if (FezModType != null)
            {
                MethodDefinition FezModCctor = null;
                for (int i = 0; i < FezModType.Methods.Count; i++)
                {
                    if (FezModType.Methods[i].IsStatic && FezModType.Methods[i].IsConstructor)
                    {
                        FezModCctor = FezModType.Methods[i];
                        break;
                    }
                }
                if (FezModCctor == null)
                {
                    ins.ExeSelected(null);
                    return;
                }
                ins.FezModVersion = null;
                for (int i = 0; i < FezModCctor.Body.Instructions.Count; i++)
                {
                    if (!(FezModCctor.Body.Instructions[i].Operand is FieldReference))
                    {
                        continue;
                    }
                    if (((FieldReference)FezModCctor.Body.Instructions[i].Operand).Name == "Version")
                    {
                        ins.FezModVersion = getString(FezModCctor.Body.Instructions, i - 1);
                        break;
                    }
                }
            }

            ins.Invoke(delegate() {
                if (ins.FezVersion == null)
                {
                    ins.ExeStatusLabel.Text      = "FEZ [unknown version]";
                    ins.ExeStatusLabel.BackColor = Color.FromArgb(127, 255, 255, 63);
                }
                else
                {
                    ins.ExeStatusLabel.Text      = "FEZ ";
                    ins.ExeStatusLabel.Text     += ins.FezVersion;
                    ins.ExeStatusLabel.BackColor = Color.FromArgb(127, 63, 255, 91);
                }

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

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

                ins.InstallButton.Enabled = true;
            });
        }
Exemple #12
0
        public static bool UnzipMod(this InstallerWindow ins, Stream zs)
        {
            string platform = "";
            string os       = FezFinder.GetPlatform().ToString().ToLower();

            if (os.Contains("win"))
            {
                platform = "win32";
            }
            else if (os.Contains("mac") || os.Contains("osx"))
            {
                platform = "osx";
            }
            else if (os.Contains("lin") || os.Contains("unix"))
            {
                platform = IntPtr.Size == 4 ? "lib" : /*== 8*/ "lib64";
            }

            string prefix = "FEZMOD";
            int    v      = int.Parse(ins.FezVersion.Substring(2));

            if (12 <= v)
            {
                prefix += "-FNA";
                ins.LogLine("FEZ 1.12 has switched from MonoGame to FNA.");
                ins.LogLine("Make sure the version you've picked is supported!");
            }
            prefix += "/";

            string pathFez = ins.ExeMod.Dir.FullName;

            ins.Log("Checking for ").Log(prefix).LogLine("...");

            using (ZipArchive zip = new ZipArchive(zs, ZipArchiveMode.Read)) {
                int prefixCount   = 0;
                int fallbackCount = 0;
                int noneCount     = 0;
                ins.InitProgress("Scanning ZIP", zip.Entries.Count);
                for (int i = 0; i < zip.Entries.Count; i++)
                {
                    ins.SetProgress(i);
                    ZipArchiveEntry entry = zip.Entries[i];
                    ins.Log("Entry: ").Log(entry.FullName).Log(": ").Log(entry.Length.ToString()).LogLine(" bytes");

                    if (entry.FullName == "InstallerVersion.txt")
                    {
                        ins.LogLine("Found version file.");

                        using (Stream s = entry.Open()) {
                            using (StreamReader sr = new StreamReader(s)) {
                                Version minv = new Version(sr.ReadLine().Trim());
                                if (InstallerWindow.Version < minv)
                                {
                                    ins.LogLine("There's a new FEZMod Installer version!");
                                    ins.LogLine("Visit https://fezmod.xyz/#download to download it.");
                                    ins.Log("(Minimum installer version for this FEZMod version: ").LogLine(minv.ToString()).Log(")");
                                    return(false);
                                }
                                if (new Version(16, 5, 10) <= minv)
                                {
                                    ins.LogLine("Blacklisting FEZMod.Speedrun as it's obsolete and causes upgrading issues");
                                    Blacklist.Add("FEZ.Speedrun.mm.dll");
                                }
                            }
                        }

                        continue;
                    }

                    string entryName = entry.FullName;
                    if (entry.FullName.StartsWith(prefix))
                    {
                        prefixCount++;
                    }
                    else if (entry.FullName.StartsWith("FEZMOD/"))
                    {
                        fallbackCount++;
                    }
                    else
                    {
                        noneCount++;
                    }
                }

                if (0 < prefixCount)
                {
                    ins.Log(prefix).LogLine(" found.");
                    ins.InitProgress("Extracting ZIP", prefixCount);
                }
                else if (0 == prefixCount && 0 < fallbackCount)
                {
                    ins.Log("Didn't find ").Log(prefix).LogLine(" - HALT THE GEARS!");
                    ins.EndProgress("Halted.").SetProgress(0);
                    return(false);
                }
                else
                {
                    ins.LogLine("Is this even a FEZMod ZIP? uh...");
                    prefix = "";
                    ins.InitProgress("Extracting ZIP", noneCount);
                }

                int extracted = 0;
                for (int i = 0; i < zip.Entries.Count; i++)
                {
                    ZipArchiveEntry entry = zip.Entries[i];
                    if (!entry.FullName.StartsWith(prefix) || entry.FullName == prefix)
                    {
                        continue;
                    }
                    ins.SetProgress(++extracted);

                    string entryName = entry.FullName.Substring(prefix.Length);

                    if (entryName.StartsWith("LIBS/"))
                    {
                        entryName = entryName.Substring(5);
                        if (!entryName.StartsWith(platform + "/"))
                        {
                            continue;
                        }
                        entryName = entryName.Substring(platform.Length + 1);
                    }

                    entryName = entryName.Replace('/', Path.DirectorySeparatorChar);

                    string path = Path.Combine(pathFez, entryName);
                    ins.Log("Extracting: ").Log(entry.FullName).Log(" -> ").LogLine(path);
                    if (entry.Length == 0 && entry.CompressedLength == 0)
                    {
                        Directory.CreateDirectory(path);
                    }
                    else
                    {
                        entry.ExtractToFile(path, true);
                    }
                }
                ins.EndProgress("Extracted ZIP.");
            }

            return(true);
        }
Exemple #13
0
 public static bool UnzipMod(this InstallerWindow ins, byte[] data)
 {
     using (MemoryStream ms = new MemoryStream(data, 0, data.Length, false, true)) {
         return(ins.UnzipMod(ms));
     }
 }
Exemple #14
0
        public static byte[] Download(this InstallerWindow ins, string url)
        {
            byte[] data = null;

            ins.Log("Downloading ").Log(url).LogLine("...");
            ins.InitProgress("Starting download", 1);

            DateTime timeStart = DateTime.Now;

            using (WebClient wc = new WebClient()) {
                using (Stream s = wc.OpenRead(url)) {
                    long sLength;
                    if (s.CanSeek)
                    {
                        //Mono
                        sLength = s.Length;
                    }
                    else
                    {
                        //.NET
                        sLength = getLength(url);
                    }
                    data = new byte[sLength];

                    long progressSize  = sLength;
                    int  progressScale = 1;
                    while (progressSize > int.MaxValue)
                    {
                        progressScale *= 10;
                        progressSize   = sLength / progressScale;
                    }

                    ins.InitProgress("Downloading", (int)progressSize);

                    DateTime timeLast = timeStart;

                    //if downloading to another stream, use CopyTo
                    int      read;
                    int      readForSpeed = 0;
                    int      pos          = 0;
                    int      speed        = 0;
                    TimeSpan td;
                    while (pos < data.Length)
                    {
                        read          = s.Read(data,  pos,  Math.Min(2048, data.Length - pos));
                        pos          += read;
                        readForSpeed += read;

                        td = (DateTime.Now - timeLast);
                        if (td.TotalMilliseconds > 100)
                        {
                            speed        = (int)((readForSpeed / 1024D) / (double)td.TotalSeconds);
                            readForSpeed = 0;
                            timeLast     = DateTime.Now;
                        }

                        ins.SetProgress(
                            "Downloading - " +
                            (int)(Math.Round(100D * ((double)(pos / progressScale) / (double)progressSize))) + "%, " +
                            speed + " KiB/s",
                            (int)(pos / progressScale)
                            );
                    }
                }
            }

            ins.EndProgress("Download complete");

            string logSize = (data.Length / 1024D).ToString(CultureInfo.InvariantCulture);

            logSize = logSize.Substring(0, Math.Min(logSize.IndexOf('.') + 3, logSize.Length));
            string logTime = (DateTime.Now - timeStart).TotalSeconds.ToString(CultureInfo.InvariantCulture);

            logTime = logTime.Substring(0, Math.Min(logTime.IndexOf('.') + 3, logTime.Length));
            ins.Log("Download complete, ").Log(logSize).Log(" KiB in ").Log(logTime).LogLine(" s.");

            return(data);
        }
Exemple #15
0
        private static void Install_(this InstallerWindow ins)
        {
            ins.Invoke(() => ins.LogBox.Visible = true).SetMainEnabled(false);

            Directory.SetCurrentDirectory(ins.ExeMod.Dir.FullName);

            ins.Log("FEZ ").LogLine(ins.FezVersion);

            //Clean FEZ from any previous FEZMod installation
            ins.Uninstall();

            ins.Backup("Common.dll");
            ins.Backup("EasyStorage.dll");
            int v = int.Parse(ins.FezVersion.Substring(2));

            if (12 <= v)
            {
                ins.Backup("FNA.dll");
            }
            else
            {
                ins.Backup("MonoGame.Framework.dll");
            }
            ins.Backup("FezEngine.dll");
            ins.Backup("FEZ.exe");

            //Setup the files and MonoMod instances
            if (ins.VersionTabs.SelectedIndex == 0)
            {
                Tuple <string, string> t = ins.StableVersions[ins.StableVersionList.SelectedIndex];
                ins.Log("FEZMod Stable ").LogLine(t.Item1);
                if (!ins.UnzipMod(ins.DownloadCached(t.Item2, "stable" + t.Item1 + ".zip")))
                {
                    return;
                }
            }
            else if (ins.VersionTabs.SelectedIndex == 1)
            {
                Tuple <string, string> t = ins.NightlyVersions[ins.NightlyVersionList.SelectedIndex];
                ins.Log("FEZMod Nightly ").LogLine(t.Item1);
                if (!ins.UnzipMod(ins.DownloadCached(t.Item2, "devbuild" + t.Item1 + ".zip")))
                {
                    return;
                }
            }
            else if (ins.VersionTabs.SelectedIndex == 2)
            {
                string path = ins.ManualPathBox.Text;

                if (path.ToLower().EndsWith(".zip"))
                {
                    ins.LogLine("FEZMod Manual ZIP");
                    if (!ins.UnzipMod(File.OpenRead(path)))
                    {
                        return;
                    }
                }
                else
                {
                    ins.LogLine("FEZMod Manual Folder");

                    string   pathFez = ins.ExeMod.Dir.FullName;
                    string[] files   = Directory.GetFiles(path);
                    ins.InitProgress("Copying FEZMod", 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(pathFez, file);
                        File.Copy(files[i], origPath, true);
                    }
                    ins.EndProgress("Copying FEZMod 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 pathFez         = ins.ExeMod.Dir.FullName;
                    string blacklistedPath = Path.Combine(pathFez, 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.ExeMod.Dir.FullName, "FEZModInstallLog.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://hastebin.com/ and");
            ins.LogLine("send it to @0x0ade on Twitter or FEZMod on GitHub.");
            ins.LogLine();

            ins.LogLine("Modding Common.dll").InitProgress("Modding Common.dll", 5);
            ins.LogLine("Common.dll is not that huge - not much to say here.");
            ins.LogLine();
            if (!ins.Mod("Common.dll"))
            {
                return;
            }

            ins.LogLine("Modding EasyStorage.dll").SetProgress("Modding EasyStorage.dll", 1);
            ins.LogLine("EasyStorage.dll also isn't huge - most probably Steam and Android stuff.");
            ins.LogLine();
            if (!ins.Mod("EasyStorage.dll"))
            {
                return;
            }

            if (12 <= v)
            {
                ins.LogLine("Modding FNA.dll").SetProgress("Modding FNA.dll", 2);
                ins.LogLine("Future versions may replace \"modding\" with replacing.");
                ins.LogLine("FNA is the \"framework\" below FEZ and powering some other games, too.");
                ins.LogLine("It replaces MonoGame in FEZ 1.12+.");
                ins.LogLine();
                if (!ins.Mod("FNA.dll"))
                {
                    return;
                }
            }
            else
            {
                ins.LogLine("Modding MonoGame.Framework.dll").SetProgress("Modding MonoGame.Framework.dll", 2);
                ins.LogLine("Wait... where's FNA? Well, I guess you're using old FEZ.");
                ins.LogLine();
                if (!ins.Mod("MonoGame.Framework.dll"))
                {
                    return;
                }
            }

            ins.LogLine("Modding FezEngine.dll").SetProgress("Modding FezEngine.dll", 3);
            ins.LogLine("The Trixel Engine also becomes the \"FEZMod Engine.\"");
            ins.LogLine("If something low-level happens, for example loading textures,");
            ins.LogLine("music, handling geometry, inter-mod-communication,... it's here.");
            ins.LogLine();
            if (!ins.Mod("FezEngine.dll"))
            {
                return;
            }

            ins.LogLine("Modding FEZ.exe").SetProgress("Modding FEZ.exe", 4);
            ins.LogLine("This process will take the longest of all.");
            ins.LogLine("You won't see anything happening here, but don't panic:");
            ins.LogLine("If the installer crashes, an error log appears here.");
            ins.LogLine();
            if (!ins.Mod())
            {
                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 FEZ.");
            ins.LogLine("If FEZ crashes with FEZMod, go to the FEZ folder (that one");
            ins.LogLine("where FEZ.exe is, basically the path at the top-right),");
            ins.LogLine("upload JAFM Log.txt somewhere and give it @0x0ade.");
            ins.LogLine("Good luck - Have fun!");
            ins.ExeSelected(ins.ExeMod.In.FullName, " [just installed]");
            ins.SetMainEnabled(true);
        }