Ejemplo n.º 1
0
        public void CreateAndSaveEmptyGame()
        {
            UndertaleData data = UndertaleData.CreateNew();

            using (MemoryStream ms = new MemoryStream())
            {
                UndertaleIO.Write(ms, data);
            }
        }
Ejemplo n.º 2
0
        public void SaveDataAndCompare()
        {
            using (MemoryStream ms = new MemoryStream())
            {
                UndertaleIO.Write(ms, data);

                ms.Position = 0;
                string writtenMD5 = GenerateMD5(ms);
                Assert.AreEqual(expectedMD5, writtenMD5, "Written file doesn't match read file");
            }
        }
Ejemplo n.º 3
0
        static void Main(string[] args)
        {
            UndertaleData data = UndertaleIO.Read(new FileStream(@"deltarune\data.win", FileMode.Open, FileAccess.Read));

            foreach (var code in data.Code)
            {
                Debug.WriteLine(code.Name.Content);
                code.Replace(Assembler.Assemble(code.Disassemble(data.Variables, data.CodeLocals.For(code)), data.Functions, data.Variables, data.Strings));
            }

            UndertaleIO.Write(new FileStream(@"deltarune\newdata.win", FileMode.Create), data);
        }
 private void saveOutputButton_Click(object sender, EventArgs e)
 {
     label1.Text = boxWorkingMsg;
     try {
         UndertaleIO.Write(fsin, Data);
     }
     catch (Exception es) {
         label1.Text = es.ToString();
         MessageBox.Show(es.Message, "Writing error", MessageBoxButtons.OK, MessageBoxIcon.Error);
     }
     label1.Text = boxCompleteMsg;
 }
Ejemplo n.º 5
0
        /// <summary>
        /// Saves the currently loaded <see cref="Data"/> to an output path.
        /// </summary>
        /// <param name="outputPath">The path where to save the data.</param>
        private void SaveDataFile(string outputPath)
        {
            if (Verbose)
            {
                Console.WriteLine($"Saving new data file to '{outputPath}'");
            }

            using FileStream fs = new FileInfo(outputPath).OpenWrite();
            UndertaleIO.Write(fs, Data, MessageHandler);
            if (Verbose)
            {
                Console.WriteLine($"Saved data file to '{outputPath}'");
            }
        }
