internal AScriptHandler(OMOD omod, string script, OMODScriptSettings settings, string?extractionFolder)
        {
            ScriptSettings = settings;

            OMOD   = omod;
            Script = script;

            var guid = Guid.NewGuid();

            ExtractionFolder = extractionFolder ?? Path.Combine(Path.GetTempPath(), "OMODFramework", guid.ToString("D"));

            DataFolder    = Path.Combine(ExtractionFolder, "data");
            PluginsFolder = Path.Combine(ExtractionFolder, "plugins");

            if (!settings.DryRun)
            {
                Directory.CreateDirectory(DataFolder);
                Directory.CreateDirectory(PluginsFolder);

                omod.ExtractFilesParallel(DataFolder, 4);
                if (omod.HasEntryFile(OMODEntryFileType.Plugins))
                {
                    omod.ExtractFiles(false, PluginsFolder);
                }
            }

            ScriptReturnData = new ScriptReturnData(DataFolder, PluginsFolder);
            ScriptFunctions  = new ScriptFunctions(ScriptSettings, omod, ScriptReturnData);
        }
Beispiel #2
0
        /// <summary>
        /// Executes the script
        /// </summary>
        public ScriptReturnData ExecuteScript()
        {
            srd = new ScriptReturnData();

            var sf = new ScriptFunctions(
                srd, DataPath, PluginsPath, OMOD.GetFramework(), ScriptRunnerFunctions);

            switch (type)
            {
            case ScriptType.obmmScript:
                return(OBMMScriptHandler.Execute(
                           OMOD.GetFramework(), script, DataPath, PluginsPath, ScriptRunnerFunctions));

            case ScriptType.Python:
                throw new NotImplementedException();

            case ScriptType.cSharp:
                DotNetScriptHandler.ExecuteCS(script, sf);
                break;

            case ScriptType.vb:
                DotNetScriptHandler.ExecuteVB(script, sf);
                break;
            }

            return(srd);
        }
 internal DotNetScriptFunctions(ScriptReturnData srd, string dataFilesPath, string pluginsPath, ref SharedFunctionsHandler handler)
 {
     _srd       = srd;
     _dataFiles = dataFilesPath;
     _plugins   = pluginsPath;
     _handler   = handler;
 }
        internal ScriptFunctions(ScriptReturnData srd, string dataFilesPath, string pluginsPath,
                                 Framework _f,
                                 IScriptRunnerFunctions scriptRunnerFunctions)
        {
            f = _f;
            //Warn = scriptRunnerFunctions.Warn;
            IDialogYesNo         = scriptRunnerFunctions.DialogYesNo;
            ExistsFile           = scriptRunnerFunctions.ExistsFile;
            GetFileVersion       = scriptRunnerFunctions.GetFileVersion;
            DialogSelect         = scriptRunnerFunctions.DialogSelect;
            IMessage             = scriptRunnerFunctions.Message;
            IDisplayImage        = scriptRunnerFunctions.DisplayImage;
            IDisplayText         = scriptRunnerFunctions.DisplayText;
            IInputString         = scriptRunnerFunctions.InputString;
            IGetActiveESPNames   = scriptRunnerFunctions.GetActiveESPNames;
            IGetFile             = scriptRunnerFunctions.GetFileFromPath;
            IGetExistingESPNames = scriptRunnerFunctions.GetExistingESPNames;
            IUncheckESP          = scriptRunnerFunctions.UncheckESP;
            IRegisterBSA         = scriptRunnerFunctions.RegisterBSA;
            IUnregisterBSA       = scriptRunnerFunctions.UnregisterBSA;
            IReadINI             = scriptRunnerFunctions.ReadINI;
            IReadRendererInfo    = scriptRunnerFunctions.ReadRendererInfo;

            this.srd  = srd;
            DataFiles = dataFilesPath;
            Plugins   = pluginsPath;
        }
