Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of AlliedDefenses v0.4.0
AlliedDefenses.dll
Decompiled 8 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using AlliedDefenses.Config; using AlliedDefenses.Core; using AlliedDefenses.Defenses; using AlliedDefenses.NetcodePatcher; using AlliedDefenses.Networking; using AlliedDefenses.UI; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using GameNetcodeStuff; using HarmonyLib; using Microsoft.CodeAnalysis; using Unity.Netcode; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("AlliedDefenses")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.4.0.0")] [assembly: AssemblyInformationalVersion("0.4.0+10500bfa76dcc5896caacbaa107916fcbd1098bb")] [assembly: AssemblyProduct("AlliedDefenses")] [assembly: AssemblyTitle("AlliedDefenses")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.4.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] [module: NetcodePatchedAssembly] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace AlliedDefenses { [BepInPlugin("Remilulz_91.AlliedDefenses", "AlliedDefenses", "0.4.0")] public class Plugin : BaseUnityPlugin { public const string Author = "Remilulz_91"; public const string Guid = "Remilulz_91.AlliedDefenses"; public const string Name = "AlliedDefenses"; public const string Version = "0.4.0"; private readonly Harmony _harmony = new Harmony("Remilulz_91.AlliedDefenses"); public static Plugin Instance { get; private set; } public static ManualLogSource Log { get; private set; } private void Awake() { Instance = this; Log = ((BaseUnityPlugin)this).Logger; ModConfig.Init(((BaseUnityPlugin)this).Config); try { _harmony.PatchAll(); DefenseRegistry.RegisterDefaults(); HijackTicker.EnsureExists(); Log.LogInfo((object)string.Format("{0} v{1} by {2} loaded. {3} defense module(s) active.", "AlliedDefenses", "0.4.0", "Remilulz_91", DefenseRegistry.Count)); } catch (Exception arg) { Log.LogError((object)$"Failed to apply Harmony patches: {arg}"); } } } public static class MyPluginInfo { public const string PLUGIN_GUID = "AlliedDefenses"; public const string PLUGIN_NAME = "AlliedDefenses"; public const string PLUGIN_VERSION = "0.4.0"; } } namespace AlliedDefenses.UI { public static class CommandText { private static string Keyword => ModConfig.HijackCommand.Value.Trim(); public static string Usage() { string keyword = Keyword; return "ALLIED DEFENSES\n-------------------------\n" + keyword + " <id> : hijack one defense by its id (turret or mine, e.g. " + keyword + " U9)\n" + keyword + " turrets : list all turrets and their ids\n" + keyword + " mines : list all mines and their ids\n" + keyword + " help : how the mod works\n" + keyword + " config : show the current settings\n"; } public static string HowItWorks() { string keyword = Keyword; StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("ALLIED DEFENSES - HOW IT WORKS"); stringBuilder.AppendLine("------------------------------------"); stringBuilder.AppendLine("Normally the facility defenses target YOU (the employees) and"); stringBuilder.AppendLine("ignore the monsters. This mod lets you flip that."); stringBuilder.AppendLine(""); stringBuilder.AppendLine("TURRETS:"); stringBuilder.AppendLine(" " + keyword + " turrets list all turrets and their ids."); stringBuilder.AppendLine(" " + keyword + " <id> hijack one turret (same id you'd use to disable it)."); stringBuilder.AppendLine(" An allied turret stops shooting players and instead aims at"); stringBuilder.AppendLine(" the nearest visible enemy in range."); stringBuilder.AppendLine(""); stringBuilder.AppendLine("MINES:"); stringBuilder.AppendLine(" " + keyword + " mines list all mines and their ids."); stringBuilder.AppendLine(" " + keyword + " <id> hijack one mine (same id you'd use to disable it)."); stringBuilder.AppendLine(" An allied mine no longer explodes under players; it detonates"); stringBuilder.AppendLine(" only when an enemy steps close to it."); stringBuilder.AppendLine(""); stringBuilder.AppendLine("All hijacks last for a set time, then the defense turns hostile"); stringBuilder.AppendLine("again. Everyone in the lobby must have the mod; effects are synced."); stringBuilder.AppendLine(""); stringBuilder.AppendLine("Type " + keyword + " config to see the exact current settings."); return stringBuilder.ToString(); } public static string CurrentConfig() { float value = ModConfig.HijackDuration.Value; string text = ((value > 0f) ? $"{value:0} seconds, then it turns hostile again" : "unlimited (stays allied until end of round)"); bool value2 = ModConfig.IgnorePlayersWhenAllied.Value; int value3 = ModConfig.HijackCreditCost.Value; string text2 = ((value3 > 0) ? $"{value3} credits per hijack" : "free"); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("ALLIED DEFENSES - CURRENT CONFIG"); stringBuilder.AppendLine("------------------------------------"); stringBuilder.AppendLine("Command keyword : " + Keyword); stringBuilder.AppendLine("Allied duration : " + text); stringBuilder.AppendLine($"Turret detect range : {ModConfig.EnemyDetectionRange.Value:0} meters"); stringBuilder.AppendLine($"Mine trigger radius : {ModConfig.MineTriggerRadius.Value:0} meters"); stringBuilder.AppendLine("Players can be hit : " + (value2 ? "NO - allied defenses never hurt players" : "yes - friendly fire is ON")); stringBuilder.AppendLine("Hijack cost : " + text2); stringBuilder.AppendLine("Allied colour cue : " + (ModConfig.ColorAlliedDefenses.Value ? "ON (green laser/light in dungeon, blue code on radar)" : "off")); stringBuilder.AppendLine(""); stringBuilder.AppendLine($"Defense types supported : {DefenseRegistry.Count}"); stringBuilder.AppendLine($"Currently hijacked : {HijackManager.ActiveCount}"); stringBuilder.AppendLine(""); stringBuilder.AppendLine("(Settings live in BepInEx/config/Remilulz_91.AlliedDefenses.cfg)"); return stringBuilder.ToString(); } } } namespace AlliedDefenses.Patches { [HarmonyPatch(typeof(Landmine))] public static class MinePatches { [HarmonyPrefix] [HarmonyPatch("OnTriggerEnter")] public static bool OnTriggerEnterPrefix(Landmine __instance, Collider other) { if (ShouldProtectPlayers(__instance) && ((Component)other).CompareTag("Player")) { return false; } return true; } [HarmonyPrefix] [HarmonyPatch("OnTriggerExit")] public static bool OnTriggerExitPrefix(Landmine __instance, Collider other) { if (ShouldProtectPlayers(__instance) && ((Component)other).CompareTag("Player")) { return false; } return true; } private static bool ShouldProtectPlayers(Landmine mine) { if (ModConfig.IgnorePlayersWhenAllied.Value) { return HijackManager.IsAllied((Component)(object)mine); } return false; } } [HarmonyPatch(typeof(Terminal))] public static class TerminalPatches { [HarmonyPrefix] [HarmonyPatch("ParsePlayerSentence")] public static bool ParsePrefix(Terminal __instance, ref TerminalNode __result) { string typedText = GetTypedText(__instance); if (string.IsNullOrWhiteSpace(typedText)) { return true; } typedText = typedText.Trim(); string text = ModConfig.HijackCommand.Value.Trim(); bool flag = typedText.Equals(text, StringComparison.OrdinalIgnoreCase); bool flag2 = typedText.StartsWith(text + " ", StringComparison.OrdinalIgnoreCase); if (!flag && !flag2) { return true; } string text2 = (flag ? "" : typedText.Substring(text.Length).Trim()); string typeId; string text3 = (string.IsNullOrEmpty(text2) ? CommandText.Usage() : ((!text2.Equals("help", StringComparison.OrdinalIgnoreCase) && !text2.Equals("howitworks", StringComparison.OrdinalIgnoreCase) && !text2.Equals("info", StringComparison.OrdinalIgnoreCase)) ? ((text2.Equals("config", StringComparison.OrdinalIgnoreCase) || text2.Equals("settings", StringComparison.OrdinalIgnoreCase)) ? CommandText.CurrentConfig() : ((!TryMatchGroup(text2, out typeId)) ? HijackManager.RequestHijack(text2) : HijackManager.ListDefenses(typeId))) : CommandText.HowItWorks())); __result = MakeNode(text3); return false; } private static bool TryMatchGroup(string arg, out string typeId) { string text = arg.Trim().ToLowerInvariant(); foreach (IHijackableDefense item in DefenseRegistry.All) { string text2 = item.TypeId.ToLowerInvariant(); string text3 = item.DisplayName.ToLowerInvariant(); if (text == text2 || text == text2 + "s" || text == text3 || text == text3 + "s") { typeId = item.TypeId; return true; } } typeId = ""; return false; } private static string GetTypedText(Terminal terminal) { try { object value = Traverse.Create((object)terminal).Field("screenText").GetValue(); string text = Traverse.Create(value).Property("text", (object[])null).GetValue<string>() ?? ""; int value2 = Traverse.Create((object)terminal).Field("textAdded").GetValue<int>(); if (value2 <= 0 || value2 > text.Length) { return ""; } return text.Substring(text.Length - value2); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not read terminal input: " + ex.Message)); return ""; } } private static TerminalNode MakeNode(string text) { TerminalNode val = ScriptableObject.CreateInstance<TerminalNode>(); val.displayText = text + "\n\n"; val.clearPreviousText = true; val.maxCharactersToType = 50; return val; } } [HarmonyPatch(typeof(Turret))] public static class TurretPatches { private static readonly TurretHijack _module = new TurretHijack(); [HarmonyPrefix] [HarmonyPatch("Update")] public static bool UpdatePrefix(Turret __instance) { if (!HijackManager.IsAllied((Component)(object)__instance)) { return true; } _module.DriveAlliedTurret(__instance); return false; } } } namespace AlliedDefenses.Networking { public class HijackNetworker : NetworkBehaviour { private static bool _warnedRpc; public static HijackNetworker? Instance { get; private set; } public static HijackNetworker? Active { get { if ((Object)(object)Instance != (Object)null) { return Instance; } Instance = Object.FindObjectOfType<HijackNetworker>(); return Instance; } } public override void OnNetworkSpawn() { Instance = this; ((NetworkBehaviour)this).OnNetworkSpawn(); Plugin.Log.LogInfo((object)"HijackNetworker ready (network active)."); } public override void OnNetworkDespawn() { if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } ((NetworkBehaviour)this).OnNetworkDespawn(); } private static void Safe(Action rpc) { try { rpc(); } catch (Exception ex) { if (!_warnedRpc) { _warnedRpc = true; Plugin.Log.LogWarning((object)("Networking note: an RPC could not be sent. This is harmless in solo and if the build isn't fully netcode-patched; multiplayer sync may be limited. (" + ex.Message + ")")); } } } public void RequestHijack(ulong netId, string typeId) { ApplyHijack(netId, typeId, allied: true); } public void RequestUnhijack(ulong netId, string typeId) { ApplyHijack(netId, typeId, allied: false); } private void ApplyHijack(ulong netId, string typeId, bool allied) { if (((NetworkBehaviour)this).IsServer) { HijackManager.ApplyHijack(netId, typeId, allied); Safe(delegate { ApplyHijackClientRpc(netId, typeId, allied); }); } else { Safe(delegate { RequestHijackServerRpc(netId, typeId, allied); }); } } [ServerRpc(RequireOwnership = false)] private void RequestHijackServerRpc(ulong netId, string typeId, bool allied) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)base.__rpc_exec_stage != 1 && (networkManager.IsClient || networkManager.IsHost)) { ServerRpcParams val2 = default(ServerRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendServerRpc(946746885u, val2, (RpcDelivery)0); BytePacker.WriteValueBitPacked(val, netId); bool flag = typeId != null; ((FastBufferWriter)(ref val)).WriteValueSafe<bool>(ref flag, default(ForPrimitives)); if (flag) { ((FastBufferWriter)(ref val)).WriteValueSafe(typeId, false); } ((FastBufferWriter)(ref val)).WriteValueSafe<bool>(ref allied, default(ForPrimitives)); ((NetworkBehaviour)this).__endSendServerRpc(ref val, 946746885u, val2, (RpcDelivery)0); } if ((int)base.__rpc_exec_stage == 1 && (networkManager.IsServer || networkManager.IsHost)) { base.__rpc_exec_stage = (__RpcExecStage)0; ulong netId2 = netId; string typeId2 = typeId; bool allied2 = allied; HijackManager.ApplyHijack(netId2, typeId2, allied2); Safe(delegate { ApplyHijackClientRpc(netId2, typeId2, allied2); }); } } [ClientRpc] private void ApplyHijackClientRpc(ulong netId, string typeId, bool allied) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)base.__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(4088680816u, val2, (RpcDelivery)0); BytePacker.WriteValueBitPacked(val, netId); bool flag = typeId != null; ((FastBufferWriter)(ref val)).WriteValueSafe<bool>(ref flag, default(ForPrimitives)); if (flag) { ((FastBufferWriter)(ref val)).WriteValueSafe(typeId, false); } ((FastBufferWriter)(ref val)).WriteValueSafe<bool>(ref allied, default(ForPrimitives)); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 4088680816u, val2, (RpcDelivery)0); } if ((int)base.__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost)) { base.__rpc_exec_stage = (__RpcExecStage)0; if (!((NetworkBehaviour)this).IsServer) { HijackManager.ApplyHijack(netId, typeId, allied); } } } protected override void __initializeVariables() { ((NetworkBehaviour)this).__initializeVariables(); } protected override void __initializeRpcs() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown ((NetworkBehaviour)this).__registerRpc(946746885u, new RpcReceiveHandler(__rpc_handler_946746885), "RequestHijackServerRpc"); ((NetworkBehaviour)this).__registerRpc(4088680816u, new RpcReceiveHandler(__rpc_handler_4088680816), "ApplyHijackClientRpc"); ((NetworkBehaviour)this).__initializeRpcs(); } private static void __rpc_handler_946746885(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = target.NetworkManager; if (networkManager != null && networkManager.IsListening) { ulong netId = default(ulong); ByteUnpacker.ReadValueBitPacked(reader, ref netId); bool flag = default(bool); ((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref flag, default(ForPrimitives)); string typeId = null; if (flag) { ((FastBufferReader)(ref reader)).ReadValueSafe(ref typeId, false); } bool allied = default(bool); ((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref allied, default(ForPrimitives)); target.__rpc_exec_stage = (__RpcExecStage)1; ((HijackNetworker)(object)target).RequestHijackServerRpc(netId, typeId, allied); target.__rpc_exec_stage = (__RpcExecStage)0; } } private static void __rpc_handler_4088680816(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = target.NetworkManager; if (networkManager != null && networkManager.IsListening) { ulong netId = default(ulong); ByteUnpacker.ReadValueBitPacked(reader, ref netId); bool flag = default(bool); ((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref flag, default(ForPrimitives)); string typeId = null; if (flag) { ((FastBufferReader)(ref reader)).ReadValueSafe(ref typeId, false); } bool allied = default(bool); ((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref allied, default(ForPrimitives)); target.__rpc_exec_stage = (__RpcExecStage)1; ((HijackNetworker)(object)target).ApplyHijackClientRpc(netId, typeId, allied); target.__rpc_exec_stage = (__RpcExecStage)0; } } [MethodImpl(MethodImplOptions.NoInlining)] protected internal override string __getTypeName() { return "HijackNetworker"; } } public static class NetcodePatcher { [RuntimeInitializeOnLoadMethod] private static void Init() { Type[] types = Assembly.GetExecutingAssembly().GetTypes(); Type[] array = types; foreach (Type type in array) { MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); MethodInfo[] array2 = methods; foreach (MethodInfo methodInfo in array2) { object[] customAttributes = methodInfo.GetCustomAttributes(typeof(RuntimeInitializeOnLoadMethodAttribute), inherit: false); if (customAttributes.Length != 0 && methodInfo.Name != "Init") { methodInfo.Invoke(null, null); } } } } } [HarmonyPatch] public static class NetworkObjectManager { private static GameObject? _networkPrefab; [HarmonyPostfix] [HarmonyPatch(typeof(GameNetworkManager), "Start")] public static void RegisterPrefab() { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Expected O, but got Unknown Plugin.Log.LogInfo((object)"NetworkObjectManager: GameNetworkManager.Start reached."); if ((Object)(object)_networkPrefab != (Object)null) { Plugin.Log.LogInfo((object)"NetworkObjectManager: prefab already created, skipping."); return; } try { if ((Object)(object)NetworkManager.Singleton == (Object)null) { Plugin.Log.LogError((object)"NetworkObjectManager: NetworkManager.Singleton is null; cannot register prefab."); return; } _networkPrefab = new GameObject("AlliedDefensesNetworkHandler"); Object.DontDestroyOnLoad((Object)(object)_networkPrefab); ((Object)_networkPrefab).hideFlags = (HideFlags)61; NetworkObject netObj = _networkPrefab.AddComponent<NetworkObject>(); _networkPrefab.AddComponent<HijackNetworker>(); AssignStableHash(netObj, "AlliedDefenses.HijackNetworker"); NetworkManager.Singleton.AddNetworkPrefab(_networkPrefab); Plugin.Log.LogInfo((object)"NetworkObjectManager: network prefab registered."); } catch (Exception arg) { Plugin.Log.LogError((object)$"NetworkObjectManager: failed to register prefab: {arg}"); } } [HarmonyPostfix] [HarmonyPatch(typeof(StartOfRound), "Start")] public static void SpawnHandler() { try { NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null) { Plugin.Log.LogWarning((object)"NetworkObjectManager: NetworkManager null at StartOfRound.Start."); return; } if (!singleton.IsHost && !singleton.IsServer) { Plugin.Log.LogInfo((object)"NetworkObjectManager: not the host; client will receive the handler from the host."); return; } if ((Object)(object)HijackNetworker.Instance != (Object)null) { Plugin.Log.LogInfo((object)"NetworkObjectManager: handler already spawned."); return; } if ((Object)(object)_networkPrefab == (Object)null) { Plugin.Log.LogError((object)"NetworkObjectManager: prefab is null (registration failed?); cannot spawn."); return; } GameObject val = Object.Instantiate<GameObject>(_networkPrefab); val.GetComponent<NetworkObject>().Spawn(false); Plugin.Log.LogInfo((object)"NetworkObjectManager: HijackNetworker spawned by the host."); } catch (Exception arg) { Plugin.Log.LogError((object)$"NetworkObjectManager: failed to spawn handler: {arg}"); } } private static void AssignStableHash(NetworkObject netObj, string key) { uint hashCode = (uint)key.GetHashCode(); FieldInfo field = typeof(NetworkObject).GetField("GlobalObjectIdHash", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field == null) { Plugin.Log.LogError((object)"NetworkObjectManager: GlobalObjectIdHash field not found; spawn will likely fail."); return; } field.SetValue(netObj, hashCode); Plugin.Log.LogInfo((object)$"NetworkObjectManager: GlobalObjectIdHash set to {hashCode}."); } } } namespace AlliedDefenses.Defenses { public class MineHijack : IHijackableDefense { public string TypeId => "mine"; public string DisplayName => "Mine"; public Type ComponentType => typeof(Landmine); public bool TryResolveByTerminalCode(string code, out Component? defense) { defense = TerminalCodeResolver.Resolve(code, typeof(Landmine)); return (Object)(object)defense != (Object)null; } public void ApplyAlliedState(Component defense, bool allied) { if (!allied) { AlliedLightTint.Apply(defense, allied: false); } } public void TickAlliedTargeting(Component defense) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)defense == (Object)null) { return; } Landmine val = (Landmine)(object)((defense is Landmine) ? defense : null); if (val == null || val.hasExploded) { return; } AlliedLightTint.Apply((Component)(object)val, allied: true); if (!((Object)(object)NetworkManager.Singleton != (Object)null) || NetworkManager.Singleton.IsServer) { EnemyAI val2 = TargetingHelper.FindBestEnemy(((Component)val).transform.position, Vector3.up, ModConfig.MineTriggerRadius.Value, 180f, requireLineOfSight: false); if (!((Object)(object)val2 == (Object)null)) { Detonate(val); } } } private static void Detonate(Landmine mine) { if (mine.hasExploded) { return; } try { Traverse.Create((object)mine).Method("TriggerMineOnLocalClientByExiting", Array.Empty<object>()).GetValue(); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Failed to detonate allied mine: " + ex.Message)); } } } public class TurretHijack : IHijackableDefense { private static readonly Dictionary<int, float> _nextFire = new Dictionary<int, float>(); private static readonly Dictionary<int, Vector3> _baseDir = new Dictionary<int, Vector3>(); private const float FireInterval = 0.21f; private const int EnemyDamagePerShot = 1; private const float AlignToleranceDeg = 10f; private static bool _diagLogged; public string TypeId => "turret"; public string DisplayName => "Turret"; public Type ComponentType => typeof(Turret); public bool TryResolveByTerminalCode(string code, out Component? defense) { defense = TerminalCodeResolver.Resolve(code, typeof(Turret)); return (Object)(object)defense != (Object)null; } public void ApplyAlliedState(Component defense, bool allied) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007d: 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_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) Turret val = (Turret)(object)((defense is Turret) ? defense : null); if (val == null) { return; } if (allied) { val.turretActive = true; val.turretMode = (TurretMode)0; if ((Object)(object)val.turretAnimator != (Object)null) { val.turretAnimator.SetInteger("TurretMode", 0); } TurretVisuals.SetAllied(val, allied: true); if ((Object)(object)val.aimPoint != (Object)null && (Object)(object)val.centerPoint != (Object)null) { Dictionary<int, Vector3> baseDir = _baseDir; int instanceID = ((Object)val).GetInstanceID(); Vector3 val2 = val.aimPoint.position - val.centerPoint.position; baseDir[instanceID] = ((Vector3)(ref val2)).normalized; } LogHierarchyOnce(val); } else { int instanceID2 = ((Object)val).GetInstanceID(); _nextFire.Remove(instanceID2); _baseDir.Remove(instanceID2); TurretVisuals.SetAllied(val, allied: false); } } public void TickAlliedTargeting(Component defense) { } public void DriveAlliedTurret(Turret turret) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: 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_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) if (!GetNodes(turret, out Transform rod, out Transform pivot, out Transform muzzle)) { return; } Vector3 val = muzzle.position - pivot.position; Vector3 normalized = ((Vector3)(ref val)).normalized; EnemyAI val2 = TargetingHelper.FindBestEnemy(muzzle.position, normalized, ModConfig.EnemyDetectionRange.Value); if ((Object)(object)val2 == (Object)null) { IdleScan(turret, rod, pivot, muzzle); TurretVisuals.HideBeam(turret); return; } Vector3 val3 = ((Component)val2).transform.position + Vector3.up * 0.5f; float degPerSec = Mathf.Max(turret.rotationSpeed, 90f); AimRodAt(rod, pivot.position, muzzle.position, val3, degPerSec); UpdateBeam(turret, pivot, muzzle); bool flag = (Object)(object)NetworkManager.Singleton == (Object)null || NetworkManager.Singleton.IsServer; float num = Vector3.Angle(muzzle.position - pivot.position, val3 - pivot.position); if (flag && num <= 10f) { TryFireAtEnemy(turret, val2); } } private static bool GetNodes(Turret turret, out Transform rod, out Transform pivot, out Transform muzzle) { rod = turret.turretRod; pivot = turret.centerPoint; muzzle = turret.aimPoint; if ((Object)(object)rod != (Object)null && (Object)(object)pivot != (Object)null) { return (Object)(object)muzzle != (Object)null; } return false; } private static void AimRodAt(Transform rod, Vector3 pivotPos, Vector3 muzzlePos, Vector3 targetPoint, float degPerSec) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: 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) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) Vector3 val = targetPoint - pivotPos; Vector3 val2 = muzzlePos - pivotPos; if (!(((Vector3)(ref val)).sqrMagnitude < 1E-05f) && !(((Vector3)(ref val2)).sqrMagnitude < 1E-05f)) { ((Vector3)(ref val)).Normalize(); ((Vector3)(ref val2)).Normalize(); Vector3 val3 = rod.InverseTransformDirection(val2); Quaternion val4 = Quaternion.LookRotation(val, Vector3.up) * Quaternion.Inverse(Quaternion.LookRotation(val3, Vector3.up)); rod.rotation = Quaternion.RotateTowards(rod.rotation, val4, degPerSec * Time.deltaTime); } } private static void IdleScan(Turret turret, Transform rod, Transform pivot, Transform muzzle) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //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) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) int instanceID = ((Object)turret).GetInstanceID(); Vector3 val2; if (!_baseDir.TryGetValue(instanceID, out var value)) { Vector3 val = muzzle.position - pivot.position; val2 = ((Vector3)(ref val)).normalized; } else { val2 = value; } Vector3 val3 = val2; float num = Mathf.Sin(Time.time * 0.6f) * 50f; Vector3 val4 = Quaternion.AngleAxis(num, Vector3.up) * val3; AimRodAt(rod, pivot.position, muzzle.position, pivot.position + val4 * 5f, 60f); } private static void LogHierarchyOnce(Turret turret) { if (_diagLogged) { return; } _diagLogged = true; StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("[Turret diagnostic] PREFAB TREE (R=Renderer L=Light Ln=LineRenderer T=Turret):"); Transform val = ((Component)turret).transform; for (int i = 0; i < 2; i++) { if (!((Object)(object)val.parent != (Object)null)) { break; } val = val.parent; } int count = 0; DumpTree(val, 0, stringBuilder, ref count); stringBuilder.AppendLine("[Turret diagnostic] Transform fields on Turret:"); FieldInfo[] fields = typeof(Turret).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { if (typeof(Transform).IsAssignableFrom(fieldInfo.FieldType)) { object? value = fieldInfo.GetValue(turret); Transform val2 = (Transform)((value is Transform) ? value : null); stringBuilder.AppendLine(" " + fieldInfo.Name + " -> " + (((Object)(object)val2 != (Object)null) ? ((Object)val2).name : "null")); } } Plugin.Log.LogInfo((object)stringBuilder.ToString()); } private static void DumpTree(Transform t, int depth, StringBuilder sb, ref int count) { //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Expected O, but got Unknown if (count++ > 80 || depth > 5) { return; } string text = ""; if ((Object)(object)((Component)t).GetComponent<Renderer>() != (Object)null) { text += "R"; } if ((Object)(object)((Component)t).GetComponent<Light>() != (Object)null) { text += "L"; } if ((Object)(object)((Component)t).GetComponent<LineRenderer>() != (Object)null) { text += "Ln"; } if ((Object)(object)((Component)t).GetComponent<Turret>() != (Object)null) { text += "T"; } sb.AppendLine(new string(' ', depth * 2) + ((Object)t).name + " [" + text + "]"); foreach (Transform item in t) { Transform t2 = item; DumpTree(t2, depth + 1, sb, ref count); } } private static void UpdateBeam(Turret turret, Transform pivot, Transform muzzle) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) float value = ModConfig.EnemyDetectionRange.Value; Vector3 val = muzzle.position - pivot.position; Vector3 normalized = ((Vector3)(ref val)).normalized; Vector3 position = muzzle.position; RaycastHit val2 = default(RaycastHit); Vector3 to = (Physics.Raycast(position, normalized, ref val2, value, -1, (QueryTriggerInteraction)1) ? ((RaycastHit)(ref val2)).point : (position + normalized * value)); TurretVisuals.DrawBeam(turret, position, to); } private void TryFireAtEnemy(Turret turret, EnemyAI enemy) { int instanceID = ((Object)turret).GetInstanceID(); float time = Time.time; if (!_nextFire.TryGetValue(instanceID, out var value) || !(time < value)) { _nextFire[instanceID] = time + 0.21f; enemy.HitEnemy(1, (PlayerControllerB)null, false, -1); MuzzleFlash(turret); } } private static void MuzzleFlash(Turret turret) { if ((Object)(object)turret.bulletParticles != (Object)null) { turret.bulletParticles.Emit(2); } } } } namespace AlliedDefenses.Core { public static class AlliedLightTint { private sealed class Cache { public Light[] Lights = Array.Empty<Light>(); public Color[] Colors = Array.Empty<Color>(); } private static readonly Dictionary<int, Cache> _cache = new Dictionary<int, Cache>(); public static void Apply(Component defense, bool allied) { //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) if (!ModConfig.ColorAlliedDefenses.Value || (Object)(object)defense == (Object)null) { return; } int instanceID = ((Object)defense).GetInstanceID(); if (allied) { if (!_cache.TryGetValue(instanceID, out Cache value)) { Light[] componentsInChildren = defense.GetComponentsInChildren<Light>(true); Cache cache = new Cache(); cache.Lights = componentsInChildren; cache.Colors = (Color[])(object)new Color[componentsInChildren.Length]; value = cache; for (int i = 0; i < componentsInChildren.Length; i++) { value.Colors[i] = componentsInChildren[i].color; } _cache[instanceID] = value; } Color alliedColor = ModConfig.AlliedColor; Light[] lights = value.Lights; foreach (Light val in lights) { if ((Object)(object)val != (Object)null) { val.color = alliedColor; } } } else { if (!_cache.TryGetValue(instanceID, out Cache value2)) { return; } for (int k = 0; k < value2.Lights.Length; k++) { if ((Object)(object)value2.Lights[k] != (Object)null) { value2.Lights[k].color = value2.Colors[k]; } } _cache.Remove(instanceID); } } } public static class DefenseRegistry { private static readonly List<IHijackableDefense> _defenses = new List<IHijackableDefense>(); public static IReadOnlyList<IHijackableDefense> All => _defenses; public static int Count => _defenses.Count; public static void RegisterDefaults() { Register(new TurretHijack()); Register(new MineHijack()); } public static void Register(IHijackableDefense defense) { _defenses.Add(defense); Plugin.Log.LogInfo((object)("Defense module registered: " + defense.TypeId + " (" + defense.DisplayName + ")")); } public static bool TryResolve(string code, out IHijackableDefense? module, out Component? defense) { foreach (IHijackableDefense defense3 in _defenses) { if (defense3.TryResolveByTerminalCode(code, out Component defense2) && (Object)(object)defense2 != (Object)null) { module = defense3; defense = defense2; return true; } } module = null; defense = null; return false; } public static IHijackableDefense? FindModule(string typeId) { foreach (IHijackableDefense defense in _defenses) { if (defense.TypeId == typeId) { return defense; } } return null; } } public class HijackEntry { public ulong NetworkId; public string TypeId = ""; public Component Defense; public float ExpireTime; } public static class HijackManager { private static readonly Dictionary<ulong, HijackEntry> _active = new Dictionary<ulong, HijackEntry>(); public static int ActiveCount => _active.Count; public static bool IsAllied(ulong networkId) { return _active.ContainsKey(networkId); } public static bool IsAllied(Component defense) { ulong? num = ResolveNetworkId(defense); if (num.HasValue) { return _active.ContainsKey(num.Value); } return false; } public static HijackEntry? Get(ulong networkId) { if (!_active.TryGetValue(networkId, out HijackEntry value)) { return null; } return value; } public static string RequestHijack(string code) { if (!DefenseRegistry.TryResolve(code, out IHijackableDefense module, out Component defense) || (Object)(object)defense == (Object)null || module == null) { return "No defense found for code '" + code + "'."; } ulong? num = ResolveNetworkId(defense); if (!num.HasValue) { return "This defense has no network identity (cannot be hijacked)."; } HijackNetworker active = HijackNetworker.Active; if ((Object)(object)active == (Object)null) { return "Network handler not ready yet. Try again in a moment."; } active.RequestHijack(num.Value, module.TypeId); float value = ModConfig.HijackDuration.Value; string text = ((value > 0f) ? $"for {value:0} seconds" : "until end of round"); return "Hijacking " + module.DisplayName + " '" + code + "' " + text + "..."; } public static string ListDefenses(string typeId) { IHijackableDefense hijackableDefense = DefenseRegistry.FindModule(typeId); if (hijackableDefense == null) { return "Unknown defense type '" + typeId + "'."; } List<string> list = new List<string>(); Object[] array = Object.FindObjectsOfType(hijackableDefense.ComponentType); foreach (Object val in array) { Component val2 = (Component)(object)((val is Component) ? val : null); if (val2 != null) { list.Add(TerminalCodeResolver.GetCodeFor(val2)); } } list.Sort(StringComparer.OrdinalIgnoreCase); string text = hijackableDefense.DisplayName.ToLower(); if (list.Count == 0) { return "No " + text + "s on this level."; } return string.Format("{0} {1}(s) on this level:\n {2}\n", list.Count, text, string.Join(", ", list)) + "Use '" + ModConfig.HijackCommand.Value + " <id>' to hijack one."; } public static void ApplyHijack(ulong networkId, string typeId, bool allied) { Component val = ResolveComponent(networkId, typeId); IHijackableDefense hijackableDefense = DefenseRegistry.FindModule(typeId); if ((Object)(object)val == (Object)null || hijackableDefense == null) { Plugin.Log.LogWarning((object)$"ApplyHijack: could not resolve netId={networkId} type={typeId}"); return; } hijackableDefense.ApplyAlliedState(val, allied); if (allied) { float value = ModConfig.HijackDuration.Value; _active[networkId] = new HijackEntry { NetworkId = networkId, TypeId = typeId, Defense = val, ExpireTime = ((value > 0f) ? (Time.time + value) : 0f) }; Plugin.Log.LogInfo((object)$"{hijackableDefense.DisplayName} (net {networkId}) is now ALLIED."); } else { RadarTimerDisplay.Restore(val); _active.Remove(networkId); Plugin.Log.LogInfo((object)$"{hijackableDefense.DisplayName} (net {networkId}) is hostile again."); } } public static void Tick() { if (_active.Count == 0) { return; } bool flag = (Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsServer; List<HijackEntry> list = null; List<ulong> list2 = null; foreach (KeyValuePair<ulong, HijackEntry> item in _active) { HijackEntry value = item.Value; if ((Object)(object)value.Defense == (Object)null) { (list2 ?? (list2 = new List<ulong>())).Add(value.NetworkId); continue; } try { DefenseRegistry.FindModule(value.TypeId)?.TickAlliedTargeting(value.Defense); RadarTimerDisplay.Update(value); } catch (Exception ex) { Plugin.Log.LogWarning((object)$"Tick error for {value.TypeId} (net {value.NetworkId}); dropping it: {ex.Message}"); (list2 ?? (list2 = new List<ulong>())).Add(value.NetworkId); continue; } if (flag && value.ExpireTime > 0f && Time.time >= value.ExpireTime) { (list ?? (list = new List<HijackEntry>())).Add(value); } } if (list2 != null) { foreach (ulong item2 in list2) { _active.Remove(item2); } } if (list == null) { return; } foreach (HijackEntry item3 in list) { HijackNetworker.Active?.RequestUnhijack(item3.NetworkId, item3.TypeId); } } public static void ClearAll() { foreach (HijackEntry value in _active.Values) { DefenseRegistry.FindModule(value.TypeId)?.ApplyAlliedState(value.Defense, allied: false); RadarTimerDisplay.Restore(value.Defense); } _active.Clear(); } public static ulong? ResolveNetworkId(Component c) { NetworkObject componentInParent = c.GetComponentInParent<NetworkObject>(); if (!((Object)(object)componentInParent != (Object)null)) { return null; } return componentInParent.NetworkObjectId; } private static Component? ResolveComponent(ulong networkId, string typeId) { NetworkManager singleton = NetworkManager.Singleton; NetworkSpawnManager val = ((singleton != null) ? singleton.SpawnManager : null); if (val == null) { return null; } if (!val.SpawnedObjects.TryGetValue(networkId, out var value) || (Object)(object)value == (Object)null) { return null; } IHijackableDefense hijackableDefense = DefenseRegistry.FindModule(typeId); if (hijackableDefense == null) { return null; } return ((Component)value).GetComponentInChildren(hijackableDefense.ComponentType); } } public class HijackTicker : MonoBehaviour { public static HijackTicker? Instance { get; private set; } public static void EnsureExists() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown if (!((Object)(object)Instance != (Object)null)) { GameObject val = new GameObject("AlliedDefenses_Ticker"); Object.DontDestroyOnLoad((Object)(object)val); ((Object)val).hideFlags = (HideFlags)61; Instance = val.AddComponent<HijackTicker>(); } } private void Update() { HijackManager.Tick(); } } public interface IHijackableDefense { string TypeId { get; } string DisplayName { get; } Type ComponentType { get; } bool TryResolveByTerminalCode(string code, out Component? defense); void ApplyAlliedState(Component defense, bool allied); void TickAlliedTargeting(Component defense); } public static class RadarTimerDisplay { private static readonly Dictionary<int, string> _originalText = new Dictionary<int, string>(); private static readonly Dictionary<int, Color> _originalColor = new Dictionary<int, Color>(); public static void Update(HijackEntry entry) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) TerminalAccessibleObject val = FindAccessible(entry.Defense); if ((Object)(object)val == (Object)null) { return; } Component radarText = GetRadarText(val); if (!((Object)(object)radarText == (Object)null)) { int instanceID = ((Object)val).GetInstanceID(); if (!_originalText.ContainsKey(instanceID)) { _originalText[instanceID] = StripTimer(GetText(radarText)); _originalColor[instanceID] = GetColor(radarText); } string text = _originalText[instanceID]; string text2 = ((!(entry.ExpireTime <= 0f)) ? Format(Mathf.Max(0f, entry.ExpireTime - Time.time)) : "ALLY"); SetText(radarText, text + "\n" + text2); if (ModConfig.ColorAlliedDefenses.Value) { SetColor(radarText, ModConfig.RadarAlliedColor); } } } public static void Restore(Component defense) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) TerminalAccessibleObject val = FindAccessible(defense); if ((Object)(object)val == (Object)null) { return; } int instanceID = ((Object)val).GetInstanceID(); Component radarText = GetRadarText(val); if ((Object)(object)radarText != (Object)null) { if (_originalText.TryGetValue(instanceID, out string value)) { SetText(radarText, value); } if (_originalColor.TryGetValue(instanceID, out var value2)) { SetColor(radarText, value2); } } _originalText.Remove(instanceID); _originalColor.Remove(instanceID); } private static string Format(float seconds) { int num = Mathf.CeilToInt(seconds); return $"{num / 60}:{num % 60:00}"; } private static string StripTimer(string text) { if (string.IsNullOrEmpty(text)) { return text ?? ""; } int num = text.IndexOf('\n'); if (num < 0) { return text; } return text.Substring(0, num); } private static TerminalAccessibleObject? FindAccessible(Component defense) { if ((Object)(object)defense == (Object)null) { return null; } return defense.GetComponentInParent<TerminalAccessibleObject>() ?? defense.GetComponentInChildren<TerminalAccessibleObject>(); } private static Component? GetRadarText(TerminalAccessibleObject tao) { string[] array = new string[3] { "mapRadarText", "radarText", "codeText" }; foreach (string text in array) { try { Component value = Traverse.Create((object)tao).Field(text).GetValue<Component>(); if ((Object)(object)value != (Object)null) { return value; } } catch { } } return null; } private static string GetText(Component tmp) { try { return Traverse.Create((object)tmp).Property("text", (object[])null).GetValue<string>() ?? ""; } catch { return ""; } } private static void SetText(Component tmp, string value) { try { Traverse.Create((object)tmp).Property("text", (object[])null).SetValue((object)value); } catch { } } private static Color GetColor(Component tmp) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: 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) try { return Traverse.Create((object)tmp).Property("color", (object[])null).GetValue<Color>(); } catch { return Color.white; } } private static void SetColor(Component tmp, Color value) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) try { Traverse.Create((object)tmp).Property("color", (object[])null).SetValue((object)value); } catch { } } } public static class TargetingHelper { private const int LineOfSightMask = 1051400; public static float Range => ModConfig.EnemyDetectionRange.Value; public static EnemyAI? FindBestEnemy(Vector3 origin, Vector3 forward, float range, float coneHalfAngle = 180f, bool requireLineOfSight = true) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) RoundManager instance = RoundManager.Instance; if ((Object)(object)instance == (Object)null || instance.SpawnedEnemies == null) { return null; } EnemyAI result = null; float num = float.MaxValue; float num2 = range * range; foreach (EnemyAI spawnedEnemy in instance.SpawnedEnemies) { if (!((Object)(object)spawnedEnemy == (Object)null) && !spawnedEnemy.isEnemyDead) { Vector3 position = ((Component)spawnedEnemy).transform.position; Vector3 val = position - origin; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (!(sqrMagnitude > num2) && (!(coneHalfAngle < 180f) || !(Vector3.Angle(forward, val) > coneHalfAngle)) && (!requireLineOfSight || HasLineOfSight(origin, position)) && sqrMagnitude < num) { num = sqrMagnitude; result = spawnedEnemy; } } } return result; } public static bool HasLineOfSight(Vector3 from, Vector3 to) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_001a: 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) Vector3 val = to - from; float magnitude = ((Vector3)(ref val)).magnitude; if (magnitude < 0.01f) { return true; } return !Physics.Raycast(from, ((Vector3)(ref val)).normalized, magnitude - 0.5f, 1051400, (QueryTriggerInteraction)1); } } public static class TerminalCodeResolver { public static Component? Resolve(string code, Type componentType) { if (string.IsNullOrEmpty(code)) { return null; } TerminalAccessibleObject[] array = Object.FindObjectsOfType<TerminalAccessibleObject>(); foreach (TerminalAccessibleObject val in array) { string a = ReadObjectCode(val); if (string.Equals(a, code, StringComparison.OrdinalIgnoreCase)) { Component val2 = ((Component)val).GetComponentInChildren(componentType) ?? ((Component)val).GetComponentInParent(componentType); if ((Object)(object)val2 != (Object)null) { return val2; } } } return null; } public static string GetCodeFor(Component c) { if ((Object)(object)c == (Object)null) { return "?"; } TerminalAccessibleObject val = c.GetComponentInParent<TerminalAccessibleObject>() ?? c.GetComponentInChildren<TerminalAccessibleObject>(); string text = (((Object)(object)val != (Object)null) ? ReadObjectCode(val) : ""); if (!string.IsNullOrEmpty(text)) { return text; } return "?"; } public static string ReadObjectCode(TerminalAccessibleObject acc) { string[] array = new string[3] { "objectCode", "codeString", "code" }; foreach (string text in array) { try { string value = Traverse.Create((object)acc).Field(text).GetValue<string>(); if (!string.IsNullOrEmpty(value)) { return value; } } catch { } } return ""; } } public static class TurretVisuals { private sealed class Cache { public LineRenderer[] Lines = Array.Empty<LineRenderer>(); public Color[] LineStart = Array.Empty<Color>(); public Color[] LineEnd = Array.Empty<Color>(); public Light[] Lights = Array.Empty<Light>(); public Color[] LightColors = Array.Empty<Color>(); } private static readonly Dictionary<int, Cache> _cache = new Dictionary<int, Cache>(); private static readonly Dictionary<int, LineRenderer> _beams = new Dictionary<int, LineRenderer>(); public static void SetAllied(Turret turret, bool allied) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) if (!ModConfig.ColorAlliedDefenses.Value) { return; } int instanceID = ((Object)turret).GetInstanceID(); if (allied) { if (!_cache.ContainsKey(instanceID)) { _cache[instanceID] = Capture(turret); } Color alliedColor = ModConfig.AlliedColor; Cache cache = _cache[instanceID]; LineRenderer[] lines = cache.Lines; foreach (LineRenderer val in lines) { if (!((Object)(object)val == (Object)null)) { val.startColor = alliedColor; val.endColor = alliedColor; } } Light[] lights = cache.Lights; foreach (Light val2 in lights) { if (!((Object)(object)val2 == (Object)null)) { val2.color = alliedColor; } } } else { if (!_cache.TryGetValue(instanceID, out Cache value)) { return; } for (int k = 0; k < value.Lines.Length; k++) { if (!((Object)(object)value.Lines[k] == (Object)null)) { value.Lines[k].startColor = value.LineStart[k]; value.Lines[k].endColor = value.LineEnd[k]; } } for (int l = 0; l < value.Lights.Length; l++) { if (!((Object)(object)value.Lights[l] == (Object)null)) { value.Lights[l].color = value.LightColors[l]; } } _cache.Remove(instanceID); if (_beams.TryGetValue(instanceID, out LineRenderer value2)) { if ((Object)(object)value2 != (Object)null) { Object.Destroy((Object)(object)((Component)value2).gameObject); } _beams.Remove(instanceID); } } } public static void DrawBeam(Turret turret, Vector3 from, Vector3 to) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) if (ModConfig.ColorAlliedDefenses.Value) { int instanceID = ((Object)turret).GetInstanceID(); if (!_beams.TryGetValue(instanceID, out LineRenderer value) || (Object)(object)value == (Object)null) { value = CreateBeam(turret); _beams[instanceID] = value; } ((Renderer)value).enabled = true; value.useWorldSpace = true; value.positionCount = 2; value.SetPosition(0, from); value.SetPosition(1, to); } } public static void HideBeam(Turret turret) { if (_beams.TryGetValue(((Object)turret).GetInstanceID(), out LineRenderer value) && (Object)(object)value != (Object)null) { ((Renderer)value).enabled = false; } } private static LineRenderer CreateBeam(Turret turret) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Expected O, but got Unknown //IL_007c: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("AlliedDefenses_Beam"); val.transform.SetParent(((Component)turret).transform, false); LineRenderer val2 = val.AddComponent<LineRenderer>(); LineRenderer componentInChildren = ((Component)turret).GetComponentInChildren<LineRenderer>(true); if ((Object)(object)componentInChildren != (Object)null && (Object)(object)((Renderer)componentInChildren).sharedMaterial != (Object)null) { ((Renderer)val2).material = new Material(((Renderer)componentInChildren).sharedMaterial); } Color color = (val2.endColor = (val2.startColor = ModConfig.AlliedColor)); try { if ((Object)(object)((Renderer)val2).material != (Object)null) { ((Renderer)val2).material.color = color; } } catch { } val2.startWidth = (((Object)(object)componentInChildren != (Object)null) ? componentInChildren.startWidth : 0.04f); val2.endWidth = (((Object)(object)componentInChildren != (Object)null) ? componentInChildren.endWidth : 0.04f); val2.numCapVertices = 2; ((Renderer)val2).enabled = false; return val2; } private static Cache Capture(Turret turret) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) LineRenderer[] componentsInChildren = ((Component)turret).GetComponentsInChildren<LineRenderer>(true); Light[] componentsInChildren2 = ((Component)turret).GetComponentsInChildren<Light>(true); Cache cache = new Cache(); cache.Lines = componentsInChildren; cache.LineStart = (Color[])(object)new Color[componentsInChildren.Length]; cache.LineEnd = (Color[])(object)new Color[componentsInChildren.Length]; cache.Lights = componentsInChildren2; cache.LightColors = (Color[])(object)new Color[componentsInChildren2.Length]; Cache cache2 = cache; for (int i = 0; i < componentsInChildren.Length; i++) { cache2.LineStart[i] = componentsInChildren[i].startColor; cache2.LineEnd[i] = componentsInChildren[i].endColor; } for (int j = 0; j < componentsInChildren2.Length; j++) { cache2.LightColors[j] = componentsInChildren2[j].color; } return cache2; } } } namespace AlliedDefenses.Config { public static class ModConfig { public static ConfigEntry<string> HijackCommand; public static ConfigEntry<float> HijackDuration; public static ConfigEntry<float> EnemyDetectionRange; public static ConfigEntry<float> MineTriggerRadius; public static ConfigEntry<bool> IgnorePlayersWhenAllied; public static ConfigEntry<int> HijackCreditCost; public static ConfigEntry<bool> ColorAlliedDefenses; public static ConfigEntry<string> AlliedColorHex; public static ConfigEntry<string> RadarAlliedColorHex; public static Color AlliedColor => ParseHex(AlliedColorHex.Value, Color.green); public static Color RadarAlliedColor => ParseHex(RadarAlliedColorHex.Value, new Color(0.118f, 0.565f, 1f)); public static void Init(ConfigFile cfg) { HijackCommand = cfg.Bind<string>("General", "HijackCommand", "ally", "Keyword typed in the terminal. In-game usage: <command> <id> (e.g. ally A0)"); HijackDuration = cfg.Bind<float>("General", "HijackDuration", 60f, "How many seconds a defense stays allied. Set to 0 for unlimited."); EnemyDetectionRange = cfg.Bind<float>("Targeting", "EnemyDetectionRange", 30f, "Maximum distance (m) at which a hijacked turret detects an enemy."); MineTriggerRadius = cfg.Bind<float>("Targeting", "MineTriggerRadius", 4f, "Radius (m) within which an allied mine detonates on a nearby enemy."); IgnorePlayersWhenAllied = cfg.Bind<bool>("Targeting", "IgnorePlayersWhenAllied", true, "If true, an allied defense never fires at a player (recommended)."); HijackCreditCost = cfg.Bind<int>("Economy", "HijackCreditCost", 0, "Credit cost to hijack a defense. 0 = free."); ColorAlliedDefenses = cfg.Bind<bool>("Visuals", "ColorAlliedDefenses", true, "Tint allied defenses (turret laser/light and the radar code) so you can tell they're on your side."); AlliedColorHex = cfg.Bind<string>("Visuals", "AlliedColorHex", "00FF00", "In-world color for allied turret laser/light, HTML hex without '#'. Default 00FF00 (green)."); RadarAlliedColorHex = cfg.Bind<string>("Visuals", "RadarAlliedColorHex", "1E90FF", "Radar-map color for allied defenses, HTML hex without '#'. Default 1E90FF (blue). Avoid green here: the game already uses green for active codes."); } private static Color ParseHex(string hex, Color fallback) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) Color result = default(Color); if (!ColorUtility.TryParseHtmlString("#" + hex, ref result)) { return fallback; } return result; } } } namespace __GEN { internal class NetworkVariableSerializationHelper { [RuntimeInitializeOnLoadMethod] internal static void InitializeSerialization() { } } } namespace AlliedDefenses.NetcodePatcher { [AttributeUsage(AttributeTargets.Module)] internal class NetcodePatchedAssemblyAttribute : Attribute { } }