using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Core.Logging.Interpolation; using BepInEx.Logging; using BepInEx.Unity.IL2CPP; using BetterTerminal.Scripts.Language; using BetterTerminal.Scripts.Runtime; using HarmonyLib; using LevelGeneration; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("STFO")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+09dcc6a36661551cc3e378f1ce513b747a2397d4")] [assembly: AssemblyProduct("STFO")] [assembly: AssemblyTitle("STFO")] [assembly: AssemblyVersion("1.0.0.0")] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace BetterTerminal { [BepInPlugin("STFO", "STFO", "1.0.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class StfoPlugin : BasePlugin { internal static ConfigFile Settings { get; private set; } internal static ManualLogSource ModLog { get; private set; } internal static ConfigEntry EnableScripts { get; private set; } internal static ConfigEntry AllowScriptFileWrites { get; private set; } internal static ConfigEntry ScriptMaximumInstructions { get; private set; } internal static ConfigEntry ScriptMaximumMemoryKB { get; private set; } internal static ConfigEntry ScriptMaximumExecutionSeconds { get; private set; } internal static ConfigEntry ScriptMaximumCallDepth { get; private set; } internal static ConfigEntry ScriptMaximumImportDepth { get; private set; } internal static ConfigEntry ScriptMaximumSourceKB { get; private set; } internal static ConfigEntry ScriptMaximumCollectionSize { get; private set; } internal static ConfigEntry ScriptMaximumStringLength { get; private set; } internal static ConfigEntry MaximumInputLength { get; private set; } internal static ConfigEntry MaximumListedScripts { get; private set; } internal static ConfigEntry UppercaseInput { get; private set; } internal static ConfigEntry ShowExecutionStatistics { get; private set; } internal static ConfigEntry PromptPrefix { get; private set; } internal static ConfigEntry OptionMarker { get; private set; } public override void Load() { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown //IL_007a: Unknown result type (might be due to invalid IL or missing references) ModLog = ((BasePlugin)this).Log; Settings = ((BasePlugin)this).Config; BindConfiguration(); ScriptWorkspace.Initialize(); ModCommands.Register("SCRIPTS", "commands.stfo_scripts"); ModCommands.Register("STFO", "commands.stfo_check"); ModCommands.Register("RUN", "commands.stfo_run"); PipelineExtensionRegistry.Register("STFO", new PipelineExtensionHandler(StfoPipelineBridge.ExecuteExtension)); TerminalInputReservationRegistry.Register((Func)StfoSessionManager.IsActive); new Harmony("STFO").PatchAll(typeof(StfoPlugin).Assembly); ((BasePlugin)this).Log.LogInfo((object)"STFO loaded"); } private void BindConfiguration() { //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Expected O, but got Unknown //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Expected O, but got Unknown EnableScripts = ((BasePlugin)this).Config.Bind("Scripts", "Enabled", true, "Enables STFO programs and pipeline extensions."); AllowScriptFileWrites = ((BasePlugin)this).Config.Bind("Scripts", "AllowFileWrites", false, "Allows WRITE operations only inside the STFO workspace."); ScriptMaximumInstructions = BindLimit("MaximumInstructions", 100000, 1000, 10000000); ScriptMaximumMemoryKB = BindLimit("MaximumMemoryKB", 4096, 256, 65536); ScriptMaximumExecutionSeconds = BindLimit("MaximumExecutionSeconds", 10, 1, 300); ScriptMaximumCallDepth = BindLimit("MaximumCallDepth", 64, 4, 1024); ScriptMaximumImportDepth = BindLimit("MaximumImportDepth", 16, 1, 128); ScriptMaximumSourceKB = BindLimit("MaximumSourceKB", 256, 8, 4096); ScriptMaximumCollectionSize = BindLimit("MaximumCollectionSize", 10000, 10, 1000000); ScriptMaximumStringLength = BindLimit("MaximumStringLength", 65536, 256, 1048576); MaximumInputLength = ((BasePlugin)this).Config.Bind("Interface", "MaximumInputLength", 1024, new ConfigDescription("Maximum characters accepted by an interactive input request.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 65536), Array.Empty())); MaximumListedScripts = ((BasePlugin)this).Config.Bind("Interface", "MaximumListedScripts", 100, new ConfigDescription("Maximum scripts displayed by SCRIPTS.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 1000), Array.Empty())); UppercaseInput = ((BasePlugin)this).Config.Bind("Interface", "UppercaseInput", false, "Converts interactive input to uppercase. Disabled preserves user text."); ShowExecutionStatistics = ((BasePlugin)this).Config.Bind("Interface", "ShowExecutionStatistics", true, "Shows instruction and memory usage when execution finishes."); PromptPrefix = ((BasePlugin)this).Config.Bind("Interface", "PromptPrefix", "STFO>", "Prefix displayed for interactive input."); OptionMarker = ((BasePlugin)this).Config.Bind("Interface", "OptionMarker", "->", "Marker displayed beside the selected option."); } private ConfigEntry BindLimit(string key, int value, int minimum, int maximum) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown return ((BasePlugin)this).Config.Bind("Limits", key, value, new ConfigDescription("STFO safety limit: " + key + ".", (AcceptableValueBase)(object)new AcceptableValueRange(minimum, maximum), Array.Empty())); } } internal static class ScriptWorkspace { private sealed class WorkspaceAdapter : IStfoWorkspace { string IStfoWorkspace.RootDirectory => RootDirectory; bool IStfoWorkspace.TryResolveScript(string scriptName, out string scriptPath, out string error, string? relativeToDirectory) { return TryResolveScript(scriptName, out scriptPath, out error, relativeToDirectory); } bool IStfoWorkspace.TryResolveFile(string requestedPath, out string filePath, out string error, string? relativeToDirectory) { return TryResolveFile(requestedPath, out filePath, out error, relativeToDirectory); } } internal const string LanguageName = "STFO"; internal const string Extension = ".stfo"; internal static string RootDirectory { get; private set; } = string.Empty; internal static IStfoWorkspace Service { get; } = (IStfoWorkspace)(object)new WorkspaceAdapter(); internal static void Initialize() { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Expected O, but got Unknown //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown RootDirectory = Path.GetFullPath(Path.Combine(Paths.ConfigPath, "STFO", "Scripts")); bool flag = default(bool); try { Directory.CreateDirectory(RootDirectory); ManualLogSource modLog = StfoPlugin.ModLog; BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(33, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[WORKSPACE] READY PATH='"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(RootDirectory); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' EXISTS="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(Directory.Exists(RootDirectory)); } modLog.LogInfo(val); } catch (Exception ex) { ManualLogSource modLog2 = StfoPlugin.ModLog; BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(33, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[WORKSPACE] COULD NOT CREATE '"); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted(RootDirectory); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("': "); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted(ex); } modLog2.LogError(val2); } } internal static IReadOnlyList ListScripts(string? filter = null) { //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Expected O, but got Unknown if (!Directory.Exists(RootDirectory)) { return Array.Empty(); } try { return (from path in Directory.EnumerateFiles(RootDirectory, "*.stfo", SearchOption.AllDirectories) select Path.GetRelativePath(RootDirectory, path) into path select Path.ChangeExtension(path, null) into name where !string.IsNullOrWhiteSpace(name) select name.Replace(Path.DirectorySeparatorChar, '/') into name where string.IsNullOrWhiteSpace(filter) || name.Contains(filter, StringComparison.OrdinalIgnoreCase) select name).OrderBy((string name) => name, StringComparer.OrdinalIgnoreCase).ToArray(); } catch (Exception ex) { ManualLogSource modLog = StfoPlugin.ModLog; bool flag = default(bool); BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(36, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[WORKSPACE] COULD NOT LIST SCRIPTS: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(ex.Message); } modLog.LogWarning(val); return Array.Empty(); } } internal static bool TryResolveScript(string scriptName, out string scriptPath, out string error, string? relativeToDirectory = null) { string text = scriptName.Trim(); if (!text.EndsWith(".stfo", StringComparison.OrdinalIgnoreCase)) { text += ".stfo"; } return TryResolveFile(text, out scriptPath, out error, relativeToDirectory); } internal static bool TryResolveFile(string requestedPath, out string filePath, out string error, string? relativeToDirectory = null) { filePath = string.Empty; error = string.Empty; if (string.IsNullOrWhiteSpace(requestedPath) || requestedPath.IndexOfAny(Path.GetInvalidPathChars()) >= 0) { error = "INVALID FILE PATH."; return false; } string text = (string.IsNullOrWhiteSpace(relativeToDirectory) ? RootDirectory : Path.GetFullPath(relativeToDirectory)); if (!IsInsideRoot(text, allowRoot: true)) { error = "BASE DIRECTORY OUTSIDE SCRIPT WORKSPACE."; return false; } string fullPath = Path.GetFullPath(Path.Combine(text, requestedPath)); if (!IsInsideRoot(fullPath, allowRoot: false)) { error = "FILE PATH OUTSIDE SCRIPT WORKSPACE."; return false; } if (ContainsReparsePoint(fullPath)) { error = "SYMLINKS AND JUNCTIONS ARE NOT ALLOWED IN SCRIPT PATHS."; return false; } filePath = fullPath; return true; } private static bool IsInsideRoot(string path, bool allowRoot) { string text = RootDirectory.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); string text2 = Path.GetFullPath(path).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); if (allowRoot && string.Equals(text2, text, StringComparison.OrdinalIgnoreCase)) { return true; } return text2.StartsWith(text + Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase); } private static bool ContainsReparsePoint(string path) { string relativePath = Path.GetRelativePath(RootDirectory, path); string text = RootDirectory; string[] array = relativePath.Split(new char[2] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries); foreach (string path2 in array) { text = Path.Combine(text, path2); if ((Directory.Exists(text) || File.Exists(text)) && (File.GetAttributes(text) & FileAttributes.ReparsePoint) != FileAttributes.None) { return true; } } return false; } } internal static class StfoIntegration { internal static StfoPolicy CreatePolicy() { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown return new StfoPolicy(StfoPlugin.ScriptMaximumInstructions.Value, StfoPlugin.ScriptMaximumMemoryKB.Value, StfoPlugin.ScriptMaximumExecutionSeconds.Value, StfoPlugin.ScriptMaximumCallDepth.Value, StfoPlugin.ScriptMaximumImportDepth.Value, StfoPlugin.ScriptMaximumSourceKB.Value, StfoPlugin.ScriptMaximumCollectionSize.Value, StfoPlugin.ScriptMaximumStringLength.Value); } internal static StfoAnalyzer CreateAnalyzer(StfoPolicy policy) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown return new StfoAnalyzer(policy, ScriptWorkspace.Service); } internal static StfoVirtualMachine CreateVirtualMachine(StfoPolicy policy, IEnumerable? inputs = null) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown return new StfoVirtualMachine(policy, ScriptWorkspace.Service, StfoPlugin.AllowScriptFileWrites.Value, inputs); } } internal enum ScriptCommand { Scripts, Stfo, Run } internal enum StfoCommand { Check, Config } internal enum StfoSetting { Enabled, Writes, Stats, UppercaseInput, InputLimit, ListLimit, Prompt, Marker } [HarmonyPatch(typeof(LG_ComputerTerminalCommandInterpreter), "EvaluateInput")] internal static class ScriptCommandPatch { private static bool Prefix(LG_ComputerTerminalCommandInterpreter __instance, string inputString) { string text = inputString.Trim(); string text2 = text.ToUpperInvariant(); string[] array = text.Split(' ', StringSplitOptions.RemoveEmptyEntries); if (array.Length == 0 || !Enum.TryParse(array[0], ignoreCase: true, out var result)) { return true; } if (!StfoPlugin.EnableScripts.Value) { TerminalCommandOutput.WriteImmediate(__instance, text2, (IEnumerable)new string[1] { LocalizationService.Text("stfo.disabled", Array.Empty()) }); return false; } switch (result) { case ScriptCommand.Stfo: return HandleStfo(__instance, text2, array); case ScriptCommand.Run: return HandleRun(__instance, text2, array); default: { if (array.Length > 2) { return true; } IReadOnlyList readOnlyList = ScriptWorkspace.ListScripts((array.Length == 2) ? array[1] : null); int num = Math.Min(readOnlyList.Count, StfoPlugin.MaximumListedScripts.Value); List list = new List(); list.Add(LocalizationService.Text("stfo.directory", new object[1] { ScriptWorkspace.RootDirectory })); list.Add($"COUNT: {readOnlyList.Count}"); List list2 = list; list2.AddRange(from name in readOnlyList.Take(num) select name.ToUpperInvariant()); if (num < readOnlyList.Count) { list2.Add($"... {readOnlyList.Count - num} MORE. USE SCRIPTS FILTER."); } TerminalCommandOutput.WriteImmediate(__instance, text2, (IEnumerable)list2); return false; } } } private static bool HandleStfo(LG_ComputerTerminalCommandInterpreter interpreter, string commandLine, string[] arguments) { if (arguments.Length >= 2 && Enum.TryParse(arguments[1], ignoreCase: true, out var result) && result == StfoCommand.Config) { HandleConfig(interpreter, commandLine, arguments); return false; } if (arguments.Length != 3 || !Enum.TryParse(arguments[1], ignoreCase: true, out var result2) || result2 != StfoCommand.Check) { TerminalCommandOutput.WriteImmediate(interpreter, commandLine, (IEnumerable)new string[1] { LocalizationService.Text("stfo.use_check", Array.Empty()) }); return false; } if (!ScriptWorkspace.TryResolveScript(arguments[2], out string scriptPath, out string error)) { TerminalCommandOutput.WriteImmediate(interpreter, commandLine, (IEnumerable)new string[1] { LocalizationService.Text("stfo.error", new object[1] { error }) }); return false; } StfoAnalysisResult val = StfoIntegration.CreateAnalyzer(StfoIntegration.CreatePolicy()).Analyze(scriptPath); List list = new List { "STFO CHECK: " + arguments[2].ToUpperInvariant(), $"FILES: {val.Files.Count}", $"DIAGNOSTICS: {val.Diagnostics.Count}" }; if (val.Diagnostics.Count == 0) { list.Add(LocalizationService.Text("stfo.no_problems", Array.Empty())); } else { list.AddRange(val.Diagnostics.Select((StfoDiagnostic item) => item.Format())); } TerminalCommandOutput.WriteImmediate(interpreter, commandLine, (IEnumerable)list); return false; } private static bool HandleRun(LG_ComputerTerminalCommandInterpreter interpreter, string commandLine, string[] arguments) { //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) if (arguments.Length != 2) { TerminalCommandOutput.WriteImmediate(interpreter, commandLine, (IEnumerable)new string[1] { LocalizationService.Text("stfo.use_run", Array.Empty()) }); return false; } if (!ScriptWorkspace.TryResolveScript(arguments[1], out string scriptPath, out string error)) { TerminalCommandOutput.WriteImmediate(interpreter, commandLine, (IEnumerable)new string[1] { LocalizationService.Text("stfo.error", new object[1] { error }) }); return false; } StfoPolicy policy = StfoIntegration.CreatePolicy(); StfoAnalysisResult val = StfoIntegration.CreateAnalyzer(policy).Analyze(scriptPath); if (val.HasErrors) { TerminalCommandOutput.WriteImmediate(interpreter, commandLine, val.Diagnostics.Select((StfoDiagnostic item) => item.Format())); return false; } StfoExecutionResult val2 = StfoIntegration.CreateVirtualMachine(policy).Execute(scriptPath, (StfoEntryPointKind)0, (StfoValue?)null); List list = new List(val2.PrintedLines); if (val2.InputRequest != null) { TerminalCommandOutput.WriteImmediate(interpreter, commandLine, (IEnumerable)list); StfoSessionManager.Start(interpreter, scriptPath, policy, val2, commandLine); StfoSessionManager.RenderCurrent(interpreter); return false; } StfoValue output = val2.Output; if ((int)((StfoValue)(ref output)).Type != 0) { list.Add(LocalizationService.Text("stfo.output", new object[1] { val2.Output })); } list.AddRange(val2.Diagnostics.Select((StfoDiagnostic item) => item.Format())); if (StfoPlugin.ShowExecutionStatistics.Value) { list.Add(LocalizationService.Text("stfo.finished", new object[2] { val2.Instructions, val2.EstimatedMemoryBytes })); } TerminalCommandOutput.WriteImmediate(interpreter, commandLine, (IEnumerable)list); return false; } private static void HandleConfig(LG_ComputerTerminalCommandInterpreter interpreter, string commandLine, string[] arguments) { if (arguments.Length == 2) { WriteConfig(interpreter, commandLine, CurrentConfiguration()); return; } if (arguments.Length == 3 && arguments[2].Equals("RELOAD", StringComparison.OrdinalIgnoreCase)) { StfoPlugin.Settings.Reload(); WriteConfig(interpreter, commandLine, CurrentConfiguration()); return; } if (arguments.Length != 4 || !Enum.TryParse(arguments[2], ignoreCase: true, out var result)) { WriteConfig(interpreter, commandLine, ConfigHelp()); return; } string value = arguments[3]; WriteConfig(interpreter, commandLine, result switch { StfoSetting.Enabled => SetBoolean(StfoPlugin.EnableScripts, value, result), StfoSetting.Writes => SetBoolean(StfoPlugin.AllowScriptFileWrites, value, result), StfoSetting.Stats => SetBoolean(StfoPlugin.ShowExecutionStatistics, value, result), StfoSetting.UppercaseInput => SetBoolean(StfoPlugin.UppercaseInput, value, result), StfoSetting.InputLimit => SetInteger(StfoPlugin.MaximumInputLength, value, result, 1, 65536), StfoSetting.ListLimit => SetInteger(StfoPlugin.MaximumListedScripts, value, result, 1, 1000), StfoSetting.Prompt => SetText(StfoPlugin.PromptPrefix, value, result), StfoSetting.Marker => SetText(StfoPlugin.OptionMarker, value, result), _ => ConfigHelp(), }); } private static string CurrentConfiguration() { return string.Join("\n", "STFO CONFIGURATION", "ENABLED: " + StfoPlugin.EnableScripts.Value.ToString().ToUpperInvariant(), "WRITES: " + StfoPlugin.AllowScriptFileWrites.Value.ToString().ToUpperInvariant(), "STATS: " + StfoPlugin.ShowExecutionStatistics.Value.ToString().ToUpperInvariant(), "UPPERCASE INPUT: " + StfoPlugin.UppercaseInput.Value.ToString().ToUpperInvariant(), $"INPUT LIMIT: {StfoPlugin.MaximumInputLength.Value}", $"LIST LIMIT: {StfoPlugin.MaximumListedScripts.Value}", "PROMPT: " + StfoPlugin.PromptPrefix.Value, "MARKER: " + StfoPlugin.OptionMarker.Value, "WORKSPACE: " + ScriptWorkspace.RootDirectory); } private static string ConfigHelp() { return string.Join("\n", "STFO CONFIG", "STFO CONFIG RELOAD", "STFO CONFIG ENABLED ON|OFF", "STFO CONFIG WRITES ON|OFF", "STFO CONFIG STATS ON|OFF", "STFO CONFIG UPPERCASEINPUT ON|OFF", "STFO CONFIG INPUTLIMIT 1-65536", "STFO CONFIG LISTLIMIT 1-1000", "STFO CONFIG PROMPT TEXT", "STFO CONFIG MARKER TEXT"); } private static string SetBoolean(ConfigEntry entry, string value, StfoSetting setting) { if (!value.Equals("ON", StringComparison.OrdinalIgnoreCase) && !value.Equals("OFF", StringComparison.OrdinalIgnoreCase)) { return "INVALID " + setting.ToString().ToUpperInvariant() + ". USE ON OR OFF."; } entry.Value = value.Equals("ON", StringComparison.OrdinalIgnoreCase); return setting.ToString().ToUpperInvariant() + ": " + (entry.Value ? "ON" : "OFF"); } private static string SetInteger(ConfigEntry entry, string value, StfoSetting setting, int minimum, int maximum) { if (int.TryParse(value, out var result) && result >= minimum && result <= maximum) { entry.Value = result; return $"{setting.ToString().ToUpperInvariant()}: {result}"; } return $"INVALID {setting.ToString().ToUpperInvariant()}. USE {minimum}-{maximum}."; } private static string SetText(ConfigEntry entry, string value, StfoSetting setting) { string text = new string(value.Where((char character) => !char.IsControl(character)).Take(16).ToArray()); if (text.Length == 0) { return "INVALID " + setting.ToString().ToUpperInvariant() + "."; } entry.Value = text; return setting.ToString().ToUpperInvariant() + ": " + text; } private static void WriteConfig(LG_ComputerTerminalCommandInterpreter interpreter, string commandLine, string response) { TerminalCommandOutput.WriteImmediate(interpreter, commandLine, (IEnumerable)response.Split('\n')); } } } namespace BetterTerminal.Scripts.Runtime { internal sealed class StfoSession { internal string ScriptPath { get; init; } = string.Empty; internal StfoPolicy Policy { get; init; } internal List Inputs { get; } = new List(); internal int PrintedLineCount { get; set; } internal StfoInputRequest Request { get; set; } internal int SelectedOption { get; set; } internal List RenderedOptionLines { get; } = new List(); internal string TextBuffer { get; set; } = string.Empty; internal bool WaitingForFreshInput { get; set; } = true; internal string ActivationCommand { get; init; } = string.Empty; internal bool ActivationCommandDiscarded { get; set; } internal bool InputLimitReached { get; set; } } internal static class StfoSessionManager { private static readonly Dictionary Sessions = new Dictionary(); internal static void Start(LG_ComputerTerminalCommandInterpreter interpreter, string scriptPath, StfoPolicy policy, StfoExecutionResult result, string activationCommand) { if (result.InputRequest != null && interpreter.m_terminal != null) { Sessions[interpreter.m_terminal.SyncID] = new StfoSession { ScriptPath = scriptPath, Policy = policy, PrintedLineCount = result.PrintedLines.Count, Request = result.InputRequest, ActivationCommand = activationCommand.Trim().ToUpperInvariant() }; AutoCompletePatch.ClearSelection(); PrepareInputLine(interpreter); } } internal static bool TryHandleInput(LG_ComputerTerminalCommandInterpreter interpreter, string input) { //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Invalid comparison between Unknown and I4 //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Expected O, but got Unknown //IL_0282: Unknown result type (might be due to invalid IL or missing references) //IL_0287: Unknown result type (might be due to invalid IL or missing references) //IL_028b: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Expected O, but got Unknown //IL_02a3: Unknown result type (might be due to invalid IL or missing references) if (interpreter.m_terminal == null || !Sessions.TryGetValue(interpreter.m_terminal.SyncID, out StfoSession value)) { return false; } string text = input.Trim().ToUpperInvariant(); bool flag = default(bool); if (!value.ActivationCommandDiscarded && text.Equals(value.ActivationCommand, StringComparison.OrdinalIgnoreCase)) { value.ActivationCommandDiscarded = true; interpreter.m_terminal.m_currentLine = string.Empty; ManualLogSource modLog = StfoPlugin.ModLog; BepInExDebugLogInterpolatedStringHandler val = new BepInExDebugLogInterpolatedStringHandler(52, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[INPUT] DISCARDED EVALUATEINPUT ACTIVATION REPLAY '"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(text); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("'"); } modLog.LogDebug(val); PrepareInputLine(interpreter); return true; } if (!TryNormalizeInput(value.Request.Kind, input, out string normalized, out string error)) { TerminalCommandOutput.WriteTransient(interpreter, (IEnumerable)new string[2] { "STFO INPUT ERROR: " + error, "> " + value.Request.Prompt }); PrepareInputLine(interpreter); return true; } if ((int)value.Request.Kind == 3) { normalized = (value.Request.Options ?? Array.Empty())[value.SelectedOption]; value.RenderedOptionLines.Clear(); interpreter.m_screenBuffer.Add(LocalizationService.Text("stfo.selected", new object[1] { normalized.ToUpperInvariant() })); interpreter.m_screenBuffer.Add(string.Empty); ManualLogSource modLog2 = StfoPlugin.ModLog; BepInExDebugLogInterpolatedStringHandler val = new BepInExDebugLogInterpolatedStringHandler(39, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[INPUT] OPTION ACCEPTED INDEX="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(value.SelectedOption); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" VALUE='"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(normalized); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("'"); } modLog2.LogDebug(val); } value.ActivationCommandDiscarded = true; value.Inputs.Add(normalized); StfoExecutionResult val2 = StfoIntegration.CreateVirtualMachine(value.Policy, value.Inputs).Execute(value.ScriptPath, (StfoEntryPointKind)0, (StfoValue?)null); List list = val2.PrintedLines.Skip(value.PrintedLineCount).ToList(); value.PrintedLineCount = val2.PrintedLines.Count; if (val2.InputRequest != null) { value.Request = val2.InputRequest; value.SelectedOption = 0; value.TextBuffer = string.Empty; value.InputLimitReached = false; value.WaitingForFreshInput = true; TerminalCommandOutput.WriteTransient(interpreter, (IEnumerable)list); RenderCurrent(interpreter); return true; } Sessions.Remove(interpreter.m_terminal.SyncID); ReleaseInputLine(interpreter); StfoValue output = val2.Output; if ((int)((StfoValue)(ref output)).Type != 0) { list.Add(LocalizationService.Text("stfo.output", new object[1] { val2.Output })); } list.AddRange(val2.Diagnostics.Select((StfoDiagnostic item) => item.Format())); if (StfoPlugin.ShowExecutionStatistics.Value) { list.Add(LocalizationService.Text("stfo.finished", new object[2] { val2.Instructions, val2.EstimatedMemoryBytes })); } TerminalCommandOutput.WriteTransient(interpreter, list.Concat(new string[1] { string.Empty })); return true; } internal static void RenderCurrent(LG_ComputerTerminalCommandInterpreter interpreter) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 if (interpreter.m_terminal == null || !Sessions.TryGetValue(interpreter.m_terminal.SyncID, out StfoSession value)) { return; } if ((int)value.Request.Kind != 3) { TerminalCommandOutput.WriteTransient(interpreter, (IEnumerable)new string[3] { "> " + value.Request.Prompt, LocalizationService.Text("stfo.write_below", Array.Empty()), string.Empty }); PrepareInputLine(interpreter); return; } RemoveOptionLines(interpreter, value); IReadOnlyList readOnlyList = value.Request.Options ?? Array.Empty(); value.RenderedOptionLines.Add(value.Request.Prompt); for (int i = 0; i < readOnlyList.Count; i++) { string value2 = ((i == value.SelectedOption) ? SanitizeInterfaceToken(StfoPlugin.OptionMarker.Value, "->") : " "); value.RenderedOptionLines.Add($"{value2} {i + 1}. {readOnlyList[i]}"); } TerminalCommandOutput.WriteTransient(interpreter, (IEnumerable)value.RenderedOptionLines); PrepareInputLine(interpreter); } internal static bool TryMoveOption(LG_ComputerTerminal terminal, bool previous) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Invalid comparison between Unknown and I4 if (!Sessions.TryGetValue(terminal.SyncID, out StfoSession value) || (int)value.Request.Kind != 3) { return false; } int num = value.Request.Options?.Count ?? 0; if (num == 0) { return false; } value.SelectedOption = (value.SelectedOption + ((!previous) ? 1 : (-1)) + num) % num; RenderCurrent(terminal.m_command); return true; } internal static bool IsActive(uint terminalId) { return Sessions.ContainsKey(terminalId); } internal static bool TryConsumeKeyboardInput(LG_ComputerTerminal terminal) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Invalid comparison between Unknown and I4 //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Expected O, but got Unknown //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Expected O, but got Unknown if (!Sessions.TryGetValue(terminal.SyncID, out StfoSession value) || (int)value.Request.Kind == 3) { return false; } string inputString = Input.inputString; if (value.WaitingForFreshInput) { if (string.IsNullOrEmpty(inputString)) { value.WaitingForFreshInput = false; StfoPlugin.ModLog.LogDebug((object)"[INPUT] FRESH KEYBOARD INPUT ARMED"); } else { ManualLogSource modLog = StfoPlugin.ModLog; bool flag = default(bool); BepInExDebugLogInterpolatedStringHandler val = new BepInExDebugLogInterpolatedStringHandler(42, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[INPUT] DISCARDED ACTIVATION INPUT LENGTH="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(inputString.Length); } modLog.LogDebug(val); } return true; } if (string.IsNullOrEmpty(inputString)) { return false; } string text = inputString; foreach (char c in text) { bool flag; switch (c) { case '\b': if (value.TextBuffer.Length > 0) { StfoSession stfoSession = value; string textBuffer = value.TextBuffer; stfoSession.TextBuffer = textBuffer.Substring(0, textBuffer.Length - 1); } value.InputLimitReached = false; continue; case '\n': case '\r': flag = true; break; default: flag = false; break; } if (flag) { string textBuffer2 = value.TextBuffer; value.TextBuffer = string.Empty; BepInExDebugLogInterpolatedStringHandler val; if (!value.ActivationCommandDiscarded && textBuffer2.Equals(value.ActivationCommand, StringComparison.OrdinalIgnoreCase)) { value.ActivationCommandDiscarded = true; ManualLogSource modLog2 = StfoPlugin.ModLog; val = new BepInExDebugLogInterpolatedStringHandler(48, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[INPUT] DISCARDED REPLAYED ACTIVATION COMMAND '"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(textBuffer2); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("'"); } modLog2.LogDebug(val); UpdateCustomInputLine(terminal.m_command); return true; } value.ActivationCommandDiscarded = true; ManualLogSource modLog3 = StfoPlugin.ModLog; val = new BepInExDebugLogInterpolatedStringHandler(30, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[INPUT] TEXT SUBMITTED LENGTH="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(textBuffer2.Length); } modLog3.LogDebug(val); TryHandleInput(terminal.m_command, textBuffer2); return true; } if (!char.IsControl(c) && value.TextBuffer.Length < StfoPlugin.MaximumInputLength.Value) { value.TextBuffer += (StfoPlugin.UppercaseInput.Value ? char.ToUpperInvariant(c) : c); } else if (!char.IsControl(c)) { value.InputLimitReached = true; } } UpdateCustomInputLine(terminal.m_command); return true; } private static void PrepareInputLine(LG_ComputerTerminalCommandInterpreter interpreter) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown interpreter.ShowInputLine = false; interpreter.ShowCustomLine = true; interpreter.CustomLineBlinkEnabled = true; interpreter.m_inputBufferStep = 0; if (interpreter.m_terminal != null) { interpreter.m_terminal.m_currentLine = string.Empty; } UpdateCustomInputLine(interpreter); ManualLogSource modLog = StfoPlugin.ModLog; bool flag = default(bool); BepInExDebugLogInterpolatedStringHandler val = new BepInExDebugLogInterpolatedStringHandler(51, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[INPUT] READY TERMINAL="); LG_ComputerTerminal terminal = interpreter.m_terminal; ((BepInExLogInterpolatedStringHandler)val).AppendFormatted((terminal != null) ? new uint?(terminal.SyncID) : ((uint?)null)); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" "); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("PRIVATE_BUFFER=True CUSTOM="); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(interpreter.ShowCustomLine); } modLog.LogDebug(val); } internal static void UpdateCustomInputLine(LG_ComputerTerminalCommandInterpreter interpreter) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Invalid comparison between Unknown and I4 if (interpreter.m_terminal != null && Sessions.TryGetValue(interpreter.m_terminal.SyncID, out StfoSession value)) { string text = SanitizeInterfaceToken(StfoPlugin.PromptPrefix.Value, "STFO>"); interpreter.CustomLineText = (((int)value.Request.Kind == 3) ? (text + " [UP/DOWN + ENTER]") : (text + " " + value.TextBuffer + (value.InputLimitReached ? " [MAX]" : string.Empty))); } } private static void ReleaseInputLine(LG_ComputerTerminalCommandInterpreter interpreter) { interpreter.ShowCustomLine = false; interpreter.CustomLineBlinkEnabled = false; interpreter.CustomLineText = string.Empty; interpreter.ShowInputLine = true; interpreter.m_isNewInputLine = true; if (interpreter.m_terminal != null) { interpreter.m_terminal.m_currentLine = string.Empty; } } internal static void Cancel(LG_ComputerTerminal terminal) { if (Sessions.Remove(terminal.SyncID)) { ReleaseInputLine(terminal.m_command); TerminalCommandOutput.WriteTransient(terminal.m_command, (IEnumerable)new string[1] { LocalizationService.Text("stfo.cancelled", Array.Empty()) }); } } private static void RemoveOptionLines(LG_ComputerTerminalCommandInterpreter interpreter, StfoSession session) { for (int num = session.RenderedOptionLines.Count - 1; num >= 0; num--) { int num2 = -1; for (int num3 = interpreter.m_screenBuffer.Count - 1; num3 >= 0; num3--) { if (string.Equals(interpreter.m_screenBuffer[num3], session.RenderedOptionLines[num], StringComparison.Ordinal)) { num2 = num3; break; } } if (num2 >= 0) { interpreter.m_screenBuffer.RemoveAt(num2); } } session.RenderedOptionLines.Clear(); } private static bool TryNormalizeInput(StfoInputKind kind, string input, out string normalized, out string error) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Invalid comparison between Unknown and I4 //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Invalid comparison between Unknown and I4 normalized = input.Trim(); error = string.Empty; if ((int)kind == 0) { return true; } if ((int)kind == 3) { return true; } if ((int)kind == 1) { if (!double.TryParse(normalized, NumberStyles.Float, CultureInfo.InvariantCulture, out var _)) { error = LocalizationService.Text("stfo.expected_number", Array.Empty()); return false; } return true; } if (normalized.Equals("TRUE", StringComparison.OrdinalIgnoreCase) || normalized.Equals("FALSE", StringComparison.OrdinalIgnoreCase) || normalized.Equals("ON", StringComparison.OrdinalIgnoreCase) || normalized.Equals("OFF", StringComparison.OrdinalIgnoreCase) || normalized.Equals("YES", StringComparison.OrdinalIgnoreCase) || normalized.Equals("NO", StringComparison.OrdinalIgnoreCase) || normalized.Equals("SI", StringComparison.OrdinalIgnoreCase)) { return true; } error = LocalizationService.Text("stfo.expected_boolean", Array.Empty()); return false; } private static string SanitizeInterfaceToken(string value, string fallback) { string text = new string(value.Where((char character) => !char.IsControl(character)).Take(16).ToArray()).Trim(); if (text.Length != 0) { return text; } return fallback; } } [HarmonyPatch(typeof(LG_ComputerTerminalCommandInterpreter), "EvaluateInput")] [HarmonyPriority(800)] internal static class StfoPrivateInputPatch { private static bool Prefix(LG_ComputerTerminalCommandInterpreter __instance, string inputString) { return !StfoSessionManager.TryHandleInput(__instance, inputString); } } [HarmonyPatch(typeof(LG_ComputerTerminal), "Update")] [HarmonyPriority(800)] internal static class StfoCancelInputPatch { private static bool Prefix(LG_ComputerTerminal __instance) { if (!StfoSessionManager.IsActive(__instance.SyncID)) { return true; } if (!InputMapper.GetButtonDown.Invoke((InputAction)20, (eFocusState)8)) { if (StfoSessionManager.TryConsumeKeyboardInput(__instance)) { return false; } bool flag = InputMapper.GetButtonDown.Invoke((InputAction)15, (eFocusState)8); bool flag2 = InputMapper.GetButtonDown.Invoke((InputAction)16, (eFocusState)8); if (!flag && !flag2) { return true; } return !StfoSessionManager.TryMoveOption(__instance, flag); } StfoSessionManager.Cancel(__instance); return false; } private static void Postfix(LG_ComputerTerminal __instance) { if (StfoSessionManager.IsActive(__instance.SyncID)) { StfoSessionManager.UpdateCustomInputLine(__instance.m_command); } } } internal sealed record StfoPipelineResult(bool Succeeded, List Items, IReadOnlyList PrintedLines, IReadOnlyList Diagnostics); internal static class StfoPipelineBridge { internal static PipelineExtensionResult ExecuteExtension(string[] arguments, List source) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Expected O, but got Unknown //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Expected O, but got Unknown if (StfoPlugin.EnableScripts.Value) { if (arguments.Length == 2) { StfoPipelineResult stfoPipelineResult = Execute(arguments[1], source); List list = new List(stfoPipelineResult.PrintedLines); list.AddRange(stfoPipelineResult.Diagnostics.Select((StfoDiagnostic item) => item.Format())); return new PipelineExtensionResult(stfoPipelineResult.Succeeded, stfoPipelineResult.Items, (IReadOnlyList)list); } return new PipelineExtensionResult(false, source, (IReadOnlyList)new string[1] { "PIPELINE ERROR: USE: STFO SCRIPT" }); } return new PipelineExtensionResult(false, source, (IReadOnlyList)new string[1] { LocalizationService.Text("stfo.disabled", Array.Empty()) }); } internal unsafe static StfoPipelineResult Execute(string scriptName, List source) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Invalid comparison between Unknown and I4 //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Expected O, but got Unknown //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Expected O, but got Unknown //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Invalid comparison between Unknown and I4 //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Invalid comparison between Unknown and I4 if (!ScriptWorkspace.TryResolveScript(scriptName, out string scriptPath, out string error)) { return Failure(error, source); } StfoPolicy policy = StfoIntegration.CreatePolicy(); StfoAnalysisResult val = StfoIntegration.CreateAnalyzer(policy).Analyze(scriptPath); if (val.HasErrors) { return new StfoPipelineResult(Succeeded: false, source, Array.Empty(), val.Diagnostics); } StfoValue value = StfoValue.FromList((IReadOnlyList)source.Select(ToValue).ToArray()); StfoExecutionResult val2 = StfoIntegration.CreateVirtualMachine(policy).Execute(scriptPath, (StfoEntryPointKind)1, (StfoValue?)value); if (val2.Succeeded) { StfoValue output = val2.Output; if ((int)((StfoValue)(ref output)).Type == 4) { Dictionary dictionary = source.ToDictionary((PipelineItem item) => item.Id, StringComparer.OrdinalIgnoreCase); List list = new List(); output = val2.Output; foreach (StfoValue item in ((StfoValue)(ref output)).List) { StfoValue current = item; StfoValueType type = ((StfoValue)(ref current)).Type; StfoValue value2; string text = (((int)type == 3) ? ((StfoValue)(ref current)).Text : (((int)type != 5 || !((StfoValue)(ref current)).Map.TryGetValue("ID", out value2)) ? null : ((object)(*(StfoValue*)(&value2))/*cast due to .constrained prefix*/).ToString())); string text2 = text; if (text2 != null && dictionary.TryGetValue(text2, out var value3)) { list.Add(value3); } } return new StfoPipelineResult(Succeeded: true, list, val2.PrintedLines, val2.Diagnostics); } } IReadOnlyList readOnlyList2; if (val2.Diagnostics.Count <= 0) { IReadOnlyList readOnlyList = (IReadOnlyList)(object)new StfoDiagnostic[1] { new StfoDiagnostic((StfoDiagnosticCode)2103, (StfoDiagnosticSeverity)2, "PIPELINE ENTRY MUST OUTPUT A LIST.", new StfoSourceLocation(scriptName, 1, 1, 1)) }; readOnlyList2 = readOnlyList; } else { readOnlyList2 = val2.Diagnostics; } IReadOnlyList diagnostics = readOnlyList2; return new StfoPipelineResult(Succeeded: false, source, val2.PrintedLines, diagnostics); } private static StfoValue ToValue(PipelineItem item) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) return StfoValue.FromMap((IReadOnlyDictionary)new Dictionary(StringComparer.OrdinalIgnoreCase) { ["ID"] = StfoValue.FromText(item.Id), ["TYPE"] = StfoValue.FromText(item.Type), ["ZONE"] = StfoValue.FromText(item.Zone), ["AREA"] = StfoValue.FromText(item.Area), ["STATUS"] = StfoValue.FromText(item.Status) }); } private static StfoPipelineResult Failure(string message, List source) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown return new StfoPipelineResult(Succeeded: false, source, Array.Empty(), (IReadOnlyList)(object)new StfoDiagnostic[1] { new StfoDiagnostic((StfoDiagnosticCode)4001, (StfoDiagnosticSeverity)2, message, new StfoSourceLocation("PIPELINE", 1, 1, 1)) }); } } }