using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using Dissonance.Integrations.Unity_NFGO; using HarmonyLib; using Microsoft.CodeAnalysis; using Microsoft.ML.OnnxRuntime; using Microsoft.ML.OnnxRuntime.Tensors; using Unity.Collections; using Unity.Netcode; using UnityEngine; using UnityEngine.Events; using UnityEngine.Rendering; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("WormtownAI")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+6ee958d45c268a70f4db457289d12410c4201df6")] [assembly: AssemblyProduct("WormtownAI")] [assembly: AssemblyTitle("WormtownAI")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [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 WormtownAI { public class AiWorm : MonoBehaviour { public ulong requester_client_id; public int owner_slot; public AiWormDifficulty difficulty; public PlayerCosmeticData cosmetic_data; public bool has_cosmetic_data; } [HarmonyPatch] public static class AiWormCosmetics { private struct CosmeticBankState { public Dictionary bank; public ulong owner_id; public bool had_original; public PlayerCosmeticData original; } private const string GRAY_HEX = "7A7A7A"; private const string DARK_GRAY_HEX = "727272"; public static PlayerCosmeticData Create(PlayerCosmeticData source) { //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_0182: Unknown result type (might be due to invalid IL or missing references) PlayerCosmeticData result = source; byte[] bytes = Encoding.UTF8.GetBytes("7A7A7A"); byte[] bytes2 = Encoding.UTF8.GetBytes("727272"); result.worm_Hat_Model_Index = 0; result.worm_Horn_Model_Index = 0; result.worm_Eyes_Model_Index = 0; result.worm_Teeth_Model_Index = 2; result.worm_Head_Model_Index = 0; result.worm_Head_Color_Primary_Index = 0; result.worm_Head_Color_Secondary_Index = 0; result.worm_Head_Color_Primary_Hex = bytes; result.worm_Head_Color_Secondary_Hex = bytes; result.worm_BodySegment_Model_Index_0 = 0; result.worm_BodySegment_Color_Primary_Index_0 = 0; result.worm_BodySegment_Color_Secondary_Index_0 = 0; result.worm_BodySegment_Color_Primary_Hex_0 = bytes2; result.worm_BodySegment_Color_Secondary_Hex_0 = bytes2; result.worm_BodySegment_Model_Index_1 = 0; result.worm_BodySegment_Color_Primary_Index_1 = 0; result.worm_BodySegment_Color_Secondary_Index_1 = 0; result.worm_BodySegment_Color_Primary_Hex_1 = bytes; result.worm_BodySegment_Color_Secondary_Hex_1 = bytes; result.worm_BodySegment_Model_Index_2 = 0; result.worm_BodySegment_Color_Primary_Index_2 = 0; result.worm_BodySegment_Color_Secondary_Index_2 = 0; result.worm_BodySegment_Color_Primary_Hex_2 = bytes2; result.worm_BodySegment_Color_Secondary_Hex_2 = bytes2; result.worm_BodySegment_Model_Index_3 = 0; result.worm_BodySegment_Color_Primary_Index_3 = 0; result.worm_BodySegment_Color_Secondary_Index_3 = 0; result.worm_BodySegment_Color_Primary_Hex_3 = bytes; result.worm_BodySegment_Color_Secondary_Hex_3 = bytes; result.worm_BodySegment_Model_Index_4 = 0; result.worm_BodySegment_Color_Primary_Index_4 = 0; result.worm_BodySegment_Color_Secondary_Index_4 = 0; result.worm_BodySegment_Color_Primary_Hex_4 = bytes2; result.worm_BodySegment_Color_Secondary_Hex_4 = bytes2; result.worm_BodySegment_Model_Index_5 = 0; result.worm_BodySegment_Color_Primary_Index_5 = 0; result.worm_BodySegment_Color_Secondary_Index_5 = 0; result.worm_BodySegment_Color_Primary_Hex_5 = bytes; result.worm_BodySegment_Color_Secondary_Hex_5 = bytes; result.worm_BodySegment_Model_Index_6 = 0; result.worm_BodySegment_Color_Primary_Index_6 = 0; result.worm_BodySegment_Color_Secondary_Index_6 = 0; result.worm_BodySegment_Color_Primary_Hex_6 = bytes2; result.worm_BodySegment_Color_Secondary_Hex_6 = bytes2; return result; } public static bool TryGet(InGameWormCosmeticBuilder builder, out PlayerCosmeticData data) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) data = default(PlayerCosmeticData); if (!LobbyAiState.IsLocalHost || (Object)(object)builder == (Object)null) { return false; } AiWorm componentInParent = ((Component)builder).GetComponentInParent(); if ((Object)(object)componentInParent == (Object)null || !componentInParent.has_cosmetic_data) { return false; } data = componentInParent.cosmetic_data; return true; } [HarmonyPatch(typeof(InGameWormCosmeticBuilder), "CreateCosmetics")] [HarmonyPrefix] public static void CreateCosmetics_Prefix(InGameWormCosmeticBuilder __instance) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) if (TryGet(__instance, out var data)) { __instance.pcr = data; } } [HarmonyPatch(typeof(InGameWormCosmeticBuilder), "RequestPlayerCosmeticDataFromServer_ServerRPC")] [HarmonyPrefix] private static void RequestPlayerCosmeticData_Prefix(InGameWormCosmeticBuilder __instance, ulong __1, ref CosmeticBankState __state) { //IL_0059: Unknown result type (might be due to invalid IL or missing references) __state = default(CosmeticBankState); if (TryGet(__instance, out var data) && !((Object)(object)GameManager.Singleton == (Object)null) && GameManager.Singleton.PlayerCosmeticDataBank != null) { Dictionary dictionary = (__state.bank = GameManager.Singleton.PlayerCosmeticDataBank); __state.owner_id = __1; __state.had_original = dictionary.TryGetValue(__1, out __state.original); dictionary[__1] = data; } } [HarmonyPatch(typeof(InGameWormCosmeticBuilder), "RequestPlayerCosmeticDataFromServer_ServerRPC")] [HarmonyFinalizer] private static Exception RequestPlayerCosmeticData_Finalizer(Exception __exception, CosmeticBankState __state) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) if (__state.bank == null) { return __exception; } if (__state.had_original) { __state.bank[__state.owner_id] = __state.original; } else { __state.bank.Remove(__state.owner_id); } return __exception; } } public enum AiWormDifficulty : byte { Garden, Snake, Bull } public static class AiWormDifficultyRules { public const float BULL_DESTRUCTION_CHANCE = 0.75f; public static AiWormDifficulty Clamp(int value) { return (AiWormDifficulty)Mathf.Clamp(value, 0, 2); } public static float Multiplier(AiWormDifficulty difficulty) { return difficulty switch { AiWormDifficulty.Snake => 1.3f, AiWormDifficulty.Bull => 2f, _ => 1f, }; } public static float BurrowMultiplier(AiWormDifficulty difficulty) { return difficulty switch { AiWormDifficulty.Snake => 2f, AiWormDifficulty.Bull => 3f, _ => 1f, }; } public static string DisplayName(AiWormDifficulty difficulty) { return difficulty switch { AiWormDifficulty.Snake => "Snake Worm", AiWormDifficulty.Bull => "Bull Worm", _ => "Garden Worm", }; } public static AiWormDifficulty For(Component component) { AiWorm aiWorm = (((Object)(object)component != (Object)null) ? component.GetComponentInParent() : null); if (!((Object)(object)aiWorm != (Object)null)) { return AiWormDifficulty.Garden; } return aiWorm.difficulty; } public static float Multiplier(Component component) { return Multiplier(For(component)); } } [HarmonyPatch] public static class AiWormDifficultyPatches { private const float IMPACT_DEDUP_SECONDS = 0.25f; private const float EXPLOSION_RADIUS_MIN = 0.08f; private const float EXPLOSION_RADIUS_MID = 0.15f; private const float EXPLOSION_RADIUS_MAX = 0.25f; private const ulong NO_PLAYER_ID = 1000000uL; private static readonly Dictionary> impact_retry_at = new Dictionary>(); [HarmonyPatch(typeof(WormAbilityManager), "GetCooldownMultiplier")] [HarmonyPostfix] public static void GetCooldownMultiplier_Postfix(WormAbilityManager __instance, ref float __result) { if (AiWormManager.IsActiveAiWorm((Component)(object)__instance)) { __result *= AiWormDifficultyRules.Multiplier((Component)(object)__instance); } } [HarmonyPatch(typeof(WormMovement), "OnCollisionEnter")] [HarmonyPostfix] public static void OnCollisionEnter_Postfix(WormMovement __instance, Collision other) { //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_005d: 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_0062: Invalid comparison between Unknown and I4 //IL_00da: Unknown result type (might be due to invalid IL or missing references) NetworkManager singleton = NetworkManager.Singleton; AiWorm aiWorm = (((Object)(object)__instance != (Object)null) ? ((Component)__instance).GetComponentInParent() : null); if ((Object)(object)singleton == (Object)null || !singleton.IsHost || !AiWormManager.IsActiveAiWorm((Component)(object)__instance) || (Object)(object)aiWorm == (Object)null || aiWorm.difficulty != AiWormDifficulty.Bull || other == null || (Object)(object)other.collider == (Object)null) { return; } WormMovementState wormMovementState = __instance.wormMovementState; if ((int)wormMovementState != 0 && (int)wormMovementState != 2) { return; } GameObject val = ResolveDestructible(other.collider); if ((Object)(object)val == (Object)null || !CanDestroy(val) || !BeginImpactRoll(__instance, val) || Random.value >= 0.75f) { return; } if (!TryFindContainedExplosion(other, val, out var explosion_pos, out var radius)) { Plugin.log.LogWarning((object)("[worm] bull impact could not isolate " + ((Object)val).name + " for destruction")); return; } GameManager singleton2 = GameManager.Singleton; if (!((Object)(object)singleton2 == (Object)null)) { singleton2.CreateExplosionAtPosition_ServerRPC(explosion_pos, radius, 1000000uL, 1000000uL, false); Plugin.log.LogInfo((object)("[worm] bull destroyed " + ((Object)val).name)); } } public static void ForgetImpacts(WormMovement worm) { if ((Object)(object)worm != (Object)null) { impact_retry_at.Remove(worm); } } public static void ResetImpacts() { impact_retry_at.Clear(); } private static GameObject ResolveDestructible(Collider collider) { Transform root = ((Component)collider).transform.root; if (((Component)root).CompareTag("Rock") || ((Component)root).CompareTag("Cactus")) { GameObject gameObject = ((Component)root).gameObject; if (!((Object)(object)gameObject.GetComponent() != (Object)null)) { return null; } return gameObject; } RootFinder componentInParent = ((Component)collider).GetComponentInParent(); GameObject val = (((Object)(object)componentInParent != (Object)null) ? ((Component)componentInParent).gameObject : null); if ((Object)(object)val == (Object)null) { return null; } if (val.CompareTag("CollapsibleBuilding") && (Object)(object)val.GetComponent() != (Object)null) { return val; } if (val.CompareTag("DestructibleTrain") && (Object)(object)val.GetComponent() != (Object)null) { return val; } return null; } private static bool CanDestroy(GameObject target) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) CollapsibleBuilding component = target.GetComponent(); if ((Object)(object)component != (Object)null) { return !component.GetHasCollapsed(); } DestructibleTrain component2 = target.GetComponent(); if ((Object)(object)component2 != (Object)null) { return !component2.GetDestroyedState(); } return target.transform.position.y < 5000f; } private static bool BeginImpactRoll(WormMovement worm, GameObject target) { if (!impact_retry_at.TryGetValue(worm, out var value)) { value = new Dictionary(); impact_retry_at[worm] = value; } int instanceID = ((Object)target).GetInstanceID(); if (value.TryGetValue(instanceID, out var value2) && Time.time < value2) { return false; } value[instanceID] = Time.time + 0.25f; return true; } private static bool TryFindContainedExplosion(Collision collision, GameObject target, out Vector3 explosion_pos, out float radius) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: 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_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_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: 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_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_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006f: 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_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: 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_0088: 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) //IL_0093: 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_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: 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) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) Collider collider = collision.collider; Vector3 val; if (collision.contactCount <= 0) { val = collider.ClosestPoint(collision.transform.position); } else { ContactPoint contact = collision.GetContact(0); val = ((ContactPoint)(ref contact)).point; } Vector3 val2 = val; Bounds bounds = collider.bounds; Vector3 val3 = ((Bounds)(ref bounds)).center - val2; Vector3 val4 = ((((Vector3)(ref val3)).sqrMagnitude > 0.0001f) ? ((Vector3)(ref val3)).normalized : Vector3.zero); Vector3[] obj = new Vector3[4] { val2 + val4 * 0.2f, val2 + val4 * 0.4f, default(Vector3), default(Vector3) }; bounds = collider.bounds; obj[2] = collider.ClosestPoint(((Bounds)(ref bounds)).center); bounds = collider.bounds; obj[3] = ((Bounds)(ref bounds)).center; Vector3[] array = (Vector3[])(object)obj; float[] array2 = new float[3] { 0.08f, 0.15f, 0.25f }; foreach (float num in array2) { Vector3[] array3 = array; foreach (Vector3 val5 in array3) { if (IsContainedTargetSphere(val5, num, target)) { explosion_pos = val5; radius = num; return true; } } } explosion_pos = Vector3.zero; radius = 0f; return false; } private static bool IsContainedTargetSphere(Vector3 position, float radius, GameObject target) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) bool result = false; Collider[] array = Physics.OverlapSphere(position, radius, -1, (QueryTriggerInteraction)1); foreach (Collider val in array) { if (((Component)val).CompareTag("Player") || ((Component)val).CompareTag("WormPlayer") || ((Component)val).CompareTag("PickUp")) { return false; } GameObject val2 = ResolveDestructible(val); if ((Object)(object)val2 != (Object)null && (Object)(object)val2 != (Object)(object)target) { return false; } if ((Object)(object)val2 == (Object)(object)target) { result = true; } } return result; } } [HarmonyPatch] public static class AiWormLoadoutPatches { [HarmonyPatch(typeof(WormAbilityManager), "Start", new Type[] { })] [HarmonyPostfix] public static void Start_Postfix(WormAbilityManager __instance) { if (!AiWormManager.IsAiWorm((Component)(object)__instance)) { return; } try { if (LobbyAiState.ApplyAiLoadout(__instance)) { Plugin.log.LogInfo((object)"[ai-toggle] applied required powers to spawned ai worm"); } else { Plugin.log.LogWarning((object)"[ai-toggle] could not apply powers to spawned ai worm"); } } catch (Exception ex) { Plugin.log.LogWarning((object)("[ai-toggle] spawned worm loadout failed: " + ex.Message)); } } } [HarmonyPatch] public static class AiWormManager { public static readonly List ai_worms = new List(); private static readonly Dictionary ai_worms_by_client = new Dictionary(); private static readonly Dictionary owner_slots_by_client = new Dictionary(); private static readonly Dictionary pending_start_clients = new Dictionary(); public static bool IsAiWorm(Component c) { if (LobbyAiState.IsLocalHost && (Object)(object)c != (Object)null) { return (Object)(object)c.GetComponentInParent() != (Object)null; } return false; } public static bool IsActiveAiWorm(Component c) { if (!IsAiWorm(c)) { return false; } AiWorm componentInParent = c.GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null) { return ai_worms.Contains(((Component)componentInParent).gameObject); } return false; } [HarmonyPatch(typeof(LobbyManager), "SpawnPlayersAndStartGame")] [HarmonyPostfix] public static void SpawnPlayersAndStartGame_Postfix() { ReconcileSpawnedWorms(allow_start_hook: true); } public static void ReconcileSpawnedWorms() { ReconcileSpawnedWorms(allow_start_hook: false); } public static void CaptureStartRoster() { pending_start_clients.Clear(); NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || !singleton.IsHost || !LobbyAiState.IsHostEnabled) { return; } foreach (ulong enabledClientId in LobbyAiState.GetEnabledClientIds()) { if (singleton.ConnectedClients.ContainsKey(enabledClientId)) { pending_start_clients[enabledClientId] = LobbyAiState.GetClientDifficulty(enabledClientId); } } } public static void ClearStartRoster() { pending_start_clients.Clear(); } private static void ReconcileSpawnedWorms(bool allow_start_hook) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Invalid comparison between Unknown and I4 //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Invalid comparison between Unknown and I4 NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || !singleton.IsHost) { return; } GameManager singleton2 = GameManager.Singleton; if ((Object)(object)singleton2 == (Object)null || (!allow_start_hook && (int)singleton2.gameState != 1 && (int)singleton2.gameState != 3)) { return; } RemoveMissingEntries(); Dictionary dictionary = new Dictionary(); if (allow_start_hook && pending_start_clients.Count > 0) { foreach (KeyValuePair pending_start_client in pending_start_clients) { if (singleton.ConnectedClients.ContainsKey(pending_start_client.Key)) { dictionary[pending_start_client.Key] = pending_start_client.Value; } } pending_start_clients.Clear(); } else if (LobbyAiState.IsHostEnabled) { foreach (ulong enabledClientId in LobbyAiState.GetEnabledClientIds()) { if (singleton.ConnectedClients.ContainsKey(enabledClientId)) { dictionary[enabledClientId] = LobbyAiState.GetClientDifficulty(enabledClientId); } } } List list = new List(dictionary.Keys); list.Sort(); if (list.Count > 16) { list.RemoveRange(16, list.Count - 16); } HashSet hashSet = new HashSet(list); foreach (ulong item in new List(ai_worms_by_client.Keys)) { if (!hashSet.Contains(item)) { RemoveForClient(item); } } if (list.Count == 0 || !allow_start_hook) { return; } Plugin.EnsurePolicyLoaded(); LobbyAiState.EnsureAiLoadout(); GameObject wormPrefab = singleton2.wormPrefab; if ((Object)(object)wormPrefab == (Object)null) { Plugin.log.LogError((object)"wormPrefab null; cannot spawn ai worm"); return; } int count = ai_worms.Count; for (int i = 0; i < list.Count; i++) { ulong num = list[i]; if (!ai_worms_by_client.ContainsKey(num)) { int num2 = NextAvailableOwnerSlot(); if (num2 < 0) { Plugin.log.LogWarning((object)"no reserved owner id remained for another ai worm"); break; } TrySpawnOne(wormPrefab, num, num2, dictionary[num]); } } if (ai_worms.Count != count) { Plugin.log.LogInfo((object)$"spawned {ai_worms.Count} ai worm(s)"); } } [HarmonyPatch(typeof(GameManager), "SwitchGameStateServerRPC")] [HarmonyPostfix] public static void SwitchGameState_Postfix(int gameStateInt) { if (LobbyAiState.IsLocalHost && (gameStateInt == 2 || gameStateInt == 0)) { DespawnAll(); } } public static void DespawnAll() { AiWormDifficultyPatches.ResetImpacts(); NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || !singleton.IsHost) { return; } foreach (GameObject ai_worm in ai_worms) { if (!((Object)(object)ai_worm == (Object)null)) { WormMovement componentInChildren = ai_worm.GetComponentInChildren(); WormPerception.Remove(componentInChildren); AiWormDifficultyPatches.ForgetImpacts(componentInChildren); DespawnOne(ai_worm); } } ai_worms.Clear(); ai_worms_by_client.Clear(); owner_slots_by_client.Clear(); pending_start_clients.Clear(); WormPerception.Reset(); } public static void RemoveForClient(ulong client_id) { if (!ai_worms_by_client.TryGetValue(client_id, out var value)) { owner_slots_by_client.Remove(client_id); return; } ai_worms_by_client.Remove(client_id); owner_slots_by_client.Remove(client_id); ai_worms.Remove(value); WormMovement worm = (((Object)(object)value != (Object)null) ? value.GetComponentInChildren() : null); WormPerception.Remove(worm); AiWormDifficultyPatches.ForgetImpacts(worm); DespawnOne(value); } private static void DespawnOne(GameObject go) { if ((Object)(object)go == (Object)null) { return; } WormMouth componentInChildren = go.GetComponentInChildren(true); if (GrabReleasePatches.ReleaseBeforeDespawn(componentInChildren)) { try { ((MonoBehaviour)componentInChildren).StartCoroutine(DespawnAfterRelease(go)); return; } catch (Exception ex) { Plugin.log.LogWarning((object)("delayed ai worm despawn failed: " + ex.Message)); } } DespawnNow(go); } private static IEnumerator DespawnAfterRelease(GameObject go) { yield return null; yield return null; DespawnNow(go); } private static void DespawnNow(GameObject go) { try { NetworkObject val = (((Object)(object)go != (Object)null) ? go.GetComponent() : null); if ((Object)(object)val != (Object)null && val.IsSpawned) { val.Despawn(true); } else if ((Object)(object)go != (Object)null) { Object.Destroy((Object)(object)go); } } catch (Exception ex) { Plugin.log.LogWarning((object)("ai worm despawn failed: " + ex.Message)); } } private static void RemoveMissingEntries() { ai_worms.RemoveAll((GameObject worm) => (Object)(object)worm == (Object)null); foreach (ulong item in new List(ai_worms_by_client.Keys)) { if ((Object)(object)ai_worms_by_client[item] == (Object)null) { ai_worms_by_client.Remove(item); owner_slots_by_client.Remove(item); } } } private static int NextAvailableOwnerSlot() { HashSet hashSet = new HashSet(owner_slots_by_client.Values); for (int i = 0; i < 16; i++) { if (!hashSet.Contains(i)) { return i; } } return -1; } private static void TrySpawnOne(GameObject prefab, ulong requester_client_id, int owner_slot, AiWormDifficulty difficulty) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0034: 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) GameObject val = null; try { int num = owner_slot % 4; int num2 = owner_slot / 4; Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(((float)num - 1.5f) * 8f, 0f, -12f - (float)num2 * 8f); val = Object.Instantiate(prefab, val2, Quaternion.identity); if ((Object)(object)MenuToGameBridger.Singleton == (Object)null) { throw new InvalidOperationException("MenuToGameBridger null"); } AiWorm aiWorm = val.AddComponent(); aiWorm.requester_client_id = requester_client_id; aiWorm.owner_slot = owner_slot; aiWorm.difficulty = difficulty; aiWorm.cosmetic_data = AiWormCosmetics.Create(MenuToGameBridger.Singleton.localPlayerCosmeticData); aiWorm.has_cosmetic_data = true; ApplyDifficulty(val, difficulty); NetworkObject component = val.GetComponent(); if ((Object)(object)component == (Object)null) { throw new InvalidOperationException("worm prefab has no NetworkObject"); } component.SpawnWithOwnership(AiWormNetworkIdentity.OwnerIdFor(owner_slot), false); ai_worms.Add(val); ai_worms_by_client[requester_client_id] = val; owner_slots_by_client[requester_client_id] = owner_slot; Plugin.log.LogInfo((object)("spawned " + AiWormDifficultyRules.DisplayName(difficulty) + " " + $"for client {requester_client_id}")); } catch (Exception arg) { try { if ((Object)(object)val != (Object)null) { NetworkObject component2 = val.GetComponent(); if ((Object)(object)component2 != (Object)null && component2.IsSpawned) { component2.Despawn(true); } else { Object.Destroy((Object)(object)val); } } } catch (Exception ex) { Plugin.log.LogWarning((object)("ai worm spawn cleanup failed: " + ex.Message)); } Plugin.log.LogError((object)$"ai worm spawn failed: {arg}"); } } private static void ApplyDifficulty(GameObject go, AiWormDifficulty difficulty) { WormMovement componentInChildren = go.GetComponentInChildren(true); if ((Object)(object)componentInChildren == (Object)null) { throw new InvalidOperationException("worm prefab has no WormMovement"); } float num = AiWormDifficultyRules.Multiplier(difficulty); float num2 = AiWormDifficultyRules.BurrowMultiplier(difficulty); if (!Mathf.Approximately(num, 1f) || !Mathf.Approximately(num2, 1f)) { string[] obj = new string[5] { "surfaceSpeed", "surfaceSpeed_Sneak", "divePower", "aboveGroundDivePower", "diveUpwardsPower" }; Traverse val = Traverse.Create((object)componentInChildren); string[] array = obj; foreach (string text in array) { Traverse obj2 = val.Field(text); obj2.SetValue((object)(obj2.GetValue() * num)); } array = new string[2] { "burrowSpeed", "burrowSpeed_Sneak" }; foreach (string text2 in array) { Traverse obj3 = val.Field(text2); obj3.SetValue((object)(obj3.GetValue() * num2)); } componentInChildren.diveCooldown /= num; } } } [HarmonyPatch] public static class AiWormNetworkIdentity { private struct NetworkOwnerState { public NetworkObject network_object; public ulong owner_id; } public const int MAX_AI_WORMS = 16; private const ulong FIRST_OWNER_ID = 18446744073709550591uL; public static ulong OwnerIdFor(int index) { return 18446744073709550591uL - (ulong)index; } private static bool IsReservedOwnerId(ulong owner_id) { if (owner_id <= 18446744073709550591uL) { return owner_id >= 18446744073709550576uL; } return false; } [HarmonyPatch(typeof(NetworkBehaviour), "UpdateNetworkProperties")] [HarmonyPostfix] private static void UpdateNetworkProperties_Postfix(NetworkBehaviour __instance) { NetworkManager singleton = NetworkManager.Singleton; if (!((Object)(object)singleton == (Object)null) && singleton.IsHost && !((Object)(object)__instance == (Object)null) && !((Object)(object)((Component)__instance).GetComponentInParent() == (Object)null)) { Traverse obj = Traverse.Create((object)__instance); obj.Property("IsOwner", (object[])null).SetValue((object)true); obj.Property("OwnerClientId", (object[])null).SetValue((object)singleton.LocalClientId); } } [HarmonyPatch(typeof(NetworkVariableBase), "CanClientWrite")] [HarmonyPostfix] private static void CanClientWrite_Postfix(NetworkVariableBase __instance, ulong clientId, ref bool __result) { if (!__result) { NetworkManager singleton = NetworkManager.Singleton; NetworkBehaviour val = ((__instance != null) ? __instance.GetBehaviour() : null); if ((Object)(object)singleton != (Object)null && singleton.IsHost && clientId == singleton.LocalClientId && (Object)(object)val != (Object)null && (Object)(object)((Component)val).GetComponentInParent() != (Object)null) { __result = true; } } } [HarmonyPatch(typeof(WormPlayer), "DamageWorm_ServerRPC")] [HarmonyPrefix] private static void DamageWorm_Prefix(WormPlayer __instance, ref NetworkOwnerState __state) { __state = default(NetworkOwnerState); NetworkManager singleton = NetworkManager.Singleton; if (!((Object)(object)singleton == (Object)null) && singleton.IsHost && !((Object)(object)__instance == (Object)null) && !((Object)(object)((Component)__instance).GetComponentInParent() == (Object)null)) { NetworkObject networkObject = ((NetworkBehaviour)__instance).NetworkObject; if (!((Object)(object)networkObject == (Object)null)) { __state.network_object = networkObject; __state.owner_id = networkObject.OwnerClientId; Traverse.Create((object)networkObject).Property("OwnerClientId", (object[])null).SetValue((object)singleton.LocalClientId); } } } [HarmonyPatch(typeof(WormPlayer), "DamageWorm_ServerRPC")] [HarmonyFinalizer] private static Exception DamageWorm_Finalizer(Exception __exception, NetworkOwnerState __state) { if ((Object)(object)__state.network_object != (Object)null) { Traverse.Create((object)__state.network_object).Property("OwnerClientId", (object[])null).SetValue((object)__state.owner_id); } return __exception; } [HarmonyPatch(typeof(EventFeedManager), "GetPlayerNamesFromServerAndCreateEventStringsWithThem_ServerRPC")] [HarmonyPrefix] private static void EventFeed_Prefix(ref ulong _playerID1, ref ulong _playerID2) { NetworkManager singleton = NetworkManager.Singleton; if (!((Object)(object)singleton == (Object)null) && singleton.IsHost) { if (IsReservedOwnerId(_playerID1)) { _playerID1 = singleton.LocalClientId; } if (IsReservedOwnerId(_playerID2)) { _playerID2 = singleton.LocalClientId; } } } } [HarmonyPatch] public static class BileBombRedirect { private const float ARM_WINDOW_SECONDS = 0.5f; private const float TRAVEL_SPEED = 40f; private const float ARRIVAL_RADIUS = 1f; private static bool armed; private static Vector3 armed_target; private static float armed_at = float.NegativeInfinity; private static readonly Dictionary redirects = new Dictionary(); public static void Arm(Vector3 target) { //IL_0006: 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) armed = true; armed_target = target; armed_at = Time.time; } [HarmonyPatch(typeof(BileBombProjectile), "OnNetworkSpawn")] [HarmonyPostfix] public static void OnNetworkSpawn_Postfix(BileBombProjectile __instance) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) if (armed && !((Object)(object)__instance == (Object)null)) { armed = false; if (Time.time - armed_at <= 0.5f) { redirects[__instance] = armed_target; } } } [HarmonyPatch(typeof(BileBombProjectile), "Update")] [HarmonyPrefix] public static void Update_Prefix(BileBombProjectile __instance) { //IL_0061: 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_0072: 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_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_0091: 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_009f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null || !redirects.TryGetValue(__instance, out var value)) { return; } NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || !singleton.IsHost) { return; } Rigidbody component = ((Component)__instance).GetComponent(); if (!((Object)(object)component == (Object)null)) { Collider component2 = ((Component)__instance).GetComponent(); if ((Object)(object)component2 != (Object)null) { component2.isTrigger = true; } component.useGravity = false; component.angularVelocity = Vector3.zero; Vector3 val = value - ((Component)__instance).transform.position; float magnitude = ((Vector3)(ref val)).magnitude; component.velocity = ((magnitude <= 1f) ? Vector3.zero : (val / magnitude * 40f)); } } } [HarmonyPatch] public static class GrabReleasePatches { private class ForcedRelease { public ulong worm_owner_id; public float expires_at; } private static readonly Dictionary ai_grabber = new Dictionary(); private static readonly Dictionary forced_releases = new Dictionary(); private static readonly MethodInfo mini_game_ended_client_rpc = AccessTools.Method(typeof(StruggleMiniGameHandler), "MiniGameEnded_ClientRPC", new Type[1] { typeof(ulong) }, (Type[])null); private static WormMouth last_ai_mouth; [HarmonyPatch(typeof(WormMouth), "GrabPlayer_Server")] [HarmonyPrefix] public static bool GrabPlayer_Server_Prefix(WormMouth __instance, NetworkObject pObject, ref bool __result) { if ((Object)(object)pObject != (Object)null && forced_releases.TryGetValue(pObject.OwnerClientId, out var value)) { if (Time.unscaledTime <= value.expires_at) { __result = false; return false; } forced_releases.Remove(pObject.OwnerClientId); } if (AiWormManager.IsAiWorm((Component)(object)__instance)) { last_ai_mouth = __instance; } return true; } [HarmonyPatch(typeof(WormMouth), "GrabPlayer_Server")] [HarmonyPostfix] public static void GrabPlayer_Server_Postfix(WormMouth __instance, NetworkObject pObject, bool __result) { if (__result && AiWormManager.IsAiWorm((Component)(object)__instance) && (Object)(object)pObject != (Object)null) { ai_grabber[pObject.OwnerClientId] = __instance; Player componentInParent = ((Component)pObject).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null) { WormPerception.OnTargetGrabbed(((Component)__instance).GetComponentInParent(), componentInParent); } } } [HarmonyPatch(typeof(StruggleMiniGameHandler), "StartNewStruggleMiniGame_ClientRPC")] [HarmonyPrefix] public static void StartStruggle_Prefix(ref ulong _wormPlayerObjectID) { if (!LobbyAiState.IsLocalHost || (Object)(object)last_ai_mouth == (Object)null || (Object)(object)((NetworkBehaviour)last_ai_mouth).NetworkObject == (Object)null) { return; } NetworkManager singleton = NetworkManager.Singleton; if (!((Object)(object)singleton == (Object)null)) { Dictionary spawnedObjects = singleton.SpawnManager.SpawnedObjects; if (!spawnedObjects.ContainsKey(_wormPlayerObjectID) || !((Object)(object)((Component)spawnedObjects[_wormPlayerObjectID]).GetComponentInChildren() != (Object)null)) { _wormPlayerObjectID = ((NetworkBehaviour)last_ai_mouth).NetworkObject.NetworkObjectId; } } } [HarmonyPatch(typeof(StruggleMiniGameHandler), "InformWormTheMiniGameIsOver_ServerRPC")] [HarmonyPrefix] public static bool InformWormTheMiniGameIsOver_Prefix(StruggleMiniGameHandler __instance, ulong _wormPlayerID, ulong _humanPlayerID, int _damage) { if (forced_releases.TryGetValue(_humanPlayerID, out var value)) { if (Time.unscaledTime <= value.expires_at && value.worm_owner_id == _wormPlayerID) { forced_releases.Remove(_humanPlayerID); ai_grabber.Remove(_humanPlayerID); ClearGrabbedFlag(_humanPlayerID); return false; } if (Time.unscaledTime > value.expires_at) { forced_releases.Remove(_humanPlayerID); } } NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || !singleton.IsHost || !ai_grabber.TryGetValue(_humanPlayerID, out var value2) || (Object)(object)value2 == (Object)null) { return true; } try { value2.PlayerMiniGameEnded_ServerRPC(_damage); if ((Object)(object)LobbyManager.Singleton != (Object)null && LobbyManager.Singleton.cachedClients.ContainsKey(_humanPlayerID)) { Player component = ((Component)LobbyManager.Singleton.cachedClients[_humanPlayerID].PlayerObject).GetComponent(); if ((Object)(object)component != (Object)null) { component.currentlyInWormMouth.Value = false; } } } catch (Exception ex) { Plugin.log.LogWarning((object)("ai grab-release reroute failed: " + ex.Message)); } ((MonoBehaviour)__instance).StartCoroutine(BroadcastMiniGameEndedNextFrame(__instance, _humanPlayerID)); ai_grabber.Remove(_humanPlayerID); return false; } public static bool ReleaseBeforeDespawn(WormMouth mouth) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Invalid comparison between Unknown and I4 if ((Object)(object)mouth == (Object)null || (int)mouth.thingInMouthType.Value != 2 || mouth.playerIDInMouth == 1000000) { return false; } ulong playerIDInMouth = mouth.playerIDInMouth; NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || !singleton.IsHost || !singleton.ConnectedClients.ContainsKey(playerIDInMouth)) { return false; } forced_releases[playerIDInMouth] = new ForcedRelease { worm_owner_id = ((NetworkBehaviour)mouth).OwnerClientId, expires_at = Time.unscaledTime + 10f }; ai_grabber.Remove(playerIDInMouth); if ((Object)(object)last_ai_mouth == (Object)(object)mouth) { last_ai_mouth = null; } ClearGrabbedFlag(playerIDInMouth); try { mouth.DropPlayerInOurMouth_ServerRPC(); return true; } catch (Exception ex) { forced_releases.Remove(playerIDInMouth); Plugin.log.LogWarning((object)("ai grab release before despawn failed: " + ex.Message)); return false; } } public static void ReconcileMouthFlags() { NetworkManager singleton = NetworkManager.Singleton; GameManager singleton2 = GameManager.Singleton; if ((Object)(object)singleton == (Object)null || !singleton.IsHost || (Object)(object)singleton2 == (Object)null || singleton2.humanPlayerScripts == null) { return; } foreach (Player humanPlayerScript in singleton2.humanPlayerScripts) { if ((Object)(object)humanPlayerScript == (Object)null) { continue; } bool value; try { value = humanPlayerScript.currentlyInWormMouth.Value; } catch { continue; } if (value && !IsHeldByAnyMouth(((NetworkBehaviour)humanPlayerScript).OwnerClientId)) { try { humanPlayerScript.currentlyInWormMouth.Value = false; } catch { } } } } private static bool IsHeldByAnyMouth(ulong owner_id) { foreach (GameObject ai_worm in AiWormManager.ai_worms) { if ((Object)(object)ai_worm != (Object)null && MouthHolds(ai_worm.GetComponentInChildren(true), owner_id)) { return true; } } GameManager singleton = GameManager.Singleton; if ((Object)(object)singleton != (Object)null && singleton.wormPlayerScripts != null) { foreach (WormPlayer wormPlayerScript in singleton.wormPlayerScripts) { if ((Object)(object)wormPlayerScript != (Object)null && MouthHolds(((Component)wormPlayerScript).GetComponentInChildren(true), owner_id)) { return true; } } } return false; } private static bool MouthHolds(WormMouth mouth, ulong owner_id) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Invalid comparison between Unknown and I4 if ((Object)(object)mouth != (Object)null && (int)mouth.thingInMouthType.Value == 2) { return mouth.playerIDInMouth == owner_id; } return false; } private static void ClearGrabbedFlag(ulong human_player_id) { if (!((Object)(object)LobbyManager.Singleton == (Object)null) && LobbyManager.Singleton.cachedClients.ContainsKey(human_player_id)) { Player component = ((Component)LobbyManager.Singleton.cachedClients[human_player_id].PlayerObject).GetComponent(); if ((Object)(object)component != (Object)null) { component.currentlyInWormMouth.Value = false; } } } private static IEnumerator BroadcastMiniGameEndedNextFrame(StruggleMiniGameHandler handler, ulong human_player_id) { yield return null; if ((Object)(object)handler == (Object)null || mini_game_ended_client_rpc == null) { Plugin.log.LogWarning((object)"ai grab-release cleanup rpc was unavailable"); yield break; } NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || !singleton.IsHost || !singleton.IsListening || !singleton.ConnectedClients.TryGetValue(human_player_id, out var value) || (Object)(object)value.PlayerObject == (Object)null || !singleton.SpawnManager.SpawnedObjects.ContainsKey(value.PlayerObject.NetworkObjectId)) { yield break; } try { mini_game_ended_client_rpc.Invoke(handler, new object[1] { value.PlayerObject.NetworkObjectId }); } catch (Exception ex) { Plugin.log.LogWarning((object)("ai grab-release cleanup broadcast failed: " + ex.Message)); } } } [HarmonyPatch] public static class HeartJarDropPatches { private const ulong NO_JAR = 1000000uL; [HarmonyPatch(typeof(HeartJarManager), "HandleDictionaryTimesAndSpawningJars")] [HarmonyPrefix] public static void HandleDictionaryTimes_Prefix(HeartJarManager __instance) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Invalid comparison between Unknown and I4 //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) NetworkManager singleton = NetworkManager.Singleton; GameManager singleton2 = GameManager.Singleton; if ((Object)(object)singleton == (Object)null || !singleton.IsHost || (Object)(object)singleton2 == (Object)null || (int)singleton2.gameState != 1 || __instance.heartJarInfo_MasterDictionary == null) { return; } List list = null; foreach (HeartJarInfo value in __instance.heartJarInfo_MasterDictionary.Values) { if (value != null && (int)value.lastCauseOfDeath == 0 && !(value.timeBeforeDigested > 0f) && IsSpawnable(value.heartJarState) && !VanillaCanResolve(singleton, value.wormIdWhoAteThem)) { (list ?? (list = new List())).Add(value); } } if (list == null) { return; } foreach (HeartJarInfo item in list) { try { DropEatenJar(__instance, singleton, singleton2, item); } catch (Exception ex) { Plugin.log.LogWarning((object)("ai heart-jar drop failed: " + ex.Message)); } } } private static void DropEatenJar(HeartJarManager manager, NetworkManager nm, GameManager gm, HeartJarInfo info) { //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_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0010: 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_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) Vector3 val = ResolveDropPosition(nm, info); float num = gm.CalculateSurfacedYPosition(val); if (val.y <= num) { val.y = num; } NetworkObject value; if ((int)info.heartJarState == 0) { Traverse.Create((object)manager).Method("SpawnPlayerHeartJar_ServerRPC", new object[3] { info.ownerID, val, true }).GetValue(); } else if (info.spawnedJarObjectID != 1000000 && nm.SpawnManager.SpawnedObjects.TryGetValue(info.spawnedJarObjectID, out value) && (Object)(object)value != (Object)null) { Traverse.Create((object)manager).Method("SetHeartJarToInteractable_ServerRPC", new object[1] { info.spawnedJarObjectID }).GetValue(); Rigidbody component = ((Component)value).GetComponent(); if ((Object)(object)component != (Object)null) { component.velocity = Vector3.zero; } Component component2 = ((Component)value).GetComponent("NetworkTransform"); if ((Object)(object)component2 != (Object)null) { Traverse.Create((object)component2).Method("Teleport", new object[3] { val, ((Component)value).transform.rotation, ((Component)value).transform.localScale }).GetValue(); } else { ((Component)value).transform.position = val; } if ((Object)(object)component != (Object)null) { Traverse.Create((object)manager).Method("HeartJarBoopUpwardForce", new object[1] { component }).GetValue(); } } info.heartJarState = (HeartJarState)3; } private static Vector3 ResolveDropPosition(NetworkManager nm, HeartJarInfo info) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00af: 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) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) foreach (GameObject ai_worm in AiWormManager.ai_worms) { if (!((Object)(object)ai_worm == (Object)null)) { InGameWormCosmeticBuilder componentInChildren = ai_worm.GetComponentInChildren(true); if ((Object)(object)componentInChildren != (Object)null) { return componentInChildren.GetWormTailPosition() + Vector3.up; } } } if (nm.ConnectedClients.TryGetValue(info.ownerID, out var value) && (Object)(object)value.PlayerObject != (Object)null) { return ((Component)value.PlayerObject).transform.position + Vector3.up; } return new Vector3(0f, 10f, 0f); } private static bool VanillaCanResolve(NetworkManager nm, ulong worm_id) { if (nm.ConnectedClients.TryGetValue(worm_id, out var value) && (Object)(object)value.PlayerObject != (Object)null) { return (Object)(object)((Component)value.PlayerObject).GetComponent() != (Object)null; } return false; } private static bool IsSpawnable(HeartJarState state) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Invalid comparison between Unknown and I4 //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Invalid comparison between Unknown and I4 if ((int)state != 0 && (int)state != 1) { return (int)state == 2; } return true; } } public class LobbyAiState : MonoBehaviour { private const string PREFERENCE_MESSAGE = "com.wormtown.ai.preference.v3"; private const string PREFERENCE_ACK_MESSAGE = "com.wormtown.ai.preference-ack.v3"; private const byte PROTOCOL_VERSION = 3; private const float PREFERENCE_RETRY_INITIAL_SECONDS = 1f; private const float PREFERENCE_RETRY_MAX_SECONDS = 10f; private const float PREFERENCE_CHANGE_COOLDOWN = 0.25f; private const float MOUTH_RECONCILE_INTERVAL = 0.5f; private const string SERVICE_OBJECT_NAME = "WormtownAI Runtime Services"; private static LobbyAiState instance; private readonly Dictionary enabled_clients = new Dictionary(); private readonly Dictionary next_preference_change_time = new Dictionary(); private NetworkManager network_manager; private bool registered_as_host; private bool preference_acknowledged; private float next_preference_send_time; private float preference_retry_seconds; private float next_mouth_reconcile; private WormAbilityPickerBank applied_picker; private bool loadout_saved; private bool logged_loadout_error; private int bile_bomb_index = -1; private int sand_storm_index = -1; public static bool IsLocalHost { get { NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton != (Object)null) { return singleton.IsHost; } return false; } } public static bool IsHostEnabled { get { MenuToGameBridger singleton = MenuToGameBridger.Singleton; if (IsLocalHost && EnabledWormCount > 0) { if (!((Object)(object)singleton == (Object)null)) { if (!singleton.isWormTutorial) { return !singleton.isPardnerTutorial; } return false; } return true; } return false; } } public static int EnabledWormCount { get { if (!IsLocalHost) { return 0; } if ((Object)(object)instance != (Object)null && instance.registered_as_host) { return instance.enabled_clients.Count; } return Settings.ai_enabled ? 1 : 0; } } public static bool IsClientEnabled(ulong client_id) { NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null) { return false; } if (client_id == singleton.LocalClientId) { if (Settings.ai_enabled) { if (!singleton.IsHost) { if ((Object)(object)instance != (Object)null && (Object)(object)instance.network_manager == (Object)(object)singleton) { return instance.preference_acknowledged; } return false; } return true; } return false; } if (singleton.IsHost && (Object)(object)instance != (Object)null && instance.registered_as_host) { return instance.enabled_clients.ContainsKey(client_id); } return false; } public static AiWormDifficulty GetClientDifficulty(ulong client_id) { NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton != (Object)null && client_id == singleton.LocalClientId) { return Settings.ai_difficulty; } if ((Object)(object)singleton != (Object)null && singleton.IsHost && (Object)(object)instance != (Object)null && instance.enabled_clients.TryGetValue(client_id, out var value)) { return value; } return AiWormDifficulty.Garden; } public static IEnumerable GetEnabledClientIds() { NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || !singleton.IsHost) { yield break; } if ((Object)(object)instance != (Object)null && instance.registered_as_host) { foreach (ulong key in instance.enabled_clients.Keys) { yield return key; } } else if (Settings.ai_enabled) { yield return singleton.LocalClientId; } } public static void Initialize(bool enabled, AiWormDifficulty difficulty) { Settings.ai_enabled = enabled; Settings.ai_difficulty = AiWormDifficultyRules.Clamp((int)difficulty); } public static bool EnsureAvailable() { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown if ((Object)(object)instance != (Object)null) { return true; } try { LobbyAiState lobbyAiState = Object.FindObjectOfType(); GameObject val = (((Object)(object)lobbyAiState != (Object)null) ? ((Component)lobbyAiState).gameObject : GameObject.Find("WormtownAI Runtime Services")); if ((Object)(object)val == (Object)null) { val = new GameObject("WormtownAI Runtime Services"); Object.DontDestroyOnLoad((Object)(object)val); } lobbyAiState = val.GetComponent(); if ((Object)(object)lobbyAiState == (Object)null) { lobbyAiState = val.AddComponent(); } instance = lobbyAiState; return (Object)(object)instance != (Object)null; } catch (Exception ex) { Plugin.log.LogWarning((object)("[ai-toggle] coordinator creation failed: " + ex.Message)); return false; } } public static void SetLocalEnabled(bool enabled) { if (!EnsureAvailable()) { Plugin.log.LogWarning((object)"[ai-toggle] coordinator unavailable; setting unchanged"); return; } Settings.ai_enabled = enabled; Plugin.SaveLocalPreferences(); instance.applied_picker = null; instance.loadout_saved = false; TeamPatches.ResetAssignments(); if ((Object)(object)instance.network_manager != (Object)null && instance.registered_as_host) { if (instance.SetClientPreference(instance.network_manager.LocalClientId, enabled, Settings.ai_difficulty)) { instance.OnEnabledClientsChanged(); } } else { instance.ResetPreferenceSends(); instance.TrySendLocalPreference(); } Plugin.log.LogInfo((object)$"[ai-toggle] local AI Worm enabled = {enabled}"); } public static void SetLocalDifficulty(AiWormDifficulty difficulty) { difficulty = AiWormDifficultyRules.Clamp((int)difficulty); if (difficulty == Settings.ai_difficulty || !EnsureAvailable()) { return; } Settings.ai_difficulty = difficulty; Plugin.SaveLocalPreferences(); if ((Object)(object)instance.network_manager != (Object)null && instance.registered_as_host) { if (instance.SetClientPreference(instance.network_manager.LocalClientId, Settings.ai_enabled, difficulty)) { instance.OnEnabledClientsChanged(); } } else { instance.ResetPreferenceSends(); instance.TrySendLocalPreference(); } Plugin.log.LogInfo((object)("[ai-toggle] local AI Worm difficulty = " + AiWormDifficultyRules.DisplayName(difficulty))); } public static bool EnsureAiLoadout() { if ((Object)(object)instance != (Object)null && IsHostEnabled) { if (!instance.loadout_saved) { return instance.TryApplyAiLoadout(); } return true; } return false; } public static bool ApplyAiLoadout(WormAbilityManager ability_manager) { if ((Object)(object)ability_manager == (Object)null || !IsLocalHost) { return false; } int num = (((Object)(object)instance != (Object)null) ? instance.bile_bomb_index : (-1)); int num2 = (((Object)(object)instance != (Object)null) ? instance.sand_storm_index : (-1)); if (num < 0 || num2 < 0) { WormAbility[] value = Traverse.Create((object)ability_manager).Field("abilityBank").GetValue(); num = FindAbilityIndex(value); num2 = FindAbilityIndex(value); if (num < 0 || num2 < 0) { return false; } if ((Object)(object)instance != (Object)null) { instance.bile_bomb_index = num; instance.sand_storm_index = num2; } } ability_manager.AddAbility(1, num); ability_manager.AddAbility(2, num2); return true; } private void Awake() { if ((Object)(object)instance != (Object)null && (Object)(object)instance != (Object)(object)this) { Object.Destroy((Object)(object)((Component)this).gameObject); return; } instance = this; Plugin.log.LogInfo((object)"[ai-toggle] coordinator ready"); } private void OnDestroy() { UnregisterNetworkManager(); if ((Object)(object)instance == (Object)(object)this) { instance = null; Plugin.log.LogInfo((object)"[ai-toggle] coordinator stopped"); } } private void Update() { NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)network_manager != (Object)null && ((Object)(object)network_manager != (Object)(object)singleton || !network_manager.IsListening)) { UnregisterNetworkManager(); } if ((Object)(object)network_manager == (Object)null && (Object)(object)singleton != (Object)null && singleton.IsListening) { RegisterNetworkManager(singleton); } if ((Object)(object)network_manager == (Object)null) { return; } if (registered_as_host) { if (IsHostEnabled) { TeamPatches.EnsureEnabledPlayersArePardners(); if (!loadout_saved || (Object)(object)applied_picker != (Object)(object)WormAbilityPickerBank.Singleton) { TryApplyAiLoadout(); } if (Time.unscaledTime >= next_mouth_reconcile) { next_mouth_reconcile = Time.unscaledTime + 0.5f; GrabReleasePatches.ReconcileMouthFlags(); } } } else { TrySendLocalPreference(); } } private void RegisterNetworkManager(NetworkManager manager) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected O, but got Unknown //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Expected O, but got Unknown network_manager = manager; registered_as_host = manager.IsHost; preference_acknowledged = false; enabled_clients.Clear(); next_preference_change_time.Clear(); manager.CustomMessagingManager.RegisterNamedMessageHandler("com.wormtown.ai.preference.v3", new HandleNamedMessageDelegate(ReceivePreference)); manager.CustomMessagingManager.RegisterNamedMessageHandler("com.wormtown.ai.preference-ack.v3", new HandleNamedMessageDelegate(ReceivePreferenceAck)); manager.OnClientConnectedCallback += OnClientConnected; manager.OnClientDisconnectCallback += OnClientDisconnected; TeamPatches.ResetAssignments(); if (registered_as_host) { SetClientPreference(manager.LocalClientId, Settings.ai_enabled, Settings.ai_difficulty); OnEnabledClientsChanged(); } else { ResetPreferenceSends(); } } private void UnregisterNetworkManager() { if (!((Object)(object)network_manager == (Object)null)) { try { network_manager.CustomMessagingManager.UnregisterNamedMessageHandler("com.wormtown.ai.preference.v3"); network_manager.CustomMessagingManager.UnregisterNamedMessageHandler("com.wormtown.ai.preference-ack.v3"); network_manager.OnClientConnectedCallback -= OnClientConnected; network_manager.OnClientDisconnectCallback -= OnClientDisconnected; } catch { } network_manager = null; registered_as_host = false; preference_acknowledged = false; enabled_clients.Clear(); next_preference_change_time.Clear(); applied_picker = null; TeamPatches.ResetAssignments(); } } private void OnClientConnected(ulong client_id) { if (!registered_as_host && (Object)(object)network_manager != (Object)null && client_id == network_manager.LocalClientId) { ResetPreferenceSends(); } } private void OnClientDisconnected(ulong client_id) { next_preference_change_time.Remove(client_id); if (registered_as_host && enabled_clients.Remove(client_id)) { OnEnabledClientsChanged(); } } private bool SetClientPreference(ulong client_id, bool enabled, AiWormDifficulty difficulty) { if (!enabled) { return enabled_clients.Remove(client_id); } difficulty = AiWormDifficultyRules.Clamp((int)difficulty); if (enabled_clients.TryGetValue(client_id, out var value) && value == difficulty) { return false; } enabled_clients[client_id] = difficulty; return true; } private void OnEnabledClientsChanged() { applied_picker = null; loadout_saved = false; TeamPatches.ResetAssignments(); if (IsHostEnabled) { try { ApplyEnabledEffects(); } catch (Exception ex) { Plugin.log.LogWarning((object)("[ai-toggle] enable side effect failed: " + ex.Message)); } } AiWormManager.ReconcileSpawnedWorms(); } private void ResetPreferenceSends() { preference_acknowledged = false; next_preference_send_time = Time.unscaledTime; preference_retry_seconds = 1f; } private unsafe void TrySendLocalPreference() { //IL_007a: Unknown result type (might be due to invalid IL or missing references) if (registered_as_host || preference_acknowledged || (Object)(object)network_manager == (Object)null || !network_manager.IsConnectedClient || Time.unscaledTime < next_preference_send_time) { return; } try { FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(3, (Allocator)2, 3); try { ((FastBufferWriter)(ref val)).WriteByteSafe((byte)3); ((FastBufferWriter)(ref val)).WriteByteSafe(Settings.ai_enabled ? ((byte)1) : ((byte)0)); ((FastBufferWriter)(ref val)).WriteByteSafe((byte)Settings.ai_difficulty); network_manager.CustomMessagingManager.SendNamedMessage("com.wormtown.ai.preference.v3", 0uL, val, (NetworkDelivery)2); } finally { ((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose(); } } catch { } next_preference_send_time = Time.unscaledTime + preference_retry_seconds; preference_retry_seconds = Mathf.Min(10f, preference_retry_seconds * 2f); } private void ReceivePreference(ulong sender_client_id, FastBufferReader reader) { if (!registered_as_host || (Object)(object)network_manager == (Object)null || !network_manager.IsHost || !network_manager.ConnectedClients.ContainsKey(sender_client_id) || ((FastBufferReader)(ref reader)).Length < 3) { return; } byte b = default(byte); byte b2 = default(byte); byte b3 = default(byte); try { ((FastBufferReader)(ref reader)).ReadByteSafe(ref b); ((FastBufferReader)(ref reader)).ReadByteSafe(ref b2); ((FastBufferReader)(ref reader)).ReadByteSafe(ref b3); } catch { return; } if (b != 3 || b2 > 1 || b3 > 2) { return; } bool flag = b2 != 0; AiWormDifficulty aiWormDifficulty = (AiWormDifficulty)b3; AiWormDifficulty value; bool flag2 = enabled_clients.TryGetValue(sender_client_id, out value); bool flag3 = flag2 != flag; if (flag3 || (flag && value != aiWormDifficulty)) { if (!IsPreferenceChangeAllowed() || (flag3 && next_preference_change_time.TryGetValue(sender_client_id, out var value2) && Time.unscaledTime < value2)) { SendPreferenceAck(sender_client_id, flag2, flag2 ? value : aiWormDifficulty); return; } if (flag3) { next_preference_change_time[sender_client_id] = Time.unscaledTime + 0.25f; } SetClientPreference(sender_client_id, flag, aiWormDifficulty); OnEnabledClientsChanged(); Plugin.log.LogInfo((object)($"[ai-toggle] client {sender_client_id} AI Worm enabled = {flag}, " + "difficulty = " + AiWormDifficultyRules.DisplayName(aiWormDifficulty))); } SendPreferenceAck(sender_client_id, flag, aiWormDifficulty); } private void ReceivePreferenceAck(ulong sender_client_id, FastBufferReader reader) { if (!registered_as_host && !((Object)(object)network_manager == (Object)null) && sender_client_id == 0L && ((FastBufferReader)(ref reader)).Length >= 3) { byte b = default(byte); byte b2 = default(byte); byte b3 = default(byte); try { ((FastBufferReader)(ref reader)).ReadByteSafe(ref b); ((FastBufferReader)(ref reader)).ReadByteSafe(ref b2); ((FastBufferReader)(ref reader)).ReadByteSafe(ref b3); } catch { return; } if (b == 3 && b2 != 0 == Settings.ai_enabled && (uint)b3 == (uint)Settings.ai_difficulty) { preference_acknowledged = true; } } } private static bool IsPreferenceChangeAllowed() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) GameManager singleton = GameManager.Singleton; MenuToGameBridger singleton2 = MenuToGameBridger.Singleton; if ((Object)(object)singleton != (Object)null && (int)singleton.gameState == 0) { if (!((Object)(object)singleton2 == (Object)null)) { if (!singleton2.isWormTutorial) { return !singleton2.isPardnerTutorial; } return false; } return true; } return false; } private unsafe void SendPreferenceAck(ulong client_id, bool enabled, AiWormDifficulty difficulty) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) try { FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(3, (Allocator)2, 3); try { ((FastBufferWriter)(ref val)).WriteByteSafe((byte)3); ((FastBufferWriter)(ref val)).WriteByteSafe(enabled ? ((byte)1) : ((byte)0)); ((FastBufferWriter)(ref val)).WriteByteSafe((byte)difficulty); network_manager.CustomMessagingManager.SendNamedMessage("com.wormtown.ai.preference-ack.v3", client_id, val, (NetworkDelivery)2); } finally { ((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose(); } } catch { } } private void ApplyEnabledEffects() { if (IsHostEnabled) { Plugin.EnsurePolicyLoaded(); TeamPatches.EnsureEnabledPlayersArePardners(); TryApplyAiLoadout(); } } private bool TryApplyAiLoadout() { try { MenuToGameBridger singleton = MenuToGameBridger.Singleton; if (!IsHostEnabled || (Object)(object)singleton == (Object)null || singleton.savedWormAbilitySet == null || !TryResolveAiLoadout(null)) { return false; } singleton.savedWormAbilitySet.savedSlotAbilityIndex_1 = bile_bomb_index; singleton.savedWormAbilitySet.savedSlotAbilityIndex_2 = sand_storm_index; loadout_saved = true; WormAbilityPickerBank singleton2 = WormAbilityPickerBank.Singleton; if ((Object)(object)singleton2 == (Object)null) { return true; } if (singleton2.slotButtons == null || singleton2.slotButtons.Length < 3 || singleton2.pickerBank == null || bile_bomb_index >= singleton2.pickerBank.Length || sand_storm_index >= singleton2.pickerBank.Length) { LogLoadoutError("could not refresh the worm ability picker"); return true; } singleton2.AssignNewAbility(1, bile_bomb_index); singleton2.AssignNewAbility(2, sand_storm_index); applied_picker = singleton2; logged_loadout_error = false; Plugin.log.LogInfo((object)"[ai-toggle] set worm powers to Bile Bomb and Sandstorm"); return true; } catch (Exception ex) { LogLoadoutError("could not assign the required worm abilities: " + ex.Message); return false; } } private bool TryResolveAiLoadout(WormAbilityManager ability_manager) { if (bile_bomb_index >= 0 && sand_storm_index >= 0) { return true; } if ((Object)(object)ability_manager == (Object)null && (Object)(object)GameManager.Singleton != (Object)null && (Object)(object)GameManager.Singleton.wormPrefab != (Object)null) { ability_manager = GameManager.Singleton.wormPrefab.GetComponentInChildren(true); } WormAbility[] ability_bank = (((Object)(object)ability_manager != (Object)null) ? Traverse.Create((object)ability_manager).Field("abilityBank").GetValue() : null); bile_bomb_index = FindAbilityIndex(ability_bank); sand_storm_index = FindAbilityIndex(ability_bank); if (bile_bomb_index >= 0 && sand_storm_index >= 0) { return true; } WormAbilityPickerBank singleton = WormAbilityPickerBank.Singleton; WormAbilityUIPicker[] picker_bank = (((Object)(object)singleton != (Object)null) ? singleton.pickerBank : null); bile_bomb_index = FindPickerAbilityIndex(picker_bank, "bilebomb"); sand_storm_index = FindPickerAbilityIndex(picker_bank, "sandstorm"); if (bile_bomb_index >= 0 && sand_storm_index >= 0) { return true; } LogLoadoutError("could not resolve the required worm abilities"); return false; } private void LogLoadoutError(string message) { if (!logged_loadout_error) { logged_loadout_error = true; Plugin.log.LogWarning((object)("[ai-toggle] " + message)); } } private static int FindAbilityIndex(WormAbility[] ability_bank) where TAbility : WormAbility { if (ability_bank == null) { return -1; } for (int i = 0; i < ability_bank.Length; i++) { if (ability_bank[i] is TAbility) { return i; } } return -1; } private static int FindPickerAbilityIndex(WormAbilityUIPicker[] picker_bank, string ability_key) { if (picker_bank == null) { return -1; } for (int i = 0; i < picker_bank.Length; i++) { WormAbilityUIPicker val = picker_bank[i]; if ((Object)(object)val != (Object)null && (NormalizeAbilityKey(val.abilityName).Contains(ability_key) || NormalizeAbilityKey(((Object)val).name).Contains(ability_key))) { return i; } } return -1; } private static string NormalizeAbilityKey(string value) { if (string.IsNullOrEmpty(value)) { return string.Empty; } char[] array = new char[value.Length]; int length = 0; foreach (char c in value) { if (char.IsLetterOrDigit(c)) { array[length++] = char.ToLowerInvariant(c); } } return new string(array, 0, length); } } [HarmonyPatch] public static class LobbyAiStatePatches { [HarmonyPatch(typeof(LobbyManager), "OnNetworkSpawn", new Type[] { })] [HarmonyPostfix] public static void OnNetworkSpawn_Postfix() { LobbyAiState.EnsureAvailable(); } } [HarmonyPatch] public static class LobbySettingsUI { private const string PANEL_NAME = "Worm AI Panel"; private const string TOGGLE_BUTTON_NAME = "Toggle Button (ITS A BUTTON, Toggles are dumb)"; private const float PANEL_HEIGHT = 220f; private const float PANEL_GAP = 12f; private const float TITLE_Y = 72f; private const float TOGGLE_Y = 5f; private const float DIFFICULTY_Y = -63f; [HarmonyPatch(typeof(ConnectedPlayerLobbyPanel), "SetupPanel")] [HarmonyPostfix] public static void SetupPanel_Postfix() { EnsurePanel(); } [HarmonyPatch(typeof(MatchSettingsManager), "OnNetworkSpawn")] [HarmonyPostfix] public static void MatchSettingsManager_OnNetworkSpawn_Postfix() { EnsurePanel(); } private static void EnsurePanel() { try { LobbyAiState.EnsureAvailable(); TryAdd(); } catch (Exception ex) { Plugin.log.LogWarning((object)("[ai-toggle] failed: " + ex.Message)); } } private static void TryAdd() { //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Expected O, but got Unknown //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Unknown result type (might be due to invalid IL or missing references) //IL_024a: Unknown result type (might be due to invalid IL or missing references) //IL_0262: Unknown result type (might be due to invalid IL or missing references) //IL_026e: Unknown result type (might be due to invalid IL or missing references) //IL_029b: Unknown result type (might be due to invalid IL or missing references) //IL_02a7: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_0305: Unknown result type (might be due to invalid IL or missing references) //IL_0369: Unknown result type (might be due to invalid IL or missing references) //IL_03fa: Unknown result type (might be due to invalid IL or missing references) //IL_0404: Expected O, but got Unknown //IL_0494: Unknown result type (might be due to invalid IL or missing references) //IL_0544: Unknown result type (might be due to invalid IL or missing references) //IL_054e: Expected O, but got Unknown //IL_05c8: Unknown result type (might be due to invalid IL or missing references) MatchSettingsManager val = Object.FindObjectOfType(); if ((Object)(object)val == (Object)null) { return; } GameObject val2 = RefGameObject(val, "WormAbilityScream_CheckBox_CheckMarkImage"); Transform val3 = (((Object)(object)val2 != (Object)null) ? val2.transform.parent : null); Transform val4 = (((Object)(object)val3 != (Object)null) ? val3.parent : null); Transform val5 = (((Object)(object)val4 != (Object)null) ? val4.parent : null); if ((Object)(object)val4 == (Object)null || (Object)(object)val5 == (Object)null || (Object)(object)val5.Find("Worm AI Panel") != (Object)null) { return; } Transform val6 = val5.Find("Backer"); Transform val7 = val5.Find("Worm Settings Header"); Transform val8 = FindMapGroup(val); Transform val9 = (((Object)(object)val8 != (Object)null) ? val8.Find("Backer") : null); Transform val10 = (((Object)(object)val9 != (Object)null) ? val9 : val6); Component val11 = RefComponent(HudManager.Singleton, "matchSettings_WormAbilityCooldown_DifficultyText"); Transform val12 = (((Object)(object)val11 != (Object)null) ? FindDirectChildAncestor(val11.transform, val5) : null); if ((Object)(object)val6 == (Object)null || (Object)(object)val7 == (Object)null || (Object)(object)val10 == (Object)null || (Object)(object)val12 == (Object)null) { Plugin.log.LogWarning((object)"[ai-toggle] source panel objects not found"); return; } GameObject val13 = null; try { val13 = new GameObject("Worm AI Panel", new Type[1] { typeof(RectTransform) }); val13.transform.SetParent(val5, false); RectTransform component = val13.GetComponent(); RectTransform component2 = ((Component)val6).GetComponent(); Rect rect = component2.rect; float num = Mathf.Abs(((Rect)(ref rect)).width); if (num < 1f) { num = Mathf.Abs(component2.sizeDelta.x); } rect = component2.rect; float num2 = Mathf.Abs(((Rect)(ref rect)).height); if (num2 < 1f) { num2 = Mathf.Abs(component2.sizeDelta.y); } float num3 = component2.anchoredPosition.y - num2 * component2.pivot.y; component.anchorMin = component2.anchorMin; component.anchorMax = component2.anchorMax; component.pivot = new Vector2(0.5f, 0.5f); component.sizeDelta = new Vector2(num, 220f); component.anchoredPosition = new Vector2(component2.anchoredPosition.x, num3 - 12f - 110f); ((Transform)component).localScale = Vector3.one; GameObject val14 = Object.Instantiate(((Component)val10).gameObject, val13.transform); ((Object)val14).name = "Backer"; PlaceChild(val14, Vector2.zero, (Vector2?)new Vector2(num, 220f)); Image component3 = val14.GetComponent(); if ((Object)(object)component3 != (Object)null) { ((Graphic)component3).raycastTarget = false; } GameObject val15 = Object.Instantiate(((Component)val7).gameObject, val13.transform); ((Object)val15).name = "Worm AI Header"; StripLocalizers(val15); PlaceChild(val15, new Vector2(0f, 72f), null); SetFirstLabel(val15, "Worm AI"); GameObject val16 = Object.Instantiate(((Component)val4).gameObject, val13.transform); ((Object)val16).name = "Enable Worm AI Group"; StripLocalizers(val16); RemoveChild(val16.transform, "Sub Label"); PlaceChild(val16, new Vector2(0f, 5f), null); SetFirstLabel(val16, "Enable AI Worm"); Transform val17 = val16.transform.Find("Toggle Button (ITS A BUTTON, Toggles are dumb)"); Button val18 = (((Object)(object)val17 != (Object)null) ? ((Component)val17).GetComponent