using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using EnhancedRadarBooster; using GameNetcodeStuff; using HarmonyLib; using ImmersiveCompany.Patches; using Microsoft.CodeAnalysis; using OpenBodyCams; using OpenBodyCams.API; using TMPro; using TwoRadarMaps.Compatibility; using TwoRadarMaps.Patches; using TwoRadarMaps.Utilities.IL; using Unity.Netcode; using UnityEngine; using UnityEngine.Rendering; using UnityEngine.Rendering.HighDefinition; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("OpenBodyCams")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("OpenBodyCams")] [assembly: AssemblyCopyright("Copyright © 2025")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("58be1122-f068-4465-95ee-b1f09dcd559f")] [assembly: AssemblyFileVersion("3.0.11")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("3.0.11.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class IsUnmanagedAttribute : Attribute { } [CompilerGenerated] [Microsoft.CodeAnalysis.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 TwoRadarMaps { [BepInPlugin("Zaggy1024.TwoRadarMaps", "TwoRadarMaps", "1.6.5")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { private const string MOD_NAME = "TwoRadarMaps"; private const string MOD_UNIQUE_NAME = "Zaggy1024.TwoRadarMaps"; private const string MOD_VERSION = "1.6.5"; internal static readonly Harmony Harmony = new Harmony("Zaggy1024.TwoRadarMaps"); public static ConfigEntry TextureFiltering; public static ConfigEntry BodyCamHorizontalResolution; public static ConfigEntry EnableZoom; public static ConfigEntry ZoomLevels; public static ConfigEntry DefaultZoomLevel; public static ConfigEntry EnableTeleportCommand; public static ConfigEntry EnableTeleportCommandShorthand; private const string OLD_DEFAULT_ZOOM_LEVELS = "19.7, 29.55, 39.4"; private const string DEFAULT_ZOOM_LEVELS = "30, 45, 60"; internal static Terminal Terminal; internal static ShipTeleporter Teleporter; public static ManualCameraRenderer TerminalMapRenderer; public static TextMeshProUGUI TerminalMapScreenPlayerName; public static Canvas TerminalMapScreenUICanvas; public static float[] TerminalMapZoomLevelOptions; public static int TerminalMapZoomLevel; public static ConfigEntry LastConfigVersion; public static Plugin Instance { get; private set; } public ManualLogSource Logger => ((BaseUnityPlugin)this).Logger; public void Awake() { Instance = this; TextureFiltering = ((BaseUnityPlugin)this).Config.Bind("Rendering", "TextureFiltering", (FilterMode)0, "The filtering mode to apply to the map (and the body cam if present).\n\nPoint will result in sharp edges on pixels.\nBilinear and Trilinear will result in smooth transitions between pixels."); TextureFiltering.SettingChanged += delegate { //IL_0014: Unknown result type (might be due to invalid IL or missing references) ((Texture)TerminalMapRenderer.cam.targetTexture).filterMode = TextureFiltering.Value; OpenBodyCamsCompatibility.UpdateBodyCamTexture(); }; BodyCamHorizontalResolution = ((BaseUnityPlugin)this).Config.Bind("Compatibility", "BodyCamHorizontalResolution", 170, "The horizontal resolution to use for the picture-in-picture body cam when it is enabled in OpenBodyCams 2.1.0+.\n\nThe vertical resolution will be calculated based on a 4:3 aspect ratio."); EnableZoom = ((BaseUnityPlugin)this).Config.Bind("Zoom", "Enabled", false, "Enable 'zoom in' and 'zoom out' commands in the terminal to zoom in and out of the terminal radar map."); EnableZoom.SettingChanged += delegate { TerminalCommands.Initialize(); }; ZoomLevels = ((BaseUnityPlugin)this).Config.Bind("Zoom", "Sizes", "30, 45, 60", "The orthographic sizes to use for each zoom level.\nA list of comma-separated numbers.\nLower values indicate a smaller field of view.\n100% zoom is 30."); ZoomLevels.SettingChanged += delegate { UpdateZoomFactors(); }; DefaultZoomLevel = ((BaseUnityPlugin)this).Config.Bind("Zoom", "DefaultLevel", 0, "The zoom factor to select by default. The first zoom level is 0."); EnableTeleportCommand = ((BaseUnityPlugin)this).Config.Bind("TeleportCommand", "Enabled", false, "Enable an 'activate teleport' command in the terminal. A player can be specified to teleport them instead of the target of the terminal's map."); EnableTeleportCommand.SettingChanged += delegate { TerminalCommands.Initialize(); }; EnableTeleportCommandShorthand = ((BaseUnityPlugin)this).Config.Bind("TeleportCommand", "ShorthandEnabled", true, "Enable a 'tp' shorthand for the 'activate teleport' command. Will only function if the longhand command is enabled."); EnableTeleportCommandShorthand.SettingChanged += delegate { TerminalCommands.Initialize(); }; LastConfigVersion = ((BaseUnityPlugin)this).Config.Bind("Debug", "LastConfigVersion", "", "The last version of the mod that loaded/saved this config file. Used for setting migration."); MigrateConfigOptions(); Harmony.PatchAll(typeof(PatchTerminal)); Harmony.PatchAll(typeof(PatchVanillaBugs)); Harmony.PatchAll(typeof(PatchManualCameraRenderer)); PatchShipTeleporter.Apply(); RenderPipelineManager.beginCameraRendering += BeforeCameraRendering; OpenBodyCamsCompatibility.Initialize(); EnhancedRadarBoosterCompatibility.Initialize(); } private void MigrateConfigOptions() { if (!Version.TryParse(LastConfigVersion.Value, out Version result)) { result = new Version(1, 5, 0); } Logger.LogInfo((object)$"Last config version is {result}."); if (result < new Version(1, 6, 0) && ZoomLevels.Value == "19.7, 29.55, 39.4") { Logger.LogInfo((object)$"{((ConfigEntryBase)ZoomLevels).Definition} is being migrated to factors that correspond to the new map size in v70."); ZoomLevels.Value = "30, 45, 60"; } LastConfigVersion.Value = "1.6.5"; } public static void BeforeCameraRendering(ScriptableRenderContext context, Camera camera) { ManualCameraRenderer val = StartOfRound.Instance?.mapScreen; if ((Object)(object)val == (Object)null) { return; } ManualCameraRenderer val2 = null; ((Renderer)val.lineFromRadarTargetToExit).forceRenderingOff = true; if ((Object)(object)camera == (Object)(object)val.cam) { val2 = val; } if ((Object)(object)TerminalMapRenderer != (Object)null) { ((Renderer)TerminalMapRenderer.lineFromRadarTargetToExit).forceRenderingOff = true; if ((Object)(object)camera == (Object)(object)TerminalMapRenderer.cam) { val2 = TerminalMapRenderer; } } if (!((Object)(object)val2 == (Object)null)) { ((Renderer)val2.lineFromRadarTargetToExit).forceRenderingOff = false; SetContourMapVisibility(val2); } } private static void SetContourMapVisibility(ManualCameraRenderer map) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) GameObject contourMap = StartOfRound.Instance.mapScreen.contourMap; if (!((Object)(object)contourMap == (Object)null)) { if ((Object)(object)map.targetedPlayer == (Object)null && ((Component)map.headMountedCamTarget).transform.position.y <= -80f) { contourMap.SetActive(false); return; } if ((Object)(object)map.targetedPlayer != (Object)null && map.targetedPlayer.isInsideFactory) { contourMap.SetActive(false); return; } contourMap.SetActive(true); contourMap.transform.position = new Vector3(contourMap.transform.position.x, ((Component)map.headMountedCamTarget).transform.position.y - 1.5f, contourMap.transform.position.z); } } private static bool TargetIsValid(Transform targetTransform) { if ((Object)(object)targetTransform == (Object)null) { return false; } PlayerControllerB val = default(PlayerControllerB); if (!((Component)((Component)targetTransform).transform).TryGetComponent(ref val)) { return true; } if (!val.isPlayerControlled && !val.isPlayerDead) { return (Object)(object)val.redirectToEnemy != (Object)null; } return true; } internal static void SetTargetIndex(ManualCameraRenderer mapRenderer, int targetIndex) { if (targetIndex >= 0 && targetIndex < mapRenderer.radarTargets.Count) { mapRenderer.targetTransformIndex = targetIndex; mapRenderer.targetedPlayer = ((Component)mapRenderer.radarTargets[targetIndex].transform).GetComponent(); } } internal static int GetNextValidTarget(List targets, int initialIndex) { int count = targets.Count; for (int i = 0; i < count; i++) { int num = (initialIndex + i) % count; if (TargetIsValid(targets[num]?.transform)) { return num; } } return -1; } internal static void StartTargetTransition(ManualCameraRenderer mapRenderer, int targetIndex) { if (mapRenderer.updateMapCameraCoroutine != null) { ((MonoBehaviour)mapRenderer).StopCoroutine(mapRenderer.updateMapCameraCoroutine); } mapRenderer.updateMapCameraCoroutine = ((MonoBehaviour)mapRenderer).StartCoroutine(mapRenderer.updateMapTarget(targetIndex, true)); } internal static void EnsureMapRendererHasValidTarget(ManualCameraRenderer mapRenderer) { int nextValidTarget = GetNextValidTarget(mapRenderer.radarTargets, mapRenderer.targetTransformIndex); if (nextValidTarget != -1) { StartTargetTransition(mapRenderer, nextValidTarget); } } public static void EnsureAllMapRenderersHaveValidTargets() { if (((NetworkBehaviour)StartOfRound.Instance.mapScreen).IsOwner) { EnsureMapRendererHasValidTarget(StartOfRound.Instance.mapScreen); } EnsureMapRendererHasValidTarget(TerminalMapRenderer); } public static void UpdateZoomFactors(string factors) { try { TerminalMapZoomLevelOptions = (from s in factors.Split(new char[2] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries) select float.Parse(s.Trim(), CultureInfo.InvariantCulture)).ToArray(); } catch (Exception arg) { Instance.Logger.LogError((object)$"Failed to parse terminal map radar zoom levels: {arg}"); UpdateZoomFactors("30, 45, 60"); } SetZoomLevel(DefaultZoomLevel.Value); } public static void UpdateZoomFactors() { UpdateZoomFactors(ZoomLevels.Value); } public static float GetZoomOrthographicSize() { return TerminalMapZoomLevelOptions[TerminalMapZoomLevel]; } public static void SetZoomLevel(int level) { if (!((Object)(object)TerminalMapRenderer == (Object)null)) { TerminalMapRenderer.mapCameraAnimator.SetTrigger("Transition"); TerminalMapZoomLevel = Math.Max(0, Math.Min(level, TerminalMapZoomLevelOptions.Length - 1)); TerminalMapRenderer.cam.orthographicSize = GetZoomOrthographicSize(); } } public static void CycleTerminalMapZoom() { SetZoomLevel((TerminalMapZoomLevel + 1) % TerminalMapZoomLevelOptions.Length); } public static void ZoomTerminalMapIn() { SetZoomLevel(TerminalMapZoomLevel - 1); } public static void ZoomTerminalMapOut() { SetZoomLevel(TerminalMapZoomLevel + 1); } public static void TeleportTarget(int targetIndex) { ManualCameraRenderer mapScreen = StartOfRound.Instance.mapScreen; if (mapScreen.targetTransformIndex >= mapScreen.radarTargets.Count) { Instance.Logger.LogError((object)$"Attempted to teleport target #{targetIndex} which is out of bounds of the {mapScreen.radarTargets.Count} targets available."); } else if ((Object)(object)Teleporter == (Object)null) { Instance.Logger.LogError((object)$"Attempted to teleport target #{targetIndex} ({mapScreen.radarTargets[targetIndex].name}) with no teleporter."); } else if (!(Teleporter.cooldownTime > 0f)) { int targetTransformIndex = mapScreen.targetTransformIndex; SetTargetIndex(mapScreen, targetIndex); Teleporter.PressTeleportButtonOnLocalClient(); SetTargetIndex(mapScreen, targetTransformIndex); } } } public static class TerminalCommands { public static TerminalNode CycleZoomNode = null; public static TerminalNode ZoomInNode = null; public static TerminalNode ZoomOutNode = null; public static TerminalNode ResetZoomNode = null; public static TerminalNode TeleportNode = null; private static readonly List newTerminalKeywords = new List(); private static readonly List modifiedTerminalKeywords = new List(); private static readonly List<(TerminalNode, string)> appendedDescriptions = new List<(TerminalNode, string)>(); public static void Initialize() { //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Expected O, but got Unknown //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Expected O, but got Unknown //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Expected O, but got Unknown //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Expected O, but got Unknown if ((Object)(object)Plugin.Terminal == (Object)null) { return; } RemoveAddedKeywords(); Plugin.UpdateZoomFactors(); CycleZoomNode = null; ZoomInNode = null; ZoomOutNode = null; ResetZoomNode = null; if (Plugin.EnableZoom.Value) { CycleZoomNode = ScriptableObject.CreateInstance(); ((Object)CycleZoomNode).name = "CycleZoomNode"; CycleZoomNode.displayText = ""; CycleZoomNode.clearPreviousText = true; ZoomInNode = ScriptableObject.CreateInstance(); ((Object)ZoomInNode).name = "ZoomIn"; ZoomInNode.displayText = ""; ZoomInNode.clearPreviousText = true; ZoomOutNode = ScriptableObject.CreateInstance(); ((Object)ZoomOutNode).name = "ZoomOut"; ZoomOutNode.displayText = ""; ZoomOutNode.clearPreviousText = true; ResetZoomNode = ScriptableObject.CreateInstance(); ((Object)ResetZoomNode).name = "ResetZoom"; ResetZoomNode.displayText = ""; ResetZoomNode.clearPreviousText = true; TerminalKeyword val = FindOrCreateKeyword("In", "in", verb: false); TerminalKeyword val2 = FindOrCreateKeyword("Out", "out", verb: false); FindOrCreateKeyword("Zoom", "zoom", verb: true, (CompatibleNoun[])(object)new CompatibleNoun[2] { new CompatibleNoun(val, ZoomInNode), new CompatibleNoun(val2, ZoomOutNode) }).specialKeywordResult = CycleZoomNode; TerminalKeyword val3 = FindOrCreateKeyword("Zoom", "zoom", verb: false); FindOrCreateKeyword("Reset", "reset", verb: true, (CompatibleNoun[])(object)new CompatibleNoun[1] { new CompatibleNoun(val3, ResetZoomNode) }); AddCommandDescription("other", "ZOOM", "Cycle through zoom levels on the map. Specify direction with 'IN' and 'OUT'.\nThe 'RESET ZOOM' command will set the zoom back to the default level."); } TeleportNode = null; if (Plugin.EnableTeleportCommand.Value) { TeleportNode = ScriptableObject.CreateInstance(); ((Object)TeleportNode).name = "TeleportNode"; TeleportNode.clearPreviousText = true; TerminalKeyword val4 = FindOrCreateKeyword("Teleporter", "teleporter", verb: false); FindOrCreateKeyword("Activate", "activate", verb: true, (CompatibleNoun[])(object)new CompatibleNoun[1] { new CompatibleNoun(val4, TeleportNode) }); string text = ""; if (Plugin.EnableTeleportCommandShorthand.Value) { FindOrCreateKeyword("TeleportShorthand", "tp", verb: true).specialKeywordResult = TeleportNode; text = "/TP"; } AddCommandDescription("other", "ACTIVATE TELEPORTER" + text, "Activate the teleporter to beam the player monitored on the map into the ship."); } AddNewlyCreatedCommands(); } public static bool ProcessNode(TerminalNode node) { if ((Object)(object)node == (Object)(object)CycleZoomNode) { Plugin.CycleTerminalMapZoom(); return false; } if ((Object)(object)node == (Object)(object)ZoomInNode) { Plugin.ZoomTerminalMapIn(); return false; } if ((Object)(object)node == (Object)(object)ZoomOutNode) { Plugin.ZoomTerminalMapOut(); return false; } if ((Object)(object)node == (Object)(object)ResetZoomNode) { Plugin.SetZoomLevel(Plugin.DefaultZoomLevel.Value); return false; } if ((Object)(object)node == (Object)(object)TeleportNode) { if ((Object)(object)Plugin.Teleporter == (Object)null) { TeleportNode.displayText = "Teleporter is not installed.\n\n"; return true; } if (Plugin.Teleporter.cooldownTime > 0f) { TeleportNode.displayText = $"Teleporter is on cooldown for {(int)(Plugin.Teleporter.cooldownTime + 1f)} more seconds."; return true; } TeleportNode.displayText = "Teleporting " + StartOfRound.Instance.mapScreen.radarTargets[Plugin.TerminalMapRenderer.targetTransformIndex]?.name + "...\n\n"; Plugin.TeleportTarget(Plugin.TerminalMapRenderer.targetTransformIndex); return false; } return true; } private static TerminalKeyword FindKeyword(string word, bool verb) { return ((IEnumerable)Plugin.Terminal.terminalNodes.allKeywords).FirstOrDefault((Func)((TerminalKeyword keyword) => keyword.word == word && keyword.isVerb == verb)); } private static CompatibleNoun FindCompatibleNoun(this TerminalKeyword keyword, string noun) { return ((IEnumerable)keyword.compatibleNouns).FirstOrDefault((Func)((CompatibleNoun compatible) => compatible.noun.word == noun)); } private static TerminalKeyword FindOrCreateKeyword(string name, string word, bool verb, CompatibleNoun[] compatibleNouns = null) { Plugin.Instance.Logger.LogInfo((object)("Creating terminal " + (verb ? "verb" : "noun") + " '" + word + "' (" + name + ").")); TerminalKeyword val = FindKeyword(word, verb); if ((Object)(object)val == (Object)null) { val = ScriptableObject.CreateInstance(); ((Object)val).name = name; val.isVerb = verb; val.word = word; val.compatibleNouns = compatibleNouns; newTerminalKeywords.Add(val); Plugin.Instance.Logger.LogInfo((object)" Keyword was not found, created a new one."); } else { TerminalKeyword obj = val; CompatibleNoun[] array = val.compatibleNouns ?? Array.Empty(); CompatibleNoun[] array2 = compatibleNouns ?? Array.Empty(); int num = 0; CompatibleNoun[] array3 = (CompatibleNoun[])(object)new CompatibleNoun[array.Length + array2.Length]; ReadOnlySpan readOnlySpan = new ReadOnlySpan(array); readOnlySpan.CopyTo(new Span(array3).Slice(num, readOnlySpan.Length)); num += readOnlySpan.Length; ReadOnlySpan readOnlySpan2 = new ReadOnlySpan(array2); readOnlySpan2.CopyTo(new Span(array3).Slice(num, readOnlySpan2.Length)); num += readOnlySpan2.Length; obj.compatibleNouns = array3; Plugin.Instance.Logger.LogInfo((object)" Keyword existed, appended nouns."); } modifiedTerminalKeywords.Add(val); return val; } private static void AddNewlyCreatedCommands() { TerminalNodesList terminalNodes; TerminalKeyword[] allKeywords = (terminalNodes = Plugin.Terminal.terminalNodes).allKeywords; List list = newTerminalKeywords; int num = 0; TerminalKeyword[] array = (TerminalKeyword[])(object)new TerminalKeyword[allKeywords.Length + list.Count]; ReadOnlySpan readOnlySpan = new ReadOnlySpan(allKeywords); readOnlySpan.CopyTo(new Span(array).Slice(num, readOnlySpan.Length)); num += readOnlySpan.Length; foreach (TerminalKeyword item in list) { array[num] = item; num++; } terminalNodes.allKeywords = array; } private static void AddCommandDescription(string category, string word, string description) { TerminalNode specialKeywordResult = FindKeyword(category, verb: false).specialKeywordResult; string text = new StringBuilder(word.Length + description.Length + 5).Append(">").Append(word).Append("\n") .Append(description) .Append("\n\n") .ToString(); appendedDescriptions.Add((specialKeywordResult, text)); if (specialKeywordResult.displayText.EndsWith("\n\n\n")) { specialKeywordResult.displayText = specialKeywordResult.displayText.Insert(specialKeywordResult.displayText.Length - 1, text); } else { specialKeywordResult.displayText += text; } } private static void RemoveAddedKeywords() { foreach (TerminalKeyword modifiedTerminalKeyword in modifiedTerminalKeywords) { if (modifiedTerminalKeyword.compatibleNouns != null) { modifiedTerminalKeyword.compatibleNouns = modifiedTerminalKeyword.compatibleNouns.Where((CompatibleNoun compatible) => !newTerminalKeywords.Contains(compatible.noun)).ToArray(); } } modifiedTerminalKeywords.Clear(); foreach (TerminalKeyword newTerminalKeyword in newTerminalKeywords) { Object.Destroy((Object)(object)newTerminalKeyword); } TerminalNodesList terminalNodes = Plugin.Terminal.terminalNodes; terminalNodes.allKeywords = terminalNodes.allKeywords.Where((TerminalKeyword keyword) => !newTerminalKeywords.Contains(keyword)).ToArray(); newTerminalKeywords.Clear(); foreach (var appendedDescription in appendedDescriptions) { TerminalNode item = appendedDescription.Item1; string item2 = appendedDescription.Item2; int num = item.displayText.IndexOf(item2); if (num == -1) { Plugin.Instance.Logger.LogError((object)("Could not find command description text in " + ((Object)item).name + " to remove it:")); Plugin.Instance.Logger.LogError((object)item2); } else { item.displayText = item.displayText.Remove(num, item2.Length); } } appendedDescriptions.Clear(); } } } namespace TwoRadarMaps.Utilities.IL { internal class ILInjector { [CompilerGenerated] private sealed class d__31 : IEnumerable, IEnumerable, IEnumerator, IEnumerator, IDisposable { private int <>1__state; private CodeInstruction <>2__current; private int <>l__initialThreadId; public ILInjector <>4__this; private int offset; public int <>3__offset; private int size; public int <>3__size; private int 5__2; CodeInstruction IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__31(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { int num = <>1__state; ILInjector iLInjector = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; 5__2 = 0; break; case 1: <>1__state = -1; 5__2++; break; } if (5__2 < size) { <>2__current = iLInjector.instructions[iLInjector.index + offset + 5__2]; <>1__state = 1; return true; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__31 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__31(0) { <>4__this = <>4__this }; } d__.offset = <>3__offset; d__.size = <>3__size; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } private const string INVALID = "Injector is invalid"; private List instructions = instructions.ToList(); private ILGenerator generator; private int index; private int matchEnd; public bool IsValid { get { if (instructions != null) { return IsIndexValid(index); } return false; } } public CodeInstruction Instruction { get { if (!IsIndexInRange(index)) { return null; } return instructions[index]; } set { if (!IsIndexInRange(index)) { throw new InvalidOperationException($"Current index {index} is out of range of instruction count {instructions.Count}"); } instructions[index] = value; } } public CodeInstruction LastMatchedInstruction { get { int num = matchEnd - 1; if (!IsIndexInRange(num)) { return null; } return instructions[num]; } set { int num = matchEnd - 1; if (!IsIndexInRange(num)) { throw new InvalidOperationException($"Last matched index {index} is out of range of instruction count {instructions.Count}"); } instructions[num] = value; } } public ICollection Instructions => instructions.AsReadOnly(); public ILInjector(IEnumerable instructions, ILGenerator generator = null) { this.generator = generator; matchEnd = -1; base..ctor(); } public ILInjector GoToStart() { matchEnd = index; index = 0; return this; } public ILInjector GoToEnd() { matchEnd = index; index = instructions.Count; return this; } public ILInjector Forward(int offset) { if (!IsValid) { return this; } matchEnd = index; index = Math.Clamp(index + offset, -1, instructions.Count); return this; } public ILInjector Back(int offset) { return Forward(-offset); } private void MarkInvalid() { index = -1; matchEnd = -1; } private void Search(bool forward, ILMatcher[] predicates) { if (!IsValid) { return; } int num = 1; if (!forward) { num = -1; index--; } while (forward ? (index < instructions.Count) : (index >= 0)) { if (forward && index + predicates.Length > instructions.Count) { index = instructions.Count; break; } int i; for (i = 0; i < predicates.Length && predicates[i].Matches(instructions[index + i]); i++) { } if (i == predicates.Length) { matchEnd = index + i; return; } index += num; } MarkInvalid(); } public ILInjector Find(params ILMatcher[] predicates) { Search(forward: true, predicates); return this; } public ILInjector ReverseFind(params ILMatcher[] predicates) { Search(forward: false, predicates); return this; } public ILInjector GoToPush(int popIndex) { if (!IsValid) { return this; } matchEnd = index; index--; int num = 0; while (index >= 0) { CodeInstruction instruction = instructions[index]; num += instruction.PushCount(); num -= instruction.PopCount(); if (num > popIndex) { return this; } index--; } return this; } public ILInjector SkipBranch() { if (Instruction == null) { return this; } if (!(Instruction.operand is Label label)) { throw new InvalidOperationException($"Current instruction is not a branch: {Instruction}"); } return FindLabel(label); } public ILInjector FindLabel(Label label) { if (label == default(Label)) { return this; } matchEnd = index; for (index = 0; index < instructions.Count; index++) { if (instructions[index].labels.Contains(label)) { return this; } } MarkInvalid(); return this; } public ILInjector GoToMatchEnd() { index = matchEnd; return this; } public ILInjector GoToLastMatchedInstruction() { if (!IsIndexValid(matchEnd)) { return this; } index = matchEnd - 1; return this; } private bool IsIndexValid(int index) { return index != -1; } private bool IsIndexInRange(int index) { if (index >= 0) { return index < instructions.Count; } return false; } public CodeInstruction GetRelativeInstruction(int offset) { if (!IsValid) { throw new InvalidOperationException("Injector is invalid"); } int num = index + offset; if (!IsIndexInRange(num)) { throw new IndexOutOfRangeException($"Offset {offset} would read out of bounds at index {num}"); } return instructions[num]; } public ILInjector SetRelativeInstruction(int offset, CodeInstruction instruction) { if (!IsValid) { throw new InvalidOperationException("Injector is invalid"); } int num = index + offset; if (!IsIndexInRange(num)) { throw new IndexOutOfRangeException($"Offset {offset} would write out of bounds at index {num}"); } instructions[num] = instruction; return this; } [IteratorStateMachine(typeof(d__31))] public IEnumerable GetRelativeInstructions(int offset, int size) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__31(-2) { <>4__this = this, <>3__offset = offset, <>3__size = size }; } public IEnumerable GetRelativeInstructions(int size) { return GetRelativeInstructions(0, size); } private void GetLastMatchRangeAbsolute(out int start, out int end) { start = index; end = matchEnd; if (start > end) { int num = end; int num2 = start; start = num; end = num2; } } private void GetLastMatchRange(out int start, out int size) { GetLastMatchRangeAbsolute(out start, out var end); if (start < 0 || start >= instructions.Count) { throw new InvalidOperationException($"Last match range starts at invalid index {start}"); } if (end < 0 || end > instructions.Count) { throw new InvalidOperationException($"Last match range ends at invalid index {end}"); } size = end - start; } public List GetLastMatch() { GetLastMatchRange(out var start, out var size); return instructions.GetRange(start, size); } public ILInjector DefineLabel(out Label label) { if (generator == null) { throw new InvalidOperationException("No ILGenerator was provided"); } label = generator.DefineLabel(); return this; } public ILInjector AddLabel(out Label label) { DefineLabel(out label); return AddLabel(label); } public ILInjector AddLabel(Label label) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown Instruction = new CodeInstruction(Instruction); Instruction.labels.Add(label); return this; } public ILInjector InsertInPlace(params CodeInstruction[] instructions) { if (!IsValid) { throw new InvalidOperationException("Injector is invalid"); } this.instructions.InsertRange(index, instructions); if (matchEnd >= index) { matchEnd += instructions.Length; } return this; } public ILInjector Insert(params CodeInstruction[] instructions) { InsertInPlace(instructions); index += instructions.Length; return this; } public ILInjector InsertInPlaceAfterBranch(params CodeInstruction[] instructions) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown if (!IsValid) { throw new InvalidOperationException("Injector is invalid"); } List