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 DropNSpawn v1.4.11
DropNSpawn.dll
Decompiled 12 hours 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 Data; using HarmonyLib; using JetBrains.Annotations; using Microsoft.CodeAnalysis; using ServerSync; using SoftReferenceableAssets; using TMPro; using UnityEngine; using UnityEngine.SceneManagement; using YamlDotNet.Core; using YamlDotNet.Core.Events; using YamlDotNet.Core.ObjectPool; using YamlDotNet.Core.Tokens; using YamlDotNet.Helpers; using YamlDotNet.RepresentationModel; using YamlDotNet.Serialization; using YamlDotNet.Serialization.BufferedDeserialization; using YamlDotNet.Serialization.BufferedDeserialization.TypeDiscriminators; using YamlDotNet.Serialization.Callbacks; 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: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("DropNSpawn")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("sighsorry")] [assembly: AssemblyProduct("DropNSpawn")] [assembly: AssemblyCopyright("Copyright © 2021")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("4358610B-F3F4-4843-B7AF-98B7BC60DCDE")] [assembly: AssemblyFileVersion("1.4.11")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.4.11.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class ExtensionMarkerAttribute : Attribute { private readonly string <Name>k__BackingField; public string Name => <Name>k__BackingField; public ExtensionMarkerAttribute(string name) { <Name>k__BackingField = name; } } } namespace LocalizationManager { [PublicAPI] public class Localizer { private static readonly Action<Localization, string, string> AddWord; private static readonly FieldRef<Localization, Dictionary<string, string>> Translations; private static readonly Dictionary<string, Dictionary<string, Func<string>>> PlaceholderProcessors; private static readonly Dictionary<string, Dictionary<string, string>> loadedTexts; private static readonly ConditionalWeakTable<Localization, string> localizationLanguage; private static readonly List<WeakReference<Localization>> localizationObjects; private static BaseUnityPlugin? _plugin; private static readonly List<string> fileExtensions; private static BaseUnityPlugin plugin { get { //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Expected O, but got Unknown if (_plugin == null) { IEnumerable<TypeInfo> source; try { source = Assembly.GetExecutingAssembly().DefinedTypes.ToList(); } catch (ReflectionTypeLoadException ex) { source = from t in ex.Types where t != null select t.GetTypeInfo(); } _plugin = (BaseUnityPlugin)Chainloader.ManagerObject.GetComponent((Type)source.First((TypeInfo t) => t.IsClass && typeof(BaseUnityPlugin).IsAssignableFrom(t))); } return _plugin; } } public static event Action? OnLocalizationComplete; private static void UpdatePlaceholderText(Localization localization, string key) { localizationLanguage.TryGetValue(localization, out string value); string text = loadedTexts[value][key]; if (PlaceholderProcessors.TryGetValue(key, out Dictionary<string, Func<string>> value2)) { text = value2.Aggregate(text, (string current, KeyValuePair<string, Func<string>> kv) => current.Replace("{" + kv.Key + "}", kv.Value())); } AddWord(localization, key, text); } public static void AddPlaceholder<T>(string key, string placeholder, ConfigEntry<T> config, Func<T, string>? convertConfigValue = null) where T : notnull { if (convertConfigValue == null) { convertConfigValue = (T val) => val.ToString(); } if (!PlaceholderProcessors.ContainsKey(key)) { PlaceholderProcessors[key] = new Dictionary<string, Func<string>>(); } config.SettingChanged += delegate { UpdatePlaceholder(); }; if (loadedTexts.ContainsKey(Localization.instance.GetSelectedLanguage())) { UpdatePlaceholder(); } void UpdatePlaceholder() { PlaceholderProcessors[key][placeholder] = () => convertConfigValue(config.Value); UpdatePlaceholderText(Localization.instance, key); } } public static void AddText(string key, string text) { List<WeakReference<Localization>> list = new List<WeakReference<Localization>>(); foreach (WeakReference<Localization> localizationObject in localizationObjects) { if (localizationObject.TryGetTarget(out var target)) { Dictionary<string, string> dictionary = loadedTexts[localizationLanguage.GetOrCreateValue(target)]; if (!Translations.Invoke(target).ContainsKey(key)) { dictionary[key] = text; AddWord(target, key, text); } } else { list.Add(localizationObject); } } foreach (WeakReference<Localization> item in list) { localizationObjects.Remove(item); } } public static void Load() { _ = plugin; } public static void LoadLocalizationLater(Localization __instance) { LoadLocalization(Localization.instance, __instance.GetSelectedLanguage()); } public static void SafeCallLocalizeComplete() { Localizer.OnLocalizationComplete?.Invoke(); } private static void LoadLocalization(Localization __instance, string language) { if (!localizationLanguage.Remove(__instance)) { localizationObjects.Add(new WeakReference<Localization>(__instance)); } localizationLanguage.Add(__instance, language); Dictionary<string, string> dictionary = new Dictionary<string, string>(); foreach (string item in from f in Directory.GetFiles(Path.GetDirectoryName(Paths.PluginPath), plugin.Info.Metadata.Name + ".*", SearchOption.AllDirectories) where fileExtensions.IndexOf(Path.GetExtension(f)) >= 0 select f) { string[] array = Path.GetFileNameWithoutExtension(item).Split('.'); if (array.Length >= 2) { string text = array[1]; if (dictionary.ContainsKey(text)) { Debug.LogWarning((object)("Duplicate key " + text + " found for " + plugin.Info.Metadata.Name + ". The duplicate file found at " + item + " will be skipped.")); } else { dictionary[text] = item; } } } byte[] array2 = LoadTranslationFromAssembly("English"); if (array2 == null) { throw new Exception("Found no English localizations in mod " + plugin.Info.Metadata.Name + ". Expected an embedded resource translations/English.json or translations/English.yml."); } Dictionary<string, string> dictionary2 = new DeserializerBuilder().IgnoreFields().Build().Deserialize<Dictionary<string, string>>(Encoding.UTF8.GetString(array2)); if (dictionary2 == null) { throw new Exception("Localization for mod " + plugin.Info.Metadata.Name + " failed: Localization file was empty."); } string text2 = null; if (language != "English") { if (dictionary.TryGetValue(language, out var value)) { text2 = File.ReadAllText(value); } else { byte[] array3 = LoadTranslationFromAssembly(language); if (array3 != null) { text2 = Encoding.UTF8.GetString(array3); } } } if (text2 == null && dictionary.TryGetValue("English", out var value2)) { text2 = File.ReadAllText(value2); } if (text2 != null) { foreach (KeyValuePair<string, string> item2 in new DeserializerBuilder().IgnoreFields().Build().Deserialize<Dictionary<string, string>>(text2) ?? new Dictionary<string, string>()) { dictionary2[item2.Key] = item2.Value; } } loadedTexts[language] = dictionary2; foreach (KeyValuePair<string, string> item3 in dictionary2) { UpdatePlaceholderText(__instance, item3.Key); } } static Localizer() { //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Expected O, but got Unknown //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Expected O, but got Unknown //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Expected O, but got Unknown AddWord = AccessTools.MethodDelegate<Action<Localization, string, string>>(AccessTools.Method(typeof(Localization), "AddWord", new Type[2] { typeof(string), typeof(string) }, (Type[])null), (object)null, true); Translations = AccessTools.FieldRefAccess<Localization, Dictionary<string, string>>("m_translations"); PlaceholderProcessors = new Dictionary<string, Dictionary<string, Func<string>>>(); loadedTexts = new Dictionary<string, Dictionary<string, string>>(); localizationLanguage = new ConditionalWeakTable<Localization, string>(); localizationObjects = new List<WeakReference<Localization>>(); fileExtensions = new List<string>(2) { ".json", ".yml" }; Harmony val = new Harmony("org.bepinex.helpers.LocalizationManager"); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Localization), "SetupLanguage", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Localizer), "LoadLocalization", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(FejdStartup), "SetupGui", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Localizer), "LoadLocalizationLater", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(FejdStartup), "Start", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Localizer), "SafeCallLocalizeComplete", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } private static byte[]? LoadTranslationFromAssembly(string language) { foreach (string fileExtension in fileExtensions) { byte[] array = ReadEmbeddedFileBytes("translations." + language + fileExtension); if (array != null) { return array; } } return null; } public static byte[]? ReadEmbeddedFileBytes(string resourceFileName, Assembly? containingAssembly = null) { using MemoryStream memoryStream = new MemoryStream(); if ((object)containingAssembly == null) { containingAssembly = Assembly.GetCallingAssembly(); } string text = containingAssembly.GetManifestResourceNames().FirstOrDefault((string str) => str.EndsWith(resourceFileName, StringComparison.Ordinal)); if (text != null) { containingAssembly.GetManifestResourceStream(text)?.CopyTo(memoryStream); } return (memoryStream.Length == 0L) ? null : memoryStream.ToArray(); } } public static class LocalizationManagerVersion { public const string Version = "1.4.1"; } } namespace DropNSpawn { [HarmonyPatch(typeof(ZNetScene), "Awake")] internal static class ZNetSceneAwakePatch { private static void Postfix() { DropNSpawnPlugin.QueueGameDataRefresh(DropNSpawnPlugin.ReloadDomain.All, "ZNetScene.Awake"); } } [HarmonyPatch(typeof(ObjectDB), "Awake")] internal static class ObjectDBAwakePatch { private static void Postfix() { DropNSpawnPlugin.QueueGameDataRefresh(DropNSpawnPlugin.ReloadDomain.All, "ObjectDB.Awake"); } } [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] internal static class ObjectDBCopyOtherDBPatch { private static void Postfix() { DropNSpawnPlugin.QueueGameDataRefresh(DropNSpawnPlugin.ReloadDomain.All, "ObjectDB.CopyOtherDB"); } } [HarmonyPatch(typeof(ZNet), "Shutdown")] internal static class ZNetShutdownPatch { private static void Prefix() { CharacterDropManager.ResetWorldRuntimeState(); DungeonSpawnManager.ResetWorld(); } } [HarmonyPatch(typeof(ZoneSystem), "Start")] internal static class ZoneSystemStartPatch { private static void Postfix() { DropNSpawnPlugin.QueueGameDataRefresh(DropNSpawnPlugin.ReloadDomain.SpawnSystem, "ZoneSystem.Start"); } } [HarmonyPatch(typeof(RandEventSystem), "Awake")] internal static class RandEventSystemAwakePatch { private static void Postfix() { EventManager.ApplyGlobalEventSettings(); } } [HarmonyPatch(typeof(RandEventSystem), "Start")] internal static class RandEventSystemStartPatch { private static void Postfix() { EventManager.ApplyGlobalEventSettings(); } } [HarmonyPatch(typeof(ZoneSystem), "Start")] internal static class ZoneSystemStartEventPatch { [HarmonyPriority(0)] private static void Postfix() { EventManager.NotifyGameDataReady("ZoneSystem.Start"); } } [HarmonyPatch(typeof(RandEventSystem), "OnDestroy")] internal static class RandEventSystemOnDestroyPatch { private static void Prefix() { EventManager.OnRandEventSystemDestroyed(); } } [HarmonyPatch(typeof(RandEventSystem), "FixedUpdate")] internal static class RandEventSystemFixedUpdatePatch { private static bool Prefix(RandEventSystem __instance) { return !EventManager.TryRunMultipleEventsFixedUpdate(__instance); } } [HarmonyPatch(typeof(RandEventSystem), "SetRandomEvent")] internal static class RandEventSystemSetRandomEventPatch { private static bool Prefix(RandEventSystem __instance, RandomEvent ev, Vector3 pos) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) return !EventManager.TryHandleMultipleSetRandomEvent(__instance, ev, pos); } } [HarmonyPatch(typeof(RandEventSystem), "SendCurrentRandomEvent")] internal static class RandEventSystemSendCurrentRandomEventPatch { private static bool Prefix(RandEventSystem __instance) { return !EventManager.TrySendMultipleCurrentRandomEvent(__instance); } } [HarmonyPatch(typeof(RandEventSystem), "UpdateRandomEvent")] internal static class RandEventSystemUpdateRandomEventPatch { private static bool Prefix(RandEventSystem __instance, float dt) { return !EventManager.TryRunCheckPerPlayerRandomUpdate(__instance, dt); } } [HarmonyPatch(typeof(RandomEvent), "Clone")] internal static class RandomEventClonePatch { private static void Postfix(RandomEvent __instance, RandomEvent __result) { EventManager.CopySpawnPayloads(__instance, __result); } } [HarmonyPatch(typeof(RandEventSystem), "CheckBase")] internal static class RandEventSystemCheckBasePatch { private static bool Prefix(RandomEvent ev, PlayerEventData player, ref bool __result) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) if (!EventManager.TryCheckBase(ev, player, out var result)) { return true; } __result = result; return false; } } [HarmonyPatch(typeof(RandEventSystem), "InValidBiome")] internal static class RandEventSystemInValidBiomePatch { private static void Postfix(RandomEvent ev, Vector3 point, ref bool __result) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) __result = EventManager.PassesExtraChecks(ev, point, __result); } } [HarmonyPatch(typeof(RandomEvent), "OnStart")] internal static class RandomEventOnStartPatch { private static void Postfix(RandomEvent __instance) { EventManager.RunStartCommands(__instance); } } [HarmonyPatch(typeof(RandomEvent), "OnStop")] internal static class RandomEventOnStopPatch { private static void Postfix(RandomEvent __instance) { EventManager.RunEndCommands(__instance); } } [HarmonyPatch(typeof(Location), "OnDestroy")] internal static class LocationOnDestroyPatch { private static void Prefix(Location __instance) { SpawnerManager.UntrackLocationInstanceProvenance(__instance); } } [HarmonyPatch(typeof(LocationProxy), "SpawnLocation")] internal static class LocationProxySpawnLocationPatch { private static readonly FieldRef<LocationProxy, GameObject> InstanceRef = AccessTools.FieldRefAccess<LocationProxy, GameObject>("m_instance"); private static void Postfix(LocationProxy __instance, bool __result) { if (__result && PluginSettingsFacade.IsSpawnerDomainEnabled() && !DropNSpawnPlugin.IsGameDataRefreshDeferred(DropNSpawnPlugin.ReloadDomain.Spawner)) { GameObject spawnedRoot = (((Object)(object)__instance != (Object)null) ? InstanceRef.Invoke(__instance) : null); SpawnerManager.RecordSpawnedLocationProxyProvenance(__instance, spawnedRoot); } } } internal readonly struct TemporaryFieldOverrideState<T> where T : class { internal bool Applied { get; } internal T? Previous { get; } internal TemporaryFieldOverrideState(T? previous) { Applied = true; Previous = previous; } } [HarmonyPatch(typeof(Piece), "Awake")] internal static class PieceAwakePatch { private static void Postfix(Piece __instance) { ObjectDropManager.QueueObjectInstanceReconcile(((Component)__instance).gameObject, ObjectDropManager.LiveObjectComponentKind.Piece); } } [HarmonyPatch(typeof(Piece), "SetCreator")] internal static class PieceSetCreatorPatch { private static void Postfix(Piece __instance) { if (PluginSettingsFacade.IsObjectDomainEnabled()) { ObjectDropManager.ReconcilePieceInstance(__instance); } } } [HarmonyPatch(typeof(Piece), "OnDestroy")] internal static class PieceOnDestroyPatch { private static void Prefix(Piece __instance) { ObjectDropManager.UntrackObjectInstance(((Component)__instance).gameObject); } } [HarmonyPatch(typeof(ZNetView), "OnDestroy")] internal static class ZNetViewOnDestroyPatch { private static void Prefix(ZNetView __instance) { ObjectDropManager.UntrackObjectInstance(((Component)__instance).gameObject); SpawnArea component = ((Component)__instance).GetComponent<SpawnArea>(); if ((Object)(object)component != (Object)null) { SpawnerManager.UntrackSpawnAreaInstance(component); } } } [HarmonyPatch(typeof(Destructible), "Awake")] internal static class DestructibleAwakePatch { private static void Postfix(Destructible __instance) { ObjectDropManager.QueueObjectInstanceReconcile(((Component)__instance).gameObject, ObjectDropManager.LiveObjectComponentKind.Destructible); } } [HarmonyPatch(typeof(Destructible), "GetDestructibleType")] internal static class DestructibleGetDestructibleTypePatch { private static void Prefix(Destructible __instance) { if (PluginSettingsFacade.IsObjectDomainEnabled()) { ObjectDropManager.ApplyLazyDestructibleTypeIfNeeded(__instance); } } } [HarmonyPatch(typeof(Destructible), "RPC_Damage")] internal static class DestructibleDamagePatch { private static void Prefix(Destructible __instance) { if (PluginSettingsFacade.IsObjectDomainEnabled()) { ObjectDropManager.ApplyLazyDestructibleScalarsIfNeeded(__instance); } } } [HarmonyPatch(typeof(Destructible), "Destroy")] internal static class DestructibleDestroyPatch { private static void Prefix(Destructible __instance, out TemporaryFieldOverrideState<GameObject> __state) { __state = default(TemporaryFieldOverrideState<GameObject>); if (PluginSettingsFacade.IsObjectDomainEnabled() && ObjectDropManager.TryOverrideConditionalDestructibleSpawnWhenDestroyed(__instance, out GameObject previous)) { __state = new TemporaryFieldOverrideState<GameObject>(previous); } } private static void Postfix(Destructible __instance, TemporaryFieldOverrideState<GameObject> __state) { if (__state.Applied) { __instance.m_spawnWhenDestroyed = __state.Previous; } } private static Exception? Finalizer(Destructible __instance, TemporaryFieldOverrideState<GameObject> __state, Exception? __exception) { if (__exception != null && __state.Applied) { __instance.m_spawnWhenDestroyed = __state.Previous; } return __exception; } } [HarmonyPatch(typeof(DropOnDestroyed), "Awake")] internal static class DropOnDestroyedAwakePatch { private static void Postfix(DropOnDestroyed __instance) { ObjectDropManager.QueueObjectInstanceReconcile(((Component)__instance).gameObject, ObjectDropManager.LiveObjectComponentKind.DropOnDestroyed); } } [HarmonyPatch(typeof(Container), "Awake")] internal static class ContainerAwakePatch { private static void Postfix(Container __instance) { ObjectDropManager.QueueObjectInstanceReconcile(((Component)__instance).gameObject, ObjectDropManager.LiveObjectComponentKind.Container); } } [HarmonyPatch(typeof(Pickable), "Awake")] internal static class PickableAwakePatch { private static void Postfix(Pickable __instance) { if (!PluginSettingsFacade.IsObjectDomainEnabled()) { ObjectDropManager.TrackObjectInstance(((Component)__instance).gameObject); } else { ObjectDropManager.QueueObjectInstanceReconcile(((Component)__instance).gameObject, ObjectDropManager.LiveObjectComponentKind.Pickable); } } } [HarmonyPatch(typeof(PickableItem), "Awake")] internal static class PickableItemAwakePatch { private static void Postfix(PickableItem __instance) { if (!PluginSettingsFacade.IsObjectDomainEnabled()) { ObjectDropManager.TrackObjectInstance(((Component)__instance).gameObject); } else { ObjectDropManager.QueueObjectInstanceReconcile(((Component)__instance).gameObject, ObjectDropManager.LiveObjectComponentKind.PickableItem); } } } [HarmonyPatch(typeof(Fish), "Awake")] internal static class FishAwakePatch { private static void Postfix(Fish __instance) { ObjectDropManager.QueueObjectInstanceReconcile(((Component)__instance).gameObject, ObjectDropManager.LiveObjectComponentKind.Fish); } } [HarmonyPatch(typeof(Container), "AddDefaultItems")] internal static class ContainerAddDefaultItemsPatch { private static void Prefix(Container __instance, out TemporaryFieldOverrideState<DropTable> __state) { __state = default(TemporaryFieldOverrideState<DropTable>); if (PluginSettingsFacade.IsObjectDomainEnabled() && ObjectDropManager.TryOverrideContainerDrops(__instance, out DropTable previous)) { __state = new TemporaryFieldOverrideState<DropTable>(previous); } } private static void Postfix(Container __instance, TemporaryFieldOverrideState<DropTable> __state) { if (__state.Applied) { __instance.m_defaultItems = __state.Previous; } } private static Exception? Finalizer(Container __instance, TemporaryFieldOverrideState<DropTable> __state, Exception? __exception) { if (__exception != null && __state.Applied) { __instance.m_defaultItems = __state.Previous; } return __exception; } } [HarmonyPatch(typeof(DropOnDestroyed), "OnDestroyed")] internal static class DropOnDestroyedPatch { private static void Prefix(DropOnDestroyed __instance, out TemporaryFieldOverrideState<DropTable> __state) { __state = default(TemporaryFieldOverrideState<DropTable>); if (PluginSettingsFacade.IsObjectDomainEnabled() && ObjectDropManager.TryOverrideConditionalDropOnDestroyed(__instance, out DropTable previous)) { __state = new TemporaryFieldOverrideState<DropTable>(previous); } } private static void Postfix(DropOnDestroyed __instance, TemporaryFieldOverrideState<DropTable> __state) { if (__state.Applied) { __instance.m_dropWhenDestroyed = __state.Previous; } } private static Exception? Finalizer(DropOnDestroyed __instance, TemporaryFieldOverrideState<DropTable> __state, Exception? __exception) { if (__exception != null && __state.Applied) { __instance.m_dropWhenDestroyed = __state.Previous; } return __exception; } } [HarmonyPatch(typeof(MineRock), "RPC_Hit")] internal static class MineRockHitPatch { private static void Prefix(MineRock __instance, out TemporaryFieldOverrideState<DropTable> __state) { __state = default(TemporaryFieldOverrideState<DropTable>); if (PluginSettingsFacade.IsObjectDomainEnabled()) { ObjectDropManager.ApplyLazyMineRockScalarsIfNeeded(__instance); if (ObjectDropManager.TryOverrideConditionalMineRockDrops(__instance, out DropTable previous)) { __state = new TemporaryFieldOverrideState<DropTable>(previous); } } } private static void Postfix(MineRock __instance, TemporaryFieldOverrideState<DropTable> __state) { if (__state.Applied) { __instance.m_dropItems = __state.Previous; } } private static Exception? Finalizer(MineRock __instance, TemporaryFieldOverrideState<DropTable> __state, Exception? __exception) { if (__exception != null && __state.Applied) { __instance.m_dropItems = __state.Previous; } return __exception; } } [HarmonyPatch(typeof(MineRock), "Start")] internal static class MineRockStartPatch { private static void Postfix(MineRock __instance) { ObjectDropManager.QueueObjectInstanceReconcile(((Component)__instance).gameObject, ObjectDropManager.LiveObjectComponentKind.MineRock); } } [HarmonyPatch(typeof(MineRock5), "RPC_Damage")] internal static class MineRock5DamagePatch { private static void Prefix(MineRock5 __instance, out TemporaryFieldOverrideState<DropTable> __state) { __state = default(TemporaryFieldOverrideState<DropTable>); if (PluginSettingsFacade.IsObjectDomainEnabled()) { ObjectDropManager.ApplyLazyMineRock5ScalarsIfNeeded(__instance); if (ObjectDropManager.TryOverrideConditionalMineRock5Drops(__instance, out DropTable previous)) { __state = new TemporaryFieldOverrideState<DropTable>(previous); } } } private static void Postfix(MineRock5 __instance, TemporaryFieldOverrideState<DropTable> __state) { if (__state.Applied) { __instance.m_dropItems = __state.Previous; } } private static Exception? Finalizer(MineRock5 __instance, TemporaryFieldOverrideState<DropTable> __state, Exception? __exception) { if (__exception != null && __state.Applied) { __instance.m_dropItems = __state.Previous; } return __exception; } } [HarmonyPatch(typeof(MineRock5), "Awake")] internal static class MineRock5AwakePatch { private static void Postfix(MineRock5 __instance) { ObjectDropManager.QueueObjectInstanceReconcile(((Component)__instance).gameObject, ObjectDropManager.LiveObjectComponentKind.MineRock5); } } [HarmonyPatch(typeof(TreeBase), "RPC_Damage")] internal static class TreeBaseDamagePatch { private static void Prefix(TreeBase __instance, out TemporaryFieldOverrideState<DropTable> __state) { __state = default(TemporaryFieldOverrideState<DropTable>); if (PluginSettingsFacade.IsObjectDomainEnabled()) { ObjectDropManager.ApplyLazyTreeBaseScalarsIfNeeded(__instance); if (ObjectDropManager.TryOverrideConditionalTreeBaseDrops(__instance, out DropTable previous)) { __state = new TemporaryFieldOverrideState<DropTable>(previous); } } } private static void Postfix(TreeBase __instance, TemporaryFieldOverrideState<DropTable> __state) { if (__state.Applied) { __instance.m_dropWhenDestroyed = __state.Previous; } } private static Exception? Finalizer(TreeBase __instance, TemporaryFieldOverrideState<DropTable> __state, Exception? __exception) { if (__exception != null && __state.Applied) { __instance.m_dropWhenDestroyed = __state.Previous; } return __exception; } } [HarmonyPatch(typeof(TreeBase), "Awake")] internal static class TreeBaseAwakePatch { private static void Postfix(TreeBase __instance) { ObjectDropManager.QueueObjectInstanceReconcile(((Component)__instance).gameObject, ObjectDropManager.LiveObjectComponentKind.TreeBase); } } [HarmonyPatch(typeof(TreeLog), "Destroy")] internal static class TreeLogDestroyPatch { private static void Prefix(TreeLog __instance, out TemporaryFieldOverrideState<DropTable> __state) { __state = default(TemporaryFieldOverrideState<DropTable>); if (PluginSettingsFacade.IsObjectDomainEnabled() && ObjectDropManager.TryOverrideConditionalTreeLogDrops(__instance, out DropTable previous)) { __state = new TemporaryFieldOverrideState<DropTable>(previous); } } private static void Postfix(TreeLog __instance, TemporaryFieldOverrideState<DropTable> __state) { if (__state.Applied) { __instance.m_dropWhenDestroyed = __state.Previous; } } private static Exception? Finalizer(TreeLog __instance, TemporaryFieldOverrideState<DropTable> __state, Exception? __exception) { if (__exception != null && __state.Applied) { __instance.m_dropWhenDestroyed = __state.Previous; } return __exception; } } [HarmonyPatch(typeof(TreeLog), "RPC_Damage")] internal static class TreeLogDamagePatch { private static void Prefix(TreeLog __instance) { if (PluginSettingsFacade.IsObjectDomainEnabled()) { ObjectDropManager.ApplyLazyTreeLogScalarsIfNeeded(__instance); } } } [HarmonyPatch(typeof(TreeLog), "Awake")] internal static class TreeLogAwakePatch { private static void Postfix(TreeLog __instance) { ObjectDropManager.QueueObjectInstanceReconcile(((Component)__instance).gameObject, ObjectDropManager.LiveObjectComponentKind.TreeLog); } } [HarmonyPatch(typeof(CharacterDrop), "GenerateDropList")] internal static class CharacterDropGenerateDropListPatch { private readonly struct State { internal List<Drop>? PreviousDrops { get; } internal bool HasOnePerPlayerScope { get; } internal IReadOnlyList<Drop>? AmountSourceDrops { get; } internal State(List<Drop>? previousDrops, bool hasOnePerPlayerScope, IReadOnlyList<Drop>? amountSourceDrops) { PreviousDrops = previousDrops; HasOnePerPlayerScope = hasOnePerPlayerScope; AmountSourceDrops = amountSourceDrops; } } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod) { return CharacterLootPatchInstructions.TryRewrite(instructions, ref CharacterDropManager.DropRowTrackingAvailable, delegate(List<CodeInstruction> input) { int num = CharacterLootPatchInstructions.FindSingleCall(input, CharacterLootPatchInstructions.AddDrop); if (num < 4 || input[num - 3].opcode != OpCodes.Ldfld || !object.Equals(input[num - 3].operand, AccessTools.Field(typeof(Drop), "m_prefab"))) { throw new InvalidOperationException("CharacterDrop successful-row contract changed; refusing partial loot scaling."); } CodeInstruction val = CharacterLootPatchInstructions.LoadLocal(input[num - 4], typeof(Drop), __originalMethod); CharacterLootPatchInstructions.ReplaceCall(input, num, (CodeInstruction[])(object)new CodeInstruction[1] { val }, AccessTools.Method(typeof(CharacterDropManager), "RecordGeneratedDrop", (Type[])null, (Type[])null)); return input; }); } private static void Prefix(CharacterDrop __instance, out State __state) { __state = new State(null, hasOnePerPlayerScope: false, null); bool flag = PluginSettingsFacade.IsCharacterDomainEnabled(); if (flag || CharacterDropManager.IsGlobalCharacterLootLevelScalingEnabled() || PluginSettingsFacade.IsLinearChanceOnlyDropScalingEnabled()) { List<Drop> list = (flag ? CharacterDropManager.OverrideConditionalDrops(__instance) : null); __state = new State(list, hasOnePerPlayerScope: false, null); IReadOnlyList<Drop> sourceDrops; List<Drop> list2 = CharacterDropManager.PrepareCharacterLootScalingDrops(__instance, out sourceDrops); if (list == null) { list = list2; } __state = new State(list, hasOnePerPlayerScope: false, sourceDrops); bool hasOnePerPlayerScope = flag && CharacterDropManager.BeginOnePerPlayerNearbyPlayerScope(__instance); __state = new State(list, hasOnePerPlayerScope, sourceDrops); } } [HarmonyPriority(0)] private static void Postfix(CharacterDrop __instance, List<KeyValuePair<GameObject, int>> __result, State __state) { CharacterDropManager.KeepUnmatchedDropsLoose(__result); CharacterDropManager.ApplyGlobalCharacterLootLevelMultiplier(__instance, __result, __state.AmountSourceDrops); if (__state.PreviousDrops != null) { __instance.m_drops = __state.PreviousDrops; } CharacterDropKillerFilter.SuppressScopedGeneratedDrops(__instance, __result); } private static Exception? Finalizer(CharacterDrop __instance, State __state, List<KeyValuePair<GameObject, int>>? __result, Exception? __exception) { if (__state.PreviousDrops != null) { __instance.m_drops = __state.PreviousDrops; } if (__state.HasOnePerPlayerScope) { CharacterDropManager.EndOnePerPlayerNearbyPlayerScope(); } if (__exception == null && __result != null) { CharacterDropManager.KeepUnmatchedDropsLoose(__result); } return __exception; } } [HarmonyPatch(typeof(Ragdoll), "SaveLootList")] internal static class RagdollSaveDropPolicyPatch { private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { return CharacterLootPatchInstructions.TryRewrite(instructions, ref CharacterDropManager.SaveStackPolicyAvailable, delegate(List<CodeInstruction> input) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown int index = CharacterLootPatchInstructions.FindSingleCall(input, AccessTools.Method(typeof(CharacterDrop), "GenerateDropList", (Type[])null, (Type[])null)); CharacterLootPatchInstructions.ReplaceCall(input, index, (CodeInstruction[])(object)new CodeInstruction[1] { new CodeInstruction(OpCodes.Ldarg_0, (object)null) }, AccessTools.Method(typeof(CharacterDropManager), "GenerateAndSaveStackPolicy", (Type[])null, (Type[])null)); return input; }); } } [HarmonyPatch(typeof(Ragdoll), "SpawnLoot")] internal static class RagdollLoadDropPolicyPatch { private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod) { return CharacterLootPatchInstructions.TryRewrite(instructions, ref CharacterDropManager.LoadStackPolicyAvailable, delegate(List<CodeInstruction> input) { CodeInstruction[] array = FindLocals("drop_hash"); CodeInstruction[] array2 = FindLocals("drop_amount"); if (!object.Equals(array[0].operand, array2[0].operand) || !object.Equals(array[1].operand, array2[1].operand)) { throw new InvalidOperationException("Ragdoll saved rows no longer share a ZDO/index."); } int index = CharacterLootPatchInstructions.FindSingleCall(input, CharacterLootPatchInstructions.AddDrop); CharacterLootPatchInstructions.ReplaceCall(input, index, array, AccessTools.Method(typeof(CharacterDropManager), "RecordSavedDrop", (Type[])null, (Type[])null)); return input; }); CodeInstruction[] FindLocals(string key) { int[] array = (from pair in P_1.input.Select((CodeInstruction instruction, int index) => (instruction: instruction, index: index)) where pair.instruction.opcode == OpCodes.Ldstr && object.Equals(pair.instruction.operand, key) select pair.index).ToArray(); if (array.Length != 1 || array[0] < 1 || array[0] + 1 >= P_1.input.Count) { throw new InvalidOperationException("Ragdoll saved-row contract changed: " + key); } int num = array[0]; return (CodeInstruction[])(object)new CodeInstruction[2] { CharacterLootPatchInstructions.LoadLocal(P_1.input[num - 1], typeof(ZDO), __originalMethod), CharacterLootPatchInstructions.LoadLocal(P_1.input[num + 1], typeof(int), __originalMethod, address: true) }; } } } internal static class CharacterLootPatchInstructions { internal static readonly MethodInfo AddDrop = AccessTools.Method(typeof(List<KeyValuePair<GameObject, int>>), "Add", (Type[])null, (Type[])null); internal static IEnumerable<CodeInstruction> TryRewrite(IEnumerable<CodeInstruction> instructions, ref bool available, Func<List<CodeInstruction>, List<CodeInstruction>> rewrite) { List<CodeInstruction> list = instructions.ToList(); available = false; try { List<CodeInstruction> result = rewrite(((IEnumerable<CodeInstruction>)list).Select((Func<CodeInstruction, CodeInstruction>)((CodeInstruction instruction) => new CodeInstruction(instruction))).ToList()); available = true; return result; } catch (InvalidOperationException ex) { ManualLogSource dropNSpawnLogger = DropNSpawnPlugin.DropNSpawnLogger; if (dropNSpawnLogger != null) { dropNSpawnLogger.LogWarning((object)("Loot row tracking hook unavailable; affected native amount/stack overrides are disabled, and existing loot is preserved. " + ex.Message)); } return list; } } internal static int FindSingleCall(List<CodeInstruction> instructions, MethodInfo target) { int[] array = (from pair in instructions.Select((CodeInstruction instruction, int index) => (instruction: instruction, index: index)) where CodeInstructionExtensions.Calls(pair.instruction, target) select pair.index).ToArray(); if (array.Length != 1) { throw new InvalidOperationException("Loot row hook requires one call to " + target); } return array[0]; } internal static CodeInstruction LoadLocal(CodeInstruction instruction, Type type, MethodBase method, bool address = false) { //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Expected O, but got Unknown int num; bool num2; if (!address && instruction.opcode == OpCodes.Ldloc_0) { num = 0; } else if (!address && instruction.opcode == OpCodes.Ldloc_1) { num = 1; } else if (!address && instruction.opcode == OpCodes.Ldloc_2) { num = 2; } else { if (address || !(instruction.opcode == OpCodes.Ldloc_3)) { if (!address) { if (!(instruction.opcode == OpCodes.Ldloc)) { num2 = instruction.opcode == OpCodes.Ldloc_S; goto IL_00bf; } } else if (!(instruction.opcode == OpCodes.Ldloca)) { num2 = instruction.opcode == OpCodes.Ldloca_S; goto IL_00bf; } goto IL_00c1; } num = 3; } goto IL_0108; IL_0108: if (num < 0 || num >= method.GetMethodBody().LocalVariables.Count || method.GetMethodBody().LocalVariables[num].LocalType != type) { throw new InvalidOperationException("Unexpected loot local type."); } return new CodeInstruction(OpCodes.Ldloc, (object)num); IL_00c1: num = ((instruction.operand is LocalVariableInfo localVariableInfo) ? localVariableInfo.LocalIndex : ((instruction.operand is LocalBuilder localBuilder) ? localBuilder.LocalIndex : Convert.ToInt32(instruction.operand))); goto IL_0108; IL_00bf: if (!num2) { throw new InvalidOperationException("Unexpected loot local instruction."); } goto IL_00c1; } internal static void ReplaceCall(List<CodeInstruction> instructions, int index, CodeInstruction[] arguments, MethodInfo target) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Expected O, but got Unknown arguments[0].labels.AddRange(instructions[index].labels); arguments[0].blocks.AddRange(instructions[index].blocks); instructions[index] = new CodeInstruction(OpCodes.Call, (object)target); instructions.InsertRange(index, arguments); } } [HarmonyPatch(typeof(ZNet), "GetNrOfPlayers")] internal static class ZNetGetNrOfPlayersPatch { private static bool Prefix(ref int __result) { if (!PluginSettingsFacade.IsCharacterDomainEnabled()) { return true; } if (!CharacterDropManager.TryGetScopedOnePerPlayerNearbyPlayerCount(out var playerCount)) { return true; } __result = playerCount; return false; } } [HarmonyPatch(typeof(CharacterDrop), "Start")] internal static class CharacterDropStartPatch { private static void Postfix(CharacterDrop __instance) { if (PluginSettingsFacade.IsCharacterDomainEnabled()) { CharacterDropManager.TrackCharacterDropInstance(__instance); } } } [HarmonyPatch(typeof(Character), "OnDestroy")] internal static class CharacterOnDestroyCharacterDropPatch { private static void Postfix(Character __instance) { CharacterDropKillerFilter.ForgetCharacter(__instance); CharacterDrop characterDrop = default(CharacterDrop); if ((Object)(object)__instance != (Object)null && ((Component)__instance).TryGetComponent<CharacterDrop>(ref characterDrop)) { CharacterDropManager.UntrackCharacterDropInstance(characterDrop); } } } [HarmonyPatch(typeof(CharacterDrop), "OnDeath")] internal static class CharacterDropOnDeathPatch { private static bool Prefix(CharacterDrop __instance) { if (CharacterDropKillerFilter.ShouldSuppressDeathCallback(__instance)) { return false; } if (!PluginSettingsFacade.IsCharacterDomainEnabled()) { return true; } return !CharacterDropManager.TryHandleConfiguredDeath(__instance); } } [HarmonyPatch(typeof(CharacterDrop), "DropItems")] internal static class CharacterDropDropItemsPatch { private static void Prefix(ref List<KeyValuePair<GameObject, int>> drops, Vector3 centerPos, float dropArea, bool cheated) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) if (PluginSettingsFacade.IsCharacterDomainEnabled()) { CharacterDropManager.ApplyGlobalDropInStack(ref drops, centerPos, dropArea, cheated); } } } [HarmonyPatch(typeof(Ragdoll), "Setup")] internal static class RagdollSetupMonsterInstantLootDropPatch { internal const string EpicLootGuid = "randyknapp.mods.epicloot"; private static readonly MethodInfo SpawnLootMethod = AccessTools.Method(typeof(Ragdoll), "SpawnLoot", new Type[1] { typeof(Vector3) }, (Type[])null); private static readonly Action<Ragdoll, Vector3> SpawnLoot = AccessTools.MethodDelegate<Action<Ragdoll, Vector3>>(SpawnLootMethod, (object)null, true); private static bool _instantLootCompatible; [ThreadStatic] private static Ragdoll? _instantLootRagdoll; internal static void InitializeEpicLootCompatibility(Harmony harmony) { PluginInfo value; bool present = Chainloader.PluginInfos.TryGetValue("randyknapp.mods.epicloot", out value); ConfigureEpicLootCompatibility(harmony, present, (value == null) ? null : ((object)value.Instance)?.GetType().Assembly); } private static void ConfigureEpicLootCompatibility(Harmony harmony, bool present, Assembly? assembly) { //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Expected O, but got Unknown _instantLootCompatible = !present; if (!present) { return; } try { MethodInfo callback = assembly?.GetType("EpicLoot.Ragdoll_SpawnLoot_Patch", throwOnError: false)?.GetMethod("Postfix", BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[2] { typeof(Ragdoll), typeof(Vector3) }, null); if (!(callback == null) && !(callback.ReturnType != typeof(void)) && !callback.ContainsGenericParameters) { Patches patchInfo = Harmony.GetPatchInfo((MethodBase)SpawnLootMethod); if (patchInfo != null && patchInfo.Postfixes.Any((Patch p) => p.PatchMethod == callback)) { MethodInfo guard = AccessTools.DeclaredMethod(typeof(RagdollSetupMonsterInstantLootDropPatch), "EpicLootSpawnLootPrefix", (Type[])null, (Type[])null); Patches patchInfo2 = Harmony.GetPatchInfo((MethodBase)callback); if (patchInfo2 == null || !patchInfo2.Prefixes.Any((Patch p) => p.owner == harmony.Id && p.PatchMethod == guard)) { harmony.Patch((MethodBase)callback, new HarmonyMethod(guard), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } Patches patchInfo3 = Harmony.GetPatchInfo((MethodBase)callback); if (patchInfo3 == null || !patchInfo3.Prefixes.Any((Patch p) => p.owner == harmony.Id && p.PatchMethod == guard)) { throw new InvalidOperationException("The EpicLoot early-loot guard was not installed."); } _instantLootCompatible = true; return; } } throw new InvalidOperationException("The registered EpicLoot Ragdoll.SpawnLoot callback could not be verified."); } catch (Exception arg) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)$"EpicLoot instant-loot compatibility unavailable; monster loot will use normal ragdoll timing. Settings are unchanged. {arg}"); } } private static bool EpicLootSpawnLootPrefix(Ragdoll __0) { if (_instantLootRagdoll != null) { return _instantLootRagdoll != __0; } return true; } private static void SpawnInstantLoot(Ragdoll ragdoll, Vector3 center) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) Ragdoll instantLootRagdoll = _instantLootRagdoll; _instantLootRagdoll = ragdoll; try { SpawnLoot(ragdoll, center); } finally { _instantLootRagdoll = instantLootRagdoll; } } private static void Postfix(Ragdoll __instance, CharacterDrop characterDrop, ZNetView ___m_nview) { //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) if (!_instantLootCompatible || !PluginSettingsFacade.IsMonsterInstantLootDropEnabled() || (Object)(object)characterDrop == (Object)null || !__instance.m_dropItems) { return; } if ((Object)(object)___m_nview == (Object)null || !___m_nview.IsValid() || !___m_nview.IsOwner()) { return; } ZDO zDO = ___m_nview.GetZDO(); if (zDO.GetInt(ZDOVars.s_drops, 0) > 0 && !PluginSettingsFacade.IsMonsterInstantLootDropBlacklisted(CharacterDropManager.GetPrefabName(((Component)characterDrop).gameObject))) { Vector3 center = __instance.GetAverageBodyPosition(); if ((Object)(object)__instance.m_lootSpawnJoint != (Object)null) { center = __instance.m_lootSpawnJoint.transform.position; } SpawnInstantLoot(__instance, center); zDO.Set(ZDOVars.s_drops, 0, false); } } } [HarmonyPatch(typeof(ZoneSystem), "SpawnLocation", new Type[] { typeof(ZoneLocation), typeof(int), typeof(Vector3), typeof(Quaternion), typeof(SpawnMode), typeof(List<GameObject>), typeof(bool) })] [HarmonyAfter(new string[] { "expand_world_data" })] internal static class ZoneSystemSpawnLocationContextPatch { private sealed class SpawnLocationContextState { public bool HasContext { get; set; } } private static void Prefix(ZoneLocation location, ref SpawnLocationContextState? __state) { __state = null; if (PluginSettingsFacade.IsSpawnerDomainEnabled() && !DropNSpawnPlugin.IsGameDataRefreshDeferred(DropNSpawnPlugin.ReloadDomain.Spawner)) { SpawnerManager.BeginLocationSpawnContext(location); __state = new SpawnLocationContextState { HasContext = true }; } } private static void Postfix(GameObject __result, SpawnLocationContextState? __state) { if (__state != null && __state.HasContext) { SpawnerManager.RecordSpawnedLocationRootProvenance(__result); } } private static void Finalizer(SpawnLocationContextState? __state) { if (__state != null && __state.HasContext) { SpawnerManager.EndLocationSpawnContext(); } } } [HarmonyPatch(typeof(DungeonGenerator), "Generate", new Type[] { typeof(SpawnMode) })] internal static class DungeonGeneratorGenerateContextPatch { private static void Prefix(DungeonGenerator __instance, ref bool __state) { __state = false; if (PluginSettingsFacade.IsSpawnerDomainEnabled() && !DropNSpawnPlugin.IsGameDataRefreshDeferred(DropNSpawnPlugin.ReloadDomain.Spawner)) { __state = SpawnerManager.TryBeginDerivedLocationSpawnContext(__instance); } } private static void Finalizer(bool __state) { if (__state) { SpawnerManager.EndLocationSpawnContext(); } } } [HarmonyPatch(typeof(DungeonGenerator), "Spawn")] internal static class DungeonGeneratorSpawnContextPatch { private static void Prefix(DungeonGenerator __instance, ref bool __state) { __state = false; if (PluginSettingsFacade.IsSpawnerDomainEnabled() && !DropNSpawnPlugin.IsGameDataRefreshDeferred(DropNSpawnPlugin.ReloadDomain.Spawner)) { __state = SpawnerManager.TryBeginDerivedLocationSpawnContext(__instance); } } private static void Finalizer(bool __state) { if (__state) { SpawnerManager.EndLocationSpawnContext(); } } } [HarmonyPatch(typeof(SpawnArea), "Awake")] internal static class SpawnAreaAwakePatch { private static void Postfix(SpawnArea __instance) { SpawnerManager.HandleSpawnAreaInstanceAwake(__instance); } } [HarmonyPatch(typeof(SpawnArea), "UpdateSpawn")] internal static class SpawnAreaUpdateSpawnPatch { private static bool Prefix(SpawnArea __instance) { if (!PluginSettingsFacade.IsSpawnerDomainEnabled()) { return true; } if (SpawnerManager.ShouldBlockClientSpawnerUpdate()) { return false; } return SpawnerManager.PrepareSpawnAreaForUpdate(__instance); } } [HarmonyPatch(typeof(SpawnArea), "SelectWeightedPrefab")] internal static class SpawnAreaSelectWeightedPrefabPatch { private static void Postfix(SpawnArea __instance, SpawnData __result) { if (PluginSettingsFacade.IsSpawnerDomainEnabled()) { SpawnerManager.RecordSelectedSpawnAreaPrefab(__instance, __result); } } } [HarmonyPatch(typeof(SpawnArea), "FindSpawnPoint")] internal static class SpawnAreaFindSpawnPointPatch { private static void Postfix(SpawnArea __instance, GameObject prefab, ref Vector3 point, bool __result) { //IL_000b: 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) if (PluginSettingsFacade.IsSpawnerDomainEnabled()) { SpawnerManager.RecordSpawnAreaSpawnPoint(__instance, __result, point); if (__result) { SpawnerManager.InitializeSpawnAreaSpawnData(__instance, prefab, point); } } } } [HarmonyPatch(typeof(SpawnArea), "SpawnOne")] internal static class SpawnAreaSpawnOnePatch { private static readonly MethodInfo InstantiateGameObjectMethod = (from method in typeof(Object).GetMethods(BindingFlags.Static | BindingFlags.Public) where method.Name == "Instantiate" && method.IsGenericMethodDefinition select method).First(delegate(MethodInfo method) { ParameterInfo[] parameters = method.GetParameters(); return parameters.Length == 3 && parameters[2].ParameterType == typeof(Quaternion); }).MakeGenericMethod(typeof(GameObject)); private static void Prefix(SpawnArea __instance) { if (PluginSettingsFacade.IsSpawnerDomainEnabled()) { SpawnerManager.BeginSpawnAreaSpawnAttempt(__instance); } } [HarmonyTranspiler] private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Expected O, but got Unknown //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Expected O, but got Unknown CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null); val.MatchForward(false, (CodeMatch[])(object)new CodeMatch[1] { new CodeMatch((OpCode?)OpCodes.Call, (object)InstantiateGameObjectMethod, (string)null) }); if (!val.IsValid) { DropNSpawnPlugin.DropNSpawnLogger.LogError((object)"Failed to locate SpawnArea.SpawnOne instantiate call for faction tracking."); return instructions; } return val.Advance(1).InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1] { new CodeInstruction(OpCodes.Dup, (object)null) }).InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1] { new CodeInstruction(OpCodes.Ldarg_0, (object)null) }) .InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1] { new CodeInstruction(OpCodes.Call, Transpilers.EmitDelegate<Action<GameObject, SpawnArea>>((Action<GameObject, SpawnArea>)RecordSpawnedObject).operand) }) .InstructionEnumeration(); } private static void Postfix(SpawnArea __instance, bool __result) { if (PluginSettingsFacade.IsSpawnerDomainEnabled()) { SpawnerManager.FinalizeSpawnAreaSpawnAttempt(__instance, __result); } } private static void RecordSpawnedObject(GameObject spawnedObject, SpawnArea spawnArea) { SpawnerManager.RecordDirectSpawnAreaSpawnedObject(spawnArea, spawnedObject); } } [HarmonyPatch(typeof(CreatureSpawner), "Awake")] internal static class CreatureSpawnerAwakePatch { private static void Postfix(CreatureSpawner __instance) { SpawnerManager.HandleCreatureSpawnerInstanceAwake(__instance); } } [HarmonyPatch(typeof(CreatureSpawner), "OnDestroy")] internal static class CreatureSpawnerOnDestroyPatch { private static void Prefix(CreatureSpawner __instance) { SpawnerManager.UntrackCreatureSpawnerInstance(__instance); } } [HarmonyPatch(typeof(CreatureSpawner), "UpdateSpawner")] internal static class CreatureSpawnerUpdateSpawnerPatch { private static bool Prefix(CreatureSpawner __instance) { if (!PluginSettingsFacade.IsSpawnerDomainEnabled()) { return true; } if (SpawnerManager.ShouldBlockClientSpawnerUpdate()) { return false; } return SpawnerManager.PrepareCreatureSpawnerForUpdate(__instance); } } [HarmonyPatch(typeof(CreatureSpawner), "Spawn")] internal static class CreatureSpawnerSpawnPatch { private static bool Prefix(CreatureSpawner __instance, out ZDO? __state) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_004e: 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) __state = null; if (!PluginSettingsFacade.IsSpawnerDomainEnabled()) { return true; } if (!SpawnerManager.PrepareCreatureSpawnerSpawn(__instance, out __state)) { return false; } Vector3 position = ((Component)__instance).transform.position; float y = default(float); if ((Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.FindFloor(position, ref y)) { position.y = y; } SpawnerManager.InitializeCreatureSpawnerSpawnData(__instance, __instance.m_creaturePrefab, position); return true; } private static void Postfix(CreatureSpawner __instance, ZNetView __result, ZDO? __state, bool __runOriginal) { SpawnerManager.RecordCreatureSpawnerTotalSpawn(__state, __runOriginal && (Object)(object)__result != (Object)null && __result.IsValid()); if (PluginSettingsFacade.IsSpawnerDomainEnabled()) { SpawnerManager.ApplyCreatureSpawnerSpawnOverrides(__instance, __result); } } } [HarmonyPatch(typeof(Group), "SpawnWeighted")] internal static class CreatureSpawnerGroupSpawnPatch { private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Expected O, but got Unknown //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Expected O, but got Unknown //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Expected O, but got Unknown List<CodeInstruction> list = instructions.ToList(); MethodInfo add = AccessTools.Method(typeof(List<CreatureSpawner>), "Add", (Type[])null, (Type[])null); int num = list.FindIndex((CodeInstruction instruction) => CodeInstructionExtensions.Calls(instruction, add)); int num2 = num - 3; if (num2 < 1 || list[num2].opcode != OpCodes.Ldarg_0 || list[num2 + 1].opcode != OpCodes.Ldfld || !(list[num2 + 1].operand is FieldInfo fieldInfo) || fieldInfo.Name != "m_activeSpawners" || (list[num2 - 1].opcode != OpCodes.Brtrue && list[num2 - 1].opcode != OpCodes.Brtrue_S) || !(list[num2 - 1].operand is Label label)) { throw new InvalidOperationException("CreatureSpawner.Group.SpawnWeighted candidate/weight contract changed."); } CodeInstruction val = new CodeInstruction(list[num - 1].opcode, list[num - 1].operand); val.labels.AddRange(list[num2].labels); val.blocks.AddRange(list[num2].blocks); list[num2].labels.Clear(); list[num2].blocks.Clear(); list.InsertRange(num2, (IEnumerable<CodeInstruction>)(object)new CodeInstruction[3] { val, new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(SpawnerManager), "IsCreatureSpawnerGroupCandidate", (Type[])null, (Type[])null)), new CodeInstruction(OpCodes.Brfalse, (object)label) }); return list; } } [HarmonyPatch(typeof(BaseAI), "Awake")] internal static class BaseAIAwakeFactionPatch { private static void Postfix(BaseAI __instance) { FactionIntegration.ApplyFromZdo(__instance); } } [HarmonyPatch(typeof(SpawnSystem), "Awake")] [HarmonyPriority(0)] internal static class SpawnSystemAwakePatch { private static void Prefix(SpawnSystem __instance) { SpawnSystemManager.PreAttachCompiledTableToAwakeningSystem(__instance); } private static void Postfix(SpawnSystem __instance) { SpawnSystemManager.OnSpawnSystemAwake(__instance); } } [HarmonyPatch(typeof(SpawnSystem), "OnDestroy")] internal static class SpawnSystemOnDestroyPatch { private static void Prefix(SpawnSystem __instance) { SpawnSystemTimers.Detach(__instance); SpawnSystemManager.UntrackLiveSystem(__instance); } } [HarmonyPatch(typeof(SpawnSystem), "UpdateSpawnList", new Type[] { typeof(List<SpawnData>), typeof(DateTime), typeof(bool), typeof(string) })] internal static class SpawnSystemTimerPatch { private static bool Prefix(SpawnSystem __instance, List<SpawnData> spawners, bool eventSpawners, string groupSalt, ZNetView ___m_nview, out SpawnSystemTimers.ZoneState? __state) { return SpawnSystemTimers.Begin(__instance, spawners, eventSpawners, groupSalt, ___m_nview, out __state); } private static Exception? Finalizer(SpawnSystemTimers.ZoneState? __state, Exception? __exception) { try { SpawnSystemTimers.End(__state); return __exception; } catch (Exception ex) { DropNSpawnPlugin.DropNSpawnLogger.LogError((object)$"Failed to persist SpawnSystem timer batch: {ex}"); return __exception ?? ex; } } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod) { //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Expected O, but got Unknown //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Expected O, but got Unknown //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Expected O, but got Unknown //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Expected O, but got Unknown //IL_01ec: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Expected O, but got Unknown List<CodeInstruction> list = instructions.ToList(); LocalVariableInfo[] array = __originalMethod.GetMethodBody().LocalVariables.Where((LocalVariableInfo local) => local.LocalType == typeof(SpawnData)).ToArray(); MethodInfo get = AccessTools.Method(typeof(ZDO), "GetLong", new Type[2] { typeof(int), typeof(long) }, (Type[])null); MethodInfo set = AccessTools.Method(typeof(ZDO), "Set", new Type[2] { typeof(int), typeof(long) }, (Type[])null); if (array.Length != 1 || list.Count((CodeInstruction i) => CodeInstructionExtensions.Calls(i, get)) != 1 || list.Count((CodeInstruction i) => CodeInstructionExtensions.Calls(i, set)) != 1) { throw new InvalidOperationException("SpawnSystem.UpdateSpawnList timer contract changed; refusing a partial timer replacement."); } List<CodeInstruction> list2 = new List<CodeInstruction>(list.Count + 8); foreach (CodeInstruction item in list) { bool flag = CodeInstructionExtensions.Calls(item, get); if (!flag && !CodeInstructionExtensions.Calls(item, set)) { list2.Add(item); continue; } CodeInstruction val = new CodeInstruction(OpCodes.Ldarg_0, (object)null); val.labels.AddRange(item.labels); val.blocks.AddRange(item.blocks); list2.Add(val); list2.Add(new CodeInstruction(OpCodes.Ldloc, (object)array[0].LocalIndex)); list2.Add(new CodeInstruction(OpCodes.Ldarg_3, (object)null)); list2.Add(new CodeInstruction(OpCodes.Ldarg_S, (object)(byte)4)); list2.Add(new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(SpawnSystemTimers), flag ? "ReadTime" : "WriteTime", (Type[])null, (Type[])null))); } return list2; } } [HarmonyPatch(typeof(SpawnSystem), "UpdateSpawnList", new Type[] { typeof(List<SpawnData>), typeof(DateTime), typeof(bool), typeof(string) })] internal static class SpawnSystemSpawnLimitPatch { private static int CountForLimit(int existing, int allNew, SpawnData row, bool enabled, Dictionary<int, int>? recent, ref int groupCount) { if (!enabled) { return existing + allNew; } int value = 0; recent?.TryGetValue(StringExtensionMethods.GetStableHashCode(((Object)row.m_prefab).name), out value); groupCount = existing + value; return groupCount; } private static void RecordSpawn(SpawnData row, bool enabled, ref Dictionary<int, int>? recent) { if (enabled) { if (recent == null) { recent = new Dictionary<int, int>(); } int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)row.m_prefab).name); recent.TryGetValue(stableHashCode, out var value); recent[stableHashCode] = value + 1; } } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod, ILGenerator generator) { //IL_03bc: Unknown result type (might be due to invalid IL or missing references) //IL_03c6: Expected O, but got Unknown //IL_03cd: Unknown result type (might be due to invalid IL or missing references) //IL_03d7: Expected O, but got Unknown //IL_03de: Unknown result type (might be due to invalid IL or missing references) //IL_03e8: Expected O, but got Unknown //IL_03f4: Unknown result type (might be due to invalid IL or missing references) //IL_03fe: Expected O, but got Unknown //IL_041a: Unknown result type (might be due to invalid IL or missing references) //IL_0424: Expected O, but got Unknown //IL_042c: Unknown result type (might be due to invalid IL or missing references) //IL_0436: Expected O, but got Unknown //IL_043d: Unknown result type (might be due to invalid IL or missing references) //IL_0447: Expected O, but got Unknown //IL_044f: Unknown result type (might be due to invalid IL or missing references) //IL_0459: Expected O, but got Unknown //IL_046b: Unknown result type (might be due to invalid IL or missing references) //IL_0472: Expected O, but got Unknown //IL_0489: Unknown result type (might be due to invalid IL or missing references) //IL_0490: Expected O, but got Unknown //IL_04c8: Unknown result type (might be due to invalid IL or missing references) //IL_04d2: Expected O, but got Unknown //IL_04db: Unknown result type (might be due to invalid IL or missing references) //IL_04e5: Expected O, but got Unknown //IL_04f3: Unknown result type (might be due to invalid IL or missing references) //IL_04fd: Expected O, but got Unknown //IL_051a: Unknown result type (might be due to invalid IL or missing references) //IL_0524: Expected O, but got Unknown //IL_0543: Unknown result type (might be due to invalid IL or missing references) //IL_054d: Expected O, but got Unknown //IL_0556: Unknown result type (might be due to invalid IL or missing references) //IL_0560: Expected O, but got Unknown //IL_0569: Unknown result type (might be due to invalid IL or missing references) //IL_0573: Expected O, but got Unknown //IL_0590: Unknown result type (might be due to invalid IL or missing references) //IL_059a: Expected O, but got Unknown List<CodeInstruction> list = instructions.ToList(); MethodInfo count = AccessTools.Method(typeof(SpawnSystem), "GetNrOfZDOInstances", new Type[3] { typeof(GameObject), typeof(List<ZDO>), typeof(bool) }, (Type[])null); MethodInfo spawn = AccessTools.Method(typeof(SpawnSystem), "Spawn", new Type[3] { typeof(SpawnData), typeof(Vector3), typeof(bool) }, (Type[])null); FieldInfo fieldInfo = AccessTools.Field(typeof(SpawnData), "m_maxSpawned"); MethodBody methodBody = __originalMethod.GetMethodBody(); if (count == null || spawn == null || fieldInfo == null || methodBody == null) { return SkipCorrection(list); } int num = list.FindIndex((CodeInstruction i) => CodeInstructionExtensions.Calls(i, count)); int num2 = list.FindIndex((CodeInstruction i) => CodeInstructionExtensions.Calls(i, spawn)); int num3 = ((num >= 0 && num + 7 < list.Count) ? LocalIndex(list[num + 1], store: true) : (-1)); int num4 = ((num3 >= 0) ? LocalIndex(list[num + 3]) : (-1)); int num5 = ((num3 >= 0) ? LocalIndex(list[num + 5]) : (-1)); IList<LocalVariableInfo> locals = methodBody.LocalVariables; bool flag = num >= 0 && num2 > num + 7 && num2 + 4 < list.Count && list.Count((CodeInstruction i) => CodeInstructionExtensions.Calls(i, count)) == 1 && list.Count((CodeInstruction i) => CodeInstructionExtensions.Calls(i, spawn)) == 1 && LocalIs(num3, typeof(int)) && LocalIs(num4, typeof(int)) && num3 != num4 && LocalIs(num5, typeof(SpawnData)) && LocalIndex(list[num + 2]) == num3 && list[num + 4].opcode == OpCodes.Add && CodeInstructionExtensions.LoadsField(list[num + 6], fieldInfo, false) && (list[num + 7].opcode == OpCodes.Bge || list[num + 7].opcode == OpCodes.Bge_S) && LocalIndex(list[num2 + 1]) == num4 && list[num2 + 2].opcode == OpCodes.Ldc_I4_1 && list[num2 + 3].opcode == OpCodes.Add && LocalIndex(list[num2 + 4], store: true) == num4; if (flag) { int num6 = 0; for (int num7 = num + 8; num7 + 3 < num2; num7++) { if (LocalIndex(list[num7]) == num5 && CodeInstructionExtensions.LoadsField(list[num7 + 1], fieldInfo, false) && LocalIndex(list[num7 + 2]) == num3 && list[num7 + 3].opcode == OpCodes.Sub) { num6++; } } flag = num6 == 1; } if (!flag) { return SkipCorrection(list); } LocalBuilder localBuilder = generator.DeclareLocal(typeof(bool)); LocalBuilder localBuilder2 = generator.DeclareLocal(typeof(Dictionary<int, int>)); List<CodeInstruction> list2 = new List<CodeInstruction>(list.Count + 18) { new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Ldarg_1, (object)null), new CodeInstruction(OpCodes.Ldarg_3, (object)null), new CodeInstruction(OpCodes.Ldarg_S, (object)(byte)4), new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(SpawnSystemTimers), "IsManagedList", (Type[])null, (Type[])null)), new CodeInstruction(OpCodes.Stloc, (object)localBuilder), new CodeInstruction(OpCodes.Ldnull, (object)null), new CodeInstruction(OpCodes.Stloc, (object)localBuilder2) }; for (int num8 = 0; num8 < list.Count; num8++) { CodeInstruction val = new CodeInstruction(list[num8]); if (num8 == num + 4) { CodeInstruction val2 = new CodeInstruction(OpCodes.Ldloc, (object)num5); val2.labels.AddRange(val.labels); val2.blocks.AddRange(val.blocks); list2.Add(val2); list2.Add(new CodeInstruction(OpCodes.Ldloc, (object)localBuilder)); list2.Add(new CodeInstruction(OpCodes.Ldloc, (object)localBuilder2)); list2.Add(new CodeInstruction(OpCodes.Ldloca, (object)num3)); list2.Add(new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(SpawnSystemSpawnLimitPatch), "CountForLimit", (Type[])null, (Type[])null))); } else { list2.Add(val); if (num8 == num2) { list2.Add(new CodeInstruction(OpCodes.Ldloc, (object)num5)); list2.Add(new CodeInstruction(OpCodes.Ldloc, (object)localBuilder)); list2.Add(new CodeInstruction(OpCodes.Ldloca, (object)localBuilder2)); list2.Add(new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(SpawnSystemSpawnLimitPatch), "RecordSpawn", (Type[])null, (Type[])null))); } } } return list2; bool LocalIs(int index, Type type) { if (index >= 0 && index < locals.Count) { return locals[index].LocalType == type; } return false; } } private static IEnumerable<CodeInstruction> SkipCorrection(List<CodeInstruction> input) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)"Natural spawn limit correction skipped: UpdateSpawnList count/group contract changed. Existing spawn and timer behavior is unchanged."); return input; } private static int LocalIndex(CodeInstruction instruction, bool store = false) { OpCode opcode = instruction.opcode; if (opcode == (store ? OpCodes.Stloc_0 : OpCodes.Ldloc_0)) { return 0; } if (opcode == (store ? OpCodes.Stloc_1 : OpCodes.Ldloc_1)) { return 1; } if (opcode == (store ? OpCodes.Stloc_2 : OpCodes.Ldloc_2)) { return 2; } if (opcode == (store ? OpCodes.Stloc_3 : OpCodes.Ldloc_3)) { return 3; } if (opcode != (store ? OpCodes.Stloc : OpCodes.Ldloc) && opcode != (store ? OpCodes.Stloc_S : OpCodes.Ldloc_S)) { return -1; } object operand = instruction.operand; if (!(operand is LocalVariableInfo { LocalIndex: var localIndex })) { if (!(operand is int result)) { if (!(operand is short result2)) { if (operand is byte result3) { return result3; } return -1; } return result2; } return result; } return localIndex; } } [HarmonyPatch(typeof(SpawnSystem), "UpdateSpawning")] internal static class SpawnSystemUpdateSpawningRequiredGlobalKeyPatch { private static bool Prefix(SpawnSystem __instance, out bool __state) { __state = false; if (!PluginSettingsFacade.IsSpawnSystemDomainEnabled()) { return true; } if (SpawnSystemManager.ShouldBlockClientSpawnSystemUpdate(__instance)) { return false; } SpawnSystemManager.RefreshRuntimeTimeOfDayState(); __state = true; SpawnSystemManager.EnterRequiredGlobalKeyEvaluation(); return true; } private static Exception? Finalizer(bool __state, Exception? __exception) { if (__state) { SpawnSystemManager.ExitRequiredGlobalKeyEvaluation(); } return __exception; } } [HarmonyPatch(typeof(ZoneSystem), "GetGlobalKey", new Type[] { typeof(string) })] internal static class ZoneSystemGetGlobalKeyStringPatch { private static bool Prefix(ZoneSystem __instance, string name, ref bool __result) { if (!PluginSettingsFacade.IsSpawnSystemDomainEnabled()) { return true; } if (!SpawnSystemManager.TryEvaluateExtendedRequiredGlobalKey(__instance, name, out var result)) { return true; } __result = result; return false; } } [HarmonyPatch(typeof(ZoneSystem), "RPC_SetGlobalKey")] internal static class ZoneSystemRpcSetGlobalKeyPatch { private static void Prefix(ZoneSystem __instance, ref string name) { if (DropNSpawnPlugin.IsSourceOfTruth && PluginSettingsFacade.IsSpawnSystemDomainEnabled() && SpawnSystemManager.TryRewriteExtendedGlobalKeyMutation(__instance, name, out string rewrittenValue)) { name = rewrittenValue; } } } [HarmonyPatch(typeof(SpawnSystem), "Spawn")] internal static class SpawnSystemSpawnPatch { private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Expected O, but got Unknown //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Expected O, but got Unknown List<CodeInstruction> list = instructions.ToList(); int num = list.FindIndex((CodeInstruction instruction) => instruction.opcode == OpCodes.Call && instruction.operand is MethodInfo methodInfo && methodInfo.DeclaringType == typeof(Object) && methodInfo.Name == "Instantiate" && methodInfo.IsGenericMethod && methodInfo.GetGenericArguments().SequenceEqual(new Type[1] { typeof(GameObject) }) && (from parameter in methodInfo.GetParameters() select parameter.ParameterType).SequenceEqual(new Type[3] { typeof(GameObject), typeof(Vector3), typeof(Quaternion) })); if (num < 0) { throw new InvalidOperationException("SpawnSystem.Spawn instantiate contract changed; cannot preserve standalone faction overrides."); } list.InsertRange(num + 1, (IEnumerable<CodeInstruction>)(object)new CodeInstruction[3] { new CodeInstruction(OpCodes.Dup, (object)null), new CodeInstruction(OpCodes.Ldarg_1, (object)null), new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(SpawnSystemCustomDataSupport), "ApplyStandaloneFaction", (Type[])null, (Type[])null)) }); return list; } private static void Prefix(SpawnData critter, Vector3 spawnPoint, out bool __state) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) __state = false; if (PluginSettingsFacade.IsSpawnSystemDomainEnabled() || SpawnSystemCustomDataSupport.HasPreparedPayload(critter) || ExpandWorldDataCompatibility.HasAltBiomeKeyConsumer(critter)) { __state = true; SpawnSystemCustomDataSupport.InitializeSpawn(critter, spawnPoint); } } private static void Postfix(SpawnData critter, Vector3 spawnPoint, bool __state) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) if (__state) { if (!ExpandWorldDataCompatibility.ConsumeAltBiomeKeys(critter) && PluginSettingsFacade.IsSpawnSystemDomainEnabled()) { SpawnSystemManager.ConsumeExtendedRequiredGlobalKeyAfterSpawn(critter); } SpawnSystemCustomDataSupport.SpawnObjects(critter, spawnPoint); } } } internal static class GeneratedFileWriter { internal static bool WriteAllTextIfChanged(string path, string content) { if (path == null) { throw new ArgumentNullException("path"); } if (content == null) { content = ""; } string directoryName = Path.GetDirectoryName(path); if (!string.IsNullOrEmpty(directoryName)) { Directory.CreateDirectory(directoryName); } if (File.Exists(path) && string.Equals(File.ReadAllText(path), content, StringComparison.Ordinal)) { return false; } File.WriteAllText(path, content); return true; } } internal static class GeneratedArtifactWriter { internal static bool WriteText(string path, string content, string? logMessage = null, bool logOnlyWhenChanged = false) { bool flag = GeneratedFileWriter.WriteAllTextIfChanged(path, content); if (!string.IsNullOrWhiteSpace(logMessage) && (!logOnlyWhenChanged || flag)) { DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)logMessage); } return flag; } internal static void WriteTextAlways(string path, string content, string? logMessage = null) { string directoryName = Path.GetDirectoryName(path); if (!string.IsNullOrWhiteSpace(directoryName)) { Directory.CreateDirectory(directoryName); } File.WriteAllText(path, content ?? ""); if (!string.IsNullOrWhiteSpace(logMessage)) { DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)logMessage); } } } internal static class ReferenceRefreshSupport { internal sealed class LocationReferenceScan { private readonly HashSet<AssetID>? _excludedAssets; internal string Signature { get; } internal unsafe LocationReferenceScan(HashSet<AssetID>? excludedAssets) { _excludedAssets = excludedAssets; string[] first = new string[1] { "# DropNSpawn location scan: automatic-mwl-excluded-v1" }; IEnumerable<string> second; if (excludedAssets != null) { second = excludedAssets.Select((AssetID id) => ((object)(*(AssetID*)(&id))/*cast due to .constrained prefix*/).ToString()); } else { IEnumerable<string> enumerable = new string[1] { "all-locations-deferred" }; second = enumerable; } Signature = ComputeStableHashForKeys(first.Concat(second)); } internal bool ShouldSkip(AssetID assetId) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) if (_excludedAssets != null) { return _excludedAssets.Contains(assetId); } return true; } internal string Annotate(string content) { return "# DropNSpawn location scan: automatic-mwl-excluded-v1" + Environment.NewLine + ((_excludedAssets == null) ? "# Location interiors were not scanned because the MWL manifest could not be read." : "# MWL location interiors were not scanned; registered prefab references are still included.") + Environment.NewLine + "# Explicit dns:reference object/spawner exports include all locations and can be expensive." + Environment.NewLine + content; } } internal const string CurrentReferenceLogicVersion = "2026-03-26-full-rewrite-v1"; internal const string MoreWorldLocationsGuid = "warpalicious.More_World_Locations_AIO"; internal const string PartialLocationReferenceHeader = "# DropNSpawn location scan: automatic-mwl-excluded-v1"; internal static LocationReferenceScan? CreateAutomaticLocationScan() { if (!Chainloader.PluginInfos.TryGetValue("warpalicious.More_World_Locations_AIO", out var value)) { return null; } try { string text = Directory.EnumerateFiles(Path.GetDirectoryName(value.Location)).FirstOrDefault((string file) => string.Equals(Path.GetFileName(file), "assetBundleManifest_full", StringComparison.OrdinalIgnoreCase)); AssetBundleManifest val = ((text == null) ? null : AssetBundleManifest.DeserializeFromDisk(text)); if (val != null && val.AssetCount != 0) { return new LocationReferenceScan(val.m_assetToLocationMap.Keys.ToHashSet()); } } catch (Exception ex) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("Could not read MWL reference-scan metadata: " + ex.Message)); } DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)"MWL manifest unavailable: automatic location-interior references are deferred; registered prefab references and override rules remain available."); return new LocationReferenceScan(null); } internal static IEnumerable<(string LocationPrefab, GameObject RootPrefab)> EnumerateLocationRootPrefabs(LocationReferenceScan? scan = null) { if ((Object)(object)ZoneSystem.instance == (Object)null) { yield break; } HashSet<string> seen = new HashSet<string>(StringComparer.OrdinalIgnoreCase); foreach (ZoneLocation location in ZoneSystem.instance.m_locations) { SoftReference<GameObject> prefab = location.m_prefab; if (!prefab.IsValid || (scan?.ShouldSkip(prefab.m_assetID) ?? false)) { continue; } string text = (prefab.Name ?? "").Trim(); if (text.Length == 0 || !seen.Add(text)) { continue; } try { if ((int)prefab.Load() == 0) { GameObject asset = prefab.Asset; if ((Object)(object)asset != (Object)null) { yield return (LocationPrefab: text, RootPrefab: asset); } } } finally { prefab.Release(); } } } internal static void WarnBeforeFullLocationScan() { if (Chainloader.PluginInfos.ContainsKey("warpalicious.More_World_Locations_AIO")) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)"Explicit full location reference export includes MWL interiors. This can take minutes and use substantial memory on low-memory systems."); } } internal static string ComputeStableHashForKeys(IEnumerable<string?> keys) { StringBuilder stringBuilder = new StringBuilder(); foreach (string item in (from key in (keys ?? Enumerable.Empty<string>()).Select(NormalizeKey) where key.Length > 0 select key).OrderBy<string, string>((string key) => key, StringComparer.OrdinalIgnoreCase)) { stringBuilder.AppendLine(item); } return ComputeStableHash(stringBuilder.ToString()); } internal static string SerializeReferenceSections<T>(IEnumerable<T> entries, Func<T, string> getPrefabName, ISerializer serializer) { return PrefabOutputSections.SerializeReferenceSections(PrefabOutputSections.BuildSections(entries ?? Enumerable.Empty<T>(), getPrefabName), serializer); } internal static HashSet<string> ToNormalizedKeySet(IEnumerable<string?> keys) { HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); foreach (string item in keys ?? Enumerable.Empty<string>()) { string text = NormalizeKey(item); if (text.Length > 0) { hashSet.Add(text); } } return hashSet; } internal static string NormalizeKey(string? key) { return (key ?? "").Trim(); } internal static bool ShouldSkipAutoUpdate(string stateKey, string referencePath, string sourceSignature, string? logicVersion = null) { if (string.IsNullOrWhiteSpace(stateKey) || string.IsNullOrWhiteSpace(referencePath) || string.IsNullOrWhiteSpace(sourceSignature) || !File.Exists(referencePath)) { return false; } string autoUpdateStatePath = GetAutoUpdateStatePath(stateKey); if (!File.Exists(autoUpdateStatePath)) { return false; } try { string text = (logicVersion ?? "").Trim(); string[] array = File.ReadAllLines(autoUpdateStatePath); if (array.Length < 2) { return false; } string a = (array[0] ?? "").Trim(); string a2 = (array[1] ?? "").Trim(); string a3 = ((array.Length >= 4) ? (array[3] ?? "").Trim() : ""); if (text.Length > 0 && !string.Equals(a3, text, StringComparison.Ordinal)) { return false; } return string.Equals(a, sourceSignature, StringComparison.Ordinal) && string.Equals(a2, BuildReferenceFileStamp(referencePath), StringComparison.Ordinal); } catch { return false; } } internal static void RecordAutoUpdateState(string stateKey, string referencePath, string sourceSignature, string? precheckSignature = null, string? logicVersion = null) { if (!string.IsNullOrWhiteSpace(stateKey) && !string.IsNullOrWhiteSpace(referencePath) && !string.IsNullOrWhiteSpace(sourceSignature) && File.Exists(referencePath)) { string autoUpdateStatePath = GetAutoUpdateStatePath(stateKey); string content = sourceSignature.Trim() + Environment.NewLine + BuildReferenceFileStamp(referencePath) + Environment.NewLine + (precheckSignature ?? "").Trim() + Environment.NewLine + (logicVersion ?? "").Trim() + Environment.NewLine; GeneratedFileWriter.WriteAllTextIfChanged(autoUpdateStatePath, content); } } internal static string ComputeStableHash(string? value) { using SHA256 sHA = SHA256.Create(); byte[] bytes = Encoding.UTF8.GetBytes(value ?? ""); byte[] array = sHA.ComputeHash(bytes); StringBuilder stringBuilder = new StringBuilder(array.Length * 2); byte[] array2 = array; foreach (byte b in array2) { stringBuilder.Append(b.ToString("x2")); } return stringBuilder.ToString(); } private static string GetAutoUpdateStatePath(string stateKey) { string text = SanitizeFileName(stateKey); return Path.Combine(GetAutoUpdateStateDirectoryPath(), ".reference-state." + text + ".txt"); } private static string GetAutoUpdateStateDirectoryPath() { return Path.Combine(DropNSpawnPlugin.YamlConfigDirectoryPath, "cache"); } private static string BuildReferenceFileStamp(string referencePath) { FileInfo fileInfo = new FileInfo(referencePath); return $"{fileInfo.Length}:{fileInfo.LastWriteTimeUtc.Ticks}"; } private static string SanitizeFileName(string value) { StringBuilder stringBuilder = new StringBuilder(value.Length); HashSet<char> hashSet = Path.GetInvalidFileNameChars().ToHashSet(); foreach (char c in value) { stringBuilder.Append(hashSet.Contains(c) ? '_' : c); } return stringBuilder.ToString(); } } internal enum ReferenceArtifactUpdateKind { None, Created, Updated } internal static class ReferenceArtifactLifecycle { internal static bool TryPlanUpdate(string stateKey, string referencePath, string sourceSignature, out ReferenceArtifactUpdateKind updateKind, string? requiredExistingHeader = null) { updateKind = ReferenceArtifactUpdateKind.None; if (!File.Exists(referencePath)) { updateKind = ReferenceArtifactUpdateKind.Created; return true; } if (requiredExistingHeader != null && !HasHeader(referencePath, requiredExistingHeader)) { DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)("Preserved existing reference at " + referencePath + ": automatic MWL location scanning is restricted. Use dns:reference for an explicit full refresh.")); return false; } if (ReferenceRefreshSupport.ShouldSkipAutoUpdate(stateKey, referencePath, sourceSignature, "2026-03-26-full-rewrite-v1")) { return false; } updateKind = ReferenceArtifactUpdateKind.Updated; return true; } internal static void RecordUpdate(string stateKey, string referencePath, string sourceSignature) { ReferenceRefreshSupport.RecordAutoUpdateState(stateKey, referencePath, sourceSignature, null, "2026-03-26-full-rewrite-v1"); } private static bool HasHeader(string path, string header) { using StreamReader streamReader = File.OpenText(path); return string.Equals(streamReader.ReadLine(), header, StringComparison.Ordinal); } internal static string FormatAction(ReferenceArtifactUpdateKind updateKind) { if (updateKind != ReferenceArtifactUpdateKind.Created) { return "Updated"; } return "Created"; } } internal sealed class CharacterDropPrefabEntry { [YamlMember(Order = 1)] public string Prefab { get; set; } = ""; [YamlMember(Order = 2)] public bool Enabled { get; set; } = true; [YamlMember(Order = 3)] public ConditionsDefinition? Conditions { get; set; } [YamlMember(Order = 4)] public CharacterDropDefinition? CharacterDrop { get; set; } [YamlIgnore] public string RuleId { get; set; } = ""; [YamlIgnore] public string? SourcePath { get; set; } [YamlIgnore] public int SourceLine { get; set; } [YamlIgnore] public int SourceColumn { get; set; } } internal sealed class CharacterDropReferenceEntry { [YamlMember(Order = 1)] public string Prefab { get; set; } = ""; [YamlMember(Order = 2)] public CharacterDropDefinition? CharacterDrop { get; set; } } internal sealed class CharacterDropDefinition { [YamlMember(Order = 1)] public List<CharacterDropEntryDefinition>? Drops { get; set; } } internal sealed class CharacterDropEntryDefinition { [YamlMember(Order = 1)] public string Item { get; set; } = ""; [YamlMember(Order = 2)] public IntRangeDefinition? Amount { get; set; } [YamlIgnore] public int? AmountMin { get; set; } [YamlIgnore] public int? AmountMax { get; set; } [YamlMember(Order = 3)] public float? Chance { get; set; } [YamlMember(Order = 4)] public bool? DontScale { get; set; } [YamlMember(Order = 5)] public bool? LevelMultiplier { get; set; } [YamlMember(Order = 6)] public bool? LevelMultiplierNotAmount { get; set; } [YamlMember(Order = 7)] public bool? OnePerPlayer { get; set; } [YamlMember(Order = 8)] public int? AmountLimit { get; set; } [YamlMember(Order = 9)] public bool? DropInStack { get; set; } } internal sealed class CompiledCharacterDropDefinition { public string Fingerprint { get; set; } = ""; public GameObject Prefab { get; set; } public int AmountMin { get; set; } public int AmountMax { get; set; } public float Chance { get; set; } public bool DontScale { get; set; } public bool LevelMultiplier { get; set; } public bool? LevelMultiplierOverride { get; set; } public bool LevelMultiplierNotAmount { get; set; } public bool OnePerPlayer { get; set; } public int? AmountLimit { get; set; } public bool? DropInStack { get; set; } } internal sealed class CompiledCharacterDropRule { public CharacterDropPrefabEntry Entry { get; set; } public List<CompiledCharacterDropDefinition> Drops { get; } = new List<CompiledCharacterDropDefinition>(); } internal sealed class CachedCharacterRuntimeDropResolution { public bool HasMatchedRuntimeRule { get; set; } public CompiledCharacterDropDefinition[] Definitions { get; set; } = Array.Empty<CompiledCharacterDropDefinition>(); public List<Drop>? OverrideDrops { get; set; } public bool HasCustomDropHandling { get; set; } } internal sealed class CharacterRuntimeDropCacheState { public bool IsCacheable { get; set; } = true; public bool UsesLevel { get; set; } public bool UsesFaction { get; set; } public bool UsesState { get; set; } public bool UsesTimeOfDay { get; set; } public bool UsesRequiredEnvironments { get; set; } public bool UsesInsidePlayerBase { get; set; } public string[] RequiredGlobalKeys { get; set; } = Array.Empty<string>(); public string[] ForbiddenGlobalKeys { get; set; } = Array.Empty<string>(); public Dictionary<int, CachedCharacterRuntimeDropResolution> ResolutionsBySignature { get; } = new Dictionary<int, CachedCharacterRuntimeDropResolution>(); } internal sealed class CharacterCompiledState { public static CharacterCompiledState Empty { get; } = new CharacterCompiledState(); public Dictionary<string, List<CompiledCharacterDropRule>> RuntimeRulesByPrefab { get; } = new Dictionary<string, List<CompiledCharacterDropRule>>(StringComparer.OrdinalIgnoreCase); public Dictionary<string, CharacterRuntimeDropCacheState> RuntimeDropCachesByPrefab { get; } = new Dictionary<string, CharacterRuntimeDropCacheState>(StringComparer.OrdinalIgnoreCase); public Dictionary<string, List<CompiledCharacterDropDefinition>> StaticDropsByPrefab { get; } = new Dictionary<string, List<CompiledCharacterDropDefinition>>(StringComparer.OrdinalIgnoreCase); public Dictionary<string, List<Drop>> StaticBuiltDropsByPrefab { get; } = new Dictionary<string, List<Drop>>(StringComparer.OrdinalIgnoreCase); } internal sealed class CharacterDropSnapshot { public GameObject Prefab { get; set; } public List<Drop> BuiltDrops { get; set; } = new List<Drop>(); } internal sealed class PendingCharacterDropSnapshotBuildState { public int GameDataSignature { get; set; } public int SnapshotSignature { get; set; } public string Source { get; set; } = ""; public List<GameObject> Prefabs { get; } = new List<GameObject>(); public List<CharacterDropSnapshot> Snapshots { get; } = new List<CharacterDropSnapshot>(); public Dictionary<string, CharacterDropSnapshot> SnapshotsByPrefab { get; } = new Dictionary<string, CharacterDropSnapshot>(StringComparer.OrdinalIgnoreCase); public int NextIndex { get; set; } } internal static class CharacterDropRuntime { private static readonly List<CharacterDropSnapshot> Snapshots = new List<CharacterDropSnapshot>(); private static readonly Dictionary<string, CharacterDropSnapshot> SnapshotsByPrefab = new Dictionary<string, CharacterDropSnapshot>(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary<string, HashSet<CharacterDrop>> LiveCharacterDropsByPrefab = new Dictionary<string, HashSet<CharacterDrop>>(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary<CharacterDrop, string> LiveCharacterDropPrefabsByInstance = new Dictionary<CharacterDrop, string>(); private static int? _lastProcessedSnapshotSignature; private static int? _lastProcessedGameDataSignature; private static int? _lastBootstrappedLiveObjectsSceneSignature; private static PendingCharacterDropSnapshotBuildState? _pendingSnapshotBuild; internal static void Reset() { Snapshots.Clear(); SnapshotsByPrefab.Clear(); LiveCharacterDropsByPrefab.Clear(); LiveCharacterDropPrefabsByInstance.Clear(); _lastProcessedSnapshotSignature = null; _lastProcessedGameDataSignature = null; _lastBootstrappedLiveObjectsSceneSignature = null; _pendingSnapshotBuild = null; } internal static bool HasSnapshots() { return Snapshots.Count > 0; } internal static IReadOnlyList<CharacterDropSnapshot> GetSnapshots() { return Snapshots; } internal static bool HasSnapshot(string prefabName) { if (!string.IsNullOrWhiteSpace(prefabName)) { return SnapshotsByPrefab.ContainsKey(prefabName); } return false; } internal static bool TryGetSnapshot(string prefabName, out CharacterDropSnapshot? snapshot) { return SnapshotsByPrefab.TryGetValue(prefabName ?? "", out snapshot); } internal static bool IsGameDataAlreadyProcessed(int gameDataSignature) { return _lastProcessedGameDataSignature == gameDataSignature; } internal static bool NeedsSnapshotBuild(int snapshotSignature) { if (_lastProcessedSnapshotSignature == snapshotSignature) { return Snapshots.Count == 0; } return true; } internal static void ScheduleSnapshotBuild(string source, int gameDataSignature, int snapshotSignature, IEnumerable<GameObject> prefabs) { if (_pendingSnapshotBuild == null || _pendingSnapshotBuild.GameDataSignature != gameDataSignature || _pendingSnapshotBuild.SnapshotSignature != snapshotSignature) { PendingCharacterDropSnapshotBuildState pendingCharacterDropSnapshotBuildState = new PendingCharacterDropSnapshotBuildState(); pendingCharacterDropSnapshotBuildState.GameDataSignature = gameDataSignature; pendingCharacterDropSnapshotBuildState.SnapshotSignature = snapshotSignature; pendingCharacterDropSnapshotBuildState.Source = source; pendingCharacterDropSnapshotBuildState.Prefabs.AddRange(prefabs); _pendingSnapshotBuild = pendingCharacterDropSnapshotBuildState; } } internal static bool HasPendingSnapshotBuildWork() { return _pendingSnapshotBuild != null; } internal static bool ProcessPendingSnapshotBuildStep(double deadline, Func<GameObject, CharacterDropSnapshot?> captureSnapshot, Action<string, int, int> onCompleted) { PendingCharacterDropSnapshotBuildState pendingSnapshotBuild = _pendingSnapshotBuild; if (pendingSnapshotBuild == null) { return false; } if (pendingSnapshotBuild.NextIndex >= pendingSnapshotBuild.Prefabs.Count) { CompletePendingSnapshotBuild(pendingSnapshotBuild, onCompleted); return true; } GameObject val = pendingSnapshotBuild.Prefabs[pendingSnapshotBuild.NextIndex]; pendingSnapshotBuild.NextIndex++; CharacterDropSnapshot characterDropSnapshot = (((Object)(object)val != (Object)null) ? captureSnapshot(val) : null); if (_pendingSnapshotBuild == null || _pendingSnapshotBuild != pendingSnapshotBuild) { return true; } if (characterDropSnapshot != null) { pendingSnapshotBuild.Snapshots.Add(characterDropSnapshot); if (!pendingSnapshotBuild.SnapshotsByPrefab.ContainsKey(((Object)characterDropSnapshot.Prefab).name)) { pendingSnapshotBuild.SnapshotsByPrefab.Add(((Object)characterDropSnapshot.Prefab).name, characterDropSnapshot); } } if (pendingSnapshotBuild.NextIndex >= pendingSnapshotBuild.Prefabs.Count && Time.realtimeSinceStartupAsDouble <= deadline) { CompletePendingSnapshotBuild(pendingSnapshotBuild, onCompleted); } return true; } internal static void CaptureSnapshotsIfNeeded(IEnumerable<GameObject> prefabs, Func<GameObject, CharacterDropSnapshot?> captureSnapshot) { if (Snapshots.Count > 0) { return; } foreach (GameObject prefab in prefabs) { CharacterDropSnapshot characterDropSnapshot = captureSnapshot(prefab); if (characterDropSnapshot != null) { Snapshots.Add(characterDropSnapshot); if (!SnapshotsByPrefab.ContainsKey(((Object)characterDropSnapshot.Prefab).name)) { SnapshotsByPrefab.Add(((Object)characterDropSnapshot.Prefab).name, characterDropSnapshot); } } } } internal static void RegisterLiveCharacterDrop(CharacterDrop characterDrop, string prefabName) { if ((Object)(object)characterDrop == (Object)null || string.IsNullOrWhiteSpace(prefabName)) { return; } if (LiveCharacterDropPrefabsByInstance.TryGetValue(characterDrop, out string value)) { if (string.Equals(value, prefabName, StringComparison.OrdinalIgnoreCase)) { return; } UnregisterLiveCharacterDrop(characterDrop, value); } LiveCharacterDropPrefabsByInstance[characterDrop] = prefabName; if (!LiveCharacterDropsByPrefab.TryGetValue(prefabName, out HashSet<CharacterDrop> value2)) { value2 = new HashSet<CharacterDrop>(); LiveCharacterDropsByPrefab[prefabName] = value2; } value2.Add(characterDrop); } internal static bool TryGetRegisteredPrefabName(CharacterDrop characterDrop, out string prefabName) { return LiveCharacterDropPrefabsByInstance.TryGetValue(characterDrop, out prefabName); } internal static void UnregisterLiveCharacterDrop(CharacterDrop characterDrop, string prefabName) { LiveCharacterDropPrefabsByInstance.Remove(characterDrop); if (LiveCharacterDropsByPrefab.TryGetValue(prefabName, out HashSet<CharacterDrop> value)) { value.Remove(characterDrop); if (value.Count == 0) { LiveCharacterDropsByPrefab.Remove(prefabName); } } } internal static void BootstrapRegisteredCharacterDropsIfNeeded(int sceneSignature, IEnumerabl