using System;
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.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.3")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("3.0.3.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]
[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.5.0")]
[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.5.0";
internal static readonly Harmony Harmony = new Harmony("Zaggy1024.TwoRadarMaps");
public static ConfigEntry<FilterMode> TextureFiltering;
public static ConfigEntry<int> BodyCamHorizontalResolution;
public static ConfigEntry<bool> EnableZoom;
public static ConfigEntry<string> ZoomLevels;
public static ConfigEntry<int> DefaultZoomLevel;
public static ConfigEntry<bool> EnableTeleportCommand;
public static ConfigEntry<bool> EnableTeleportCommandShorthand;
private const string DEFAULT_ZOOM_LEVELS = "19.7, 29.55, 39.4";
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 Plugin Instance { get; private set; }
public ManualLogSource Logger => ((BaseUnityPlugin)this).Logger;
public void Awake()
{
Instance = this;
TextureFiltering = ((BaseUnityPlugin)this).Config.Bind<FilterMode>("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<int>("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<bool>("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<string>("Zoom", "Sizes", "19.7, 29.55, 39.4", "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 19.7.");
ZoomLevels.SettingChanged += delegate
{
UpdateZoomFactors();
};
DefaultZoomLevel = ((BaseUnityPlugin)this).Config.Bind<int>("Zoom", "DefaultLevel", 0, "The zoom factor to select by default. The first zoom level is 0.");
EnableTeleportCommand = ((BaseUnityPlugin)this).Config.Bind<bool>("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<bool>("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();
};
Harmony.PatchAll(typeof(PatchTerminal));
Harmony.PatchAll(typeof(PatchVanillaBugs));
Harmony.PatchAll(typeof(PatchManualCameraRenderer));
Harmony.PatchAll(typeof(PatchShipTeleporter));
RenderPipelineManager.beginCameraRendering += BeforeCameraRendering;
OpenBodyCamsCompatibility.Initialize();
EnhancedRadarBoosterCompatibility.Initialize(Harmony);
}
public static void BeforeCameraRendering(ScriptableRenderContext context, Camera camera)
{
ManualCameraRenderer val = StartOfRound.Instance?.mapScreen;
if ((Object)(object)val == (Object)null)
{
return;
}
ManualCameraRenderer val2 = null;
((Behaviour)val.mapCameraLight).enabled = false;
if ((Object)(object)camera == (Object)(object)val.cam)
{
val2 = val;
}
if ((Object)(object)TerminalMapRenderer != (Object)null)
{
((Behaviour)TerminalMapRenderer.mapCameraLight).enabled = false;
if ((Object)(object)camera == (Object)(object)TerminalMapRenderer.cam)
{
val2 = TerminalMapRenderer;
}
}
if (!((Object)(object)val2 == (Object)null))
{
((Behaviour)val2.mapCameraLight).enabled = true;
}
}
private static bool TargetIsValid(Transform targetTransform)
{
if ((Object)(object)targetTransform == (Object)null)
{
return false;
}
PlayerControllerB val = default(PlayerControllerB);
if (!((Component)((Component)targetTransform).transform).TryGetComponent<PlayerControllerB>(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<PlayerControllerB>();
}
}
internal static int GetNextValidTarget(List<TransformAndName> 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("19.7, 29.55, 39.4");
}
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<TerminalKeyword> newTerminalKeywords = new List<TerminalKeyword>();
private static readonly List<TerminalKeyword> modifiedTerminalKeywords = new List<TerminalKeyword>();
private static readonly List<(TerminalNode, string)> appendedDescriptions = new List<(TerminalNode, string)>();
public static void Initialize()
{
//IL_0142: Unknown result type (might be due to invalid IL or missing references)
//IL_0147: Unknown result type (might be due to invalid IL or missing references)
//IL_014e: Unknown result type (might be due to invalid IL or missing references)
//IL_015a: Expected O, but got Unknown
//IL_015c: Unknown result type (might be due to invalid IL or missing references)
//IL_0161: Unknown result type (might be due to invalid IL or missing references)
//IL_0168: Unknown result type (might be due to invalid IL or missing references)
//IL_0174: Expected O, but got Unknown
//IL_01a8: 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_01b4: Unknown result type (might be due to invalid IL or missing references)
//IL_01c0: Expected O, but got Unknown
//IL_0238: Unknown result type (might be due to invalid IL or missing references)
//IL_023d: Unknown result type (might be due to invalid IL or missing references)
//IL_0244: Unknown result type (might be due to invalid IL or missing references)
//IL_0250: 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<TerminalNode>();
((Object)CycleZoomNode).name = "CycleZoomNode";
CycleZoomNode.displayText = "";
CycleZoomNode.clearPreviousText = true;
ZoomInNode = ScriptableObject.CreateInstance<TerminalNode>();
((Object)ZoomInNode).name = "ZoomIn";
ZoomInNode.displayText = "";
ZoomInNode.clearPreviousText = true;
ZoomOutNode = ScriptableObject.CreateInstance<TerminalNode>();
((Object)ZoomOutNode).name = "ZoomOut";
ZoomOutNode.displayText = "";
ZoomOutNode.clearPreviousText = true;
ResetZoomNode = ScriptableObject.CreateInstance<TerminalNode>();
((Object)ResetZoomNode).name = "ResetZoom";
ResetZoomNode.displayText = "";
ResetZoomNode.clearPreviousText = true;
TerminalKeyword noun = FindOrCreateKeyword("In", "in", verb: false);
TerminalKeyword noun2 = FindOrCreateKeyword("Out", "out", verb: false);
FindOrCreateKeyword("Zoom", "zoom", verb: true, (CompatibleNoun[])(object)new CompatibleNoun[2]
{
new CompatibleNoun
{
noun = noun,
result = ZoomInNode
},
new CompatibleNoun
{
noun = noun2,
result = ZoomOutNode
}
}).specialKeywordResult = CycleZoomNode;
TerminalKeyword noun3 = FindOrCreateKeyword("Zoom", "zoom", verb: false);
FindOrCreateKeyword("Reset", "reset", verb: true, (CompatibleNoun[])(object)new CompatibleNoun[1]
{
new CompatibleNoun
{
noun = noun3,
result = 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<TerminalNode>();
((Object)TeleportNode).name = "TeleportNode";
TeleportNode.clearPreviousText = true;
TerminalKeyword noun4 = FindOrCreateKeyword("Teleporter", "teleporter", verb: false);
FindOrCreateKeyword("Activate", "activate", verb: true, (CompatibleNoun[])(object)new CompatibleNoun[1]
{
new CompatibleNoun
{
noun = noun4,
result = 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<TerminalKeyword>)Plugin.Terminal.terminalNodes.allKeywords).FirstOrDefault((Func<TerminalKeyword, bool>)((TerminalKeyword keyword) => keyword.word == word && keyword.isVerb == verb));
}
private static CompatibleNoun FindCompatibleNoun(this TerminalKeyword keyword, string noun)
{
return ((IEnumerable<CompatibleNoun>)keyword.compatibleNouns).FirstOrDefault((Func<CompatibleNoun, bool>)((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<TerminalKeyword>();
((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>();
CompatibleNoun[] array2 = compatibleNouns ?? Array.Empty<CompatibleNoun>();
int num = 0;
CompatibleNoun[] array3 = (CompatibleNoun[])(object)new CompatibleNoun[array.Length + array2.Length];
ReadOnlySpan<CompatibleNoun> readOnlySpan = new ReadOnlySpan<CompatibleNoun>(array);
readOnlySpan.CopyTo(new Span<CompatibleNoun>(array3).Slice(num, readOnlySpan.Length));
num += readOnlySpan.Length;
ReadOnlySpan<CompatibleNoun> readOnlySpan2 = new ReadOnlySpan<CompatibleNoun>(array2);
readOnlySpan2.CopyTo(new Span<CompatibleNoun>(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<TerminalKeyword> list = newTerminalKeywords;
int num = 0;
TerminalKeyword[] array = (TerminalKeyword[])(object)new TerminalKeyword[allKeywords.Length + list.Count];
ReadOnlySpan<TerminalKeyword> readOnlySpan = new ReadOnlySpan<TerminalKeyword>(allKeywords);
readOnlySpan.CopyTo(new Span<TerminalKeyword>(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)
{
List<CompatibleNoun> list = new List<CompatibleNoun>();
list.AddRange(modifiedTerminalKeyword.compatibleNouns.Where((CompatibleNoun compatible) => !newTerminalKeywords.Contains(compatible.noun)));
modifiedTerminalKeyword.compatibleNouns = list.ToArray();
}
}
modifiedTerminalKeywords.Clear();
foreach (TerminalKeyword newTerminalKeyword in newTerminalKeywords)
{
Object.Destroy((Object)(object)newTerminalKeyword);
}
TerminalNodesList terminalNodes = Plugin.Terminal.terminalNodes;
List<TerminalKeyword> list2 = new List<TerminalKeyword>();
list2.AddRange(terminalNodes.allKeywords.Where((TerminalKeyword keyword) => !newTerminalKeywords.Contains(keyword)));
terminalNodes.allKeywords = list2.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
{
private const string INVALID = "Injector is invalid";
private List<CodeInstruction> 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<CodeInstruction> Instructions => instructions.AsReadOnly();
public ILInjector(IEnumerable<CodeInstruction> 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))
{
Debug.Log((object)$"Default label.\n{new StackTrace()}");
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;
}
public IEnumerable<CodeInstruction> GetRelativeInstructions(int offset, int size)
{
for (int i = 0; i < size; i++)
{
yield return instructions[index + offset + i];
}
}
public IEnumerable<CodeInstruction> 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<CodeInstruction> 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<Label> labels = Instruction.labels;
Instruction = new CodeInstruction(Instruction);
Instruction.labels.Clear();
this.instructions.InsertRange(index, instructions);
Instruction.labels.AddRange(labels);
if (matchEnd >= index)
{
matchEnd += instructions.Length;
}
return this;
}
public ILInjector InsertAfterBranch(params CodeInstruction[] instructions)
{
InsertInPlaceAfterBranch(instructions);
index += instructions.Length;
return this;
}
public ILInjector RemoveAllPreviousInstructions()
{
if (!IsValid)
{
throw new InvalidOperationException("Injector is invalid");
}
instructions.RemoveRange(0, index);
matchEnd -= index;
if (matchEnd < 0)
{
matchEnd = 0;
}
index = 0;
return this;
}
public ILInjector Remove(int count = 1)
{
if (!IsValid)
{
throw new InvalidOperationException("Injector is invalid");
}
instructions.RemoveRange(index, count);
if (matchEnd > index)
{
matchEnd = Math.Max(index, matchEnd - count);
}
return this;
}
public ILInjector RemoveLastMatch()
{
GetLastMatchRange(out var start, out var size);
instructions.RemoveRange(start, size);
index = start;
matchEnd = start;
return this;
}
public ILInjector ReplaceLastMatch(params CodeInstruction[] replacementInstructions)
{
if (replacementInstructions.Length == 0)
{
throw new ArgumentException("Cannot replace a match with an empty array.");
}
GetLastMatchRange(out var start, out var size);
List<Label> labels = instructions[start].labels;
instructions.RemoveRange(start, size);
instructions.InsertRange(start, replacementInstructions);
index = start;
matchEnd = start + replacementInstructions.Length;
instructions[start].labels.AddRange(labels);
return this;
}
public List<CodeInstruction> ReleaseInstructions()
{
List<CodeInstruction> result = instructions;
instructions = null;
return result;
}
public ILInjector PrintContext(int context, string header = "")
{
if (!IsValid)
{
throw new InvalidOperationException("Injector is invalid (" + header + ")");
}
StringBuilder stringBuilder = new StringBuilder(header);
if (header.Length > 0)
{
stringBuilder.Append(':');
}
stringBuilder.AppendLine();
GetLastMatchRangeAbsolute(out var start, out var end);
int num = Math.Min(end + 1 + context, instructions.Count);
for (int i = Math.Max(start - context, 0); i < num; i++)
{
if (end == -1 && i == index)
{
stringBuilder.Append("╶> ");
}
else
{
if (i >= start && i < end)
{
stringBuilder.Append("│");
}
else
{
stringBuilder.Append(" ");
}
if (i == index)
{
stringBuilder.Append("╶> ");
}
else
{
stringBuilder.Append(" ");
}
}
stringBuilder.AppendLine($"{i}: {instructions[i]}");
}
Plugin.Instance.Logger.LogInfo((object)stringBuilder);
return this;
}
public ILInjector PrintContext(string header = "")
{
return PrintContext(4, header);
}
}
internal interface ILMatcher
{
bool Matches(CodeInstruction instruction);
ILMatcher CaptureAs(out CodeInstruction variable)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: Expected O, but got Unknown
variable = new CodeInstruction(OpCodes.Nop, (object)null);
return new InstructionCapturingMatcher(this, variable);
}
unsafe ILMatcher CaptureLabelOperandAs(out Label label)
{
label = default(Label);
fixed (Label* label2 = &label)
{
return new LabelCapturingMatcher(this, label2);
}
}
static ILMatcher Not(ILMatcher matcher)
{
return new NotMatcher(matcher);
}
static ILMatcher Opcode(OpCode opcode)
{
return new OpcodeMatcher(opcode);
}
static ILMatcher Opcodes(params OpCode[] opcodes)
{
return new OpcodesMatcher(opcodes);
}
static ILMatcher OpcodeOperand(OpCode opcode, object operand)
{
return new OpcodeOperandMatcher(opcode, operand);
}
static ILMatcher Instruction(CodeInstruction instruction)
{
return new InstructionMatcher(instruction);
}
static ILMatcher Ldarg(int? arg = null)
{
return new LdargMatcher(arg);
}
static ILMatcher Ldloc(int? loc = null)
{
return new LdlocMatcher(loc);
}
static ILMatcher Stloc(int? loc = null)
{
return new StlocMatcher(loc);
}
static ILMatcher Ldc(int? value = null)
{
return new LdcI32Matcher(value);
}
static ILMatcher Branch()
{
return new BranchMatcher();
}
static ILMatcher Ldfld(FieldInfo field)
{
if (field == null)
{
Plugin.Instance.Logger.LogWarning((object)$"Field passed to ILMatcher.Ldfld() was null\n{new StackTrace()}");
}
return new OpcodeOperandMatcher(OpCodes.Ldfld, field);
}
static ILMatcher Ldsfld(FieldInfo field)
{
if (field == null)
{
Plugin.Instance.Logger.LogWarning((object)$"Field passed to ILMatcher.Ldsfld() was null\n{new StackTrace()}");
}
return new OpcodeOperandMatcher(OpCodes.Ldsfld, field);
}
static ILMatcher Stfld(FieldInfo field)
{
if (field == null)
{
Plugin.Instance.Logger.LogWarning((object)$"Field passed to ILMatcher.Stfld() was null\n{new StackTrace()}");
}
return new OpcodeOperandMatcher(OpCodes.Stfld, field);
}
static ILMatcher Stsfld(FieldInfo field)
{
if (field == null)
{
Plugin.Instance.Logger.LogWarning((object)$"Field passed to ILMatcher.Stsfld() was null\n{new StackTrace()}");
}
return new OpcodeOperandMatcher(OpCodes.Stsfld, field);
}
static ILMatcher Callvirt(MethodBase method)
{
if (method == null)
{
Plugin.Instance.Logger.LogWarning((object)$"Method passed to ILMatcher.Callvirt() was null\n{new StackTrace()}");
}
return OpcodeOperand(OpCodes.Callvirt, method);
}
static ILMatcher Call(MethodBase method)
{
if (method == null)
{
Plugin.Instance.Logger.LogWarning((object)$"Method passed to ILMatcher.Call() was null\n{new StackTrace()}");
}
return OpcodeOperand(OpCodes.Call, method);
}
static ILMatcher Predicate(Func<CodeInstruction, bool> predicate)
{
return new PredicateMatcher(predicate);
}
static ILMatcher Predicate(Func<FieldInfo, bool> predicate)
{
return new PredicateMatcher((CodeInstruction insn) => insn.operand is FieldInfo arg && predicate(arg));
}
}
internal class NotMatcher : ILMatcher
{
private readonly ILMatcher matcher;
public NotMatcher(ILMatcher matcher)
{
this.matcher = matcher;
base..ctor();
}
public bool Matches(CodeInstruction instruction)
{
return !matcher.Matches(instruction);
}
}
internal class OpcodeMatcher : ILMatcher
{
private readonly OpCode opcode;
public OpcodeMatcher(OpCode opcode)
{
this.opcode = opcode;
base..ctor();
}
public bool Matches(CodeInstruction instruction)
{
return instruction.opcode == opcode;
}
}
internal class OpcodesMatcher : ILMatcher
{
private readonly OpCode[] opcodes;
public OpcodesMatcher(OpCode[] opcodes)
{
this.opcodes = opcodes;
base..ctor();
}
public bool Matches(CodeInstruction instruction)
{
return opcodes.Contains(instruction.opcode);
}
}
internal class OpcodeOperandMatcher : ILMatcher
{
private readonly OpCode opcode;
private readonly object operand;
public OpcodeOperandMatcher(OpCode opcode, object operand)
{
this.opcode = opcode;
this.operand = operand;
base..ctor();
}
public bool Matches(CodeInstruction instruction)
{
if (instruction.opcode == opcode)
{
return instruction.operand == operand;
}
return false;
}
}
internal class InstructionMatcher : ILMatcher
{
private readonly OpCode opcode = instruction.opcode;
private readonly object operand = instruction.operand;
private readonly Label[] labels = instruction.labels.ToArray();
public InstructionMatcher(CodeInstruction instruction)
{
}
public bool Matches(CodeInstruction instruction)
{
if (instruction.opcode != opcode)
{
return false;
}
if (instruction.operand != operand)
{
return false;
}
if (instruction.labels.Count != labels.Length)
{
return false;
}
for (int i = 0; i < labels.Length; i++)
{
if (labels[i] != instruction.labels[i])
{
return false;
}
}
return true;
}
}
internal class LdargMatcher : ILMatcher
{
private readonly int? arg;
public LdargMatcher(int? arg)
{
this.arg = arg;
base..ctor();
}
public bool Matches(CodeInstruction instruction)
{
if (!arg.HasValue)
{
return instruction.GetLdargIndex().HasValue;
}
return instruction.GetLdargIndex() == arg;
}
}
internal class LdlocMatcher : ILMatcher
{
private readonly int? loc;
public LdlocMatcher(int? loc)
{
this.loc = loc;
base..ctor();
}
public bool Matches(CodeInstruction instruction)
{
if (!loc.HasValue)
{
return instruction.GetLdlocIndex().HasValue;
}
return instruction.GetLdlocIndex() == loc;
}
}
internal class StlocMatcher : ILMatcher
{
private readonly int? loc;
public StlocMatcher(int? loc)
{
this.loc = loc;
base..ctor();
}
public bool Matches(CodeInstruction instruction)
{
if (!loc.HasValue)
{
return instruction.GetStlocIndex().HasValue;
}
return instruction.GetStlocIndex() == loc;
}
}
internal class LdcI32Matcher : ILMatcher
{
private readonly int? value;
public LdcI32Matcher(int? value)
{
this.value = value;
base..ctor();
}
public bool Matches(CodeInstruction instruction)
{
if (value.HasValue || !instruction.GetLdcI32().HasValue)
{
return instruction.GetLdcI32() == value;
}
return true;
}
}
internal class BranchMatcher : ILMatcher
{
public bool Matches(CodeInstruction instruction)
{
Label? label = default(Label?);
return CodeInstructionExtensions.Branches(instruction, ref label);
}
}
internal class PredicateMatcher : ILMatcher
{
private readonly Func<CodeInstruction, bool> predicate;
public PredicateMatcher(Func<CodeInstruction, bool> predicate)
{
this.predicate = predicate;
base..ctor();
}
public bool Matches(CodeInstruction instruction)
{
return predicate(instruction);
}
}
internal class InstructionCapturingMatcher : ILMatcher
{
private readonly ILMatcher matcher;
private readonly CodeInstruction variable;
public InstructionCapturingMatcher(ILMatcher matcher, CodeInstruction variable)
{
this.matcher = matcher;
this.variable = variable;
base..ctor();
}
public bool Matches(CodeInstruction instruction)
{
bool num = matcher.Matches(instruction);
if (num)
{
variable.opcode = instruction.opcode;
variable.operand = instruction.operand;
CodeInstruction obj = variable;
List<ExceptionBlock> blocks = instruction.blocks;
List<ExceptionBlock> list = new List<ExceptionBlock>(blocks.Count);
list.AddRange(blocks);
obj.blocks = list;
CodeInstruction obj2 = variable;
List<Label> labels = instruction.labels;
List<Label> list2 = new List<Label>(labels.Count);
list2.AddRange(labels);
obj2.labels = list2;
}
return num;
}
}
internal class LabelCapturingMatcher : ILMatcher
{
private readonly ILMatcher matcher;
private unsafe readonly Label* label;
public unsafe LabelCapturingMatcher(ILMatcher matcher, Label* label)
{
this.matcher = matcher;
this.label = label;
base..ctor();
}
public unsafe bool Matches(CodeInstruction instruction)
{
bool num = matcher.Matches(instruction);
if (num)
{
*label = (Label)instruction.operand;
}
return num;
}
}
internal static class InstructionUtilities
{
public static CodeInstruction MakeLdarg(int index)
{
//IL_0076: Unknown result type (might be due to invalid IL or missing references)
//IL_007c: Expected O, but got Unknown
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Expected O, but got Unknown
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_003a: 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_0050: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Expected O, but got Unknown
//IL_0063: Unknown result type (might be due to invalid IL or missing references)
//IL_0069: Expected O, but got Unknown
if (index < 256)
{
return (CodeInstruction)(index switch
{
0 => (object)new CodeInstruction(OpCodes.Ldarg_0, (object)null),
1 => (object)new CodeInstruction(OpCodes.Ldarg_1, (object)null),
2 => (object)new CodeInstruction(OpCodes.Ldarg_2, (object)null),
3 => (object)new CodeInstruction(OpCodes.Ldarg_3, (object)null),
_ => (object)new CodeInstruction(OpCodes.Ldarg_S, (object)index),
});
}
return new CodeInstruction(OpCodes.Ldarg, (object)index);
}
public static int PopCount(this CodeInstruction instruction)
{
if (instruction.opcode == OpCodes.Call || instruction.opcode == OpCodes.Callvirt)
{
MethodInfo obj = (MethodInfo)instruction.operand;
int num = obj.GetParameters().Length;
if (!obj.IsStatic)
{
num++;
}
return num;
}
if (instruction.opcode == OpCodes.Ret)
{
return 1;
}
return instruction.opcode.StackBehaviourPop switch
{
StackBehaviour.Pop0 => 0,
StackBehaviour.Pop1 => 1,
StackBehaviour.Pop1_pop1 => 2,
StackBehaviour.Popi => 1,
StackBehaviour.Popi_pop1 => 2,
StackBehaviour.Popi_popi => 2,
StackBehaviour.Popi_popi8 => 2,
StackBehaviour.Popi_popi_popi => 3,
StackBehaviour.Popi_popr4 => 2,
StackBehaviour.Popi_popr8 => 2,
StackBehaviour.Popref => 1,
StackBehaviour.Popref_pop1 => 2,
StackBehaviour.Popref_popi => 2,
StackBehaviour.Popref_popi_popi => 3,
StackBehaviour.Popref_popi_popi8 => 3,
StackBehaviour.Popref_popi_popr4 => 3,
StackBehaviour.Popref_popi_popr8 => 3,
StackBehaviour.Popref_popi_popref => 3,
StackBehaviour.Varpop => throw new NotImplementedException($"Variable pop on non-call instruction '{instruction}'"),
StackBehaviour.Popref_popi_pop1 => 3,
_ => throw new NotSupportedException($"StackBehaviourPop of {instruction.opcode.StackBehaviourPop} was not a pop for instruction '{instruction}'"),
};
}
public static int PushCount(this CodeInstruction instruction)
{
if (instruction.opcode == OpCodes.Call || instruction.opcode == OpCodes.Callvirt)
{
if (((MethodInfo)instruction.operand).ReturnType == typeof(void))
{
return 0;
}
return 1;
}
return instruction.opcode.StackBehaviourPush switch
{
StackBehaviour.Push0 => 0,
StackBehaviour.Push1 => 1,
StackBehaviour.Push1_push1 => 2,
StackBehaviour.Pushi => 1,
StackBehaviour.Pushi8 => 1,
StackBehaviour.Pushr4 => 1,
StackBehaviour.Pushr8 => 1,
StackBehaviour.Pushref => 1,
StackBehaviour.Varpush => throw new NotImplementedException($"Variable push on non-call instruction '{instruction}'"),
_ => throw new NotSupportedException($"StackBehaviourPush of {instruction.opcode.StackBehaviourPush} was not a push for instruction '{instruction}'"),
};
}
public static int? GetLdargIndex(this CodeInstruction instruction)
{
OpCode opcode = instruction.opcode;
if (opcode == OpCodes.Ldarg_0)
{
return 0;
}
if (opcode == OpCodes.Ldarg_1)
{
return 1;
}
if (opcode == OpCodes.Ldarg_2)
{
return 2;
}
if (opcode == OpCodes.Ldarg_3)
{
return 3;
}
if (opcode == OpCodes.Ldarg || opcode == OpCodes.Ldarg_S)
{
return instruction.operand as int?;
}
return null;
}
public static int? GetLdlocIndex(this CodeInstruction instruction)
{
OpCode opcode = instruction.opcode;
if (opcode == OpCodes.Ldloc_0)
{
return 0;
}
if (opcode == OpCodes.Ldloc_1)
{
return 1;
}
if (opcode == OpCodes.Ldloc_2)
{
return 2;
}
if (opcode == OpCodes.Ldloc_3)
{
return 3;
}
if (opcode == OpCodes.Ldloc || opcode == OpCodes.Ldloc_S)
{
return (instruction.operand as LocalBuilder)?.LocalIndex;
}
return null;
}
public static int? GetStlocIndex(this CodeInstruction instruction)
{
OpCode opcode = instruction.opcode;
if (opcode == OpCodes.Stloc_0)
{
return 0;
}
if (opcode == OpCodes.Stloc_1)
{
return 1;
}
if (opcode == OpCodes.Stloc_2)
{
return 2;
}
if (opcode == OpCodes.Stloc_3)
{
return 3;
}
if (opcode == OpCodes.Stloc || opcode == OpCodes.Stloc_S)
{
return (instruction.operand as LocalBuilder)?.LocalIndex;
}
return null;
}
public static CodeInstruction LdlocToStloc(this CodeInstruction instruction)
{
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: 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
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: Expected O, but got Unknown
//IL_0065: Unknown result type (might be due to invalid IL or missing references)
//IL_006b: Expected O, but got Unknown
//IL_0090: Unknown result type (might be due to invalid IL or missing references)
//IL_0096: Expected O, but got Unknown
OpCode opcode = instruction.opcode;
if (opcode == OpCodes.Ldloc_0)
{
return new CodeInstruction(OpCodes.Stloc_0, (object)null);
}
if (opcode == OpCodes.Ldloc_1)
{
return new CodeInstruction(OpCodes.Stloc_1, (object)null);
}
if (opcode == OpCodes.Ldloc_2)
{
return new CodeInstruction(OpCodes.Stloc_2, (object)null);
}
if (opcode == OpCodes.Ldloc_3)
{
return new CodeInstruction(OpCodes.Stloc_3, (object)null);
}
if (opcode == OpCodes.Ldloc || opcode == OpCodes.Ldloc_S)
{
return new CodeInstruction(OpCodes.Stloc, instruction.operand);
}
return null;
}
public static CodeInstruction StlocToLdloc(this CodeInstruction instruction)
{
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: 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
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: Expected O, but got Unknown
//IL_0065: Unknown result type (might be due to invalid IL or missing references)
//IL_006b: Expected O, but got Unknown
//IL_0090: Unknown result type (might be due to invalid IL or missing references)
//IL_0096: Expected O, but got Unknown
OpCode opcode = instruction.opcode;
if (opcode == OpCodes.Stloc_0)
{
return new CodeInstruction(OpCodes.Ldloc_0, (object)null);
}
if (opcode == OpCodes.Stloc_1)
{
return new CodeInstruction(OpCodes.Ldloc_1, (object)null);
}
if (opcode == OpCodes.Stloc_2)
{
return new CodeInstruction(OpCodes.Ldloc_2, (object)null);
}
if (opcode == OpCodes.Stloc_3)
{
return new CodeInstruction(OpCodes.Ldloc_3, (object)null);
}
if (opcode == OpCodes.Stloc || opcode == OpCodes.Stloc_S)
{
return new CodeInstruction(OpCodes.Ldloc, instruction.operand);
}
return null;
}
public static int? GetLdcI32(this CodeInstruction instruction)
{
OpCode opcode = instruction.opcode;
if (opcode == OpCodes.Ldc_I4_M1)
{
return -1;
}
if (opcode == OpCodes.Ldc_I4_0)
{
return 0;
}
if (opcode == OpCodes.Ldc_I4_1)
{
return 1;
}
if (opcode == OpCodes.Ldc_I4_2)
{
return 2;
}
if (opcode == OpCodes.Ldc_I4_3)
{
return 3;
}
if (opcode == OpCodes.Ldc_I4_4)
{
return 4;
}
if (opcode == OpCodes.Ldc_I4_5)
{
return 5;
}
if (opcode == OpCodes.Ldc_I4_6)
{
return 6;
}
if (opcode == OpCodes.Ldc_I4_7)
{
return 7;
}
if (opcode == OpCodes.Ldc_I4_8)
{
return 8;
}
if (opcode == OpCodes.Ldc_I4_S)
{
return instruction.operand as sbyte?;
}
if (opcode == OpCodes.Ldc_I4)
{
return instruction.operand as int?;
}
return null;
}
}
}
namespace TwoRadarMaps.Patches
{
internal static class Common
{
public static ILInjector ReplaceMainMapWithTerminalMap(this ILInjector injector)
{
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Expected O, but got Unknown
injector.GoToStart();
while (true)
{
injector.Find(ILMatcher.Call(Reflection.m_StartOfRound_Instance), ILMatcher.Ldfld(Reflection.f_StartOfRound_mapScreen));
if (!injector.IsValid)
{
break;
}
injector.ReplaceLastMatch(new CodeInstruction(OpCodes.Ldsfld, (object)Reflection.f_Plugin_terminalMapRenderer));
}
return injector.GoToStart();
}
internal static ILInjector InsertTerminalField(this ILInjector injector, CodeInstruction loadRenderer, FieldInfo vanillaStartOfRoundField, FieldInfo pluginField)
{
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_0059: Expected O, but got Unknown
//IL_0066: Unknown result type (might be due to invalid IL or missing references)
//IL_006c: Expected O, but got Unknown
//IL_0090: Unknown result type (might be due to invalid IL or missing references)
//IL_0096: Expected O, but got Unknown
//IL_009e: Unknown result type (might be due to invalid IL or missing references)
//IL_00b6: Expected O, but got Unknown
injector.GoToStart();
while (true)
{
injector.Find(ILMatcher.Call(Reflection.m_StartOfRound_Instance), ILMatcher.Ldfld(vanillaStartOfRoundField));
if (!injector.IsValid)
{
break;
}
injector.DefineLabel(out var label).Insert(loadRenderer, new CodeInstruction(OpCodes.Ldsfld, (object)Reflection.f_Plugin_terminalMapRenderer), new CodeInstruction(OpCodes.Beq_S, (object)label)).GoToMatchEnd()
.AddLabel(out var label2)
.Insert(new CodeInstruction(OpCodes.Br_S, (object)label2), CodeInstructionExtensions.WithLabels(new CodeInstruction(OpCodes.Ldsfld, (object)pluginField), new Label[1] { label }));
}
return injector.GoToStart();
}
}
[HarmonyPatch(typeof(ManualCameraRenderer))]
internal static class PatchManualCameraRenderer
{
[HarmonyPatch(/*Could not decode attribute arguments.*/)]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> updateMapTargetTranspiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: Expected O, but got Unknown
return new ILInjector(instructions, generator).InsertTerminalField(new CodeInstruction(OpCodes.Ldloc_1, (object)null), Reflection.f_StartOfRound_mapScreenPlayerName, Reflection.f_Plugin_terminalMapScreenPlayerName).ReleaseInstructions();
}
[HarmonyPatch("MapCameraFocusOnPosition")]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> MapCameraFocusOnPositionTranspiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: Expected O, but got Unknown
return new ILInjector(instructions, generator).InsertTerminalField(new CodeInstruction(OpCodes.Ldarg_0, (object)null), Reflection.f_StartOfRound_radarCanvas, Reflection.f_Plugin_terminalMapScreenUICanvas).ReleaseInstructions();
}
[HarmonyPatch("ChangeNameOfTargetTransform")]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> ChangeNameOfTargetTransformTranspiler(IEnumerable<CodeInstruction> instructions)
{
//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
//IL_00d0: Expected O, but got Unknown
CodeInstruction variable;
ILInjector iLInjector = new ILInjector(instructions).Find(ILMatcher.Ldarg(0), ILMatcher.Ldfld(Reflection.f_ManualCameraRenderer_radarTargets), ILMatcher.Ldloc().CaptureAs(out variable), ILMatcher.Callvirt(Reflection.m_List_TransformAndName_get_Item), ILMatcher.Ldarg(), ILMatcher.Stfld(Reflection.f_TransformAndName_name));
if (!iLInjector.IsValid)
{
Plugin.Instance.Logger.LogError((object)"Could not find setting of a radar target name in ManualCameraRenderer.ChangeNameOfTargetTransform().");
return instructions;
}
return iLInjector.Insert(variable, new CodeInstruction(OpCodes.Call, (object)Reflection.GetMethod(typeof(PatchManualCameraRenderer), "OnTargetNameChanged", BindingFlags.Static | BindingFlags.NonPublic, new Type[1] { typeof(int) }))).ReleaseInstructions();
}
private static void ApplyTargetNameChange(ManualCameraRenderer mapRenderer, int targetIndex)
{
if (targetIndex == mapRenderer.targetTransformIndex)
{
Plugin.StartTargetTransition(mapRenderer, mapRenderer.targetTransformIndex);
}
}
private static void OnTargetNameChanged(int targetIndex)
{
ApplyTargetNameChange(StartOfRound.Instance.mapScreen, targetIndex);
ApplyTargetNameChange(Plugin.TerminalMapRenderer, targetIndex);
}
[HarmonyPatch("RemoveTargetFromRadar")]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> RemoveTargetFromRadarTranspiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
//IL_0143: Unknown result type (might be due to invalid IL or missing references)
//IL_0149: Expected O, but got Unknown
//IL_0179: Unknown result type (might be due to invalid IL or missing references)
//IL_017f: Expected O, but got Unknown
CodeInstruction variable;
ILInjector iLInjector = new ILInjector(instructions, generator).Find(ILMatcher.Ldarg(0), ILMatcher.Ldfld(Reflection.f_ManualCameraRenderer_radarTargets), ILMatcher.Ldloc().CaptureAs(out variable), ILMatcher.Callvirt(typeof(List<TransformAndName>).GetMethod("RemoveAt", new Type[1] { typeof(int) })));
if (!iLInjector.IsValid)
{
Plugin.Instance.Logger.LogError((object)"Failed to find the removal of a target from the list in ManualCameraRenderer.RemoveTargetFromRadar.");
return instructions;
}
iLInjector.Find(ILMatcher.Ldarg(0), ILMatcher.Ldfld(typeof(ManualCameraRenderer).GetField("targetTransformIndex")), ILMatcher.Ldarg(0), ILMatcher.Ldfld(Reflection.f_ManualCameraRenderer_radarTargets), ILMatcher.Callvirt(typeof(List<TransformAndName>).GetMethod("get_Count")), ILMatcher.Opcode(OpCodes.Blt).CaptureLabelOperandAs(out var label)).FindLabel(label);
if (!iLInjector.IsValid)
{
Plugin.Instance.Logger.LogError((object)"No check for out-of-bounds target was found in ManualCameraRenderer.RemoveTargetFromRadar.");
return instructions;
}
return iLInjector.ReplaceLastMatch(new CodeInstruction(variable), new CodeInstruction(OpCodes.Call, (object)Reflection.GetMethod(typeof(PatchManualCameraRenderer), "RadarTargetWasRemoved", BindingFlags.Static | BindingFlags.NonPublic, new Type[1] { typeof(int) }))).ReleaseInstructions();
}
private static void FixUpRadarTargetRemovalFor(ManualCameraRenderer mapRenderer, int removedIndex)
{
bool flag = removedIndex <= mapRenderer.targetTransformIndex;
if (mapRenderer.targetTransformIndex >= mapRenderer.radarTargets.Count)
{
mapRenderer.targetTransformIndex--;
}
int nextValidTarget = Plugin.GetNextValidTarget(mapRenderer.radarTargets, mapRenderer.targetTransformIndex);
if (nextValidTarget == -1)
{
mapRenderer.targetedPlayer = null;
}
else if (flag)
{
Plugin.StartTargetTransition(mapRenderer, nextValidTarget);
}
}
private static void RadarTargetWasRemoved(int removedIndex)
{
FixUpRadarTargetRemovalFor(StartOfRound.Instance.mapScreen, removedIndex);
FixUpRadarTargetRemovalFor(Plugin.TerminalMapRenderer, removedIndex);
}
[HarmonyPatch("SyncOrderOfRadarBoostersInList")]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> SyncOrderOfRadarBoostersInListPostfix(IEnumerable<CodeInstruction> instructions)
{
foreach (CodeInstruction instruction in instructions)
{
if (CodeInstructionExtensions.StoresField(instruction, Reflection.f_ManualCameraRenderer_radarTargets))
{
yield return new CodeInstruction(OpCodes.Call, (object)Reflection.GetMethod(typeof(PatchManualCameraRenderer), "ApplySortedTargets", BindingFlags.Static | BindingFlags.NonPublic, new Type[2]
{
typeof(ManualCameraRenderer),
typeof(List<TransformAndName>)
}));
}
else
{
yield return instruction;
}
}
}
private static void OnTargetListResorted(ManualCameraRenderer mapRenderer, List<TransformAndName> sortedTargets)
{
int targetTransformIndex = mapRenderer.targetTransformIndex;
Transform transform = mapRenderer.radarTargets[targetTransformIndex].transform;
if (mapRenderer.radarTargets[targetTransformIndex] == sortedTargets[targetTransformIndex])
{
return;
}
for (int i = 0; i < sortedTargets.Count; i++)
{
if ((Object)(object)sortedTargets[i].transform == (Object)(object)transform)
{
Plugin.SetTargetIndex(mapRenderer, i);
return;
}
}
mapRenderer.radarTargets = sortedTargets;
int nextValidTarget = Plugin.GetNextValidTarget(sortedTargets, targetTransformIndex);
if (nextValidTarget != -1)
{
Plugin.StartTargetTransition(mapRenderer, nextValidTarget);
}
}
private static void ApplySortedTargets(ManualCameraRenderer _, List<TransformAndName> sortedTargets)
{
OnTargetListResorted(StartOfRound.Instance.mapScreen, sortedTargets);
OnTargetListResorted(Plugin.TerminalMapRenderer, sortedTargets);
StartOfRound.Instance.mapScreen.radarTargets = sortedTargets;
Plugin.TerminalMapRenderer.radarTargets = sortedTargets;
}
[HarmonyPatch("MeetsCameraEnabledConditions")]
[HarmonyPrefix]
private static bool MeetsCameraEnabledConditionsPrefix(ManualCameraRenderer __instance, ref bool __result)
{
if ((Object)(object)__instance != (Object)(object)Plugin.TerminalMapRenderer)
{
return true;
}
RawImage terminalImage = Plugin.Terminal.terminalImage;
__result = ((Behaviour)terminalImage).isActiveAndEnabled && (Object)(object)terminalImage.texture == (Object)(object)__instance.cam.targetTexture;
return false;
}
}
[HarmonyPatch(typeof(ShipTeleporter))]
internal static class PatchShipTeleporter
{
public static readonly MethodInfo m_NetworkManager_get_IsListening = typeof(NetworkManager).GetMethod("get_IsListening");
public static readonly MethodInfo m_WriteCurrentTarget = Reflection.GetMethod(typeof(PatchShipTeleporter), "WriteCurrentTargetIndex", BindingFlags.Static | BindingFlags.NonPublic, new Type[1] { typeof(FastBufferWriter) });
public static readonly MethodInfo m_ReadTargetIndexAndSet = Reflection.GetMethod(typeof(PatchShipTeleporter), "ReadTargetIndexAndSet", BindingFlags.Static | BindingFlags.NonPublic, new Type[1] { typeof(FastBufferReader) });
public static readonly MethodInfo m_Plugin_SetTargetIndex = Reflection.GetMethod(typeof(Plugin), "SetTargetIndex", BindingFlags.Static | BindingFlags.NonPublic, new Type[2]
{
typeof(ManualCameraRenderer),
typeof(int)
});
public static readonly MethodInfo m_ShipTeleporter_PressTeleportButtonServerRpcHandler = Reflection.GetMethod(typeof(ShipTeleporter), "__rpc_handler_389447712", BindingFlags.Static | BindingFlags.NonPublic, new Type[3]
{
typeof(NetworkBehaviour),
typeof(FastBufferReader),
typeof(__RpcParams)
});
public static readonly MethodInfo m_ShipTeleporter_PressTeleportButtonClientRpc = typeof(ShipTeleporter).GetMethod("PressTeleportButtonClientRpc", Array.Empty<Type>());
private static readonly MethodInfo m_TranspileRPCReceiveHAndlerToSetTarget = Reflection.GetMethod(typeof(PatchShipTeleporter), "TranspileRPCReceiveHandlerToSetTarget", BindingFlags.Static | BindingFlags.NonPublic, new Type[3]
{
typeof(IEnumerable<CodeInstruction>),
typeof(ILGenerator),
typeof(MethodBase)
});
private static readonly List<uint> rpcMessageIDs = new List<uint>(2);
[HarmonyPostfix]
[HarmonyPatch("OnEnable")]
private static void OnEnablePostfix(ShipTeleporter __instance)
{
if (!__instance.isInverseTeleporter)
{
Plugin.Teleporter = __instance;
}
}
[HarmonyPostfix]
[HarmonyPatch("OnDisable")]
private static void OnDisablePostfix(ShipTeleporter __instance)
{
if (!((Object)(object)__instance != (Object)(object)Plugin.Teleporter))
{
Plugin.Teleporter = null;
}
}
[HarmonyTranspiler]
[HarmonyPatch("PressTeleportButtonServerRpc")]
[HarmonyPatch("PressTeleportButtonClientRpc")]
private static IEnumerable<CodeInstruction> TranspileRPCSendToWriteTargetIndex(IEnumerable<CodeInstruction> instructions, MethodBase method)
{
//IL_010e: Unknown result type (might be due to invalid IL or missing references)
//IL_0114: Expected O, but got Unknown
CodeInstruction variable;
CodeInstruction variable2;
ILInjector iLInjector = new ILInjector(instructions).Find(ILMatcher.Ldarg(0), ILMatcher.Ldc().CaptureAs(out variable), ILMatcher.Ldloc(), ILMatcher.Ldc(), ILMatcher.Predicate((CodeInstruction insn) => insn.opcode == OpCodes.Call && ((MethodBase)insn.operand).Name.StartsWith("__beginSend")), ILMatcher.Stloc().CaptureAs(out variable2)).GoToMatchEnd();
if (!iLInjector.IsValid)
{
Plugin.Instance.Logger.LogError((object)("No call to __beginSend[..]() was found in " + method.DeclaringType.Name + "." + method.Name + "()."));
return instructions;
}
iLInjector.Insert(variable2.StlocToLdloc(), new CodeInstruction(OpCodes.Call, (object)m_WriteCurrentTarget));
rpcMessageIDs.Add((uint)(int)variable.operand);
return iLInjector.ReleaseInstructions();
}
[HarmonyPostfix]
[HarmonyPatch("InitializeRPCS_ShipTeleporter")]
private static void InitializeRPCS_ShipTeleporterPostfix()
{
PatchRPCReceiveHandlers(Plugin.Harmony);
}
private static void WriteCurrentTargetIndex(FastBufferWriter writer)
{
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
((FastBufferWriter)(ref writer)).WriteValue<int>(ref StartOfRound.Instance.mapScreen.targetTransformIndex, default(ForPrimitives));
}
private static void PatchRPCReceiveHandlers(Harmony harmony)
{
foreach (uint rpcMessageID in rpcMessageIDs)
{
MethodInfo methodInfo = ((Delegate)(object)NetworkManager.__rpc_func_table[rpcMessageID]).GetMethodInfo();
harmony.CreateProcessor((MethodBase)methodInfo).AddTranspiler(m_TranspileRPCReceiveHAndlerToSetTarget).Patch();
}
}
private static int ReadTargetIndexAndSet(FastBufferReader reader)
{
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
ManualCameraRenderer mapScreen = StartOfRound.Instance.mapScreen;
int targetTransformIndex = mapScreen.targetTransformIndex;
int targetIndex = default(int);
((FastBufferReader)(ref reader)).ReadValue<int>(ref targetIndex, default(ForPrimitives));
Plugin.SetTargetIndex(mapScreen, targetIndex);
return targetTransformIndex;
}
private static IEnumerable<CodeInstruction> TranspileRPCReceiveHandlerToSetTarget(IEnumerable<CodeInstruction> instructions, ILGenerator generator, MethodBase method)
{
//IL_00be: Unknown result type (might be due to invalid IL or missing references)
//IL_00c4: Expected O, but got Unknown
//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
//IL_00d6: Expected O, but got Unknown
//IL_00de: Unknown result type (might be due to invalid IL or missing references)
//IL_00e4: Expected O, but got Unknown
//IL_0168: Unknown result type (might be due to invalid IL or missing references)
//IL_016e: Expected O, but got Unknown
//IL_017a: Unknown result type (might be due to invalid IL or missing references)
//IL_0180: Expected O, but got Unknown
//IL_0188: Unknown result type (might be due to invalid IL or missing references)
//IL_018e: Expected O, but got Unknown
//IL_019a: Unknown result type (might be due to invalid IL or missing references)
//IL_01a0: Expected O, but got Unknown
Label label;
ILInjector iLInjector = new ILInjector(instructions).Find(ILMatcher.Ldloc(), ILMatcher.Callvirt(m_NetworkManager_get_IsListening), ILMatcher.Opcode(OpCodes.Brtrue).CaptureLabelOperandAs(out label)).FindLabel(label);
if (!iLInjector.IsValid)
{
Plugin.Instance.Logger.LogError((object)("No access of NetworkManager.IsListening was found in " + method.DeclaringType.Name + "." + method.Name + "()."));
return instructions;
}
LocalBuilder localBuilder = generator.DeclareLocal(typeof(int));
iLInjector.InsertAfterBranch(new CodeInstruction(OpCodes.Ldarg_1, (object)null), new CodeInstruction(OpCodes.Call, (object)m_ReadTargetIndexAndSet), new CodeInstruction(OpCodes.Stloc, (object)localBuilder)).Find(ILMatcher.Opcode(OpCodes.Ret));
if (!iLInjector.IsValid)
{
Plugin.Instance.Logger.LogError((object)("No return instruction was found in " + method.DeclaringType.Name + "." + method.Name + "()."));
return instructions;
}
return iLInjector.Insert(new CodeInstruction(OpCodes.Call, (object)Reflection.m_StartOfRound_Instance), new CodeInstruction(OpCodes.Ldfld, (object)Reflection.f_StartOfRound_mapScreen), new CodeInstruction(OpCodes.Ldloc, (object)localBuilder), new CodeInstruction(OpCodes.Call, (object)m_Plugin_SetTargetIndex)).ReleaseInstructions();
}
}
[HarmonyPatch(typeof(Terminal))]
internal static class PatchTerminal
{
[HarmonyPostfix]
[HarmonyPatch("Awake")]
public static void AwakePostfix(Terminal __instance)
{
Plugin.Terminal = __instance;
TerminalCommands.Initialize();
}
[HarmonyPrefix]
[HarmonyPatch("Start")]
private static void StartPrefix()
{
//IL_0349: Unknown result type (might be due to invalid IL or missing references)
//IL_034e: Unknown result type (might be due to invalid IL or missing references)
//IL_0359: Unknown result type (might be due to invalid IL or missing references)
//IL_035f: Unknown result type (might be due to invalid IL or missing references)
//IL_036e: Expected O, but got Unknown
GameObject gameObject = ((Component)Plugin.Terminal).gameObject;
GameObject val = GameObject.Find("Systems/GameSystems/ItemSystems");
if ((Object)(object)val == (Object)null)
{
Plugin.Instance.Logger.LogError((object)"Could not find the ItemSystems object.");
return;
}
Transform obj = val.transform.Find("MapCamera");
GameObject val2 = ((obj != null) ? ((Component)obj).gameObject : null);
if ((Object)(object)val2 == (Object)null)
{
Plugin.Instance.Logger.LogError((object)"Could not find the default map camera.");
return;
}
ManualCameraRenderer val3 = StartOfRound.Instance?.mapScreen;
if ((Object)(object)val3 == (Object)null)
{
Plugin.Instance.Logger.LogError((object)"Default map camera renderer is null.");
return;
}
Transform obj2 = val.transform.Find("MapScreenUI");
GameObject val4 = ((obj2 != null) ? ((Component)obj2).gameObject : null);
if ((Object)(object)val4 == (Object)null)
{
Plugin.Instance.Logger.LogError((object)"Could not find the map screen UI.");
return;
}
GameObject val5 = Object.Instantiate<GameObject>(val2, val.transform, false);
Camera val6 = ((val5 != null) ? val5.GetComponent<Camera>() : null);
if ((Object)(object)val6 == (Object)null)
{
Plugin.Instance.Logger.LogError((object)"Failed to clone the default map camera.");
return;
}
((Object)val5).name = "TerminalMapCamera";
GameObject val7 = Object.Instantiate<GameObject>(val4, val.transform, false);
Canvas val8 = ((val7 != null) ? val7.GetComponent<Canvas>() : null);
val8.worldCamera = val6;
if ((Object)(object)val8 == (Object)null)
{
Plugin.Instance.Logger.LogError((object)"Failed to clone the default map's UI.");
return;
}
((Object)val7).name = "TerminalMapScreenUI";
Transform obj3 = val7.transform.Find("PlanetVideoReel");
GameObject val9 = ((obj3 != null) ? ((Component)obj3).gameObject : null);
Transform obj4 = val7.transform.Find("PlanetDescription");
GameObject val10 = ((obj4 != null) ? ((Component)obj4).gameObject : null);
if ((Object)(object)val9 == (Object)null || (Object)(object)val10 == (Object)null)
{
Plugin.Instance.Logger.LogError((object)"Failed to delete duplicated planet description.");
return;
}
Object.Destroy((Object)(object)val9);
Object.Destroy((Object)(object)val10);
Transform obj5 = val7.transform.Find("ArrowUI");
GameObject val11 = ((obj5 != null) ? ((Component)obj5).gameObject : null);
Transform val12 = val11.transform.Find("ArrowContainer");
if ((Object)(object)val11 == (Object)null || (Object)(object)val12 == (Object)null)
{
Plugin.Instance.Logger.LogError((object)"Failed to get cloned ship arrow pointer.");
return;
}
Transform obj6 = val7.transform.Find("PlayerBeingMonitored");
TextMeshProUGUI val13 = ((obj6 != null) ? ((Component)obj6).GetComponent<TextMeshProUGUI>() : null);
((Behaviour)val13).enabled = true;
if ((Object)(object)val11 == (Object)null || (Object)(object)val12 == (Object)null)
{
Plugin.Instance.Logger.LogError((object)"Failed to get cloned 'MONITORING:' text UI.");
return;
}
Animator componentInChildren = val5.GetComponentInChildren<Animator>();
if ((Object)(object)componentInChildren == (Object)null)
{
Plugin.Instance.Logger.LogError((object)"Failed to find new map flash animation.");
return;
}
Light componentInChildren2 = val5.GetComponentInChildren<Light>();
if ((Object)(object)componentInChildren2 == (Object)null)
{
Plugin.Instance.Logger.LogError((object)"Failed to find new map night vision light.");
return;
}
GameObject obj7 = GameObject.Find("Environment/HangarShip/Terminal");
if ((Object)(object)((obj7 != null) ? obj7.GetComponentInChildren<MeshRenderer>() : null) == (Object)null)
{
Plugin.Instance.Logger.LogError((object)"Failed to find terminal object mesh.");
return;
}
ManualCameraRenderer val14 = gameObject.AddComponent<ManualCameraRenderer>();
val14.cam = val6;
val14.mapCamera = val6;
val14.cam.targetTexture = new RenderTexture(val3.cam.targetTexture)
{
name = "TerminalMapTexture",
filterMode = Plugin.TextureFiltering.Value
};
val14.shipArrowUI = val11;
val14.shipArrowPointer = val12;
val14.mapCameraAnimator = componentInChildren;
val14.mapCameraLight = componentInChildren2;
TerminalNode val15 = ((IEnumerable<CompatibleNoun>)((IEnumerable<TerminalKeyword>)Plugin.Terminal.terminalNodes.allKeywords).FirstOrDefault((Func<TerminalKeyword, bool>)((TerminalKeyword keyword) => keyword.word == "view"))?.compatibleNouns).FirstOrDefault((Func<CompatibleNoun, bool>)((CompatibleNoun noun) => noun.noun.word == "monitor"))?.result;
if ((Object)(object)val15 != (Object)null)
{
val15.displayTexture = (Texture)(object)val14.cam.targetTexture;
Plugin.Instance.Logger.LogInfo((object)("Terminal node '" + ((Object)val15).name + "' will now use a separate texture."));
}
Plugin.TerminalMapRenderer = val14;
Plugin.TerminalMapScreenUICanvas = val8;
Plugin.TerminalMapScreenPlayerName = val13;
val3.SyncOrderOfRadarBoostersInList();
Plugin.UpdateZoomFactors();
}
[HarmonyTranspiler]
[HarmonyPatch("RunTerminalEvents")]
[HarmonyPatch("ParsePlayerSentence")]
[HarmonyPatch("CheckForPlayerNameCommand")]
private static IEnumerable<CodeInstruction> TranspileRunTerminalEvents(IEnumerable<CodeInstruction> instructions)
{
return new ILInjector(instructions).ReplaceMainMapWithTerminalMap().ReleaseInstructions();
}
[HarmonyPrefix]
[HarmonyPatch("RunTerminalEvents")]
private static bool RunTerminalEventsPrefix(TerminalNode __0)
{
return TerminalCommands.ProcessNode(__0);
}
}
internal static class PatchVanillaBugs
{
[HarmonyFinalizer]
[HarmonyPatch(typeof(PlayerControllerB), "ConnectClientToPlayerObject")]
[HarmonyAfter(new string[] { "Zaggy1024.OpenBodyCams" })]
private static void ConnectClientToPlayerObjectPostfix()
{
UpdateMonitoredPlayerNames();
OpenBodyCamsCompatibility.InitializeAtStartOfGame();
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(PlayerControllerB), "SendNewPlayerValuesClientRpc")]
private static IEnumerable<CodeInstruction> SendNewPlayerValuesClientRpcTranspiler(IEnumerable<CodeInstruction> instructions)
{
//IL_00db: Unknown result type (might be due to invalid IL or missing references)
//IL_00e1: Expected O, but got Unknown
//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
//IL_00f3: Expected O, but got Unknown
//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
//IL_0105: Expected O, but got Unknown
//IL_0111: Unknown result type (might be due to invalid IL or missing references)
//IL_0117: Expected O, but got Unknown
//IL_012c: Unknown result type (might be due to invalid IL or missing references)
//IL_0132: Expected O, but got Unknown
//IL_013e: Unknown result type (might be due to invalid IL or missing references)
//IL_0144: Expected O, but got Unknown
//IL_0183: Unknown result type (might be due to invalid IL or missing references)
//IL_0189: Expected O, but got Unknown
CodeInstruction variable;
CodeInstruction variable2;
ILInjector iLInjector = new ILInjector(instructions).Find(ILMatcher.Call(Reflection.m_StartOfRound_Instance), ILMatcher.Ldfld(Reflection.f_StartOfRound_mapScreen), ILMatcher.Ldfld(Reflection.f_ManualCameraRenderer_radarTargets), ILMatcher.Ldloc().CaptureAs(out variable), ILMatcher.Callvirt(Reflection.m_List_TransformAndName_get_Item), ILMatcher.Ldloc().CaptureAs(out variable2), ILMatcher.Stfld(Reflection.f_TransformAndName_name));
if (!iLInjector.IsValid)
{
if (!Chainloader.PluginInfos.ContainsKey("mattymatty.LobbyControl"))
{
Plugin.Instance.Logger.LogWarning((object)"Failed to patch SendNewPlayerValuesClientRpc to set the correct transform index's name.");
Plugin.Instance.Logger.LogWarning((object)"LobbyControl is not installed, but another mod may have fixed this vanilla bug.");
}
return instructions;
}
return iLInjector.ReplaceLastMatch(new CodeInstruction(OpCodes.Call, (object)Reflection.m_StartOfRound_Instance), new CodeInstruction(OpCodes.Ldfld, (object)Reflection.f_StartOfRound_mapScreen), new CodeInstruction(OpCodes.Call, (object)Reflection.m_StartOfRound_Instance), new CodeInstruction(OpCodes.Ldfld, (object)Reflection.f_StartOfRound_allPlayerScripts), variable, new CodeInstruction(OpCodes.Ldelem, (object)typeof(PlayerControllerB)), new CodeInstruction(OpCodes.Call, (object)Reflection.m_Component_Transform), variable2, new CodeInstruction(OpCodes.Call, (object)typeof(ManualCameraRenderer).GetMethod("ChangeNameOfTargetTransform", new Type[2]
{
typeof(Transform),
typeof(string)
}))).ReleaseInstructions();
}
private static void UpdateMonitoredPlayerNames()
{
Plugin.EnsureAllMapRenderersHaveValidTargets();
}
[HarmonyPatch(typeof(StartOfRound), "OnClientConnect")]
[HarmonyTranspiler]
public static IEnumerable<CodeInstruction> OnClientConnectTranspiler(IEnumerable<CodeInstruction> instructions)
{
//IL_0078: Unknown result type (might be due to invalid IL or missing references)
//IL_007e: Expected O, but got Unknown
ILInjector iLInjector = new ILInjector(instructions).Find(ILMatcher.Call(typeof(StartOfRound).GetMethod("OnPlayerConnectedClientRpc", BindingFlags.Instance | BindingFlags.NonPublic))).GoToMatchEnd();
if (!iLInjector.IsValid)
{
Plugin.Instance.Logger.LogError((object)"Failed to find the call to OnPlayerConnectedClientRpc in StartOfRound.OnClientConnect().");
return instructions;
}
return iLInjector.Insert(new CodeInstruction(OpCodes.Call, (object)typeof(PatchVanillaBugs).GetMethod("SynchronizeMapTargetsToNewClient", BindingFlags.Static | BindingFlags.NonPublic))).ReleaseInstructions();
}
private static void SynchronizeMapTargetsToNewClient()
{
StartOfRound.Instance.mapScreen.SwitchRadarTargetClientRpc(StartOfRound.Instance.mapScreen.targetTransformIndex);
Plugin.TerminalMapRenderer.SwitchRadarTargetClientRpc(Plugin.TerminalMapRenderer.targetTransformIndex);
}
}
public static class Reflection
{
public static readonly MethodInfo m_Component_Transform = typeof(Component).GetMethod("get_transform");
public static readonly MethodInfo m_StartOfRound_Instance = typeof(StartOfRound).GetMethod("get_Instance");
public static readonly FieldInfo f_StartOfRound_allPlayerScripts = typeof(StartOfRound).GetField("allPlayerScripts");
public static readonly FieldInfo f_StartOfRound_mapScreen = typeof(StartOfRound).GetField("mapScreen");
public static readonly FieldInfo f_StartOfRound_mapScreenPlayerName = typeof(StartOfRound).GetField("mapScreenPlayerName");
public static readonly FieldInfo f_StartOfRound_radarCanvas = typeof(StartOfRound).GetField("radarCanvas");
public static readonly FieldInfo f_ManualCameraRenderer_radarTargets = typeof(ManualCameraRenderer).GetField("radarTargets");
public static readonly MethodInfo m_List_TransformAndName_get_Item = typeof(List<TransformAndName>).GetMethod("get_Item", new Type[1] { typeof(int) });
public static readonly FieldInfo f_Plugin_terminalMapRenderer = typeof(Plugin).GetField("TerminalMapRenderer");
public static readonly FieldInfo f_Plugin_terminalMapScreenUICanvas = typeof(Plugin).GetField("TerminalMapScreenUICanvas");
public static readonly FieldInfo f_Plugin_terminalMapScreenPlayerName = typeof(Plugin).GetField("TerminalMapScreenPlayerName");
public static readonly FieldInfo f_TransformAndName_name = typeof(TransformAndName).GetField("name");
public static readonly MethodInfo m_UnityEngine_Object_op_Equality = typeof(Object).GetMethod("op_Equality", new Type[2]
{
typeof(Object),
typeof(Object)
});
public static MethodInfo GetMethod(this Type type, string name, BindingFlags bindingFlags, Type[] parameters)
{
return type.GetMethod(name, bindingFlags, null, parameters, null);
}
public static MethodInfo GetGenericMethod(this Type type, string name, Type[] parameters, Type[] genericArgs)
{
MethodInfo[] methods = type.GetMethods();
foreach (MethodInfo methodInfo in methods)
{
if (!(methodInfo.Name != name) && methodInfo.IsGenericMethodDefinition)
{
return methodInfo.MakeGenericMethod(genericArgs);
}
}
return null;
}
}
}
namespace TwoRadarMaps.Compatibility
{
internal static class EnhancedRadarBoosterCompatibility
{
internal const string ENHANCED_RADAR_BOOSTER_MOD_ID = "MrHydralisk.EnhancedRadarBooster";
internal const string IMMERSIVE_COMPANY_MOD_ID = "ImmersiveCompany";
private static MethodInfo m_MapCameraFocusOnPositionPostfixTranspiler;
private static MethodInfo m_Camera_set_orthographicSize;
private static bool patchAppliedSuccessfully;
internal static void Initialize(Harmony harmony)
{
m_MapCameraFocusOnPositionPostfixTranspiler = Reflection.GetMethod(typeof(EnhancedRadarBoosterCompatibility), "MapCameraFocusOnPositionPostfixTranspiler", BindingFlags.Static | BindingFlags.NonPublic, new Type[3]
{
typeof(IEnumerable<CodeInstruction>),
typeof(ILGenerator),
typeof(MethodBase)
});
if (m_MapCameraFocusOnPositionPostfixTranspiler == null)
{
Plugin.Instance.Logger.LogError((object)"MapCameraFocusOnPositionPostfixTranspiler was not found.");
Plugin.Instance.Logger.LogError((object)"Patches for MrHydralisk.EnhancedRadarBooster and ImmersiveCompany cannot be applied.");
return;
}
m_Camera_set_orthographicSize = typeof(Camera).GetMethod("set_orthographicSize");
if (Chainloader.PluginInfos.ContainsKey("MrHydralisk.EnhancedRadarBooster"))
{
InitializeForEnhancedRadarBooster(harmony);
}
if (Chainloader.PluginInfos.ContainsKey("ImmersiveCompany"))
{
InitializeForImmersiveCompany(harmony);
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void InitializeForEnhancedRadarBooster(Harmony harmony)
{
MethodInfo method = typeof(HarmonyPatches).GetMethod("MCR_MapCameraFocusOnPosition_Postfix", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(ManualCameraRenderer) }, null);
if (method == null)
{
Plugin.Instance.Logger.LogError((object)"MrHydralisk.EnhancedRadarBooster is present, but MCR_MapCameraFocusOnPosition_Postfix was not found.");
return;
}
try
{
harmony.CreateProcessor((MethodBase)method).AddTranspiler(m_MapCameraFocusOnPositionPostfixTranspiler).Patch();
}
catch (Exception ex)
{
Plugin.Instance.Logger.LogError((object)"Failed to transpile MrHydralisk.EnhancedRadarBooster's MCR_MapCameraFocusOnPosition_Postfix");
Plugin.Instance.Logger.LogError((object)ex);
}
if (patchAppliedSuccessfully)
{
Plugin.Instance.Logger.LogInfo((object)"Finished patching EnhancedRadarBooster for compatibility with the zoom command.");
}
else
{
Plugin.Instance.Logger.LogError((object)"Failed to patch EnhancedRadarBooster for compatibility with the zoom command.");
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void InitializeForImmersiveCompany(Harmony harmony)
{
MethodInfo method = typeof(ManualCameraRendererPatch).GetMethod("MapCameraFocusPatch", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(ManualCameraRenderer) }, null);
if (method == null)
{
Plugin.Instance.Logger.LogError((object)"ImmersiveCompany is present, but MapCameraFocusPatch was not found.");
return;
}
try
{
harmony.CreateProcessor((MethodBase)method).AddTranspiler(m_MapCameraFocusOnPositionPostfixTranspiler).Patch();
}
catch (Exception ex)
{
Plugin.Instance.Logger.LogError((object)"Failed to transpile ImmersiveCompany's MapCameraFocusPatch");
Plugin.Instance.Logger.LogError((object)ex);
}
if (patchAppliedSuccessfully)
{
Plugin.Instance.Logger.LogInfo((object)"Finished patching ImmersiveCompany for compatibility with the zoom command.");
}
else
{
Plugin.Instance.Logger.LogError((object)"Failed to patch ImmersiveCompany for compatibility with the zoom command.");
}
}
private static IEnumerable<CodeInstruction> MapCameraFocusOnPositionPostfixTranspiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator, MethodBase method)
{
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: Expected O, but got Unknown
//IL_008f: Unknown result type (might be due to invalid IL or missing references)
//IL_0095: Expected O, but got Unknown
//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
//IL_00a8: Expected O, but got Unknown
//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
//IL_00b6: Expected O, but got Unknown
//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
//IL_00c8: Expected O, but got Unknown
//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
//IL_00da: Expected O, but got Unknown
//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
//IL_00ed: Expected O, but got Unknown
//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
//IL_0100: Expected O, but got Unknown
ILInjector iLInjector = new ILInjector(instructions, generator).InsertTerminalField(new CodeInstruction(OpCodes.Ldarg_0, (object)null), Reflection.f_StartOfRound_radarCanvas, Reflection.f_Plugin_terminalMapScreenUICanvas);
patchAppliedSuccessfully = false;
while (true)
{
iLInjector.Find(ILMatcher.Callvirt(m_Camera_set_orthographicSize));
if (!iLInjector.IsValid)
{
break;
}
iLInjector.Forward(1).AddLabel(out var label).Back(1)
.GoToPush(1)
.AddLabel(out var label2)
.Insert(new CodeInstruction(OpCodes.Ldsfld, (object)typeof(TerminalCommands).GetField("CycleZoomNode")), new CodeInstruction(OpCodes.Brfalse_S, (object)label2), new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Call, (object)Reflection.m_StartOfRound_Instance), new CodeInstruction(OpCodes.Ldfld, (object)Reflection.f_StartOfRound_mapScreen), new CodeInstruction(OpCodes.Beq_S, (object)label2), new CodeInstruction(OpCodes.Br_S, (object)label))
.Find(ILMatcher.Callvirt(m_Camera_set_orthographicSize))
.GoToMatchEnd();
patchAppliedSuccessfully = true;
}
return iLInjector.ReleaseInstructions();
}
}
internal static class LobbyControlCompatibility
{
internal const string MOD_ID = "mattymatty.LobbyControl";
}
internal static class OpenBodyCamsCompatibility
{
internal const string MOD_ID = "Zaggy1024.OpenBodyCams";
public static MonoBehaviour TerminalBodyCam;
private static bool ShouldUseCompatibilityMode()
{
if (!Chainloader.PluginInfos.ContainsKey("Zaggy1024.OpenBodyCams"))
{
return false;
}
if (Chainloader.PluginInfos["Zaggy1024.OpenBodyCams"].Metadata.Version < new Version(1, 2, 0))
{
return false;
}
return true;
}
internal static void Initialize()
{
if (ShouldUseCompatibilityMode())
{
InitializeInternal();
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void InitializeInternal()
{
Plugin.TerminalPiPBodyCamEnabled.SettingChanged += delegate
{
InitializeAtStartOfGameInternal();
};
Plugin.TerminalPiPPosition.SettingChanged += delegate
{
InitializeAtStartOfGameInternal();
};
Plugin.TerminalPiPWidth.SettingChanged += delegate
{
InitializeAtStartOfGameInternal();
};
}
internal static void InitializeAtStartOfGame()
{
if (ShouldUseCompatibilityMode())
{
InitializeAtStartOfGameInternal();
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void InitializeAtStartOfGameInternal()
{
Object.Destroy((Object)(object)TerminalBodyCam);
TerminalBodyCam = null;
if (!((Object)(object)TerminalCommands.PiPImage == (Object)null))
{
BodyCamComponent val = (BodyCamComponent)(object)(TerminalBodyCam = (MonoBehaviour)(object)BodyCam.CreateBodyCam(((Component)Plugin.Terminal).gameObject, (Material)null, Plugin.TerminalMapRenderer));
ShipObjects.MainBodyCam.OnRenderTextureCreated -= TerminalCommands.SetRenderTexture;
val.OnRenderTextureCreated += SetBodyCamTexture;
SetBodyCamTexture(val.GetCamera().targetTexture);
ShipObjects.MainBodyCam.OnBlankedSet -= TerminalCommands.SetBodyCamBlanked;
val.OnBlankedSet += SetBodyCamBlanked;
UpdateTerminalBodyCamSettings();
Plugin.BodyCamHorizontalResolution.SettingChanged += delegate
{
UpdateTerminalBodyCamSettings();
};
((Component)TerminalCommands.PiPImage).GetComponent<TerminalBodyCamVisibilityTracker>().BodyCamToActivate = val;
}
}
private static void UpdateTerminalBodyCamSettings()
{
try
{
UpdateTerminalBodyCamResolution();
}
catch
{
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void UpdateTerminalBodyCamResolution()
{
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
int value = Plugin.BodyCamHorizontalResolution.Value;
Vector2Int resolution = default(Vector2Int);
((Vector2Int)(ref resolution))..ctor(value, value * 3 / 4);
((BodyCamComponent)TerminalBodyCam).Resolution = resolution;
}
public static void UpdateBodyCamTexture()
{
UpdateBodyCamTextureInternal();
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void UpdateBodyCamTextureInternal()
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
SetBodyCamTexture(((BodyCamComponent)TerminalBodyCam).GetCamera().targetTexture);
}
private static void SetBodyCamTexture(RenderTexture texture)
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((Texture)texture).filterMode = Plugin.TextureFiltering.Value;
TerminalCommands.PiPImage.texture = (Texture)(object)texture;
}
private static void SetBodyCamBlanked(bool blanked)
{
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
((Graphic)TerminalCommands.PiPImage).color = (blanked ? Color.black : Color.white);
}
}
}
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
internal sealed class IgnoresAccessChecksToAttribute : Attribute
{
public IgnoresAccessChecksToAttribute(string assemblyName)
{
}
}
}