Beispiel #5
0
        internal static PluginFile GetPluginFile(this ScriptReturnData srd, string file, bool byInput = true)
        {
            var pluginFile = srd.PluginFiles.First(x => byInput
                ? x.Input.Name.Equals(file.MakePath(), StringComparison.OrdinalIgnoreCase)
                : x.Output.Equals(file.MakePath(), StringComparison.OrdinalIgnoreCase));

            return(pluginFile);
        }
        internal static ScriptReturnData ExecuteScript(string script, string dataPath, string pluginsPath, IScriptFunctions scriptFunctions)
        {
            Utils.Info("Starting script execution...");
            if (string.IsNullOrWhiteSpace(script))
            {
                Utils.Error("Script is empty! Returning empty ScriptReturnData");
                return(new ScriptReturnData());
            }

            ScriptType type;

            if ((byte)script[0] >= (byte)ScriptType.Count)
            {
                type = ScriptType.OBMMScript;
            }
            else
            {
                type   = (ScriptType)script[0];
                script = script.Substring(1);
            }

            Utils.Debug($"ScriptType is {type.ToString()}");

            var handler = new SharedFunctionsHandler(type, ref scriptFunctions);
            var srd     = new ScriptReturnData();
            var dotNetScriptFunctions = new Lazy <DotNetScriptFunctions>(() =>
                                                                         new DotNetScriptFunctions(srd, dataPath, pluginsPath, ref handler)).Value;

            switch (type)
            {
            case ScriptType.OBMMScript:
                return(OBMMScriptHandler.Execute(script, dataPath, pluginsPath, ref handler));

            case ScriptType.Python:     //TODO
                break;

            case ScriptType.CSharp:
                DotNetScriptHandler.ExecuteCS(script, ref dotNetScriptFunctions);
                break;

            case ScriptType.VB:
                DotNetScriptHandler.ExecuteVB(script, ref dotNetScriptFunctions);
                break;

            case ScriptType.Count:     //Impossible
                Utils.Error("Impossible switch case triggered, how dafuq did this happen?");
                break;

            default:     //Impossible
                Utils.Error("Impossible switch case triggered, how dafuq did this happen?");
                return(srd);
            }

            return(srd);
        }
Beispiel #7
0
        internal static PluginFile GetOrAddPluginFile(this ScriptReturnData srd, string file, OMOD omod, bool byInput = true)
        {
            var filePath   = file.MakePath();
            var pluginFile = srd.PluginFiles.FirstOrDefault(x => byInput
                ? x.Input.Name.Equals(filePath, StringComparison.OrdinalIgnoreCase)
                : x.Output.Equals(filePath, StringComparison.OrdinalIgnoreCase));

            if (pluginFile != null)
            {
                return(pluginFile);
            }

            var compressedFile = GetPluginFile(omod, filePath);

            pluginFile = new PluginFile(compressedFile);
            srd.PluginFiles.Add(pluginFile);

            return(pluginFile);
        }
