using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using GameNetcodeStuff; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("DoorTeleporter")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("DoorTeleporter")] [assembly: AssemblyTitle("DoorTeleporter")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] 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; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace DoorTeleporter { internal static class ManualPatches { internal static void Apply(Harmony harmony) { try { Prefix(typeof(Terminal), "OnSubmit", typeof(OnSubmitPatch), "Prefix"); Prefix(typeof(Terminal), "ParseWord", typeof(ParseWordPatch), "Prefix", new Type[2] { typeof(string), typeof(int) }); Prefix(typeof(Terminal), "ParsePlayerSentence", typeof(ParseSentencePatch), "Prefix"); Prefix(typeof(Terminal), "LoadNewNode", typeof(LoadNewNodePatch), "Prefix"); Postfix(typeof(Terminal), "Awake", typeof(TerminalLifecyclePatch), "AwakePostfix"); Postfix(typeof(Terminal), "Start", typeof(TerminalLifecyclePatch), "StartPostfix"); } catch (Exception arg) { Plugin.Log.LogError((object)$"ManualPatches.Apply failed: {arg}"); } void Postfix(Type type, string name, Type patchType, string method) { //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(type, name, (Type[])null, (Type[])null); Plugin.Log.LogInfo((object)("Resolve " + type.Name + "." + name + " => " + ((methodInfo == null) ? "NULL" : "ok"))); if (!(methodInfo == null)) { harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(patchType, method, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Plugin.Log.LogInfo((object)("Patched " + type.Name + "." + name + " postfix " + method)); } } void Prefix(Type type, string name, Type patchType, string method, Type[]? args = null) { //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Expected O, but got Unknown MethodInfo methodInfo = ((args == null) ? AccessTools.Method(type, name, (Type[])null, (Type[])null) : AccessTools.Method(type, name, args, (Type[])null)); Plugin.Log.LogInfo((object)("Resolve " + type.Name + "." + name + " => " + ((methodInfo == null) ? "NULL" : (methodInfo.IsPublic ? "public" : "nonpublic")))); if (!(methodInfo == null)) { harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(patchType, method, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Plugin.Log.LogInfo((object)("Patched " + type.Name + "." + name + " prefix " + method)); } } } } internal static class TerminalInput { internal static string? LastSubmitted; private static readonly HashSet Commands = new HashSet(StringComparer.Ordinal) { "doorport", "dtp", "exitport", "fireexit", "randomexit", "door teleport", "door teleporter" }; internal static string Normalize(string? raw) { if (string.IsNullOrEmpty(raw)) { return ""; } return Regex.Replace(Regex.Replace(raw.ToLowerInvariant(), "[^a-z0-9\\s]", " "), "\\s+", " ").Trim(); } internal static string Extract(Terminal terminal) { try { string text = (((Object)(object)terminal.screenText != (Object)null) ? terminal.screenText.text : null); if (string.IsNullOrEmpty(text)) { return ""; } if (terminal.textAdded > 0 && text.Length >= terminal.textAdded) { return Normalize(text.Substring(text.Length - terminal.textAdded)); } int num = text.LastIndexOf('\n'); return Normalize(((num >= 0) ? text.Substring(num + 1) : text).Trim().TrimStart('>', ' ')); } catch { return ""; } } internal static bool IsDoorPortCommand(string input) { return Commands.Contains(input); } } internal static class OnSubmitPatch { public static bool Prefix(Terminal __instance) { try { string text = (TerminalInput.LastSubmitted = TerminalInput.Extract(__instance)); Plugin.Log.LogInfo((object)$"[OnSubmit] captured='{text}' enabled={Plugin.Enabled?.Value}"); if (Plugin.Enabled == null || !Plugin.Enabled.Value) { return true; } if (!TerminalInput.IsDoorPortCommand(text)) { return true; } string text2 = DoorPortActions.Run(text); Plugin.Log.LogInfo((object)("[OnSubmit] doorport handled '" + text + "'")); __instance.LoadNewNode(DoorPortActions.CreateDisplayNode(text2)); DoorPortActions.ReadyForNextCommand(__instance); return false; } catch (Exception arg) { Plugin.Log.LogWarning((object)$"[OnSubmit] {arg}"); return true; } } } internal static class ParseWordPatch { public static bool Prefix(string playerWord, int specificityRequired, ref TerminalKeyword __result) { if (Plugin.Enabled == null || !Plugin.Enabled.Value) { return true; } try { string text = TerminalInput.Normalize(playerWord); Plugin.V($"[ParseWord] '{playerWord}' -> '{text}' spec={specificityRequired}"); if (!TerminalInput.IsDoorPortCommand(text)) { return true; } __result = DoorPortActions.GetKeyword(text); Plugin.Log.LogInfo((object)("[ParseWord] returning doorport keyword for '" + text + "'")); return false; } catch (Exception arg) { Plugin.Log.LogWarning((object)$"[ParseWord] {arg}"); return true; } } } internal static class ParseSentencePatch { public static bool Prefix(Terminal __instance, ref TerminalNode __result) { if (Plugin.Enabled == null || !Plugin.Enabled.Value) { return true; } try { string text = TerminalInput.LastSubmitted; if (string.IsNullOrEmpty(text)) { text = TerminalInput.Extract(__instance); } Plugin.V("[ParseSentence] input='" + text + "'"); if (string.IsNullOrEmpty(text) || !TerminalInput.IsDoorPortCommand(text)) { return true; } string text2 = DoorPortActions.Run(text); __result = DoorPortActions.CreateDisplayNode(text2); TerminalInput.LastSubmitted = null; Plugin.Log.LogInfo((object)("[ParseSentence] handled '" + text + "'")); return false; } catch (Exception arg) { Plugin.Log.LogWarning((object)$"[ParseSentence] {arg}"); return true; } } } internal static class LoadNewNodePatch { private static int _reentry; public static void Prefix(TerminalNode node) { if ((Object)(object)node == (Object)null || _reentry > 0) { return; } try { if (Plugin.Enabled == null || !Plugin.Enabled.Value) { return; } if (!DoorPortActions.TryGetCommandForNode(node, out string cmd)) { Plugin.V("[LoadNewNode] unrelated"); return; } Plugin.Log.LogInfo((object)("[LoadNewNode] doorport keyword node for '" + cmd + "' — running action")); _reentry++; try { string text = DoorPortActions.Run(cmd); string text2 = (text.EndsWith("\n") ? text : (text + "\n")); if (!text2.EndsWith("\n\n")) { text2 += "\n"; } node.displayText = text2; node.clearPreviousText = true; node.acceptAnything = false; node.overrideOptions = false; } finally { _reentry--; } } catch (Exception arg) { Plugin.Log.LogWarning((object)$"[LoadNewNode] {arg}"); } } } internal static class TerminalLifecyclePatch { public static void AwakePostfix(Terminal __instance) { Plugin.Log.LogInfo((object)"[Terminal.Awake] postfix hit"); DoorPortActions.EnsureKeywordsRegistered(__instance); DoorPortActions.EnsureHelpText(__instance); } public static void StartPostfix(Terminal __instance) { Plugin.Log.LogInfo((object)"[Terminal.Start] postfix hit"); DoorPortActions.EnsureKeywordsRegistered(__instance); DoorPortActions.EnsureHelpText(__instance); } } internal static class DoorPortActions { private static readonly Dictionary Keywords = new Dictionary(); private static readonly Dictionary NodeCommands = new Dictionary(); private static bool _registered; private static bool _helpInjected; private const string HelpMarker = "[DoorTeleporter]"; private const string HelpFingerprint = ">DOORPORT"; private const string HelpBlock = ">DOORPORT\nTeleport yourself in front of a random main or fire exit.\nAlso: DTP / EXITPORT / FIREEXIT\n\n"; internal static TerminalNode CreateDisplayNode(string text) { TerminalNode obj = ScriptableObject.CreateInstance(); string text2 = text ?? ""; if (!text2.EndsWith("\n")) { text2 += "\n"; } if (!text2.EndsWith("\n\n")) { text2 += "\n"; } obj.displayText = text2; obj.clearPreviousText = true; obj.maxCharactersToType = 80; obj.acceptAnything = false; obj.overrideOptions = false; return obj; } internal static void ReadyForNextCommand(Terminal terminal) { try { if (!((Object)(object)terminal?.screenText == (Object)null)) { terminal.screenText.ActivateInputField(); ((Selectable)terminal.screenText).Select(); int num = ((terminal.screenText.text != null) ? terminal.screenText.text.Length : 0); terminal.screenText.caretPosition = num; terminal.screenText.selectionAnchorPosition = num; terminal.screenText.selectionFocusPosition = num; } } catch (Exception ex) { Plugin.Log.LogWarning((object)("[ReadyForNextCommand] " + ex.Message)); } } internal static bool TryGetCommandForNode(TerminalNode node, out string cmd) { if (NodeCommands.TryGetValue(node, out cmd)) { return true; } string text = node.displayText ?? ""; if (text.StartsWith("Ship teleport command:", StringComparison.OrdinalIgnoreCase)) { cmd = TerminalInput.Normalize(text.Substring("Ship teleport command:".Length)); return TerminalInput.IsDoorPortCommand(cmd); } cmd = ""; return false; } internal static TerminalKeyword GetKeyword(string word) { string text = (word.Contains(" ") ? word.Split(' ')[0] : word); if (Keywords.TryGetValue(text, out TerminalKeyword value) && (Object)(object)value != (Object)null) { return value; } EnsureKeyword(text); return Keywords[text]; } private static void EnsureKeyword(string word) { if (!Keywords.ContainsKey(word)) { TerminalNode val = CreateDisplayNode("Ship teleport command: " + word + "\n"); NodeCommands[val] = word; TerminalKeyword val2 = ScriptableObject.CreateInstance(); val2.word = word; val2.isVerb = false; val2.specialKeywordResult = val; Keywords[word] = val2; } } internal static void EnsureKeywordsRegistered(Terminal terminal) { try { if (terminal?.terminalNodes?.allKeywords == null) { Plugin.Log.LogInfo((object)"Keyword register skipped: allKeywords null"); return; } EnsureKeyword("doorport"); EnsureKeyword("dtp"); EnsureKeyword("exitport"); EnsureKeyword("fireexit"); EnsureKeyword("randomexit"); if (_registered) { Plugin.V("Keywords already registered"); return; } List list = new List(terminal.terminalNodes.allKeywords); foreach (KeyValuePair kv in Keywords) { if (!list.Exists((TerminalKeyword k) => (Object)(object)k != (Object)null && k.word == kv.Key)) { list.Add(kv.Value); } } terminal.terminalNodes.allKeywords = list.ToArray(); _registered = true; Plugin.Log.LogInfo((object)$"Registered doorport keywords (allKeywords={list.Count}, trackedNodes={NodeCommands.Count})"); } catch (Exception ex) { Plugin.Log.LogWarning((object)("EnsureKeywordsRegistered failed: " + ex.Message)); } } internal static void EnsureHelpText(Terminal terminal) { try { if (terminal?.terminalNodes?.specialNodes == null) { return; } int num = 0; for (int i = 0; i < terminal.terminalNodes.specialNodes.Count; i++) { if (TryApplyHelpToNode(terminal.terminalNodes.specialNodes[i], $"specialNodes[{i}]")) { num++; } } TerminalKeyword[] allKeywords = terminal.terminalNodes.allKeywords; if (allKeywords != null) { TerminalKeyword[] array = allKeywords; foreach (TerminalKeyword val in array) { if (!((Object)(object)val == (Object)null) && !string.IsNullOrEmpty(val.word)) { string word = val.word; if ((string.Equals(word, "help", StringComparison.OrdinalIgnoreCase) || string.Equals(word, "other", StringComparison.OrdinalIgnoreCase) || string.Equals(word, "others", StringComparison.OrdinalIgnoreCase)) && TryApplyHelpToNode(val.specialKeywordResult, "keyword:" + word)) { num++; } } } } if (num > 0) { _helpInjected = true; } else if (!_helpInjected) { Plugin.Log.LogInfo((object)"[Help] no command-list page found yet"); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("[Help] " + ex.Message)); } } private static bool IsCommandListPage(string page) { if (string.IsNullOrEmpty(page)) { return false; } bool num = page.IndexOf(">STORE", StringComparison.OrdinalIgnoreCase) >= 0; bool flag = page.IndexOf(">BESTIARY", StringComparison.OrdinalIgnoreCase) >= 0; bool flag2 = page.IndexOf(">STORAGE", StringComparison.OrdinalIgnoreCase) >= 0; bool flag3 = page.IndexOf(">OTHER", StringComparison.OrdinalIgnoreCase) >= 0; if (!num || !(flag || flag2 || flag3)) { return false; } return true; } private static bool TryApplyHelpToNode(TerminalNode? node, string label) { if ((Object)(object)node == (Object)null || string.IsNullOrEmpty(node.displayText)) { return false; } string text = StripLegacyHelpHeader(node.displayText); if (!IsCommandListPage(text)) { string text2 = StripDoorPortHelp(text); if (text2 != node.displayText) { node.displayText = text2; Plugin.Log.LogInfo((object)("[Help] stripped doorport docs from non-list " + label)); } return false; } if (text.IndexOf(">DOORPORT", StringComparison.OrdinalIgnoreCase) >= 0) { if (text != node.displayText) { node.displayText = text; } return false; } node.displayText = InjectHelp(text); Plugin.Log.LogInfo((object)("[Help] injected doorport docs into " + label)); return true; } private static string StripLegacyHelpHeader(string page) { if (string.IsNullOrEmpty(page) || page.IndexOf("[DoorTeleporter]", StringComparison.Ordinal) < 0) { return page; } return page.Replace("[DoorTeleporter]\n\n", "").Replace("[DoorTeleporter]\n", "").Replace("[DoorTeleporter]", ""); } private static string StripDoorPortHelp(string page) { if (string.IsNullOrEmpty(page) || page.IndexOf(">DOORPORT", StringComparison.OrdinalIgnoreCase) < 0) { return page; } if (page.Contains(">DOORPORT\nTeleport yourself in front of a random main or fire exit.\nAlso: DTP / EXITPORT / FIREEXIT\n\n")) { return page.Replace(">DOORPORT\nTeleport yourself in front of a random main or fire exit.\nAlso: DTP / EXITPORT / FIREEXIT\n\n", ""); } int num = page.IndexOf(">DOORPORT", StringComparison.OrdinalIgnoreCase); if (num < 0) { return page; } int num2 = page.IndexOf("\n\n", num); num2 = ((num2 >= 0) ? (num2 + 2) : page.Length); int num3 = num; if (num3 >= 2 && page[num3 - 2] == '\n' && page[num3 - 1] == '\n') { num3 -= 2; } else if (num3 >= 1 && page[num3 - 1] == '\n') { num3--; } return page.Substring(0, num3) + page.Substring(num2); } private static string InjectHelp(string page) { page = StripLegacyHelpHeader(page); int num = page.IndexOf(">OTHER", StringComparison.OrdinalIgnoreCase); if (num < 0) { num = page.IndexOf("OTHER", StringComparison.OrdinalIgnoreCase); } if (num >= 0) { int num2 = page.IndexOf("\n\n", num); if (num2 > num) { int num3 = num2 + 2; return page.Substring(0, num3) + ">DOORPORT\nTeleport yourself in front of a random main or fire exit.\nAlso: DTP / EXITPORT / FIREEXIT\n\n" + page.Substring(num3); } } if (!page.EndsWith("\n")) { page += "\n"; } if (!page.EndsWith("\n\n")) { page += "\n"; } return page + ">DOORPORT\nTeleport yourself in front of a random main or fire exit.\nAlso: DTP / EXITPORT / FIREEXIT\n\n"; } internal static string Run(string input) { if (input != null) { int length = input.Length; if (length <= 8) { if (length != 3) { if (length == 8) { switch (input[0]) { case 'd': break; case 'e': goto IL_0060; case 'f': goto IL_006f; default: goto IL_00c0; } if (input == "doorport") { goto IL_00b8; } } } else if (input == "dtp") { goto IL_00b8; } } else if (length != 10) { if (length != 13) { if (length == 15 && input == "door teleporter") { goto IL_00b8; } } else if (input == "door teleport") { goto IL_00b8; } } else if (input == "randomexit") { goto IL_00b8; } } goto IL_00c0; IL_00b8: return TeleportToRandomDoor(); IL_00c0: return "Unknown doorport command.\n"; IL_0060: if (input == "exitport") { goto IL_00b8; } goto IL_00c0; IL_006f: if (input == "fireexit") { goto IL_00b8; } goto IL_00c0; } private static string TeleportToRandomDoor() { //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; if ((Object)(object)val == (Object)null) { return "Local player not available.\n"; } if (val.isPlayerDead) { return "Can't door-teleport while dead.\n"; } StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance != (Object)null && instance.inShipPhase) { return "No facility doors while in orbit.\n"; } bool flag = Plugin.IncludeMain == null || Plugin.IncludeMain.Value; bool flag2 = Plugin.IncludeFireExits == null || Plugin.IncludeFireExits.Value; if (!flag && !flag2) { return "Both main and fire exits are disabled in config.\n"; } EntranceTeleport[] array; try { array = Object.FindObjectsOfType(); } catch (Exception ex) { Plugin.Log.LogWarning((object)("[DoorPort] FindObjectsOfType: " + ex.Message)); return "Could not find facility doors.\n"; } if (array == null || array.Length == 0) { return "No facility doors found (land on a moon first).\n"; } List list = new List(); EntranceTeleport[] array2 = array; foreach (EntranceTeleport val2 in array2) { if ((Object)(object)val2 == (Object)null || (Object)(object)val2.entrancePoint == (Object)null || !val2.isEntranceToBuilding) { continue; } if (val2.entranceId == 0) { if (flag) { list.Add(val2); } } else if (flag2) { list.Add(val2); } } if (list.Count == 0) { return "No matching entrances (check IncludeMainEntrance / IncludeFireExits).\n"; } EntranceTeleport val3 = list[Random.Range(0, list.Count)]; Transform entrancePoint = val3.entrancePoint; float num = Plugin.StandBackMeters?.Value ?? 0.35f; Vector3 val4 = entrancePoint.position; try { Vector3 val5 = -entrancePoint.forward; val5.y = 0f; if (((Vector3)(ref val5)).sqrMagnitude > 0.0001f) { ((Vector3)(ref val5)).Normalize(); val4 += val5 * Mathf.Max(0f, num); } } catch { } float y = entrancePoint.eulerAngles.y; try { Vector3 val6 = entrancePoint.position - val4; Quaternion val7 = Quaternion.LookRotation(((Vector3)(ref val6)).normalized, Vector3.up); y = ((Quaternion)(ref val7)).eulerAngles.y; } catch { } try { val.TeleportPlayer(val4, true, y, true, true); Plugin.Log.LogInfo((object)$"[DoorPort] Teleported to entranceId={val3.entranceId} pos={val4} candidates={list.Count}"); } catch (Exception ex2) { Plugin.Log.LogWarning((object)("[DoorPort] TeleportPlayer failed: " + ex2.Message)); return "Teleport failed.\n"; } string text = ((val3.entranceId == 0) ? "main entrance" : $"fire exit #{val3.entranceId}"); return "Teleported to " + text + ".\n"; } } [BepInPlugin("com.benhough.lethal.DoorTeleporter", "DoorTeleporter", "1.0.0")] public class Plugin : BaseUnityPlugin { public const string ModGuid = "com.benhough.lethal.DoorTeleporter"; public const string ModName = "DoorTeleporter"; public const string ModVersion = "1.0.0"; private readonly Harmony _harmony = new Harmony("com.benhough.lethal.DoorTeleporter"); internal static Plugin Instance { get; private set; } internal static ManualLogSource Log { get; private set; } internal static ConfigEntry Enabled { get; private set; } internal static ConfigEntry IncludeMain { get; private set; } internal static ConfigEntry IncludeFireExits { get; private set; } internal static ConfigEntry StandBackMeters { get; private set; } internal static ConfigEntry Verbose { get; private set; } private void Awake() { Instance = this; Log = ((BaseUnityPlugin)this).Logger; Enabled = ((BaseUnityPlugin)this).Config.Bind("General", "Enabled", true, "Enable terminal commands: doorport / dtp / exitport / fireexit."); IncludeMain = ((BaseUnityPlugin)this).Config.Bind("General", "IncludeMainEntrance", true, "Allow teleporting to the main facility entrance (entranceId 0)."); IncludeFireExits = ((BaseUnityPlugin)this).Config.Bind("General", "IncludeFireExits", true, "Allow teleporting to fire-exit entrances (entranceId > 0)."); StandBackMeters = ((BaseUnityPlugin)this).Config.Bind("General", "StandBackMeters", 0.35f, "Nudge slightly back from the entrance point so you stand in front of the door."); Verbose = ((BaseUnityPlugin)this).Config.Bind("General", "VerboseLogging", false, "Log terminal/door-teleport traces."); ManualPatches.Apply(_harmony); Log.LogInfo((object)"DoorTeleporter v1.0.0 loaded."); } internal static void V(string msg) { if (Verbose != null && Verbose.Value) { Log.LogInfo((object)msg); } } } internal static class PluginInfo { public const string PLUGIN_GUID = "com.benhough.lethal.DoorTeleporter"; public const string PLUGIN_NAME = "DoorTeleporter"; public const string PLUGIN_VERSION = "1.0.0"; } }