Ejemplo n.º 6
0
        public void CliSave(string to)
        {
            if (Verbose)
            {
                Console.WriteLine($"Saving new data file to {this.Output.FullName}");
            }

            using (var fs = new FileInfo(to).OpenWrite())
            {
                UndertaleIO.Write(fs, Data, OnMessage);
                if (Verbose)
                {
                    Console.WriteLine($"Saved data file to {this.Output.FullName}");
                }
            }
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Writes the data to a new data.win using UndertaleModLib
        /// </summary>
        /// <param name="outputPath">Output path for new data.win</param>
        static void WriteData(string outputPath)
        {
            Console.WriteLine("Writing randomised data.win");
            FileStream fs = new FileStream(outputPath, FileMode.Create, FileAccess.Write);

            try
            {
                UndertaleIO.Write(fs, data);
            }
            catch (IOException e)
            {
                Console.WriteLine(e.Message);
                Console.ReadLine();
                Environment.Exit(1);
            }
            fs.Close();
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Method that gets executed on the "new" command
        /// </summary>
        /// <param name="options">The arguments that have been provided with the "new" command</param>
        /// <returns><see cref="EXIT_SUCCESS"/> and <see cref="EXIT_FAILURE"/> for being successful and failing respectively</returns>
        private static int New(NewOptions options)
        {
            //TODO: this should probably create a new Program instance, with just the properties that it needs

            UndertaleData data = UndertaleData.CreateNew();

            // If stdout flag is set, write new data to stdout and quit
            if (options.Stdout)
            {
                if (options.Verbose)
                {
                    Console.WriteLine("Attempting to write new Data file to STDOUT...");
                }
                using MemoryStream ms = new MemoryStream();
                UndertaleIO.Write(ms, data);
                Console.OpenStandardOutput().Write(ms.ToArray(), 0, (int)ms.Length);
                Console.Out.Flush();
                if (options.Verbose)
                {
                    Console.WriteLine("Successfully wrote new Data file to STDOUT.");
                }

                return(EXIT_SUCCESS);
            }

            // If not STDOUT, write to file instead. Check first if we have permission to overwrite
            if (options.Output.Exists && !options.Overwrite)
            {
                Console.Error.WriteLine($"'{options.Output}' already exists. Pass --overwrite to overwrite");
                return(EXIT_FAILURE);
            }

            // We're not writing to STDOUT, and overwrite flag was given, so we write to specified file.
            if (options.Verbose)
            {
                Console.WriteLine($"Attempting to write new Data file to '{options.Output}'...");
            }
            using FileStream fs = options.Output.OpenWrite();
            UndertaleIO.Write(fs, data);
            if (options.Verbose)
            {
                Console.WriteLine($"Successfully wrote new Data file to '{options.Output}'.");
            }
            return(EXIT_SUCCESS);
        }
Ejemplo n.º 9
0
        public static int New(NewOptions options)
        {
            var data = UndertaleData.CreateNew();

            if (options.Stdout)
            {
                WriteStdout();
            }
            else
            {
                if (WriteFile() == EXIT_FAILURE)
                {
                    return(EXIT_FAILURE);
                }
            }
            return(EXIT_SUCCESS);


            int WriteFile()
            {
                if (options.Output.Exists && !options.Overwrite)
                {
                    Console.Error.WriteLine($"{options.Output} already exists. Pass --overwrite to overwrite");
                    return(EXIT_FAILURE);
                }
                using (var fs = options.Output.OpenWrite())
                {
                    UndertaleIO.Write(fs, data);
                    return(EXIT_SUCCESS);
                }
            }

            void WriteStdout()
            {
                using (var ms = new MemoryStream())
                {
                    UndertaleIO.Write(ms, data);
                    System.Console.OpenStandardOutput().Write(ms.ToArray(), 0, (int)ms.Length);
                    System.Console.Out.Flush();
                }
            }
        }
Ejemplo n.º 10
0
        private async Task SaveFile(string filename)
        {
            if (Data == null || Data.UnsupportedBytecodeVersion)
            {
                return;
            }
            SetStatics();
            LoadDlg dialogue = null;
            Task    t        = null;
            bool    thingy   = await DoCorrupt.DoThing(Data, Values.DoSprite, Values.DoBackground, Values.DoSound, Values.DoText, Values.DoFont, Values.SpriteType, FilePath, rng, IsDelta());

            if (thingy)
            {
                MessageBox.Show("Corrupted succesfully! Probably!", "Egg?!?!?!?!??!", MessageBoxButton.OK, MessageBoxImage.None);
                dialogue = new LoadDlg {
                    Owner = this
                };

                t = Task.Run(() =>
                {
                    //OldData = Data;
                    //MessageBox.Show("Data old set", "", MessageBoxButton.OK, MessageBoxImage.None);
                    using (var stream = new FileStream(filename, FileMode.Create))
                    {
                        UndertaleIO.Write(stream, Data);
                    }

                    Dispatcher.Invoke(() =>
                    {
                        dialogue.Close();
                        //Data = OldData;
                        //MessageBox.Show("New data set", "", MessageBoxButton.OK, MessageBoxImage.None);
                    });
                });
                dialogue.ShowDialog();
                await t;
            }
        }
Ejemplo n.º 11
0
        private async Task SaveFile(string filename)
        {
            if (Data == null || Data.UnsupportedBytecodeVersion)
            {
                return;
            }

            LoaderDialog dialog = new LoaderDialog("Saving", "Saving, please wait...");
            IProgress <Tuple <int, string> > progress = new Progress <Tuple <int, string> >(i => { dialog.ReportProgress(i.Item2, i.Item1); });
            IProgress <double?> setMax = new Progress <double?>(i => { dialog.Maximum = i; });

            dialog.Owner = this;
            FilePath     = filename;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("FilePath"));
            if (System.IO.Path.GetDirectoryName(FilePath) != System.IO.Path.GetDirectoryName(filename))
            {
                CloseChildFiles();
            }

            DebugDataDialog.DebugDataMode debugMode = DebugDataDialog.DebugDataMode.NoDebug;
            if (!Data.GeneralInfo.DisableDebugger) // TODO: I think the game itself can also use the .yydebug file on crash reports
            {
                DebugDataDialog debugDialog = new DebugDataDialog();
                debugDialog.Owner = this;
                debugDialog.ShowDialog();
                debugMode = debugDialog.Result;
            }
            Task t = Task.Run(() =>
            {
                try
                {
                    using (var stream = new FileStream(filename, FileMode.Create, FileAccess.Write))
                    {
                        UndertaleIO.Write(stream, Data);
                    }

                    if (debugMode != DebugDataDialog.DebugDataMode.NoDebug)
                    {
                        Debug.WriteLine("Generating debugger data...");

                        UndertaleDebugData debugData = UndertaleDebugData.CreateNew();

                        setMax.Report(Data.Code.Count);
                        int count        = 0;
                        object countLock = new object();
                        string[] outputs = new string[Data.Code.Count];
                        UndertaleDebugInfo[] outputsOffsets = new UndertaleDebugInfo[Data.Code.Count];
                        Parallel.For(0, Data.Code.Count, (i) =>
                        {
                            var code = Data.Code[i];

                            if (debugMode == DebugDataDialog.DebugDataMode.Decompiled)
                            {
                                //Debug.WriteLine("Decompiling " + code.Name.Content);
                                string output;
                                try
                                {
                                    output = Decompiler.Decompile(code, Data);
                                }
                                catch (Exception e)
                                {
                                    Debug.WriteLine(e.Message);
                                    output = "/*\nEXCEPTION!\n" + e.ToString() + "\n*/";
                                }
                                outputs[i] = output;

                                UndertaleDebugInfo debugInfo = new UndertaleDebugInfo();
                                debugInfo.Add(new UndertaleDebugInfo.DebugInfoPair()
                                {
                                    SourceCodeOffset = 0, BytecodeOffset = 0
                                });                                                                                                 // TODO: generate this too! :D
                                outputsOffsets[i] = debugInfo;
                            }
                            else
                            {
                                StringBuilder sb             = new StringBuilder();
                                UndertaleDebugInfo debugInfo = new UndertaleDebugInfo();

                                foreach (var instr in code.Instructions)
                                {
                                    if (debugMode == DebugDataDialog.DebugDataMode.FullAssembler || instr.Kind == UndertaleInstruction.Opcode.Pop || instr.Kind == UndertaleInstruction.Opcode.Popz || instr.Kind == UndertaleInstruction.Opcode.B || instr.Kind == UndertaleInstruction.Opcode.Bt || instr.Kind == UndertaleInstruction.Opcode.Bf || instr.Kind == UndertaleInstruction.Opcode.Ret || instr.Kind == UndertaleInstruction.Opcode.Exit)
                                    {
                                        debugInfo.Add(new UndertaleDebugInfo.DebugInfoPair()
                                        {
                                            SourceCodeOffset = (uint)sb.Length, BytecodeOffset = instr.Address * 4
                                        });
                                    }
                                    sb.Append(instr.ToString(code, Data.Variables));
                                    sb.Append("\n");
                                }
                                outputs[i]        = sb.ToString();
                                outputsOffsets[i] = debugInfo;
                            }

                            lock (countLock)
                            {
                                progress.Report(new Tuple <int, string>(++count, code.Name.Content));
                            }
                        });
                        setMax.Report(null);

                        for (int i = 0; i < Data.Code.Count; i++)
                        {
                            debugData.SourceCode.Add(new UndertaleScriptSource()
                            {
                                SourceCode = debugData.Strings.MakeString(outputs[i])
                            });
                            debugData.DebugInfo.Add(outputsOffsets[i]);
                            debugData.LocalVars.Add(Data.CodeLocals[i]);
                            if (debugData.Strings.IndexOf(Data.CodeLocals[i].Name) < 0)
                            {
                                debugData.Strings.Add(Data.CodeLocals[i].Name);
                            }
                            foreach (var local in Data.CodeLocals[i].Locals)
                            {
                                if (debugData.Strings.IndexOf(local.Name) < 0)
                                {
                                    debugData.Strings.Add(local.Name);
                                }
                            }
                        }

                        using (UndertaleWriter writer = new UndertaleWriter(new FileStream(System.IO.Path.ChangeExtension(FilePath, ".yydebug"), FileMode.Create, FileAccess.Write)))
                        {
                            debugData.FORM.Serialize(writer);
                            writer.ThrowIfUnwrittenObjects();
                        }
                    }
                }
                catch (Exception e)
                {
                    MessageBox.Show("An error occured while trying to save:\n" + e.Message, "Save error", MessageBoxButton.OK, MessageBoxImage.Error);
                }

                Dispatcher.Invoke(() =>
                {
                    dialog.Hide();
                });
            });

            dialog.ShowDialog();
            await t;
        }
Ejemplo n.º 12
0
        private async Task SaveFile(string filename)
        {
            if (Data == null || Data.UnsupportedBytecodeVersion)
            {
                return;
            }

            if (IsGMS2 == Visibility.Visible)
            {
                MessageBox.Show("This is not yet fully stable and may break. You have been warned.", "GMS2 game", MessageBoxButton.OK, MessageBoxImage.Warning);
            }

            LoaderDialog dialog = new LoaderDialog("Saving", "Saving, please wait...");

            dialog.Owner = this;
            FilePath     = filename;
            if (System.IO.Path.GetDirectoryName(FilePath) != System.IO.Path.GetDirectoryName(filename))
            {
                CloseChildFiles();
            }

            DebugDataMode debugMode = DebugDataMode.NoDebug;

            if (!Data.GeneralInfo.DisableDebugger) // TODO: I think the game itself can also use the .yydebug file on crash reports
            {
                DebugDataDialog debugDialog = new DebugDataDialog();
                debugDialog.Owner = this;
                debugDialog.ShowDialog();
                debugMode = debugDialog.Result;
                // TODO: Add an option to generate debug data for just selected scripts (to make running faster / make the full assembly not take forever to load)
            }
            Task t = Task.Run(() =>
            {
                try
                {
                    using (var stream = new FileStream(filename, FileMode.Create))
                    {
                        UndertaleIO.Write(stream, Data);
                    }

                    if (debugMode != DebugDataMode.NoDebug)
                    {
                        Debug.WriteLine("Generating debugger data...");
                        UndertaleDebugData debugData = DebugDataGenerator.GenerateDebugData(Data, debugMode);
                        using (FileStream stream = new FileStream(System.IO.Path.ChangeExtension(FilePath, ".yydebug"), FileMode.Create))
                        {
                            using (UndertaleWriter writer = new UndertaleWriter(stream))
                            {
                                debugData.FORM.Serialize(writer);
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    MessageBox.Show("An error occured while trying to save:\n" + e.Message, "Save error", MessageBoxButton.OK, MessageBoxImage.Error);
                }

                Dispatcher.Invoke(() =>
                {
                    dialog.Hide();
                });
            });

            dialog.ShowDialog();
            await t;
        }
Ejemplo n.º 13
0
        private static void Main()
        {
            Console.WriteLine("Main() called!");
            Console.WriteLine();
            Console.WriteLine();
            Console.WriteLine("Downwell Custom Controls Mod Installer Thing...");
            Console.WriteLine("Open the game folder, what do you see?");
            Console.WriteLine("1 - A single Downwell.exe file, that's it.");
            Console.WriteLine("2 - A lot of files, and data.win is one of them.");
            Console.Write("Input: ");
            var key = Console.ReadKey(false);

            Console.WriteLine();
            bool   singleexe = false;
            string datawinpath;

            if (key.Key == ConsoleKey.D2)
            {
                Console.WriteLine("Please drag data.win onto this window and press enter:");
                datawinpath = Console.ReadLine();
            }
            else if (key.Key == ConsoleKey.D1)
            {
                Console.WriteLine("Please start the game, and press any key.");
                Console.ReadKey(true);
                Console.WriteLine("Copying IXP000.TMP...");
                if (!CopyIXPFolder())
                {
                    Console.WriteLine("Cannot detect or copy the game's folder, ask nik on Steam Discussion forums.");
                    Console.ReadKey(true);
                    return;
                }

                // We copied the folder without any issues.
                datawinpath = Environment.GetEnvironmentVariable("TEMP") + Path.DirectorySeparatorChar + "ForPatchTemp" + Path.DirectorySeparatorChar + "data.win";

                singleexe = true;
            }
            else
            {
                Console.WriteLine("Unknown Input, relaunch this program and try again.");
                Console.ReadKey(true);
                return;
            }

            if (!File.Exists(datawinpath))
            {
                Console.WriteLine("What? Somehow data.win is missing, ask nik on Steam Discussion forums.");
                Console.ReadKey(true);
                return;
            }

            Console.WriteLine("Please make sure you've closed the game. If you did, press any key.");
            Console.ReadKey(true);

            // Ok, we can finally patch!!!
            Console.WriteLine("Loading data.win in UndertaleModLib...");
            bool quit = false;

            try
            {
                using (var stream = new FileStream(datawinpath, FileMode.Open, FileAccess.Read))
                {
                    Data = UndertaleIO.Read(stream, warning =>
                    {
                        Console.WriteLine("[MODLIB|WARN]: " + warning);
                        quit = true;
                    });
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("[MODLIB|ERR ]: " + e.Message);
                quit = true;
            }

            if (quit)
            {
                Console.WriteLine("Warnings or errors occured when loading data.win!");
                Console.WriteLine("Press any key to exit...");
                Console.ReadKey(true);
                Environment.Exit(-1); // forcefully quit.
            }

            Console.WriteLine("Executing PatchThing();");
            PatchThing();
            Console.WriteLine();
            Console.WriteLine("Writing new data.win...");
            File.Delete(datawinpath);
            using (var stream = new FileStream(datawinpath, FileMode.Create, FileAccess.Write))
            {
                UndertaleIO.Write(stream, Data);
            }
            Console.WriteLine("Writing default controls.ini...");
            File.WriteAllText(Path.GetDirectoryName(datawinpath) + Path.DirectorySeparatorChar + "controls.ini", DefaultIni);
            if (singleexe)
            {
                FindDownwellExe(new DirectoryInfo(Path.GetDirectoryName(datawinpath)));
                Process.Start("explorer.exe", Path.GetDirectoryName(datawinpath));
                Console.WriteLine("Copy all files from this folder to your game folder.");
                Console.WriteLine("(if it asks to replace, agree, then press any key)");
                Console.ReadKey(true);
            }
            Console.WriteLine("Ok, we're done here, launch the game and press any key to exit.");
            Console.ReadKey(true);
            Console.WriteLine("Cleaning up...");
            if (singleexe)
            {
                Directory.Delete(Path.GetDirectoryName(datawinpath), true);
            }
        }
Ejemplo n.º 14
0
        static void Main(string[] args)
        {
            bool israel = false;

            if (args.Length < 1 || args.Contains("help"))
            {
                Console.WriteLine(@"Sanae's Disappearing Rabbit Patcher v1.1
A game patcher for Oh Jeez, Oh No, My Rabbits Are Gone!
Command Line Usage: RMP.exe <path to data.win> [patches]
The path to the data.win file should be where you downloaded your game.
If you downloaded it on Steam, look up how to get to a game's local files.
Patches available are:
- all - default option, applies all patches, all must be the first patch in the command
  all other supplied patches will be ignored
  if you want to specific patches, please type them instead of using all
- speedrun - the main patch for speedrunning, some patches have a dependency on this one
- intro - skips the intro in speedrunning mode (depends on speedrun)
- clock - adds a clock to the top left of the window (depends on speedrun)
- frame - press P to change maximum frame speed between 1000 and 60
- debug - adds several debug options to the game (disabled by default) (see github readme for more info)
- color - a cute little bunny color changer, randomized on room (re)entry
- nosave - prevents savepoints from being created (disabled by default)
- decomp - dumps all game code to a folder inside current directory (disabled by default)
- everything - runs *every* patch/action, unlike all, which just runs all non-severe actions/patches
- every - everything except for the decomp action
- ever - every but no decomp and no debug
");
                if (args.Length == 1 && args[0] != "help")
                {
                    Console.WriteLine("Press any key to exit");
                    Console.ReadKey();
                    return;
                }
                var ofd = new OpenFileDialog();
                ofd.Title  = "Locate your data.win file";
                ofd.Filter = "data.win|data.win";
                DialogResult dr = ofd.ShowDialog();
                if (dr == DialogResult.Cancel)
                {
                    return;
                }
                baseloc = ofd.FileName;
                israel  = true;
            }
            else
            {
                baseloc = args[0];
            }
            List <string> actions;

            {
                if (israel || args.Length == 1 || (args[1] == "all"))
                {
                    actions = new List <string>()
                    {
                        "speedrun",
                        "frame",
                        "color",
                        "clock",
                        "intro"
                    }
                }
                ;
                else if (args[1] == "everything")
                {
                    actions = new List <string>()
                    {
                        "speedrun",
                        "frame",
                        "color",
                        "clock",
                        "intro",
                        "debug",
                        "nosave",
                        "decomp"
                    };
                }
                else if (args[1] == "every")
                {
                    actions = new List <string>()
                    {
                        "speedrun",
                        "frame",
                        "color",
                        "clock",
                        "intro",
                        "debug",
                        "nosave"
                    };
                }
                else
                {
                    actions = new List <string>()
                    {
                        ""
                    };
                    actions.AddRange(args.Skip(1));
                }
            }
            if (!Path.HasExtension(baseloc) || !Directory.Exists(Path.GetDirectoryName(baseloc)))
            {
                Console.Error.WriteLine("Invalid data.win path!\n" + baseloc);
                return;
            }
            baseloc = Path.GetDirectoryName(baseloc) + "\\";
            if (!File.Exists(baseloc + "data.win.orig"))
            {
                if (File.Exists(baseloc + "data.win"))
                {
                    File.Move(baseloc + "data.win", baseloc + "data.win.orig");
                }
                else
                {
                    Console.Error.WriteLine("There's no data.win in this folder, and there's no data.win.orig!");
                    return;
                }
            }
            File.Delete(baseloc + "data.win");
            File.Copy(baseloc + "data.win.orig", baseloc + "data.win");
            FileStream    fileStream = File.Open(baseloc + "data.win", FileMode.Open);
            UndertaleData data       = UndertaleIO.Read(fileStream);

            fileStream.Close();
            File.Delete(baseloc + "data.win");
            if (data.GeneralInfo.DisplayName.Content != "My Rabbits Are Gone")
            {
                Console.Error.WriteLine("This data.win is not from Oh Jeez, Oh No, My Rabbits Are Gone\nPlease provide that one instead.");
                File.Copy(baseloc + "data.win.orig", baseloc + "data.win");
                return;
            }

            List <string> usedActions = new List <string>();
            var           gi          = new UndertaleGlobalInit();
            var           code        = new UndertaleCode();

            code.ReplaceGML("global.patched = true", data);
            code.Name = data.Strings.MakeString("gml_global_set_patched");
            gi.Code   = code;
            bool speedran = false;

            for (int i = 0; i < actions.Count; i++)
            {
                if (actions[i] != "")
                {
                    if (usedActions.Contains(actions[i]))
                    {
                        continue;
                    }
                    usedActions.Add(actions[i]);//prevent repatching actions that are already patched
                    Console.WriteLine(actions[i]);
                }
                switch (actions[i])
                {
                case "speedrun":
                    speedran = true;
                    SpeedrunPatches(data);
                    break;

                case "debug":
                    DebugPatches(data);
                    break;

                case "clock":
                    if (!speedran)
                    {
                        YUNORAN();
                    }
                    ClockPatches(data);
                    break;

                case "intro":
                    if (!speedran)
                    {
                        YUNORAN();
                    }
                    IntroPatch(data);
                    break;

                case "nosave":
                    if (!speedran)
                    {
                        YUNORAN();
                    }
                    SavePointPatch(data);
                    break;

                case "decomp":
                    Directory.CreateDirectory("./decomp/");
                    for (int ia = 0; ia < data.Code.Count; ia++)
                    {
                        UndertaleCode uc = data.Code[ia];
                        Console.WriteLine("Writing " + uc.Name.Content);
                        try
                        {
                            File.WriteAllText(baseloc + "/decomp/" + uc.Name.Content, Decompiler.Decompile(uc, new DecompileContext(data, false)));
                        }
                        catch (Exception e)
                        {
                            Console.WriteLine("failed! " + e.Message);
                        }
                        Console.WriteLine("Wrote " + uc.Name.Content);
                    }
                    break;

                case "frame":
                    FramecapRemover(data);
                    break;

                case "color":
                    ColorRandomizer(data);
                    break;

                case "multiplayer":
                    Console.WriteLine("maybe one day, not today 😭");
                    break;

                case "":
                    break;

                default:
                    Console.Error.WriteLine($"Invalid action {actions[i]}\n Run RMP.exe with no arguments to see proper usage of the program.");
                    File.Copy(baseloc + "data.win.orig", baseloc + "data.win");
                    return;
                }
            }

            UndertaleIO.Write(File.Open(baseloc + "data.win", FileMode.OpenOrCreate), data);
            Console.WriteLine("Wrote data.win! A new option has been added to the main menu.");
        }