Please disclose if your mod was created primarily 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.0.4
DropNSpawn.dll
Decompiled 11 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.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 ExpandWorldData; using HarmonyLib; using JetBrains.Annotations; using Microsoft.CodeAnalysis; using ServerSync; using Service; using TMPro; using UnityEngine; 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.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [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.0.4")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.4.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.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] [Microsoft.CodeAnalysis.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] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.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 { public ExtensionMarkerAttribute(string name) { } } } namespace LocalizationManager { [PublicAPI] public class Localizer { 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_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: 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())); } localization.AddWord(key, text); } public static void AddPlaceholder<T>(string key, string placeholder, ConfigEntry<T> config, Func<T, string>? convertConfigValue = null) where T : notnull { string key2 = key; string placeholder2 = placeholder; Func<T, string> convertConfigValue2 = convertConfigValue; ConfigEntry<T> config2 = config; if (convertConfigValue2 == null) { convertConfigValue2 = (T val) => val.ToString(); } if (!PlaceholderProcessors.ContainsKey(key2)) { PlaceholderProcessors[key2] = new Dictionary<string, Func<string>>(); } config2.SettingChanged += delegate { UpdatePlaceholder(); }; if (loadedTexts.ContainsKey(Localization.instance.GetSelectedLanguage())) { UpdatePlaceholder(); } void UpdatePlaceholder() { PlaceholderProcessors[key2][placeholder2] = () => convertConfigValue2(config2.Value); UpdatePlaceholderText(Localization.instance, key2); } } 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 (!target.m_translations.ContainsKey(key)) { dictionary[key] = text; target.AddWord(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_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Expected O, but got Unknown //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Expected O, but got Unknown //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Expected O, but got Unknown 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) { string resourceFileName2 = resourceFileName; using MemoryStream memoryStream = new MemoryStream(); if ((object)containingAssembly == null) { containingAssembly = Assembly.GetCallingAssembly(); } string text = containingAssembly.GetManifestResourceNames().FirstOrDefault((string str) => str.EndsWith(resourceFileName2, 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 { internal sealed class CllcDefinition { [YamlMember(Order = 1)] public string? Infusion { get; set; } [YamlMember(Order = 2)] public string? ExtraEffect { get; set; } [YamlMember(Order = 3)] public string? BossAffix { get; set; } internal bool HasValues() { return HasAnyValues(); } internal bool HasAnyValues() { return HasModifierValues(); } internal bool HasModifierValues() { return !string.IsNullOrWhiteSpace(Infusion) || !string.IsNullOrWhiteSpace(ExtraEffect) || !string.IsNullOrWhiteSpace(BossAffix); } internal void Normalize() { Infusion = NormalizeOptionalString(Infusion); ExtraEffect = NormalizeOptionalString(ExtraEffect); BossAffix = NormalizeOptionalString(BossAffix); } private static string? NormalizeOptionalString(string? value) { string text = (value ?? "").Trim(); return (text.Length > 0) ? text : null; } } internal static class CllcIntegration { private static readonly object Sync = new object(); private static readonly HashSet<string> WarningCache = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private static bool _resolved; private static Type? _apiType; private static MethodInfo? _getWorldLevelMethod; private static MethodInfo? _isEnabledMethod; private static MethodInfo? _isInfusionEnabledMethod; private static MethodInfo? _isExtraEffectEnabledMethod; private static MethodInfo? _isAffixEnabledMethod; private static MethodInfo? _getInfusionMethod; private static MethodInfo? _getExtraEffectMethod; private static MethodInfo? _getBossAffixMethod; private static MethodInfo? _setInfusionMethod; private static MethodInfo? _setExtraEffectMethod; private static MethodInfo? _setBossAffixMethod; private static Type? _infusionEnumType; private static Type? _extraEffectEnumType; private static Type? _bossAffixEnumType; private static readonly List<Character> CharacterBuffer = new List<Character>(); internal static bool AreWorldLevelConditionsSatisfied(int? minWorldLevel, int? maxWorldLevel) { if (!minWorldLevel.HasValue && !maxWorldLevel.HasValue) { return true; } if (!TryGetWorldLevel(out var worldLevel)) { WarnOnce("cllc-conditions-missing", "CLLC world-level conditions require CreatureLevelControl. The condition was treated as not satisfied."); return false; } if (minWorldLevel.HasValue && worldLevel < minWorldLevel.Value) { return false; } if (maxWorldLevel.HasValue && worldLevel > maxWorldLevel.Value) { return false; } return true; } internal static bool TryGetWorldLevel(out int worldLevel) { worldLevel = 0; lock (Sync) { if (!TryResolveApi()) { return false; } try { if (_isEnabledMethod?.Invoke(null, null) is bool flag && !flag) { return false; } object obj = _getWorldLevelMethod?.Invoke(null, null); if (obj is int) { int num = (int)obj; if (true) { worldLevel = num; return true; } } } catch (Exception ex) { WarnOnce("cllc-world-level-error", "Failed to query CreatureLevelControl world level. " + ex.Message); } return false; } } internal static bool TryGetInfusion(Character? character, out string infusion) { return TryGetEnumValue(character, _isInfusionEnabledMethod, _getInfusionMethod, "infusion", out infusion); } internal static bool TryGetExtraEffect(Character? character, out string effect) { return TryGetEnumValue(character, _isExtraEffectEnabledMethod, _getExtraEffectMethod, "extraEffect", out effect); } internal static bool TryGetBossAffix(Character? character, out string bossAffix) { return TryGetEnumValue(character, _isAffixEnabledMethod, _getBossAffixMethod, "bossAffix", out bossAffix); } internal static void Apply(Character? character, CllcDefinition? definition, string context) { if ((Object)(object)character == (Object)null || definition == null || !definition.HasModifierValues()) { return; } lock (Sync) { if (!TryResolveApi()) { WarnOnce("cllc-missing:" + context, "Entry '" + context + "' uses cllc, but CreatureLevelControl is not loaded. The cllc block was ignored."); return; } ZNetView component = ((Component)character).GetComponent<ZNetView>(); if (((component != null) ? component.GetZDO() : null) == null) { WarnOnce("cllc-zdo:" + context, "Entry '" + context + "' tried to apply cllc before the spawned character ZDO was ready. The cllc block was ignored."); return; } if (!string.IsNullOrWhiteSpace(definition.Infusion)) { ApplyEnumEffect(character, definition.Infusion, context, _isInfusionEnabledMethod, _setInfusionMethod, _infusionEnumType, "infusion"); } bool flag = !string.IsNullOrWhiteSpace(definition.BossAffix); bool flag2 = !string.IsNullOrWhiteSpace(definition.ExtraEffect); if (flag && flag2) { WarnOnce("cllc-effect-conflict:" + context, "Entry '" + context + "' configured both cllc.extraEffect and cllc.bossAffix. bossAffix takes priority because both use the same CreatureLevelControl effect slot."); } if (flag) { if (!character.IsBoss()) { WarnOnce("cllc-boss-affix-nonboss:" + context, "Entry '" + context + "' configured cllc.bossAffix for a non-boss character. The boss affix was ignored."); } else { ApplyEnumEffect(character, definition.BossAffix, context, _isAffixEnabledMethod, _setBossAffixMethod, _bossAffixEnumType, "bossAffix"); } } else if (flag2) { ApplyEnumEffect(character, definition.ExtraEffect, context, _isExtraEffectEnabledMethod, _setExtraEffectMethod, _extraEffectEnumType, "extraEffect"); } } } internal static HashSet<int> CaptureNearbyCharacterIds(Vector3 point, float radius) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) CharacterBuffer.Clear(); Character.GetCharactersInRange(point, radius, CharacterBuffer); return (from character in CharacterBuffer where (Object)(object)character != (Object)null select ((Object)character).GetInstanceID()).ToHashSet(); } internal static Character? FindNewCharacter(Vector3 point, float radius, HashSet<int>? existingCharacterIds, GameObject? expectedPrefab = null) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) CharacterBuffer.Clear(); Character.GetCharactersInRange(point, radius, CharacterBuffer); Character result = null; float num = float.MaxValue; foreach (Character item in CharacterBuffer) { if (!((Object)(object)item == (Object)null) && (existingCharacterIds == null || !existingCharacterIds.Contains(((Object)item).GetInstanceID())) && MatchesExpectedPrefab(item, expectedPrefab)) { Vector3 val = ((Component)item).transform.position - point; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (!(sqrMagnitude >= num)) { num = sqrMagnitude; result = item; } } } return result; } private static bool MatchesExpectedPrefab(Character character, GameObject? expectedPrefab) { if ((Object)(object)expectedPrefab == (Object)null) { return true; } string text = NormalizePrefabName(((Object)expectedPrefab).name); if (text.Length == 0) { return true; } string text2 = ResolveCharacterPrefabName(character); return text2.Length > 0 && string.Equals(text2, text, StringComparison.OrdinalIgnoreCase); } private static string ResolveCharacterPrefabName(Character character) { if ((Object)(object)character == (Object)null) { return ""; } ZNetView component = ((Component)character).GetComponent<ZNetView>(); ZDO val = ((component != null) ? component.GetZDO() : null); if (val != null && (Object)(object)ZNetScene.instance != (Object)null) { GameObject prefab = ZNetScene.instance.GetPrefab(val.GetPrefab()); if ((Object)(object)prefab != (Object)null) { return NormalizePrefabName(((Object)prefab).name); } } string prefabName = Utils.GetPrefabName(((Component)character).gameObject); if (!string.IsNullOrWhiteSpace(prefabName)) { return NormalizePrefabName(prefabName); } return NormalizePrefabName(((Object)((Component)character).gameObject).name); } private static string NormalizePrefabName(string? rawName) { string text = (rawName ?? "").Trim(); if (text.EndsWith("(Clone)", StringComparison.Ordinal)) { string text2 = text; int length = "(Clone)".Length; text = text2.Substring(0, text2.Length - length).TrimEnd(); } return text; } private static bool TryGetEnumValue(Character? character, MethodInfo? isFeatureEnabledMethod, MethodInfo? getValueMethod, string key, out string value) { value = ""; if ((Object)(object)character == (Object)null) { return false; } lock (Sync) { if (!TryResolveApi()) { WarnOnce("cllc-condition-missing:" + key, "CLLC " + key + " conditions require CreatureLevelControl. The condition was treated as not satisfied."); return false; } try { if (_isEnabledMethod?.Invoke(null, null) is bool flag && !flag) { WarnOnce("cllc-condition-disabled:" + key, "CLLC " + key + " conditions require CreatureLevelControl to be enabled. The condition was treated as not satisfied."); return false; } if (isFeatureEnabledMethod?.Invoke(null, null) is bool flag2 && !flag2) { WarnOnce("cllc-condition-feature-disabled:" + key, "CLLC " + key + " conditions require that CreatureLevelControl feature to be enabled. The condition was treated as not satisfied."); return false; } ZNetView component = ((Component)character).GetComponent<ZNetView>(); if (((component != null) ? component.GetZDO() : null) == null) { return false; } if (getValueMethod == null) { WarnOnce("cllc-condition-method-missing:" + key, "CreatureLevelControl does not expose a usable API for reading cllc." + key + ". The condition was treated as not satisfied."); return false; } object obj = getValueMethod.Invoke(null, new object[1] { character }); if (obj == null) { return false; } value = obj.ToString(); return !string.IsNullOrWhiteSpace(value); } catch (Exception ex) { WarnOnce("cllc-condition-read-error:" + key, "Failed to query CreatureLevelControl " + key + " state. The condition was treated as not satisfied. " + ex.Message); return false; } } } private static void ApplyEnumEffect(Character character, string configuredValue, string context, MethodInfo? isEnabledMethod, MethodInfo? setMethod, Type? enumType, string key) { if (setMethod == null || enumType == null) { WarnOnce("cllc-method-missing:" + key, "CreatureLevelControl does not expose a usable API for cllc." + key + ". The value was ignored."); return; } if (isEnabledMethod?.Invoke(null, null) is bool flag && !flag) { WarnOnce("cllc-feature-disabled:" + key, "Entry '" + context + "' configured cllc." + key + ", but that CreatureLevelControl feature is disabled. The value was ignored."); return; } object obj; try { obj = Enum.Parse(enumType, configuredValue, ignoreCase: true); } catch { string text = string.Join(", ", Enum.GetNames(enumType)); WarnOnce("cllc-invalid:" + key + ":" + configuredValue, "Entry '" + context + "' uses invalid cllc." + key + " value '" + configuredValue + "'. Supported values: " + text + "."); return; } try { setMethod.Invoke(null, new object[2] { character, obj }); } catch (Exception ex) { WarnOnce("cllc-apply-error:" + key + ":" + context, "Entry '" + context + "' failed to apply cllc." + key + ". " + ex.Message); } } private static bool TryResolveApi() { if (_resolved) { return _apiType != null; } _resolved = true; _apiType = SafeTypeLookup.FindLoadedType("CreatureLevelControl.API", "CreatureLevelControl"); if (_apiType == null) { return false; } BindingFlags bindingAttr = BindingFlags.Static | BindingFlags.Public; _getWorldLevelMethod = _apiType.GetMethod("GetWorldLevel", bindingAttr, null, Type.EmptyTypes, null); _isEnabledMethod = _apiType.GetMethod("IsEnabled", bindingAttr, null, Type.EmptyTypes, null); _isInfusionEnabledMethod = _apiType.GetMethod("IsInfusionEnabled", bindingAttr, null, Type.EmptyTypes, null); _isExtraEffectEnabledMethod = _apiType.GetMethod("IsExtraEffectEnabled", bindingAttr, null, Type.EmptyTypes, null); _isAffixEnabledMethod = _apiType.GetMethod("IsAffixEnabled", bindingAttr, null, Type.EmptyTypes, null); _getInfusionMethod = _apiType.GetMethod("GetInfusionCreature", bindingAttr, null, new Type[1] { typeof(Character) }, null); _getExtraEffectMethod = _apiType.GetMethod("GetExtraEffectCreature", bindingAttr, null, new Type[1] { typeof(Character) }, null); _getBossAffixMethod = _apiType.GetMethod("GetAffixBoss", bindingAttr, null, new Type[1] { typeof(Character) }, null); MethodInfo[] methods = _apiType.GetMethods(bindingAttr); foreach (MethodInfo methodInfo in methods) { ParameterInfo[] parameters = methodInfo.GetParameters(); if (methodInfo.Name == "SetInfusionCreature" && parameters.Length == 2 && parameters[0].ParameterType == typeof(Character)) { _setInfusionMethod = methodInfo; _infusionEnumType = parameters[1].ParameterType; } else if (methodInfo.Name == "SetExtraEffectCreature" && parameters.Length == 2 && parameters[0].ParameterType == typeof(Character)) { _setExtraEffectMethod = methodInfo; _extraEffectEnumType = parameters[1].ParameterType; } else if (methodInfo.Name == "SetAffixBoss" && parameters.Length == 2 && parameters[0].ParameterType == typeof(Character)) { _setBossAffixMethod = methodInfo; _bossAffixEnumType = parameters[1].ParameterType; } } return _apiType != null; } private static void WarnOnce(string key, string message) { if (WarningCache.Add(key)) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)message); } } } internal sealed class LocationConfigurationEntry { [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 LocationOfferingBowlDefinition? OfferingBowl { get; set; } [YamlMember(Order = 5)] public List<LocationItemStandDefinition>? ItemStands { get; set; } [YamlMember(Order = 6)] public List<LocationVegvisirDefinition>? Vegvisirs { get; set; } [YamlIgnore] public string RuleId { get; set; } = ""; [YamlIgnore] public string? SourcePath { get; set; } } internal sealed class LocationReferenceEntry { [YamlMember(Order = 1)] public string Prefab { get; set; } = ""; [YamlMember(Order = 2)] public LocationOfferingBowlDefinition? OfferingBowl { get; set; } [YamlMember(Order = 3)] public List<LocationItemStandDefinition>? ItemStands { get; set; } [YamlMember(Order = 4)] public List<LocationVegvisirDefinition>? Vegvisirs { get; set; } } internal sealed class LocationOfferingBowlDefinition { [YamlMember(Order = 1)] public string? Name { get; set; } [YamlMember(Order = 2)] public string? UseItemText { get; set; } [YamlMember(Order = 3)] public string? UsedAltarText { get; set; } [YamlMember(Order = 4)] public string? CantOfferText { get; set; } [YamlMember(Order = 5)] public string? WrongOfferText { get; set; } [YamlMember(Order = 6)] public string? IncompleteOfferText { get; set; } [YamlMember(Order = 7)] public string? BossItem { get; set; } [YamlMember(Order = 8)] public int? BossItems { get; set; } [YamlMember(Order = 9)] public string? BossPrefab { get; set; } [YamlMember(Order = 10)] public string? ItemPrefab { get; set; } [YamlMember(Order = 11)] public string? SetGlobalKey { get; set; } [YamlMember(Order = 12)] public bool? RenderSpawnAreaGizmos { get; set; } [YamlMember(Order = 13)] public bool? AlertOnSpawn { get; set; } [YamlMember(Order = 14)] public float? SpawnBossDelay { get; set; } [YamlMember(Order = 15)] public FloatRangeDefinition? SpawnBossDistance { get; set; } [YamlIgnore] public float? SpawnBossMaxDistance { get; set; } [YamlIgnore] public float? SpawnBossMinDistance { get; set; } [YamlMember(Order = 18)] public float? SpawnBossMaxYDistance { get; set; } [YamlMember(Order = 19)] public int? GetSolidHeightMargin { get; set; } [YamlMember(Order = 20)] public bool? EnableSolidHeightCheck { get; set; } [YamlMember(Order = 21)] public float? SpawnPointClearingRadius { get; set; } [YamlMember(Order = 22)] public float? SpawnYOffset { get; set; } [YamlMember(Order = 23)] public bool? UseItemStands { get; set; } [YamlMember(Order = 24)] public string? ItemStandPrefix { get; set; } [YamlMember(Order = 25)] public float? ItemStandMaxRange { get; set; } [YamlMember(Order = 26)] public float? RespawnMinutes { get; set; } [YamlMember(Order = 27)] public string? Data { get; set; } [YamlMember(Order = 28)] public Dictionary<string, string>? Fields { get; set; } [YamlMember(Order = 29)] public List<string>? Objects { get; set; } [YamlMember(Order = 30)] public string? CllcInfusion { get; set; } [YamlMember(Order = 31)] public string? CllcEffect { get; set; } [YamlMember(Order = 32)] public string? CllcBossEffect { get; set; } } internal sealed class LocationVegvisirDefinition { [YamlMember(Order = 1)] public string Path { get; set; } = ""; [YamlMember(Order = 2)] public List<string>? ExpectedLocations { get; set; } [YamlMember(Order = 3)] public string? Name { get; set; } [YamlMember(Order = 4)] public string? UseText { get; set; } [YamlMember(Order = 5)] public string? HoverName { get; set; } [YamlMember(Order = 6)] public string? SetsGlobalKey { get; set; } [YamlMember(Order = 7)] public string? SetsPlayerKey { get; set; } [YamlMember(Order = 8)] public List<LocationVegvisirTargetDefinition>? Locations { get; set; } } internal sealed class LocationItemStandDefinition { [YamlMember(Order = 1)] public string? Path { get; set; } [YamlMember(Order = 2)] public string? Name { get; set; } [YamlMember(Order = 3)] public bool? CanBeRemoved { get; set; } [YamlMember(Order = 4)] public bool? AutoAttach { get; set; } [YamlMember(Order = 5)] public string? OrientationType { get; set; } [YamlMember(Order = 6)] public List<string>? SupportedTypes { get; set; } [YamlMember(Order = 7)] public List<string>? SupportedItems { get; set; } [YamlMember(Order = 8)] public List<string>? UnsupportedItems { get; set; } [YamlMember(Order = 9)] public float? PowerActivationDelay { get; set; } [YamlMember(Order = 10)] public string? GuardianPower { get; set; } } internal sealed class LocationVegvisirTargetDefinition { [YamlMember(Order = 1)] public string LocationName { get; set; } = ""; [YamlMember(Order = 2)] public string? PinName { get; set; } [YamlMember(Order = 3)] public string? PinType { get; set; } [YamlMember(Order = 4)] public bool? DiscoverAll { get; set; } [YamlMember(Order = 5)] public bool? ShowMap { get; set; } } internal static class LocationManager { private sealed class OfferingBowlSnapshot { public string Name { get; set; } = ""; public string UseItemText { get; set; } = ""; public string UsedAltarText { get; set; } = ""; public string CantOfferText { get; set; } = ""; public string WrongOfferText { get; set; } = ""; public string IncompleteOfferText { get; set; } = ""; public string BossItem { get; set; } = ""; public int BossItems { get; set; } public string BossPrefab { get; set; } = ""; public string ItemPrefab { get; set; } = ""; public string SetGlobalKey { get; set; } = ""; public bool RenderSpawnAreaGizmos { get; set; } public bool AlertOnSpawn { get; set; } public float SpawnBossDelay { get; set; } public float SpawnBossMaxDistance { get; set; } public float SpawnBossMinDistance { get; set; } public float SpawnBossMaxYDistance { get; set; } public int GetSolidHeightMargin { get; set; } public bool EnableSolidHeightCheck { get; set; } public float SpawnPointClearingRadius { get; set; } public float SpawnYOffset { get; set; } public bool UseItemStands { get; set; } public string ItemStandPrefix { get; set; } = ""; public float ItemStandMaxRange { get; set; } public string? CllcInfusion { get; set; } public string? CllcEffect { get; set; } public string? CllcBossEffect { get; set; } } private sealed class VegvisirTargetSnapshot { public string LocationName { get; set; } = ""; public string PinName { get; set; } = ""; public string PinType { get; set; } = ""; public bool DiscoverAll { get; set; } public bool ShowMap { get; set; } } private sealed class VegvisirSnapshot { public string Name { get; set; } = ""; public string UseText { get; set; } = ""; public string HoverName { get; set; } = ""; public string SetsGlobalKey { get; set; } = ""; public string SetsPlayerKey { get; set; } = ""; public List<VegvisirTargetSnapshot> Locations { get; set; } = new List<VegvisirTargetSnapshot>(); } private sealed class PathScopedVegvisirSnapshot { public string Path { get; set; } = ""; public VegvisirSnapshot Snapshot { get; set; } = new VegvisirSnapshot(); } private sealed class PathScopedOfferingBowlSnapshot { public string Path { get; set; } = ""; public OfferingBowlSnapshot Snapshot { get; set; } = new OfferingBowlSnapshot(); } private sealed class ItemStandSnapshot { public string Name { get; set; } = ""; public bool CanBeRemoved { get; set; } public bool AutoAttach { get; set; } public string OrientationType { get; set; } = ""; public List<string> SupportedTypes { get; set; } = new List<string>(); public List<string> SupportedItems { get; set; } = new List<string>(); public List<string> UnsupportedItems { get; set; } = new List<string>(); public float PowerActivationDelay { get; set; } public string GuardianPower { get; set; } = ""; } private sealed class PathScopedItemStandSnapshot { public string Path { get; set; } = ""; public ItemStandSnapshot Snapshot { get; set; } = new ItemStandSnapshot(); } private sealed class LocationSnapshot { public string Prefab { get; set; } = ""; public OfferingBowlSnapshot? OfferingBowl { get; set; } public List<PathScopedItemStandSnapshot> ItemStands { get; set; } = new List<PathScopedItemStandSnapshot>(); public List<PathScopedVegvisirSnapshot> Vegvisirs { get; set; } = new List<PathScopedVegvisirSnapshot>(); } private sealed class LiveLocationSnapshot { public string Prefab { get; set; } = ""; public PathScopedOfferingBowlSnapshot? OfferingBowl { get; set; } public List<PathScopedItemStandSnapshot> ItemStands { get; set; } = new List<PathScopedItemStandSnapshot>(); public List<PathScopedVegvisirSnapshot> Vegvisirs { get; set; } = new List<PathScopedVegvisirSnapshot>(); } private sealed class LocationComponentCatalog { public string Prefab { get; set; } = ""; public string? OfferingBowlPath { get; set; } public List<string> ItemStandPaths { get; set; } = new List<string>(); public List<string> VegvisirPaths { get; set; } = new List<string>(); } private sealed class LocationRuntimeComponents { public Transform Root { get; set; } = null; public List<OfferingBowl> OfferingBowls { get; } = new List<OfferingBowl>(); public OfferingBowl? PrimaryOfferingBowl { get; set; } public List<ItemStand> ItemStands { get; } = new List<ItemStand>(); public List<Vegvisir> Vegvisirs { get; } = new List<Vegvisir>(); public Dictionary<string, OfferingBowl> OfferingBowlsByPath { get; set; } = new Dictionary<string, OfferingBowl>(StringComparer.Ordinal); public Dictionary<string, ItemStand> ItemStandsByPath { get; set; } = new Dictionary<string, ItemStand>(StringComparer.Ordinal); public Dictionary<string, Vegvisir> VegvisirsByPath { get; set; } = new Dictionary<string, Vegvisir>(StringComparer.Ordinal); public List<ItemStand> RelevantItemStands { get; set; } = new List<ItemStand>(); } private sealed class AuthoredItemStandSlotTemplate { public string Path { get; set; } = ""; public Vector3 OfferingBowlLocalOffset { get; set; } } private enum PendingLocationRootPhase { TraverseHierarchy, FinalizeBundles, ReconcileLocations } private readonly struct PendingLocationTraversalNode { public Transform Transform { get; } public Location? CurrentLocation { get; } public PendingLocationTraversalNode(Transform transform, Location? currentLocation) { Transform = transform; CurrentLocation = currentLocation; } } private sealed class PendingLocationRootReconcile { public int RootInstanceId { get; set; } public GameObject RootObject { get; set; } = null; public int Epoch { get; set; } public PendingLocationRootPhase Phase { get; set; } public List<Location>? Locations { get; set; } public List<PendingLocationTraversalNode>? TraversalStack { get; set; } public Dictionary<int, LocationRuntimeComponents>? RuntimeComponentsByLocationId { get; set; } public List<SpawnArea>? SpawnAreasForProvenance { get; set; } public List<CreatureSpawner>? CreatureSpawnersForProvenance { get; set; } public int NextFinalizeIndex { get; set; } public int NextIndex { get; set; } } private readonly struct PendingLocationReconcile { public Location Location { get; } public int Epoch { get; } public PendingLocationReconcile(Location location, int epoch) { Location = location; Epoch = epoch; } } private readonly struct PendingLooseOfferingBowlOverride { public OfferingBowl OfferingBowl { get; } public int OfferingBowlInstanceId { get; } public int Epoch { get; } public PendingLooseOfferingBowlOverride(OfferingBowl offeringBowl, int offeringBowlInstanceId, int epoch) { OfferingBowl = offeringBowl; OfferingBowlInstanceId = offeringBowlInstanceId; Epoch = epoch; } } [CompilerGenerated] private sealed class <EnumerateOverrideConfigurationPaths>d__131 : IEnumerable<string>, IEnumerable, IEnumerator<string>, IDisposable, IEnumerator { private int <>1__state; private string <>2__current; private int <>l__initialThreadId; private IEnumerator<string> <>s__1; private string <path>5__2; string IEnumerator<string>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <EnumerateOverrideConfigurationPaths>d__131(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 3) { try { } finally { <>m__Finally1(); } } <>s__1 = null; <path>5__2 = null; <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; if (!Directory.Exists(DropNSpawnPlugin.YamlConfigDirectoryPath)) { return false; } if (File.Exists(PrimaryOverrideConfigurationPathYml)) { <>2__current = PrimaryOverrideConfigurationPathYml; <>1__state = 1; return true; } goto IL_0085; case 1: <>1__state = -1; goto IL_0085; case 2: <>1__state = -1; goto IL_00b7; case 3: { <>1__state = -3; <path>5__2 = null; break; } IL_0085: if (File.Exists(PrimaryOverrideConfigurationPathYaml)) { <>2__current = PrimaryOverrideConfigurationPathYaml; <>1__state = 2; return true; } goto IL_00b7; IL_00b7: <>s__1 = EnumerateSupplementalOverrideConfigurationPaths().GetEnumerator(); <>1__state = -3; break; } if (<>s__1.MoveNext()) { <path>5__2 = <>s__1.Current; <>2__current = <path>5__2; <>1__state = 3; return true; } <>m__Finally1(); <>s__1 = null; return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<>s__1 != null) { <>s__1.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator<string> IEnumerable<string>.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; return this; } return new <EnumerateOverrideConfigurationPaths>d__131(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<string>)this).GetEnumerator(); } } [CompilerGenerated] private sealed class <EnumerateSupplementalOverrideConfigurationPaths>d__132 : IEnumerable<string>, IEnumerable, IEnumerator<string>, IDisposable, IEnumerator { private int <>1__state; private string <>2__current; private int <>l__initialThreadId; private IEnumerator<string> <>s__1; private string <path>5__2; string IEnumerator<string>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <EnumerateSupplementalOverrideConfigurationPaths>d__132(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <>s__1 = null; <path>5__2 = null; <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>s__1 = DropNSpawnPlugin.EnumerateSupplementalOverrideConfigurationPaths(DropNSpawnPlugin.GetYamlDomainSupplementalPrefix("location") + "*.*", IsOverrideConfigurationFileName).GetEnumerator(); <>1__state = -3; break; case 1: <>1__state = -3; <path>5__2 = null; break; } if (<>s__1.MoveNext()) { <path>5__2 = <>s__1.Current; <>2__current = <path>5__2; <>1__state = 1; return true; } <>m__Finally1(); <>s__1 = null; return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<>s__1 != null) { <>s__1.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator<string> IEnumerable<string>.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; return this; } return new <EnumerateSupplementalOverrideConfigurationPaths>d__132(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<string>)this).GetEnumerator(); } } [CompilerGenerated] private sealed class <GetRegisteredLocations>d__159 : IEnumerable<Location>, IEnumerable, IEnumerator<Location>, IDisposable, IEnumerator { private int <>1__state; private Location <>2__current; private int <>l__initialThreadId; private HashSet<string> dirtyPrefabs; public HashSet<string> <>3__dirtyPrefabs; private HashSet<Location> <visited>5__1; private HashSet<string>.Enumerator <>s__2; private string <prefabName>5__3; private HashSet<Location> <locations>5__4; private HashSet<Location>.Enumerator <>s__5; private Location <location>5__6; Location IEnumerator<Location>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <GetRegisteredLocations>d__159(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if ((uint)(num - -4) <= 1u || num == 1) { try { if (num == -4 || num == 1) { try { } finally { <>m__Finally2(); } } } finally { <>m__Finally1(); } } <visited>5__1 = null; <>s__2 = default(HashSet<string>.Enumerator); <prefabName>5__3 = null; <locations>5__4 = null; <>s__5 = default(HashSet<Location>.Enumerator); <location>5__6 = null; <>1__state = -2; } private bool MoveNext() { try { int num = <>1__state; if (num != 0) { if (num != 1) { return false; } <>1__state = -4; goto IL_0115; } <>1__state = -1; CleanupRegisteredLocations(); <visited>5__1 = new HashSet<Location>(); <>s__2 = dirtyPrefabs.GetEnumerator(); <>1__state = -3; goto IL_014f; IL_014f: do { if (<>s__2.MoveNext()) { <prefabName>5__3 = <>s__2.Current; continue; } <>m__Finally1(); <>s__2 = default(HashSet<string>.Enumerator); return false; } while (!LiveLocationsByPrefab.TryGetValue(<prefabName>5__3, out <locations>5__4)); <>s__5 = <locations>5__4.GetEnumerator(); <>1__state = -4; goto IL_011d; IL_0115: <location>5__6 = null; goto IL_011d; IL_011d: if (<>s__5.MoveNext()) { <location>5__6 = <>s__5.Current; if ((Object)(object)<location>5__6 != (Object)null && (Object)(object)((Component)<location>5__6).gameObject != (Object)null && <visited>5__1.Add(<location>5__6)) { <>2__current = <location>5__6; <>1__state = 1; return true; } goto IL_0115; } <>m__Finally2(); <>s__5 = default(HashSet<Location>.Enumerator); <locations>5__4 = null; <prefabName>5__3 = null; goto IL_014f; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; ((IDisposable)<>s__2).Dispose(); } private void <>m__Finally2() { <>1__state = -3; ((IDisposable)<>s__5).Dispose(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator<Location> IEnumerable<Location>.GetEnumerator() { <GetRegisteredLocations>d__159 <GetRegisteredLocations>d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; <GetRegisteredLocations>d__ = this; } else { <GetRegisteredLocations>d__ = new <GetRegisteredLocations>d__159(0); } <GetRegisteredLocations>d__.dirtyPrefabs = <>3__dirtyPrefabs; return <GetRegisteredLocations>d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<Location>)this).GetEnumerator(); } } [CompilerGenerated] private sealed class <GetTrackedLooseItemStands>d__160 : IEnumerable<ItemStand>, IEnumerable, IEnumerator<ItemStand>, IDisposable, IEnumerator { private int <>1__state; private ItemStand <>2__current; private int <>l__initialThreadId; private HashSet<string> dirtyPrefabs; public HashSet<string> <>3__dirtyPrefabs; private List<KeyValuePair<ItemStand, string>> <trackedItemStands>5__1; private List<KeyValuePair<ItemStand, string>>.Enumerator <>s__2; private ItemStand <itemStand>5__3; private string <prefabName>5__4; ItemStand IEnumerator<ItemStand>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <GetTrackedLooseItemStands>d__160(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <trackedItemStands>5__1 = null; <>s__2 = default(List<KeyValuePair<ItemStand, string>>.Enumerator); <itemStand>5__3 = null; <prefabName>5__4 = null; <>1__state = -2; } private bool MoveNext() { try { int num = <>1__state; if (num != 0) { if (num != 1) { return false; } <>1__state = -3; goto IL_00e1; } <>1__state = -1; CleanupTrackedLooseItemStandPrefabs(); <trackedItemStands>5__1 = TrackedLooseItemStandPrefabs.ToList(); <>s__2 = <trackedItemStands>5__1.GetEnumerator(); <>1__state = -3; goto IL_00f0; IL_00e1: <itemStand>5__3 = null; <prefabName>5__4 = null; goto IL_00f0; IL_00f0: if (!<>s__2.MoveNext()) { <>m__Finally1(); <>s__2 = default(List<KeyValuePair<ItemStand, string>>.Enumerator); return false; } (<itemStand>5__3, <prefabName>5__4) = (KeyValuePair<ItemStand, string>)(ref <>s__2.Current); if ((Object)(object)<itemStand>5__3 != (Object)null && (Object)(object)((Component)<itemStand>5__3).gameObject != (Object)null && dirtyPrefabs.Contains(<prefabName>5__4)) { <>2__current = <itemStand>5__3; <>1__state = 1; return true; } goto IL_00e1; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; ((IDisposable)<>s__2).Dispose(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator<ItemStand> IEnumerable<ItemStand>.GetEnumerator() { <GetTrackedLooseItemStands>d__160 <GetTrackedLooseItemStands>d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; <GetTrackedLooseItemStands>d__ = this; } else { <GetTrackedLooseItemStands>d__ = new <GetTrackedLooseItemStands>d__160(0); } <GetTrackedLooseItemStands>d__.dirtyPrefabs = <>3__dirtyPrefabs; return <GetTrackedLooseItemStands>d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<ItemStand>)this).GetEnumerator(); } } private const string ReferenceAutoUpdateStateKey = "location"; private static readonly int OfferingBowlLastUseTicksKey = StringExtensionMethods.GetStableHashCode("DropNSpawn.offering_bowl_last_use_ticks"); private static readonly object Sync = new object(); private static readonly IDeserializer Deserializer = new DeserializerBuilder().WithNamingConvention(CamelCaseNamingConvention.Instance).Build(); private static readonly ISerializer Serializer = new SerializerBuilder().WithNamingConvention(CamelCaseNamingConvention.Instance).ConfigureDefaultValuesHandling(DefaultValuesHandling.OmitNull | DefaultValuesHandling.OmitDefaults).Build(); private static readonly List<LocationSnapshot> Snapshots = new List<LocationSnapshot>(); private static readonly Dictionary<string, LocationSnapshot> SnapshotsByPrefab = new Dictionary<string, LocationSnapshot>(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary<string, List<LocationConfigurationEntry>> ActiveEntriesByPrefab = new Dictionary<string, List<LocationConfigurationEntry>>(StringComparer.OrdinalIgnoreCase); private static readonly HashSet<string> InvalidEntryWarnings = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private static readonly HashSet<string> DuplicateComponentWarnings = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private static readonly HashSet<string> ItemStandDiagnosticLogs = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private static readonly HashSet<string> LocationDiagnosticLogs = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private static readonly HashSet<string> RedundantLocationConditionWarnings = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private static readonly HashSet<string> VegvisirWarningLogs = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary<OfferingBowl, HashSet<int>> PendingOfferingBowlNearbyCharacterIds = new Dictionary<OfferingBowl, HashSet<int>>(); private static readonly Dictionary<ItemStand, ItemStandSnapshot> LooseItemStandSnapshots = new Dictionary<ItemStand, ItemStandSnapshot>(); private static readonly Dictionary<Location, LiveLocationSnapshot> LiveLocationSnapshots = new Dictionary<Location, LiveLocationSnapshot>(); private static readonly Dictionary<string, LocationComponentCatalog> CatalogsByPrefab = new Dictionary<string, LocationComponentCatalog>(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary<string, HashSet<Location>> LiveLocationsByPrefab = new Dictionary<string, HashSet<Location>>(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary<Location, string> LiveLocationPrefabsByInstance = new Dictionary<Location, string>(); private static readonly Dictionary<string, List<AuthoredItemStandSlotTemplate>> AuthoredItemStandSlotsByPrefab = new Dictionary<string, List<AuthoredItemStandSlotTemplate>>(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary<string, List<LocationConfigurationEntry>> LooseItemStandEntriesByPrefab = new Dictionary<string, List<LocationConfigurationEntry>>(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary<ItemStand, string> TrackedLooseItemStandPrefabs = new Dictionary<ItemStand, string>(); private static readonly Dictionary<ItemStand, string> LooseItemStandAuthoredPathsByInstance = new Dictionary<ItemStand, string>(); private static readonly RingBufferQueue<PendingLocationReconcile> PendingLocationReconciles = new RingBufferQueue<PendingLocationReconcile>(); private static readonly HashSet<int> PendingLocationReconcileIds = new HashSet<int>(); private static readonly Dictionary<int, int> SuppressedQueuedLocationReconciles = new Dictionary<int, int>(); private static readonly RingBufferQueue<PendingLocationRootReconcile> PendingLocationRootReconciles = new RingBufferQueue<PendingLocationRootReconcile>(); private static readonly HashSet<int> PendingLocationRootReconcileIds = new HashSet<int>(); private static readonly RingBufferQueue<PendingLooseOfferingBowlOverride> PendingLooseOfferingBowlOverrides = new RingBufferQueue<PendingLooseOfferingBowlOverride>(); private static readonly HashSet<int> PendingLooseOfferingBowlOverrideIds = new HashSet<int>(); private static List<LocationConfigurationEntry> _configuration = new List<LocationConfigurationEntry>(); private static string _configurationSignature = ""; private static string _lastLoadedConfigurationPayload = ""; private static bool _initialized; private static bool _snapshotsCaptured; private static int? _lastProcessedGameDataSignature; private static bool _referenceArtifactsAutoRefreshConsumed; private static readonly Dictionary<string, string> _lastAppliedEntrySignaturesByPrefab = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); private static string _lastAppliedConfigurationSignature = ""; private static int? _lastAppliedGameDataSignature; private static bool? _lastAppliedDomainEnabled; private static int _reconcileQueueEpoch; private static readonly Dictionary<string, string> EmptyEntrySignatures = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); private static string ReferenceConfigurationPath => Path.Combine(DropNSpawnPlugin.YamlConfigDirectoryPath, DropNSpawnPlugin.GetYamlDomainFilePrefix("location") + ".reference.yml"); private static string PrimaryOverrideConfigurationPathYml => Path.Combine(DropNSpawnPlugin.YamlConfigDirectoryPath, DropNSpawnPlugin.GetYamlDomainFilePrefix("location") + ".yml"); private static string PrimaryOverrideConfigurationPathYaml => Path.Combine(DropNSpawnPlugin.YamlConfigDirectoryPath, DropNSpawnPlugin.GetYamlDomainFilePrefix("location") + ".yaml"); private static string FullScaffoldConfigurationPath => Path.Combine(DropNSpawnPlugin.YamlConfigDirectoryPath, DropNSpawnPlugin.GetYamlDomainFilePrefix("location") + ".full.yml"); internal static bool ShouldReloadForPath(string? path) { return DropNSpawnPlugin.IsEligibleOverrideConfigurationPath(path) && IsOverrideConfigurationFileName(Path.GetFileName(path ?? "")); } internal static void Initialize() { lock (Sync) { if (!_initialized) { LoadConfiguration(); _initialized = true; } } } internal static void ReloadConfiguration() { lock (Sync) { LoadConfiguration(); ApplyIfReady(); } } internal static void OnGameDataReady(string source) { lock (Sync) { if (!_initialized) { Initialize(); } if (!IsGameDataReady()) { return; } int num = ComputeGameDataSignature(); if (_lastProcessedGameDataSignature == num) { return; } ResetReferenceSnapshots(); ResetRuntimeState(preserveLiveRegistries: true); CleanupRegisteredLocations(); if (DropNSpawnPlugin.IsSourceOfTruth) { if (!_referenceArtifactsAutoRefreshConsumed) { EnsureReferenceArtifactsUpToDate(); _referenceArtifactsAutoRefreshConsumed = true; } if (EnsurePrimaryOverrideConfigurationFileExists()) { LoadConfiguration(); } } else { _referenceArtifactsAutoRefreshConsumed = true; } ApplyIfReady(); _lastProcessedGameDataSignature = num; DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)("Locations processed after " + source + ".")); } } internal static void ReconcileLocationInstance(Location location) { lock (Sync) { TrackLocationInstanceInternal(location); if (!_initialized) { Initialize(); } if (IsGameDataReady()) { ReconcileLocationInstanceInternal(location); } } } internal static void QueueLocationReconcile(Location? location) { lock (Sync) { if (!((Object)(object)location == (Object)null) && !((Object)(object)((Component)location).gameObject == (Object)null)) { int instanceID = ((Object)location).GetInstanceID(); if (PendingLocationReconcileIds.Add(instanceID)) { PendingLocationReconciles.Enqueue(new PendingLocationReconcile(location, _reconcileQueueEpoch)); } } } } internal static void ReconcileSpawnedLocationRoot(GameObject? rootObject) { QueueSpawnedLocationRootReconcile(rootObject); } internal static void QueueSpawnedLocationRootReconcile(GameObject? rootObject) { lock (Sync) { if (!((Object)(object)rootObject == (Object)null)) { int instanceID = ((Object)rootObject).GetInstanceID(); if (PendingLocationRootReconcileIds.Add(instanceID)) { PendingLocationRootReconciles.Enqueue(new PendingLocationRootReconcile { RootInstanceId = instanceID, RootObject = rootObject, Epoch = _reconcileQueueEpoch, Phase = PendingLocationRootPhase.TraverseHierarchy }); } } } } internal static void TrackLocationInstance(Location? location) { lock (Sync) { TrackLocationInstanceInternal(location); } } internal static void TrackSpawnedLocationRoot(GameObject? rootObject) { lock (Sync) { TrackSpawnedLocationRootInternal(rootObject); } } internal static void QueueLooseItemStandOverride(ItemStand? itemStand) { lock (Sync) { if (!((Object)(object)itemStand == (Object)null) && !((Object)(object)((Component)itemStand).gameObject == (Object)null) && LooseItemStandEntriesByPrefab.Count != 0 && !((Object)(object)((Component)itemStand).GetComponentInParent<Location>() != (Object)null) && AltarItemStandHoverInfoFormatter.TryGetRelevantOfferingBowl(itemStand, out OfferingBowl offeringBowl) && !((Object)(object)offeringBowl == (Object)null)) { QueueLooseOfferingBowlOverrideInternal(offeringBowl); } } } internal static void QueueLooseOfferingBowlOverride(OfferingBowl? offeringBowl) { lock (Sync) { QueueLooseOfferingBowlOverrideInternal(offeringBowl); } } internal static void QueueLooseOfferingBowlOverridesUnderRoot(GameObject? rootObject) { lock (Sync) { if (!((Object)(object)rootObject == (Object)null) && LooseItemStandEntriesByPrefab.Count != 0) { OfferingBowl[] componentsInChildren = rootObject.GetComponentsInChildren<OfferingBowl>(true); foreach (OfferingBowl offeringBowl in componentsInChildren) { QueueLooseOfferingBowlOverrideInternal(offeringBowl); } } } } private static void QueueLooseOfferingBowlOverrideInternal(OfferingBowl? offeringBowl) { if (!((Object)(object)offeringBowl == (Object)null) && !((Object)(object)((Component)offeringBowl).gameObject == (Object)null) && LooseItemStandEntriesByPrefab.Count != 0 && offeringBowl.m_useItemStands && !((Object)(object)((Component)offeringBowl).GetComponentInParent<Location>() != (Object)null)) { int instanceID = ((Object)offeringBowl).GetInstanceID(); if (PendingLooseOfferingBowlOverrideIds.Add(instanceID)) { PendingLooseOfferingBowlOverrides.Enqueue(new PendingLooseOfferingBowlOverride(offeringBowl, instanceID, _reconcileQueueEpoch)); } } } internal static bool HasPendingReconcileWork() { lock (Sync) { return PendingLocationReconciles.Count > 0 || PendingLocationRootReconciles.Count > 0 || PendingLooseOfferingBowlOverrides.Count > 0; } } internal static bool ProcessQueuedReconcileStep(float deadline) { lock (Sync) { if (Time.realtimeSinceStartup >= deadline) { return false; } if (!IsGameDataReady() || DropNSpawnPlugin.IsGameDataRefreshDeferred(DropNSpawnPlugin.ReloadDomain.Location)) { return false; } if (PendingLocationRootReconciles.Count > 0) { return ProcessQueuedLocationRootStep(deadline); } while (PendingLocationReconciles.Count > 0) { if (!PendingLocationReconciles.TryDequeue(out var item) || item.Epoch != _reconcileQueueEpoch || (Object)(object)item.Location == (Object)null) { continue; } Location location = item.Location; int instanceID = ((Object)location).GetInstanceID(); PendingLocationReconcileIds.Remove(instanceID); if (SuppressedQueuedLocationReconciles.TryGetValue(instanceID, out var value) && value > 0) { if (value == 1) { SuppressedQueuedLocationReconciles.Remove(instanceID); } else { SuppressedQueuedLocationReconciles[instanceID] = value - 1; } return true; } TrackLocationInstanceInternal(location); if (!_initialized) { Initialize(); } ReconcileLocationInstanceInternal(location); return true; } while (PendingLooseOfferingBowlOverrides.Count > 0) { if (!PendingLooseOfferingBowlOverrides.TryDequeue(out var item2)) { continue; } PendingLooseOfferingBowlOverrideIds.Remove(item2.OfferingBowlInstanceId); if (item2.Epoch != _reconcileQueueEpoch || (Object)(object)item2.OfferingBowl == (Object)null) { continue; } if (!_initialized) { Initialize(); } TryApplyLooseOfferingBowlOverrideInternal(item2.OfferingBowl); return true; } } return false; } internal static void UntrackLocationInstance(Location? location) { lock (Sync) { if ((Object)(object)location != (Object)null && LiveLocationPrefabsByInstance.TryGetValue(location, out string value)) { UnregisterLiveLocation(location, value); } } } internal static bool TryBlockOfferingBowlRespawn(OfferingBowl offeringBowl, Humanoid? user, ref bool result) { lock (Sync) { if ((Object)(object)offeringBowl == (Object)null || (Object)(object)ZNet.instance == (Object)null) { return false; } OfferingBowlRuntimeState component = ((Component)offeringBowl).GetComponent<OfferingBowlRuntimeState>(); if ((Object)(object)component == (Object)null || component.RespawnMinutes <= 0f) { return false; } long offeringBowlLastUseTicks = GetOfferingBowlLastUseTicks(offeringBowl, component); if (offeringBowlLastUseTicks <= 0) { return false; } if ((ZNet.instance.GetTime() - new DateTime(offeringBowlLastUseTicks)).TotalMinutes >= (double)component.RespawnMinutes) { return false; } if ((Object)(object)user != (Object)null) { ((Character)user).Message((MessageType)2, Localization.instance.Localize(offeringBowl.m_cantOfferText), 0, (Sprite)null); } result = true; return true; } } internal static void MarkOfferingBowlUsed(OfferingBowl offeringBowl) { lock (Sync) { if ((Object)(object)offeringBowl == (Object)null || (Object)(object)ZNet.instance == (Object)null) { return; } OfferingBowlRuntimeState component = ((Component)offeringBowl).GetComponent<OfferingBowlRuntimeState>(); if ((Object)(object)component == (Object)null || component.RespawnMinutes <= 0f) { return; } long num = (component.LocalLastUseTicks = ZNet.instance.GetTime().Ticks); ZNetView componentInParent = ((Component)offeringBowl).GetComponentInParent<ZNetView>(); if (!((Object)(object)componentInParent == (Object)null) && componentInParent.IsValid()) { if (!componentInParent.IsOwner()) { componentInParent.ClaimOwnership(); } if (componentInParent.IsOwner()) { componentInParent.GetZDO().Set(OfferingBowlLastUseTicksKey, num); } } } } internal static bool TryWriteFullScaffoldConfigurationFile(out string path, out string error) { lock (Sync) { path = FullScaffoldConfigurationPath; error = ""; if (!IsGameDataReady() && !_snapshotsCaptured) { error = "Location game data is not ready yet."; return false; } RefreshSnapshots(); Directory.CreateDirectory(DropNSpawnPlugin.YamlConfigDirectoryPath); File.WriteAllText(path, BuildFullScaffoldConfigurationTemplate()); DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)("Wrote location full scaffold configuration to " + path + ".")); return true; } } internal static void RefreshReferenceConfigurationFile() { lock (Sync) { if (IsGameDataReady()) { RefreshSnapshots(); WriteReferenceConfigurationFile(BuildReferenceConfigurationTemplate(), "Updated location reference configuration at " + ReferenceConfigurationPath + "."); ReferenceRefreshSupport.RecordAutoUpdateState("location", ReferenceConfigurationPath, ComputeReferenceSourceSignature(), null, "2026-03-26-full-rewrite-v1"); ResetReferenceSnapshots(); } } } private static bool IsGameDataReady() { return (Object)(object)ZoneSystem.instance != (Object)null && (Object)(object)ZNetScene.instance != (Object)null && (Object)(object)ObjectDB.instance != (Object)null; } private static int ComputeGameDataSignature() { if (!IsGameDataReady() || (Object)(object)ZoneSystem.instance == (Object)null || (Object)(object)ZNetScene.instance == (Object)null || (Object)(object)ObjectDB.instance == (Object)null) { return 0; } int num = 17; num = num * 31 + ((Object)ZoneSystem.instance).GetInstanceID(); num = num * 31 + ((Object)ZNetScene.instance).GetInstanceID(); num = num * 31 + ((Object)ObjectDB.instance).GetInstanceID(); num = HashGameObjectCollection(num, ZNetScene.instance.m_prefabs); num = HashGameObjectCollection(num, ZNetScene.instance.m_nonNetViewPrefabs); num = HashGameObjectCollection(num, ObjectDB.instance.m_items); foreach (ZoneLocation location in ZoneSystem.instance.m_locations) { num = num * 31 + (location?.m_prefabName?.GetHashCode()).GetValueOrDefault(); } return num; } private static int HashGameObjectCollection(int hash, IEnumerable<GameObject> prefabs) { foreach (GameObject prefab in prefabs) { hash = hash * 31 + (((Object)(object)prefab != (Object)null) ? ((Object)prefab).GetInstanceID() : 0); } return hash; } private static string ComputeReferenceSourceSignature() { if ((Object)(object)ZoneSystem.instance == (Object)null) { return ""; } return ReferenceRefreshSupport.ComputeStableHashForKeys(ZoneSystem.instance.m_locations.Select((ZoneLocation location) => location?.m_prefabName ?? location?.m_prefab.Name)); } private static bool EnsurePrimaryOverrideConfigurationFileExists() { if (File.Exists(PrimaryOverrideConfigurationPathYml) || File.Exists(PrimaryOverrideConfigurationPathYaml) || EnumerateSupplementalOverrideConfigurationPaths().Any()) { return false; } Directory.CreateDirectory(DropNSpawnPlugin.YamlConfigDirectoryPath); File.WriteAllText(PrimaryOverrideConfigurationPathYml, BuildPrimaryOverrideConfigurationTemplate()); DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)("Created location override configuration at " + PrimaryOverrideConfigurationPathYml + ".")); return true; } private static void EnsureReferenceArtifactsUpToDate() { if (!IsGameDataReady()) { return; } string sourceSignature = ComputeReferenceSourceSignature(); if (!File.Exists(ReferenceConfigurationPath)) { if (DropNSpawnPlugin.ShouldAutoCreateMissingReferenceFiles()) { RefreshSnapshots(); WriteReferenceConfigurationFile(BuildReferenceConfigurationTemplate(), "Created location reference configuration at " + ReferenceConfigurationPath + "."); ReferenceRefreshSupport.RecordAutoUpdateState("location", ReferenceConfigurationPath, sourceSignature, null, "2026-03-26-full-rewrite-v1"); ResetReferenceSnapshots(); } } else if (DropNSpawnPlugin.ShouldAutoUpdateReferenceFiles() && !ReferenceRefreshSupport.ShouldSkipAutoUpdate("location", ReferenceConfigurationPath, sourceSignature, "2026-03-26-full-rewrite-v1")) { RefreshSnapshots(); WriteReferenceConfigurationFile(BuildReferenceConfigurationTemplate(), "Updated location reference configuration at " + ReferenceConfigurationPath + "."); ReferenceRefreshSupport.RecordAutoUpdateState("location", ReferenceConfigurationPath, sourceSignature, null, "2026-03-26-full-rewrite-v1"); ResetReferenceSnapshots(); } } private static void LoadConfiguration() { List<LocationConfigurationEntry> entries2; string payloadToken; if (DropNSpawnPlugin.IsSourceOfTruth) { EnsurePrimaryOverrideConfigurationFileExists(); List<ConfigurationLoadSupport.LocalYamlDocument> documents = ConfigurationLoadSupport.ReadLocalYamlDocuments(EnumerateOverrideConfigurationPaths().ToList()); string text = ConfigurationLoadSupport.BuildLocalPayload(documents); List<LocationConfigurationEntry> entries; if (string.Equals(_lastLoadedConfigurationPayload, text, StringComparison.Ordinal)) { entries = BuildSyncedClientProjectionEntries(); DropNSpawnPlugin.UpdateSyncedLocationPayload(entries); return; } ResetLoadedConfigurationState(); LoadLocalConfiguration(documents); _configurationSignature = Serializer.Serialize(_configuration); _lastLoadedConfigurationPayload = text; entries = BuildSyncedClientProjectionEntries(); DropNSpawnPlugin.UpdateSyncedLocationPayload(entries); } else if (!DropNSpawnPlugin.TryGetSyncedLocationEntries(out entries2, out payloadToken)) { DropNSpawnPlugin.DropNSpawnLogger.LogDebug((object)"Waiting for synchronized location override payload from the server."); } else { if (string.Equals(_lastLoadedConfigurationPayload, payloadToken, StringComparison.Ordinal)) { return; } ResetLoadedConfigurationState(); if (entries2.Count == 0) { _configurationSignature = Serializer.Serialize(_configuration); _lastLoadedConfigurationPayload = payloadToken; return; } try { MergeConfiguration(entries2, "ServerSync:DropNSpawnLocation"); DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)$"Loaded {ActiveEntriesByPrefab.Count} synchronized location projection(s) from the server."); } catch (Exception arg) { DropNSpawnPlugin.DropNSpawnLogger.LogError((object)$"Failed to deserialize synchronized location payload DTO. {arg}"); } _configurationSignature = Serializer.Serialize(_configuration); _lastLoadedConfigurationPayload = payloadToken; } } private static void ResetLoadedConfigurationState() { ClearQueuedReconcileState(); ActiveEntriesByPrefab.Clear(); AuthoredItemStandSlotsByPrefab.Clear(); LooseItemStandEntriesByPrefab.Clear(); InvalidEntryWarnings.Clear(); ItemStandDiagnosticLogs.Clear(); LocationDiagnosticLogs.Clear(); _configuration = new List<LocationConfigurationEntry>(); } private static void LoadLocalConfiguration(List<ConfigurationLoadSupport.LocalYamlDocument> documents) { if (documents.Count == 0) { DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)"Loaded 0 location configuration(s) from 0 override file(s)."); return; } int num = 0; foreach (ConfigurationLoadSupport.LocalYamlDocument document in documents) { if (document.ReadError != null) { DropNSpawnPlugin.DropNSpawnLogger.LogError((object)("Failed to read " + document.Path + ". " + document.ReadError)); continue; } try { string yaml = document.Yaml ?? ""; List<LocationConfigurationEntry> configuration = ParseConfiguration(yaml); MergeConfiguration(configuration, document.Path); num++; } catch (Exception arg) { DropNSpawnPlugin.DropNSpawnLogger.LogError((object)$"Failed to parse location YAML '{document.Path}'. Location override YAML must start with a root list like '- prefab: ...'. {arg}"); } } DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)$"Loaded {ActiveEntriesByPrefab.Count} location configuration(s) from {num} override file(s)."); } private static List<LocationConfigurationEntry> ParseConfiguration(string yaml) { if (string.IsNullOrWhiteSpace(yaml)) { return new List<LocationConfigurationEntry>(); } List<LocationConfigurationEntry> list = Deserializer.Deserialize<List<LocationConfigurationEntry>>(yaml) ?? new List<LocationConfigurationEntry>(); foreach (LocationConfigurationEntry item in list) { item.Prefab = (item.Prefab ?? "").Trim(); NormalizeOfferingBowlDefinition(item.OfferingBowl); NormalizeItemStandDefinitions(item.ItemStands); NormalizeVegvisirDefinitions(item.Vegvisirs); FinalizeNormalizedEntry(item); } return list; } private static void MergeConfiguration(List<LocationConfigurationEntry> configuration, string source) { foreach (LocationConfigurationEntry item in configuration) { item.SourcePath = source; item.Prefab = (item.Prefab ?? "").Trim(); NormalizeOfferingBowlDefinition(item.OfferingBowl); NormalizeItemStandDefinitions(item.ItemStands); NormalizeVegvisirDefinitions(item.Vegvisirs); FinalizeNormalizedEntry(item); StripRedundantLocationComponentConditions(item, source); if (item.Prefab.Length == 0) { WarnInvalidEntry("Entry in '" + source + "' is missing prefab."); } else { if (!item.Enabled) { continue; } RemoveEffectiveConfigurationEntry(item.Prefab, item.RuleId); _configuration.Add(item); if (HasOverride(item)) { GetOrCreateActiveEntries(item.Prefab).Add(item); if (HasLooseItemStandOverride(item.ItemStands)) { GetOrCreateLooseItemStandEntries(item.Prefab).Add(item); } LogLoadedLocationEntry(item); } } } } private static bool RemoveEffectiveConfigurationEntry(string prefabName, string ruleId) { bool result = false; for (int num = _configuration.Count - 1; num >= 0; num--) { LocationConfigurationEntry locationConfigurationEntry = _configuration[num]; if (string.Equals(locationConfigurationEntry.Prefab, prefabName, StringComparison.OrdinalIgnoreCase) && string.Equals(locationConfigurationEntry.RuleId, ruleId, StringComparison.Ordinal)) { _configuration.RemoveAt(num); result = true; } } if (ActiveEntriesByPrefab.TryGetValue(prefabName, out List<LocationConfigurationEntry> value)) { for (int num2 = value.Count - 1; num2 >= 0; num2--) { if (string.Equals(value[num2].RuleId, ruleId, StringComparison.Ordinal)) { value.RemoveAt(num2); result = true; } } if (value.Count == 0) { ActiveEntriesByPrefab.Remove(prefabName); } } if (LooseItemStandEntriesByPrefab.TryGetValue(prefabName, out List<LocationConfigurationEntry> value2)) { for (int num3 = value2.Count - 1; num3 >= 0; num3--) { if (string.Equals(value2[num3].RuleId, ruleId, StringComparison.Ordinal)) { value2.RemoveAt(num3); result = true; } } if (value2.Count == 0) { LooseItemStandEntriesByPrefab.Remove(prefabName); } } return result; } private static List<LocationConfigurationEntry> GetOrCreateActiveEntries(string prefabName) { if (!ActiveEntriesByPrefab.TryGetValue(prefabName, out List<LocationConfigurationEntry> value)) { value = new List<LocationConfigurationEntry>(); ActiveEntriesByPrefab[prefabName] = value; } return value; } private static List<LocationConfigurationEntry> GetOrCreateLooseItemStandEntries(string prefabName) { if (!LooseItemStandEntriesByPrefab.TryGetValue(prefabName, out List<LocationConfigurationEntry> value)) { value = new List<LocationConfigurationEntry>(); LooseItemStandEntriesByPrefab[prefabName] = value; } return value; } private static List<LocationConfigurationEntry> BuildSyncedClientProjectionEntries() { List<LocationConfigurationEntry> list = new List<LocationConfigurationEntry>(); foreach (LocationConfigurationEntry item in _configuration) { LocationConfigurationEntry locationConfigurationEntry = CreateClientProjectionEntry(item); if (locationConfigurationEntry != null) { list.Add(locationConfigurationEntry); } } return list; } private static LocationConfigurationEntry? CreateClientProjectionEntry(LocationConfigurationEntry? entry) { if (entry == null || !entry.Enabled || string.IsNullOrWhiteSpace(entry.Prefab)) { return null; } LocationOfferingBowlDefinition locationOfferingBowlDefinition = CreateClientProjectionOfferingBowlDefinition(entry.OfferingBowl); List<LocationItemStandDefinition> list = (HasItemStandOverride(entry.ItemStands) ? entry.ItemStands : null); List<LocationVegvisirDefinition> list2 = (HasVegvisirOverride(entry.Vegvisirs) ? entry.Vegvisirs : null); if (locationOfferingBowlDefinition == null && list == null && list2 == null) { return null; } return new LocationConfigurationEntry { RuleId = entry.RuleId, Prefab = entry.Prefab, Enabled = true, Conditions = entry.Conditions, OfferingBowl = locationOfferingBowlDefinition, ItemStands = list, Vegvisirs = list2 }; } private static LocationOfferingBowlDefinition? CreateClientProjectionOfferingBowlDefinition(LocationOfferingBowlDefinition? definition) { if (!HasClientVisibleOfferingBowlOverride(definition)) { return null; } return new LocationOfferingBowlDefinition { Name = definition.Name, UseItemText = definition.UseItemText, UsedAltarText = definition.UsedAltarText, CantOfferText = definition.CantOfferText, WrongOfferText = definition.WrongOfferText, IncompleteOfferText = definition.IncompleteOfferText, BossItem = definition.BossItem, BossItems = definition.BossItems, BossPrefab = definition.BossPrefab, ItemPrefab = definition.ItemPrefab, RenderSpawnAreaGizmos = definition.RenderSpawnAreaGizmos, AlertOnSpawn = definition.AlertOnSpawn, UseItemStands = definition.UseItemStands, ItemStandPrefix = definition.ItemStandPrefix, ItemStandMaxRange = definition.ItemStandMaxRange, RespawnMinutes = definition.RespawnMinutes, CllcInfusion = definition.CllcInfusion, CllcEffect = definition.CllcEffect, CllcBossEffect = definition.CllcBossEffect }; } private static void LogLoadedLocationEntry(LocationConfigurationEntry entry) { string text = ((entry.ItemStands == null) ? "(none)" : JoinDiagnosticValues(entry.ItemStands.Where(HasItemStandOverride).SelectMany(delegate(LocationItemStandDefinition itemStand) { IEnumerable<string> supportedItems = itemStand.SupportedItems; return supportedItems ?? Enumerable.Empty<string>(); }))); string item = $"config|{entry.Prefab}|{text}|{entry.ItemStands?.Count ?? 0}"; if (LocationDiagnosticLogs.Add(item)) { DropNSpawnPlugin.DropNSpawnLogger.LogDebug((object)$"Loaded location override entry: prefab='{entry.Prefab}', hasOfferingBowl={HasOfferingBowlOverride(entry.OfferingBowl)}, hasItemStands={HasItemStandOverride(entry.ItemStands)}, hasVegvisir={HasVegvisirOverride(entry.Vegvisirs)}, itemStands.supportedItems=[{text}]."); } } private static void NormalizeOfferingBowlDefinition(LocationOfferingBowlDefinition? definition) { if (definition != null) { definition.BossItem = definition.BossItem?.Trim(); definition.BossPrefab = definition.BossPrefab?.Trim(); definition.ItemPrefab = definition.ItemPrefab?.Trim(); definition.SetGlobalKey = definition.SetGlobalKey?.Trim(); definition.ItemStandPrefix = definition.ItemStandPrefix?.Trim(); definition.Data = NormalizeOptionalString(definition.Data); definition.Fields = NormalizeOptionalStringDictionary(definition.Fields); definition.Objects = NormalizeOptionalStringList(definition.Objects); FloatRangeDefinition? spawnBossDistance = definition.SpawnBossDistance; if (spawnBossDistance != null && spawnBossDistance.HasValues()) { definition.SpawnBossMinDistance = RangeFormatting.GetMin(definition.SpawnBossDistance, definition.SpawnBossMinDistance); definition.SpawnBossMaxDistance = RangeFormatting.GetMax(definition.SpawnBossDistance, definition.SpawnBossMinDistance, definition.SpawnBossMaxDistance); } definition.CllcInfusion = definition.CllcInfusion?.Trim(); definition.CllcEffect = definition.CllcEffect?.Trim(); definition.CllcBossEffect = definition.CllcBossEffect?.Trim(); } } private static string? NormalizeOptionalString(string? value) { if (value == null) { return null; } string text = value.Trim(); return (text.Length == 0) ? null : text; } private static List<string>? NormalizeOptionalStringList(List<string>? values) { if (values == null) { return null; } List<string> list = (from value in values select (value ?? "").Trim() into value where value.Length > 0 select value).ToList(); return (list.Count == 0) ? null : list; } private static Dictionary<string, string>? NormalizeOptionalStringDictionary(Dictionary<string, string>? values) { if (values == null) { return null; } Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); foreach (KeyValuePair<string, string> value2 in values) { value2.Deconstruct(out var key, out var value); string text = key; string text2 = value; string text3 = (text ?? "").Trim(); if (text3.Length != 0) { dictionary[text3] = (text2 ?? "").Trim(); } } return (dictionary.Count == 0) ? null : dictionary; } private static void NormalizeVegvisirDefinitions(List<LocationVegvisirDefinition>? definitions) { if (definitions == null) { return; } foreach (LocationVegvisirDefinition definition in definitions) { NormalizeVegvisirDefinition(definition); } } private static void NormalizeVegvisirDefinition(LocationVegvisirDefinition? definition) { if (definition == null) { return; } definition.Path = (definition.Path ?? "").Trim(); definition.ExpectedLocations = (from value in definition.ExpectedLocations?.Select((string value) => (value ?? "").Trim()) where value.Length > 0 select value).Distinct<string>(StringComparer.OrdinalIgnoreCase).ToList(); definition.Name = definition.Name?.Trim(); definition.UseText = definition.UseText?.Trim(); definition.HoverName = definition.HoverName?.Trim(); definition.SetsGlobalKey = definition.SetsGlobalKey?.Trim(); definition.SetsPlayerKey = definition.SetsPlayerKey?.Trim(); if (definition.Locations == null) { return; } foreach (LocationVegvisirTargetDefinition location in definition.Locations) { location.LocationName = (location.LocationName ?? "").Trim(); location.PinName = location.PinName?.Trim(); location.PinType = location.PinType?.Trim(); } } private static void NormalizeItemStandDefinitions(List<LocationItemStandDefinition>? definitions) { if (definitions == null) { return; } foreach (LocationItemStandDefinition definition in definitions) { NormalizeItemStandDefinition(definition); } } private static void NormalizeItemStandDefinition(LocationItemStandDefinition? definition) { if (definition != null) { definition.Path = definition.Path?.Trim(); definition.Name = definition.Name?.Trim(); definition.OrientationType = definition.OrientationType?.Trim(); definition.GuardianPower = definition.GuardianPower?.Trim(); definition.SupportedTypes = (from value in definition.SupportedTypes?.Select((string value) => (value ?? "").Trim()) where value.Length > 0 select value).Distinct<string>(StringComparer.OrdinalIgnoreCase).ToList(); definition.SupportedItems = (from value in definition.SupportedItems?.Select((string value) => (value ?? "").Trim()) where value.Length > 0 select value).Distinct<string>(StringComparer.OrdinalIgnoreCase).ToList(); definition.UnsupportedItems = (from value in definition.UnsupportedItems?.Select((string value) => (value ?? "").Trim()) where value.Length > 0 select value).Distinct<string>(StringComparer.OrdinalIgnoreCase).ToList(); } } private static void FinalizeNormalizedEntry(LocationConfigurationEntry entry) { entry.RuleId = BuildRuleId(entry); } private static string BuildRuleId(LocationConfigurationEntry entry) { LocationConfigurationEntry entry2 = new LocationConfigurationEntry { Prefab = entry.Prefab, Enabled = true, Conditions = entry.Conditions, OfferingBowl = entry.OfferingBowl, ItemStands = entry.ItemStands, Vegvisirs = entry.Vegvisirs }; return entry.Prefab + ":" + NetworkPayloadSyncSupport.ComputeLocationEntrySignature(entry2); } private static void StripRedundantLocationComponentConditions(LocationConfigurationEntry entry, string source) { StripRedundantLocationFilter(entry.Prefab, "conditions", entry.Conditions, source); } private static void StripRedundantLocationFilter(string prefabName, string componentName, ConditionsDefinition? conditions, string source) { if (conditions?.Locations != null && conditions.Locations.Count != 0) { conditions.Locations = null; string text = (string.IsNullOrWhiteSpace(prefabName) ? "(missing prefab)" : prefabName); string item = source + "|" + text + "|" + componentName; if (RedundantLocationConditionWarnings.Add(item)) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("Entry '" + text + "' in '" + source + "' uses '" + componentName + ".conditions.locations', but " + componentName + " is already scoped by the parent location prefab. This filter is ignored.")); } } } private static bool HasOverride(LocationConfigurationEntry entry) { return HasOfferingBowlOverride(entry.OfferingBowl) || HasItemStandOverride(entry.ItemStands) || HasVegvisirOverride(entry.Vegvisirs); } private static bool HasOfferingBowlOverride(LocationOfferingBowlDefinition? definition) { if (definition == null) { return false; } int result; if (definition.Name == null && definition.UseItemText == null && definition.UsedAltarText == null && definition.CantOfferText == null && definition.WrongOfferText == null && definition.IncompleteOfferText == null && definition.BossItem == null && !definition.BossItems.HasValue && definition.BossPrefab == null && definition.ItemPrefab == null && definition.SetGlobalKey == null && !definition.RenderSpawnAreaGizmos.HasValue && !definition.AlertOnSpawn.HasValue && !definition.SpawnBossDelay.HasValue) { FloatRangeDefinition? spawnBossDistance = definition.SpawnBossDistance; if ((spawnBossDistance == null || !spawnBossDistance.HasValues()) && !definition.SpawnBossMaxDistance.HasValue && !definition.SpawnBossMinDistance.HasValue && !definition.SpawnBossMaxYDistance.HasValue && !definition.GetSolidHeightMargin.HasValue && !definition.EnableSolidHeightCheck.HasValue && !definition.SpawnPointClearingRadius.HasValue && !definition.SpawnYOffset.HasValue && !definition.UseItemStands.HasValue && definition.ItemStandPrefix == null && !definition.ItemStandMaxRange.HasValue && !definition.RespawnMinutes.HasValue && definition.Data == null && definition.Fields == null && definition.Objects == null) { result = (HasCllcEffectOverride(definition.CllcInfusion, definition.CllcEffect, definition.CllcBossEffect) ? 1 : 0); goto IL_01d3; } } result = 1; goto IL_01d3; IL_01d3: return (byte)result != 0; } private static bool HasClientVisibleOfferingBowlOverride(LocationOfferingBowlDefinition? definition) { if (definition == null) { return false; } return definition.Name != null || definition.UseItemText != null || definition.UsedAltarText != null || definition.CantOfferText != null || definition.WrongOfferText != null || definition.IncompleteOfferText != null || definition.BossItem != null || definition.BossItems.HasValue || definition.BossPrefab != null || definition.ItemPrefab != null || definition.RenderSpawnAreaGizmos.HasValue || definition.AlertOnSpawn.HasValue || definition.UseItemStands.HasValue || definition.ItemStandPrefix != null || definition.ItemStandMaxRange.HasValue || definition.RespawnMinutes.HasValue || HasCllcEffectOverride(definition.CllcInfusion, definition.CllcEffect, definition.CllcBossEffect); } private static bool HasCllcEffectOverride(string? infusion, string? effect, string? bossEffect) { return !string.IsNullOrWhiteSpace(infusion) || !string.IsNullOrWhiteSpace(effect) || !string.IsNullOrWhiteSpace(bossEffect); } private static CllcDefinition? BuildRuntimeCllcDefinition(string? infusion, string? effect, string? bossEffect) { if (!HasCllcEffectOverride(infusion, effect, bossEffect)) { return null; } return new CllcDefinition { Infusion = infusion, ExtraEffect = effect, BossAffix = bossEffect }; } private static bool HasVegvisirOverride(List<LocationVegvisirDefinition>? definitions) { return definitions?.Any(HasVegvisirOverride) ?? false; } private static bool HasVegvisirOverride(LocationVegvisirDefinition? definition) { if (definition == null) { return false; } return definition.Name != null || definition.UseText != null || definition.HoverName != null || definition.SetsGlobalKey != null || definition.SetsPlayerKey != null || definition.Locations != null; } private static bool HasItemStandOverride(List<LocationItemStandDefinition>? definitions) { return definitions?.Any(HasItemStandOverride) ?? false; } private static bool HasLooseItemStandOverride(List<LocationItemStandDefinition>? definitions) { return definitions?.Any(HasLooseItemStandOverride) ?? false; } private static bool HasItemStandOverride(LocationItemStandDefinition? definition) { if (definition == null) { return false; } return definition.Name != null || definition.CanBeRemoved.HasValue || definition.AutoAttach.HasValue || definition.OrientationType != null || definition.SupportedTypes != null || definition.SupportedItems != null || definition.UnsupportedItems != null || definition.PowerActivationDelay.HasValue || definition.GuardianPower != null; } private static bool HasLooseItemStandOverride(LocationItemStandDefinition? definition) { return HasItemStandOverride(definition); } private static bool HasConditions(ConditionsDefinition? conditions) { return DropConditionEvaluator.HasConditions(conditions); } [IteratorStateMachine(typeof(<EnumerateOverrideConfigurationPaths>d__131))] private static IEnumerable<string> EnumerateOverrideConfigurationPaths() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <EnumerateOverrideConfigurationPaths>d__131(-2); } [IteratorStateMachine(typeof(<EnumerateSupplementalOverrideConfigurationPaths>d__132))] private static IEnumerable<string> EnumerateSupplementalOverrideConfigurationPaths() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <EnumerateSupplementalOverrideConfigurationPaths>d__132(-2); } private static bool IsOverrideConfigurationFileName(string fileName) { if (string.IsNullOrWhiteSpace(fileName)) { return false; } return fileName.Equals(DropNSpawnPlugin.GetYamlDomainFilePrefix("location") + ".yml", StringComparison.OrdinalIgnoreCase) || fileName.Equals(DropNSpawnPlugin.GetYamlDomainFilePrefix("location") + ".yaml", StringComparison.OrdinalIgnoreCase) || (fileName.StartsWith(DropNSpawnPlugin.GetYamlDomainSupplementalPrefix("location"), StringComparison.OrdinalIgnoreCase) && (fileName.EndsWith(".yml", StringComparison.OrdinalIgnoreCase) || fileName.EndsWith(".yaml", StringComparison.OrdinalIgnoreCase))); } private static void CaptureSnapshotsIfNeeded() { if (_snapshotsCaptured || (Object)(object)ZoneSystem.instance == (Object)null) { return; } foreach (ZoneLocation location in ZoneSystem.instance.m_locations) { CaptureSnapshot(location); } _snapshotsCaptured = true; DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)$"Captured {Snapshots.Count} location snapshot(s)."); } private static void ResetReferenceSnapshots() { Snapshots.Clear(); SnapshotsByPrefab.Clear(); DuplicateComponentWarnings.Clear(); _snapshotsCaptured = false; } private static void ResetRuntimeState(bool preserveLiveRegistries) { ClearQueuedReconcileState(); CatalogsByPrefab.Clear(); LiveLocationSnapshots.Clear(); PendingOfferingBowlNearbyCharacterIds.Clear(); LooseItemStandSnapshots.Clear(); TrackedLooseItemStandPrefabs.Clear(); LooseItemStandAuthoredPathsByInstance.Clear(); if (!preserveLiveRegistries) { LiveLocationsByPrefab.Clear(); LiveLocationPrefabsByInstance.Clear(); } } private static void ClearQueuedReconcileState() { _reconcileQueueEpoch++; PendingLocationReconciles.Clear(); PendingLocationReconcileIds.Clear(); SuppressedQueuedLocationReconciles.Clear(); PendingLocationRootReconciles.Clear(); PendingLocationRootReconcileIds.Clear(); PendingLooseOfferingBowlOverrides.Clear(); PendingLooseOfferingBowlOverrideIds.Clear(); } private static void RefreshSnapshots() { ResetReferenceSnapshots(); CaptureSnapshotsIfNeeded(); } private static void CaptureSnapshot(ZoneLocation location) { //IL_0063: Unknown result type (might be due to invalid IL or missing references) if (!location.m_prefab.IsValid) { return; } string text = (location.m_prefab.Name ?? "").Trim(); if (text.Length == 0 || SnapshotsByPrefab.ContainsKey(text)) { return; } location.m_prefab.Load(); GameObject rootPrefab = location.m_prefab.Asset; if ((Object)(object)rootPrefab == (Object)null) { return; } List<OfferingBowl> list = new List<OfferingBowl>(); List<ItemStand> list2 = new List<ItemStand>(); List<Vegvisir> list3 = new List<Vegvisir>(); CollectLocationRuntimeComponents(rootPrefab.transform, list, list2, list3); OfferingBowl[] array = list.ToArray(); ItemStand[] array2 = list2.ToArray(); Vegvisir[] array3 = list3.ToArray(); if (array.Length != 0 || array2.Length != 0 || array3.Length != 0) { WarnDuplicateComponent(text, "OfferingBowl", array.Length); LocationSnapshot locationSnapshot = new LocationSnapshot { Prefab = text, OfferingBowl = ((array.Length != 0) ? CaptureOfferingBowlSnapshot(array[0]) : null), ItemStands = array2.Select((ItemStand itemStand) => CapturePathScopedItemStandSnapshot(rootPrefab.transform, itemStand)).OrderBy<PathScopedItemStandSnapshot, string>((PathScopedItemStandSnapshot itemStand) => itemStand.Path, StringComparer.Ordinal).ToList(), Vegvisirs = array3.Select((Vegvisir vegvisir) => CaptureVegvisirSnapshot(rootPrefab.transform, vegvisir)).OrderBy<PathScopedVegvisirSnapshot, string>((PathScopedVegvisirSnapshot vegvisir) => vegvisir.Path, StringComparer.Ordinal).ToList() }; Snapshots.Add(locationSnapshot); SnapshotsByPrefab[text] = locationSnapshot; } } private static void WarnDuplicateComponent(string prefabName, string componentName, int count) { if (count > 1) { string item = prefabName + "@" + componentName; if