Beispiel #8
0
        static void Main(string[] args)
        {
            // BEFORE you checkout the example:
            // this example is not optimized, it is not intended to be used in production
            // this should be used for understanding how the Framework operates, what it
            // needs, what you can do with it and what it returns

            Framework f = new Framework(); // basic, do this or go home

            string temp      = @"M:\Projects\omod\testDLL\temp";
            string OutputDir = @"M:\Projects\omod\testDLL\output";

            // check if the temp and output dir already exist and delete them if they do
            if (Directory.Exists(temp))
            {
                DeleteDirectory(temp);
            }
            Directory.CreateDirectory(temp);
            if (Directory.Exists(OutputDir))
            {
                DeleteDirectory(OutputDir);
            }
            Directory.CreateDirectory(OutputDir);

            f.SetOBMMVersion(1, 1, 12); // latest official obmm version use this unless you know what you're doing
            f.SetTempDirectory(temp);
            // setting the dll path is mostly used for debugging or if you execute the code from somewhere else
            // better safe than sorry just do this if
            f.SetDLLPath(@"M:\Projects\OMOD-Framework\OMOD-Framework\bin\Release\erri120.OMODFramework.dll");

            // after everything is setup you can go ahead and grap the omod
            OMOD omod = new OMOD(@"M:\Projects\omod\testDLL\Robert Male Body Replacer v52 OMOD-40532-1.omod", ref f);

            // before you run the install script, extract the data files and plugins from the omod
            // ExtractDataFiles will always return something but ExtractPlugins can return null if there is no
            // plugins.crc in the OMOD
            string dataPath    = omod.ExtractDataFiles(); //extracts all data files and returns the path to them
            string pluginsPath = omod.ExtractPlugins();   //extracts all plugins and returns the path to them

            // the interface IScriptRunnerFunctions should be implemented by something that you can pass on
            // as an argument, in this case I created an internal class called ScriptFunctions that implements
            // all functions from the interface
            ScriptFunctions a = new ScriptFunctions();

            // the script runner can execute the script, return the script and/or script type
            ScriptRunner sr = new ScriptRunner(ref omod, a);

            //to get the type:
            //ScriptType scriptType = sr.GetScriptType();

            //to get the entire script without the first byte:
            //String script = sr.GetScript();

            // this will execute the script and return all information about what needs to be installed
            ScriptReturnData srd = sr.ExecuteScript();

            // after the script executed go ahead and do whatever you want with the ScriptReturnData:
            // be sure to check if the installation is canceled or you will run into issues
            if (srd.CancelInstall)
            {
                Console.WriteLine("Installation canceled");
            }

            // just for testing
            bool doPretty = true;

            if (doPretty)
            {
                // if you do not want the raw output but a more 'prettier' version, use this method
                // it will change the ScriptReturnData and will populate the InstallFiles list
                srd.Pretty(true, ref omod, ref pluginsPath, ref dataPath);

                // loop through the whole thing, do note the custom struct
                foreach (InstallFile file in srd.InstallFiles)
                {
                    string s = Path.GetDirectoryName(file.InstallTo);
                    if (!Directory.Exists(Path.Combine(OutputDir, s)))
                    {
                        Directory.CreateDirectory(Path.Combine(OutputDir, s));
                    }
                    File.Move(file.InstallFrom, Path.Combine(OutputDir, file.InstallTo));
                }
            }
            else
            {
                // in the following example I will create two lists, one for all data files and one for all
                // plugins that need to be installed
                // this may seem non-intuitive since the ScriptReturnData should return this list
                // the thing is that you have InstallAll, Install, Ignore and Copy operations
                // the install script in the omod decideds what is best for itself

                List <string> InstallPlugins   = new List <string>();
                List <string> InstallDataFiles = new List <string>();

                // start by checking if you can install all plugins
                if (srd.InstallAllPlugins)
                {
                    // simply get all plugin files from the omod and loop through them
                    // the s.Contains is just a safety check
                    foreach (string s in omod.GetPluginList())
                    {
                        if (!s.Contains("\\"))
                        {
                            InstallPlugins.Add(s);
                        }
                    }
                }
                // if you can't install everything go and check the list called InstallPlugins
                // this list gets populated when InstallAllPlugins is false
                // the Framework comes with two utility functions that helps in creating the temp list:
                // strArrayContains and strArrayRemove
                foreach (string s in srd.InstallPlugins)
                {
                    if (!Framework.strArrayContains(InstallPlugins, s))
                    {
                        InstallPlugins.Add(s);
                    }
                }
                // next up is removing all plugins that are set to be ignored:
                foreach (string s in srd.IgnorePlugins)
                {
                    Framework.strArrayRemove(InstallPlugins, s);
                }
                // last is going through the CopyPlugins list
                // in case you ask why there is a CopyPlugins list and what is does:
                // (it makes more sense with data files but whatever)
                // if the omod has eg this folder structure:
                //
                // installfiles/
                //              Option1/
                //                      Meshes/
                //                      Textures/
                //              Option2/
                //                      Meshes/
                //                      Textures/
                // this is nice for writing the installation script as you kan keep track of what option
                // has what files
                // Authors than call CopyPlugins/Data and move the files from the options folder to
                // the root folder:
                //
                // meshes/
                // textures/
                // installfiles/
                //              Option1/
                //                      Meshes/
                //                      Textures/
                //              Option2/
                //                      Meshes/
                //                      Textures/
                foreach (ScriptCopyDataFile scd in srd.CopyPlugins)
                {
                    // check if the file you want to copy actually exists
                    if (!File.Exists(Path.Combine(pluginsPath, scd.CopyFrom)))
                    {
                        return;
                    }
                    else
                    {
                        // check if the mod author didnt make a mistake
                        if (scd.CopyFrom != scd.CopyTo)
                        {
                            // unlikely but you never know
                            if (File.Exists(Path.Combine(pluginsPath, scd.CopyTo)))
                            {
                                File.Delete(Path.Combine(pluginsPath, scd.CopyTo));
                            }
                            File.Copy(Path.Combine(pluginsPath, scd.CopyFrom), Path.Combine(pluginsPath, scd.CopyTo));
                        }
                        // important to add the file to the temp list or else it will not be installed
                        if (!Framework.strArrayContains(InstallPlugins, scd.CopyTo))
                        {
                            InstallPlugins.Add(scd.CopyTo);
                        }
                    }
                }

                // now do the same for the data files :)
                if (srd.InstallAllData)
                {
                    foreach (string s in omod.GetDataFileList())
                    {
                        InstallDataFiles.Add(s);
                    }
                }
                foreach (string s in srd.InstallData)
                {
                    if (!Framework.strArrayContains(InstallDataFiles, s))
                    {
                        InstallDataFiles.Add(s);
                    }
                }
                foreach (string s in srd.IgnoreData)
                {
                    Framework.strArrayRemove(InstallDataFiles, s);
                }
                foreach (ScriptCopyDataFile scd in srd.CopyDataFiles)
                {
                    if (!File.Exists(Path.Combine(dataPath, scd.CopyFrom)))
                    {
                        return;
                    }
                    else
                    {
                        if (scd.CopyFrom != scd.CopyTo)
                        {
                            // because data files can be in subdirectories we have to check if the folder actually exists
                            string dirName = Path.GetDirectoryName(Path.Combine(dataPath, scd.CopyTo));
                            if (!Directory.Exists(dirName))
                            {
                                Directory.CreateDirectory(dirName);
                            }
                            if (File.Exists(Path.Combine(dataPath, scd.CopyTo)))
                            {
                                File.Delete(Path.Combine(dataPath, scd.CopyTo));
                            }
                            File.Copy(Path.Combine(dataPath, scd.CopyFrom), Path.Combine(dataPath, scd.CopyTo));
                        }
                        if (!Framework.strArrayContains(InstallDataFiles, scd.CopyTo))
                        {
                            InstallDataFiles.Add(scd.CopyTo);
                        }
                    }
                }

                // after everything is done some final checks
                for (int i = 0; i < InstallDataFiles.Count; i++)
                {
                    // if the files have \\ at the start than Path.Combine wont work :(
                    if (InstallDataFiles[i].StartsWith("\\"))
                    {
                        InstallDataFiles[i] = InstallDataFiles[i].Substring(1);
                    }
                    string currentFile = Path.Combine(dataPath, InstallDataFiles[i]);
                    // also check if the file we want to install exists and is not in the 5th dimension eating lunch
                    if (!File.Exists(currentFile))
                    {
                        InstallDataFiles.RemoveAt(i--);
                    }
                }

                for (int i = 0; i < InstallPlugins.Count; i++)
                {
                    if (InstallPlugins[i].StartsWith("\\"))
                    {
                        InstallPlugins[i] = InstallPlugins[i].Substring(1);
                    }
                    string currentFile = Path.Combine(pluginsPath, InstallPlugins[i]);
                    if (!File.Exists(currentFile))
                    {
                        InstallPlugins.RemoveAt(i--);
                    }
                }

                // now install
                for (int i = 0; i < InstallDataFiles.Count; i++)
                {
                    // check if the folder exists before copying
                    string s = Path.GetDirectoryName(InstallDataFiles[i]);
                    if (!Directory.Exists(Path.Combine(OutputDir, s)))
                    {
                        Directory.CreateDirectory(Path.Combine(OutputDir, s));
                    }
                    File.Move(Path.Combine(dataPath, InstallDataFiles[i]), Path.Combine(OutputDir, InstallDataFiles[i]));
                }
                for (int i = 0; i < InstallPlugins.Count; i++)
                {
                    File.Move(Path.Combine(pluginsPath, InstallPlugins[i]), Path.Combine(OutputDir, InstallPlugins[i]));
                }
            }
        }
