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 Magic Supremacy v2.1.9
plugins/Magic_Supremacy.dll
Decompiled 2 months ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Security; using System.Security.Cryptography; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Threading; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using ItemManager; using JetBrains.Annotations; using LocalizationManager; using Magic_Supremacy; using Microsoft.CodeAnalysis; using PieceManager; using ServerSync; using Splatform; using TMPro; using UnityEngine; using UnityEngine.UI; using YamlDotNet.Core; using YamlDotNet.Core.Events; using YamlDotNet.Core.Tokens; using YamlDotNet.Helpers; using YamlDotNet.Serialization; using YamlDotNet.Serialization.BufferedDeserialization; using YamlDotNet.Serialization.BufferedDeserialization.TypeDiscriminators; using YamlDotNet.Serialization.Converters; using YamlDotNet.Serialization.EventEmitters; using YamlDotNet.Serialization.NamingConventions; using YamlDotNet.Serialization.NodeDeserializers; using YamlDotNet.Serialization.NodeTypeResolvers; using YamlDotNet.Serialization.ObjectFactories; using YamlDotNet.Serialization.ObjectGraphTraversalStrategies; using YamlDotNet.Serialization.ObjectGraphVisitors; using YamlDotNet.Serialization.Schemas; using YamlDotNet.Serialization.TypeInspectors; using YamlDotNet.Serialization.TypeResolvers; using YamlDotNet.Serialization.Utilities; using YamlDotNet.Serialization.ValueDeserializers; [assembly: AssemblyFileVersion("2.1.9")] [assembly: Guid("4358610B-F3F4-4843-B7AF-98B7BC60DCDE")] [assembly: ComVisible(false)] [assembly: AssemblyTrademark("")] [assembly: AssemblyCopyright("Copyright © 2021")] [assembly: AssemblyProduct("Magic_Supremacy")] [assembly: AssemblyCompany("Dreanegade")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyDescription("")] [assembly: AssemblyTitle("Magic_Supremacy")] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: CompilationRelaxations(8)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2.1.9.0")] [module: UnverifiableCode] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [<58040e1a-0c6a-4780-8472-5838ad4d2d68>Embedded] internal sealed class <58040e1a-0c6a-4780-8472-5838ad4d2d68>EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] [<58040e1a-0c6a-4780-8472-5838ad4d2d68>Embedded] internal sealed class <839beae5-12ea-4eaa-8a82-47e46d9c3654>NullableAttribute : Attribute { public readonly byte[] NullableFlags; public <839beae5-12ea-4eaa-8a82-47e46d9c3654>NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public <839beae5-12ea-4eaa-8a82-47e46d9c3654>NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] [<58040e1a-0c6a-4780-8472-5838ad4d2d68>Embedded] internal sealed class <44d44cce-7ad9-4445-90b1-2eb839d16508>NullableContextAttribute : Attribute { public readonly byte Flag; public <44d44cce-7ad9-4445-90b1-2eb839d16508>NullableContextAttribute(byte P_0) { Flag = P_0; } } } [<44d44cce-7ad9-4445-90b1-2eb839d16508>NullableContext(1)] [<839beae5-12ea-4eaa-8a82-47e46d9c3654>Nullable(0)] internal sealed class ConfigurationManagerAttributes { [<44d44cce-7ad9-4445-90b1-2eb839d16508>NullableContext(0)] public delegate void CustomHotkeyDrawerFunc(ConfigEntryBase setting, ref bool isCurrentlyAcceptingInput); public bool? ShowRangeAsPercent; public Action<ConfigEntryBase> CustomDrawer; public CustomHotkeyDrawerFunc CustomHotkeyDrawer; public bool? Browsable; public string Category; public object DefaultValue; public bool? HideDefaultButton; public bool? HideSettingName; public string Description; public string DispName; public int? Order; public bool? ReadOnly; public bool? IsAdvanced; public Func<object, string> ObjToStr; public Func<string, object> StrToObj; } [<44d44cce-7ad9-4445-90b1-2eb839d16508>NullableContext(1)] [<839beae5-12ea-4eaa-8a82-47e46d9c3654>Nullable(0)] public static class ExtraStats { [<44d44cce-7ad9-4445-90b1-2eb839d16508>NullableContext(0)] private static class DevLog { public const bool Enabled = false; public const bool AttackSpeed = false; public const bool WetImmune = false; public const bool Tooltips = false; public const bool FoodStats = false; } [<44d44cce-7ad9-4445-90b1-2eb839d16508>NullableContext(0)] public enum ExtraStatType { Health, Stamina, Eitr, AttackSpeed, WetImmune } [<44d44cce-7ad9-4445-90b1-2eb839d16508>NullableContext(0)] public enum ExtraSourceType { ItemDrop, StatusEffect } [<839beae5-12ea-4eaa-8a82-47e46d9c3654>Nullable(0)] public class ExtraStatEntry { public string PrefabName; public ExtraStatType StatType; public float Value; public float? DisplayValue; public ExtraSourceType SourceType; public ExtraStatEntry(string prefab, ExtraStatType stat, float value, ExtraSourceType source) { PrefabName = prefab; StatType = stat; Value = value; DisplayValue = null; SourceType = source; } public ExtraStatEntry(string prefab, ExtraStatType stat, float value, float? displayValue, ExtraSourceType source) { PrefabName = prefab; StatType = stat; Value = value; DisplayValue = displayValue; SourceType = source; } } [HarmonyPatch(typeof(Player), "GetTotalFoodValue")] [<44d44cce-7ad9-4445-90b1-2eb839d16508>NullableContext(0)] public static class Player_GetTotalFoodValue_ExtraStatsPatch { [<44d44cce-7ad9-4445-90b1-2eb839d16508>NullableContext(1)] private static void Postfix(Player __instance, ref float hp, ref float stamina, ref float eitr) { if ((Object)(object)__instance == (Object)null) { return; } float num = 0f; float num2 = 0f; float num3 = 0f; try { Inventory inventory = ((Humanoid)__instance).GetInventory(); if (inventory != null) { foreach (ItemData equippedItem in inventory.GetEquippedItems()) { if (equippedItem != null && !((Object)(object)equippedItem.m_dropPrefab == (Object)null)) { string name = ((Object)equippedItem.m_dropPrefab).name; GetItemDropBonusesForPrefab(name, out var extraHp, out var extraStamina, out var extraEitr, out var _, out var _); if (extraHp != 0f || extraStamina != 0f || extraEitr != 0f) { num += extraHp; num2 += extraStamina; num3 += extraEitr; DLogFood($"ItemDrop matched for food stats: {name} → +HP {extraHp}, +Stamina {extraStamina}, +Eitr {extraEitr}"); } } } } if (((Character)__instance).m_seman != null && ((Character)__instance).m_seman.m_statusEffects != null) { foreach (StatusEffect statusEffect in ((Character)__instance).m_seman.m_statusEffects) { if (!((Object)(object)statusEffect == (Object)null)) { string name2 = ((Object)statusEffect).name; GetStatusEffectBonuses(name2, out var extraHp2, out var extraStamina2, out var extraEitr2, out var _, out var _); if (extraHp2 != 0f || extraStamina2 != 0f || extraEitr2 != 0f) { num += extraHp2; num2 += extraStamina2; num3 += extraEitr2; string prefabName = Utils.GetPrefabName(name2); DLogFood($"StatusEffect matched for food stats: {name2} (clean={prefabName}) → +HP {extraHp2}, +Stamina {extraStamina2}, +Eitr {extraEitr2}"); } } } } } catch (Exception ex) { LogError("Exception in ExtraStats Player.GetTotalFoodValue Postfix: " + ex); } if (num != 0f || num2 != 0f || num3 != 0f) { DLogFood($"Total food bonuses applied to player: +HP {num}, +Stamina {num2}, +Eitr {num3}"); hp += num; stamina += num2; eitr += num3; } } } [<839beae5-12ea-4eaa-8a82-47e46d9c3654>Nullable(0)] [HarmonyPatch] public static class ItemData_StaticGetTooltip_ExtraStatsPatch { private static MethodBase TargetMethod() { return AccessTools.Method(typeof(ItemData), "GetTooltip", new Type[5] { typeof(ItemData), typeof(int), typeof(bool), typeof(float), typeof(int) }, (Type[])null); } private static void Postfix(ItemData item, int qualityLevel, bool crafting, float worldLevel, int stackOverride, ref string __result) { try { if (item == null || (Object)(object)item.m_dropPrefab == (Object)null) { return; } string name = ((Object)item.m_dropPrefab).name; DLogTooltip($"Static GetTooltip Postfix called for {name}, q={qualityLevel}, crafting={crafting}, worldLevel={worldLevel}, stackOverride={stackOverride}"); GetItemDropBonusesForPrefab(name, out var extraHp, out var extraStamina, out var extraEitr, out var _, out var displayAttackSpeedPercent, out var wetImmune); if (extraHp != 0f || extraStamina != 0f || extraEitr != 0f || displayAttackSpeedPercent != 0f || wetImmune) { string text = BuildExtraStatsTooltipBlock(extraHp, extraStamina, extraEitr, displayAttackSpeedPercent, wetImmune); if (!string.IsNullOrEmpty(text)) { DLogTooltip($"Appending extras for {name}: HP {extraHp}, Stamina {extraStamina}, Eitr {extraEitr}, AttackSpeed(Display)% {displayAttackSpeedPercent}, WetImmune {wetImmune}"); __result += text; } } } catch (Exception ex) { LogError("Exception in ItemData_StaticGetTooltip_ExtraStatsPatch: " + ex); } } } [<44d44cce-7ad9-4445-90b1-2eb839d16508>NullableContext(0)] [HarmonyPatch(typeof(SE_Stats), "GetTooltipString")] public static class SE_Stats_GetTooltipString_ExtraStatsPatch { [<44d44cce-7ad9-4445-90b1-2eb839d16508>NullableContext(1)] private static void Postfix(SE_Stats __instance, ref string __result) { try { if ((Object)(object)__instance == (Object)null) { return; } string name = ((Object)__instance).name; string prefabName = Utils.GetPrefabName(name); DLogTooltip("SE GetTooltipString for " + name + " (clean=" + prefabName + ")"); GetStatusEffectBonuses(name, out var extraHp, out var extraStamina, out var extraEitr, out var _, out var displayAttackSpeedPercent, out var wetImmune); if (extraHp != 0f || extraStamina != 0f || extraEitr != 0f || displayAttackSpeedPercent != 0f || wetImmune) { string text = BuildExtraStatsTooltipBlock(extraHp, extraStamina, extraEitr, displayAttackSpeedPercent, wetImmune); if (!string.IsNullOrEmpty(text)) { DLogTooltip($"Appending SE extras for {name} (clean={prefabName}): HP {extraHp}, Stamina {extraStamina}, Eitr {extraEitr}, AttackSpeed(Display)% {displayAttackSpeedPercent}, WetImmune {wetImmune}"); __result += text; } } } catch (Exception ex) { LogError("Exception in SE_Stats_GetTooltipString_ExtraStatsPatch: " + ex); } } } [<44d44cce-7ad9-4445-90b1-2eb839d16508>NullableContext(0)] private sealed class HumanoidState { public float DesiredSpeed = 1f; public float LastAppliedSpeed = 1f; public bool HasDesiredSpeed; public bool WasInAttack; public int ActiveAttackDepth; public float ActiveAttackMul = 1f; } [<44d44cce-7ad9-4445-90b1-2eb839d16508>NullableContext(0)] [HarmonyPatch(typeof(Humanoid), "StartAttack", new Type[] { typeof(Character), typeof(bool) })] public static class Humanoid_StartAttack_AttackSpeedPatch { [HarmonyPostfix] [<44d44cce-7ad9-4445-90b1-2eb839d16508>NullableContext(1)] private static void Postfix(Humanoid __instance, Character target, bool secondaryAttack, ref bool __result) { EnsureAttackInit(); if (!__result) { return; } HumanoidState attackState = GetAttackState(__instance); float num = ComputeTotalAttackSpeedPercentForHumanoid(__instance); if (num == 0f) { attackState.DesiredSpeed = 1f; attackState.HasDesiredSpeed = false; ApplyAnimSpeed(__instance, attackState, 1f); attackState.ActiveAttackDepth = 0; attackState.ActiveAttackMul = 1f; return; } float num2 = 1f + num / 100f; if (num2 <= 0f || float.IsNaN(num2) || float.IsInfinity(num2)) { attackState.DesiredSpeed = 1f; attackState.HasDesiredSpeed = false; ApplyAnimSpeed(__instance, attackState, 1f); attackState.ActiveAttackDepth = 0; attackState.ActiveAttackMul = 1f; } else { attackState.DesiredSpeed = num2; attackState.HasDesiredSpeed = true; ApplyAnimSpeed(__instance, attackState, num2); attackState.ActiveAttackDepth++; attackState.ActiveAttackMul = num2; DLogAttackSpeed($"StartAttack: total AttackSpeed%={num} → mul={num2} (activeDepth={attackState.ActiveAttackDepth})"); } } } [<44d44cce-7ad9-4445-90b1-2eb839d16508>NullableContext(0)] [HarmonyPatch(typeof(Attack), "Stop")] public static class Attack_Stop_AttackSpeedResetPatch { [<44d44cce-7ad9-4445-90b1-2eb839d16508>NullableContext(1)] [HarmonyPostfix] private static void Postfix(Attack __instance) { try { EnsureAttackInit(); if (__instance != null) { Humanoid character = __instance.m_character; if (!((Object)(object)character == (Object)null)) { ResetForHumanoid(character); DLogAttackSpeed("Attack.Stop: ResetForHumanoid"); } } } catch (Exception) { } } } [<44d44cce-7ad9-4445-90b1-2eb839d16508>NullableContext(0)] [HarmonyPatch(typeof(Humanoid), "UpdateAttack")] public static class Humanoid_UpdateAttack_AttackSpeedDtPatch { [HarmonyPrefix] [<44d44cce-7ad9-4445-90b1-2eb839d16508>NullableContext(1)] private static void Prefix(Humanoid __instance, ref float dt) { try { EnsureAttackInit(); if ((Object)(object)__instance == (Object)null) { return; } HumanoidState attackState = GetAttackState(__instance); if (attackState.ActiveAttackDepth > 0) { float activeAttackMul = attackState.ActiveAttackMul; if (!(activeAttackMul <= 0f) && !float.IsNaN(activeAttackMul) && !float.IsInfinity(activeAttackMul)) { dt *= activeAttackMul; } } } catch (Exception ex) { LogError("Exception in Humanoid_UpdateAttack_AttackSpeedDtPatch: " + ex); } } } [<44d44cce-7ad9-4445-90b1-2eb839d16508>NullableContext(0)] [HarmonyPatch(typeof(Humanoid), "CustomFixedUpdate")] public static class Humanoid_CustomFixedUpdate_AttackSpeedPatch { [HarmonyPostfix] [<44d44cce-7ad9-4445-90b1-2eb839d16508>NullableContext(1)] private static void Postfix(Humanoid __instance, float fixedDeltaTime) { EnsureAttackInit(); HumanoidState attackState = GetAttackState(__instance); bool flag = ((Character)__instance).InAttack(); if (flag) { if (attackState.HasDesiredSpeed) { ApplyAnimSpeed(__instance, attackState, attackState.DesiredSpeed); } else { ApplyAnimSpeed(__instance, attackState, 1f); } } else if (attackState.WasInAttack) { ApplyAnimSpeed(__instance, attackState, 1f); attackState.HasDesiredSpeed = false; attackState.DesiredSpeed = 1f; } attackState.WasInAttack = flag; } } [<44d44cce-7ad9-4445-90b1-2eb839d16508>NullableContext(0)] [HarmonyPatch(typeof(Character), "RPC_Stagger")] public static class Character_RPC_Stagger_AttackSpeedResetPatch { [<44d44cce-7ad9-4445-90b1-2eb839d16508>NullableContext(1)] [HarmonyPostfix] private static void Postfix(Character __instance, long sender, Vector3 forceDirection) { try { EnsureAttackInit(); Humanoid val = (Humanoid)(object)((__instance is Humanoid) ? __instance : null); if (!((Object)(object)val == (Object)null)) { ResetForHumanoid(val); } } catch (Exception) { } } } [<44d44cce-7ad9-4445-90b1-2eb839d16508>NullableContext(0)] [HarmonyPatch(typeof(Character), "OnDeath")] public static class Character_OnDeath_AttackSpeedResetPatch { [HarmonyPostfix] [<44d44cce-7ad9-4445-90b1-2eb839d16508>NullableContext(1)] private static void Postfix(Character __instance) { try { EnsureAttackInit(); Humanoid val = (Humanoid)(object)((__instance is Humanoid) ? __instance : null); if (!((Object)(object)val == (Object)null)) { ResetForHumanoid(val); } } catch (Exception) { } } } [HarmonyPatch(typeof(Character), "FreezeFrame")] [<44d44cce-7ad9-4445-90b1-2eb839d16508>NullableContext(0)] public static class Character_FreezeFrame_AttackSpeedScalePatch { [HarmonyPrefix] [<44d44cce-7ad9-4445-90b1-2eb839d16508>NullableContext(1)] private static void Prefix(Character __instance, ref float duration) { try { EnsureAttackInit(); if ((Object)(object)__instance == (Object)null || Mathf.Abs(duration - 0.15f) > 0.01f) { return; } Humanoid val = (Humanoid)(object)((__instance is Humanoid) ? __instance : null); if ((Object)(object)val == (Object)null) { return; } HumanoidState attackState = GetAttackState(val); if (!attackState.HasDesiredSpeed) { return; } float desiredSpeed = attackState.DesiredSpeed; if (!(desiredSpeed <= 1.001f) && !float.IsNaN(desiredSpeed) && !float.IsInfinity(desiredSpeed)) { float num = duration / desiredSpeed; if (num < 0.03f) { num = 0.03f; } DLogAttackSpeed($"FreezeFrame scale: {duration:F3} -> {num:F3} (mul={desiredSpeed:F3})"); duration = num; } } catch (Exception ex) { LogError("Exception in Character_FreezeFrame_AttackSpeedScalePatch: " + ex); } } } [<44d44cce-7ad9-4445-90b1-2eb839d16508>NullableContext(0)] [HarmonyPatch(typeof(CharacterAnimEvent), "UpdateFreezeFrame")] public static class CharacterAnimEvent_UpdateFreezeFrame_ReapplySpeedPatch { [<44d44cce-7ad9-4445-90b1-2eb839d16508>NullableContext(1)] [HarmonyPostfix] private static void Postfix(CharacterAnimEvent __instance, float dt) { try { EnsureAttackInit(); if ((Object)(object)__instance == (Object)null) { return; } Character componentInParent = ((Component)__instance).GetComponentInParent<Character>(); Humanoid val = (Humanoid)(object)((componentInParent is Humanoid) ? componentInParent : null); if (!((Object)(object)val == (Object)null)) { HumanoidState attackState = GetAttackState(val); if (attackState.HasDesiredSpeed && (attackState.ActiveAttackDepth > 0 || ((Character)val).InAttack())) { ApplyAnimSpeed(val, attackState, attackState.DesiredSpeed); } else { ApplyAnimSpeed(val, attackState, 1f); } } } catch (Exception ex) { LogError("Exception in CharacterAnimEvent_UpdateFreezeFrame_ReapplySpeedPatch: " + ex); } } } [HarmonyPatch(typeof(SEMan), "AddStatusEffect", new Type[] { typeof(int), typeof(bool), typeof(int), typeof(float) })] [<44d44cce-7ad9-4445-90b1-2eb839d16508>NullableContext(0)] public static class SEMan_AddStatusEffect_ByHash_WetImmunePatch { [<44d44cce-7ad9-4445-90b1-2eb839d16508>NullableContext(1)] [HarmonyPrefix] private static bool Prefix(SEMan __instance, int nameHash, bool resetTime, int itemLevel, float skillLevel) { try { EnsureWetInit(); if (nameHash != SEMan.s_statusEffectWet) { return true; } Character val = null; try { val = _semanCharacterRef.Invoke(__instance); } catch (Exception) { val = null; } if ((Object)(object)val != (Object)null && HasWetImmune(val)) { DLogWet("Blocked Wet (AddStatusEffect by hash) due to WetImmune"); return false; } } catch (Exception ex2) { LogError("Exception in SEMan_AddStatusEffect_ByHash_WetImmunePatch: " + ex2); } return true; } } [<44d44cce-7ad9-4445-90b1-2eb839d16508>NullableContext(0)] [HarmonyPatch(typeof(SEMan), "AddStatusEffect", new Type[] { typeof(StatusEffect), typeof(bool), typeof(int), typeof(float) })] public static class SEMan_AddStatusEffect_BySE_WetImmunePatch { [<44d44cce-7ad9-4445-90b1-2eb839d16508>NullableContext(1)] [HarmonyPrefix] private static bool Prefix(SEMan __instance, StatusEffect statusEffect, bool resetTime, int itemLevel, float skillLevel, ref StatusEffect __result) { try { if ((Object)(object)statusEffect == (Object)null) { return true; } if (statusEffect.NameHash() != SEMan.s_statusEffectWet) { return true; } Character character = statusEffect.m_character; if ((Object)(object)character != (Object)null && HasWetImmune(character)) { DLogWet("Blocked Wet (AddStatusEffect by SE) due to WetImmune"); __result = null; return false; } } catch (Exception ex) { LogError("Exception in SEMan_AddStatusEffect_BySE_WetImmunePatch: " + ex); } return true; } } public static bool DEBUG = false; public static readonly List<ExtraStatEntry> ExtraStatsConfig = new List<ExtraStatEntry> { new ExtraStatEntry("SE_LightcallerArmor_DO", ExtraStatType.Eitr, 5f, ExtraSourceType.StatusEffect), new ExtraStatEntry("SE_DeathcallerArmor_DO", ExtraStatType.Eitr, 10f, ExtraSourceType.StatusEffect), new ExtraStatEntry("SE_FrostcallerArmor_DO", ExtraStatType.Eitr, 15f, ExtraSourceType.StatusEffect), new ExtraStatEntry("SE_FirecallerArmor_DO", ExtraStatType.Eitr, 20f, ExtraSourceType.StatusEffect), new ExtraStatEntry("SE_StormcallerArmor_DO", ExtraStatType.Eitr, 25f, ExtraSourceType.StatusEffect), new ExtraStatEntry("SE_LightcallerBelt_DO", ExtraStatType.Eitr, 10f, ExtraSourceType.StatusEffect), new ExtraStatEntry("SE_DeathcallerBelt_DO", ExtraStatType.Eitr, 15f, ExtraSourceType.StatusEffect), new ExtraStatEntry("SE_FrostcallerBelt_DO", ExtraStatType.Eitr, 20f, ExtraSourceType.StatusEffect), new ExtraStatEntry("SE_FirecallerBelt_DO", ExtraStatType.Eitr, 20f, ExtraSourceType.StatusEffect), new ExtraStatEntry("SE_StormcallerBelt_DO", ExtraStatType.Eitr, 25f, ExtraSourceType.StatusEffect), new ExtraStatEntry("SE_TotemcallerBelt_DO", ExtraStatType.Health, 10f, ExtraSourceType.StatusEffect), new ExtraStatEntry("SE_WindcallerBelt_DO", ExtraStatType.Stamina, 10f, ExtraSourceType.StatusEffect), new ExtraStatEntry("SE_BloodcallerArmor_DO", ExtraStatType.Health, 50f, ExtraSourceType.StatusEffect), new ExtraStatEntry("ArmorBloodcallerCapeDO", ExtraStatType.Health, 30f, ExtraSourceType.ItemDrop) }; private static readonly ConditionalWeakTable<Humanoid, HumanoidState> _attackState = new ConditionalWeakTable<Humanoid, HumanoidState>(); private static FieldRef<Character, ZSyncAnimation> _zanimRef; private static bool _attackInit; private const float HitFreeze_Default = 0.15f; private const float HitFreeze_Epsilon = 0.01f; private const float HitFreeze_Min = 0.03f; private static FieldRef<SEMan, Character> _semanCharacterRef; private static bool _wetInit; private static void LogInfo(string msg) { } private static void LogError(string msg) { } private static void DLogAttackSpeed(string msg) { } private static void DLogWet(string msg) { } private static void DLogTooltip(string msg) { } private static void DLogFood(string msg) { } private static void GetItemDropBonusesForPrefab(string prefabName, out float extraHp, out float extraStamina, out float extraEitr, out float extraAttackSpeedPercent, out float displayAttackSpeedPercent, out bool wetImmune) { extraHp = 0f; extraStamina = 0f; extraEitr = 0f; extraAttackSpeedPercent = 0f; displayAttackSpeedPercent = 0f; wetImmune = false; if (string.IsNullOrEmpty(prefabName)) { return; } for (int i = 0; i < ExtraStatsConfig.Count; i++) { ExtraStatEntry extraStatEntry = ExtraStatsConfig[i]; if (extraStatEntry.SourceType == ExtraSourceType.ItemDrop && string.Equals(prefabName, extraStatEntry.PrefabName, StringComparison.OrdinalIgnoreCase)) { switch (extraStatEntry.StatType) { case ExtraStatType.Health: extraHp += extraStatEntry.Value; break; case ExtraStatType.Stamina: extraStamina += extraStatEntry.Value; break; case ExtraStatType.Eitr: extraEitr += extraStatEntry.Value; break; case ExtraStatType.AttackSpeed: extraAttackSpeedPercent += extraStatEntry.Value; displayAttackSpeedPercent += (extraStatEntry.DisplayValue.HasValue ? extraStatEntry.DisplayValue.Value : extraStatEntry.Value); break; case ExtraStatType.WetImmune: wetImmune = true; break; } } } } private static void GetItemDropBonusesForPrefab(string prefabName, out float extraHp, out float extraStamina, out float extraEitr, out float extraAttackSpeedPercent, out bool wetImmune) { GetItemDropBonusesForPrefab(prefabName, out extraHp, out extraStamina, out extraEitr, out extraAttackSpeedPercent, out var _, out wetImmune); } private static void GetStatusEffectBonuses(string seRawName, out float extraHp, out float extraStamina, out float extraEitr, out float extraAttackSpeedPercent, out float displayAttackSpeedPercent, out bool wetImmune) { extraHp = 0f; extraStamina = 0f; extraEitr = 0f; extraAttackSpeedPercent = 0f; displayAttackSpeedPercent = 0f; wetImmune = false; if (string.IsNullOrEmpty(seRawName)) { return; } string prefabName = Utils.GetPrefabName(seRawName); for (int i = 0; i < ExtraStatsConfig.Count; i++) { ExtraStatEntry extraStatEntry = ExtraStatsConfig[i]; if (extraStatEntry.SourceType == ExtraSourceType.StatusEffect && string.Equals(prefabName, extraStatEntry.PrefabName, StringComparison.OrdinalIgnoreCase)) { switch (extraStatEntry.StatType) { case ExtraStatType.Health: extraHp += extraStatEntry.Value; break; case ExtraStatType.Stamina: extraStamina += extraStatEntry.Value; break; case ExtraStatType.Eitr: extraEitr += extraStatEntry.Value; break; case ExtraStatType.AttackSpeed: extraAttackSpeedPercent += extraStatEntry.Value; displayAttackSpeedPercent += (extraStatEntry.DisplayValue.HasValue ? extraStatEntry.DisplayValue.Value : extraStatEntry.Value); break; case ExtraStatType.WetImmune: wetImmune = true; break; } } } } private static void GetStatusEffectBonuses(string seRawName, out float extraHp, out float extraStamina, out float extraEitr, out float extraAttackSpeedPercent, out bool wetImmune) { GetStatusEffectBonuses(seRawName, out extraHp, out extraStamina, out extraEitr, out extraAttackSpeedPercent, out var _, out wetImmune); } private static string BuildExtraStatsTooltipBlock(float extraHp, float extraStamina, float extraEitr, float displayAttackSpeedPercent, bool wetImmune) { if (extraHp == 0f && extraStamina == 0f && extraEitr == 0f && displayAttackSpeedPercent == 0f && !wetImmune) { return string.Empty; } StringBuilder stringBuilder = new StringBuilder(); string text = "$extrastats_health_DO"; string text2 = "$extrastats_stamina_DO"; string text3 = "$extrastats_eitr_DO"; string text4 = "$extrastats_attackspeed_DO"; string text5 = "$extrastats_immune_DO"; string text6 = "$extrastats_wet_DO"; if (Localization.instance != null) { text = Localization.instance.Localize(text); text2 = Localization.instance.Localize(text2); text3 = Localization.instance.Localize(text3); text4 = Localization.instance.Localize(text4); text5 = Localization.instance.Localize(text5); text6 = Localization.instance.Localize(text6); } if (extraHp != 0f) { string arg = ((extraHp >= 0f) ? "+" : ""); stringBuilder.Append($"\n{text}: <color=#f27979>{arg}{extraHp:F0}</color>"); } if (extraStamina != 0f) { string arg2 = ((extraStamina >= 0f) ? "+" : ""); stringBuilder.Append($"\n{text2}: <color=#ffff80>{arg2}{extraStamina:F0}</color>"); } if (extraEitr != 0f) { string arg3 = ((extraEitr >= 0f) ? "+" : ""); stringBuilder.Append($"\n{text3}: <color=#8686ee>{arg3}{extraEitr:F0}</color>"); } if (displayAttackSpeedPercent != 0f) { int num = Mathf.RoundToInt(displayAttackSpeedPercent); string arg4 = ((num >= 0) ? "+" : ""); stringBuilder.Append($"\n{text4}: <color=orange>{arg4}{num}%</color>"); } if (wetImmune) { stringBuilder.Append("\n" + text5 + ": <color=orange>" + text6 + "</color>"); } return stringBuilder.ToString(); } private static bool HasWetImmune(Character c) { if ((Object)(object)c == (Object)null) { return false; } try { Player val = (Player)(object)((c is Player) ? c : null); if ((Object)(object)val != (Object)null) { Inventory inventory = ((Humanoid)val).GetInventory(); if (inventory != null) { List<ItemData> equippedItems = inventory.GetEquippedItems(); for (int i = 0; i < equippedItems.Count; i++) { ItemData val2 = equippedItems[i]; if (val2 != null && !((Object)(object)val2.m_dropPrefab == (Object)null)) { string name = ((Object)val2.m_dropPrefab).name; GetItemDropBonusesForPrefab(name, out var _, out var _, out var _, out var _, out var _, out var wetImmune); if (wetImmune) { DLogWet("WetImmune from ItemDrop: " + name); return true; } } } } } if (c.m_seman != null && c.m_seman.m_statusEffects != null) { List<StatusEffect> statusEffects = c.m_seman.m_statusEffects; for (int j = 0; j < statusEffects.Count; j++) { StatusEffect val3 = statusEffects[j]; if (!((Object)(object)val3 == (Object)null)) { string name2 = ((Object)val3).name; GetStatusEffectBonuses(name2, out var _, out var _, out var _, out var _, out var _, out var wetImmune2); if (wetImmune2) { string prefabName = Utils.GetPrefabName(name2); DLogWet("WetImmune from StatusEffect: " + name2 + " (clean=" + prefabName + ")"); return true; } } } } } catch (Exception ex) { LogError("Exception in HasWetImmune: " + ex); } return false; } private static void EnsureAttackInit() { if (!_attackInit) { _attackInit = true; _zanimRef = AccessTools.FieldRefAccess<Character, ZSyncAnimation>("m_zanim"); } } private static HumanoidState GetAttackState(Humanoid h) { return _attackState.GetValue(h, (Humanoid _) => new HumanoidState()); } private static void ApplyAnimSpeed(Humanoid h, HumanoidState state, float speed) { ZSyncAnimation val = null; try { val = _zanimRef.Invoke((Character)(object)h); } catch (Exception) { return; } if (!((Object)(object)val == (Object)null) && !Mathf.Approximately(state.LastAppliedSpeed, speed)) { val.SetSpeed(speed); state.LastAppliedSpeed = speed; } } private static void ResetForHumanoid(Humanoid h) { if (!((Object)(object)h == (Object)null)) { EnsureAttackInit(); HumanoidState attackState = GetAttackState(h); ApplyAnimSpeed(h, attackState, 1f); attackState.HasDesiredSpeed = false; attackState.DesiredSpeed = 1f; attackState.WasInAttack = false; attackState.ActiveAttackDepth = 0; attackState.ActiveAttackMul = 1f; } } private static float ComputeTotalAttackSpeedPercentForHumanoid(Humanoid h) { float num = 0f; if ((Object)(object)h == (Object)null) { return 0f; } try { Player val = (Player)(object)((h is Player) ? h : null); if ((Object)(object)val != (Object)null) { Inventory inventory = ((Humanoid)val).GetInventory(); if (inventory != null) { List<ItemData> equippedItems = inventory.GetEquippedItems(); for (int i = 0; i < equippedItems.Count; i++) { ItemData val2 = equippedItems[i]; if (val2 != null && !((Object)(object)val2.m_dropPrefab == (Object)null)) { string name = ((Object)val2.m_dropPrefab).name; GetItemDropBonusesForPrefab(name, out var _, out var _, out var _, out var extraAttackSpeedPercent, out var _, out var _); if (extraAttackSpeedPercent != 0f) { num += extraAttackSpeedPercent; DLogAttackSpeed($"AttackSpeed from ItemDrop: {name} → {extraAttackSpeedPercent}%"); } } } } } if (((Character)h).m_seman != null && ((Character)h).m_seman.m_statusEffects != null) { List<StatusEffect> statusEffects = ((Character)h).m_seman.m_statusEffects; for (int j = 0; j < statusEffects.Count; j++) { StatusEffect val3 = statusEffects[j]; if (!((Object)(object)val3 == (Object)null)) { string name2 = ((Object)val3).name; GetStatusEffectBonuses(name2, out var _, out var _, out var _, out var extraAttackSpeedPercent2, out var _, out var _); if (extraAttackSpeedPercent2 != 0f) { num += extraAttackSpeedPercent2; string prefabName = Utils.GetPrefabName(name2); DLogAttackSpeed($"AttackSpeed from StatusEffect: {name2} (clean={prefabName}) → {extraAttackSpeedPercent2}%"); } } } } } catch (Exception ex) { LogError("Exception in ComputeTotalAttackSpeedPercentForHumanoid: " + ex); } return num; } private static void EnsureWetInit() { if (!_wetInit) { _wetInit = true; _semanCharacterRef = AccessTools.FieldRefAccess<SEMan, Character>("m_character"); } } } [<44d44cce-7ad9-4445-90b1-2eb839d16508>NullableContext(1)] [<839beae5-12ea-4eaa-8a82-47e46d9c3654>Nullable(0)] [HarmonyPatch] public static class LivingContainerSpawner { [<44d44cce-7ad9-4445-90b1-2eb839d16508>NullableContext(0)] private static class DevLog { public const bool Enabled = false; public const bool SpawnTimers = true; public const bool SpawnAttempts = true; public const bool Dedicated = true; public const bool Lifecycle = true; public const bool Perf = true; public const bool Watcher = true; public const bool WatcherVerbose = false; public const bool StateReset = true; } [<839beae5-12ea-4eaa-8a82-47e46d9c3654>Nullable(0)] private class LivingContainerDef { public string Prefab; public Biome Biomes; public float CheckInterval; public float SpawnChance; public int MaxInWorld; public float MinDistance; public float MaxDistance; public float MinAltitude; public float MaxAltitude; public bool AllowInWater; public int MaxSpawnAttempts; public float DestroyDelay; public string VfxPrefab; public string PinSprite; public string PinText; public bool PinAnimate; public bool PinDoubleSize; } [<44d44cce-7ad9-4445-90b1-2eb839d16508>NullableContext(0)] private struct ItemsCacheEntry { public int ItemsLen; public int QuickHash; public bool IsEmpty; public int DecodedCount; public float LastTouchTime; } [<44d44cce-7ad9-4445-90b1-2eb839d16508>NullableContext(0)] private struct PrefabContainerTuning { public int Width; public int Height; public int LootMin; public int LootMax; public bool Equals(PrefabContainerTuning other) { if (Width == other.Width && Height == other.Height && LootMin == other.LootMin) { return LootMax == other.LootMax; } return false; } } [<839beae5-12ea-4eaa-8a82-47e46d9c3654>Nullable(0)] private class LivingContainerRegistryComponent : MonoBehaviour { private ZNetView _nview; private ZDOID _uid; private string _prefab; private void Awake() { //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_007d: Unknown result type (might be due to invalid IL or missing references) try { _nview = ((Component)this).GetComponent<ZNetView>(); if ((Object)(object)_nview == (Object)null || !_nview.IsValid()) { return; } _prefab = Utils.GetPrefabName(((Object)((Component)this).gameObject).name); BuildDefCache(); if (DefByPrefab.ContainsKey(_prefab)) { ZDO val = null; try { val = _nview.GetZDO(); } catch { } if (val != null) { _uid = val.m_uid; RegisterLoadedRiko(_uid, _nview, _prefab); } } } catch { } } private void OnDestroy() { //IL_0001: 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_000e: 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) try { if (_uid != default(ZDOID)) { UnregisterLoadedRiko(_uid); } } catch { } } } [<44d44cce-7ad9-4445-90b1-2eb839d16508>NullableContext(0)] private enum GroundFail { None, WorldGenNoHeight, RaycastNoHit, WrongBiome, InWater, WaterTooDeep, OceanDepth, Lava, Altitude, Overlap, MistlandsBlocked } [<839beae5-12ea-4eaa-8a82-47e46d9c3654>Nullable(0)] [HarmonyPatch(typeof(InventoryGui), "Hide")] private static class InventoryGui_Hide_Patch { private static void Prefix(InventoryGui __instance, out Container __state) { __state = (((Object)(object)__instance != (Object)null) ? __instance.m_currentContainer : null); } private static void Postfix(Container __state) { if ((Object)(object)__state != (Object)null) { HandleContainerClosed(__state); } } } [<839beae5-12ea-4eaa-8a82-47e46d9c3654>Nullable(0)] private class LivingContainerPinComponent : MonoBehaviour { public string PinSprite; public string PinText; public bool PinAnimate; public bool PinDoubleSize; private PinData _pin; private const float PinUpdateInterval_Seconds = 5f; private float _nextPinUpdateTime; private void Update() { //IL_006b: 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) if (!LivingContainerConfig.IsRikoEnabled()) { if (_pin != null && (Object)(object)Minimap.instance != (Object)null) { Minimap.instance.RemovePin(_pin); _pin = null; } Object.Destroy((Object)(object)this); return; } float time = Time.time; if (_pin != null) { if (!(time < _nextPinUpdateTime)) { _nextPinUpdateTime = time + 5f; _pin.m_pos = ((Component)this).transform.position; } } else { TryCreatePin(); } } private void TryCreatePin() { //IL_004d: 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_006e: Unknown result type (might be due to invalid IL or missing references) if (!string.IsNullOrEmpty(PinSprite) && !((Object)(object)Minimap.instance == (Object)null) && Magic_SupremacyPlugin.PinSprites != null && Magic_SupremacyPlugin.PinSprites.TryGetValue(PinSprite, out var value) && !((Object)(object)value == (Object)null)) { PinData val = Minimap.instance.AddPin(((Component)this).transform.position, (PinType)8, PinText ?? "", false, false, 0L, default(PlatformUserID)); val.m_icon = value; val.m_animate = PinAnimate; val.m_doubleSize = PinDoubleSize; val.m_save = false; _pin = val; _nextPinUpdateTime = Time.time + 5f; } } private void OnDestroy() { if (_pin != null && (Object)(object)Minimap.instance != (Object)null) { Minimap.instance.RemovePin(_pin); } } } [<44d44cce-7ad9-4445-90b1-2eb839d16508>NullableContext(0)] private class RikoSpawnStabilizer : MonoBehaviour { private bool _started; public void Init() { if (!_started) { _started = true; ((MonoBehaviour)this).StartCoroutine(StabilizeRoutine()); } } [<44d44cce-7ad9-4445-90b1-2eb839d16508>NullableContext(1)] private IEnumerator StabilizeRoutine() { StabilizeOnce(((Component)this).gameObject); yield return null; StabilizeOnce(((Component)this).gameObject); yield return (object)new WaitForSeconds(0.35f); StabilizeOnce(((Component)this).gameObject); } } private static readonly LivingContainerDef[] Defs = new LivingContainerDef[6] { new LivingContainerDef { Prefab = "EncounterCreatureRikoBlackforestDO", Biomes = (Biome)8, CheckInterval = 360f, SpawnChance = 0.3f, MaxInWorld = 3, MinDistance = 18f, MaxDistance = 36f, MinAltitude = 0f, MaxAltitude = 2000f, AllowInWater = false, MaxSpawnAttempts = 15, DestroyDelay = 1f, VfxPrefab = "fx_riko_disappear_DO", PinSprite = "PinRikoDO", PinText = "", PinAnimate = false, PinDoubleSize = true }, new LivingContainerDef { Prefab = "EncounterCreatureRikoSwampDO", Biomes = (Biome)2, CheckInterval = 360f, SpawnChance = 0.3f, MaxInWorld = 3, MinDistance = 18f, MaxDistance = 36f, MinAltitude = -1f, MaxAltitude = 2000f, AllowInWater = false, MaxSpawnAttempts = 18, DestroyDelay = 1f, VfxPrefab = "fx_riko_disappear_DO", PinSprite = "PinRikoDO", PinText = "", PinAnimate = false, PinDoubleSize = true }, new LivingContainerDef { Prefab = "EncounterCreatureRikoMountainDO", Biomes = (Biome)4, CheckInterval = 360f, SpawnChance = 0.3f, MaxInWorld = 3, MinDistance = 18f, MaxDistance = 36f, MinAltitude = 10f, MaxAltitude = 2000f, AllowInWater = false, MaxSpawnAttempts = 15, DestroyDelay = 1f, VfxPrefab = "fx_riko_disappear_DO", PinSprite = "PinRikoDO", PinText = "", PinAnimate = false, PinDoubleSize = true }, new LivingContainerDef { Prefab = "EncounterCreatureRikoPlainsDO", Biomes = (Biome)16, CheckInterval = 360f, SpawnChance = 0.3f, MaxInWorld = 3, MinDistance = 18f, MaxDistance = 36f, MinAltitude = 0f, MaxAltitude = 2000f, AllowInWater = false, MaxSpawnAttempts = 15, DestroyDelay = 1f, VfxPrefab = "fx_riko_disappear_DO", PinSprite = "PinRikoDO", PinText = "", PinAnimate = false, PinDoubleSize = true }, new LivingContainerDef { Prefab = "EncounterCreatureRikoMistlandsDO", Biomes = (Biome)512, CheckInterval = 360f, SpawnChance = 0.3f, MaxInWorld = 3, MinDistance = 15f, MaxDistance = 40f, MinAltitude = 12f, MaxAltitude = 2000f, AllowInWater = false, MaxSpawnAttempts = 18, DestroyDelay = 1f, VfxPrefab = "fx_riko_disappear_DO", PinSprite = "PinRikoDO", PinText = "", PinAnimate = false, PinDoubleSize = true }, new LivingContainerDef { Prefab = "EncounterCreatureRikoAshlandsDO", Biomes = (Biome)32, CheckInterval = 360f, SpawnChance = 0.3f, MaxInWorld = 3, MinDistance = 18f, MaxDistance = 36f, MinAltitude = 0f, MaxAltitude = 2000f, AllowInWater = false, MaxSpawnAttempts = 15, DestroyDelay = 1f, VfxPrefab = "fx_riko_disappear_DO", PinSprite = "PinRikoDO", PinText = "", PinAnimate = false, PinDoubleSize = true } }; private const float Riko_SeenRadius_Meters = 120f; private const float Riko_SeenUpdateInterval_Seconds = 12f; private const float Riko_TTL_Minutes = 20f; private const float Riko_Grace_Minutes = 2f; private const float Riko_TtlScanInterval_Seconds = 45f; private const float Riko_DestroyScanInterval_Seconds = 20f; private const float Riko_LoadedDestroyCheckInterval_Seconds = 0.2f; private const float Riko_EmptyWatcherInterval_Seconds = 30f; private const float ConfigRefreshInterval_Seconds = 5f; private const int OriginMaxAttempts = 3; private const int OriginPickGuard = 16; private const int MaxCatchupChecksPerTick_PerDef = 2; private const float WorldCountRescanInterval_Seconds = 90f; private const float ServerStartupGrace_Seconds = 10f; private const float MaxAllowedWaterDepth_Center = 0.08f; private const float MaxAllowedWaterDepth_Side = 0.12f; private const float DryAreaProbeRadius = 0.9f; private const int DryAreaAllowedWetSideSamples = 1; private const float MistlandsHeadroomHeight = 2.2f; private const float MistlandsHeadroomRadius = 0.45f; private const float MistlandsCeilingCheckStart = 0.15f; private const float DedNoGroundLogInterval_Seconds = 15f; private const string ZdoKey_Killed = "MS_Riko_Killed"; private const string ZdoKey_SpawnTime = "MS_Riko_SpawnTime"; private const string ZdoKey_LastSeenTime = "MS_Riko_LastSeenTime"; private const string ZdoKey_DestroyAt = "MS_Riko_DestroyAt"; private const string ZdoKey_VfxPlayed = "MS_Riko_VfxPlayed"; private const string ZdoKey_FinalDestroyCounted = "MS_Riko_FinalDestroyCounted"; private static readonly Dictionary<string, LivingContainerDef> DefByPrefab = new Dictionary<string, LivingContainerDef>(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary<string, int> WorldCounts = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase); private static float[] WorldChecks; private static float LastWorldUpdate; private static float NextSeenUpdateTime; private static float NextDestroyScanTime; private static float NextLoadedDestroyCheckTime; private static float NextTtlScanTime; private static float NextConfigRefreshTime; private static float NextWorldCountRescanTime; private static readonly Dictionary<string, float> NextAuthoritativeCountCheckTime = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase); private const float AuthoritativeCountRefreshInterval_Seconds = 20f; private static bool WorldCountCacheInitialized; private static readonly List<Vector3> OriginPositions = new List<Vector3>(32); private static readonly FieldInfo ZNetPeer_m_refPos_Field = AccessTools.Field(typeof(ZNetPeer), "m_refPos"); private static readonly Dictionary<ZDOID, ZNetView> LoadedRikos = new Dictionary<ZDOID, ZNetView>(256); private static int LoadedRegistryInvalidSweeps; private static List<ZDOID> _registrySweepKeys; private static bool PurgeInProgress; private static int PurgePrefabIndex; private static int PurgeSectorIndex; private static readonly List<ZDO> PurgeZdos = new List<ZDO>(256); private static float ServerWorldEnterTime = -1f; private static bool ServerGraceLogged; private static float _dedNextNoGroundLogTime; private static int _dedLastPlayers = -999; private static int _dedLastPeers = -999; private static int _dedLastOriginPos = -999; private static float _dedNextHeartbeatTime; private static bool _emptyWatcherInProgress; private static int _emptyWatcherPrefabIndex; private static int _emptyWatcherSectorIndex; private static readonly List<ZDO> _emptyWatcherZdos = new List<ZDO>(256); private static float _emptyWatcherNextRunTime; private static int _hashInUse; private static int _hashItems; private static readonly Dictionary<ZDOID, ItemsCacheEntry> _itemsCache = new Dictionary<ZDOID, ItemsCacheEntry>(512); private static float _itemsCacheNextCleanupTime; private const float ItemsCacheCleanupInterval_Seconds = 60f; private const float ItemsCacheKeepSeconds = 600f; private const int ItemsCacheMaxSize = 4096; private static List<ZDOID> _itemsCacheKeysTmp; private static readonly Dictionary<string, PrefabContainerTuning> AppliedPrefabTuning = new Dictionary<string, PrefabContainerTuning>(StringComparer.OrdinalIgnoreCase); private static readonly int SolidMask = LayerMask.GetMask(new string[5] { "terrain", "static_solid", "Default", "piece", "vehicle" }); private static readonly Vector2[] DryAreaProbeOffsets = (Vector2[])(object)new Vector2[5] { new Vector2(0f, 0f), new Vector2(1f, 0f), new Vector2(-1f, 0f), new Vector2(0f, 1f), new Vector2(0f, -1f) }; private static void Log(string msg) { } private static void LogTimers(string msg) { } private static void LogSpawn(string msg) { } private static void LogDed(string msg) { } private static void LogLife(string msg) { } private static void LogPerf(string msg) { } private static void LogWatcher(string msg) { } private static void LogWatcherVerbose(string msg) { } private static void LogReset(string msg) { } private static void RegisterLoadedRiko(ZDOID uid, ZNetView nv, string prefab) { //IL_000f: 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) if (!((Object)(object)nv == (Object)null)) { LoadedRikos[uid] = nv; LogPerf($"registry ADD prefab={prefab} uid={uid} loaded={LoadedRikos.Count}"); } } private static void UnregisterLoadedRiko(ZDOID uid) { //IL_0005: 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) if (LoadedRikos.Remove(uid)) { LogPerf($"registry REMOVE uid={uid} loaded={LoadedRikos.Count}"); } } private static void EnsureRegistryComponent(GameObject go) { if (!((Object)(object)go == (Object)null) && !((Object)(object)go.GetComponent<LivingContainerRegistryComponent>() != (Object)null)) { go.AddComponent<LivingContainerRegistryComponent>(); } } [HarmonyPatch(typeof(ZNet), "Awake")] [HarmonyPostfix] private static void ZNet_Awake_Postfix() { try { if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer()) { ResetRuntimeState_Server("ZNet.Awake"); } } catch { } } private static void ResetRuntimeState_Server(string reason) { WorldChecks = null; LastWorldUpdate = 0f; WorldCounts.Clear(); WorldCountCacheInitialized = false; NextWorldCountRescanTime = 0f; NextAuthoritativeCountCheckTime.Clear(); LoadedRikos.Clear(); LoadedRegistryInvalidSweeps = 0; NextSeenUpdateTime = 0f; NextDestroyScanTime = 0f; NextLoadedDestroyCheckTime = 0f; NextTtlScanTime = 0f; NextConfigRefreshTime = 0f; PurgeInProgress = false; PurgePrefabIndex = 0; PurgeSectorIndex = 0; PurgeZdos.Clear(); _emptyWatcherInProgress = false; _emptyWatcherPrefabIndex = 0; _emptyWatcherSectorIndex = 0; _emptyWatcherZdos.Clear(); _emptyWatcherNextRunTime = 0f; _itemsCache.Clear(); _itemsCacheNextCleanupTime = 0f; ServerWorldEnterTime = Time.time; ServerGraceLogged = false; OriginPositions.Clear(); _dedNextNoGroundLogTime = 0f; _dedLastPlayers = -999; _dedLastPeers = -999; _dedLastOriginPos = -999; _dedNextHeartbeatTime = 0f; LogReset($"server RuntimeState RESET reason={reason} time={ServerWorldEnterTime:0.00} session={ZDOMan.GetSessionID()}"); } [HarmonyPostfix] [HarmonyPatch(typeof(ZoneSystem), "Update")] private static void ZoneSystem_Update_Postfix() { if (!LivingContainerConfig.IsRikoEnabled() || (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || (Object)(object)ZNetScene.instance == (Object)null || ZDOMan.instance == null || (Object)(object)ObjectDB.instance == (Object)null) { return; } if (ServerWorldEnterTime < 0f) { ServerWorldEnterTime = Time.time; } float num = Time.time - ServerWorldEnterTime; bool flag = num < 10f; if (flag && !ServerGraceLogged) { ServerGraceLogged = true; LogTimers($"server StartupGrace ACTIVE seconds={10f:0.0} sinceEnter={num:0.00}"); } BuildDefCache(); if (Time.time >= NextConfigRefreshTime) { RefreshDefsFromConfig(); NextConfigRefreshTime = Time.time + 5f; } List<Player> allPlayers = Player.GetAllPlayers(); BuildOriginPositions(allPlayers); LogDedicatedStateIfNeeded(allPlayers); UpdateLastSeenForLoadedRikos(); ProcessLoadedDestroyDueFast(); ProcessScheduledDestroyForLoadedRikos(); TryRunEmptyWatcher_Server(); TryPurgeExpiredOrKilledRikoZDOs(); if (OriginPositions.Count == 0) { return; } float time = Time.time; if (LastWorldUpdate <= 0f) { LastWorldUpdate = time; EnsureWorldChecksInitialized(); EnsureWorldCounts_Cached(initial: true); LogTimers($"server WorldTimers INIT sinceEnter={num:0.00} note=FirstWorldTick"); return; } float num2 = time - LastWorldUpdate; if (num2 < 5f) { return; } LastWorldUpdate = time; EnsureWorldChecksInitialized(); EnsureWorldCounts_Cached(initial: false); LogTimers($"server WorldTick sinceEnter={num:0.00} delta={num2:0.00} origins={OriginPositions.Count}"); for (int i = 0; i < Defs.Length; i++) { LivingContainerDef livingContainerDef = Defs[i]; if (livingContainerDef == null) { continue; } float num3 = WorldChecks[i]; WorldChecks[i] -= num2; float num4 = WorldChecks[i]; if (num3 > 0f && (num3 < 5f || num4 <= 0f)) { LogTimers($"server WorldTimer prefab={livingContainerDef.Prefab} before={num3:0.00} after={num4:0.00} delta={num2:0.00} interval={livingContainerDef.CheckInterval:0.0} grace={flag}"); } if (WorldChecks[i] > 0f) { continue; } if (flag) { WorldChecks[i] = Mathf.Max(1f, livingContainerDef.CheckInterval); LogTimers($"server WorldTimer BLOCKED_BY_GRACE prefab={livingContainerDef.Prefab} setNext={WorldChecks[i]:0.00}"); continue; } int num5 = 0; float num6 = Mathf.Max(1f, livingContainerDef.CheckInterval); while (WorldChecks[i] <= 0f && num5 < 2) { TrySpawnWithFallbackOrigins(OriginPositions, livingContainerDef, num, num5); WorldChecks[i] += num6; num5++; } if (WorldChecks[i] <= 0f) { WorldChecks[i] = Mathf.Min(1f, num6); LogTimers($"server WorldTimer STILL_OVERDUE prefab={livingContainerDef.Prefab} cappedNext={WorldChecks[i]:0.00}"); } else { LogTimers($"server WorldTimer ADVANCED prefab={livingContainerDef.Prefab} nextIn={WorldChecks[i]:0.00} catchupUsed={num5}"); } } } private static void EnsureWorldChecksInitialized() { if (WorldChecks == null || WorldChecks.Length != Defs.Length) { WorldChecks = new float[Defs.Length]; for (int i = 0; i < WorldChecks.Length; i++) { LivingContainerDef livingContainerDef = Defs[i]; float num = ((livingContainerDef != null) ? Mathf.Max(1f, livingContainerDef.CheckInterval) : 60f); float num2 = Mathf.Min(30f, num * 0.1f); WorldChecks[i] = num + Random.Range(0f, num2); } LogTimers($"server WorldChecks CREATED count={WorldChecks.Length}"); } } private static void BuildOriginPositions(List<Player> players) { //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00da: 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_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_008c: 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_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) OriginPositions.Clear(); if (players != null && players.Count > 0) { for (int i = 0; i < players.Count; i++) { Player val = players[i]; if (!((Object)(object)val == (Object)null)) { AddOriginPosition(((Component)val).transform.position); } } } else { if ((Object)(object)ZNet.instance == (Object)null) { return; } List<ZNetPeer> list = null; try { list = ZNet.instance.GetPeers(); } catch { } if (list == null || list.Count == 0) { return; } for (int j = 0; j < list.Count; j++) { ZNetPeer val2 = list[j]; if (val2 == null) { continue; } Vector3 val3 = Vector3.zero; try { if (ZNetPeer_m_refPos_Field != null) { object value = ZNetPeer_m_refPos_Field.GetValue(val2); if (value is Vector3) { Vector3 val4 = (Vector3)value; val3 = val4; } } } catch { } if (!(val3 == Vector3.zero)) { AddOriginPosition(val3); AddOriginPosition(val3 + new Vector3(24f, 0f, 0f)); AddOriginPosition(val3 + new Vector3(-24f, 0f, 0f)); AddOriginPosition(val3 + new Vector3(0f, 0f, 24f)); AddOriginPosition(val3 + new Vector3(0f, 0f, -24f)); } } } } private static void AddOriginPosition(Vector3 pos) { //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_0018: 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_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: 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 (pos == Vector3.zero) { return; } for (int i = 0; i < OriginPositions.Count; i++) { Vector3 val = OriginPositions[i] - pos; if (((Vector3)(ref val)).sqrMagnitude < 1f) { return; } } OriginPositions.Add(pos); } private static void LogDedicatedStateIfNeeded(List<Player> players) { } private static bool SafeIsDedicated() { try { return (Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsDedicated(); } catch { return false; } } private static bool TrySpawnWithFallbackOrigins(List<Vector3> origins, LivingContainerDef def, float sinceEnter, int catchup) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: 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_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: 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_018d: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0103: 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_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0099: 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_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: 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) if (origins == null || origins.Count == 0 || def == null) { return false; } int num = 0; int num2 = -1; int num3 = -1; int num4 = -1; for (int i = 0; i < 3; i++) { int num5 = -1; Vector3 val = Vector3.zero; int num6 = 0; while (num5 < 0 && num6 < 16) { num6++; int num7 = Random.Range(0, origins.Count); if (num7 != num2 && num7 != num3 && num7 != num4) { Vector3 val2 = origins[num7]; if (!(val2 == Vector3.zero)) { num5 = num7; val = val2; } } } if (num5 < 0) { for (int j = 0; j < origins.Count; j++) { if (j != num2 && j != num3 && j != num4) { Vector3 val3 = origins[j]; if (!(val3 == Vector3.zero)) { num5 = j; val = val3; break; } } } } if (num5 < 0) { return false; } switch (num) { case 0: num2 = num5; break; case 1: num3 = num5; break; case 2: num4 = num5; break; } num++; Biome biomeSafe = GetBiomeSafe(val); if ((int)biomeSafe != 0 && (biomeSafe & def.Biomes) == 0) { LogSpawn("server TrySpawn SKIP originBiomeMismatch " + $"originPos=({val.x:0.0},{val.y:0.0},{val.z:0.0}) " + $"originBiome={biomeSafe} needed={def.Biomes} prefab={def.Prefab} " + $"originAttempt={i + 1}/{3}"); continue; } LogSpawn($"server TrySpawn CALL originPos=({val.x:0.0},{val.y:0.0},{val.z:0.0}) prefab={def.Prefab} sinceEnter={sinceEnter:0.00} catchup={catchup} originAttempt={i + 1}/{3}"); if (TrySpawnAtPosition(val, def)) { return true; } } return false; } private static bool TrySpawnAtPosition(Vector3 origin, LivingContainerDef def) { //IL_037d: Unknown result type (might be due to invalid IL or missing references) //IL_038c: Unknown result type (might be due to invalid IL or missing references) //IL_039b: 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_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) if (def == null) { return false; } float value = Random.value; if (value > def.SpawnChance) { LogSpawn($"server TrySpawn FAIL chance prefab={def.Prefab} rnd={value:0.000} chance={def.SpawnChance:0.000}"); return false; } int authoritativeAliveCountForPrefab = GetAuthoritativeAliveCountForPrefab(def.Prefab); if (authoritativeAliveCountForPrefab >= def.MaxInWorld) { LogSpawn($"server TrySpawn FAIL maxInWorld prefab={def.Prefab} count={authoritativeAliveCountForPrefab} max={def.MaxInWorld}"); return false; } GameObject prefab = ZNetScene.instance.GetPrefab(def.Prefab); if ((Object)(object)prefab == (Object)null) { LogSpawn("server TrySpawn FAIL missingPrefab prefab=" + def.Prefab); return false; } ApplyContainerConfigToPrefab(def, prefab); int num = Mathf.Max(1, def.MaxSpawnAttempts); int num2 = 0; int num3 = 0; int num4 = 0; int num5 = 0; int num6 = 0; int num7 = 0; int num8 = 0; int num9 = 0; int num10 = 0; int num11 = 0; for (int i = 0; i < num; i++) { Vector3 val = PickPoint(origin, def.MinDistance, def.MaxDistance); if (!TryGetRikoSpawnPoint(val, def, out var spawnPos, out var fail)) { switch (fail) { case GroundFail.WorldGenNoHeight: case GroundFail.RaycastNoHit: num2++; break; case GroundFail.WrongBiome: num3++; break; case GroundFail.InWater: num4++; break; case GroundFail.WaterTooDeep: num5++; break; case GroundFail.OceanDepth: num6++; break; case GroundFail.Lava: num7++; break; case GroundFail.Altitude: num8++; break; case GroundFail.Overlap: num9++; break; case GroundFail.MistlandsBlocked: num10++; break; } LogSpawn($"server TrySpawn attempt={i + 1} FAIL prefab={def.Prefab} fail={fail} candidate=({val.x:0.0},{val.y:0.0},{val.z:0.0})"); continue; } Quaternion val2 = Quaternion.Euler(0f, Random.Range(0f, 360f), 0f); GameObject val3 = Object.Instantiate<GameObject>(prefab, spawnPos, val2); if ((Object)(object)val3 == (Object)null) { num11++; LogSpawn($"server TrySpawn attempt={i + 1} FAIL instantiateNull prefab={def.Prefab}"); continue; } EnsureRegistryComponent(val3); AttachPinComponent(val3, def); Container component = val3.GetComponent<Container>(); if ((Object)(object)component != (Object)null) { component.m_autoDestroyEmpty = false; } FixSpawnInsideGeometry(val3); ZNetView val4 = null; ZDO val5 = null; try { val4 = val3.GetComponent<ZNetView>(); if ((Object)(object)val4 != (Object)null && val4.IsValid()) { val5 = val4.GetZDO(); } } catch { } if (val5 != null) { try { EnsureServerOwnership(val4, val5, "SpawnInitZdo"); long nowSeconds = GetNowSeconds(); val5.Set("MS_Riko_SpawnTime", nowSeconds); val5.Set("MS_Riko_LastSeenTime", nowSeconds); val5.Set("MS_Riko_Killed", 0); val5.Set("MS_Riko_DestroyAt", 0L); val5.Set("MS_Riko_VfxPlayed", 0); val5.Set("MS_Riko_FinalDestroyCounted", 0); } catch { } } WorldCounts[def.Prefab] = ((!WorldCounts.TryGetValue(def.Prefab, out var value2)) ? 1 : (value2 + 1)); string text = ((val5 != null) ? ((object)(ZDOID)(ref val5.m_uid)).ToString() : "null"); LogSpawn($"server TrySpawn SUCCESS prefab={def.Prefab} uid={text} pos=({spawnPos.x:0.0},{spawnPos.y:0.0},{spawnPos.z:0.0}) attempt={i + 1} worldCount={WorldCounts[def.Prefab]}"); LogSpawn($"server TrySpawn SUMMARY prefab={def.Prefab} attempts={num} " + $"groundFail={num2} biomeFail={num3} waterFail={num4} deepWaterFail={num5} oceanFail={num6} lavaFail={num7} altitudeFail={num8} overlapFail={num9} mistBlockedFail={num10} instFail={num11}"); return true; } LogSpawn($"server TrySpawn SUMMARY prefab={def.Prefab} attempts={num} " + $"groundFail={num2} biomeFail={num3} waterFail={num4} deepWaterFail={num5} oceanFail={num6} lavaFail={num7} altitudeFail={num8} overlapFail={num9} mistBlockedFail={num10} instFail={num11}"); return false; } private static bool TryGetRikoSpawnPoint(Vector3 candidate, LivingContainerDef def, out Vector3 spawnPos, out GroundFail fail) { //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_000a: 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_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: 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_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_0031: 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: Invalid comparison between Unknown and I4 //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_005f: 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_004c: 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_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: 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_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0158: 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_011a: Unknown result type (might be due to invalid IL or missing references) spawnPos = candidate; fail = GroundFail.None; if (!TryGetGroundPoint(candidate, out var groundPoint, out var fail2)) { fail = fail2; return false; } Biome biomeSafe = GetBiomeSafe(groundPoint); if ((biomeSafe & def.Biomes) == 0) { fail = GroundFail.WrongBiome; return false; } bool flag = (biomeSafe & 2) > 0; Heightmap val = Heightmap.FindHeightmap(groundPoint); if ((Object)(object)val != (Object)null && val.GetOceanDepth(groundPoint) > 0.5f) { fail = GroundFail.OceanDepth; return false; } if ((def.Biomes & 0x20) != 0) { bool flag2 = IsAshlandsLavaByWorldGen(groundPoint); if (!flag2 && (Object)(object)val != (Object)null) { flag2 = val.IsLava(groundPoint, 0.4f); } if (flag2) { fail = GroundFail.Lava; return false; } } if (!def.AllowInWater && !flag && IsAreaTooWetForRiko(groundPoint, out var _, out var _)) { fail = GroundFail.WaterTooDeep; return false; } if (groundPoint.y < def.MinAltitude || groundPoint.y > def.MaxAltitude) { fail = GroundFail.Altitude; return false; } Vector3 ground = groundPoint; if (SafeIsDedicated()) { TryFindSolidBelow(groundPoint + Vector3.up * 1f, 8f, out ground); } if ((def.Biomes & 0x200) != 0 && (SafeIsDedicated() ? IsMistlandsSpawnSpaceBlocked(ground) : IsMistlandsSpawnSpaceBlocked_Local(ground))) { fail = GroundFail.MistlandsBlocked; return false; } if (IsBodyOverlapping(ground)) { fail = GroundFail.Overlap; return false; } spawnPos = ground + Vector3.up * 0.03f; return true; } private static bool TryGetGroundPoint(Vector3 candidate, out Vector3 groundPoint, out GroundFail fail) { //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_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: 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) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0103: 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_0089: 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_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0037: 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_0041: 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_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_00be: 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_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) groundPoint = candidate; fail = GroundFail.None; if (SafeIsDedicated()) { if (TryGetWorldGeneratorHeight(candidate.x, candidate.z, out var y)) { groundPoint = new Vector3(candidate.x, y, candidate.z); RaycastHit val = default(RaycastHit); if (Physics.Raycast(candidate + Vector3.up * 200f, Vector3.down, ref val, 500f, SolidMask, (QueryTriggerInteraction)1)) { groundPoint = ((RaycastHit)(ref val)).point; } return true; } RaycastHit val2 = default(RaycastHit); if (Physics.Raycast(candidate + Vector3.up * 200f, Vector3.down, ref val2, 500f, SolidMask, (QueryTriggerInteraction)1)) { groundPoint = ((RaycastHit)(ref val2)).point; return true; } fail = GroundFail.WorldGenNoHeight; ThrottledNoGroundLog(candidate, fail); return false; } RaycastHit val3 = default(RaycastHit); if (!Physics.Raycast(candidate + Vector3.up * 200f, Vector3.down, ref val3, 500f, SolidMask, (QueryTriggerInteraction)1)) { fail = GroundFail.RaycastNoHit; return false; } groundPoint = ((RaycastHit)(ref val3)).point; return true; } private static bool TryGetWorldGeneratorHeight(float x, float z, out float y) { y = 0f; try { if (WorldGenerator.instance == null) { return false; } Color val = default(Color); float height = WorldGenerator.instance.GetHeight(x, z, ref val); if (float.IsNaN(height) || float.IsInfinity(height)) { return false; } y = height; return true; } catch { return false; } } private static Biome GetBiomeSafe(Vector3 pos) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000d: 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_0029: 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_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) try { if (WorldGenerator.instance != null) { return WorldGenerator.instance.GetBiome(pos); } } catch { } try { return Heightmap.FindBiome(pos); } catch { } return (Biome)0; } private static bool IsAshlandsLavaByWorldGen(Vector3 point, float lavaValue = 0.4f) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Invalid comparison between Unknown and I4 //IL_0025: 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_003a: Unknown result type (might be due to invalid IL or missing references) try { if (WorldGenerator.instance == null) { return false; } if ((int)WorldGenerator.instance.GetBiome(point) != 32) { return false; } Color val = default(Color); WorldGenerator.instance.GetBiomeHeight((Biome)32, point.x, point.z, ref val, false); return val.a > lavaValue; } catch { return false; } } private static void ThrottledNoGroundLog(Vector3 candidate, GroundFail fail) { } private static bool IsAreaTooWetForRiko(Vector3 centerGround, out float centerDepth, out int wetSideSamples) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: 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_002d: 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_003b: 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) centerDepth = 0f; wetSideSamples = 0; for (int i = 0; i < DryAreaProbeOffsets.Length; i++) { Vector2 val = DryAreaProbeOffsets[i] * 0.9f; float num = centerGround.x + val.x; float num2 = centerGround.z + val.y; if (!TryGetWorldGeneratorHeight(num, num2, out var y)) { if (i == 0) { centerDepth = 999f; } return true; } if (!TryGetWaterSurfaceY(new Vector3(num, y, num2), out var waterY)) { continue; } float num3 = waterY - y; if (i == 0) { centerDepth = num3; if (num3 > 0.08f) { return true; } } else if (num3 > 0.12f) { wetSideSamples++; } } return wetSideSamples > 1; } private static bool TryGetWaterSurfaceY(Vector3 point, out float waterY) { //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_005d: 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_009b: Unknown result type (might be due to invalid IL or missing references) waterY = 0f; List<WaterVolume> instances = WaterVolume.Instances; if (instances == null || instances.Count == 0) { return false; } WaterVolume val = null; float num = float.MaxValue; for (int i = 0; i < instances.Count; i++) { WaterVolume val2 = instances[i]; if ((Object)(object)val2 == (Object)null) { continue; } Collider val3 = null; try { val3 = ((Component)val2).GetComponent<Collider>(); } catch { } if ((Object)(object)val3 == (Object)null) { continue; } Vector3 val4 = val3.ClosestPoint(point) - point; float sqrMagnitude = ((Vector3)(ref val4)).sqrMagnitude; if (sqrMagnitude < num) { num = sqrMagnitude; val = val2; if (num <= 1E-06f) { break; } } } if ((Object)(object)val == (Object)null) { return false; } try { waterY = val.GetWaterSurface(point, 1f); return true; } catch { return false; } } private static bool IsMistlandsSpawnSpaceBlocked(Vector3 groundPoint) { //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_000b: 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_0015: 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_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: 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_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_004a: 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_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: 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_0085: 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_00a0: 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) //IL_00bb: 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_00cc: 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_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00da: 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_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) Vector3 val = groundPoint + Vector3.up * 0.15f; Vector3 val2 = val + Vector3.up * 2.2f; if (!Physics.CheckCapsule(val, val2, 0.45f, SolidMask, (QueryTriggerInteraction)1)) { return false; } Vector3[] array = (Vector3[])(object)new Vector3[5] { Vector3.zero, new Vector3(0.45f, 0f, 0f), new Vector3(-0.45f, 0f, 0f), new Vector3(0f, 0f, 0.45f), new Vector3(0f, 0f, -0.45f) }; int num = 0; for (int i = 0; i < array.Length; i++) { Vector3 val3 = val + array[i]; Vector3 val4 = val2 + array[i]; if (Physics.CheckCapsule(val3, val4, 0.45f, SolidMask, (QueryTriggerInteraction)1)) { num++; } } return num >= 3; } private static bool IsMistlandsSpawnSpaceBlocked_Local(Vector3 groundPoint) { //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_000b: 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_0015: 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_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: 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_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_004a: 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_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: 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_0085: 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_00a0: 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) //IL_00bb: 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_00cc: 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_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00da: 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_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) Vector3 val = groundPoint + Vector3.up * 0.2f; Vector3 val2 = val + Vector3.up * 1.85f; if (!Physics.CheckCapsule(val, val2, 0.3f, SolidMask, (QueryTriggerInteraction)1)) { return false; } Vector3[] array = (Vector3[])(object)new Vector3[5] { Vector3.zero, new Vector3(0.3f, 0f, 0f), new Vector3(-0.3f, 0f, 0f), new Vector3(0f, 0f, 0.3f), new Vector3(0f, 0f, -0.3f) }; int num = 0; for (int i = 0; i < array.Length; i++) { Vector3 val3 = val + array[i]; Vector3 val4 = val2 + array[i]; if (Physics.CheckCapsule(val3, val4, 0.3f, SolidMask, (QueryTriggerInteraction)1)) { num++; } } return num >= 5; } private static bool HasAnyKnownRikoInWorld() { if (LoadedRikos.Count > 0) { return true; } foreach (KeyValuePair<string, int> worldCount in WorldCounts) { if (worldCount.Value > 0) { return true; } } return false; } private static void EnsureWorldCounts_Cached(bool initial) { float time = Time.time; if (!WorldCountCacheInitialized) { RescanWorldCounts_GlobalZdo("init"); WorldCountCacheInitialized = true; NextWorldCountRescanTime = time + 90f; } else if (!initial && !(time < NextWorldCountRescanTime)) { RescanWorldCounts_GlobalZdo("timer"); NextWorldCountRescanTime = time + 90f; } } private static void RescanWorldCounts_GlobalZdo(string reason) { WorldCounts.Clear(); if (ZDOMan.instance == null) { return; } int num = 0; int num2 = 0; for (int i = 0; i < Defs.Length; i++) { LivingContainerDef livingContainerDef = Defs[i]; if (livingContainerDef == null || string.IsNullOrEmpty(livingContainerDef.Prefab)) { continue; } int num3 = 0; PurgeZdos.Clear(); bool flag = false; int num4 = 0; try { while (!flag && num4 < 10000) { flag = ZDOMan.instance.GetAllZDOsWithPrefabIterative(livingContainerDef.Prefab, PurgeZdos, ref num3); num4++; } } catch { EnsureWorldCounts_LoadedFallback(); PurgeZdos.Clear(); LogPerf("WorldCounts RESCAN_FALLBACK reason=" + reason + " note=iterativeFailed"); return; } int num5 = 0; for (int j = 0; j < PurgeZdos.Count; j++) { ZDO val = PurgeZdos[j]; if (val != null) { int num6 = 0; try { num6 = val.GetInt("MS_Riko_Killed", 0); } catch { } if (num6 != 1) { num5++; } } } WorldCounts[livingContainerDef.Prefab] = num5; num++; num2 += PurgeZdos.Count; } PurgeZdos.Clear(); LogPerf($"WorldCounts RESCAN_OK reason={reason} prefabs={num} scannedZdos={num2}"); } private static void EnsureWorldCounts_LoadedFallback() { WorldCounts.Clear(); foreach (KeyValuePair<ZDOID, ZNetView> loadedRiko in LoadedRikos) { ZNetView value = loadedRiko.Value; if ((Object)(object)value == (Object)null || !value.IsValid()) { continue; } string prefabName = Utils.GetPrefabName(((Object)((Component)value).gameObject).name); if (!DefByPrefab.ContainsKey(prefabName)) { continue; } ZDO val = null; try { val = value.GetZDO(); } catch { } if (val != null) { int num = 0; try { num = val.GetInt("MS_Riko_Killed", 0); } catch { } if (num == 1) { continue; } } WorldCounts[prefabName] = ((!WorldCounts.TryGetValue(prefabName, out var value2)) ? 1 : (value2 + 1)); } } private static int GetAuthoritativeAliveCountForPrefab(string prefabName) { if (string.IsNullOrEmpty(prefabName)) { return 0; } int value; int num = (WorldCounts.TryGetValue(prefabName, out value) ? value : 0); if (ZDOMan.instance == null) { return num; } float time = Time.time; if (NextAuthoritativeCountCheckTime.TryGetValue(prefabName, out var value2) && time < value2) { return num; } int num2 = 0; PurgeZdos.Clear(); bool flag = false; int num3 = 0; try { while (!flag && num3 < 10000) { flag = ZDOMan.instance.GetAllZDOsWithPrefabIterative(prefabName, PurgeZdos, ref num2); num3++; } } catch { NextAuthoritativeCountCheckTime[prefabName] = time + 20f; int num4 = num; LogPerf($"WorldCounts AUTHORITATIVE_FALLBACK prefab={prefabName} cached={num4} note=iterativeFailed"); PurgeZdos.Clear(); return num4; } int num5 = 0; for (int i = 0; i < PurgeZdos.Count; i++) { ZDO val = PurgeZdos[i]; if (val != null) { int num6 = 0; try { num6 = val.GetInt("MS_Riko_Killed", 0); } catch { } if (num6 != 1) { num5++; } } } PurgeZdos.Clear(); WorldCounts[prefabName] = num5; NextAuthoritativeCountCheckTime[prefabName] = time + 20f; LogPerf($"WorldCounts AUTHORITATIVE prefab={prefabName} count={num5}"); return num5; } private static void SweepRegistryInvalidEntriesIfNeeded() { //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) LoadedRegistryInvalidSweeps++; if (LoadedRegistryInvalidSweeps < 10) { return; } LoadedRegistryInvalidSweeps = 0; if (LoadedRikos.Count == 0) { return; } if (_registrySweepKeys == null) { _registrySweepKeys = new List<ZDOID>(128); } _registrySweepKeys.Clear(); foreach (KeyValuePair<ZDOID, ZNetView> loadedRiko in LoadedRikos) { ZNetView value = loadedRiko.Value; if ((Object)(object)value == (Object)null || !value.IsValid()) { _registrySweepKeys.Add(loadedRiko.Key); } } for (int i = 0; i < _registrySweepKeys.Count; i++) { LoadedRikos.Remove(_registrySweepKeys[i]); } if (_registrySweepKeys.Count > 0) { LogPerf($"registry SWEEP removed={_registrySweepKeys.Count} remaining={LoadedRikos.Count}"); } } private static void UpdateLastSeenForLoadedRikos() { //IL_00dd: 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) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) float time = Time.time; if (time < NextSeenUpdateTime) { return; } NextSeenUpdateTime = time + 12f; if (LoadedRikos.Count == 0 || OriginPositions.Count == 0) { return; } float num = 14400f; long nowSeconds = GetNowSeconds(); SweepRegistryInvalidEntriesIfNeeded(); foreach (KeyValuePair<ZDOID, ZNetView> loadedRiko in LoadedRikos) { ZNetView value = loadedRiko.Value; if ((Object)(object)value == (Object)null || !value.IsValid()) { continue; } string prefabName = Utils.GetPrefabName(((Object)((Component)value).gameObject).name); if (!DefByPrefab.ContainsKey(prefabName)) { continue; } ZDO val = null; try { val = value.GetZDO(); } catch { } if (val != null) { int num2 = 0; try { num2 = val.GetInt("MS_Riko_Killed", 0); } catch { } if (num2 == 1) { continue; } } Vector3 position = ((Component)value).transform.position; bool flag = false; for (int i = 0; i < OriginPositions.Count; i++) { Vector3 val2 = OriginPositions[i] - position; if (((Vector3)(ref val2)).sqrMagnitude <= num) { flag = true; break; } } if (!flag) { continue; } try { if (val != null) { val.Set("MS_Riko_LastSeenTime", nowSeconds); } } catch { } } LogPerf($"SeenUpdate tick interval={12f:0.0} loaded={LoadedRikos.Count} origins={OriginPositions.Count}"); } private static void TryDestroyKilledRikoFromZdo(ZDO zdo, string prefabName, long nowS, string reason) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) if (zdo == null || string.IsNullOrEmpty(prefabName)) { return; } long num = 0L; try { num = zdo.GetLong("MS_Riko_DestroyAt", 0L); } catch { } if (num <= 0) { num = nowS; } if (nowS < num) { return; } GameObject val = null; try { if ((Object)(object)ZNetScene.instance != (Object)null) { val = ZNetScene.instance.FindInstance(zdo.m_uid); } } catch { val = null; } if ((Object)(object)val != (Object)null) { ZNetView val2 = null; try { val2 = val.GetComponent<ZNetView>(); } catch { } if ((Object)(object)val2 != (Object)null && val2.IsValid()) { DestroyKilledLoadedRiko(val2, prefabName, reason, playFx: false); return; } } ForceDestroyZDO_AndEnqueue(zdo, prefabName, reason + " notLoaded"); } private static void ProcessLoadedDestroyDueFast() { float time = Time.time; if (time < NextLoadedDestroyCheckTime) { return; } NextLoadedDestroyCheckTime = time + 0.2f; if (LoadedRikos.Count == 0) { return; } long nowSeconds = GetNowSeconds(); SweepRegistryInvalidEntriesIfNeeded(); foreach (KeyValuePair<ZDOID, ZNetView> loadedRiko in LoadedRikos) { ZNetView value = loadedRiko.Value; if ((Object)(object)value == (Object)null || !value.IsValid()) { continue; } ZDO val = null; try { val = value.GetZDO(); } catch { } if (val == null) { continue; } int num = 0; long num2 = 0L; try { num = val.GetInt("MS_Riko_Killed", 0); } catch { } if (num != 1) { continue; } try { num2 = val.GetLong("MS_Riko_DestroyAt", 0L); } catch { } if (num2 <= 0) { num2 = nowSeconds; } if (nowSeconds >= num2) { string prefabName = Utils.GetPrefabName(((Object)((Component)value).gameObject).name); if (DefByPrefab.ContainsKey(prefabName)) { DestroyKilledLoadedRiko(value, prefabName, "LoadedFastDue", playFx: false); } } } } private static void ProcessScheduledDestroyForLoadedRikos() { float time = Time.time; if (time < NextDestroyScanTime) { return; } NextDestroyScanTime = time + 20f; if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || ZDOMan.instance == null || LoadedRikos.Count == 0) { return; } long nowSeconds = GetNowSeconds(); int num = 0; int num2 = 0; int num3 = 0; for (int i = 0; i < Defs.Length; i++) { LivingContainerDef livingContainerDef = Defs[i]; if (livingContainerDef == null || string.IsNullOrEmpty(livingContainerDef.Prefab)) { continue; } int num4 = 0; PurgeZdos.Clear(); bool flag = false; int num5 = 0; try { while (!flag && num5 < 10000) { flag = ZDOMan.instance.GetAllZDOsWithPrefabIterative(livingContainerDef.Prefab, PurgeZdos, ref num4); num5++; } } catch { PurgeZdos.Clear(); continue; } num++; num2 += PurgeZdos.Count; for (int j = 0; j < PurgeZdos.Count; j++) { ZDO val = PurgeZdos[j]; if (val == null) { continue; } int num6 = 0; try { num6 = val.GetInt("MS_Riko_Killed", 0); } catch { } if (num6 == 1) { long num7 = 0L; try { num7 = val.GetLong("MS_Riko_DestroyAt", 0L); } catch { } if (num7 <= 0) { num7 = nowSeconds; } if (nowSeconds >= num7) { num3++; TryDestroyKilledRikoFromZdo(val, livingContainerDef.Prefab, nowSeconds, "ScheduledDestroy due"); } } } PurgeZdos.Clear(); } LogPerf($"DestroyScan tick interval={20f:0.0} " + $"prefabs={num} scannedZdos={num2} dueKilled={num3}"); } private static void TryRunEmptyWatcher_Server() { //IL_0213: Unknown result type (might be due to invalid IL or missing references) if (!LivingContainerConfig.IsRikoEnabled() || (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || ZDOMan.instance == null || (!_emptyWatcherInProgress && !HasAnyKnownRikoInWorld())) { return; } float time = Time.time; if (!_emptyWatcherInProgress && time < _emptyWatcherNextRunTime) { return; } CleanupItemsCacheIfNeeded(); EnsureZdoVarHashes(); BuildDefCache(); if (!_emptyWatcherInProgress) { _emptyWatcherInProgress = true; _emptyWatcherPrefabIndex = 0; _emptyWatcherSectorIndex = 0; _emptyWatcherZdos.Clear(); _emptyWatcherNextRunTime = time + 30f; } string text = null; while (_emptyWatcherPrefabIndex < Defs.Length) { LivingContainerDef livingContainerDef = Defs[_emptyWatcherPrefabIndex]; if (livingContainerDef != null && !string.IsNullOrEmpty(livingContainerDef.Prefab)) { text = livingContainerDef.Prefab; break; } _emptyWatcherPrefabIndex++; } if (text == null) { _emptyWatcherInProgress = false; return; } bool allZDOsWithPrefabIterative; try { allZDOsWithPrefabIterative = ZDOMan.instance.GetAllZDOsWithPrefabIterative(text, _emptyWatcherZdos, ref _emptyWatcherSectorIndex); } catch { _emptyWatcherInProgress = false; _emptyWatcherZdos.Clear(); return; } if (!allZDOsWithPrefabIterative) { return; } int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; int num5 = 0; int num6 = 0; int num7 = 0; long nowSeconds = GetNowSeconds(); LivingContainerDef value; bool flag = DefByPrefab.TryGetValue(text, out value);