Beispiel #9
0
 internal ScriptFunctions(OMODScriptSettings settings, OMOD omod, ScriptReturnData srd)
 {
     _settings = settings;
     _omod     = omod;
     _srd      = srd;
 }
        internal static ScriptReturnData Execute(string inputScript, string dataPath, string pluginsPath, ref SharedFunctionsHandler handler)
        {
            Handler = handler;
            Srd     = new ScriptReturnData();
            if (string.IsNullOrWhiteSpace(inputScript))
            {
                return(Srd);
            }

            DataFiles = dataPath;
            Plugins   = pluginsPath;
            Variables = new Dictionary <string, string>();

            var flowControl = new Stack <FlowControlStruct>();

            Variables["NewLine"] = Environment.NewLine;
            Variables["Tab"]     = "\t";

            var    script          = inputScript.Replace("\r", "").Split('\n');
            string skipTo          = null;
            bool   allowRunOnLines = false;
            bool   Break           = false;

            for (var i = 0; i < script.Length || ExtraLines.Count > 0; i++)
            {
                string s;
                if (ExtraLines.Count > 0)
                {
                    i--;
                    s = ExtraLines.Dequeue().Replace('\t', ' ').Trim();
                }
                else
                {
                    s = script[i].Replace('\t', ' ').Trim();
                }

                CLine = i.ToString();
                if (allowRunOnLines)
                {
                    while (s.EndsWith("\\"))
                    {
                        s = s.Remove(s.Length - 1);
                        if (ExtraLines.Count > 0)
                        {
                            s += ExtraLines.Dequeue().Replace('\t', ' ').Trim();
                        }
                        else
                        {
                            if (++i == script.Length)
                            {
                                Warn("Run-on line passed end of script");
                            }
                            else
                            {
                                s += script[i].Replace('\t', ' ').Trim();
                            }
                        }
                    }
                }

                if (skipTo != null)
                {
                    if (s == skipTo)
                    {
                        skipTo = null;
                    }
                    else
                    {
                        continue;
                    }
                }

                IReadOnlyCollection <string> line = SplitLine(s);
                if (line.Count == 0)
                {
                    continue;
                }

                if (flowControl.Count != 0 && !flowControl.Peek().Active)
                {
                    switch (line.ElementAt(0))
                    {
                    case "":
                        Warn("Empty function");
                        break;

                    case "If":
                    case "IfNot":
                        flowControl.Push(new FlowControlStruct(0));
                        break;

                    case "Else":
                        if (flowControl.Count != 0 && flowControl.Peek().Type == 0)
                        {
                            flowControl.Peek().Active = flowControl.Peek().Line != -1;
                        }
                        else
                        {
                            Warn("Unexpected Else");
                        }
                        break;

                    case "EndIf":
                        if (flowControl.Count != 0 && flowControl.Peek().Type == 0)
                        {
                            flowControl.Pop();
                        }
                        else
                        {
                            Warn("Unexpected EndIf");
                        }
                        break;

                    case "Select":
                    case "SelectMany":
                    case "SelectWithPreview":
                    case "SelectManyWithPreview":
                    case "SelectWithDescriptions":
                    case "SelectManyWithDescriptions":
                    case "SelectWithDescriptionsAndPreviews":
                    case "SelectManyWithDescriptionsAndPreviews":
                    case "SelectVar":
                    case "SelectString":
                        flowControl.Push(new FlowControlStruct(1));
                        break;

                    case "Case":
                        if (flowControl.Count != 0 && flowControl.Peek().Type == 1)
                        {
                            if (flowControl.Peek().Line != -1 && Array.IndexOf(flowControl.Peek().Values, s) != -1)
                            {
                                flowControl.Peek().Active  = true;
                                flowControl.Peek().HitCase = true;
                            }
                        }
                        else
                        {
                            Warn("Unexpected Break");
                        }

                        break;

                    case "Default":
                        if (flowControl.Count != 0 && flowControl.Peek().Type == 1)
                        {
                            if (flowControl.Peek().Line != -1 && !flowControl.Peek().HitCase)
                            {
                                flowControl.Peek().Active = true;
                            }
                        }
                        else
                        {
                            Warn("Unexpected Default");
                        }

                        break;

                    case "EndSelect":
                        if (flowControl.Count != 0 && flowControl.Peek().Type == 1)
                        {
                            flowControl.Pop();
                        }
                        else
                        {
                            Warn("Unexpected EndSelect");
                        }
                        break;

                    case "For":
                        flowControl.Push(new FlowControlStruct(2));
                        break;

                    case "EndFor":
                        if (flowControl.Count != 0 && flowControl.Peek().Type == 2)
                        {
                            flowControl.Pop();
                        }
                        else
                        {
                            Warn("Unexpected EndFor");
                        }
                        break;

                    case "Break":
                    case "Continue":
                    case "Exit":
                        break;
                    }
                }
                else
                {
                    var lineMsg = "";
                    line.Do(cur => lineMsg += "'" + cur + "' ");

                    var registry = new SharedFunctionsRegistry(Handler);
                    var function = registry.GetFunctionByName(line.ElementAt(0));
                    if (function != null)
                    {
                        if (line.Count < function.MinArgs)
                        {
                            Warn($"Missing arguments for '{function.FuncName}'");
                            break;
                        }

                        if (function.MaxArgs != 0 && line.Count > function.MaxArgs)
                        {
                            Warn($"Unexpected arguments for '{function.FuncName}'");
                        }

                        Utils.Script($"\"{function.FuncName}\" called with line: {lineMsg}");
                        function.Run(ref line);
                    }
                    else
                    {
                        Utils.Script($"\"{line.ElementAt(0)}\" called with line: {lineMsg}");
                    }
                    switch (line.ElementAt(0))
                    {
                    case "Goto":
                        if (line.Count < 2)
                        {
                            Warn("Not enough arguments to function 'Goto'!");
                        }
                        else
                        {
                            if (line.Count > 2)
                            {
                                Warn("Unexpected extra arguments to function 'Goto'");
                            }
                            skipTo = $"Label {line.ElementAt(1)}";
                            flowControl.Clear();
                        }
                        break;

                    case "Label":
                        break;

                    case "If":
                        flowControl.Push(new FlowControlStruct(i, FunctionIf(line)));
                        break;

                    case "IfNot":
                        flowControl.Push(new FlowControlStruct(i, !FunctionIf(line)));
                        break;

                    case "Else":
                        if (flowControl.Count != 0 && flowControl.Peek().Type == 0)
                        {
                            flowControl.Peek().Active = false;
                        }
                        else
                        {
                            Warn("Unexpected Else");
                        }
                        break;

                    case "EndIf":
                        if (flowControl.Count != 0 && flowControl.Peek().Type == 0)
                        {
                            flowControl.Pop();
                        }
                        else
                        {
                            Warn("Unexpected EndIf");
                        }
                        break;

                    case "Select":
                        flowControl.Push(new FlowControlStruct(i, FunctionSelect(line, false, false, false)));
                        break;

                    case "SelectMany":
                        flowControl.Push(new FlowControlStruct(i, FunctionSelect(line, true, false, false)));
                        break;

                    case "SelectWithPreview":
                        flowControl.Push(new FlowControlStruct(i, FunctionSelect(line, false, true, false)));
                        break;

                    case "SelectManyWithPreview":
                        flowControl.Push(new FlowControlStruct(i, FunctionSelect(line, true, true, false)));
                        break;

                    case "SelectWithDescriptions":
                        flowControl.Push(new FlowControlStruct(i, FunctionSelect(line, false, false, true)));
                        break;

                    case "SelectManyWithDescriptions":
                        flowControl.Push(new FlowControlStruct(i, FunctionSelect(line, true, false, true)));
                        break;

                    case "SelectWithDescriptionsAndPreviews":
                        flowControl.Push(new FlowControlStruct(i, FunctionSelect(line, false, true, true)));
                        break;

                    case "SelectManyWithDescriptionsAndPreviews":
                        flowControl.Push(new FlowControlStruct(i, FunctionSelect(line, true, true, true)));
                        break;

                    case "SelectVar":
                        flowControl.Push(new FlowControlStruct(i, FunctionSelectVar(line, true)));
                        break;

                    case "SelectString":
                        flowControl.Push(new FlowControlStruct(i, FunctionSelectVar(line, false)));
                        break;

                    case "Break": {
                        bool found = false;
                        var  fcs   = flowControl.ToArray();
                        for (int k = 0; k < fcs.Length; k++)
                        {
                            if (fcs[k].Type != 1)
                            {
                                continue;
                            }

                            for (int j = 0; j <= k; j++)
                            {
                                fcs[j].Active = false;
                            }
                            found = true;
                            break;
                        }

                        if (!found)
                        {
                            Warn("Unexpected Break");
                        }
                        break;
                    }

                    case "Case":
                        if (flowControl.Count == 0 || flowControl.Peek().Type != 1)
                        {
                            Warn("Unexpected Case");
                        }
                        break;

                    case "Default":
                        if (flowControl.Count == 0 || flowControl.Peek().Type != 1)
                        {
                            Warn("Unexpected Default");
                        }
                        break;

                    case "EndSelect":
                        if (flowControl.Count != 0 && flowControl.Peek().Type == 1)
                        {
                            flowControl.Pop();
                        }
                        else
                        {
                            Warn("Unexpected EndSelect");
                        }
                        break;

                    case "For": {
                        var fc = FunctionFor(line, i);
                        flowControl.Push(fc);
                        if (fc.Line != -1 && fc.Values.Length > 0)
                        {
                            Variables[fc.Var] = fc.Values[0];
                            fc.Active         = true;
                        }

                        break;
                    }

                    case "Continue": {
                        var found = false;
                        var fcs   = flowControl.ToArray();
                        for (int k = 0; k < fcs.Length; k++)
                        {
                            if (fcs[k].Type != 2)
                            {
                                continue;
                            }

                            fcs[k].ForCount++;
                            if (fcs[k].ForCount == fcs[k].Values.Length)
                            {
                                for (int j = 0; j <= k; j++)
                                {
                                    fcs[j].Active = false;
                                }
                            }
                            else
                            {
                                i = fcs[k].Line;
                                Variables[fcs[k].Var] = fcs[k].Values[fcs[k].ForCount];
                                for (int j = 0; j < k; j++)
                                {
                                    flowControl.Pop();
                                }
                            }

                            found = true;
                            break;
                        }

                        if (!found)
                        {
                            Warn("Unexpected Continue");
                        }
                        break;
                    }

                    case "Exit": {
                        bool found = false;
                        var  fcs   = flowControl.ToArray();
                        for (int k = 0; k < fcs.Length; k++)
                        {
                            if (fcs[k].Type != 2)
                            {
                                continue;
                            }

                            for (int j = 0; j <= k; j++)
                            {
                                flowControl.Peek().Active = false;
                            }
                            found = true;
                            break;
                        }

                        if (!found)
                        {
                            Warn("Unexpected Exit");
                        }
                        break;
                    }

                    case "EndFor":
                        if (flowControl.Count != 0 && flowControl.Peek().Type == 2)
                        {
                            var fc = flowControl.Peek();
                            fc.ForCount++;
                            if (fc.ForCount == fc.Values.Length)
                            {
                                flowControl.Pop();
                            }
                            else
                            {
                                i = fc.Line;
                                Variables[fc.Var] = fc.Values[fc.ForCount];
                            }
                        }
                        else
                        {
                            Warn("Unexpected EndFor");
                        }
                        break;

                    //Functions
                    case "DontInstallAnyPlugins":
                        Srd.InstallAllPlugins = false;
                        break;

                    case "DontInstallAnyDataFiles":
                        Srd.InstallAllData = false;
                        break;

                    case "InstallAllPlugins":
                        Srd.InstallAllPlugins = true;
                        break;

                    case "InstallAllDataFiles":
                        Srd.InstallAllData = true;
                        break;

                    case "FatalError":
                        Utils.Error("Script called FatalError!");
                        Srd.CancelInstall = true;
                        break;

                    case "Return":
                        Break = true;
                        break;

                    case "AllowRunOnLines":
                        allowRunOnLines = true;
                        break;

                    default:
                        break;
                    }
                }

                if (Break || Srd.CancelInstall)
                {
                    break;
                }
            }

            if (skipTo != null)
            {
                Warn($"Expected: {skipTo}!");
            }

            var temp = Srd;

            Srd       = null;
            Variables = null;

            return(temp);
        }