using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Security; using System.Security.Cryptography; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Threading; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using Data; using ExpandWorldData; using HarmonyLib; using JetBrains.Annotations; using Microsoft.CodeAnalysis; using ServerSync; using Splatform; using TMPro; using UnityEngine; using UnityEngine.SceneManagement; using UnityEngine.UI; using YamlDotNet.Core; using YamlDotNet.Core.Events; using YamlDotNet.Core.ObjectPool; using YamlDotNet.Core.Tokens; using YamlDotNet.Helpers; using YamlDotNet.RepresentationModel; using YamlDotNet.Serialization; using YamlDotNet.Serialization.BufferedDeserialization; using YamlDotNet.Serialization.BufferedDeserialization.TypeDiscriminators; using YamlDotNet.Serialization.Callbacks; using YamlDotNet.Serialization.Converters; using YamlDotNet.Serialization.EventEmitters; using YamlDotNet.Serialization.NamingConventions; using YamlDotNet.Serialization.NodeDeserializers; using YamlDotNet.Serialization.NodeTypeResolvers; using YamlDotNet.Serialization.ObjectFactories; using YamlDotNet.Serialization.ObjectGraphTraversalStrategies; using YamlDotNet.Serialization.ObjectGraphVisitors; using YamlDotNet.Serialization.Schemas; using YamlDotNet.Serialization.TypeInspectors; using YamlDotNet.Serialization.TypeResolvers; using YamlDotNet.Serialization.Utilities; using YamlDotNet.Serialization.ValueDeserializers; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("DropNSpawn")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("sighsorry")] [assembly: AssemblyProduct("DropNSpawn")] [assembly: AssemblyCopyright("Copyright © 2021")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("4358610B-F3F4-4843-B7AF-98B7BC60DCDE")] [assembly: AssemblyFileVersion("1.2.1")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.2.1.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 { private readonly string k__BackingField; public string Name => k__BackingField; public ExtensionMarkerAttribute(string name) { k__BackingField = name; } } } namespace LocalizationManager { [PublicAPI] public class Localizer { private static readonly Dictionary>> PlaceholderProcessors; private static readonly Dictionary> loadedTexts; private static readonly ConditionalWeakTable localizationLanguage; private static readonly List> localizationObjects; private static BaseUnityPlugin? _plugin; private static readonly List fileExtensions; private static BaseUnityPlugin plugin { get { //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Expected O, but got Unknown if (_plugin == null) { IEnumerable 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> value2)) { text = value2.Aggregate(text, (string current, KeyValuePair> kv) => current.Replace("{" + kv.Key + "}", kv.Value())); } localization.AddWord(key, text); } public static void AddPlaceholder(string key, string placeholder, ConfigEntry config, Func? convertConfigValue = null) where T : notnull { string key2 = key; string placeholder2 = placeholder; Func convertConfigValue2 = convertConfigValue; ConfigEntry config2 = config; if (convertConfigValue2 == null) { convertConfigValue2 = (T val) => val.ToString(); } if (!PlaceholderProcessors.ContainsKey(key2)) { PlaceholderProcessors[key2] = new Dictionary>(); } 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> list = new List>(); foreach (WeakReference localizationObject in localizationObjects) { if (localizationObject.TryGetTarget(out var target)) { Dictionary dictionary = loadedTexts[localizationLanguage.GetOrCreateValue(target)]; if (!target.m_translations.ContainsKey(key)) { dictionary[key] = text; target.AddWord(key, text); } } else { list.Add(localizationObject); } } foreach (WeakReference 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(__instance)); } localizationLanguage.Add(__instance, language); Dictionary dictionary = new Dictionary(); 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 dictionary2 = new DeserializerBuilder().IgnoreFields().Build().Deserialize>(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 item2 in new DeserializerBuilder().IgnoreFields().Build().Deserialize>(text2) ?? new Dictionary()) { dictionary2[item2.Key] = item2.Value; } } loadedTexts[language] = dictionary2; foreach (KeyValuePair item3 in dictionary2) { UpdatePlaceholderText(__instance, item3.Key); } } static Localizer() { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Expected O, but got Unknown //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Expected O, but got Unknown //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Expected O, but got Unknown PlaceholderProcessors = new Dictionary>>(); loadedTexts = new Dictionary>(); localizationLanguage = new ConditionalWeakTable(); localizationObjects = new List>(); fileExtensions = new List(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 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? ItemStands { get; set; } [YamlMember(Order = 6)] public List? Vegvisirs { get; set; } [YamlMember(Order = 7)] public List? Runestones { get; set; } [YamlMember(Order = 8)] public LocationRunestoneGlobalPinsDefinition? RunestoneGlobalPins { get; set; } [YamlIgnore] public string RuleId { get; set; } = ""; [YamlIgnore] public string? SourcePath { get; set; } [YamlIgnore] public int SourceLine { get; set; } [YamlIgnore] public int SourceColumn { get; set; } } internal sealed class LocationReferenceEntry { [YamlMember(Order = 1)] public string Prefab { get; set; } = ""; [YamlMember(Order = 2)] public LocationOfferingBowlDefinition? OfferingBowl { get; set; } [YamlMember(Order = 3)] public List? ItemStands { get; set; } [YamlMember(Order = 4)] public List? Vegvisirs { get; set; } [YamlMember(Order = 5)] public List? Runestones { 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? Fields { get; set; } [YamlMember(Order = 29)] public List? Objects { get; set; } } internal sealed class LocationVegvisirDefinition { [YamlMember(Order = 1)] public string Path { get; set; } = ""; [YamlMember(Order = 2)] public List? 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? 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? SupportedTypes { get; set; } [YamlMember(Order = 7)] public List? SupportedItems { get; set; } [YamlMember(Order = 8)] public List? UnsupportedItems { get; set; } [YamlMember(Order = 9)] public float? PowerActivationDelay { get; set; } [YamlMember(Order = 10)] public string? GuardianPower { get; set; } } internal sealed class LocationRunestoneDefinition { [YamlMember(Order = 1)] public string Path { get; set; } = ""; [YamlMember(Order = 2)] public string? ExpectedLocationName { get; set; } [YamlMember(Order = 3)] public string? ExpectedLabel { get; set; } [YamlMember(Order = 4)] public string? ExpectedTopic { get; set; } [YamlMember(Order = 5)] public string? Name { get; set; } [YamlMember(Order = 6)] public string? Topic { get; set; } [YamlMember(Order = 7)] public string? Label { get; set; } [YamlMember(Order = 8)] public string? Text { get; set; } [YamlMember(Order = 9)] public List? RandomTexts { get; set; } [YamlMember(Order = 10)] public string? LocationName { get; set; } [YamlMember(Order = 11)] public string? PinName { get; set; } [YamlMember(Order = 12)] public string? PinType { get; set; } [YamlMember(Order = 13)] public bool? ShowMap { get; set; } [YamlMember(Order = 14)] public float? Chance { get; set; } } internal sealed class LocationRunestoneTextDefinition { [YamlMember(Order = 1)] public string? Topic { get; set; } [YamlMember(Order = 2)] public string? Label { get; set; } [YamlMember(Order = 3)] public string? Text { get; set; } } internal sealed class LocationRunestoneGlobalPinsDefinition { [YamlMember(Order = 1)] public List? TargetLocations { get; set; } } internal sealed class LocationRunestoneGlobalPinTargetDefinition { [YamlMember(Order = 1)] public string LocationName { get; set; } = ""; [YamlMember(Order = 2)] public float? Chance { get; set; } [YamlMember(Order = 3)] public List? SourceBiomes { get; set; } [YamlMember(Order = 4)] public string? PinName { get; set; } [YamlMember(Order = 5)] public string? PinType { 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; } [YamlMember(Order = 6)] public float? Weight { 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; } } 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 Locations { get; set; } = new List(); } private sealed class PathScopedVegvisirSnapshot { public string Path { get; set; } = ""; public VegvisirSnapshot Snapshot { get; set; } = new VegvisirSnapshot(); } private sealed class RunestoneTextSnapshot { public string Topic { get; set; } = ""; public string Label { get; set; } = ""; public string Text { get; set; } = ""; } private sealed class RunestoneSnapshot { public string Name { get; set; } = ""; public string Topic { get; set; } = ""; public string Label { get; set; } = ""; public string Text { get; set; } = ""; public List RandomTexts { get; set; } = new List(); public string LocationName { get; set; } = ""; public string PinName { get; set; } = ""; public string PinType { get; set; } = ""; public bool ShowMap { get; set; } } private sealed class RunestonePinChanceState { public string RollKey { get; set; } = ""; public bool AllowsPin { get; set; } = true; } private sealed class PathScopedRunestoneSnapshot { public string Path { get; set; } = ""; public RunestoneSnapshot Snapshot { get; set; } = new RunestoneSnapshot(); } 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 SupportedTypes { get; set; } = new List(); public List SupportedItems { get; set; } = new List(); public List UnsupportedItems { get; set; } = new List(); 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 ItemStands { get; set; } = new List(); public List Vegvisirs { get; set; } = new List(); public List Runestones { get; set; } = new List(); } private sealed class LiveLocationSnapshot { public string Prefab { get; set; } = ""; public PathScopedOfferingBowlSnapshot? OfferingBowl { get; set; } public List ItemStands { get; set; } = new List(); public List Vegvisirs { get; set; } = new List(); public List Runestones { get; set; } = new List(); } private sealed class SyncedLocationConfigurationState { public List Configuration { get; set; } = new List(); public Dictionary> ActiveEntriesByPrefab { get; } = new Dictionary>(StringComparer.OrdinalIgnoreCase); public Dictionary> LooseItemStandEntriesByPrefab { get; } = new Dictionary>(StringComparer.OrdinalIgnoreCase); public string ConfigurationSignature { get; set; } = ""; } private sealed class LocationComponentCatalog { public string Prefab { get; set; } = ""; public string? OfferingBowlPath { get; set; } public List ItemStandPaths { get; set; } = new List(); public List VegvisirPaths { get; set; } = new List(); public List RunestonePaths { get; set; } = new List(); } private sealed class LocationRuntimeComponents { public Transform Root { get; set; } public List OfferingBowls { get; } = new List(); public OfferingBowl? PrimaryOfferingBowl { get; set; } public List ItemStands { get; } = new List(); public List Vegvisirs { get; } = new List(); public List Runestones { get; } = new List(); public Dictionary OfferingBowlsByPath { get; set; } = new Dictionary(StringComparer.Ordinal); public Dictionary ItemStandsByPath { get; set; } = new Dictionary(StringComparer.Ordinal); public Dictionary VegvisirsByPath { get; set; } = new Dictionary(StringComparer.Ordinal); public Dictionary RunestonesByPath { get; set; } = new Dictionary(StringComparer.Ordinal); public List RelevantItemStands { get; set; } = new List(); } private sealed class LocationProxyObservationState { public ZNetView? NView { get; set; } public uint LastObservedDataRevision { get; set; } = uint.MaxValue; public string LastObservedAlias { get; set; } = ""; public int StablePollCount { get; set; } public int LastObservedDemandEpoch { get; set; } = -1; } private sealed class LocationAliasRefreshRequestState { public int LastQueuedAliasEpoch { get; set; } = -1; public int LastQueuedFrame { get; set; } = -1; public string LastQueuedResolvedPrefabName { get; set; } = ""; } private sealed class PendingLocationProxyAliasZdoFlush { public int Epoch { get; set; } public int DueFrame { get; set; } public uint DataRevision { get; set; } } private enum LooseOfferingBowlOverrideMode { RestoreOnly, Apply } private readonly struct LooseOfferingBowlOverrideStamp : IEquatable { public int ReconcileQueueEpoch { get; } public int RegistryVersion { get; } public LooseOfferingBowlOverrideMode Mode { get; } public int RootInstanceId { get; } public string PrefabName { get; } public string ConfigurationSignature { get; } public int EntryPlanCount { get; } public int RelevantItemStandCount { get; } public int RelevantItemStandSignature { get; } public LooseOfferingBowlOverrideStamp(int reconcileQueueEpoch, int registryVersion, LooseOfferingBowlOverrideMode mode, int rootInstanceId, string prefabName, string configurationSignature, int entryPlanCount, int relevantItemStandCount, int relevantItemStandSignature) { ReconcileQueueEpoch = reconcileQueueEpoch; RegistryVersion = registryVersion; Mode = mode; RootInstanceId = rootInstanceId; PrefabName = prefabName ?? ""; ConfigurationSignature = configurationSignature ?? ""; EntryPlanCount = entryPlanCount; RelevantItemStandCount = relevantItemStandCount; RelevantItemStandSignature = relevantItemStandSignature; } public bool Equals(LooseOfferingBowlOverrideStamp other) { if (ReconcileQueueEpoch == other.ReconcileQueueEpoch && RegistryVersion == other.RegistryVersion && Mode == other.Mode && RootInstanceId == other.RootInstanceId && StringComparer.Ordinal.Equals(PrefabName, other.PrefabName) && StringComparer.Ordinal.Equals(ConfigurationSignature, other.ConfigurationSignature) && EntryPlanCount == other.EntryPlanCount && RelevantItemStandCount == other.RelevantItemStandCount) { return RelevantItemStandSignature == other.RelevantItemStandSignature; } return false; } public override bool Equals(object? obj) { if (obj is LooseOfferingBowlOverrideStamp other) { return Equals(other); } return false; } public override int GetHashCode() { //IL_0002: Unknown result type (might be due to invalid IL or missing references) HashCode val = default(HashCode); ((HashCode)(ref val)).Add(ReconcileQueueEpoch); ((HashCode)(ref val)).Add(RegistryVersion); ((HashCode)(ref val)).Add((int)Mode); ((HashCode)(ref val)).Add(RootInstanceId); ((HashCode)(ref val)).Add(PrefabName, (IEqualityComparer)StringComparer.Ordinal); ((HashCode)(ref val)).Add(ConfigurationSignature, (IEqualityComparer)StringComparer.Ordinal); ((HashCode)(ref val)).Add(EntryPlanCount); ((HashCode)(ref val)).Add(RelevantItemStandCount); ((HashCode)(ref val)).Add(RelevantItemStandSignature); return ((HashCode)(ref val)).ToHashCode(); } } private sealed class LooseOfferingBowlOverrideState { public bool HasLastAppliedStamp { get; set; } public LooseOfferingBowlOverrideStamp LastAppliedStamp { get; set; } } private readonly struct PendingLocationProxyObservation { public LocationProxy Proxy { get; } public int ProxyInstanceId { get; } public int Epoch { get; } public int DueFrame { get; } public PendingLocationProxyObservation(LocationProxy proxy, int proxyInstanceId, int epoch, int dueFrame) { Proxy = proxy; ProxyInstanceId = proxyInstanceId; Epoch = epoch; DueFrame = dueFrame; } } private sealed class ScheduledFrameQueue { private readonly SortedDictionary> _buckets = new SortedDictionary>(); public int Count { get; private set; } public void Enqueue(int dueFrame, T item) { if (!_buckets.TryGetValue(dueFrame, out RingBufferQueue value)) { value = new RingBufferQueue(); _buckets[dueFrame] = value; } value.Enqueue(item); Count++; } public bool TryPeekDueFrame(out int dueFrame) { using (SortedDictionary>.Enumerator enumerator = _buckets.GetEnumerator()) { if (enumerator.MoveNext()) { dueFrame = enumerator.Current.Key; return true; } } dueFrame = int.MaxValue; return false; } public bool HasDueItems(int currentFrame) { if (TryPeekDueFrame(out var dueFrame)) { return dueFrame <= currentFrame; } return false; } public bool TryDequeue(out int dueFrame, out T item) { while (TryPeekDueFrame(out dueFrame)) { RingBufferQueue ringBufferQueue = _buckets[dueFrame]; if (!ringBufferQueue.TryDequeue(out item)) { _buckets.Remove(dueFrame); continue; } Count--; if (ringBufferQueue.Count == 0) { _buckets.Remove(dueFrame); } return true; } dueFrame = int.MaxValue; item = default(T); return false; } public void Clear() { _buckets.Clear(); Count = 0; } } private sealed class AuthoredItemStandSlotTemplate { public string Path { get; set; } = ""; public Vector3 OfferingBowlLocalOffset { get; set; } } private enum PendingLocationRootPhase { TraverseHierarchy, 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; } public int Epoch { get; set; } public PendingLocationRootPhase Phase { get; set; } public List? Locations { get; set; } public List? TraversalStack { get; set; } public Dictionary? RuntimeComponentsByLocationId { get; set; } public int NextIndex { get; set; } } private readonly struct PendingLocationReconcile { public Location Location { get; } public int LocationInstanceId { get; } public int Epoch { get; } public PendingLocationReconcile(Location location, int locationInstanceId, int epoch) { Location = location; LocationInstanceId = locationInstanceId; 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; } } private sealed class LocationApplyOperations : IStandardBaselineDesiredStateOperations { public static LocationApplyOperations Instance { get; } = new LocationApplyOperations(); public string DomainKey => "location"; public BaselineDesiredStateCapabilities Capabilities => BaselineDesiredStateCapabilities.Validation | BaselineDesiredStateCapabilities.LiveApply; public void Validate(LocationDesiredState desiredState) { ValidateLocationDesiredState(desiredState); } public void RestoreStaticBaseline(LocationDesiredState desiredState) { RestoreLocationStaticBaseline(desiredState); } public void ApplyDesiredStateToStaticBaseline(LocationDesiredState desiredState) { ApplyLocationDesiredStateToStaticBaseline(desiredState); } public void PrepareLiveBaseline(LocationDesiredState desiredState) { PrepareLocationLiveBaseline(desiredState); } public void ApplyDesiredStateToLive(LocationDesiredState desiredState) { ApplyLocationDesiredStateToLive(desiredState); } public void Commit(LocationDesiredState desiredState) { RecordAppliedState(desiredState.GameDataSignature, desiredState.DomainEnabled, desiredState.CurrentEntrySignatures); } public void HandleFailure(LocationDesiredState desiredState, StandardApplyFailureContext failureContext) { if (failureContext.LiveStageFailed && desiredState.ReloadPrefabs.Count != 0) { QueueRegisteredLocationReconciles(desiredState.ReloadPrefabs); } } } private sealed class CompiledLocationOfferingBowlPlan { public LocationOfferingBowlDefinition Definition { get; set; } = new LocationOfferingBowlDefinition(); } private sealed class CompiledLocationItemStandPlan { public LocationItemStandDefinition Definition { get; set; } = new LocationItemStandDefinition(); public string Path { get; set; } = ""; public bool HasPath { get; set; } } private sealed class CompiledLocationVegvisirPlan { public LocationVegvisirDefinition Definition { get; set; } = new LocationVegvisirDefinition(); } private sealed class CompiledLocationRunestonePlan { public LocationRunestoneDefinition Definition { get; set; } = new LocationRunestoneDefinition(); } private sealed class CompiledLocationEntryPlan { public ConditionsDefinition? Conditions { get; set; } public bool HasConditions { get; set; } public CompiledLocationOfferingBowlPlan? OfferingBowl { get; set; } public List ItemStands { get; } = new List(); public List Vegvisirs { get; } = new List(); public List Runestones { get; } = new List(); } private sealed class CompiledLocationPrefabPlan { public List ActiveEntryPlans { get; } = new List(); public List LooseItemStandPlans { get; } = new List(); } private sealed class LocationRuntimeConfigurationState { public static LocationRuntimeConfigurationState Empty { get; } = new LocationRuntimeConfigurationState(); public Dictionary PlansByPrefab { get; } = new Dictionary(StringComparer.OrdinalIgnoreCase); } private sealed class LocationDesiredState { public StandardDomainApplyPlan ApplyPlan { get; set; } public int GameDataSignature { get; set; } public Dictionary CurrentEntrySignatures { get; set; } = EmptyEntrySignatures; public bool DomainEnabled { get; set; } public bool QueueLiveReconcile { get; set; } public HashSet ReloadPrefabs { get; set; } = new HashSet(StringComparer.OrdinalIgnoreCase); public LocationRuntimeConfigurationState RuntimeConfigurationState { get; set; } = LocationRuntimeConfigurationState.Empty; } private readonly struct InvalidEntryWarningSuppressionScope : IDisposable { private readonly bool _active; public InvalidEntryWarningSuppressionScope(bool active) { _active = active; if (_active) { _invalidEntryWarningSuppressionDepth++; } } public void Dispose() { if (_active) { _invalidEntryWarningSuppressionDepth--; } } } internal enum OfferingBowlBlockReason { None, SameBossNearby, RespawnCooldownActive } internal readonly struct OfferingBowlBlockResult { internal static OfferingBowlBlockResult None => default(OfferingBowlBlockResult); public bool Blocked { get; } public OfferingBowlBlockReason Reason { get; } public OfferingBowlBlockResult(bool blocked, OfferingBowlBlockReason reason) { Blocked = blocked; Reason = reason; } } private sealed class RunestoneGlobalPinsRollState { public string RollKey { get; set; } = ""; public ResolvedRunestoneGlobalPin? Pin { get; set; } } private sealed class RunestoneGlobalPinCandidate { public float Chance { get; set; } public ResolvedRunestoneGlobalPin Pin { get; set; } = new ResolvedRunestoneGlobalPin(); } private sealed class ResolvedRunestoneGlobalPin { public string LocationName { get; set; } = ""; public string PinName { get; set; } = ""; public PinType PinType { get; set; } = (PinType)3; public Vector3 Position { get; set; } } private sealed class RunestoneGlobalPinLocationIndex { public int ZoneSystemId { get; set; } public int LocationInstanceCount { get; set; } public Dictionary> InstancesByName { get; } = new Dictionary>(StringComparer.OrdinalIgnoreCase); } [CompilerGenerated] private sealed class d__169 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private string <>2__current; private int <>l__initialThreadId; private HashSet 5__2; private Dictionary>.Enumerator <>7__wrap2; private List.Enumerator <>7__wrap3; private LocationConfigurationEntry 5__5; private IEnumerator <>7__wrap5; private List.Enumerator <>7__wrap6; string IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__169(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if ((uint)(num - -7) <= 4u || (uint)(num - 1) <= 1u) { try { if ((uint)(num - -7) <= 3u || (uint)(num - 1) <= 1u) { try { switch (num) { case -5: case 1: try { } finally { <>m__Finally3(); } break; case -7: case -6: case 2: try { if (num == -7 || num == 2) { try { } finally { <>m__Finally5(); } } } finally { <>m__Finally4(); } break; } } finally { <>m__Finally2(); } } } finally { <>m__Finally1(); } } 5__2 = null; <>7__wrap2 = default(Dictionary>.Enumerator); <>7__wrap3 = default(List.Enumerator); 5__5 = null; <>7__wrap5 = null; <>7__wrap6 = default(List.Enumerator); <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; 5__2 = new HashSet(StringComparer.OrdinalIgnoreCase); <>7__wrap2 = ActiveEntriesByPrefab.GetEnumerator(); <>1__state = -3; goto IL_01ff; case 1: <>1__state = -5; goto IL_00f6; case 2: { <>1__state = -7; goto IL_019a; } IL_01ff: if (<>7__wrap2.MoveNext()) { <>7__wrap2.Current.Deconstruct(out string _, out List value); List list = value; <>7__wrap3 = list.GetEnumerator(); <>1__state = -4; goto IL_01dd; } <>m__Finally1(); <>7__wrap2 = default(Dictionary>.Enumerator); return false; IL_00f6: if (<>7__wrap5.MoveNext()) { string current = <>7__wrap5.Current; <>2__current = current; <>1__state = 1; return true; } <>m__Finally3(); <>7__wrap5 = null; goto IL_0110; IL_01b4: if (<>7__wrap6.MoveNext()) { LocationItemStandDefinition current2 = <>7__wrap6.Current; <>7__wrap5 = BuildConfiguredLocationResolutionKeys(current2, 5__2).GetEnumerator(); <>1__state = -7; goto IL_019a; } <>m__Finally4(); <>7__wrap6 = default(List.Enumerator); 5__5 = null; goto IL_01dd; IL_01dd: if (<>7__wrap3.MoveNext()) { 5__5 = <>7__wrap3.Current; LocationOfferingBowlDefinition offeringBowl = 5__5.OfferingBowl; if (offeringBowl != null) { <>7__wrap5 = BuildConfiguredLocationResolutionKeys(offeringBowl, 5__2).GetEnumerator(); <>1__state = -5; goto IL_00f6; } goto IL_0110; } <>m__Finally2(); <>7__wrap3 = default(List.Enumerator); goto IL_01ff; IL_019a: if (<>7__wrap5.MoveNext()) { string current3 = <>7__wrap5.Current; <>2__current = current3; <>1__state = 2; return true; } <>m__Finally5(); <>7__wrap5 = null; goto IL_01b4; IL_0110: if (5__5.ItemStands != null) { <>7__wrap6 = 5__5.ItemStands.GetEnumerator(); <>1__state = -6; goto IL_01b4; } goto IL_01dd; } } 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)<>7__wrap2).Dispose(); } private void <>m__Finally2() { <>1__state = -3; ((IDisposable)<>7__wrap3).Dispose(); } private void <>m__Finally3() { <>1__state = -4; if (<>7__wrap5 != null) { <>7__wrap5.Dispose(); } } private void <>m__Finally4() { <>1__state = -4; ((IDisposable)<>7__wrap6).Dispose(); } private void <>m__Finally5() { <>1__state = -6; if (<>7__wrap5 != null) { <>7__wrap5.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; return this; } return new d__169(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__170 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private string <>2__current; private int <>l__initialThreadId; private LocationOfferingBowlDefinition definition; public LocationOfferingBowlDefinition <>3__definition; private HashSet seen; public HashSet <>3__seen; string IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__170(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { string key2; string key3; switch (<>1__state) { default: return false; case 0: { <>1__state = -1; if (TryBuildResolvedPrefabSignatureKey("item", definition.BossItem, ResolveItemPrefab(definition.BossItem, null), out string key) && seen.Add(key)) { <>2__current = key; <>1__state = 1; return true; } goto IL_0075; } case 1: <>1__state = -1; goto IL_0075; case 2: <>1__state = -1; goto IL_00c4; case 3: { <>1__state = -1; break; } IL_00c4: if (TryBuildResolvedPrefabSignatureKey("item", definition.ItemPrefab, ResolveItemPrefab(definition.ItemPrefab, null), out key2) && seen.Add(key2)) { <>2__current = key2; <>1__state = 3; return true; } break; IL_0075: if (TryBuildResolvedPrefabSignatureKey("spawn", definition.BossPrefab, ResolveSpawnPrefab(definition.BossPrefab, null), out key3) && seen.Add(key3)) { <>2__current = key3; <>1__state = 2; return true; } goto IL_00c4; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__170 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__170(0); } d__.definition = <>3__definition; d__.seen = <>3__seen; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__171 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private string <>2__current; private int <>l__initialThreadId; private LocationItemStandDefinition definition; public LocationItemStandDefinition <>3__definition; private HashSet seen; public HashSet <>3__seen; private IEnumerator <>7__wrap1; string IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__171(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { switch (<>1__state) { case -3: case 1: try { } finally { <>m__Finally1(); } break; case -4: case 2: try { } finally { <>m__Finally2(); } break; } <>7__wrap1 = null; <>1__state = -2; } private bool MoveNext() { try { string key2; IEnumerable supportedItems; switch (<>1__state) { default: return false; case 0: <>1__state = -1; supportedItems = definition.SupportedItems; <>7__wrap1 = (supportedItems ?? Enumerable.Empty()).GetEnumerator(); <>1__state = -3; goto IL_00a8; case 1: <>1__state = -3; goto IL_00a8; case 2: <>1__state = -4; goto IL_013c; case 3: { <>1__state = -1; break; } IL_013c: while (<>7__wrap1.MoveNext()) { string current = <>7__wrap1.Current; if (TryBuildResolvedPrefabSignatureKey("item", current, ResolveItemPrefab(current, null), out string key) && seen.Add(key)) { <>2__current = key; <>1__state = 2; return true; } } <>m__Finally2(); <>7__wrap1 = null; if (TryBuildResolvedStatusEffectSignatureKey(definition.GuardianPower, out key2) && seen.Add(key2)) { <>2__current = key2; <>1__state = 3; return true; } break; IL_00a8: while (<>7__wrap1.MoveNext()) { string current2 = <>7__wrap1.Current; if (TryBuildResolvedPrefabSignatureKey("item", current2, ResolveItemPrefab(current2, null), out string key3) && seen.Add(key3)) { <>2__current = key3; <>1__state = 1; return true; } } <>m__Finally1(); <>7__wrap1 = null; supportedItems = definition.UnsupportedItems; <>7__wrap1 = (supportedItems ?? Enumerable.Empty()).GetEnumerator(); <>1__state = -4; goto IL_013c; } 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 (<>7__wrap1 != null) { <>7__wrap1.Dispose(); } } private void <>m__Finally2() { <>1__state = -1; if (<>7__wrap1 != null) { <>7__wrap1.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__171 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__171(0); } d__.definition = <>3__definition; d__.seen = <>3__seen; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__168 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private string <>2__current; private int <>l__initialThreadId; private List.Enumerator <>7__wrap1; string IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__168(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(); } } <>7__wrap1 = default(List.Enumerator); <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; if ((Object)(object)ZoneSystem.instance == (Object)null) { return false; } <>7__wrap1 = ZoneSystem.instance.m_locations.GetEnumerator(); <>1__state = -3; break; case 1: <>1__state = -3; break; } while (<>7__wrap1.MoveNext()) { string text = ReferenceRefreshSupport.NormalizeKey(GetZoneLocationPrefabName(<>7__wrap1.Current)); if (text.Length != 0) { <>2__current = text; <>1__state = 1; return true; } } <>m__Finally1(); <>7__wrap1 = default(List.Enumerator); 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; ((IDisposable)<>7__wrap1).Dispose(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; return this; } return new d__168(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__227 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private string <>2__current; private int <>l__initialThreadId; private IEnumerator <>7__wrap1; string IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__227(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(); } } <>7__wrap1 = 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_006a; case 1: <>1__state = -1; goto IL_006a; case 2: <>1__state = -1; goto IL_0093; case 3: { <>1__state = -3; break; } IL_006a: if (File.Exists(PrimaryOverrideConfigurationPathYaml)) { <>2__current = PrimaryOverrideConfigurationPathYaml; <>1__state = 2; return true; } goto IL_0093; IL_0093: <>7__wrap1 = EnumerateSupplementalOverrideConfigurationPaths().GetEnumerator(); <>1__state = -3; break; } if (<>7__wrap1.MoveNext()) { string current = <>7__wrap1.Current; <>2__current = current; <>1__state = 3; return true; } <>m__Finally1(); <>7__wrap1 = 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 (<>7__wrap1 != null) { <>7__wrap1.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; return this; } return new d__227(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__259 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private Location <>2__current; private int <>l__initialThreadId; private HashSet dirtyPrefabs; public HashSet <>3__dirtyPrefabs; private HashSet 5__2; private HashSet.Enumerator <>7__wrap2; private HashSet.Enumerator <>7__wrap3; Location IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__259(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(); } } 5__2 = null; <>7__wrap2 = default(HashSet.Enumerator); <>7__wrap3 = default(HashSet.Enumerator); <>1__state = -2; } private bool MoveNext() { try { int num = <>1__state; if (num != 0) { if (num != 1) { return false; } <>1__state = -4; goto IL_00d1; } <>1__state = -1; CleanupRegisteredLocations(); 5__2 = new HashSet(); <>7__wrap2 = dirtyPrefabs.GetEnumerator(); <>1__state = -3; goto IL_00f0; IL_00d1: while (<>7__wrap3.MoveNext()) { Location current = <>7__wrap3.Current; if ((Object)(object)current != (Object)null && (Object)(object)((Component)current).gameObject != (Object)null && 5__2.Add(current)) { <>2__current = current; <>1__state = 1; return true; } } <>m__Finally2(); <>7__wrap3 = default(HashSet.Enumerator); goto IL_00f0; IL_00f0: string current2; HashSet value; do { if (<>7__wrap2.MoveNext()) { current2 = <>7__wrap2.Current; continue; } <>m__Finally1(); <>7__wrap2 = default(HashSet.Enumerator); return false; } while (!LiveLocationsByPrefab.TryGetValue(current2, out value)); <>7__wrap3 = value.GetEnumerator(); <>1__state = -4; goto IL_00d1; } 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)<>7__wrap2).Dispose(); } private void <>m__Finally2() { <>1__state = -3; ((IDisposable)<>7__wrap3).Dispose(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__259 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__259(0); } d__.dirtyPrefabs = <>3__dirtyPrefabs; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__405 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private ItemStand <>2__current; private int <>l__initialThreadId; private HashSet dirtyPrefabs; public HashSet <>3__dirtyPrefabs; private List>.Enumerator <>7__wrap1; ItemStand IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__405(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(); } } <>7__wrap1 = default(List>.Enumerator); <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: { <>1__state = -1; CleanupTrackedLooseItemStandPrefabs(); List> list = TrackedLooseItemStandPrefabs.ToList(); <>7__wrap1 = list.GetEnumerator(); <>1__state = -3; break; } case 1: <>1__state = -3; break; } while (<>7__wrap1.MoveNext()) { var (val2, item) = (KeyValuePair)(ref <>7__wrap1.Current); if ((Object)(object)val2 != (Object)null && (Object)(object)((Component)val2).gameObject != (Object)null && dirtyPrefabs.Contains(item)) { <>2__current = val2; <>1__state = 1; return true; } } <>m__Finally1(); <>7__wrap1 = default(List>.Enumerator); 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; ((IDisposable)<>7__wrap1).Dispose(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__405 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__405(0); } d__.dirtyPrefabs = <>3__dirtyPrefabs; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } private const string ReferenceAutoUpdateStateKey = "location"; private static readonly ConditionalWeakTable RunestonePinChanceRolls = new ConditionalWeakTable(); private static readonly object RunestonePinChanceLock = new object(); private static readonly Random RunestonePinChanceRandom = new Random(); internal static readonly DomainModuleDefinition Module = new DomainModuleDefinition("location", DropNSpawnPlugin.ReloadDomain.Location, "location_yaml", 97, ShouldReloadForPath, ReloadConfiguration, OnGameDataReady, HandleExpandWorldDataReady, 12, DomainTransportProfile.SmallConfig, "location", "location", 20, (LocationConfigurationEntry entry) => entry.RuleId, ApplySyncedPayload, DomainWorkKinds.Runtime | DomainWorkKinds.Reconcile, null, null, HasPendingReconcileWork, ProcessQueuedReconcileStep, MarkSyncedPayloadPending, EnterPendingSyncedPayloadState); private static readonly int OfferingBowlLastUseTicksKey = StringExtensionMethods.GetStableHashCode("DropNSpawn.offering_bowl_last_use_ticks"); private const int LocationProxyAliasForceSendDebounceFrames = 2; private const int LocationProxyAliasForceSendBudgetPerFrame = 8; private const int LocationProxyUnresolvedObservationMaxStableCount = 90; private const int LocationProxyResolvedObservationMaxStableCount = 24; 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 Snapshots = new List(); private static readonly Dictionary SnapshotsByPrefab = new Dictionary(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary> ActiveEntriesByPrefab = new Dictionary>(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary LocationPrefabNamesByHash = new Dictionary(); private static readonly Dictionary RuntimeLocationProxyPrefabsByInstance = new Dictionary(); private static readonly Dictionary RuntimeLocationProxyPrefabsByZdoId = new Dictionary(); private static readonly ConditionalWeakTable LocationProxyObservationStates = new ConditionalWeakTable(); private static readonly ConditionalWeakTable LocationAliasRefreshRequestStates = new ConditionalWeakTable(); private const string LocationProxyResolvedPrefabZdoKey = "DropNSpawn Location Prefab"; private static readonly HashSet InvalidEntryWarnings = new HashSet(StringComparer.OrdinalIgnoreCase); private static readonly HashSet DuplicateComponentWarnings = new HashSet(StringComparer.OrdinalIgnoreCase); private static readonly HashSet OfferingBowlDiagnosticLogs = new HashSet(StringComparer.OrdinalIgnoreCase); private static readonly HashSet ItemStandDiagnosticLogs = new HashSet(StringComparer.OrdinalIgnoreCase); private static readonly HashSet LocationDiagnosticLogs = new HashSet(StringComparer.OrdinalIgnoreCase); private static readonly HashSet RedundantLocationConditionWarnings = new HashSet(StringComparer.OrdinalIgnoreCase); private static readonly HashSet VegvisirWarningLogs = new HashSet(StringComparer.OrdinalIgnoreCase); private static readonly HashSet RunestoneWarningLogs = new HashSet(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary LooseItemStandSnapshots = new Dictionary(); private static readonly Dictionary LiveLocationSnapshots = new Dictionary(); private static readonly Dictionary CatalogsByPrefab = new Dictionary(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary> LiveLocationsByPrefab = new Dictionary>(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary LiveLocationPrefabsByInstance = new Dictionary(); private static readonly HashSet TrackedLocationProxies = new HashSet(); private static readonly ConditionalWeakTable LooseOfferingBowlOverrideStates = new ConditionalWeakTable(); private static readonly Dictionary> AuthoredItemStandSlotsByPrefab = new Dictionary>(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary> LooseItemStandEntriesByPrefab = new Dictionary>(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary TrackedLooseItemStandPrefabs = new Dictionary(); private static readonly Dictionary LooseItemStandAuthoredPathsByInstance = new Dictionary(); private static readonly RingBufferQueue PendingLocationReconciles = new RingBufferQueue(); private static readonly HashSet PendingLocationReconcileIds = new HashSet(); private static readonly Dictionary SuppressedQueuedLocationReconciles = new Dictionary(); private static readonly RingBufferQueue PendingLocationRootReconciles = new RingBufferQueue(); private static readonly HashSet PendingLocationRootReconcileIds = new HashSet(); private static readonly RingBufferQueue PendingLooseOfferingBowlOverrides = new RingBufferQueue(); private static readonly HashSet PendingLooseOfferingBowlOverrideIds = new HashSet(); private static readonly ScheduledFrameQueue PendingLocationProxyAliasZdoFlushIds = new ScheduledFrameQueue(); private static readonly Dictionary PendingLocationProxyAliasZdoFlushes = new Dictionary(); private static readonly Dictionary PendingLocationProxyAliasZdoFlushEnqueuedDueFrames = new Dictionary(); private static readonly ScheduledFrameQueue PendingLocationProxyObservations = new ScheduledFrameQueue(); private static readonly HashSet PendingLocationProxyObservationIds = new HashSet(); private static readonly List PendingLocationProxyCreationPrefabs = new List(); private static readonly HashSet PendingRuntimeLocationProxyAliasDemands = new HashSet(StringComparer.OrdinalIgnoreCase); private const int LocationAliasRefreshInteractionCooldownFrames = 30; private static List _configuration = new List(); private static string _configurationSignature = ""; private static bool _initialized; private static bool _snapshotsCaptured; private static int? _lastProcessedGameDataSignature; private static bool _referenceArtifactsAutoRefreshConsumed; private static readonly Dictionary _lastAppliedEntrySignaturesByPrefab = new Dictionary(StringComparer.OrdinalIgnoreCase); private static string _lastAppliedConfigurationSignature = ""; private static int? _lastAppliedGameDataSignature; private static bool? _lastAppliedDomainEnabled; private static bool _lastAppliedSynchronizedPayloadReady; private static bool _synchronizedPayloadReady; private static int? _lastCommittedAuthorityEpoch; private static int _reconcileQueueEpoch; private static bool _needsRuntimeLocationProxyObservation; private static int _locationProxyObservationDemandEpoch; private static int _runtimeLocationAliasEpoch; private static int _locationProxyAliasFlushBudgetFrame = int.MinValue; private static int _locationProxyAliasFlushesSentThisFrame; private static readonly DomainConfigurationRuntime ConfigurationRuntime = new DomainConfigurationRuntime(new DomainLoadHooks(ParseLocalConfigurationDocuments, BuildSyncedConfigurationState, CommitSyncedConfigurationState, RejectLocalConfigurationPayload, (SyncedLocationConfigurationState state) => state.ActiveEntriesByPrefab.Count, null, LogLocalConfigurationLoaded, OnSourceOfTruthPayloadUnchanged, delegate { ConfigurationDomainHost.PublishSyncedPayload(DropNSpawnPlugin.IsSourceOfTruth, Descriptor, _configuration, _configurationSignature); }), new DomainSyncHooks(delegate(out List configuration, out string payloadToken) { return ConfigurationDomainHost.TryGetSyncedEntries(Descriptor, out configuration, out payloadToken); }, (string payloadToken) => ConfigurationDomainHost.ShouldSkipSyncedPayload(LoadState, payloadToken, Volatile.Read(ref _synchronizedPayloadReady)), BuildSyncedConfigurationState, CommitSyncedConfigurationState, (SyncedLocationConfigurationState state) => state.ActiveEntriesByPrefab.Count, "ServerSync:DropNSpawnLocation", delegate { ConfigurationDomainHost.HandleWaitingForSyncedPayload(MarkSyncedPayloadPending, "Waiting for synchronized location override payload from the server."); }, LogSyncedLocationConfigurationLoaded, LogSyncedLocationConfigurationFailure)); private static readonly Dictionary EmptyEntrySignatures = new Dictionary(StringComparer.OrdinalIgnoreCase); private static LocationRuntimeConfigurationState _runtimeConfigurationState = LocationRuntimeConfigurationState.Empty; private static int? _runtimeConfigurationGameDataSignature; private static string _runtimeConfigurationSignature = ""; private static int _invalidEntryWarningSuppressionDepth; private static readonly ConditionalWeakTable RunestoneGlobalPinsRolls = new ConditionalWeakTable(); private static readonly object RunestoneGlobalPinsLock = new object(); private static readonly Random RunestoneGlobalPinsRandom = new Random(); private static readonly Dictionary RunestoneGlobalPinDiscoverLabels = new Dictionary(StringComparer.OrdinalIgnoreCase); private static readonly HashSet RunestoneGlobalPinWarningLogs = new HashSet(StringComparer.OrdinalIgnoreCase); private static RunestoneGlobalPinLocationIndex? RunestoneGlobalPinLocationIndexCache; private static readonly FieldInfo? MinimapPinsField = AccessTools.Field(typeof(Minimap), "m_pins"); internal static DomainDescriptor Descriptor => Module.DescriptorTyped; internal static DomainTransportMetadata TransportMetadata => Module.TransportMetadataTyped; private static string ReferenceConfigurationPath => Path.Combine(DropNSpawnPlugin.YamlConfigDirectoryPath, PluginSettingsFacade.GetYamlDomainFilePrefix("location") + ".reference.yml"); private static string PrimaryOverrideConfigurationPathYml => Path.Combine(DropNSpawnPlugin.YamlConfigDirectoryPath, PluginSettingsFacade.GetYamlDomainFilePrefix("location") + ".yml"); private static string PrimaryOverrideConfigurationPathYaml => Path.Combine(DropNSpawnPlugin.YamlConfigDirectoryPath, PluginSettingsFacade.GetYamlDomainFilePrefix("location") + ".yaml"); private static string FullScaffoldConfigurationPath => Path.Combine(DropNSpawnPlugin.YamlConfigDirectoryPath, PluginSettingsFacade.GetYamlDomainFilePrefix("location") + ".full.yml"); private static DomainLoadState LoadState => ConfigurationRuntime.LoadState; internal static bool ShouldReloadForPath(string? path) { if (PluginSettingsFacade.IsEligibleOverrideConfigurationPath(path)) { return IsOverrideConfigurationFileName(Path.GetFileName(path ?? "")); } return false; } internal static void Initialize() { lock (Sync) { if (!_initialized) { LoadConfiguration(); _initialized = true; } } } internal static void ReloadConfiguration() { lock (Sync) { LoadConfiguration(); ApplyIfReady(queueLiveReconcile: true); } } internal static void MarkSyncedPayloadPending() { lock (Sync) { ConfigurationRuntime.MarkSyncedPayloadPending(DropNSpawnPlugin.IsSourceOfTruth, delegate { Volatile.Write(ref _synchronizedPayloadReady, value: false); }); } } internal static void EnterPendingSyncedPayloadState() { lock (Sync) { HashSet previouslyAppliedPrefabs = BuildLastAppliedPrefabs(); ConfigurationRuntime.EnterPendingSyncedPayloadState(DropNSpawnPlugin.IsSourceOfTruth, ResetLoadedConfigurationState, delegate { _configurationSignature = ""; _lastAppliedSynchronizedPayloadReady = false; RestoreTrackedLocations(previouslyAppliedPrefabs); }); } } private static bool CanUseCurrentRuntimeState() { if (!DropNSpawnPlugin.IsSourceOfTruth && !Volatile.Read(ref _synchronizedPayloadReady)) { return _lastCommittedAuthorityEpoch == NetworkPayloadSyncSupport.CurrentAuthorityEpoch; } return true; } private static HashSet BuildLastAppliedPrefabs() { HashSet hashSet = new HashSet(StringComparer.OrdinalIgnoreCase); if (!_lastAppliedDomainEnabled.GetValueOrDefault()) { return hashSet; } foreach (string key in _lastAppliedEntrySignaturesByPrefab.Keys) { hashSet.Add(key); } return hashSet; } private static void RestoreTrackedLocations(HashSet prefabs) { if (prefabs.Count != 0 && IsGameDataReady()) { ReapplyActiveEntriesToRegisteredLocations(prefabs); } } internal static bool HandleExpandWorldDataReady() { lock (Sync) { if (!DropNSpawnPlugin.IsSourceOfTruth) { return false; } string text = NetworkPayloadSyncSupport.ComputeLocationConfigurationSignature(_configuration); if (string.Equals(text, _configurationSignature, StringComparison.Ordinal)) { return false; } _configurationSignature = text; ConfigurationDomainHost.PublishSyncedPayload(DropNSpawnPlugin.IsSourceOfTruth, Descriptor, _configuration, _configurationSignature); ApplyIfReady(queueLiveReconcile: true); return true; } } internal static void ApplySyncedPayload() { lock (Sync) { ConfigurationRuntime.ApplySyncedPayload(delegate { ApplyIfReady(queueLiveReconcile: true); }); } } 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(queueLiveReconcile: true); _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); } } } private static bool HasCurrentLocationReconcileWorkForPrefab(string prefabName) { if (prefabName.Length > 0) { if (!ActiveEntriesByPrefab.ContainsKey(prefabName)) { return LooseItemStandEntriesByPrefab.ContainsKey(prefabName); } return true; } return false; } private static bool ShouldQueueLocationReconcileLocked(Location? location) { if ((Object)(object)location == (Object)null || (Object)(object)((Component)location).gameObject == (Object)null) { return false; } if (LiveLocationSnapshots.ContainsKey(location)) { return true; } if (LiveLocationPrefabsByInstance.TryGetValue(location, out string value) && HasCurrentLocationReconcileWorkForPrefab(value ?? "")) { return true; } if (TryGetLocationPrefabName(location, out string prefabName)) { return HasCurrentLocationReconcileWorkForPrefab(prefabName); } return false; } internal static void QueueLocationReconcile(Location? location) { lock (Sync) { if (ShouldQueueLocationReconcileLocked(location)) { int instanceID = ((Object)location).GetInstanceID(); if (PendingLocationReconcileIds.Add(instanceID)) { PendingLocationReconciles.Enqueue(new PendingLocationReconcile(location, instanceID, _reconcileQueueEpoch)); } } } } internal static void RecordLocationProxyResolvedPrefab(LocationProxy? proxy, string? prefabName) { if ((Object)(object)proxy == (Object)null) { return; } string text = (prefabName ?? "").Trim(); if (text.Length != 0) { LocationProxyObservationState orCreateValue = LocationProxyObservationStates.GetOrCreateValue(proxy); LocationProxyObservationState locationProxyObservationState = orCreateValue; if (locationProxyObservationState.NView == null) { ZNetView val = (locationProxyObservationState.NView = ((Component)proxy).GetComponent()); } lock (Sync) { TrackLocationProxyInternal(proxy); CacheLocationProxyResolvedPrefabInternal(proxy, text, (Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer(), queueLocationReconciles: true); } ZNetView? nView = orCreateValue.NView; ZDO val2 = ((nView != null) ? nView.GetZDO() : null); orCreateValue.LastObservedAlias = text; orCreateValue.LastObservedDataRevision = ((val2 != null) ? val2.DataRevision : uint.MaxValue); orCreateValue.StablePollCount = 0; orCreateValue.LastObservedDemandEpoch = _locationProxyObservationDemandEpoch; } } internal static void QueueLocationProxyObservation(LocationProxy? proxy) { lock (Sync) { QueueLocationProxyObservationInternal(proxy, Time.frameCount); } } internal static bool HasRuntimeLocationAliasDemand() { lock (Sync) { return _needsRuntimeLocationProxyObservation; } } internal static void UntrackLocationProxy(LocationProxy? proxy) { //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)proxy == (Object)null) { return; } LocationProxyObservationStates.Remove(proxy); lock (Sync) { TrackedLocationProxies.Remove(proxy); PendingLocationProxyObservationIds.Remove(((Object)proxy).GetInstanceID()); RuntimeLocationProxyPrefabsByInstance.Remove(proxy); ZNetView component = ((Component)proxy).GetComponent(); ZDOID val = (ZDOID)(((??)((component == null) ? null : component.GetZDO()?.m_uid)) ?? ZDOID.None); if (val != ZDOID.None) { RuntimeLocationProxyPrefabsByZdoId.Remove(val); } RefreshLocationProxyObservationDemandLocked(); } } internal static void BeginLocationProxyCreationContext(string? prefabName) { string text = (prefabName ?? "").Trim(); if (text.Length == 0) { return; } lock (Sync) { PendingLocationProxyCreationPrefabs.Add(text); } } private static int GetLocationProxyObservationDelayFrames(bool hasObservedAlias, int stablePollCount) { if (!hasObservedAlias) { if (stablePollCount >= 60) { if (stablePollCount < 180) { return 10; } return 60; } return 1; } if (stablePollCount >= 30) { if (stablePollCount < 120) { return 30; } return 180; } return 5; } private static bool ShouldContinueLocationProxyObservation(bool hasObservedAlias, int stablePollCount) { return stablePollCount < (hasObservedAlias ? 24 : 90); } internal static void EndLocationProxyCreationContext() { lock (Sync) { int count = PendingLocationProxyCreationPrefabs.Count; if (count > 0) { PendingLocationProxyCreationPrefabs.RemoveAt(count - 1); } } } internal static bool TryGetPendingLocationProxyCreationPrefabName(out string prefabName) { lock (Sync) { int count = PendingLocationProxyCreationPrefabs.Count; if (count > 0) { prefabName = PendingLocationProxyCreationPrefabs[count - 1]; return prefabName.Length > 0; } } prefabName = ""; return false; } private static void CacheLocationProxyResolvedPrefabInternal(LocationProxy proxy, string prefabName, bool persistToZdo, bool queueLocationReconciles) { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)proxy == (Object)null || prefabName.Length == 0) { return; } TrackLocationProxyInternal(proxy); string value; bool flag = !RuntimeLocationProxyPrefabsByInstance.TryGetValue(proxy, out value) || !string.Equals(value, prefabName, StringComparison.OrdinalIgnoreCase); RuntimeLocationProxyPrefabsByInstance[proxy] = prefabName; ZNetView component = ((Component)proxy).GetComponent(); ZDO val = ((component != null) ? component.GetZDO() : null); if (val != null) { ZDOID uid = val.m_uid; if (uid != ZDOID.None && (!RuntimeLocationProxyPrefabsByZdoId.TryGetValue(uid, out string value2) || !string.Equals(value2, prefabName, StringComparison.OrdinalIgnoreCase))) { RuntimeLocationProxyPrefabsByZdoId[uid] = prefabName; flag = true; } if (persistToZdo && !string.Equals(val.GetString("DropNSpawn Location Prefab", ""), prefabName, StringComparison.Ordinal)) { val.Set("DropNSpawn Location Prefab", prefabName); QueueLocationProxyAliasZdoFlushLocked(val); flag = true; } } if (flag && queueLocationReconciles) { QueueLocationReconcilesUnderProxyInternal(proxy); } if (flag) { _runtimeLocationAliasEpoch++; RefreshLocationProxyObservationDemandLocked(); } } private static void QueueLocationProxyAliasZdoFlushLocked(ZDO zdo) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) if (zdo == null) { return; } ZDOID uid = zdo.m_uid; if (!(uid == ZDOID.None)) { PendingLocationProxyAliasZdoFlush pendingLocationProxyAliasZdoFlush = new PendingLocationProxyAliasZdoFlush { Epoch = _reconcileQueueEpoch, DueFrame = Time.frameCount + 2, DataRevision = zdo.DataRevision }; PendingLocationProxyAliasZdoFlushes[uid] = pendingLocationProxyAliasZdoFlush; if (!PendingLocationProxyAliasZdoFlushEnqueuedDueFrames.TryGetValue(uid, out var value) || value != pendingLocationProxyAliasZdoFlush.DueFrame) { PendingLocationProxyAliasZdoFlushIds.Enqueue(pendingLocationProxyAliasZdoFlush.DueFrame, uid); PendingLocationProxyAliasZdoFlushEnqueuedDueFrames[uid] = pendingLocationProxyAliasZdoFlush.DueFrame; } } } private static bool TryProcessPendingLocationProxyAliasZdoFlushLocked(float deadline) { //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) if (PendingLocationProxyAliasZdoFlushes.Count == 0 || (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || ZDOMan.instance == null) { return false; } int frameCount = Time.frameCount; if (_locationProxyAliasFlushBudgetFrame != frameCount) { _locationProxyAliasFlushBudgetFrame = frameCount; _locationProxyAliasFlushesSentThisFrame = 0; } if (_locationProxyAliasFlushesSentThisFrame >= 8) { return false; } if (!PendingLocationProxyAliasZdoFlushIds.TryPeekDueFrame(out var dueFrame) || dueFrame > frameCount) { return false; } while (PendingLocationProxyAliasZdoFlushIds.TryPeekDueFrame(out dueFrame) && dueFrame <= frameCount) { if (Time.realtimeSinceStartup >= deadline) { return false; } if (!PendingLocationProxyAliasZdoFlushIds.TryDequeue(out var dueFrame2, out var item)) { return false; } if (!PendingLocationProxyAliasZdoFlushes.TryGetValue(item, out PendingLocationProxyAliasZdoFlush value)) { continue; } if (value.Epoch != _reconcileQueueEpoch) { PendingLocationProxyAliasZdoFlushes.Remove(item); PendingLocationProxyAliasZdoFlushEnqueuedDueFrames.Remove(item); } else { if (value.DueFrame != dueFrame2) { continue; } ZDO zDO = ZDOMan.instance.GetZDO(item); if (zDO == null) { PendingLocationProxyAliasZdoFlushes.Remove(item); PendingLocationProxyAliasZdoFlushEnqueuedDueFrames.Remove(item); continue; } if (zDO.DataRevision >= value.DataRevision) { PendingLocationProxyAliasZdoFlushes.Remove(item); PendingLocationProxyAliasZdoFlushEnqueuedDueFrames.Remove(item); _locationProxyAliasFlushesSentThisFrame++; ZDOMan.instance.ForceSendZDO(item); return true; } value.DueFrame = frameCount + 1; PendingLocationProxyAliasZdoFlushes[item] = value; PendingLocationProxyAliasZdoFlushIds.Enqueue(value.DueFrame, item); PendingLocationProxyAliasZdoFlushEnqueuedDueFrames[item] = value.DueFrame; } } return false; } private static void TrackLocationProxyInternal(LocationProxy? proxy) { if (!((Object)(object)proxy == (Object)null) && !((Object)(object)((Component)proxy).gameObject == (Object)null)) { TrackedLocationProxies.Add(proxy); LocationProxyObservationState orCreateValue = LocationProxyObservationStates.GetOrCreateValue(proxy); if (orCreateValue.NView == null) { ZNetView val = (orCreateValue.NView = ((Component)proxy).GetComponent()); } } } private static void CleanupTrackedLocationProxiesLocked() { List list = new List(); foreach (LocationProxy trackedLocationProxy in TrackedLocationProxies) { if ((Object)(object)trackedLocationProxy == (Object)null || (Object)(object)((Component)trackedLocationProxy).gameObject == (Object)null) { list.Add(trackedLocationProxy); } } foreach (LocationProxy item in list) { if ((Object)(object)item != (Object)null) { TrackedLocationProxies.Remove(item); } } } private static bool ShouldObserveLocationProxyResolvedPrefabLocked(LocationProxy proxy, LocationProxyObservationState observationState) { if (!_needsRuntimeLocationProxyObservation || (Object)(object)proxy == (Object)null || (Object)(object)((Component)proxy).gameObject == (Object)null) { return false; } if (observationState.LastObservedDemandEpoch != _locationProxyObservationDemandEpoch) { observationState.LastObservedDemandEpoch = _locationProxyObservationDemandEpoch; observationState.StablePollCount = 0; } if (observationState.LastObservedAlias.Length != 0) { return PendingRuntimeLocationProxyAliasDemands.Contains(observationState.LastObservedAlias); } return true; } private static void QueueTrackedLocationProxyObservationsLocked(int dueFrame) { CleanupTrackedLocationProxiesLocked(); foreach (LocationProxy item in TrackedLocationProxies.ToList()) { QueueLocationProxyObservationInternal(item, dueFrame); } } private static void QueueLocationProxyObservationInternal(LocationProxy? proxy, int dueFrame) { if ((Object)(object)proxy == (Object)null || (Object)(object)((Component)proxy).gameObject == (Object)null) { return; } TrackLocationProxyInternal(proxy); LocationProxyObservationState orCreateValue = LocationProxyObservationStates.GetOrCreateValue(proxy); if (ShouldObserveLocationProxyResolvedPrefabLocked(proxy, orCreateValue)) { int instanceID = ((Object)proxy).GetInstanceID(); if (PendingLocationProxyObservationIds.Add(instanceID)) { PendingLocationProxyObservations.Enqueue(dueFrame, new PendingLocationProxyObservation(proxy, instanceID, _reconcileQueueEpoch, dueFrame)); } } } private static void QueueNextLocationProxyObservationLocked(LocationProxy proxy, LocationProxyObservationState observationState, bool hasObservedAlias) { observationState.StablePollCount++; if (ShouldContinueLocationProxyObservation(hasObservedAlias, observationState.StablePollCount)) { QueueLocationProxyObservationInternal(proxy, Time.frameCount + GetLocationProxyObservationDelayFrames(hasObservedAlias, observationState.StablePollCount)); } } private static bool TryProcessPendingLocationProxyObservationLocked(float deadline) { int frameCount = Time.frameCount; if (!PendingLocationProxyObservations.TryPeekDueFrame(out var dueFrame) || dueFrame > frameCount) { return false; } while (PendingLocationProxyObservations.TryPeekDueFrame(out dueFrame) && dueFrame <= frameCount) { if (Time.realtimeSinceStartup >= deadline) { return false; } if (!PendingLocationProxyObservations.TryDequeue(out var _, out var item)) { return false; } PendingLocationProxyObservationIds.Remove(item.ProxyInstanceId); if (item.Epoch == _reconcileQueueEpoch && !((Object)(object)item.Proxy == (Object)null) && !((Object)(object)((Component)item.Proxy).gameObject == (Object)null)) { TrackLocationProxyInternal(item.Proxy); LocationProxyObservationState orCreateValue = LocationProxyObservationStates.GetOrCreateValue(item.Proxy); if (!ShouldObserveLocationProxyResolvedPrefabLocked(item.Proxy, orCreateValue)) { return true; } LocationProxyObservationState locationProxyObservationState = orCreateValue; if (locationProxyObservationState.NView == null) { ZNetView val = (locationProxyObservationState.NView = ((Component)item.Proxy).GetComponent()); } ZNetView? nView = orCreateValue.NView; ZDO val2 = ((nView != null) ? nView.GetZDO() : null); if (val2 == null) { QueueNextLocationProxyObservationLocked(item.Proxy, orCreateValue, orCreateValue.LastObservedAlias.Length > 0); return true; } uint dataRevision = val2.DataRevision; if (dataRevision == orCreateValue.LastObservedDataRevision) { QueueNextLocationProxyObservationLocked(item.Proxy, orCreateValue, orCreateValue.LastObservedAlias.Length > 0); return true; } orCreateValue.LastObservedDataRevision = dataRevision; string text = (val2.GetString("DropNSpawn Location Prefab", "") ?? "").Trim(); if (text.Length == 0) { QueueNextLocationProxyObservationLocked(item.Proxy, orCreateValue, hasObservedAlias: false); return true; } if (string.Equals(orCreateValue.LastObservedAlias, text, StringComparison.OrdinalIgnoreCase)) { QueueNextLocationProxyObservationLocked(item.Proxy, orCreateValue, hasObservedAlias: true); return true; } orCreateValue.LastObservedAlias = text; orCreateValue.StablePollCount = 0; CacheLocationProxyResolvedPrefabInternal(item.Proxy, text, persistToZdo: false, queueLocationReconciles: true); QueueLocationProxyObservationInternal(item.Proxy, Time.frameCount + 1); return true; } } return false; } private static void QueueLocationReconcilesUnderProxyInternal(LocationProxy proxy) { if ((Object)(object)proxy == (Object)null || (Object)(object)((Component)proxy).gameObject == (Object)null) { return; } List list = new List(); CollectLocationsUnderRoot(((Component)proxy).transform, list); foreach (Location item in list) { if (!((Object)(object)item == (Object)null) && !((Object)(object)((Component)item).gameObject == (Object)null)) { int instanceID = ((Object)item).GetInstanceID(); if (PendingLocationReconcileIds.Add(instanceID)) { PendingLocationReconciles.Enqueue(new PendingLocationReconcile(item, instanceID, _reconcileQueueEpoch)); } } } } internal static void MaybeQueueRuntimeLocationAliasRefresh(Component? component) { lock (Sync) { if ((Object)(object)component == (Object)null || (Object)(object)component.gameObject == (Object)null || !IsGameDataReady()) { return; } Location componentInParent = component.GetComponentInParent(true); if (!((Object)(object)componentInParent == (Object)null) && !((Object)(object)((Component)componentInParent).gameObject == (Object)null) && TryResolveRuntimeLocationPrefabName(componentInParent, out string prefabName) && prefabName.Length != 0 && (!LiveLocationPrefabsByInstance.TryGetValue(componentInParent, out string value) || !string.Equals(value, prefabName, StringComparison.OrdinalIgnoreCase))) { LocationAliasRefreshRequestState orCreateValue = LocationAliasRefreshRequestStates.GetOrCreateValue(componentInParent); if (orCreateValue.LastQueuedAliasEpoch != _runtimeLocationAliasEpoch || !string.Equals(orCreateValue.LastQueuedResolvedPrefabName, prefabName, StringComparison.OrdinalIgnoreCase) || Time.frameCount - orCreateValue.LastQueuedFrame >= 30) { orCreateValue.LastQueuedAliasEpoch = _runtimeLocationAliasEpoch; orCreateValue.LastQueuedResolvedPrefabName = prefabName; orCreateValue.LastQueuedFrame = Time.frameCount; QueueLocationReconcile(componentInParent); } } } } 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 bool HasPendingReconcileWork() { lock (Sync) { int frameCount = Time.frameCount; return PendingLocationReconciles.Count > 0 || PendingLocationRootReconciles.Count > 0 || HasPendingLooseLocationOverrideWorkLocked() || (PendingLocationProxyObservationIds.Count > 0 && PendingLocationProxyObservations.HasDueItems(frameCount)) || (PendingLocationProxyAliasZdoFlushes.Count > 0 && PendingLocationProxyAliasZdoFlushIds.HasDueItems(frameCount)); } } internal static bool ProcessQueuedReconcileStep(float deadline) { lock (Sync) { if (Time.realtimeSinceStartup >= deadline) { return false; } if (TryProcessPendingLocationProxyAliasZdoFlushLocked(deadline)) { return true; } if (TryProcessPendingLocationProxyObservationLocked(deadline)) { return true; } 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)) { continue; } int locationInstanceId = item.LocationInstanceId; PendingLocationReconcileIds.Remove(locationInstanceId); if (item.Epoch != _reconcileQueueEpoch || (Object)(object)item.Location == (Object)null) { continue; } Location location = item.Location; if (SuppressedQueuedLocationReconciles.TryGetValue(locationInstanceId, out var value) && value > 0) { if (value == 1) { SuppressedQueuedLocationReconciles.Remove(locationInstanceId); } else { SuppressedQueuedLocationReconciles[locationInstanceId] = value - 1; } return true; } TrackLocationInstanceInternal(location); if (!_initialized) { Initialize(); } ReconcileLocationInstanceInternal(location); return true; } return TryProcessPendingLooseLocationOverrideLocked(); } } 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 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; } RefreshReferenceSnapshots(); 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()) { RefreshReferenceSnapshots(); 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() { if ((Object)(object)ZoneSystem.instance != (Object)null && (Object)(object)ZNetScene.instance != (Object)null) { return (Object)(object)ObjectDB.instance != (Object)null; } return false; } 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; } return HashNormalizedKeys(HashNormalizedKeys(((17 * 31 + ((Object)ZoneSystem.instance).GetInstanceID()) * 31 + ((Object)ZNetScene.instance).GetInstanceID()) * 31 + ((Object)ObjectDB.instance).GetInstanceID(), BuildLiveLocationSourceKeys()), BuildConfiguredLocationResolutionKeys()); } private static int HashNormalizedKeys(int hash, IEnumerable keys) { foreach (string item in (from key in (keys ?? Enumerable.Empty()).Select(ReferenceRefreshSupport.NormalizeKey) where key.Length > 0 select key).OrderBy((string key) => key, StringComparer.OrdinalIgnoreCase)) { hash = hash * 31 + StringComparer.OrdinalIgnoreCase.GetHashCode(item); } return hash; } [IteratorStateMachine(typeof(d__168))] private static IEnumerable BuildLiveLocationSourceKeys() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__168(-2); } [IteratorStateMachine(typeof(d__169))] private static IEnumerable BuildConfiguredLocationResolutionKeys() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__169(-2); } [IteratorStateMachine(typeof(d__170))] private static IEnumerable BuildConfiguredLocationResolutionKeys(LocationOfferingBowlDefinition definition, HashSet seen) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__170(-2) { <>3__definition = definition, <>3__seen = seen }; } [IteratorStateMachine(typeof(d__171))] private static IEnumerable BuildConfiguredLocationResolutionKeys(LocationItemStandDefinition definition, HashSet seen) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__171(-2) { <>3__definition = definition, <>3__seen = seen }; } private static bool TryBuildResolvedPrefabSignatureKey(string prefix, string? prefabName, GameObject? prefab, out string key) { string text = ReferenceRefreshSupport.NormalizeKey(prefabName); if (text.Length == 0) { key = ""; return false; } key = prefix + ":" + text + ":" + (((Object)(object)prefab != (Object)null) ? ((Object)prefab).GetInstanceID() : 0).ToString(CultureInfo.InvariantCulture); return true; } private static bool TryBuildResolvedStatusEffectSignatureKey(string? statusEffectName, out string key) { string text = ReferenceRefreshSupport.NormalizeKey(statusEffectName); if (text.Length == 0) { key = ""; return false; } StatusEffect val = ResolveStatusEffect(text, null); key = "status:" + text + ":" + (((Object)(object)val != (Object)null) ? ((Object)val).GetInstanceID() : 0).ToString(CultureInfo.InvariantCulture); return true; } private static string ComputeReferenceSourceSignature() { if ((Object)(object)ZoneSystem.instance == (Object)null) { return ""; } return ReferenceRefreshSupport.ComputeStableHashForKeys(ZoneSystem.instance.m_locations.Select(delegate(ZoneLocation location) { object obj = location?.m_prefabName; if (obj == null) { if (location == null) { return null; } obj = location.m_prefab.Name; } return (string)obj; })); } 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 (PluginSettingsFacade.ShouldAutoCreateMissingReferenceFiles()) { RefreshReferenceSnapshots(); WriteReferenceConfigurationFile(BuildReferenceConfigurationTemplate(), "Created location reference configuration at " + ReferenceConfigurationPath + "."); ReferenceRefreshSupport.RecordAutoUpdateState("location", ReferenceConfigurationPath, sourceSignature, null, "2026-03-26-full-rewrite-v1"); ResetReferenceSnapshots(); } } else if (PluginSettingsFacade.ShouldAutoUpdateReferenceFiles() && !ReferenceRefreshSupport.ShouldSkipAutoUpdate("location", ReferenceConfigurationPath, sourceSignature, "2026-03-26-full-rewrite-v1")) { RefreshReferenceSnapshots(); 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() { if (DropNSpawnPlugin.IsSourceOfTruth) { EnsurePrimaryOverrideConfigurationFileExists(); ConfigurationRuntime.ReloadSourceOfTruth(EnumerateOverrideConfigurationPaths().ToList()); } else { ConfigurationRuntime.ReloadSynced(); } } private static void ResetLoadedConfigurationState() { ClearQueuedReconcileState(); ResetLocationRuntimeConfigurationState(); LocationPrefabNamesByHash.Clear(); ActiveEntriesByPrefab.Clear(); AuthoredItemStandSlotsByPrefab.Clear(); LooseItemStandEntriesByPrefab.Clear(); OfferingBowlDiagnosticLogs.Clear(); InvalidEntryWarnings.Clear(); ItemStandDiagnosticLogs.Clear(); LocationDiagnosticLogs.Clear(); RunestoneWarningLogs.Clear(); _configuration = new List(); Volatile.Write(ref _synchronizedPayloadReady, value: false); RefreshLocationProxyObservationDemandLocked(); } private static List CloneAndNormalizeConfigurationEntries(List? configuration, string source) { List list = NetworkPayloadSyncSupport.CloneEntries(Descriptor, configuration); foreach (LocationConfigurationEntry item in list) { string source2 = (item.SourcePath = (string.IsNullOrWhiteSpace(item.SourcePath) ? source : (item.SourcePath ?? ""))); item.Prefab = (item.Prefab ?? "").Trim(); NormalizeOfferingBowlDefinition(item.OfferingBowl); NormalizeItemStandDefinitions(item.ItemStands); NormalizeVegvisirDefinitions(item.Vegvisirs); NormalizeRunestoneDefinitions(item.Runestones); NormalizeRunestoneGlobalPinsDefinition(item.RunestoneGlobalPins); FinalizeNormalizedEntry(item); StripRedundantLocationComponentConditions(item, source2); } return list; } private static SyncedLocationConfigurationState BuildSyncedConfigurationState(List configuration, string source) { using (BeginInvalidEntryWarningSuppressionForSyncedClientBuild(source)) { SyncedLocationConfigurationState syncedLocationConfigurationState = new SyncedLocationConfigurationState(); foreach (LocationConfigurationEntry item in CloneAndNormalizeConfigurationEntries(configuration, source)) { string text = item.SourcePath ?? ""; bool flag = HasRunestoneGlobalPinsOverride(item.RunestoneGlobalPins); if (item.Prefab.Length == 0 && !flag) { WarnInvalidEntry("Entry in '" + text + "' is missing prefab."); } else { if (!item.Enabled) { continue; } RemoveEffectiveConfigurationEntry(syncedLocationConfigurationState.Configuration, syncedLocationConfigurationState.ActiveEntriesByPrefab, syncedLocationConfigurationState.LooseItemStandEntriesByPrefab, item.Prefab, item.RuleId); syncedLocationConfigurationState.Configuration.Add(item); if (item.Prefab.Length != 0 && HasOverride(item)) { GetOrCreateActiveEntries(syncedLocationConfigurationState.ActiveEntriesByPrefab, item.Prefab).Add(item); if (HasLooseItemStandOverride(item.ItemStands)) { GetOrCreateLooseItemStandEntries(syncedLocationConfigurationState.LooseItemStandEntriesByPrefab, item.Prefab).Add(item); } } } } syncedLocationConfigurationState.ConfigurationSignature = NetworkPayloadSyncSupport.ComputeLocationConfigurationSignature(syncedLocationConfigurationState.Configuration); return syncedLocationConfigurationState; } } private static void CommitSyncedConfigurationState(SyncedLocationConfigurationState state, string payloadToken) { ResetLoadedConfigurationState(); _configuration = state.Configuration; string key; List value; foreach (KeyValuePair> item in state.ActiveEntriesByPrefab) { item.Deconstruct(out key, out value); string key2 = key; List value2 = value; ActiveEntriesByPrefab[key2] = value2; } foreach (KeyValuePair> item2 in state.LooseItemStandEntriesByPrefab) { item2.Deconstruct(out key, out value); string key3 = key; List value3 = value; LooseItemStandEntriesByPrefab[key3] = value3; } _configurationSignature = state.ConfigurationSignature; LoadState.LastLoadedPayload = payloadToken; LoadState.LastRejectedPayload = ""; LoadState.PendingStrictPayload = ""; LoadState.LastRejectedValidationKey = ""; Volatile.Write(ref _synchronizedPayloadReady, value: true); _lastCommittedAuthorityEpoch = (DropNSpawnPlugin.IsSourceOfTruth ? null : new int?(NetworkPayloadSyncSupport.CurrentAuthorityEpoch)); RefreshLocationProxyObservationDemandLocked(); } private static LocalLoadResult ParseLocalConfigurationDocuments(List documents) { SyncedLocationConfigurationState state; List errors; int loadedFileCount; bool flag = TryBuildLocalConfigurationState(documents, out state, out errors, out loadedFileCount); return new LocalLoadResult { Entries = (flag ? state.Configuration : new List()), Errors = errors, Warnings = new List(), ParsedEntryCount = (flag ? state.Configuration.Count : 0), LoadedFileCount = loadedFileCount }; } private static bool TryBuildLocalConfigurationState(List documents, out SyncedLocationConfigurationState state, out List errors, out int loadedFileCount) { state = new SyncedLocationConfigurationState(); errors = new List(); loadedFileCount = 0; List list = new List(); foreach (ConfigurationLoadSupport.LocalYamlDocument document in documents) { if (document.ReadError != null) { errors.Add("Failed to read " + document.Path + ". " + document.ReadError); continue; } try { List entries = ParseConfiguration(document.Yaml ?? ""); List list2 = NetworkPayloadSyncSupport.CloneEntries(Descriptor, entries); foreach (LocationConfigurationEntry item in list2) { item.SourcePath = document.Path; } list.AddRange(list2); loadedFileCount++; } catch (Exception arg) { errors.Add($"Failed to parse location YAML '{document.Path}'. Location override YAML must start with a root list like '- prefab: ...'. {arg}"); } } if (errors.Count > 0) { return false; } state = BuildSyncedConfigurationState(list, ""); return true; } private static void LogLocalConfigurationLoaded(int acceptedEntryCount, int loadedFileCount) { DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)$"Loaded {acceptedEntryCount} location configuration(s) from {loadedFileCount} override file(s)."); } private static void OnSourceOfTruthPayloadUnchanged() { if (!NetworkPayloadSyncSupport.IsPayloadCurrent(Descriptor, _configurationSignature)) { ConfigurationDomainHost.PublishSyncedPayload(DropNSpawnPlugin.IsSourceOfTruth, Descriptor, _configuration, _configurationSignature); } } private static void LogSyncedLocationConfigurationLoaded(string payloadToken, int acceptedEntryCount) { DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)$"Loaded {acceptedEntryCount} synchronized location configuration(s) from the server."); } private static void LogSyncedLocationConfigurationFailure(string payloadToken, Exception ex) { DropNSpawnPlugin.DropNSpawnLogger.LogError((object)$"Failed to deserialize synchronized location payload DTO. {ex}"); } private static void RejectLocalConfigurationPayload(string payload, IEnumerable errors) { if (string.Equals(LoadState.LastRejectedPayload, payload, StringComparison.Ordinal)) { return; } LoadState.LastRejectedPayload = payload; LoadState.PendingStrictPayload = ""; LoadState.LastRejectedValidationKey = ""; DropNSpawnPlugin.DropNSpawnLogger.LogError((object)"Rejected location reload. Keeping the previous authoritative location configuration."); foreach (string item in errors.Where((string message) => !string.IsNullOrWhiteSpace(message)).Distinct(StringComparer.OrdinalIgnoreCase)) { DropNSpawnPlugin.DropNSpawnLogger.LogError((object)item); } } private static void LoadLocalConfiguration(List 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 { MergeConfiguration(ParseConfiguration(document.Yaml ?? ""), 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 ParseConfiguration(string yaml) { if (string.IsNullOrWhiteSpace(yaml)) { return new List(); } return Deserializer.Deserialize>(yaml) ?? new List(); } private static void MergeConfiguration(List configuration, string source) { foreach (LocationConfigurationEntry item in CloneAndNormalizeConfigurationEntries(configuration, source)) { bool flag = HasRunestoneGlobalPinsOverride(item.RunestoneGlobalPins); if (item.Prefab.Length == 0 && !flag) { WarnInvalidEntry("Entry in '" + item.SourcePath + "' is missing prefab."); } else { if (!item.Enabled) { continue; } RemoveEffectiveConfigurationEntry(item.Prefab, item.RuleId); _configuration.Add(item); if (item.Prefab.Length > 0 && HasOverride(item)) { GetOrCreateActiveEntries(item.Prefab).Add(item); if (HasLooseItemStandOverride(item.ItemStands)) { GetOrCreateLooseItemStandEntries(item.Prefab).Add(item); } } } } } private static bool RemoveEffectiveConfigurationEntry(string prefabName, string ruleId) { return RemoveEffectiveConfigurationEntry(_configuration, ActiveEntriesByPrefab, LooseItemStandEntriesByPrefab, prefabName, ruleId); } private static bool RemoveEffectiveConfigurationEntry(List configuration, Dictionary> activeEntriesByPrefab, Dictionary> looseItemStandEntriesByPrefab, 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 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 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 GetOrCreateActiveEntries(string prefabName) { return GetOrCreateActiveEntries(ActiveEntriesByPrefab, prefabName); } private static List GetOrCreateActiveEntries(Dictionary> activeEntriesByPrefab, string prefabName) { if (!activeEntriesByPrefab.TryGetValue(prefabName, out List value)) { value = (activeEntriesByPrefab[prefabName] = new List()); } return value; } private static List GetOrCreateLooseItemStandEntries(string prefabName) { return GetOrCreateLooseItemStandEntries(LooseItemStandEntriesByPrefab, prefabName); } private static List GetOrCreateLooseItemStandEntries(Dictionary> looseItemStandEntriesByPrefab, string prefabName) { if (!looseItemStandEntriesByPrefab.TryGetValue(prefabName, out List value)) { value = (looseItemStandEntriesByPrefab[prefabName] = new List()); } return value; } 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); } } } private static string? NormalizeOptionalString(string? value) { if (value == null) { return null; } string text = value.Trim(); if (text.Length != 0) { return text; } return null; } private static List? NormalizeOptionalStringList(List? values) { if (values == null) { return null; } List list = (from value in values select (value ?? "").Trim() into value where value.Length > 0 select value).ToList(); if (list.Count != 0) { return list; } return null; } private static Dictionary? NormalizeOptionalStringDictionary(Dictionary? values) { if (values == null) { return null; } Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); foreach (KeyValuePair value in values) { object obj; string text3; (obj, text3) = (KeyValuePair)(ref value); if (obj == null) { obj = ""; } string text4 = ((string)obj).Trim(); if (text4.Length != 0) { dictionary[text4] = (text3 ?? "").Trim(); } } if (dictionary.Count != 0) { return dictionary; } return null; } private static void NormalizeVegvisirDefinitions(List? 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(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(); if (location.Weight.HasValue) { location.Weight = Mathf.Max(0f, location.Weight.Value); } } } private static void NormalizeRunestoneDefinitions(List? definitions) { if (definitions == null) { return; } foreach (LocationRunestoneDefinition definition in definitions) { NormalizeRunestoneDefinition(definition); } } private static void NormalizeRunestoneDefinition(LocationRunestoneDefinition? definition) { if (definition == null) { return; } definition.Path = (definition.Path ?? "").Trim(); definition.ExpectedLocationName = definition.ExpectedLocationName?.Trim(); definition.ExpectedLabel = definition.ExpectedLabel?.Trim(); definition.ExpectedTopic = definition.ExpectedTopic?.Trim(); definition.Name = definition.Name?.Trim(); definition.Topic = definition.Topic?.Trim(); definition.Label = definition.Label?.Trim(); definition.Text = definition.Text?.Trim(); definition.LocationName = definition.LocationName?.Trim(); definition.PinName = definition.PinName?.Trim(); definition.PinType = definition.PinType?.Trim(); if (definition.Chance.HasValue) { definition.Chance = Mathf.Clamp01(definition.Chance.Value); } if (definition.RandomTexts == null) { return; } foreach (LocationRunestoneTextDefinition randomText in definition.RandomTexts) { randomText.Topic = randomText.Topic?.Trim(); randomText.Label = randomText.Label?.Trim(); randomText.Text = randomText.Text?.Trim(); } } private static void NormalizeRunestoneGlobalPinsDefinition(LocationRunestoneGlobalPinsDefinition? definition) { if (definition == null || definition.TargetLocations == null) { return; } foreach (LocationRunestoneGlobalPinTargetDefinition targetLocation in definition.TargetLocations) { targetLocation.LocationName = (targetLocation.LocationName ?? "").Trim(); targetLocation.PinName = targetLocation.PinName?.Trim(); targetLocation.PinType = targetLocation.PinType?.Trim(); targetLocation.SourceBiomes = (from value in targetLocation.SourceBiomes?.Select((string value) => (value ?? "").Trim()) where value.Length > 0 select value).Distinct(StringComparer.OrdinalIgnoreCase).ToList(); if (targetLocation.Chance.HasValue) { targetLocation.Chance = Mathf.Clamp01(targetLocation.Chance.Value); } } } private static void NormalizeItemStandDefinitions(List? 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(StringComparer.OrdinalIgnoreCase).ToList(); definition.SupportedItems = (from value in definition.SupportedItems?.Select((string value) => (value ?? "").Trim()) where value.Length > 0 select value).Distinct(StringComparer.OrdinalIgnoreCase).ToList(); definition.UnsupportedItems = (from value in definition.UnsupportedItems?.Select((string value) => (value ?? "").Trim()) where value.Length > 0 select value).Distinct(StringComparer.OrdinalIgnoreCase).ToList(); } } private static void FinalizeNormalizedEntry(LocationConfigurationEntry entry) { entry.RuleId = NormalizeOptionalRuleId(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, Runestones = entry.Runestones, RunestoneGlobalPins = entry.RunestoneGlobalPins }; return entry.Prefab + ":" + NetworkPayloadSyncSupport.ComputeLocationEntryIdentitySignature(entry2); } private static string? NormalizeOptionalRuleId(string? ruleId) { if (ruleId == null) { return null; } string text = ruleId.Trim(); if (text.Length != 0) { return text; } return null; } private static void StripRedundantLocationComponentConditions(LocationConfigurationEntry entry, string source) { StripRedundantLocationFilter(entry.Prefab, "conditions", entry.Conditions, source); StripUnsupportedLocationConditionFields(entry.Prefab, "conditions", entry.Conditions); } 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 void StripUnsupportedLocationConditionFields(string prefabName, string componentName, ConditionsDefinition? conditions) { if (conditions != null) { string text = (string.IsNullOrWhiteSpace(prefabName) ? "(missing prefab)" : prefabName.Trim()); IntRangeDefinition? level = conditions.Level; if ((level != null && level.HasValues()) || conditions.MinLevel.HasValue || conditions.MaxLevel.HasValue) { WarnInvalidEntry("Entry '" + text + "' uses " + componentName + ".conditions.level, but level filters are only valid for character conditions. The key was ignored."); conditions.Level = null; conditions.MinLevel = null; conditions.MaxLevel = null; } if (conditions.TimeOfDay != null) { WarnInvalidEntry("Entry '" + text + "' uses " + componentName + ".conditions.timeOfDay, but location conditions are evaluated only when the location is loaded or reconciled. The key was ignored."); conditions.TimeOfDay = null; } List? requiredEnvironments = conditions.RequiredEnvironments; if (requiredEnvironments != null && requiredEnvironments.Count > 0) { WarnInvalidEntry("Entry '" + text + "' uses " + componentName + ".conditions.requiredEnvironments, but location conditions are evaluated only when the location is loaded or reconciled. The key was ignored."); conditions.RequiredEnvironments = null; } List? requiredGlobalKeys = conditions.RequiredGlobalKeys; if (requiredGlobalKeys != null && requiredGlobalKeys.Count > 0) { WarnInvalidEntry("Entry '" + text + "' uses " + componentName + ".conditions.requiredGlobalKeys, but location conditions are static location filters only. The key was ignored."); conditions.RequiredGlobalKeys = null; } List? forbiddenGlobalKeys = conditions.ForbiddenGlobalKeys; if (forbiddenGlobalKeys != null && forbiddenGlobalKeys.Count > 0) { WarnInvalidEntry("Entry '" + text + "' uses " + componentName + ".conditions.forbiddenGlobalKeys, but location conditions are static location filters only. The key was ignored."); conditions.ForbiddenGlobalKeys = null; } List? states = conditions.States; if (states != null && states.Count > 0) { WarnInvalidEntry("Entry '" + text + "' uses " + componentName + ".conditions.states, but state filters are only valid for character conditions. The key was ignored."); conditions.States = null; } List? factions = conditions.Factions; if (factions != null && factions.Count > 0) { WarnInvalidEntry("Entry '" + text + "' uses " + componentName + ".conditions.factions, but faction filters are only valid for character conditions. The key was ignored."); conditions.Factions = null; } if (conditions.InsidePlayerBase.HasValue) { WarnInvalidEntry("Entry '" + text + "' uses " + componentName + ".conditions.insidePlayerBase, but location conditions are static location filters only. The key was ignored."); conditions.InsidePlayerBase = null; } } } private static bool HasOverride(LocationConfigurationEntry entry) { if (!HasOfferingBowlOverride(entry.OfferingBowl) && !HasItemStandOverride(entry.ItemStands) && !HasVegvisirOverride(entry.Vegvisirs)) { return HasRunestoneOverride(entry.Runestones); } return true; } private static bool HasRunestoneGlobalPinsOverride(LocationRunestoneGlobalPinsDefinition? definition) { return definition?.TargetLocations != null; } private static bool HasOfferingBowlOverride(LocationOfferingBowlDefinition? definition) { if (definition == null) { return false; } 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) { return definition.Objects != null; } } return true; } private static bool HasVegvisirOverride(List? definitions) { return definitions?.Any(HasVegvisirOverride) ?? false; } private static bool HasVegvisirOverride(LocationVegvisirDefinition? definition) { if (definition == null) { return false; } if (definition.Name == null && definition.UseText == null && definition.HoverName == null && definition.SetsGlobalKey == null && definition.SetsPlayerKey == null) { return definition.Locations != null; } return true; } private static bool HasRunestoneOverride(List? definitions) { return definitions?.Any(HasRunestoneOverride) ?? false; } private static bool HasRunestoneOverride(LocationRunestoneDefinition? definition) { if (definition == null) { return false; } if (definition.Name == null && definition.Topic == null && definition.Label == null && definition.Text == null && definition.RandomTexts == null && definition.LocationName == null && definition.PinName == null && definition.PinType == null && !definition.ShowMap.HasValue) { return definition.Chance.HasValue; } return true; } private static bool HasItemStandOverride(List? definitions) { return definitions?.Any(HasItemStandOverride) ?? false; } private static bool HasLooseItemStandOverride(List? definitions) { return definitions?.Any(HasLooseItemStandOverride) ?? false; } private static bool HasItemStandOverride(LocationItemStandDefinition? definition) { if (definition == null) { return false; } if (definition.Name == null && !definition.CanBeRemoved.HasValue && !definition.AutoAttach.HasValue && definition.OrientationType == null && definition.SupportedTypes == null && definition.SupportedItems == null && definition.UnsupportedItems == null && !definition.PowerActivationDelay.HasValue) { return definition.GuardianPower != null; } return true; } private static bool HasLooseItemStandOverride(LocationItemStandDefinition? definition) { return HasItemStandOverride(definition); } private static bool HasConditions(ConditionsDefinition? conditions) { return DropConditionEvaluator.HasConditions(conditions); } [IteratorStateMachine(typeof(d__227))] private static IEnumerable EnumerateOverrideConfigurationPaths() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__227(-2); } private static IEnumerable EnumerateSupplementalOverrideConfigurationPaths() { return DomainConfigurationFileSupport.EnumerateSupplementalOverrideConfigurationPaths("location", IsOverrideConfigurationFileName); } private static bool IsOverrideConfigurationFileName(string fileName) { if (string.IsNullOrWhiteSpace(fileName)) { return false; } if (!fileName.Equals(PluginSettingsFacade.GetYamlDomainFilePrefix("location") + ".yml", StringComparison.OrdinalIgnoreCase) && !fileName.Equals(PluginSettingsFacade.GetYamlDomainFilePrefix("location") + ".yaml", StringComparison.OrdinalIgnoreCase)) { if (fileName.StartsWith(PluginSettingsFacade.GetYamlDomainSupplementalPrefix("location"), StringComparison.OrdinalIgnoreCase)) { if (!fileName.EndsWith(".yml", StringComparison.OrdinalIgnoreCase)) { return fileName.EndsWith(".yaml", StringComparison.OrdinalIgnoreCase); } return true; } return false; } return true; } private static void CaptureReferenceSnapshotsIfNeeded() { 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(); LooseItemStandSnapshots.Clear(); TrackedLooseItemStandPrefabs.Clear(); LooseItemStandAuthoredPathsByInstance.Clear(); PendingLocationProxyCreationPrefabs.Clear(); if (!preserveLiveRegistries) { LiveLocationsByPrefab.Clear(); LiveLocationPrefabsByInstance.Clear(); TrackedLocationProxies.Clear(); RuntimeLocationProxyPrefabsByInstance.Clear(); RuntimeLocationProxyPrefabsByZdoId.Clear(); _runtimeLocationAliasEpoch++; } RefreshLocationProxyObservationDemandLocked(); } private static void ClearQueuedReconcileState() { _reconcileQueueEpoch++; PendingLocationReconciles.Clear(); PendingLocationReconcileIds.Clear(); SuppressedQueuedLocationReconciles.Clear(); PendingLocationRootReconciles.Clear(); PendingLocationRootReconcileIds.Clear(); PendingLooseOfferingBowlOverrides.Clear(); PendingLooseOfferingBowlOverrideIds.Clear(); PendingLocationProxyAliasZdoFlushIds.Clear(); PendingLocationProxyAliasZdoFlushes.Clear(); PendingLocationProxyAliasZdoFlushEnqueuedDueFrames.Clear(); PendingLocationProxyObservations.Clear(); PendingLocationProxyObservationIds.Clear(); _locationProxyAliasFlushBudgetFrame = int.MinValue; _locationProxyAliasFlushesSentThisFrame = 0; } private static void RefreshReferenceSnapshots() { ResetReferenceSnapshots(); CaptureReferenceSnapshotsIfNeeded(); } private static void CaptureSnapshot(ZoneLocation location) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) if (!location.m_prefab.IsValid) { return; } string zoneLocationPrefabName = GetZoneLocationPrefabName(location); if (zoneLocationPrefabName.Length == 0 || SnapshotsByPrefab.ContainsKey(zoneLocationPrefabName)) { return; } location.m_prefab.Load(); GameObject rootPrefab = location.m_prefab.Asset; if ((Object)(object)rootPrefab == (Object)null) { return; } List list = new List(); List list2 = new List(); List list3 = new List(); List list4 = new List(); CollectLocationRuntimeComponents(rootPrefab.transform, list, list2, list3, list4); OfferingBowl[] array = list.ToArray(); ItemStand[] array2 = list2.ToArray(); Vegvisir[] array3 = list3.ToArray(); RuneStone[] array4 = list4.ToArray(); if (array.Length != 0 || array2.Length != 0 || array3.Length != 0 || array4.Length != 0) { WarnDuplicateComponent(zoneLocationPrefabName, "OfferingBowl", array.Length); LocationSnapshot locationSnapshot = new LocationSnapshot { Prefab = zoneLocationPrefabName, OfferingBowl = ((array.Length != 0) ? CaptureOfferingBowlSnapshot(array[0]) : null), ItemStands = array2.Select((ItemStand itemStand) => CapturePathScopedItemStandSnapshot(rootPrefab.transform, itemStand)).OrderBy((PathScopedItemStandSnapshot itemStand) => itemStand.Path, StringComparer.Ordinal).ToList(), Vegvisirs = array3.Select((Vegvisir vegvisir) => CaptureVegvisirSnapshot(rootPrefab.transform, vegvisir)).OrderBy((PathScopedVegvisirSnapshot vegvisir) => vegvisir.Path, StringComparer.Ordinal).ToList(), Runestones = array4.Select((RuneStone runestone) => CaptureRunestoneSnapshot(rootPrefab.transform, runestone)).OrderBy((PathScopedRunestoneSnapshot runestone) => runestone.Path, StringComparer.Ordinal).ToList() }; Snapshots.Add(locationSnapshot); SnapshotsByPrefab[zoneLocationPrefabName] = locationSnapshot; } } private static void WarnDuplicateComponent(string prefabName, string componentName, int count) { if (count > 1) { string item = prefabName + "@" + componentName; if (DuplicateComponentWarnings.Add(item)) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("Location prefab '" + prefabName + "' has multiple " + componentName + " components. The first one will be used for location.yml.")); } } } private static OfferingBowlSnapshot CaptureOfferingBowlSnapshot(OfferingBowl offeringBowl) { return new OfferingBowlSnapshot { Name = offeringBowl.m_name, UseItemText = offeringBowl.m_useItemText, UsedAltarText = offeringBowl.m_usedAltarText, CantOfferText = offeringBowl.m_cantOfferText, WrongOfferText = offeringBowl.m_wrongOfferText, IncompleteOfferText = offeringBowl.m_incompleteOfferText, BossItem = (NormalizeReferencePrefabName(((Object)(object)offeringBowl.m_bossItem != (Object)null) ? ((Component)offeringBowl.m_bossItem).gameObject : null) ?? ""), BossItems = offeringBowl.m_bossItems, BossPrefab = (NormalizeReferencePrefabName(offeringBowl.m_bossPrefab) ?? ""), ItemPrefab = (NormalizeReferencePrefabName(((Object)(object)offeringBowl.m_itemPrefab != (Object)null) ? ((Component)offeringBowl.m_itemPrefab).gameObject : null) ?? ""), SetGlobalKey = offeringBowl.m_setGlobalKey, RenderSpawnAreaGizmos = offeringBowl.m_renderSpawnAreaGizmos, AlertOnSpawn = offeringBowl.m_alertOnSpawn, SpawnBossDelay = offeringBowl.m_spawnBossDelay, SpawnBossMaxDistance = offeringBowl.m_spawnBossMaxDistance, SpawnBossMinDistance = offeringBowl.m_spawnBossMinDistance, SpawnBossMaxYDistance = offeringBowl.m_spawnBossMaxYDistance, GetSolidHeightMargin = offeringBowl.m_getSolidHeightMargin, EnableSolidHeightCheck = offeringBowl.m_enableSolidHeightCheck, SpawnPointClearingRadius = offeringBowl.m_spawnPointClearingRadius, SpawnYOffset = offeringBowl.m_spawnYOffset, UseItemStands = offeringBowl.m_useItemStands, ItemStandPrefix = offeringBowl.m_itemStandPrefix, ItemStandMaxRange = offeringBowl.m_itemstandMaxRange }; } private static PathScopedVegvisirSnapshot CaptureVegvisirSnapshot(Transform root, Vegvisir vegvisir) { return new PathScopedVegvisirSnapshot { Path = GetRelativePath(root, ((Component)vegvisir).transform), Snapshot = CaptureVegvisirSnapshot(vegvisir) }; } private static VegvisirSnapshot CaptureVegvisirSnapshot(Vegvisir vegvisir) { return new VegvisirSnapshot { Name = vegvisir.m_name, UseText = vegvisir.m_useText, HoverName = vegvisir.m_hoverName, SetsGlobalKey = vegvisir.m_setsGlobalKey, SetsPlayerKey = vegvisir.m_setsPlayerKey, Locations = vegvisir.m_locations.Select((VegvisrLocation location) => new VegvisirTargetSnapshot { LocationName = location.m_locationName, PinName = location.m_pinName, PinType = ((object)(PinType)(ref location.m_pinType)).ToString(), DiscoverAll = location.m_discoverAll, ShowMap = location.m_showMap }).ToList() }; } private static PathScopedRunestoneSnapshot CaptureRunestoneSnapshot(Transform root, RuneStone runestone) { return new PathScopedRunestoneSnapshot { Path = GetRelativePath(root, ((Component)runestone).transform), Snapshot = CaptureRunestoneSnapshot(runestone) }; } private static RunestoneSnapshot CaptureRunestoneSnapshot(RuneStone runestone) { return new RunestoneSnapshot { Name = runestone.m_name, Topic = runestone.m_topic, Label = runestone.m_label, Text = runestone.m_text, RandomTexts = (runestone.m_randomTexts ?? new List()).Select((RandomRuneText text) => new RunestoneTextSnapshot { Topic = text.m_topic, Label = text.m_label, Text = text.m_text }).ToList(), LocationName = runestone.m_locationName, PinName = runestone.m_pinName, PinType = ((object)(PinType)(ref runestone.m_pinType)).ToString(), ShowMap = runestone.m_showMap }; } private static ItemStandSnapshot CaptureItemStandSnapshot(ItemStand itemStand) { return new ItemStandSnapshot { Name = itemStand.m_name, CanBeRemoved = itemStand.m_canBeRemoved, AutoAttach = itemStand.m_autoAttach, OrientationType = ((object)(Orientation)(ref itemStand.m_orientationType)).ToString(), SupportedTypes = itemStand.m_supportedTypes.Select((ItemType type) => ((object)(ItemType)(ref type)).ToString()).ToList(), SupportedItems = (from item in itemStand.m_supportedItems where (Object)(object)item != (Object)null select NormalizeReferencePrefabName(((Component)item).gameObject) ?? "" into name where name.Length > 0 select name).ToList(), UnsupportedItems = (from item in itemStand.m_unsupportedItems where (Object)(object)item != (Object)null select NormalizeReferencePrefabName(((Component)item).gameObject) ?? "" into name where name.Length > 0 select name).ToList(), PowerActivationDelay = itemStand.m_powerActivationDelay, GuardianPower = (((Object)(object)itemStand.m_guardianPower != (Object)null) ? ((Object)itemStand.m_guardianPower).name : "") }; } private static void ApplyIfReady(bool queueLiveReconcile = false) { if (IsGameDataReady() && (DropNSpawnPlugin.IsSourceOfTruth || Volatile.Read(ref _synchronizedPayloadReady))) { int num = ComputeGameDataSignature(); bool flag = PluginSettingsFacade.IsLocationDomainEnabled(); Dictionary currentEntrySignatures = BuildActiveEntrySignaturesByPrefab(); if (!StandardDomainApplySupport.IsAlreadyApplied(_lastAppliedGameDataSignature, num, _lastAppliedDomainEnabled, flag, _lastAppliedConfigurationSignature, _configurationSignature) || _lastAppliedSynchronizedPayloadReady != Volatile.Read(ref _synchronizedPayloadReady)) { RunApplyCoordinator(num, flag, currentEntrySignatures, queueLiveReconcile); } } } private static void ValidateConfiguredPrefabs() { if ((Object)(object)ZoneSystem.instance == (Object)null) { return; } HashSet hashSet = new HashSet(StringComparer.OrdinalIgnoreCase); foreach (ZoneLocation location in ZoneSystem.instance.m_locations) { string text = (location?.m_prefabName ?? location?.m_prefab.Name ?? "").Trim(); if (text.Length > 0) { hashSet.Add(text); } } foreach (var (text3, list2) in ActiveEntriesByPrefab) { if (hashSet.Contains(text3)) { continue; } foreach (LocationConfigurationEntry item in list2) { if (LooksLikeExternalLocationAlias(text3)) { continue; } string locationPrefabBaseName = GetLocationPrefabBaseName(text3); if (text3.IndexOf(':') >= 0 && locationPrefabBaseName.Length > 0 && hashSet.Contains(locationPrefabBaseName)) { if (!IsServerSynchronizedLocationSource(item.SourcePath)) { WarnInvalidEntry("Location prefab '" + text3 + "' from " + DescribeEntrySource(item.SourcePath) + " was not found in ZoneSystem, but base prefab '" + locationPrefabBaseName + "' exists. If this is an external alias, it must be observed at runtime; otherwise this may be a typo."); } } else { WarnInvalidEntry("Location prefab '" + text3 + "' from " + DescribeEntrySource(item.SourcePath) + " was not found in ZoneSystem."); } } } } private static bool LooksLikeExternalLocationAlias(string prefabName) { string prefabName2 = prefabName; if (string.IsNullOrWhiteSpace(prefabName2) || prefabName2.IndexOf(':') < 0) { return false; } if (!RuntimeLocationProxyPrefabsByInstance.Values.Any((string value) => string.Equals(value, prefabName2, StringComparison.OrdinalIgnoreCase)) && !RuntimeLocationProxyPrefabsByZdoId.Values.Any((string value) => string.Equals(value, prefabName2, StringComparison.OrdinalIgnoreCase)) && !LiveLocationPrefabsByInstance.Values.Any((string value) => string.Equals(value, prefabName2, StringComparison.OrdinalIgnoreCase)) && !LiveLocationsByPrefab.ContainsKey(prefabName2)) { return CatalogsByPrefab.ContainsKey(prefabName2); } return true; } private static void RefreshLocationProxyObservationDemandLocked() { HashSet hashSet = new HashSet(StringComparer.OrdinalIgnoreCase); CollectPendingRuntimeLocationProxyAliasDemandsLocked(ActiveEntriesByPrefab.Keys, hashSet); CollectPendingRuntimeLocationProxyAliasDemandsLocked(LooseItemStandEntriesByPrefab.Keys, hashSet); bool flag = !PendingRuntimeLocationProxyAliasDemands.SetEquals(hashSet); if (flag) { PendingRuntimeLocationProxyAliasDemands.Clear(); foreach (string item in hashSet) { PendingRuntimeLocationProxyAliasDemands.Add(item); } PendingLocationProxyObservations.Clear(); PendingLocationProxyObservationIds.Clear(); _locationProxyObservationDemandEpoch++; } _needsRuntimeLocationProxyObservation = PendingRuntimeLocationProxyAliasDemands.Count > 0; if (_needsRuntimeLocationProxyObservation && (flag || PendingLocationProxyObservationIds.Count == 0)) { QueueTrackedLocationProxyObservationsLocked(Time.frameCount); } } private static void CollectPendingRuntimeLocationProxyAliasDemandsLocked(IEnumerable prefabNames, HashSet target) { foreach (string item in prefabNames ?? Enumerable.Empty()) { string text = (item ?? "").Trim(); if (text.Length != 0 && text.IndexOf(':') >= 0 && !LooksLikeExternalLocationAlias(text)) { target.Add(text); } } } private static bool IsServerSynchronizedLocationSource(string? sourcePath) { return (sourcePath ?? "").Trim().StartsWith("ServerSync:", StringComparison.OrdinalIgnoreCase); } private static void RecordAppliedState(int gameDataSignature, bool domainEnabled, Dictionary currentEntrySignatures) { _lastAppliedGameDataSignature = gameDataSignature; _lastAppliedDomainEnabled = domainEnabled; _lastAppliedConfigurationSignature = _configurationSignature; _lastAppliedSynchronizedPayloadReady = Volatile.Read(ref _synchronizedPayloadReady); ReplaceEntrySignatures(_lastAppliedEntrySignaturesByPrefab, currentEntrySignatures); } private static void ReapplyActiveEntriesToRegisteredLocations(HashSet prefabs) { foreach (Location registeredLocation in GetRegisteredLocations(prefabs)) { if ((Object)(object)registeredLocation != (Object)null) { ReconcileLocationInstanceInternal(registeredLocation); } } RefreshTrackedLooseItemStands(prefabs); } private static void QueueRegisteredLocationReconciles(HashSet prefabs) { foreach (Location registeredLocation in GetRegisteredLocations(prefabs)) { if ((Object)(object)registeredLocation != (Object)null) { QueueLocationReconcile(registeredLocation); } } RefreshTrackedLooseItemStands(prefabs); } private static Dictionary BuildActiveEntrySignaturesByPrefab() { return DomainEntrySignatureSupport.BuildSignaturesByKey(ActiveEntriesByPrefab, NetworkPayloadSyncSupport.ComputeLocationConfigurationSignature); } private static HashSet BuildDirtyPrefabs(Dictionary previous, Dictionary current) { return DomainDictionaryDiffSupport.BuildDirtyKeys(previous, current); } private static HashSet BuildRegisteredCatchupPrefabs(bool domainEnabled, Dictionary currentEntrySignatures) { HashSet hashSet = new HashSet(StringComparer.OrdinalIgnoreCase); if (domainEnabled) { foreach (string key in currentEntrySignatures.Keys) { hashSet.Add(key); } } if (_lastAppliedDomainEnabled.GetValueOrDefault()) { foreach (string key2 in _lastAppliedEntrySignaturesByPrefab.Keys) { hashSet.Add(key2); } } return hashSet; } private static void ReplaceEntrySignatures(Dictionary target, Dictionary source) { DomainDictionaryDiffSupport.ReplaceEntries(target, source); } private static void RegisterLiveLocation(Location location, string prefabName) { if ((Object)(object)location == (Object)null || (Object)(object)((Component)location).gameObject == (Object)null || prefabName.Length == 0) { return; } if (LiveLocationPrefabsByInstance.TryGetValue(location, out string value)) { if (string.Equals(value, prefabName, StringComparison.OrdinalIgnoreCase)) { return; } UnregisterLiveLocation(location, value); } LiveLocationPrefabsByInstance[location] = prefabName; if (!LiveLocationsByPrefab.TryGetValue(prefabName, out HashSet value2)) { value2 = new HashSet(); LiveLocationsByPrefab[prefabName] = value2; } value2.Add(location); } private static void TrackLocationInstanceInternal(Location? location) { if (!((Object)(object)location == (Object)null) && TryGetLocationPrefabName(location, out string prefabName)) { RegisterLiveLocation(location, prefabName); } } [IteratorStateMachine(typeof(d__259))] private static IEnumerable GetRegisteredLocations(HashSet dirtyPrefabs) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__259(-2) { <>3__dirtyPrefabs = dirtyPrefabs }; } private static void CleanupRegisteredLocations() { List list = null; foreach (Location key in LiveLocationPrefabsByInstance.Keys) { if ((Object)(object)key == (Object)null || (Object)(object)((Component)key).gameObject == (Object)null) { if (list == null) { list = new List(); } list.Add(key); } } if (list == null) { return; } foreach (Location item in list) { if (LiveLocationPrefabsByInstance.TryGetValue(item, out string value)) { UnregisterLiveLocation(item, value); } } } private static void UnregisterLiveLocation(Location location, string prefabName) { LiveLocationPrefabsByInstance.Remove(location); LiveLocationSnapshots.Remove(location); if (LiveLocationsByPrefab.TryGetValue(prefabName, out HashSet value)) { value.Remove(location); if (value.Count == 0) { LiveLocationsByPrefab.Remove(prefabName); } } } private static void ReconcileLocationInstanceInternal(Location location, LocationRuntimeComponents? runtimeComponents = null) { if ((Object)(object)location == (Object)null || !TryGetLocationPrefabName(location, out string prefabName)) { return; } RegisterLiveLocation(location, prefabName); bool flag = PluginSettingsFacade.IsLocationDomainEnabled(); bool flag2 = LiveLocationSnapshots.ContainsKey(location); List list = null; if (flag) { EnsureRuntimeConfigurationState(); if (_runtimeConfigurationState.PlansByPrefab.TryGetValue(prefabName, out CompiledLocationPrefabPlan value) && value.ActiveEntryPlans.Count > 0) { list = value.ActiveEntryPlans; } } bool flag3 = list != null; if (flag2 || flag3) { Transform val = runtimeComponents?.Root ?? ((Component)location).transform; IReadOnlyList readOnlyList; IReadOnlyList readOnlyList2; IReadOnlyList readOnlyList3; IReadOnlyList readOnlyList4; if (runtimeComponents != null) { readOnlyList = runtimeComponents.OfferingBowls; readOnlyList2 = runtimeComponents.ItemStands; readOnlyList3 = runtimeComponents.Vegvisirs; readOnlyList4 = runtimeComponents.Runestones; } else { List list2 = new List(); List list3 = new List(); List list4 = new List(); List list5 = new List(); CollectLocationRuntimeComponents(val, list2, list3, list4, list5); readOnlyList = list2; readOnlyList2 = list3; readOnlyList3 = list4; readOnlyList4 = list5; } OfferingBowl offeringBowl = runtimeComponents?.PrimaryOfferingBowl ?? readOnlyList.FirstOrDefault(); LocationComponentCatalog orCreateLocationComponentCatalog = GetOrCreateLocationComponentCatalog(prefabName, val, readOnlyList, readOnlyList2, readOnlyList3, readOnlyList4); CaptureLiveLocationSnapshotIfNeeded(location, prefabName, val, readOnlyList, readOnlyList2, readOnlyList3, readOnlyList4); if (runtimeComponents != null) { RestoreLiveLocationSnapshot(location, runtimeComponents); } else { RestoreLiveLocationSnapshot(location, val, readOnlyList, readOnlyList2, readOnlyList3, readOnlyList4); } if (flag && list != null) { Dictionary liveVegvisirsByPath = runtimeComponents?.VegvisirsByPath ?? BuildVegvisirLookup(val, readOnlyList3); Dictionary liveRunestonesByPath = runtimeComponents?.RunestonesByPath ?? BuildRunestoneLookup(val, readOnlyList4); LogLocationReconcileCandidate(location, prefabName, offeringBowl, readOnlyList2, readOnlyList3.Count, readOnlyList4.Count, orCreateLocationComponentCatalog, LiveLocationSnapshots[location]); List relevantItemStands = runtimeComponents?.RelevantItemStands ?? GetRelevantLocationItemStands(offeringBowl, readOnlyList2); Dictionary liveItemStandsByPath = runtimeComponents?.ItemStandsByPath ?? BuildItemStandLookup(val, readOnlyList2); ApplyCompiledLocationEntryPlans(((Component)location).gameObject, list, offeringBowl, relevantItemStands, liveItemStandsByPath, liveVegvisirsByPath, liveRunestonesByPath, prefabName, val); } } } private static LocationComponentCatalog GetOrCreateLocationComponentCatalog(string prefabName, Transform locationRoot, IReadOnlyList offeringBowls, IReadOnlyList itemStands, IReadOnlyList vegvisirs, IReadOnlyList runestones) { Transform locationRoot2 = locationRoot; if (CatalogsByPrefab.TryGetValue(prefabName, out LocationComponentCatalog value)) { return value; } WarnDuplicateComponent(prefabName, "OfferingBowl", offeringBowls.Count); LocationComponentCatalog locationComponentCatalog = new LocationComponentCatalog { Prefab = prefabName, OfferingBowlPath = ((offeringBowls.Count > 0) ? GetRelativePath(locationRoot2, ((Component)offeringBowls[0]).transform) : null), ItemStandPaths = (from itemStand in itemStands where (Object)(object)itemStand != (Object)null select GetRelativePath(locationRoot2, ((Component)itemStand).transform)).OrderBy((string path) => path, StringComparer.Ordinal).ToList(), VegvisirPaths = (from vegvisir in vegvisirs where (Object)(object)vegvisir != (Object)null select GetRelativePath(locationRoot2, ((Component)vegvisir).transform)).OrderBy((string path) => path, StringComparer.Ordinal).ToList(), RunestonePaths = (from runestone in runestones where (Object)(object)runestone != (Object)null select GetRelativePath(locationRoot2, ((Component)runestone).transform)).OrderBy((string path) => path, StringComparer.Ordinal).ToList() }; CatalogsByPrefab[prefabName] = locationComponentCatalog; return locationComponentCatalog; } private static void CaptureLiveLocationSnapshotIfNeeded(Location location, string prefabName, Transform locationRoot, IReadOnlyList offeringBowls, IReadOnlyList itemStands, IReadOnlyList vegvisirs, IReadOnlyList runestones) { Transform locationRoot2 = locationRoot; if (!LiveLocationSnapshots.ContainsKey(location)) { LiveLocationSnapshots[location] = new LiveLocationSnapshot { Prefab = prefabName, OfferingBowl = ((offeringBowls.Count > 0) ? CapturePathScopedOfferingBowlSnapshot(locationRoot2, offeringBowls[0]) : null), ItemStands = (from itemStand in itemStands where (Object)(object)itemStand != (Object)null select CapturePathScopedItemStandSnapshot(locationRoot2, itemStand)).OrderBy((PathScopedItemStandSnapshot snapshot) => snapshot.Path, StringComparer.Ordinal).ToList(), Vegvisirs = (from vegvisir in vegvisirs where (Object)(object)vegvisir != (Object)null select CaptureVegvisirSnapshot(locationRoot2, vegvisir)).OrderBy((PathScopedVegvisirSnapshot snapshot) => snapshot.Path, StringComparer.Ordinal).ToList(), Runestones = (from runestone in runestones where (Object)(object)runestone != (Object)null select CaptureRunestoneSnapshot(locationRoot2, runestone)).OrderBy((PathScopedRunestoneSnapshot snapshot) => snapshot.Path, StringComparer.Ordinal).ToList() }; } } private static void RestoreLiveLocationSnapshot(Location location, LocationRuntimeComponents runtimeComponents) { if (!LiveLocationSnapshots.TryGetValue(location, out LiveLocationSnapshot value)) { return; } if (value.OfferingBowl != null && runtimeComponents.OfferingBowlsByPath.TryGetValue(value.OfferingBowl.Path, out OfferingBowl value2)) { RestoreOfferingBowl(value2, value.OfferingBowl.Snapshot); } foreach (PathScopedItemStandSnapshot itemStand in value.ItemStands) { if (runtimeComponents.ItemStandsByPath.TryGetValue(itemStand.Path, out ItemStand value3)) { RestoreItemStand(value3, itemStand.Snapshot); } } foreach (PathScopedVegvisirSnapshot vegvisir in value.Vegvisirs) { if (runtimeComponents.VegvisirsByPath.TryGetValue(vegvisir.Path, out Vegvisir value4)) { RestoreVegvisir(value4, vegvisir.Snapshot); } } foreach (PathScopedRunestoneSnapshot runestone in value.Runestones) { if (runtimeComponents.RunestonesByPath.TryGetValue(runestone.Path, out RuneStone value5)) { RestoreRunestone(value5, runestone.Snapshot); } } } private static void RestoreLiveLocationSnapshot(Location location, Transform locationRoot, IReadOnlyList offeringBowls, IReadOnlyList itemStands, IReadOnlyList vegvisirs, IReadOnlyList runestones) { if (!LiveLocationSnapshots.TryGetValue(location, out LiveLocationSnapshot value)) { return; } Dictionary dictionary = BuildOfferingBowlLookup(locationRoot, offeringBowls); if (value.OfferingBowl != null && dictionary.TryGetValue(value.OfferingBowl.Path, out var value2)) { RestoreOfferingBowl(value2, value.OfferingBowl.Snapshot); } Dictionary dictionary2 = BuildItemStandLookup(locationRoot, itemStands); foreach (PathScopedItemStandSnapshot itemStand in value.ItemStands) { if (dictionary2.TryGetValue(itemStand.Path, out var value3)) { RestoreItemStand(value3, itemStand.Snapshot); } } Dictionary dictionary3 = BuildVegvisirLookup(locationRoot, vegvisirs); foreach (PathScopedVegvisirSnapshot vegvisir in value.Vegvisirs) { if (dictionary3.TryGetValue(vegvisir.Path, out var value4)) { RestoreVegvisir(value4, vegvisir.Snapshot); } } Dictionary dictionary4 = BuildRunestoneLookup(locationRoot, runestones); foreach (PathScopedRunestoneSnapshot runestone in value.Runestones) { if (dictionary4.TryGetValue(runestone.Path, out var value5)) { RestoreRunestone(value5, runestone.Snapshot); } } } private static PathScopedOfferingBowlSnapshot CapturePathScopedOfferingBowlSnapshot(Transform root, OfferingBowl offeringBowl) { return new PathScopedOfferingBowlSnapshot { Path = GetRelativePath(root, ((Component)offeringBowl).transform), Snapshot = CaptureOfferingBowlSnapshot(offeringBowl) }; } private static PathScopedItemStandSnapshot CapturePathScopedItemStandSnapshot(Transform root, ItemStand itemStand) { return new PathScopedItemStandSnapshot { Path = GetRelativePath(root, ((Component)itemStand).transform), Snapshot = CaptureItemStandSnapshot(itemStand) }; } private static List GetRelevantLocationItemStands(OfferingBowl? offeringBowl, IEnumerable childItemStands) { List list = new List(); HashSet hashSet = new HashSet(); foreach (ItemStand childItemStand in childItemStands) { if ((Object)(object)childItemStand != (Object)null && hashSet.Add(((Object)childItemStand).GetInstanceID())) { list.Add(childItemStand); } } if ((Object)(object)offeringBowl == (Object)null || !offeringBowl.m_useItemStands) { return list; } foreach (ItemStand item in AltarItemStandHoverInfoFormatter.FindRelevantItemStands(offeringBowl)) { if ((Object)(object)item != (Object)null && hashSet.Add(((Object)item).GetInstanceID())) { list.Add(item); } } return list; } private static bool TryGetLocationPrefabName(Location location, out string prefabName) { prefabName = ""; if ((Object)(object)location == (Object)null) { return false; } LocationProxy componentInParent = ((Component)location).GetComponentInParent(true); if ((Object)(object)componentInParent != (Object)null && TryGetRecordedLocationProxyPrefabName(componentInParent, out prefabName)) { return true; } if (TryGetLocationPrefabNameWithoutProxy(location, out prefabName)) { return true; } componentInParent = ((Component)location).GetComponentInParent(true); if ((Object)(object)componentInParent != (Object)null) { return TryGetLocationProxyHashPrefabName(componentInParent, out prefabName); } return false; } private static bool TryGetLocationPrefabNameWithoutProxy(Location location, out string prefabName) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) prefabName = ""; if ((Object)(object)location == (Object)null) { return false; } string text = TrimCloneSuffix(((Object)((Component)location).gameObject).name); string text2 = TryGetLocationRootPrefabName(location); string text3 = ""; if ((Object)(object)ZoneSystem.instance != (Object)null) { Vector2i zone = ZoneSystem.GetZone(((Component)location).transform.position); if (ZoneSystem.instance.m_locationInstances.TryGetValue(zone, out var value)) { text3 = GetZoneLocationPrefabName(value.m_location); } } if (ShouldPreferLiveLocationPrefabName(text2, text3)) { prefabName = text2; return true; } if (ShouldPreferLiveLocationPrefabName(text, text3)) { prefabName = text; return true; } if (text3.Length > 0) { prefabName = text3; return true; } prefabName = text; return prefabName.Length > 0; } private static string TryGetLocationRootPrefabName(Location location) { if ((Object)(object)location == (Object)null) { return ""; } Transform val = null; LocationProxy componentInParent = ((Component)location).GetComponentInParent(true); if ((Object)(object)componentInParent != (Object)null) { Transform val2 = ((Component)location).transform; while ((Object)(object)val2 != (Object)null && (Object)(object)val2.parent != (Object)null) { if (val2.parent == ((Component)componentInParent).transform) { val = val2; break; } val2 = val2.parent; } } if (val == null) { val = GetRootTransform(((Component)location).transform); } if (!((Object)(object)val != (Object)null)) { return ""; } return TrimCloneSuffix(((Object)((Component)val).gameObject).name); } internal static bool TryResolveRuntimeLocationPrefabName(Location? location, out string prefabName) { if ((Object)(object)location != (Object)null) { return TryGetLocationPrefabName(location, out prefabName); } prefabName = ""; return false; } internal static bool TryResolveLocationProxyPrefabName(LocationProxy? proxy, out string prefabName) { prefabName = ""; if ((Object)(object)proxy == (Object)null) { return false; } if (TryGetRecordedLocationProxyPrefabName(proxy, out prefabName)) { return true; } if (TryGetLocationProxyHashPrefabName(proxy, out prefabName)) { return true; } Location componentInChildren = ((Component)proxy).GetComponentInChildren(true); if (componentInChildren != null) { Location location = componentInChildren; if (TryGetLocationPrefabNameWithoutProxy(location, out prefabName)) { ZNetView component = ((Component)proxy).GetComponent(); ZDO obj = ((component != null) ? component.GetZDO() : null); int num = ((obj != null) ? obj.GetInt(ZDOVars.s_location, 0) : 0); if (num != 0) { LocationPrefabNamesByHash[num] = prefabName; } return true; } } ZNetView component2 = ((Component)proxy).GetComponent(); ZDO obj2 = ((component2 != null) ? component2.GetZDO() : null); int num2 = ((obj2 != null) ? obj2.GetInt(ZDOVars.s_location, 0) : 0); if (num2 != 0) { LocationPrefabNamesByHash[num2] = ""; } lock (Sync) { QueueLocationProxyObservationInternal(proxy, Time.frameCount); } return false; } private static bool TryGetLocationProxyHashPrefabName(LocationProxy proxy, out string prefabName) { prefabName = ""; if ((Object)(object)proxy == (Object)null) { return false; } if (TryGetRecordedLocationProxyPrefabName(proxy, out prefabName)) { return true; } ZNetView component = ((Component)proxy).GetComponent(); ZDO obj = ((component != null) ? component.GetZDO() : null); int num = ((obj != null) ? obj.GetInt(ZDOVars.s_location, 0) : 0); if (num != 0 && LocationPrefabNamesByHash.TryGetValue(num, out string value)) { prefabName = value ?? ""; return prefabName.Length > 0; } if (num != 0 && (Object)(object)ZoneSystem.instance != (Object)null) { foreach (ZoneLocation location in ZoneSystem.instance.m_locations) { string zoneLocationPrefabName = GetZoneLocationPrefabName(location); if (zoneLocationPrefabName.Length != 0 && StringExtensionMethods.GetStableHashCode(zoneLocationPrefabName) == num) { prefabName = zoneLocationPrefabName; LocationPrefabNamesByHash[num] = prefabName; return true; } } } if (num != 0) { LocationPrefabNamesByHash[num] = ""; } return false; } private static bool TryGetRecordedLocationProxyPrefabName(LocationProxy? proxy, out string prefabName) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) prefabName = ""; if ((Object)(object)proxy == (Object)null) { return false; } ZNetView component = ((Component)proxy).GetComponent(); ZDO val = ((component != null) ? component.GetZDO() : null); if (val != null) { string text = (val.GetString("DropNSpawn Location Prefab", "") ?? "").Trim(); if (text.Length > 0) { CacheLocationProxyResolvedPrefabInternal(proxy, text, persistToZdo: false, queueLocationReconciles: false); prefabName = text; return true; } ZDOID uid = val.m_uid; if (uid != ZDOID.None && RuntimeLocationProxyPrefabsByZdoId.TryGetValue(uid, out string value) && !string.IsNullOrWhiteSpace(value)) { RuntimeLocationProxyPrefabsByInstance[proxy] = value; prefabName = value; return true; } } if (RuntimeLocationProxyPrefabsByInstance.TryGetValue(proxy, out string value2)) { prefabName = value2 ?? ""; return prefabName.Length > 0; } return false; } internal static bool TryResolveZoneLocationPrefabName(Vector3 position, out string prefabName) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) prefabName = ""; if ((Object)(object)ZoneSystem.instance == (Object)null) { return false; } Vector2i zone = ZoneSystem.GetZone(position); if (!ZoneSystem.instance.m_locationInstances.TryGetValue(zone, out var value)) { return false; } string zoneLocationPrefabName = GetZoneLocationPrefabName(value.m_location); if (zoneLocationPrefabName.Length == 0) { return false; } prefabName = zoneLocationPrefabName; return true; } private static string GetZoneLocationPrefabName(ZoneLocation? location) { return (location?.m_prefabName ?? location?.m_prefab.Name ?? "").Trim(); } private static bool ShouldPreferLiveLocationPrefabName(string livePrefabName, string zonePrefabName) { if (livePrefabName.Length == 0 || string.Equals(livePrefabName, zonePrefabName, StringComparison.OrdinalIgnoreCase)) { return false; } if (zonePrefabName.Length > 0 && !livePrefabName.Contains(':') && (zonePrefabName.Contains(':') || string.Equals(GetLocationPrefabBaseName(zonePrefabName), livePrefabName, StringComparison.OrdinalIgnoreCase))) { return false; } if (!livePrefabName.Contains(':') && !ActiveEntriesByPrefab.ContainsKey(livePrefabName) && !CatalogsByPrefab.ContainsKey(livePrefabName)) { return LooseItemStandEntriesByPrefab.ContainsKey(livePrefabName); } return true; } private static string GetLocationPrefabBaseName(string prefabName) { string text = (prefabName ?? "").Trim(); int num = text.IndexOf(':'); if (num < 0) { return text; } return text.Substring(0, num); } private static void RestoreOfferingBowl(OfferingBowl offeringBowl, OfferingBowlSnapshot snapshot) { offeringBowl.m_name = snapshot.Name; offeringBowl.m_useItemText = snapshot.UseItemText; offeringBowl.m_usedAltarText = snapshot.UsedAltarText; offeringBowl.m_cantOfferText = snapshot.CantOfferText; offeringBowl.m_wrongOfferText = snapshot.WrongOfferText; offeringBowl.m_incompleteOfferText = snapshot.IncompleteOfferText; offeringBowl.m_bossItem = ResolveItemDrop(snapshot.BossItem, null); offeringBowl.m_bossItems = Math.Max(1, snapshot.BossItems); offeringBowl.m_bossPrefab = ResolveSpawnPrefab(snapshot.BossPrefab, null); offeringBowl.m_itemPrefab = ResolveItemDrop(snapshot.ItemPrefab, null); offeringBowl.m_setGlobalKey = snapshot.SetGlobalKey; offeringBowl.m_renderSpawnAreaGizmos = snapshot.RenderSpawnAreaGizmos; offeringBowl.m_alertOnSpawn = snapshot.AlertOnSpawn; offeringBowl.m_spawnBossDelay = snapshot.SpawnBossDelay; offeringBowl.m_spawnBossMaxDistance = snapshot.SpawnBossMaxDistance; offeringBowl.m_spawnBossMinDistance = snapshot.SpawnBossMinDistance; offeringBowl.m_spawnBossMaxYDistance = snapshot.SpawnBossMaxYDistance; offeringBowl.m_getSolidHeightMargin = snapshot.GetSolidHeightMargin; offeringBowl.m_enableSolidHeightCheck = snapshot.EnableSolidHeightCheck; offeringBowl.m_spawnPointClearingRadius = snapshot.SpawnPointClearingRadius; offeringBowl.m_spawnYOffset = snapshot.SpawnYOffset; offeringBowl.m_useItemStands = snapshot.UseItemStands; offeringBowl.m_itemStandPrefix = snapshot.ItemStandPrefix; offeringBowl.m_itemstandMaxRange = snapshot.ItemStandMaxRange; GetOrAddOfferingBowlRuntimeState(offeringBowl).RespawnMinutes = 0f; } private static void RestoreItemStand(ItemStand itemStand, ItemStandSnapshot snapshot) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) itemStand.m_name = snapshot.Name; itemStand.m_canBeRemoved = snapshot.CanBeRemoved; itemStand.m_autoAttach = snapshot.AutoAttach; if (Enum.TryParse(snapshot.OrientationType, ignoreCase: true, out Orientation result)) { itemStand.m_orientationType = result; } itemStand.m_supportedTypes = (from type in snapshot.SupportedTypes.Select(ParseItemStandType) where type.HasValue select type.Value).ToList(); itemStand.m_supportedItems = ResolveItemDropList(snapshot.SupportedItems, null); itemStand.m_unsupportedItems = ResolveItemDropList(snapshot.UnsupportedItems, null); itemStand.m_powerActivationDelay = snapshot.PowerActivationDelay; itemStand.m_guardianPower = ResolveStatusEffect(snapshot.GuardianPower, null); } private static void ApplyOfferingBowl(OfferingBowl offeringBowl, LocationOfferingBowlDefinition entry, string prefabName) { string text = prefabName + "@offeringBowl"; if (entry.Name != null) { offeringBowl.m_name = entry.Name; } if (entry.UseItemText != null) { offeringBowl.m_useItemText = entry.UseItemText; } if (entry.UsedAltarText != null) { offeringBowl.m_usedAltarText = entry.UsedAltarText; } if (entry.CantOfferText != null) { offeringBowl.m_cantOfferText = entry.CantOfferText; } if (entry.WrongOfferText != null) { offeringBowl.m_wrongOfferText = entry.WrongOfferText; } if (entry.IncompleteOfferText != null) { offeringBowl.m_incompleteOfferText = entry.IncompleteOfferText; } if (entry.BossItem != null) { offeringBowl.m_bossItem = ResolveItemDrop(entry.BossItem, text + "/bossItem"); } if (entry.BossItems.HasValue) { offeringBowl.m_bossItems = Math.Max(1, entry.BossItems.Value); } if (entry.BossPrefab != null) { offeringBowl.m_bossPrefab = ResolveSpawnPrefab(entry.BossPrefab, text + "/bossPrefab"); } if (entry.ItemPrefab != null) { offeringBowl.m_itemPrefab = ResolveItemDrop(entry.ItemPrefab, text + "/itemPrefab"); } if (entry.SetGlobalKey != null) { offeringBowl.m_setGlobalKey = entry.SetGlobalKey; } if (entry.RenderSpawnAreaGizmos.HasValue) { offeringBowl.m_renderSpawnAreaGizmos = entry.RenderSpawnAreaGizmos.Value; } if (entry.AlertOnSpawn.HasValue) { offeringBowl.m_alertOnSpawn = entry.AlertOnSpawn.Value; } if (entry.SpawnBossDelay.HasValue) { offeringBowl.m_spawnBossDelay = Mathf.Max(0f, entry.SpawnBossDelay.Value); } if (entry.SpawnBossMaxDistance.HasValue) { offeringBowl.m_spawnBossMaxDistance = Mathf.Max(0f, entry.SpawnBossMaxDistance.Value); } if (entry.SpawnBossMinDistance.HasValue) { offeringBowl.m_spawnBossMinDistance = Mathf.Max(0f, entry.SpawnBossMinDistance.Value); } if (entry.SpawnBossMaxYDistance.HasValue) { offeringBowl.m_spawnBossMaxYDistance = Mathf.Max(0f, entry.SpawnBossMaxYDistance.Value); } if (entry.GetSolidHeightMargin.HasValue) { offeringBowl.m_getSolidHeightMargin = Math.Max(0, entry.GetSolidHeightMargin.Value); } if (entry.EnableSolidHeightCheck.HasValue) { offeringBowl.m_enableSolidHeightCheck = entry.EnableSolidHeightCheck.Value; } if (entry.SpawnPointClearingRadius.HasValue) { offeringBowl.m_spawnPointClearingRadius = Mathf.Max(0f, entry.SpawnPointClearingRadius.Value); } if (entry.SpawnYOffset.HasValue) { offeringBowl.m_spawnYOffset = entry.SpawnYOffset.Value; } if (entry.UseItemStands.HasValue) { offeringBowl.m_useItemStands = entry.UseItemStands.Value; } if (entry.ItemStandPrefix != null) { offeringBowl.m_itemStandPrefix = entry.ItemStandPrefix; } if (entry.ItemStandMaxRange.HasValue) { offeringBowl.m_itemstandMaxRange = Mathf.Max(0f, entry.ItemStandMaxRange.Value); } OfferingBowlRuntimeState orAddOfferingBowlRuntimeState = GetOrAddOfferingBowlRuntimeState(offeringBowl); orAddOfferingBowlRuntimeState.RespawnMinutes = (entry.RespawnMinutes.HasValue ? Mathf.Max(0f, entry.RespawnMinutes.Value) : 0f); if ((Object)(object)offeringBowl.m_bossPrefab != (Object)null) { orAddOfferingBowlRuntimeState.SpawnPayload = ExpandWorldSpawnDataSupport.BuildPayload(offeringBowl.m_bossPrefab, entry.Data, entry.Fields, entry.Objects, text); return; } orAddOfferingBowlRuntimeState.SpawnPayload = null; if (entry.Data != null || entry.Fields != null || entry.Objects != null) { WarnInvalidEntry("Entry '" + text + "' configured offeringBowl data/fields/objects, but no bossPrefab is available. Those fields were ignored."); } } private static void ApplyItemStand(ItemStand itemStand, LocationItemStandDefinition entry, string prefabName, Transform locationRoot) { //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) string text = (string.IsNullOrWhiteSpace(entry.Path) ? (prefabName + "@itemStands") : (prefabName + "@itemStands[" + entry.Path + "]")); List list = null; if (entry.Name != null) { itemStand.m_name = entry.Name; } if (entry.CanBeRemoved.HasValue) { itemStand.m_canBeRemoved = entry.CanBeRemoved.Value; } if (entry.AutoAttach.HasValue) { itemStand.m_autoAttach = entry.AutoAttach.Value; } if (entry.OrientationType != null) { Orientation? val = ParseItemStandOrientation(entry.OrientationType, text + "/orientationType"); if (val.HasValue) { itemStand.m_orientationType = val.Value; } } if (entry.SupportedTypes != null) { itemStand.m_supportedTypes = ResolveItemStandTypes(entry.SupportedTypes, text + "/supportedTypes"); } if (entry.SupportedItems != null) { list = (itemStand.m_supportedItems = ResolveItemDropList(entry.SupportedItems, text + "/supportedItems")); WarnAboutNonAttachableItemStandItems(list, text + "/supportedItems"); } if (entry.UnsupportedItems != null) { itemStand.m_unsupportedItems = ResolveItemDropList(entry.UnsupportedItems, text + "/unsupportedItems"); } else if (list != null) { RemoveSupportedItemsFromUnsupportedList(itemStand, list); } if (entry.PowerActivationDelay.HasValue) { itemStand.m_powerActivationDelay = Mathf.Max(0f, entry.PowerActivationDelay.Value); } if (entry.GuardianPower != null) { itemStand.m_guardianPower = ResolveStatusEffect(entry.GuardianPower, text + "/guardianPower"); } } private static void RemoveSupportedItemsFromUnsupportedList(ItemStand itemStand, List supportedItems) { if (itemStand.m_unsupportedItems == null || itemStand.m_unsupportedItems.Count == 0 || supportedItems.Count == 0) { return; } HashSet supportedNames = (from name in supportedItems.Select(GetItemSharedName) where name.Length > 0 select name).ToHashSet(StringComparer.OrdinalIgnoreCase); if (supportedNames.Count != 0) { itemStand.m_unsupportedItems = itemStand.m_unsupportedItems.Where((ItemDrop item) => !supportedNames.Contains(GetItemSharedName(item))).ToList(); } } private static void WarnAboutNonAttachableItemStandItems(List supportedItems, string warnContext) { foreach (ItemDrop supportedItem in supportedItems) { if (!((Object)(object)supportedItem == (Object)null) && !((Object)(object)ItemStand.GetAttachPrefab(((Component)supportedItem).gameObject) != (Object)null)) { string text = NormalizeReferencePrefabName(((Component)supportedItem).gameObject) ?? ((Object)((Component)supportedItem).gameObject).name ?? "(unknown item)"; WarnInvalidEntry("Entry '" + warnContext + "' references '" + text + "', but that item has no ItemStand attach prefab and cannot be placed on an ItemStand."); } } } private static string GetItemSharedName(ItemDrop? itemDrop) { return itemDrop?.m_itemData?.m_shared?.m_name ?? ""; } private static void LogLocationReconcileCandidate(Location location, string prefabName, OfferingBowl? offeringBowl, IReadOnlyList itemStands, int liveVegvisirCount, int liveRunestoneCount, LocationComponentCatalog catalog, LiveLocationSnapshot snapshot) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) if (ActiveEntriesByPrefab.ContainsKey(prefabName)) { string item = $"reconcile|{prefabName}|{((Component)location).transform.position}"; if (LocationDiagnosticLogs.Add(item)) { DropNSpawnPlugin.DropNSpawnLogger.LogDebug((object)$"Reconciling live location: prefab='{prefabName}', object='{((Object)((Component)location).gameObject).name}', itemStandCount={itemStands.Count}, catalogItemStandCount={catalog.ItemStandPaths.Count}, snapshotItemStandCount={snapshot.ItemStands.Count}, hasOfferingBowl={(Object)(object)offeringBowl != (Object)null}, catalogHasOfferingBowl={catalog.OfferingBowlPath != null}, liveVegvisirCount={liveVegvisirCount}, catalogVegvisirCount={catalog.VegvisirPaths.Count}, snapshotVegvisirCount={snapshot.Vegvisirs.Count}, liveRunestoneCount={liveRunestoneCount}, catalogRunestoneCount={catalog.RunestonePaths.Count}, snapshotRunestoneCount={snapshot.Runestones.Count}."); } } } private static string JoinDiagnosticValues(IEnumerable values) { List list = (from value in values where !string.IsNullOrWhiteSpace(value) select value.Trim()).Distinct(StringComparer.OrdinalIgnoreCase).ToList(); if (list.Count != 0) { return string.Join(", ", list); } return "(none)"; } private static Dictionary BuildOfferingBowlLookup(Transform locationRoot, IEnumerable offeringBowls) { Dictionary dictionary = new Dictionary(StringComparer.Ordinal); foreach (OfferingBowl offeringBowl in offeringBowls) { if (!((Object)(object)offeringBowl == (Object)null)) { dictionary[GetRelativePath(locationRoot, ((Component)offeringBowl).transform)] = offeringBowl; } } return dictionary; } private static Dictionary BuildItemStandLookup(Transform locationRoot, IEnumerable itemStands) { Dictionary dictionary = new Dictionary(StringComparer.Ordinal); foreach (ItemStand itemStand in itemStands) { if (!((Object)(object)itemStand == (Object)null)) { dictionary[GetRelativePath(locationRoot, ((Component)itemStand).transform)] = itemStand; } } return dictionary; } private static void ApplyConfiguredItemStands(IReadOnlyList definitions, List relevantItemStands, Dictionary liveItemStandsByPath, string prefabName, Transform locationRoot, OfferingBowl? offeringBowl) { HashSet exactMatchedItemStandIds = new HashSet(); List list = new List(); foreach (CompiledLocationItemStandPlan definition2 in definitions) { LocationItemStandDefinition definition = definition2.Definition; if (!definition2.HasPath) { foreach (ItemStand relevantItemStand in relevantItemStands) { if ((Object)(object)((Component)relevantItemStand).GetComponentInParent() == (Object)null) { CaptureLooseItemStandSnapshotIfNeeded(relevantItemStand, prefabName); } ApplyItemStand(relevantItemStand, definition, prefabName, locationRoot); } } else { string path = definition2.Path; if (!liveItemStandsByPath.TryGetValue(path, out ItemStand value)) { list.Add(definition); continue; } exactMatchedItemStandIds.Add(((Object)value).GetInstanceID()); CaptureAuthoredItemStandSlot(prefabName, path, value, offeringBowl); ApplyItemStand(value, definition, prefabName, locationRoot); } } if (list.Count == 0) { return; } if ((Object)(object)offeringBowl == (Object)null) { foreach (LocationItemStandDefinition item in list) { string path2 = (item.Path ?? "").Trim(); WarnMissingItemStandPath(prefabName, path2); } return; } List list2 = relevantItemStands.Where((ItemStand itemStand) => (Object)(object)itemStand != (Object)null && !exactMatchedItemStandIds.Contains(((Object)itemStand).GetInstanceID())).ToList(); if (list2.Count == 0) { foreach (LocationItemStandDefinition item2 in list) { string path3 = (item2.Path ?? "").Trim(); WarnMissingItemStandPath(prefabName, path3); } return; } foreach (ItemStand item3 in list2) { LooseItemStandAuthoredPathsByInstance.Remove(item3); } TryStampLooseItemStandAuthoredPaths(offeringBowl, prefabName, list2); foreach (LocationItemStandDefinition item4 in list) { string unresolvedPath = (item4.Path ?? "").Trim(); string value2; ItemStand val = ((IEnumerable)list2).FirstOrDefault((Func)((ItemStand itemStand) => LooseItemStandAuthoredPathsByInstance.TryGetValue(itemStand, out value2) && string.Equals(value2, unresolvedPath, StringComparison.Ordinal))); if ((Object)(object)val == (Object)null) { WarnMissingItemStandPath(prefabName, unresolvedPath); } else { ApplyItemStand(val, item4, prefabName, locationRoot); } } } private static void CaptureAuthoredItemStandSlot(string prefabName, string configuredPath, ItemStand itemStand, OfferingBowl? offeringBowl) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)offeringBowl == (Object)null) { return; } string trimmedPath = (configuredPath ?? "").Trim(); if (trimmedPath.Length != 0) { if (!AuthoredItemStandSlotsByPrefab.TryGetValue(prefabName, out List value)) { value = new List(); AuthoredItemStandSlotsByPrefab[prefabName] = value; } Vector3 offeringBowlLocalOffset = ((Component)offeringBowl).transform.InverseTransformPoint(((Component)itemStand).transform.position); int num = value.FindIndex((AuthoredItemStandSlotTemplate slot) => string.Equals(slot.Path, trimmedPath, StringComparison.Ordinal)); AuthoredItemStandSlotTemplate authoredItemStandSlotTemplate = new AuthoredItemStandSlotTemplate { Path = trimmedPath, OfferingBowlLocalOffset = offeringBowlLocalOffset }; if (num >= 0) { value[num] = authoredItemStandSlotTemplate; } else { value.Add(authoredItemStandSlotTemplate); } } } private static Dictionary BuildVegvisirLookup(Transform locationRoot, IEnumerable vegvisirs) { Dictionary dictionary = new Dictionary(StringComparer.Ordinal); foreach (Vegvisir vegvisir in vegvisirs) { if (!((Object)(object)vegvisir == (Object)null)) { dictionary[GetRelativePath(locationRoot, ((Component)vegvisir).transform)] = vegvisir; } } return dictionary; } private static Dictionary BuildRunestoneLookup(Transform locationRoot, IEnumerable runestones) { Dictionary dictionary = new Dictionary(StringComparer.Ordinal); foreach (RuneStone runestone in runestones) { if (!((Object)(object)runestone == (Object)null)) { dictionary[GetRelativePath(locationRoot, ((Component)runestone).transform)] = runestone; } } return dictionary; } private static bool TryResolveVegvisirTarget(string prefabName, LocationVegvisirDefinition entry, Dictionary liveVegvisirsByPath, out Vegvisir resolvedVegvisir) { LocationVegvisirDefinition entry2 = entry; resolvedVegvisir = null; string text = entry2.Path ?? ""; if (text.Length > 0) { if (!liveVegvisirsByPath.TryGetValue(text, out Vegvisir value)) { WarnMissingVegvisirPath(prefabName, text); return false; } if (!MatchesExpectedVegvisirLocations(value, entry2.ExpectedLocations)) { WarnUnexpectedVegvisirTargets(prefabName, text, value, entry2.ExpectedLocations); return false; } resolvedVegvisir = value; return true; } List> list = liveVegvisirsByPath.Where>((KeyValuePair pair) => MatchesExpectedVegvisirLocations(pair.Value, entry2.ExpectedLocations)).OrderBy, string>((KeyValuePair pair) => pair.Key, StringComparer.Ordinal).ToList(); if (list.Count == 1) { resolvedVegvisir = list[0].Value; return true; } if (list.Count == 0) { WarnUnresolvedVegvisirTarget(prefabName, entry2.ExpectedLocations, liveVegvisirsByPath.Keys); return false; } WarnAmbiguousVegvisirTarget(prefabName, entry2.ExpectedLocations, list.Select((KeyValuePair pair) => pair.Key)); return false; } private static bool TryResolveRunestoneTarget(string prefabName, LocationRunestoneDefinition entry, Dictionary liveRunestonesByPath, out RuneStone resolvedRunestone) { LocationRunestoneDefinition entry2 = entry; resolvedRunestone = null; string text = entry2.Path ?? ""; if (text.Length > 0) { if (!liveRunestonesByPath.TryGetValue(text, out RuneStone value)) { WarnMissingRunestonePath(prefabName, text); return false; } if (!MatchesExpectedRunestone(value, entry2)) { WarnUnexpectedRunestoneTarget(prefabName, text, value, entry2); return false; } resolvedRunestone = value; return true; } List> list = liveRunestonesByPath.Where>((KeyValuePair pair) => MatchesExpectedRunestone(pair.Value, entry2)).OrderBy, string>((KeyValuePair pair) => pair.Key, StringComparer.Ordinal).ToList(); if (list.Count == 1) { resolvedRunestone = list[0].Value; return true; } if (list.Count == 0) { WarnUnresolvedRunestoneTarget(prefabName, entry2, liveRunestonesByPath.Keys); return false; } WarnAmbiguousRunestoneTarget(prefabName, entry2, list.Select((KeyValuePair pair) => pair.Key)); return false; } private static bool MatchesExpectedVegvisirLocations(Vegvisir vegvisir, List? expectedLocations) { if (expectedLocations == null || expectedLocations.Count == 0) { return true; } List first = (from value in expectedLocations where !string.IsNullOrWhiteSpace(value) select value.Trim()).Distinct(StringComparer.OrdinalIgnoreCase).OrderBy((string value) => value, StringComparer.OrdinalIgnoreCase).ToList(); List second = (from location in vegvisir.m_locations select (location.m_locationName ?? "").Trim() into value where value.Length > 0 select value).Distinct(StringComparer.OrdinalIgnoreCase).OrderBy((string value) => value, StringComparer.OrdinalIgnoreCase).ToList(); return first.SequenceEqual(second, StringComparer.OrdinalIgnoreCase); } private static bool MatchesExpectedRunestone(RuneStone runestone, LocationRunestoneDefinition entry) { if (MatchesExpectedRunestoneValue(entry.ExpectedLocationName, runestone.m_locationName) && MatchesExpectedRunestoneValue(entry.ExpectedLabel, runestone.m_label)) { return MatchesExpectedRunestoneValue(entry.ExpectedTopic, runestone.m_topic); } return false; } private static bool MatchesExpectedRunestoneValue(string? expected, string? actual) { string text = (expected ?? "").Trim(); if (text.Length == 0) { return true; } return string.Equals(text, (actual ?? "").Trim(), StringComparison.OrdinalIgnoreCase); } private static string GetRelativePath(Transform root, Transform target) { if ((Object)(object)target == (Object)(object)root) { return "."; } List list = new List(); Transform val = target; while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)root) { list.Add($"{((Object)val).name}[{GetSameNameSiblingIndex(val)}]"); val = val.parent; } list.Reverse(); return string.Join("/", list); } private static Transform GetRootTransform(Transform transform) { Transform val = transform; while ((Object)(object)val.parent != (Object)null) { val = val.parent; } return val; } private static int GetSameNameSiblingIndex(Transform transform) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown if ((Object)(object)transform.parent == (Object)null) { return 0; } int num = 0; foreach (Transform item in transform.parent) { Transform val = item; if (val == transform) { return num; } if (string.Equals(((Object)val).name, ((Object)transform).name, StringComparison.Ordinal)) { num++; } } return num; } private static void RestoreVegvisir(Vegvisir vegvisir, VegvisirSnapshot snapshot) { vegvisir.m_name = snapshot.Name; vegvisir.m_useText = snapshot.UseText; vegvisir.m_hoverName = snapshot.HoverName; vegvisir.m_setsGlobalKey = snapshot.SetsGlobalKey; vegvisir.m_setsPlayerKey = snapshot.SetsPlayerKey; vegvisir.m_locations = snapshot.Locations.Select(CreateVegvisirLocation).ToList(); } private static void RestoreRunestone(RuneStone runestone, RunestoneSnapshot snapshot) { //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) ClearRunestonePinChanceRoll(runestone); runestone.m_name = snapshot.Name; runestone.m_topic = snapshot.Topic; runestone.m_label = snapshot.Label; runestone.m_text = snapshot.Text; runestone.m_randomTexts = snapshot.RandomTexts.Select(CreateRunestoneText).ToList(); runestone.m_locationName = snapshot.LocationName; runestone.m_pinName = snapshot.PinName; runestone.m_pinType = ParsePinType(snapshot.PinType, null).GetValueOrDefault((PinType)9); runestone.m_showMap = snapshot.ShowMap; } private static void ApplyVegvisir(Vegvisir vegvisir, LocationVegvisirDefinition entry, string prefabName) { string text = prefabName + "@vegvisirs[" + entry.Path + "]"; if (entry.Name != null) { vegvisir.m_name = entry.Name; } if (entry.UseText != null) { vegvisir.m_useText = entry.UseText; } if (entry.HoverName != null) { vegvisir.m_hoverName = entry.HoverName; } if (entry.SetsGlobalKey != null) { vegvisir.m_setsGlobalKey = entry.SetsGlobalKey; } if (entry.SetsPlayerKey != null) { vegvisir.m_setsPlayerKey = entry.SetsPlayerKey; } if (entry.Locations == null) { return; } if (entry.Locations.Any((LocationVegvisirTargetDefinition location) => location.Weight.HasValue)) { VegvisrLocation val = SelectWeightedVegvisirLocation(entry.Locations, text); vegvisir.m_locations = ((val != null) ? new List { val } : new List()); return; } List list = new List(); for (int i = 0; i < entry.Locations.Count; i++) { VegvisrLocation val2 = CreateVegvisirLocation(entry.Locations[i], $"{text}/locations[{i}]"); if (val2 != null) { list.Add(val2); } } vegvisir.m_locations = list; } private static void ApplyRunestone(RuneStone runestone, LocationRunestoneDefinition entry, string prefabName) { //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) string warnContext = prefabName + "@runestones[" + entry.Path + "]"; if (entry.Name != null) { runestone.m_name = entry.Name; } if (entry.Topic != null) { runestone.m_topic = entry.Topic; } if (entry.Label != null) { runestone.m_label = entry.Label; } if (entry.Text != null) { runestone.m_text = entry.Text; } if (entry.RandomTexts != null) { runestone.m_randomTexts = entry.RandomTexts.Select(CreateRunestoneText).ToList(); } if (entry.LocationName != null) { runestone.m_locationName = entry.LocationName; } if (entry.PinName != null) { runestone.m_pinName = entry.PinName; } if (entry.PinType != null) { PinType? val = ParsePinType(entry.PinType, warnContext); if (val.HasValue) { runestone.m_pinType = val.Value; } } if (entry.ShowMap.HasValue) { runestone.m_showMap = entry.ShowMap.Value; } if (entry.Chance.HasValue) { ApplyRunestonePinChanceRoll(runestone, entry, prefabName); } } internal static bool ShouldSuppressRunestonePinDiscovery(RuneStone? runestone) { if ((Object)(object)runestone != (Object)null && RunestonePinChanceRolls.TryGetValue(runestone, out RunestonePinChanceState value)) { return !value.AllowsPin; } return false; } private static void ApplyRunestonePinChanceRoll(RuneStone runestone, LocationRunestoneDefinition entry, string prefabName) { float num = Mathf.Clamp01(entry.Chance.GetValueOrDefault(1f)); if (num >= 1f) { ClearRunestonePinChanceRoll(runestone); return; } string text = CreateRunestonePinChanceRollKey(runestone, entry, prefabName, num); lock (RunestonePinChanceLock) { if (!RunestonePinChanceRolls.TryGetValue(runestone, out RunestonePinChanceState value)) { value = new RunestonePinChanceState(); RunestonePinChanceRolls.Add(runestone, value); } if (!(value.RollKey == text)) { value.RollKey = text; value.AllowsPin = num > 0f && RunestonePinChanceRandom.NextDouble() <= (double)num; } } } private static string CreateRunestonePinChanceRollKey(RuneStone runestone, LocationRunestoneDefinition entry, string prefabName, float chance) { return string.Join("\n", prefabName, entry.Path ?? "", runestone.m_locationName ?? "", runestone.m_pinName ?? "", ((object)(PinType)(ref runestone.m_pinType)).ToString(), runestone.m_showMap ? "true" : "false", chance.ToString("R", CultureInfo.InvariantCulture)); } private static void ClearRunestonePinChanceRoll(RuneStone? runestone) { if (!((Object)(object)runestone == (Object)null)) { RunestonePinChanceRolls.Remove(runestone); } } private static RandomRuneText CreateRunestoneText(LocationRunestoneTextDefinition definition) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Expected O, but got Unknown return new RandomRuneText { m_topic = (definition.Topic ?? ""), m_label = (definition.Label ?? ""), m_text = (definition.Text ?? "") }; } private static RandomRuneText CreateRunestoneText(RunestoneTextSnapshot snapshot) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown return new RandomRuneText { m_topic = snapshot.Topic, m_label = snapshot.Label, m_text = snapshot.Text }; } private static VegvisrLocation? SelectWeightedVegvisirLocation(List definitions, string context) { List<(VegvisrLocation, float)> list = new List<(VegvisrLocation, float)>(); float num = 0f; for (int i = 0; i < definitions.Count; i++) { LocationVegvisirTargetDefinition locationVegvisirTargetDefinition = definitions[i]; VegvisrLocation val = CreateVegvisirLocation(locationVegvisirTargetDefinition, $"{context}/locations[{i}]"); if (val != null) { float num2 = Mathf.Max(0f, locationVegvisirTargetDefinition.Weight.GetValueOrDefault(1f)); if (!(num2 <= 0f)) { list.Add((val, num2)); num += num2; } } } if (list.Count == 0 || num <= 0f) { return null; } float num3 = Random.Range(0f, num); float num4 = 0f; foreach (var item3 in list) { VegvisrLocation item = item3.Item1; float item2 = item3.Item2; num4 += item2; if (num3 <= num4) { return item; } } return list[list.Count - 1].Item1; } private static VegvisrLocation CreateVegvisirLocation(VegvisirTargetSnapshot snapshot) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown PinType valueOrDefault = ParsePinType(snapshot.PinType, null).GetValueOrDefault(); return new VegvisrLocation { m_locationName = snapshot.LocationName, m_pinName = snapshot.PinName, m_pinType = valueOrDefault, m_discoverAll = snapshot.DiscoverAll, m_showMap = snapshot.ShowMap }; } private static VegvisrLocation? CreateVegvisirLocation(LocationVegvisirTargetDefinition definition, string warnContext) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Expected O, but got Unknown string text = (definition.LocationName ?? "").Trim(); if (text.Length == 0) { WarnInvalidEntry("Entry '" + warnContext + "' is missing locationName."); return null; } PinType valueOrDefault = ParsePinType(definition.PinType, warnContext).GetValueOrDefault(); return new VegvisrLocation { m_locationName = text, m_pinName = (string.IsNullOrWhiteSpace(definition.PinName) ? "Pin" : definition.PinName), m_pinType = valueOrDefault, m_discoverAll = definition.DiscoverAll.GetValueOrDefault(), m_showMap = definition.ShowMap.GetValueOrDefault(true) }; } private static PinType? ParsePinType(string? pinTypeName, string? warnContext) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) string text = (pinTypeName ?? "").Trim(); if (text.Length == 0) { return null; } if (Enum.TryParse(text, ignoreCase: true, out PinType result)) { return result; } if (!string.IsNullOrWhiteSpace(warnContext)) { WarnInvalidEntry("Entry '" + warnContext + "' uses unknown Minimap.PinType '" + text + "'."); } return null; } private static Orientation? ParseItemStandOrientation(string? orientationName, string? warnContext) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) string text = (orientationName ?? "").Trim(); if (text.Length == 0) { return null; } if (Enum.TryParse(text, ignoreCase: true, out Orientation result)) { return result; } if (!string.IsNullOrWhiteSpace(warnContext)) { WarnInvalidEntry("Entry '" + warnContext + "' uses unknown ItemStand.Orientation '" + text + "'."); } return null; } private static ItemType? ParseItemStandType(string? typeName) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) string text = (typeName ?? "").Trim(); if (text.Length == 0) { return null; } if (!Enum.TryParse(text, ignoreCase: true, out ItemType result)) { return null; } return result; } private static List ResolveItemStandTypes(List typeNames, string warnContext) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) List list = new List(); foreach (string typeName in typeNames) { ItemType? val = ParseItemStandType(typeName); if (!val.HasValue) { WarnInvalidEntry("Entry '" + warnContext + "' uses unknown ItemDrop.ItemData.ItemType '" + typeName + "'."); } else { list.Add(val.Value); } } return list; } private static ItemDrop? ResolveItemDrop(string? prefabName, string? warnContext) { GameObject val = ResolveItemPrefab(prefabName, warnContext); if (!((Object)(object)val != (Object)null)) { return null; } return val.GetComponent(); } private static List ResolveItemDropList(List prefabNames, string? warnContext) { List list = new List(); for (int i = 0; i < prefabNames.Count; i++) { string warnContext2 = ((warnContext == null) ? null : $"{warnContext}[{i}]"); ItemDrop val = ResolveItemDrop(prefabNames[i], warnContext2); if ((Object)(object)val != (Object)null) { list.Add(val); } } return list; } private static GameObject? ResolveItemPrefab(string? prefabName, string? warnContext) { string text = (prefabName ?? "").Trim(); if (text.Length == 0) { return null; } ObjectDB instance = ObjectDB.instance; object obj = ((instance != null) ? instance.GetItemPrefab(text) : null); if (obj == null) { ZNetScene instance2 = ZNetScene.instance; obj = ((instance2 != null) ? instance2.GetPrefab(text) : null); } GameObject val = (GameObject)obj; if ((Object)(object)val == (Object)null) { if (!string.IsNullOrWhiteSpace(warnContext)) { WarnInvalidEntry("Entry '" + warnContext + "' references unknown item prefab '" + text + "'."); } return null; } ItemDrop val2 = default(ItemDrop); if (!val.TryGetComponent(ref val2)) { if (!string.IsNullOrWhiteSpace(warnContext)) { WarnInvalidEntry("Entry '" + warnContext + "' references '" + text + "', but it is not an item prefab."); } return null; } return val; } private static GameObject? ResolveSpawnPrefab(string? prefabName, string? warnContext) { string text = (prefabName ?? "").Trim(); if (text.Length == 0) { return null; } ZNetScene instance = ZNetScene.instance; object obj = ((instance != null) ? instance.GetPrefab(text) : null); if (obj == null) { ObjectDB instance2 = ObjectDB.instance; obj = ((instance2 != null) ? instance2.GetItemPrefab(text) : null); } GameObject val = (GameObject)obj; if ((Object)(object)val == (Object)null && !string.IsNullOrWhiteSpace(warnContext)) { WarnInvalidEntry("Entry '" + warnContext + "' references unknown spawn prefab '" + text + "'."); } return val; } private static StatusEffect? ResolveStatusEffect(string? statusEffectName, string? warnContext) { string trimmedName = (statusEffectName ?? "").Trim(); if (trimmedName.Length == 0) { return null; } ObjectDB instance = ObjectDB.instance; StatusEffect val = ((instance != null) ? instance.GetStatusEffect(StringExtensionMethods.GetStableHashCode(trimmedName)) : null); if ((Object)(object)val != (Object)null) { return val; } val = ((IEnumerable)ObjectDB.instance?.m_StatusEffects).FirstOrDefault((Func)((StatusEffect effect) => string.Equals(((Object)effect).name, trimmedName, StringComparison.OrdinalIgnoreCase) || string.Equals(effect.m_name, trimmedName, StringComparison.OrdinalIgnoreCase))); if ((Object)(object)val != (Object)null) { return val; } if (!string.IsNullOrWhiteSpace(warnContext)) { WarnInvalidEntry("Entry '" + warnContext + "' references unknown status effect '" + trimmedName + "'."); } return null; } private static int CompareLocationSnapshotsForOutput(LocationSnapshot? left, LocationSnapshot? right) { if (left == right) { return 0; } if (left == null) { return 1; } if (right == null) { return -1; } int num = GetLocationPrimaryComponentRank(left).CompareTo(GetLocationPrimaryComponentRank(right)); if (num != 0) { return num; } int num2 = GetLocationComponentSignatureMask(left).CompareTo(GetLocationComponentSignatureMask(right)); if (num2 != 0) { return num2; } return string.Compare(left.Prefab, right.Prefab, StringComparison.OrdinalIgnoreCase); } private static int GetLocationPrimaryComponentRank(LocationSnapshot snapshot) { if (snapshot.OfferingBowl != null) { return 0; } if (snapshot.ItemStands.Count > 0) { return 1; } if (snapshot.Vegvisirs.Count > 0) { return 2; } if (snapshot.Runestones.Count > 0) { return 3; } return 4; } private static int GetLocationComponentSignatureMask(LocationSnapshot snapshot) { int num = 0; if (snapshot.OfferingBowl != null) { num |= 1; } if (snapshot.ItemStands.Count > 0) { num |= 2; } if (snapshot.Vegvisirs.Count > 0) { num |= 4; } if (snapshot.Runestones.Count > 0) { num |= 8; } return num; } private static string? NormalizeReferencePrefabName(GameObject? prefab) { if (!((Object)(object)prefab == (Object)null)) { return TrimCloneSuffix(((Object)prefab).name); } return null; } private static string TrimCloneSuffix(string name) { if (string.IsNullOrWhiteSpace(name)) { return ""; } if (!name.EndsWith("(Clone)", StringComparison.Ordinal)) { return name; } int length = "(Clone)".Length; return name.Substring(0, name.Length - length).TrimEnd(); } private static bool IsReferenceDefault(float value, float defaultValue) { return Math.Abs(value - defaultValue) < 0.0001f; } private static string FormatYamlBool(bool value) { if (!value) { return "false"; } return "true"; } private static string FormatYamlFloat(float value) { return value.ToString("0.###", CultureInfo.InvariantCulture); } private static string FormatYamlString(string value) { if (value.Length == 0) { return "''"; } if (!char.IsWhiteSpace(value[0]) && !char.IsWhiteSpace(value[value.Length - 1]) && value.IndexOfAny(new char[17] { ':', '#', '{', '}', '[', ']', ',', '\'', '"', '&', '*', '!', '|', '>', '%', '@', '`' }) < 0 && value[0] != '-' && value[0] != '?' && !string.Equals(value, "null", StringComparison.OrdinalIgnoreCase) && !string.Equals(value, "true", StringComparison.OrdinalIgnoreCase) && !string.Equals(value, "false", StringComparison.OrdinalIgnoreCase)) { return value; } return "'" + value.Replace("'", "''") + "'"; } private static void ApplyCompiledLocationEntryPlans(GameObject conditionTarget, IReadOnlyList entryPlans, OfferingBowl? offeringBowl, List relevantItemStands, Dictionary liveItemStandsByPath, Dictionary liveVegvisirsByPath, Dictionary liveRunestonesByPath, string prefabName, Transform locationRoot) { foreach (CompiledLocationEntryPlan entryPlan in entryPlans) { if (entryPlan.HasConditions && !DropConditionEvaluator.AreSatisfied(conditionTarget, entryPlan.Conditions, prefabName)) { continue; } if (entryPlan.OfferingBowl != null && (Object)(object)offeringBowl != (Object)null) { ApplyOfferingBowl(offeringBowl, entryPlan.OfferingBowl.Definition, prefabName); } if (entryPlan.ItemStands.Count > 0 && relevantItemStands.Count > 0) { ApplyConfiguredItemStands(entryPlan.ItemStands, relevantItemStands, liveItemStandsByPath, prefabName, locationRoot, offeringBowl); } foreach (CompiledLocationVegvisirPlan vegvisir in entryPlan.Vegvisirs) { if (TryResolveVegvisirTarget(prefabName, vegvisir.Definition, liveVegvisirsByPath, out Vegvisir resolvedVegvisir)) { ApplyVegvisir(resolvedVegvisir, vegvisir.Definition, prefabName); } } foreach (CompiledLocationRunestonePlan runestone in entryPlan.Runestones) { if (TryResolveRunestoneTarget(prefabName, runestone.Definition, liveRunestonesByPath, out RuneStone resolvedRunestone)) { ApplyRunestone(resolvedRunestone, runestone.Definition, prefabName); } } } } private static void ApplyCompiledLooseItemStandPlansForContext(ItemStand itemStand, IReadOnlyList entryPlans, string prefabName, Transform root, OfferingBowl? offeringBowl) { CaptureLooseItemStandSnapshotIfNeeded(itemStand, prefabName); if ((Object)(object)offeringBowl != (Object)null) { TryStampLooseItemStandAuthoredPaths(offeringBowl, prefabName, (IReadOnlyList)(object)new ItemStand[1] { itemStand }); } string relativePath = GetRelativePath(root, ((Component)itemStand).transform); foreach (CompiledLocationEntryPlan entryPlan in entryPlans) { if (entryPlan.ItemStands.Count == 0 || (entryPlan.HasConditions && !DropConditionEvaluator.AreSatisfied(((Component)itemStand).gameObject, entryPlan.Conditions, prefabName))) { continue; } foreach (CompiledLocationItemStandPlan itemStand2 in entryPlan.ItemStands) { if (TryMatchLooseItemStandPlan(itemStand, itemStand2, root, relativePath)) { ApplyItemStand(itemStand, itemStand2.Definition, prefabName, root); } } } } private static bool TryMatchLooseItemStandPlan(ItemStand itemStand, CompiledLocationItemStandPlan plan, Transform root, string liveRelativePath) { return TryMatchLooseItemStandDefinition(itemStand, plan.Definition, root, liveRelativePath); } private static void RunApplyCoordinator(int gameDataSignature, bool domainEnabled, Dictionary currentEntrySignatures, bool queueLiveReconcile) { LocationDesiredState locationDesiredState = BuildLocationDesiredState(gameDataSignature, domainEnabled, currentEntrySignatures, queueLiveReconcile); _ = StandardBaselineDesiredStateCoordinator.Run(locationDesiredState.ApplyPlan, locationDesiredState, LocationApplyOperations.Instance).Success; } private static LocationDesiredState BuildLocationDesiredState(int gameDataSignature, bool domainEnabled, Dictionary currentEntrySignatures, bool queueLiveReconcile) { StandardDomainApplyPlan applyPlan = StandardDomainApplySupport.BuildPlan(_lastAppliedGameDataSignature, gameDataSignature, _lastAppliedDomainEnabled, domainEnabled, _lastAppliedEntrySignaturesByPrefab, currentEntrySignatures, EmptyEntrySignatures, _lastAppliedGameDataSignature == gameDataSignature && _lastAppliedDomainEnabled.GetValueOrDefault()); if (domainEnabled) { EnsureRuntimeConfigurationState(); } return new LocationDesiredState { GameDataSignature = gameDataSignature, ApplyPlan = applyPlan, CurrentEntrySignatures = currentEntrySignatures, DomainEnabled = domainEnabled, QueueLiveReconcile = queueLiveReconcile, ReloadPrefabs = (applyPlan.DirtyKeys ?? BuildRegisteredCatchupPrefabs(domainEnabled, currentEntrySignatures)), RuntimeConfigurationState = (domainEnabled ? _runtimeConfigurationState : LocationRuntimeConfigurationState.Empty) }; } private static void EnsureRuntimeConfigurationState() { if (IsGameDataReady()) { int num = ComputeGameDataSignature(); if (_runtimeConfigurationGameDataSignature != num || !string.Equals(_runtimeConfigurationSignature, _configurationSignature, StringComparison.Ordinal)) { _runtimeConfigurationState = BuildRuntimeConfigurationState(); _runtimeConfigurationGameDataSignature = num; _runtimeConfigurationSignature = _configurationSignature; } } } private static LocationRuntimeConfigurationState BuildRuntimeConfigurationState() { LocationRuntimeConfigurationState locationRuntimeConfigurationState = new LocationRuntimeConfigurationState(); string key; List value; foreach (KeyValuePair> item in ActiveEntriesByPrefab) { item.Deconstruct(out key, out value); string prefabName = key; List list = BuildCompiledLocationEntryPlans(value, itemStandOnly: false); if (list.Count > 0) { GetOrCreateCompiledLocationPrefabPlan(locationRuntimeConfigurationState, prefabName).ActiveEntryPlans.AddRange(list); } } foreach (KeyValuePair> item2 in LooseItemStandEntriesByPrefab) { item2.Deconstruct(out key, out value); string prefabName2 = key; List list2 = BuildCompiledLocationEntryPlans(value, itemStandOnly: true); if (list2.Count > 0) { GetOrCreateCompiledLocationPrefabPlan(locationRuntimeConfigurationState, prefabName2).LooseItemStandPlans.AddRange(list2); } } return locationRuntimeConfigurationState; } private static CompiledLocationPrefabPlan GetOrCreateCompiledLocationPrefabPlan(LocationRuntimeConfigurationState state, string prefabName) { if (!state.PlansByPrefab.TryGetValue(prefabName, out CompiledLocationPrefabPlan value)) { value = new CompiledLocationPrefabPlan(); state.PlansByPrefab[prefabName] = value; } return value; } private static List BuildCompiledLocationEntryPlans(IEnumerable entries, bool itemStandOnly) { List list = new List(); foreach (LocationConfigurationEntry entry in entries) { if (TryBuildCompiledLocationEntryPlan(entry, itemStandOnly, out CompiledLocationEntryPlan compiledPlan)) { list.Add(compiledPlan); } } return list; } private static bool TryBuildCompiledLocationEntryPlan(LocationConfigurationEntry entry, bool itemStandOnly, out CompiledLocationEntryPlan? compiledPlan) { compiledPlan = new CompiledLocationEntryPlan { Conditions = entry.Conditions, HasConditions = HasConditions(entry.Conditions) }; if (!itemStandOnly && entry.OfferingBowl != null && HasOfferingBowlOverride(entry.OfferingBowl)) { compiledPlan.OfferingBowl = new CompiledLocationOfferingBowlPlan { Definition = entry.OfferingBowl }; } if (entry.ItemStands != null) { foreach (LocationItemStandDefinition itemStand in entry.ItemStands) { if (itemStandOnly ? HasLooseItemStandOverride(itemStand) : HasItemStandOverride(itemStand)) { string text = (itemStand.Path ?? "").Trim(); compiledPlan.ItemStands.Add(new CompiledLocationItemStandPlan { Definition = itemStand, Path = text, HasPath = (text.Length > 0) }); } } } if (!itemStandOnly && entry.Vegvisirs != null) { foreach (LocationVegvisirDefinition vegvisir in entry.Vegvisirs) { if (HasVegvisirOverride(vegvisir)) { compiledPlan.Vegvisirs.Add(new CompiledLocationVegvisirPlan { Definition = vegvisir }); } } } if (!itemStandOnly && entry.Runestones != null) { foreach (LocationRunestoneDefinition runestone in entry.Runestones) { if (HasRunestoneOverride(runestone)) { compiledPlan.Runestones.Add(new CompiledLocationRunestonePlan { Definition = runestone }); } } } if (compiledPlan.OfferingBowl == null && compiledPlan.ItemStands.Count == 0 && compiledPlan.Vegvisirs.Count == 0 && compiledPlan.Runestones.Count == 0) { compiledPlan = null; return false; } return true; } private static void ResetLocationRuntimeConfigurationState() { _runtimeConfigurationState = LocationRuntimeConfigurationState.Empty; _runtimeConfigurationGameDataSignature = null; _runtimeConfigurationSignature = ""; } private static void RestoreLocationStaticBaseline(LocationDesiredState desiredState) { } private static void ValidateLocationDesiredState(LocationDesiredState desiredState) { ValidateConfiguredPrefabs(); } private static void ApplyLocationDesiredStateToStaticBaseline(LocationDesiredState desiredState) { } private static void PrepareLocationLiveBaseline(LocationDesiredState desiredState) { } private static void ApplyLocationDesiredStateToLive(LocationDesiredState desiredState) { if (desiredState.ReloadPrefabs.Count != 0) { if (desiredState.QueueLiveReconcile) { QueueRegisteredLocationReconciles(desiredState.ReloadPrefabs); } else { ReapplyActiveEntriesToRegisteredLocations(desiredState.ReloadPrefabs); } } } private static void WarnMissingVegvisirPath(string prefabName, string path) { string item = prefabName + "|missing-path|" + path; if (VegvisirWarningLogs.Add(item)) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("Location prefab '" + prefabName + "' has no Vegvisir at path '" + path + "'. Use " + PluginSettingsFacade.GetYamlDomainFilePrefix("location") + ".reference.yml to copy an exact vegvisirs.path.")); } } private static void WarnMissingRunestonePath(string prefabName, string path) { string item = prefabName + "|missing-runestone-path|" + path; if (RunestoneWarningLogs.Add(item)) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("Location prefab '" + prefabName + "' has no RuneStone at path '" + path + "'. Use " + PluginSettingsFacade.GetYamlDomainFilePrefix("location") + ".reference.yml to copy an exact runestones.path.")); } } private static void WarnMissingItemStandPath(string prefabName, string path) { string item = prefabName + "|missing-itemstand-path|" + path; if (ItemStandDiagnosticLogs.Add(item)) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("Location prefab '" + prefabName + "' has no ItemStand at path '" + path + "'. Use " + PluginSettingsFacade.GetYamlDomainFilePrefix("location") + ".reference.yml to copy an exact itemStands.path.")); } } private static void WarnUnresolvedVegvisirTarget(string prefabName, List? expectedLocations, IEnumerable availablePaths) { IEnumerable values; if (expectedLocations == null) { IEnumerable enumerable = Array.Empty(); values = enumerable; } else { IEnumerable enumerable = expectedLocations; values = enumerable; } string text = JoinDiagnosticValues(values); string text2 = JoinDiagnosticValues(availablePaths); string item = prefabName + "|unresolved-target|" + text + "|" + text2; if (VegvisirWarningLogs.Add(item)) { if (expectedLocations != null && expectedLocations.Count > 0) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("Location prefab '" + prefabName + "' has no Vegvisir matching expectedLocations [" + text + "]. Available paths: [" + text2 + "]. Add an exact path or adjust expectedLocations. The override is skipped.")); } else { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("Location prefab '" + prefabName + "' could not resolve a Vegvisir target without path. Available paths: [" + text2 + "]. Add an exact path or set expectedLocations so exactly one Vegvisir matches. The override is skipped.")); } } } private static void WarnAmbiguousVegvisirTarget(string prefabName, List? expectedLocations, IEnumerable candidatePaths) { IEnumerable values; if (expectedLocations == null) { IEnumerable enumerable = Array.Empty(); values = enumerable; } else { IEnumerable enumerable = expectedLocations; values = enumerable; } string text = JoinDiagnosticValues(values); string text2 = JoinDiagnosticValues(candidatePaths); string item = prefabName + "|ambiguous-target|" + text + "|" + text2; if (VegvisirWarningLogs.Add(item)) { if (expectedLocations != null && expectedLocations.Count > 0) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("Location prefab '" + prefabName + "' has multiple Vegvisirs matching expectedLocations [" + text + "] at paths [" + text2 + "]. Add an exact path. The override is skipped.")); } else { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("Location prefab '" + prefabName + "' has multiple Vegvisirs at paths [" + text2 + "]. Add an exact path or set expectedLocations so exactly one Vegvisir matches. The override is skipped.")); } } } private static void WarnUnexpectedVegvisirTargets(string prefabName, string path, Vegvisir vegvisir, List? expectedLocations) { string text = JoinDiagnosticValues(vegvisir.m_locations.Select((VegvisrLocation location) => location.m_locationName)); IEnumerable values; if (expectedLocations == null) { IEnumerable enumerable = Array.Empty(); values = enumerable; } else { IEnumerable enumerable = expectedLocations; values = enumerable; } string text2 = JoinDiagnosticValues(values); string item = prefabName + "|target-mismatch|" + path + "|" + text + "|" + text2; if (VegvisirWarningLogs.Add(item)) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("Location prefab '" + prefabName + "' Vegvisir '" + path + "' does not match expectedLocations. Expected [" + text2 + "] but found [" + text + "]. The override is skipped.")); } } private static void WarnUnresolvedRunestoneTarget(string prefabName, LocationRunestoneDefinition entry, IEnumerable availablePaths) { string text = DescribeExpectedRunestone(entry); string text2 = JoinDiagnosticValues(availablePaths); string item = prefabName + "|unresolved-runestone-target|" + text + "|" + text2; if (RunestoneWarningLogs.Add(item)) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("Location prefab '" + prefabName + "' could not resolve a RuneStone target without path. Expected " + text + ". Available paths: [" + text2 + "]. Add an exact path or adjust expectedLocationName/expectedLabel/expectedTopic so exactly one RuneStone matches. The override is skipped.")); } } private static void WarnAmbiguousRunestoneTarget(string prefabName, LocationRunestoneDefinition entry, IEnumerable candidatePaths) { string text = DescribeExpectedRunestone(entry); string text2 = JoinDiagnosticValues(candidatePaths); string item = prefabName + "|ambiguous-runestone-target|" + text + "|" + text2; if (RunestoneWarningLogs.Add(item)) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("Location prefab '" + prefabName + "' has multiple RuneStones matching " + text + " at paths [" + text2 + "]. Add an exact path. The override is skipped.")); } } private static void WarnUnexpectedRunestoneTarget(string prefabName, string path, RuneStone runestone, LocationRunestoneDefinition entry) { string text = DescribeExpectedRunestone(entry); string text2 = DescribeRunestone(runestone); string item = prefabName + "|runestone-target-mismatch|" + path + "|" + text + "|" + text2; if (RunestoneWarningLogs.Add(item)) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("Location prefab '" + prefabName + "' RuneStone '" + path + "' does not match expected values. Expected " + text + " but found " + text2 + ". The override is skipped.")); } } private static string DescribeExpectedRunestone(LocationRunestoneDefinition entry) { List list = new List(); if (!string.IsNullOrWhiteSpace(entry.ExpectedLocationName)) { list.Add("locationName='" + entry.ExpectedLocationName.Trim() + "'"); } if (!string.IsNullOrWhiteSpace(entry.ExpectedLabel)) { list.Add("label='" + entry.ExpectedLabel.Trim() + "'"); } if (!string.IsNullOrWhiteSpace(entry.ExpectedTopic)) { list.Add("topic='" + entry.ExpectedTopic.Trim() + "'"); } if (list.Count != 0) { return string.Join(", ", list); } return "(any RuneStone)"; } private static string DescribeRunestone(RuneStone runestone) { return "locationName='" + runestone.m_locationName + "', label='" + runestone.m_label + "', topic='" + runestone.m_topic + "'"; } private static void WarnInvalidEntry(string message) { if (DropNSpawnPlugin.IsSourceOfTruth && _invalidEntryWarningSuppressionDepth <= 0 && !ShouldSuppressServerSourcedInvalidEntryWarning(message) && InvalidEntryWarnings.Add(message)) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)message); } } private static InvalidEntryWarningSuppressionScope BeginInvalidEntryWarningSuppressionForSyncedClientBuild(string sourceName) { if (DropNSpawnPlugin.IsSourceOfTruth || !sourceName.StartsWith("ServerSync:", StringComparison.Ordinal)) { return default(InvalidEntryWarningSuppressionScope); } return new InvalidEntryWarningSuppressionScope(active: true); } private static bool ShouldSuppressServerSourcedInvalidEntryWarning(string message) { if (!DropNSpawnPlugin.IsSourceOfTruth) { return message.IndexOf("ServerSync:", StringComparison.Ordinal) >= 0; } return false; } private static string DescribeEntrySource(string? sourcePath) { if (!string.IsNullOrWhiteSpace(sourcePath)) { return sourcePath; } return "unknown source"; } internal static void LogLocationProxySpawnDiagnostics(LocationProxy? proxy, GameObject? instance, int spawnCount, bool spawnResult) { if (!PluginSettingsFacade.IsOfferingBowlDiagnosticsEnabled() || (Object)(object)proxy == (Object)null) { return; } lock (Sync) { ZNetView component = ((Component)proxy).GetComponent(); Location[] array = (((Object)(object)component != (Object)null) ? ((Component)component).GetComponentsInChildren(true) : Array.Empty()); OfferingBowl[] array2 = (((Object)(object)component != (Object)null) ? ((Component)component).GetComponentsInChildren(true) : Array.Empty()); string text = (((Object)(object)instance != (Object)null) ? BuildOfferingBowlDiagnosticPath(instance.transform) : "(none)"); DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)string.Format("LocationProxy diag stage=spawn#{0} proxyId={1} result={2} proxyPath='{3}' instanceId={4} instancePath='{5}' locationsUnderSameNView={6} bowlsUnderSameNView={7}", spawnCount.ToString(CultureInfo.InvariantCulture), ((Object)proxy).GetInstanceID().ToString(CultureInfo.InvariantCulture), spawnResult, BuildOfferingBowlDiagnosticPath(((Component)proxy).transform), ((Object)(object)instance != (Object)null) ? ((Object)instance).GetInstanceID().ToString(CultureInfo.InvariantCulture) : "(none)", text, array.Length.ToString(CultureInfo.InvariantCulture), array2.Length.ToString(CultureInfo.InvariantCulture))); } } internal static void LogOfferingBowlDiagnostics(OfferingBowl? offeringBowl, string stage) { if (!PluginSettingsFacade.IsOfferingBowlDiagnosticsEnabled() || (Object)(object)offeringBowl == (Object)null) { return; } lock (Sync) { Transform transform = ((Component)offeringBowl).transform; Location componentInParent = ((Component)offeringBowl).GetComponentInParent(true); LocationProxy componentInParent2 = ((Component)offeringBowl).GetComponentInParent(true); ZNetView componentInParent3 = ((Component)offeringBowl).GetComponentInParent(true); int num = ((Component)offeringBowl).GetComponents().Length; int num2 = (((Object)(object)componentInParent3 != (Object)null) ? ((Component)componentInParent3).GetComponentsInChildren(true).Length : 0); string text = ""; string text2 = "(unknown)"; if (AltarItemStandHoverInfoFormatter.TryResolveOfferingBowlContext(offeringBowl, out string locationPrefab, out Transform root)) { text = locationPrefab; text2 = BuildOfferingBowlDiagnosticPath(root); } string text3 = BuildOfferingBowlDiagnosticPath(transform); string text4 = (((Object)(object)componentInParent3 != (Object)null) ? BuildOfferingBowlDiagnosticPath(((Component)componentInParent3).transform) : "(none)"); DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)string.Format("OfferingBowl diag stage={0} bowlId={1} object='{2}' path='{3}' sameGameObjectBowls={4} parentNViewId={5} parentNViewPath='{6}' bowlsUnderSameNView={7} locationId={8} proxyId={9} resolvedPrefab='{10}' resolvedRoot='{11}' useItemStands={12} itemStandPrefix='{13}' itemStandMaxRange={14}", stage, ((Object)offeringBowl).GetInstanceID().ToString(CultureInfo.InvariantCulture), ((Object)((Component)offeringBowl).gameObject).name, text3, num.ToString(CultureInfo.InvariantCulture), ((Object)(object)componentInParent3 != (Object)null) ? ((Object)componentInParent3).GetInstanceID().ToString(CultureInfo.InvariantCulture) : "(none)", text4, num2.ToString(CultureInfo.InvariantCulture), ((Object)(object)componentInParent != (Object)null) ? ((Object)componentInParent).GetInstanceID().ToString(CultureInfo.InvariantCulture) : "(none)", ((Object)(object)componentInParent2 != (Object)null) ? ((Object)componentInParent2).GetInstanceID().ToString(CultureInfo.InvariantCulture) : "(none)", text, text2, offeringBowl.m_useItemStands, offeringBowl.m_itemStandPrefix, offeringBowl.m_itemstandMaxRange.ToString(CultureInfo.InvariantCulture))); LogOfferingBowlStructureDiagnostics(stage, componentInParent3, componentInParent2); } } internal static void LogOfferingBowlItemFlowDiagnostics(OfferingBowl? offeringBowl, Humanoid? user, ItemData? item, string stage, int countBefore, int countAfter, bool? result = null) { if (!PluginSettingsFacade.IsOfferingBowlDiagnosticsEnabled() || (Object)(object)offeringBowl == (Object)null) { return; } lock (Sync) { ZNetView componentInParent = ((Component)offeringBowl).GetComponentInParent(true); int num = ((Component)offeringBowl).GetComponents().Length; int num2 = (((Object)(object)componentInParent != (Object)null) ? ((Component)componentInParent).GetComponentsInChildren(true).Length : 0); string text = item?.m_shared?.m_name ?? "(none)"; string text2 = ((user != null) ? ((Character)user).GetHoverName() : null) ?? ((user != null) ? ((Object)user).name : null) ?? "(none)"; string text3 = BuildOfferingBowlDiagnosticPath(((Component)offeringBowl).transform); string text4 = (((Object)(object)componentInParent != (Object)null) ? BuildOfferingBowlDiagnosticPath(((Component)componentInParent).transform) : "(none)"); string text5 = (result.HasValue ? result.Value.ToString() : "(n/a)"); DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)string.Format("OfferingBowl diag itemflow stage={0} bowlId={1} object='{2}' path='{3}' parentNViewId={4} parentNViewPath='{5}' sameGameObjectBowls={6} bowlsUnderSameNView={7} item='{8}' bossItems={9} countBefore={10} countAfter={11} result={12} user='{13}' useItemStands={14}", stage, ((Object)offeringBowl).GetInstanceID().ToString(CultureInfo.InvariantCulture), ((Object)((Component)offeringBowl).gameObject).name, text3, ((Object)(object)componentInParent != (Object)null) ? ((Object)componentInParent).GetInstanceID().ToString(CultureInfo.InvariantCulture) : "(none)", text4, num.ToString(CultureInfo.InvariantCulture), num2.ToString(CultureInfo.InvariantCulture), text, offeringBowl.m_bossItems.ToString(CultureInfo.InvariantCulture), countBefore.ToString(CultureInfo.InvariantCulture), countAfter.ToString(CultureInfo.InvariantCulture), text5, text2, offeringBowl.m_useItemStands)); } } private static void LogOfferingBowlStructureDiagnostics(string stage, ZNetView? nview, LocationProxy? proxy) { if ((Object)(object)nview == (Object)null) { return; } OfferingBowl[] componentsInChildren = ((Component)nview).GetComponentsInChildren(true); Location[] componentsInChildren2 = ((Component)nview).GetComponentsInChildren(true); if (componentsInChildren.Length <= 1 && componentsInChildren2.Length <= 1) { return; } string item = string.Join("|", "structure", ((Object)nview).GetInstanceID().ToString(CultureInfo.InvariantCulture), componentsInChildren.Length.ToString(CultureInfo.InvariantCulture), componentsInChildren2.Length.ToString(CultureInfo.InvariantCulture)); if (OfferingBowlDiagnosticLogs.Add(item)) { Transform root = ((Component)nview).transform; string text = FormatDiagnosticEntries(from bowl in componentsInChildren where (Object)(object)bowl != (Object)null select DescribeOfferingBowlStructureEntry(root, bowl)); string text2 = FormatDiagnosticEntries(from location in componentsInChildren2 where (Object)(object)location != (Object)null select DescribeLocationStructureEntry(root, location)); string text3 = FormatDiagnosticEntries(from @group in (from bowl in componentsInChildren where (Object)(object)bowl != (Object)null select GetRelativePath(root, ((Component)bowl).transform)).GroupBy((string path) => path, StringComparer.Ordinal) where @group.Count() > 1 select @group.Key + " x" + @group.Count().ToString(CultureInfo.InvariantCulture)); string text4 = FormatDiagnosticEntries(from @group in (from location in componentsInChildren2 where (Object)(object)location != (Object)null select GetRelativePath(root, ((Component)location).transform)).GroupBy((string path) => path, StringComparer.Ordinal) where @group.Count() > 1 select @group.Key + " x" + @group.Count().ToString(CultureInfo.InvariantCulture)); DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)("OfferingBowl diag structure stage=" + stage + " parentNViewId=" + ((Object)nview).GetInstanceID().ToString(CultureInfo.InvariantCulture) + " parentNViewPath='" + BuildOfferingBowlDiagnosticPath(root) + "' proxyId=" + (((Object)(object)proxy != (Object)null) ? ((Object)proxy).GetInstanceID().ToString(CultureInfo.InvariantCulture) : "(none)") + " offeringBowls=" + componentsInChildren.Length.ToString(CultureInfo.InvariantCulture) + " locations=" + componentsInChildren2.Length.ToString(CultureInfo.InvariantCulture) + " duplicateBowlPaths='" + text3 + "' duplicateLocationPaths='" + text4 + "' bowlEntries='" + text + "' locationEntries='" + text2 + "'")); } } private static string DescribeOfferingBowlStructureEntry(Transform root, OfferingBowl offeringBowl) { string relativePath = GetRelativePath(root, ((Component)offeringBowl).transform); string locationPrefab = ""; if (!AltarItemStandHoverInfoFormatter.TryResolveOfferingBowlContext(offeringBowl, out locationPrefab, out Transform _)) { locationPrefab = ""; } Location componentInParent = ((Component)offeringBowl).GetComponentInParent(true); return relativePath + "#bowl=" + ((Object)offeringBowl).GetInstanceID().ToString(CultureInfo.InvariantCulture) + "#loc=" + (((Object)(object)componentInParent != (Object)null) ? ((Object)componentInParent).GetInstanceID().ToString(CultureInfo.InvariantCulture) : "(none)") + "#prefab=" + locationPrefab; } private static string DescribeLocationStructureEntry(Transform root, Location location) { string relativePath = GetRelativePath(root, ((Component)location).transform); string prefabName = ""; if (!TryResolveRuntimeLocationPrefabName(location, out prefabName)) { prefabName = ""; } return relativePath + "#loc=" + ((Object)location).GetInstanceID().ToString(CultureInfo.InvariantCulture) + "#prefab=" + prefabName; } private static string FormatDiagnosticEntries(IEnumerable entries, int maxEntries = 12) { List list = entries.Where((string entry) => !string.IsNullOrWhiteSpace(entry)).Take(maxEntries + 1).ToList(); if (list.Count == 0) { return "(none)"; } bool num = list.Count > maxEntries; if (num) { list.RemoveAt(list.Count - 1); } string text = string.Join(" || ", list); if (!num) { return text; } return text + " || ...(truncated)"; } internal static void QueueLooseItemStandOverride(ItemStand? itemStand) { lock (Sync) { QueueOrRestoreLooseItemStandOverrideInternal(itemStand); } } internal static void EnsureLooseItemStandOverride(ItemStand? itemStand) { lock (Sync) { if (!_initialized) { Initialize(); } if (IsGameDataReady() && !DropNSpawnPlugin.IsGameDataRefreshDeferred(DropNSpawnPlugin.ReloadDomain.Location) && !((Object)(object)itemStand == (Object)null) && !((Object)(object)((Component)itemStand).gameObject == (Object)null) && !((Object)(object)((Component)itemStand).GetComponentInParent() != (Object)null)) { if (AltarItemStandHoverInfoFormatter.TryGetRelevantOfferingBowl(itemStand, out OfferingBowl offeringBowl) && (Object)(object)offeringBowl != (Object)null) { TryApplyLooseOfferingBowlOverrideInternal(offeringBowl); } else { RestoreTrackedLooseItemStand(itemStand); } } } } internal static void QueueLooseOfferingBowlOverride(OfferingBowl? offeringBowl) { lock (Sync) { QueueLooseOfferingBowlOverrideInternal(offeringBowl); } } internal static void EnsureLooseOfferingBowlOverride(OfferingBowl? offeringBowl) { lock (Sync) { if (!_initialized) { Initialize(); } if (IsGameDataReady() && !DropNSpawnPlugin.IsGameDataRefreshDeferred(DropNSpawnPlugin.ReloadDomain.Location)) { TryApplyLooseOfferingBowlOverrideInternal(offeringBowl); } } } internal static void QueueLooseOfferingBowlOverridesUnderRoot(GameObject? rootObject) { lock (Sync) { QueueLooseOfferingBowlOverridesUnderRootInternal(rootObject); } } internal static void TryApplyLooseItemStandOverride(ItemStand? itemStand) { QueueLooseItemStandOverride(itemStand); } internal static OfferingBowlBlockResult EvaluateOfferingBowlBlock(OfferingBowl offeringBowl) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) lock (Sync) { if ((Object)(object)offeringBowl == (Object)null || (Object)(object)ZNet.instance == (Object)null) { return OfferingBowlBlockResult.None; } if (BossRulesManager.ShouldBlockConfiguredSameBossSpawn(offeringBowl.m_bossPrefab, ((Component)offeringBowl).transform.position)) { return new OfferingBowlBlockResult(blocked: true, OfferingBowlBlockReason.SameBossNearby); } OfferingBowlRuntimeState component = ((Component)offeringBowl).GetComponent(); if ((Object)(object)component == (Object)null) { return OfferingBowlBlockResult.None; } if (component.RespawnMinutes <= 0f) { return OfferingBowlBlockResult.None; } long offeringBowlLastUseTicks = GetOfferingBowlLastUseTicks(offeringBowl, component); if (offeringBowlLastUseTicks <= 0) { return OfferingBowlBlockResult.None; } if ((ZNet.instance.GetTime() - new DateTime(offeringBowlLastUseTicks)).TotalMinutes >= (double)component.RespawnMinutes) { return OfferingBowlBlockResult.None; } return new OfferingBowlBlockResult(blocked: true, OfferingBowlBlockReason.RespawnCooldownActive); } } internal static void NotifyOfferingBowlBlocked(OfferingBowl offeringBowl, Humanoid? user, OfferingBowlBlockResult result) { if (!((Object)(object)offeringBowl == (Object)null) && !((Object)(object)user == (Object)null) && result.Blocked) { OfferingBowlBlockReason reason = result.Reason; if (reason != 0 && (uint)(reason - 1) <= 1u) { ((Character)user).Message((MessageType)2, Localization.instance.Localize(offeringBowl.m_cantOfferText), 0, (Sprite)null); } } } 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(); if ((Object)(object)component == (Object)null || component.RespawnMinutes <= 0f) { return; } long num = (component.LocalLastUseTicks = ZNet.instance.GetTime().Ticks); ZNetView componentInParent = ((Component)offeringBowl).GetComponentInParent(); if (!((Object)(object)componentInParent == (Object)null) && componentInParent.IsValid()) { if (!componentInParent.IsOwner()) { componentInParent.ClaimOwnership(); } if (componentInParent.IsOwner()) { componentInParent.GetZDO().Set(OfferingBowlLastUseTicksKey, num); } } } } internal static void BeginOfferingBowlBossSpawnAttempt(OfferingBowl offeringBowl, Vector3 spawnPoint) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) lock (Sync) { if (!((Object)(object)offeringBowl == (Object)null)) { OfferingBowlRuntimeState component = ((Component)offeringBowl).GetComponent(); if (PluginSettingsFacade.IsLocationDomainEnabled() && component?.SpawnPayload != null) { ExpandWorldSpawnDataSupport.InitializeSpawn(offeringBowl.m_bossPrefab, spawnPoint, component.SpawnPayload); } } } } internal static void FinalizeOfferingBowlBossSpawnAttempt(OfferingBowl offeringBowl, Vector3 spawnPoint) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) lock (Sync) { if (!((Object)(object)offeringBowl == (Object)null)) { OfferingBowlRuntimeState component = ((Component)offeringBowl).GetComponent(); if (PluginSettingsFacade.IsLocationDomainEnabled() && component != null && (component.SpawnPayload?.HasObjects).GetValueOrDefault()) { ExpandWorldSpawnDataSupport.SpawnObjects(spawnPoint, component.SpawnPayload); } } } } private static void QueueLooseOfferingBowlOverridesUnderRootInternal(GameObject? rootObject) { if (!((Object)(object)rootObject == (Object)null)) { OfferingBowl[] componentsInChildren = rootObject.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { QueueLooseOfferingBowlOverrideInternal(componentsInChildren[i]); } } } private static void QueueLooseOfferingBowlOverrideInternal(OfferingBowl? offeringBowl) { if (!((Object)(object)offeringBowl == (Object)null) && !((Object)(object)((Component)offeringBowl).gameObject == (Object)null)) { int instanceID = ((Object)offeringBowl).GetInstanceID(); if (PendingLooseOfferingBowlOverrideIds.Add(instanceID)) { PendingLooseOfferingBowlOverrides.Enqueue(new PendingLooseOfferingBowlOverride(offeringBowl, instanceID, _reconcileQueueEpoch)); } } } private static bool HasPendingLooseLocationOverrideWorkLocked() { return PendingLooseOfferingBowlOverrides.Count > 0; } private static bool TryProcessPendingLooseLocationOverrideLocked() { while (PendingLooseOfferingBowlOverrides.Count > 0) { if (!PendingLooseOfferingBowlOverrides.TryDequeue(out var item)) { continue; } PendingLooseOfferingBowlOverrideIds.Remove(item.OfferingBowlInstanceId); if (item.Epoch == _reconcileQueueEpoch && !((Object)(object)item.OfferingBowl == (Object)null)) { if (!_initialized) { Initialize(); } TryApplyLooseOfferingBowlOverrideInternal(item.OfferingBowl); return true; } } return false; } private static void RefreshTrackedLooseItemStands(HashSet prefabs) { CleanupLooseItemStandSnapshots(); foreach (ItemStand trackedLooseItemStand in GetTrackedLooseItemStands(prefabs)) { QueueOrRestoreLooseItemStandOverrideInternal(trackedLooseItemStand); } } [IteratorStateMachine(typeof(d__405))] private static IEnumerable GetTrackedLooseItemStands(HashSet dirtyPrefabs) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__405(-2) { <>3__dirtyPrefabs = dirtyPrefabs }; } private static void CleanupTrackedLooseItemStandPrefabs() { List list = null; foreach (ItemStand key in TrackedLooseItemStandPrefabs.Keys) { if ((Object)(object)key == (Object)null || (Object)(object)((Component)key).gameObject == (Object)null) { if (list == null) { list = new List(); } list.Add(key); } } if (list == null) { return; } foreach (ItemStand item in list) { TrackedLooseItemStandPrefabs.Remove(item); LooseItemStandAuthoredPathsByInstance.Remove(item); } } private static void QueueOrRestoreLooseItemStandOverrideInternal(ItemStand? itemStand) { if (!((Object)(object)itemStand == (Object)null) && !((Object)(object)((Component)itemStand).gameObject == (Object)null) && IsGameDataReady() && !((Object)(object)((Component)itemStand).GetComponentInParent() != (Object)null)) { if (!AltarItemStandHoverInfoFormatter.TryGetRelevantOfferingBowl(itemStand, out OfferingBowl offeringBowl) || (Object)(object)offeringBowl == (Object)null) { RestoreTrackedLooseItemStand(itemStand); } else { QueueLooseOfferingBowlOverrideInternal(offeringBowl); } } } private static void TryApplyLooseOfferingBowlOverrideInternal(OfferingBowl? offeringBowl) { if ((Object)(object)offeringBowl == (Object)null || !IsGameDataReady()) { return; } CleanupLooseItemStandSnapshots(); List list = (from itemStand in AltarItemStandHoverInfoFormatter.FindRelevantItemStands(offeringBowl) where (Object)(object)itemStand != (Object)null && (Object)(object)((Component)itemStand).GetComponentInParent() == (Object)null select itemStand).ToList(); LooseOfferingBowlOverrideMode looseOfferingBowlOverrideMode = LooseOfferingBowlOverrideMode.RestoreOnly; string locationPrefab = ""; Transform val = null; List list2 = null; if (CanUseCurrentRuntimeState() && offeringBowl.m_useItemStands && PluginSettingsFacade.IsLocationDomainEnabled() && AltarItemStandHoverInfoFormatter.TryResolveOfferingBowlContext(offeringBowl, out locationPrefab, out Transform root)) { val = root; EnsureRuntimeConfigurationState(); if (_runtimeConfigurationState.PlansByPrefab.TryGetValue(locationPrefab, out CompiledLocationPrefabPlan value) && value.LooseItemStandPlans.Count > 0 && list.Count > 0) { list2 = value.LooseItemStandPlans; looseOfferingBowlOverrideMode = LooseOfferingBowlOverrideMode.Apply; } } LooseOfferingBowlOverrideStamp overrideStamp = BuildLooseOfferingBowlOverrideStamp(looseOfferingBowlOverrideMode, val, locationPrefab, list2?.Count ?? 0, list); if (HasCurrentLooseOfferingBowlOverrideStamp(offeringBowl, overrideStamp)) { return; } foreach (ItemStand item2 in list) { RestoreTrackedLooseItemStand(item2); } if (looseOfferingBowlOverrideMode != LooseOfferingBowlOverrideMode.Apply || (Object)(object)val == (Object)null || list2 == null) { RecordLooseOfferingBowlOverrideStamp(offeringBowl, overrideStamp); return; } if (PluginSettingsFacade.IsOfferingBowlDiagnosticsEnabled()) { string item = "looseApply|" + ((Object)offeringBowl).GetInstanceID().ToString(CultureInfo.InvariantCulture) + "|" + locationPrefab + "|" + list2.Count.ToString(CultureInfo.InvariantCulture); if (OfferingBowlDiagnosticLogs.Add(item)) { DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)$"OfferingBowl diag stage=loose_apply bowlId={((Object)offeringBowl).GetInstanceID().ToString(CultureInfo.InvariantCulture)} object='{((Object)((Component)offeringBowl).gameObject).name}' resolvedPrefab='{locationPrefab}' root='{BuildOfferingBowlDiagnosticPath(val)}' matchingEntries={list2.Count.ToString(CultureInfo.InvariantCulture)} useItemStands={offeringBowl.m_useItemStands}"); } } TryStampLooseItemStandAuthoredPaths(offeringBowl, locationPrefab, list); overrideStamp = BuildLooseOfferingBowlOverrideStamp(looseOfferingBowlOverrideMode, val, locationPrefab, list2.Count, list); foreach (ItemStand item3 in list) { ApplyCompiledLooseItemStandPlansForContext(item3, list2, locationPrefab, val, offeringBowl); } RecordLooseOfferingBowlOverrideStamp(offeringBowl, overrideStamp); } private static LooseOfferingBowlOverrideStamp BuildLooseOfferingBowlOverrideStamp(LooseOfferingBowlOverrideMode overrideMode, Transform? root, string prefabName, int entryPlanCount, IReadOnlyList detachedRelevantItemStands) { return new LooseOfferingBowlOverrideStamp(_reconcileQueueEpoch, AltarItemStandHoverInfoFormatter.GetRegistryVersion(), overrideMode, ((Object)(object)root != (Object)null) ? ((Object)root).GetInstanceID() : 0, prefabName, _configurationSignature, entryPlanCount, detachedRelevantItemStands.Count, ComputeLooseRelevantItemStandSignature(detachedRelevantItemStands)); } private static int ComputeLooseRelevantItemStandSignature(IReadOnlyList detachedRelevantItemStands) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) HashCode val = default(HashCode); ((HashCode)(ref val)).Add(detachedRelevantItemStands.Count); foreach (ItemStand detachedRelevantItemStand in detachedRelevantItemStands) { ((HashCode)(ref val)).Add(((Object)(object)detachedRelevantItemStand != (Object)null) ? ((Object)detachedRelevantItemStand).GetInstanceID() : 0); if ((Object)(object)detachedRelevantItemStand != (Object)null && LooseItemStandAuthoredPathsByInstance.TryGetValue(detachedRelevantItemStand, out string value)) { ((HashCode)(ref val)).Add(value, (IEqualityComparer)StringComparer.Ordinal); } else { ((HashCode)(ref val)).Add("", (IEqualityComparer)StringComparer.Ordinal); } } return ((HashCode)(ref val)).ToHashCode(); } private static bool HasCurrentLooseOfferingBowlOverrideStamp(OfferingBowl offeringBowl, LooseOfferingBowlOverrideStamp overrideStamp) { if (LooseOfferingBowlOverrideStates.TryGetValue(offeringBowl, out LooseOfferingBowlOverrideState value) && value.HasLastAppliedStamp) { return value.LastAppliedStamp.Equals(overrideStamp); } return false; } private static void RecordLooseOfferingBowlOverrideStamp(OfferingBowl offeringBowl, LooseOfferingBowlOverrideStamp overrideStamp) { LooseOfferingBowlOverrideState orCreateValue = LooseOfferingBowlOverrideStates.GetOrCreateValue(offeringBowl); orCreateValue.LastAppliedStamp = overrideStamp; orCreateValue.HasLastAppliedStamp = true; } private static bool TryMatchLooseItemStandDefinition(ItemStand itemStand, LocationItemStandDefinition definition, Transform root, string liveRelativePath) { if (!HasItemStandOverride(definition)) { return false; } string text = (definition.Path ?? "").Trim(); if (text.Length == 0) { return true; } if (liveRelativePath.Length == 0) { if (LooseItemStandAuthoredPathsByInstance.TryGetValue(itemStand, out string value)) { return string.Equals(text, value, StringComparison.Ordinal); } return false; } if (string.Equals(text, liveRelativePath, StringComparison.Ordinal)) { return true; } if (text.EndsWith("/" + liveRelativePath, StringComparison.Ordinal) || liveRelativePath.EndsWith("/" + text, StringComparison.Ordinal)) { return true; } string text2 = TrimCloneSuffix(((Object)root).name) + "[0]/" + liveRelativePath; if (string.Equals(text, text2, StringComparison.Ordinal) || text.EndsWith("/" + text2, StringComparison.Ordinal)) { return true; } if (LooseItemStandAuthoredPathsByInstance.TryGetValue(itemStand, out string value2)) { return string.Equals(text, value2, StringComparison.Ordinal); } return false; } private static string BuildOfferingBowlDiagnosticPath(Transform? transform) { if ((Object)(object)transform == (Object)null) { return "(none)"; } List list = new List(); Transform val = transform; while ((Object)(object)val != (Object)null) { list.Add(((Object)val).name ?? "(null)"); val = val.parent; } list.Reverse(); return string.Join("/", list); } private static void CaptureLooseItemStandSnapshotIfNeeded(ItemStand itemStand, string prefabName) { if (!LooseItemStandSnapshots.ContainsKey(itemStand)) { LooseItemStandSnapshots[itemStand] = CaptureItemStandSnapshot(itemStand); } TrackedLooseItemStandPrefabs[itemStand] = prefabName; } private static void RestoreTrackedLooseItemStand(ItemStand itemStand) { if (LooseItemStandSnapshots.TryGetValue(itemStand, out ItemStandSnapshot value)) { RestoreItemStand(itemStand, value); } } private static void CleanupLooseItemStandSnapshots() { List list = null; foreach (ItemStand key in LooseItemStandSnapshots.Keys) { if (!((Object)(object)key != (Object)null)) { if (list == null) { list = new List(); } list.Add(key); } } if (list == null) { return; } foreach (ItemStand item in list) { LooseItemStandSnapshots.Remove(item); TrackedLooseItemStandPrefabs.Remove(item); LooseItemStandAuthoredPathsByInstance.Remove(item); } } private static void TryStampLooseItemStandAuthoredPaths(OfferingBowl offeringBowl, string prefabName, IReadOnlyList detachedRelevantItemStands) { //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)offeringBowl == (Object)null || !AuthoredItemStandSlotsByPrefab.TryGetValue(prefabName, out List value) || value.Count == 0 || detachedRelevantItemStands == null || detachedRelevantItemStands.Count == 0) { return; } HashSet hashSet = new HashSet(); HashSet hashSet2 = new HashSet(StringComparer.Ordinal); foreach (ItemStand detachedRelevantItemStand in detachedRelevantItemStands) { if (!((Object)(object)detachedRelevantItemStand == (Object)null) && LooseItemStandAuthoredPathsByInstance.TryGetValue(detachedRelevantItemStand, out string assignedPath) && !string.IsNullOrWhiteSpace(assignedPath) && value.Any((AuthoredItemStandSlotTemplate template) => string.Equals(template.Path, assignedPath, StringComparison.Ordinal))) { hashSet.Add(((Object)detachedRelevantItemStand).GetInstanceID()); hashSet2.Add(assignedPath); } } List<(float, ItemStand, AuthoredItemStandSlotTemplate)> list = new List<(float, ItemStand, AuthoredItemStandSlotTemplate)>(); foreach (ItemStand detachedRelevantItemStand2 in detachedRelevantItemStands) { if (hashSet.Contains(((Object)detachedRelevantItemStand2).GetInstanceID())) { continue; } Vector3 val = ((Component)offeringBowl).transform.InverseTransformPoint(((Component)detachedRelevantItemStand2).transform.position); foreach (AuthoredItemStandSlotTemplate item4 in value) { if (!hashSet2.Contains(item4.Path)) { float item = Vector3.SqrMagnitude(val - item4.OfferingBowlLocalOffset); list.Add((item, detachedRelevantItemStand2, item4)); } } } list.Sort(((float Distance, ItemStand ItemStand, AuthoredItemStandSlotTemplate Template) left, (float Distance, ItemStand ItemStand, AuthoredItemStandSlotTemplate Template) right) => left.Distance.CompareTo(right.Distance)); foreach (var item5 in list) { ItemStand item2 = item5.Item2; AuthoredItemStandSlotTemplate item3 = item5.Item3; int instanceID = ((Object)item2).GetInstanceID(); if (!hashSet.Contains(instanceID) && !hashSet2.Contains(item3.Path)) { LooseItemStandAuthoredPathsByInstance[item2] = item3.Path; hashSet.Add(instanceID); hashSet2.Add(item3.Path); } } } private static OfferingBowlRuntimeState GetOrAddOfferingBowlRuntimeState(OfferingBowl offeringBowl) { OfferingBowlRuntimeState component = ((Component)offeringBowl).GetComponent(); if ((Object)(object)component != (Object)null) { return component; } return ((Component)offeringBowl).gameObject.AddComponent(); } private static long GetOfferingBowlLastUseTicks(OfferingBowl offeringBowl, OfferingBowlRuntimeState state) { ZNetView componentInParent = ((Component)offeringBowl).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null && componentInParent.IsValid()) { long @long = componentInParent.GetZDO().GetLong(OfferingBowlLastUseTicksKey, 0L); if (@long > 0) { state.LocalLastUseTicks = @long; return @long; } } return state.LocalLastUseTicks; } private static List> BuildOrderedSnapshots() { List> list = PrefabOutputSections.BuildSections(Snapshots, (LocationSnapshot snapshot) => snapshot.Prefab); foreach (PrefabOwnerSection item in list) { item.Entries.Sort(CompareLocationSnapshotsForOutput); } return list; } private static string BuildReferenceConfigurationTemplate() { return PrefabOutputSections.SerializeReferenceSections((from section in BuildOrderedSnapshots() select new PrefabOwnerSection(section.OwnerName, section.Entries.Select((LocationSnapshot snapshot) => new LocationReferenceEntry { Prefab = snapshot.Prefab, OfferingBowl = ((snapshot.OfferingBowl != null) ? ConvertReferenceOfferingBowl(snapshot.OfferingBowl) : null), ItemStands = ((snapshot.ItemStands.Count > 0) ? snapshot.ItemStands.Select(ConvertReferenceItemStand).ToList() : null), Vegvisirs = ((snapshot.Vegvisirs.Count == 0) ? null : snapshot.Vegvisirs.Select(ConvertReferenceVegvisir).ToList()), Runestones = ((snapshot.Runestones.Count == 0) ? null : snapshot.Runestones.Select(ConvertReferenceRunestone).ToList()) }).ToList())).ToList(), Serializer); } private static string SerializeReferenceEntries(IEnumerable entries) { return ReferenceRefreshSupport.SerializeReferenceSections(entries, (LocationReferenceEntry entry) => entry.Prefab, Serializer); } private static void WriteReferenceConfigurationFile(string content, string logMessage) { Directory.CreateDirectory(DropNSpawnPlugin.YamlConfigDirectoryPath); GeneratedFileWriter.WriteAllTextIfChanged(ReferenceConfigurationPath, content); DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)logMessage); } private static LocationOfferingBowlDefinition ConvertReferenceOfferingBowl(OfferingBowlSnapshot snapshot) { return new LocationOfferingBowlDefinition { Name = (string.IsNullOrWhiteSpace(snapshot.Name) ? null : snapshot.Name), UseItemText = (string.IsNullOrWhiteSpace(snapshot.UseItemText) ? null : snapshot.UseItemText), UsedAltarText = (string.IsNullOrWhiteSpace(snapshot.UsedAltarText) ? null : snapshot.UsedAltarText), CantOfferText = (string.IsNullOrWhiteSpace(snapshot.CantOfferText) ? null : snapshot.CantOfferText), WrongOfferText = (string.IsNullOrWhiteSpace(snapshot.WrongOfferText) ? null : snapshot.WrongOfferText), IncompleteOfferText = (string.IsNullOrWhiteSpace(snapshot.IncompleteOfferText) ? null : snapshot.IncompleteOfferText), BossItem = ((snapshot.BossItem.Length == 0) ? null : snapshot.BossItem), BossItems = ((snapshot.BossItems == 1) ? null : new int?(snapshot.BossItems)), BossPrefab = ((snapshot.BossPrefab.Length == 0) ? null : snapshot.BossPrefab), ItemPrefab = ((snapshot.ItemPrefab.Length == 0) ? null : snapshot.ItemPrefab), SetGlobalKey = (string.IsNullOrWhiteSpace(snapshot.SetGlobalKey) ? null : snapshot.SetGlobalKey), RenderSpawnAreaGizmos = (snapshot.RenderSpawnAreaGizmos ? new bool?(true) : null), AlertOnSpawn = (snapshot.AlertOnSpawn ? new bool?(true) : null), SpawnBossDelay = (IsReferenceDefault(snapshot.SpawnBossDelay, 5f) ? null : new float?(snapshot.SpawnBossDelay)), SpawnBossDistance = RangeFormatting.FromReference(snapshot.SpawnBossMinDistance, snapshot.SpawnBossMaxDistance, 0f, 40f), SpawnBossMaxYDistance = (IsReferenceDefault(snapshot.SpawnBossMaxYDistance, 9999f) ? null : new float?(snapshot.SpawnBossMaxYDistance)), GetSolidHeightMargin = ((snapshot.GetSolidHeightMargin == 1000) ? null : new int?(snapshot.GetSolidHeightMargin)), EnableSolidHeightCheck = (snapshot.EnableSolidHeightCheck ? null : new bool?(false)), SpawnPointClearingRadius = (IsReferenceDefault(snapshot.SpawnPointClearingRadius, 0f) ? null : new float?(snapshot.SpawnPointClearingRadius)), SpawnYOffset = (IsReferenceDefault(snapshot.SpawnYOffset, 1f) ? null : new float?(snapshot.SpawnYOffset)), UseItemStands = (snapshot.UseItemStands ? new bool?(true) : null), ItemStandPrefix = (string.IsNullOrWhiteSpace(snapshot.ItemStandPrefix) ? null : snapshot.ItemStandPrefix), ItemStandMaxRange = (IsReferenceDefault(snapshot.ItemStandMaxRange, 20f) ? null : new float?(snapshot.ItemStandMaxRange)), RespawnMinutes = null }; } private static LocationVegvisirDefinition ConvertReferenceVegvisir(PathScopedVegvisirSnapshot snapshot) { return new LocationVegvisirDefinition { Path = snapshot.Path, ExpectedLocations = GetExpectedVegvisirLocations(snapshot.Snapshot), Name = ((string.IsNullOrWhiteSpace(snapshot.Snapshot.Name) || snapshot.Snapshot.Name == "$piece_vegvisir") ? null : snapshot.Snapshot.Name), UseText = ((string.IsNullOrWhiteSpace(snapshot.Snapshot.UseText) || snapshot.Snapshot.UseText == "$piece_register_location") ? null : snapshot.Snapshot.UseText), HoverName = ((string.IsNullOrWhiteSpace(snapshot.Snapshot.HoverName) || snapshot.Snapshot.HoverName == "Pin") ? null : snapshot.Snapshot.HoverName), SetsGlobalKey = (string.IsNullOrWhiteSpace(snapshot.Snapshot.SetsGlobalKey) ? null : snapshot.Snapshot.SetsGlobalKey), SetsPlayerKey = (string.IsNullOrWhiteSpace(snapshot.Snapshot.SetsPlayerKey) ? null : snapshot.Snapshot.SetsPlayerKey), Locations = ((snapshot.Snapshot.Locations.Count == 0) ? null : snapshot.Snapshot.Locations.Select(ConvertReferenceVegvisirTarget).ToList()) }; } private static List? GetExpectedVegvisirLocations(VegvisirSnapshot snapshot) { List list = (from location in snapshot.Locations select (location.LocationName ?? "").Trim() into value where value.Length > 0 select value).Distinct(StringComparer.OrdinalIgnoreCase).ToList(); if (list.Count != 0) { return list; } return null; } private static LocationItemStandDefinition ConvertReferenceItemStand(PathScopedItemStandSnapshot snapshot) { //IL_009e: Unknown result type (might be due to invalid IL or missing references) LocationItemStandDefinition obj = new LocationItemStandDefinition { Path = snapshot.Path, Name = (string.IsNullOrWhiteSpace(snapshot.Snapshot.Name) ? null : snapshot.Snapshot.Name), CanBeRemoved = (snapshot.Snapshot.CanBeRemoved ? null : new bool?(false)), AutoAttach = (snapshot.Snapshot.AutoAttach ? new bool?(true) : null) }; object orientationType2; if (!string.IsNullOrWhiteSpace(snapshot.Snapshot.OrientationType)) { string orientationType = snapshot.Snapshot.OrientationType; Orientation val = (Orientation)1; if (!(orientationType == ((object)(Orientation)(ref val)).ToString())) { orientationType2 = snapshot.Snapshot.OrientationType; goto IL_00c1; } } orientationType2 = null; goto IL_00c1; IL_00c1: obj.OrientationType = (string?)orientationType2; obj.SupportedTypes = ((snapshot.Snapshot.SupportedTypes.Count == 0) ? null : snapshot.Snapshot.SupportedTypes); obj.SupportedItems = ((snapshot.Snapshot.SupportedItems.Count == 0) ? null : snapshot.Snapshot.SupportedItems); obj.UnsupportedItems = ((snapshot.Snapshot.UnsupportedItems.Count == 0) ? null : snapshot.Snapshot.UnsupportedItems); obj.PowerActivationDelay = (IsReferenceDefault(snapshot.Snapshot.PowerActivationDelay, 2f) ? null : new float?(snapshot.Snapshot.PowerActivationDelay)); obj.GuardianPower = (string.IsNullOrWhiteSpace(snapshot.Snapshot.GuardianPower) ? null : snapshot.Snapshot.GuardianPower); return obj; } private static LocationRunestoneDefinition ConvertReferenceRunestone(PathScopedRunestoneSnapshot snapshot) { //IL_0200: Unknown result type (might be due to invalid IL or missing references) LocationRunestoneDefinition obj = new LocationRunestoneDefinition { Path = snapshot.Path, ExpectedLocationName = (string.IsNullOrWhiteSpace(snapshot.Snapshot.LocationName) ? null : snapshot.Snapshot.LocationName), ExpectedLabel = (string.IsNullOrWhiteSpace(snapshot.Snapshot.Label) ? null : snapshot.Snapshot.Label), ExpectedTopic = (string.IsNullOrWhiteSpace(snapshot.Snapshot.Topic) ? null : snapshot.Snapshot.Topic), Name = ((string.IsNullOrWhiteSpace(snapshot.Snapshot.Name) || snapshot.Snapshot.Name == "Rune stone") ? null : snapshot.Snapshot.Name), Topic = (string.IsNullOrWhiteSpace(snapshot.Snapshot.Topic) ? null : snapshot.Snapshot.Topic), Label = (string.IsNullOrWhiteSpace(snapshot.Snapshot.Label) ? null : snapshot.Snapshot.Label), Text = (string.IsNullOrWhiteSpace(snapshot.Snapshot.Text) ? null : snapshot.Snapshot.Text), RandomTexts = ((snapshot.Snapshot.RandomTexts.Count == 0) ? null : snapshot.Snapshot.RandomTexts.Select(ConvertReferenceRunestoneText).ToList()), LocationName = (string.IsNullOrWhiteSpace(snapshot.Snapshot.LocationName) ? null : snapshot.Snapshot.LocationName), PinName = ((string.IsNullOrWhiteSpace(snapshot.Snapshot.PinName) || snapshot.Snapshot.PinName == "Pin") ? null : snapshot.Snapshot.PinName) }; object pinType2; if (!string.IsNullOrWhiteSpace(snapshot.Snapshot.PinType)) { string pinType = snapshot.Snapshot.PinType; PinType val = (PinType)9; if (!(pinType == ((object)(PinType)(ref val)).ToString())) { pinType2 = snapshot.Snapshot.PinType; goto IL_0223; } } pinType2 = null; goto IL_0223; IL_0223: obj.PinType = (string?)pinType2; obj.ShowMap = (snapshot.Snapshot.ShowMap ? new bool?(true) : null); return obj; } private static LocationRunestoneTextDefinition ConvertReferenceRunestoneText(RunestoneTextSnapshot snapshot) { return new LocationRunestoneTextDefinition { Topic = (string.IsNullOrWhiteSpace(snapshot.Topic) ? null : snapshot.Topic), Label = (string.IsNullOrWhiteSpace(snapshot.Label) ? null : snapshot.Label), Text = (string.IsNullOrWhiteSpace(snapshot.Text) ? null : snapshot.Text) }; } private static LocationVegvisirTargetDefinition ConvertReferenceVegvisirTarget(VegvisirTargetSnapshot snapshot) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) LocationVegvisirTargetDefinition obj = new LocationVegvisirTargetDefinition { LocationName = snapshot.LocationName, PinName = ((string.IsNullOrWhiteSpace(snapshot.PinName) || snapshot.PinName == "Pin") ? null : snapshot.PinName) }; object pinType2; if (!string.IsNullOrWhiteSpace(snapshot.PinType)) { string pinType = snapshot.PinType; PinType val = (PinType)0; if (!(pinType == ((object)(PinType)(ref val)).ToString())) { pinType2 = snapshot.PinType; goto IL_0072; } } pinType2 = null; goto IL_0072; IL_0072: obj.PinType = (string?)pinType2; obj.DiscoverAll = (snapshot.DiscoverAll ? new bool?(true) : null); obj.ShowMap = (snapshot.ShowMap ? null : new bool?(false)); return obj; } private static void TrackSpawnedLocationRootInternal(GameObject? rootObject) { if ((Object)(object)rootObject == (Object)null) { return; } List list = new List(); CollectLocationsUnderRoot(rootObject.transform, list); foreach (Location item in list) { if ((Object)(object)item != (Object)null) { TrackLocationInstanceInternal(item); } } } private static void CollectLocationsUnderRoot(Transform? root, List locations) { List locations2 = locations; if ((Object)(object)root == (Object)null) { return; } SceneTraversalSupport.TraverseHierarchy(root, delegate(Transform transform) { Location val = default(Location); if (((Component)transform).TryGetComponent(ref val) && (Object)(object)val != (Object)null) { locations2.Add(val); } }); } private static void CollectLocationRuntimeComponents(Transform? root, List offeringBowls, List itemStands, List vegvisirs, List runestones) { List offeringBowls2 = offeringBowls; List itemStands2 = itemStands; List vegvisirs2 = vegvisirs; List runestones2 = runestones; if ((Object)(object)root == (Object)null) { return; } SceneTraversalSupport.TraverseHierarchy(root, delegate(Transform transform) { OfferingBowl val = default(OfferingBowl); if (((Component)transform).TryGetComponent(ref val) && (Object)(object)val != (Object)null) { offeringBowls2.Add(val); } ItemStand val2 = default(ItemStand); if (((Component)transform).TryGetComponent(ref val2) && (Object)(object)val2 != (Object)null) { itemStands2.Add(val2); } Vegvisir val3 = default(Vegvisir); if (((Component)transform).TryGetComponent(ref val3) && (Object)(object)val3 != (Object)null) { vegvisirs2.Add(val3); } RuneStone val4 = default(RuneStone); if (((Component)transform).TryGetComponent(ref val4) && (Object)(object)val4 != (Object)null) { runestones2.Add(val4); } }); } private static bool ProcessQueuedLocationRootStep(float deadline) { PendingLocationRootReconcile item; while (PendingLocationRootReconciles.TryPeek(out item)) { PendingLocationRootReconcile item2; if (item.Epoch != _reconcileQueueEpoch) { PendingLocationRootReconciles.TryDequeue(out item2); PendingLocationRootReconcileIds.Remove(item.RootInstanceId); continue; } if ((Object)(object)item.RootObject == (Object)null) { PendingLocationRootReconciles.TryDequeue(out item2); PendingLocationRootReconcileIds.Remove(item.RootInstanceId); return true; } if (!_initialized) { Initialize(); } bool flag = false; while (Time.realtimeSinceStartup < deadline) { switch (item.Phase) { case PendingLocationRootPhase.TraverseHierarchy: if (!TraversePendingLocationRootHierarchyStep(item, deadline)) { return flag; } break; case PendingLocationRootPhase.ReconcileLocations: return ReconcilePendingLocationRootLocationStep(item) || flag; default: return flag; } item.Phase = PendingLocationRootPhase.ReconcileLocations; flag = true; } return flag; } return false; } private static bool TraversePendingLocationRootHierarchyStep(PendingLocationRootReconcile pendingRoot, float deadline) { PendingLocationRootReconcile pendingLocationRootReconcile = pendingRoot; if (pendingLocationRootReconcile.Locations == null) { List list2 = (pendingLocationRootReconcile.Locations = new List()); } pendingLocationRootReconcile = pendingRoot; if (pendingLocationRootReconcile.TraversalStack == null) { PendingLocationRootReconcile pendingLocationRootReconcile2 = pendingLocationRootReconcile; List obj = new List { new PendingLocationTraversalNode(pendingRoot.RootObject.transform, null) }; List list3 = obj; pendingLocationRootReconcile2.TraversalStack = obj; } pendingLocationRootReconcile = pendingRoot; if (pendingLocationRootReconcile.RuntimeComponentsByLocationId == null) { Dictionary dictionary2 = (pendingLocationRootReconcile.RuntimeComponentsByLocationId = new Dictionary()); } int num = 0; Location val2 = default(Location); OfferingBowl offeringBowl = default(OfferingBowl); ItemStand itemStand = default(ItemStand); Vegvisir vegvisir = default(Vegvisir); RuneStone runestone = default(RuneStone); while (pendingRoot.TraversalStack.Count > 0) { if ((num & 0xF) == 0 && Time.realtimeSinceStartup >= deadline) { return false; } int index = pendingRoot.TraversalStack.Count - 1; PendingLocationTraversalNode pendingLocationTraversalNode = pendingRoot.TraversalStack[index]; pendingRoot.TraversalStack.RemoveAt(index); num++; Transform transform = pendingLocationTraversalNode.Transform; if ((Object)(object)transform == (Object)null) { continue; } Location val = pendingLocationTraversalNode.CurrentLocation; if (((Component)transform).TryGetComponent(ref val2) && (Object)(object)val2 != (Object)null) { val = val2; EnsurePendingLocationRuntimeComponents(pendingRoot, val2); } if ((Object)(object)val != (Object)null) { int instanceID = ((Object)val).GetInstanceID(); if (pendingRoot.RuntimeComponentsByLocationId != null && pendingRoot.RuntimeComponentsByLocationId.TryGetValue(instanceID, out LocationRuntimeComponents value) && ((Component)transform).TryGetComponent(ref offeringBowl)) { AddPendingLocationOfferingBowl(value, offeringBowl); } if (pendingRoot.RuntimeComponentsByLocationId != null && pendingRoot.RuntimeComponentsByLocationId.TryGetValue(instanceID, out value) && ((Component)transform).TryGetComponent(ref itemStand)) { AddPendingLocationItemStand(value, itemStand); } if (pendingRoot.RuntimeComponentsByLocationId != null && pendingRoot.RuntimeComponentsByLocationId.TryGetValue(instanceID, out value) && ((Component)transform).TryGetComponent(ref vegvisir)) { AddPendingLocationVegvisir(value, vegvisir); } if (pendingRoot.RuntimeComponentsByLocationId != null && pendingRoot.RuntimeComponentsByLocationId.TryGetValue(instanceID, out value) && ((Component)transform).TryGetComponent(ref runestone)) { AddPendingLocationRunestone(value, runestone); } } for (int num2 = transform.childCount - 1; num2 >= 0; num2--) { Transform child = transform.GetChild(num2); if ((Object)(object)child != (Object)null) { pendingRoot.TraversalStack.Add(new PendingLocationTraversalNode(child, val)); } } } FinalizePendingLocationRootBundle(pendingRoot); pendingRoot.NextIndex = 0; return true; } private static void EnsurePendingLocationRuntimeComponents(PendingLocationRootReconcile pendingRoot, Location location) { if (pendingRoot.RuntimeComponentsByLocationId != null && pendingRoot.Locations != null) { int instanceID = ((Object)location).GetInstanceID(); if (!pendingRoot.RuntimeComponentsByLocationId.ContainsKey(instanceID)) { pendingRoot.Locations.Add(location); pendingRoot.RuntimeComponentsByLocationId[instanceID] = new LocationRuntimeComponents { Root = ((Component)location).transform }; } } } private static void AddPendingLocationOfferingBowl(LocationRuntimeComponents components, OfferingBowl offeringBowl) { if (components != null && !((Object)(object)offeringBowl == (Object)null)) { components.OfferingBowls.Add(offeringBowl); if (components.PrimaryOfferingBowl == null) { OfferingBowl val2 = (components.PrimaryOfferingBowl = offeringBowl); } components.OfferingBowlsByPath[GetRelativePath(components.Root, ((Component)offeringBowl).transform)] = offeringBowl; } } private static void AddPendingLocationItemStand(LocationRuntimeComponents components, ItemStand itemStand) { if (components != null && !((Object)(object)itemStand == (Object)null)) { components.ItemStands.Add(itemStand); components.ItemStandsByPath[GetRelativePath(components.Root, ((Component)itemStand).transform)] = itemStand; } } private static void AddPendingLocationVegvisir(LocationRuntimeComponents components, Vegvisir vegvisir) { if (components != null && !((Object)(object)vegvisir == (Object)null)) { components.Vegvisirs.Add(vegvisir); components.VegvisirsByPath[GetRelativePath(components.Root, ((Component)vegvisir).transform)] = vegvisir; } } private static void AddPendingLocationRunestone(LocationRuntimeComponents components, RuneStone runestone) { if (components != null && !((Object)(object)runestone == (Object)null)) { components.Runestones.Add(runestone); components.RunestonesByPath[GetRelativePath(components.Root, ((Component)runestone).transform)] = runestone; } } private static void FinalizePendingLocationRootBundle(PendingLocationRootReconcile pendingRoot) { if (pendingRoot.Locations == null || pendingRoot.RuntimeComponentsByLocationId == null) { return; } for (int i = 0; i < pendingRoot.Locations.Count; i++) { Location val = pendingRoot.Locations[i]; if (!((Object)(object)val == (Object)null)) { int instanceID = ((Object)val).GetInstanceID(); if (pendingRoot.RuntimeComponentsByLocationId.TryGetValue(instanceID, out LocationRuntimeComponents value)) { value.RelevantItemStands = GetRelevantLocationItemStands(value.PrimaryOfferingBowl, value.ItemStands); } } } } private static bool ReconcilePendingLocationRootLocationStep(PendingLocationRootReconcile pendingRoot) { while (pendingRoot.Locations != null && pendingRoot.NextIndex < pendingRoot.Locations.Count) { Location val = pendingRoot.Locations[pendingRoot.NextIndex++]; if (!((Object)(object)val == (Object)null)) { int instanceID = ((Object)val).GetInstanceID(); if (PendingLocationReconcileIds.Contains(instanceID)) { SuppressedQueuedLocationReconciles[instanceID] = ((!SuppressedQueuedLocationReconciles.TryGetValue(instanceID, out var value)) ? 1 : (value + 1)); } TrackLocationInstanceInternal(val); LocationRuntimeComponents value2 = null; pendingRoot.RuntimeComponentsByLocationId?.TryGetValue(instanceID, out value2); ReconcileLocationInstanceInternal(val, value2); return true; } } PendingLocationRootReconciles.TryDequeue(out PendingLocationRootReconcile _); PendingLocationRootReconcileIds.Remove(pendingRoot.RootInstanceId); return true; } internal static void TryApplyRunestoneGlobalPins(RuneStone? runestone, bool hold, string? originalLocationName) { if (hold || (Object)(object)runestone == (Object)null || (Object)(object)((Component)runestone).gameObject == (Object)null || !PluginSettingsFacade.IsLocationDomainEnabled() || !PluginSettingsFacade.IsRunestoneGlobalPinsEnabled()) { return; } LocationRunestoneGlobalPinsDefinition effectiveRunestoneGlobalPinsDefinition = GetEffectiveRunestoneGlobalPinsDefinition(); if (effectiveRunestoneGlobalPinsDefinition?.TargetLocations != null && effectiveRunestoneGlobalPinsDefinition.TargetLocations.Count != 0 && string.IsNullOrWhiteSpace(originalLocationName ?? runestone.m_locationName)) { ResolvedRunestoneGlobalPin orRollRunestoneGlobalPin = GetOrRollRunestoneGlobalPin(runestone, effectiveRunestoneGlobalPinsDefinition, originalLocationName); if (orRollRunestoneGlobalPin != null) { TryAddRunestoneGlobalPin(orRollRunestoneGlobalPin); } } } private static LocationRunestoneGlobalPinsDefinition? GetEffectiveRunestoneGlobalPinsDefinition() { for (int num = _configuration.Count - 1; num >= 0; num--) { LocationRunestoneGlobalPinsDefinition runestoneGlobalPins = _configuration[num].RunestoneGlobalPins; if (HasRunestoneGlobalPinsOverride(runestoneGlobalPins)) { return runestoneGlobalPins; } } return null; } private static ResolvedRunestoneGlobalPin? GetOrRollRunestoneGlobalPin(RuneStone runestone, LocationRunestoneGlobalPinsDefinition definition, string? originalLocationName) { string text = CreateRunestoneGlobalPinsRollKey(runestone, definition, originalLocationName); lock (RunestoneGlobalPinsLock) { if (!RunestoneGlobalPinsRolls.TryGetValue(runestone, out RunestoneGlobalPinsRollState value)) { value = new RunestoneGlobalPinsRollState(); RunestoneGlobalPinsRolls.Add(runestone, value); } if (value.RollKey == text) { return value.Pin; } value.RollKey = text; value.Pin = RollRunestoneGlobalPin(runestone, definition); return value.Pin; } } private static ResolvedRunestoneGlobalPin? RollRunestoneGlobalPin(RuneStone runestone, LocationRunestoneGlobalPinsDefinition definition) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) if (definition.TargetLocations == null || (Object)(object)ZoneSystem.instance == (Object)null) { return null; } List list = new List(); Biome runestoneGlobalPinBiome = GetRunestoneGlobalPinBiome(((Component)runestone).transform.position); foreach (LocationRunestoneGlobalPinTargetDefinition targetLocation in definition.TargetLocations) { float num = Mathf.Clamp01(targetLocation.Chance.GetValueOrDefault()); if (targetLocation.LocationName.Length == 0 || num <= 0f) { continue; } Biome allowedSourceBiomeMask = ResolveRunestoneGlobalPinSourceBiomeMask(targetLocation); if (TryFindClosestRunestoneGlobalPinLocation(targetLocation.LocationName, ((Component)runestone).transform.position, runestoneGlobalPinBiome, allowedSourceBiomeMask, out var closest)) { ResolvedRunestoneGlobalPin resolvedRunestoneGlobalPin = CreateResolvedRunestoneGlobalPin(targetLocation, closest); if (resolvedRunestoneGlobalPin != null) { list.Add(new RunestoneGlobalPinCandidate { Chance = num, Pin = resolvedRunestoneGlobalPin }); } } } return SelectRunestoneGlobalPinCandidate(list); } private static ResolvedRunestoneGlobalPin? SelectRunestoneGlobalPinCandidate(List candidates) { float num = 0f; foreach (RunestoneGlobalPinCandidate candidate in candidates) { num += candidate.Chance; } if (num <= 0f) { return null; } if (num > 1f) { WarnRunestoneGlobalPin("globalpin|chance-total-over-1|" + num.ToString("R", CultureInfo.InvariantCulture), "Runestone global pin chance values add up to " + num.ToString("0.###", CultureInfo.InvariantCulture) + " after filtering. Normalizing them, so exactly one candidate can be selected."); } float num2 = Math.Max(1f, num); double num3 = RunestoneGlobalPinsRandom.NextDouble() * (double)num2; float num4 = 0f; foreach (RunestoneGlobalPinCandidate candidate2 in candidates) { num4 += candidate2.Chance; if (num3 < (double)num4) { return candidate2.Pin; } } return null; } private static ResolvedRunestoneGlobalPin? CreateResolvedRunestoneGlobalPin(LocationRunestoneGlobalPinTargetDefinition target, LocationInstance locationInstance) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) string pinName = ((!string.IsNullOrWhiteSpace(target.PinName)) ? target.PinName.Trim() : GetRunestoneGlobalPinDefaultPinName(target.LocationName)); PinType pinType = ParseRunestoneGlobalPinType(target.PinType, target.LocationName); return new ResolvedRunestoneGlobalPin { LocationName = target.LocationName, PinName = pinName, PinType = pinType, Position = locationInstance.m_position }; } private static bool TryAddRunestoneGlobalPin(ResolvedRunestoneGlobalPin pin) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Minimap.instance == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null) { return false; } PinType pinType = pin.PinType; if (HasSimilarRunestoneGlobalPin(pin.Position, pinType, pin.PinName, save: true)) { ((Character)Player.m_localPlayer).Message((MessageType)2, "$msg_pin_exist", 0, (Sprite)null); Minimap.instance.ShowPointOnMap(pin.Position); return false; } PinData val = Minimap.instance.AddPin(pin.Position, pinType, pin.PinName, true, false, 0L, default(PlatformUserID)); ((Character)Player.m_localPlayer).Message((MessageType)1, "$msg_pin_added: " + pin.PinName, 0, val.m_icon); Minimap.instance.ShowPointOnMap(pin.Position); return true; } private static bool TryFindClosestRunestoneGlobalPinLocation(string locationName, Vector3 runestonePosition, Biome runestoneBiome, Biome allowedSourceBiomeMask, out LocationInstance closest) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) closest = default(LocationInstance); if (!TryGetRunestoneGlobalPinLocationInstances(locationName, out List instances)) { return false; } float num = float.MaxValue; bool flag = false; foreach (LocationInstance item in instances) { if (RunestoneGlobalPinBiomesMatch(GetRunestoneGlobalPinBiome(item.m_position), runestoneBiome) || RunestoneGlobalPinAllowsSourceBiome(runestoneBiome, allowedSourceBiomeMask)) { float num2 = Utils.DistanceXZ(runestonePosition, item.m_position); if (!flag || num2 < num) { num = num2; closest = item; flag = true; } } } return flag; } private static bool TryGetRunestoneGlobalPinLocationInstances(string locationName, out List instances) { instances = null; string text = (locationName ?? "").Trim(); if (text.Length == 0 || !TryGetRunestoneGlobalPinLocationIndex(out RunestoneGlobalPinLocationIndex index)) { return false; } if (index.InstancesByName.TryGetValue(text, out instances)) { return instances.Count > 0; } return false; } private static bool TryGetRunestoneGlobalPinLocationIndex(out RunestoneGlobalPinLocationIndex index) { //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) index = null; ZoneSystem instance = ZoneSystem.instance; if ((Object)(object)instance == (Object)null) { RunestoneGlobalPinLocationIndexCache = null; return false; } int instanceID = ((Object)instance).GetInstanceID(); int count = instance.m_locationInstances.Count; if (RunestoneGlobalPinLocationIndexCache != null && RunestoneGlobalPinLocationIndexCache.ZoneSystemId == instanceID && RunestoneGlobalPinLocationIndexCache.LocationInstanceCount == count) { index = RunestoneGlobalPinLocationIndexCache; return true; } RunestoneGlobalPinLocationIndex runestoneGlobalPinLocationIndex = new RunestoneGlobalPinLocationIndex { ZoneSystemId = instanceID, LocationInstanceCount = count }; foreach (LocationInstance value2 in instance.m_locationInstances.Values) { string zoneLocationPrefabName = GetZoneLocationPrefabName(value2.m_location); if (zoneLocationPrefabName.Length != 0) { if (!runestoneGlobalPinLocationIndex.InstancesByName.TryGetValue(zoneLocationPrefabName, out List value)) { value = new List(); runestoneGlobalPinLocationIndex.InstancesByName[zoneLocationPrefabName] = value; } value.Add(value2); } } RunestoneGlobalPinLocationIndexCache = runestoneGlobalPinLocationIndex; index = runestoneGlobalPinLocationIndex; return true; } private static Biome ResolveRunestoneGlobalPinSourceBiomeMask(LocationRunestoneGlobalPinTargetDefinition target) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) if (target.SourceBiomes == null || target.SourceBiomes.Count == 0) { return (Biome)0; } if (BiomeResolutionSupport.TryResolveBiomeMask(target.SourceBiomes, out var biomeMask)) { return biomeMask; } WarnRunestoneGlobalPin("globalpin|invalid-source-biome|" + target.LocationName + "|" + string.Join(",", target.SourceBiomes), "Runestone global pin target '" + target.LocationName + "' has invalid sourceBiomes value. Matching-biome RuneStones can still target it."); return (Biome)0; } private static bool RunestoneGlobalPinBiomesMatch(Biome targetBiome, Biome runestoneBiome) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Invalid comparison between Unknown and I4 if (targetBiome != runestoneBiome) { if ((int)targetBiome != 0 && (int)runestoneBiome != 0) { return (targetBiome & runestoneBiome) > 0; } return false; } return true; } private static bool RunestoneGlobalPinAllowsSourceBiome(Biome runestoneBiome, Biome allowedSourceBiomeMask) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Invalid comparison between Unknown and I4 if ((int)allowedSourceBiomeMask != 895) { if ((int)allowedSourceBiomeMask != 0 && (int)runestoneBiome != 0) { return (allowedSourceBiomeMask & runestoneBiome) > 0; } return false; } return true; } private static Biome GetRunestoneGlobalPinBiome(Vector3 position) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) if (WorldGenerator.instance == null) { return Heightmap.FindBiome(position); } return WorldGenerator.instance.GetBiome(position); } private static string GetRunestoneGlobalPinDefaultPinName(string locationName) { string runestoneGlobalPinDiscoverLabel = GetRunestoneGlobalPinDiscoverLabel(locationName); if (runestoneGlobalPinDiscoverLabel.Length <= 0) { return locationName; } return runestoneGlobalPinDiscoverLabel; } private static string GetRunestoneGlobalPinDiscoverLabel(string locationName) { //IL_0063: Unknown result type (might be due to invalid IL or missing references) if (RunestoneGlobalPinDiscoverLabels.TryGetValue(locationName, out string value)) { return value; } string text = ""; if ((Object)(object)ZoneSystem.instance != (Object)null) { foreach (ZoneLocation location in ZoneSystem.instance.m_locations) { if (string.Equals(GetZoneLocationPrefabName(location), locationName, StringComparison.OrdinalIgnoreCase) && location.m_prefab.IsValid) { location.m_prefab.Load(); try { GameObject asset = location.m_prefab.Asset; text = (((asset == null) ? null : asset.GetComponent()?.m_discoverLabel) ?? "").Trim(); } finally { location.m_prefab.Release(); } break; } } } RunestoneGlobalPinDiscoverLabels[locationName] = text; return text; } private static PinType ParseRunestoneGlobalPinType(string? rawPinType, string locationName) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) string? text; if (!string.IsNullOrWhiteSpace(rawPinType)) { text = rawPinType.Trim(); } else { PinType val = (PinType)3; text = ((object)(PinType)(ref val)).ToString(); } string text2 = text; if (Enum.TryParse(text2, ignoreCase: true, out PinType result)) { return result; } WarnRunestoneGlobalPin("globalpin|invalid-pintype|" + locationName + "|" + text2, "Runestone global pin target '" + locationName + "' has invalid pinType '" + text2 + "'. Using Icon3."); return (PinType)3; } private static bool HasSimilarRunestoneGlobalPin(Vector3 position, PinType pinType, string pinName, bool save) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Minimap.instance == (Object)null || !(MinimapPinsField?.GetValue(Minimap.instance) is List list)) { return false; } foreach (PinData item in list) { if (item.m_type == pinType && item.m_save == save && string.Equals(item.m_name, pinName, StringComparison.Ordinal) && Utils.DistanceXZ(item.m_pos, position) < 1f) { return true; } } return false; } private static string CreateRunestoneGlobalPinsRollKey(RuneStone runestone, LocationRunestoneGlobalPinsDefinition definition, string? originalLocationName) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(((Object)runestone).GetInstanceID().ToString(CultureInfo.InvariantCulture)).Append('\n'); Vector3 position = ((Component)runestone).transform.position; stringBuilder.Append(position.x.ToString("R", CultureInfo.InvariantCulture)).Append('|').Append(position.y.ToString("R", CultureInfo.InvariantCulture)) .Append('|') .Append(position.z.ToString("R", CultureInfo.InvariantCulture)) .Append('\n'); stringBuilder.Append(originalLocationName ?? runestone.m_locationName ?? "").Append('\n'); if (definition.TargetLocations != null) { foreach (LocationRunestoneGlobalPinTargetDefinition targetLocation in definition.TargetLocations) { stringBuilder.Append(targetLocation.LocationName).Append('|').Append(targetLocation.Chance?.ToString("R", CultureInfo.InvariantCulture) ?? "") .Append('|') .Append((targetLocation.SourceBiomes == null) ? "" : string.Join(",", targetLocation.SourceBiomes)) .Append('|') .Append(targetLocation.PinName ?? "") .Append('|') .Append(targetLocation.PinType ?? "") .Append('\n'); } } return stringBuilder.ToString(); } private static void WarnRunestoneGlobalPin(string warningKey, string message) { if (RunestoneGlobalPinWarningLogs.Add(warningKey)) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)message); } } private static string BuildFullScaffoldConfigurationTemplate() { StringBuilder stringBuilder = new StringBuilder(); bool flag = false; foreach (PrefabOwnerSection item in BuildOrderedSnapshots()) { foreach (LocationSnapshot entry in item.Entries) { if (flag) { AppendScaffoldBlankLine(stringBuilder); } AppendScaffoldEntry(stringBuilder, entry); flag = true; } } if (!flag) { return "[]" + Environment.NewLine; } return stringBuilder.ToString(); } private static void AppendScaffoldEntry(StringBuilder builder, LocationSnapshot snapshot) { AppendScaffoldListEntryLine(builder, 0, "prefab", snapshot.Prefab); AppendScaffoldLine(builder, 1, "enabled: true"); AppendScaffoldConditionsBlock(builder, 1); if (snapshot.OfferingBowl != null) { AppendScaffoldLine(builder, 1, "offeringBowl:"); AppendScaffoldStringLine(builder, 2, "name", snapshot.OfferingBowl.Name); AppendScaffoldStringLine(builder, 2, "useItemText", snapshot.OfferingBowl.UseItemText); AppendScaffoldStringLine(builder, 2, "usedAltarText", snapshot.OfferingBowl.UsedAltarText); AppendScaffoldStringLine(builder, 2, "cantOfferText", snapshot.OfferingBowl.CantOfferText); AppendScaffoldStringLine(builder, 2, "wrongOfferText", snapshot.OfferingBowl.WrongOfferText); AppendScaffoldStringLine(builder, 2, "incompleteOfferText", snapshot.OfferingBowl.IncompleteOfferText); AppendScaffoldStringLine(builder, 2, "bossItem", snapshot.OfferingBowl.BossItem); AppendScaffoldLine(builder, 2, $"bossItems: {snapshot.OfferingBowl.BossItems}"); AppendScaffoldStringLine(builder, 2, "bossPrefab", snapshot.OfferingBowl.BossPrefab); AppendScaffoldStringLine(builder, 2, "itemPrefab", snapshot.OfferingBowl.ItemPrefab); AppendScaffoldStringLine(builder, 2, "setGlobalKey", snapshot.OfferingBowl.SetGlobalKey); AppendScaffoldLine(builder, 2, "renderSpawnAreaGizmos: " + FormatYamlBool(snapshot.OfferingBowl.RenderSpawnAreaGizmos)); AppendScaffoldLine(builder, 2, "alertOnSpawn: " + FormatYamlBool(snapshot.OfferingBowl.AlertOnSpawn)); AppendScaffoldLine(builder, 2, "spawnBossDelay: " + FormatYamlFloat(snapshot.OfferingBowl.SpawnBossDelay)); AppendScaffoldLine(builder, 2, "spawnBossDistance: " + RangeFormatting.FormatInlineObject(RangeFormatting.From(snapshot.OfferingBowl.SpawnBossMinDistance, snapshot.OfferingBowl.SpawnBossMaxDistance))); AppendScaffoldLine(builder, 2, "spawnBossMaxYDistance: " + FormatYamlFloat(snapshot.OfferingBowl.SpawnBossMaxYDistance)); AppendScaffoldLine(builder, 2, $"getSolidHeightMargin: {snapshot.OfferingBowl.GetSolidHeightMargin}"); AppendScaffoldLine(builder, 2, "enableSolidHeightCheck: " + FormatYamlBool(snapshot.OfferingBowl.EnableSolidHeightCheck)); AppendScaffoldLine(builder, 2, "spawnPointClearingRadius: " + FormatYamlFloat(snapshot.OfferingBowl.SpawnPointClearingRadius)); AppendScaffoldLine(builder, 2, "spawnYOffset: " + FormatYamlFloat(snapshot.OfferingBowl.SpawnYOffset)); AppendScaffoldLine(builder, 2, "useItemStands: " + FormatYamlBool(snapshot.OfferingBowl.UseItemStands)); AppendScaffoldStringLine(builder, 2, "itemStandPrefix", snapshot.OfferingBowl.ItemStandPrefix); AppendScaffoldLine(builder, 2, "itemStandMaxRange: " + FormatYamlFloat(snapshot.OfferingBowl.ItemStandMaxRange)); AppendScaffoldLine(builder, 2, "respawnMinutes: 0"); AppendScaffoldStringLine(builder, 2, "data", null); AppendScaffoldLine(builder, 2, "fields: {}"); AppendScaffoldLine(builder, 2, "objects: []"); } if (snapshot.ItemStands.Count > 0) { AppendScaffoldLine(builder, 1, "itemStands:"); foreach (PathScopedItemStandSnapshot itemStand in snapshot.ItemStands) { AppendScaffoldListEntryLine(builder, 1, "path", itemStand.Path); AppendScaffoldStringLine(builder, 2, "name", itemStand.Snapshot.Name); AppendScaffoldLine(builder, 2, "canBeRemoved: " + FormatYamlBool(itemStand.Snapshot.CanBeRemoved)); AppendScaffoldLine(builder, 2, "autoAttach: " + FormatYamlBool(itemStand.Snapshot.AutoAttach)); AppendScaffoldStringLine(builder, 2, "orientationType", itemStand.Snapshot.OrientationType); AppendScaffoldInlineListLine(builder, 2, "supportedTypes", itemStand.Snapshot.SupportedTypes); AppendScaffoldInlineListLine(builder, 2, "supportedItems", itemStand.Snapshot.SupportedItems); AppendScaffoldInlineListLine(builder, 2, "unsupportedItems", itemStand.Snapshot.UnsupportedItems); AppendScaffoldLine(builder, 2, "powerActivationDelay: " + FormatYamlFloat(itemStand.Snapshot.PowerActivationDelay)); AppendScaffoldStringLine(builder, 2, "guardianPower", itemStand.Snapshot.GuardianPower); } } if (snapshot.Vegvisirs.Count > 0) { AppendScaffoldLine(builder, 1, "vegvisirs:"); foreach (PathScopedVegvisirSnapshot vegvisir in snapshot.Vegvisirs) { AppendScaffoldListEntryLine(builder, 1, "path", vegvisir.Path); AppendScaffoldInlineListLine(builder, 2, "expectedLocations", GetExpectedVegvisirLocations(vegvisir.Snapshot)); AppendScaffoldStringLine(builder, 2, "name", vegvisir.Snapshot.Name); AppendScaffoldStringLine(builder, 2, "useText", vegvisir.Snapshot.UseText); AppendScaffoldStringLine(builder, 2, "hoverName", vegvisir.Snapshot.HoverName); AppendScaffoldStringLine(builder, 2, "setsGlobalKey", vegvisir.Snapshot.SetsGlobalKey); AppendScaffoldStringLine(builder, 2, "setsPlayerKey", vegvisir.Snapshot.SetsPlayerKey); if (vegvisir.Snapshot.Locations.Count == 0) { AppendScaffoldLine(builder, 2, "locations: []"); continue; } AppendScaffoldLine(builder, 2, "locations:"); foreach (VegvisirTargetSnapshot location in vegvisir.Snapshot.Locations) { AppendScaffoldListEntryLine(builder, 2, "locationName", location.LocationName); AppendScaffoldStringLine(builder, 3, "pinName", location.PinName); AppendScaffoldStringLine(builder, 3, "pinType", location.PinType); AppendScaffoldLine(builder, 3, "discoverAll: " + FormatYamlBool(location.DiscoverAll)); AppendScaffoldLine(builder, 3, "showMap: " + FormatYamlBool(location.ShowMap)); AppendScaffoldLine(builder, 3, "weight: null"); } } } if (snapshot.Runestones.Count <= 0) { return; } AppendScaffoldLine(builder, 1, "runestones:"); foreach (PathScopedRunestoneSnapshot runestone in snapshot.Runestones) { AppendScaffoldListEntryLine(builder, 1, "path", runestone.Path); AppendScaffoldStringLine(builder, 2, "expectedLocationName", string.IsNullOrWhiteSpace(runestone.Snapshot.LocationName) ? null : runestone.Snapshot.LocationName); AppendScaffoldStringLine(builder, 2, "expectedLabel", string.IsNullOrWhiteSpace(runestone.Snapshot.Label) ? null : runestone.Snapshot.Label); AppendScaffoldStringLine(builder, 2, "expectedTopic", string.IsNullOrWhiteSpace(runestone.Snapshot.Topic) ? null : runestone.Snapshot.Topic); AppendScaffoldStringLine(builder, 2, "name", runestone.Snapshot.Name); AppendScaffoldStringLine(builder, 2, "topic", runestone.Snapshot.Topic); AppendScaffoldStringLine(builder, 2, "label", runestone.Snapshot.Label); AppendScaffoldStringLine(builder, 2, "text", runestone.Snapshot.Text); if (runestone.Snapshot.RandomTexts.Count == 0) { AppendScaffoldLine(builder, 2, "randomTexts: []"); } else { AppendScaffoldLine(builder, 2, "randomTexts:"); foreach (RunestoneTextSnapshot randomText in runestone.Snapshot.RandomTexts) { AppendScaffoldListEntryLine(builder, 2, "topic", randomText.Topic); AppendScaffoldStringLine(builder, 3, "label", randomText.Label); AppendScaffoldStringLine(builder, 3, "text", randomText.Text); } } AppendScaffoldStringLine(builder, 2, "locationName", runestone.Snapshot.LocationName); AppendScaffoldStringLine(builder, 2, "pinName", runestone.Snapshot.PinName); AppendScaffoldStringLine(builder, 2, "pinType", runestone.Snapshot.PinType); AppendScaffoldLine(builder, 2, "showMap: " + FormatYamlBool(runestone.Snapshot.ShowMap)); } } private static void AppendScaffoldLine(StringBuilder builder, int indent, string text) { builder.Append(' ', indent * 2); builder.AppendLine(text); } private static void AppendScaffoldBlankLine(StringBuilder builder) { builder.AppendLine(); } private static void AppendScaffoldConditionsBlock(StringBuilder builder, int indent) { AppendScaffoldLine(builder, indent, "conditions:"); AppendScaffoldLine(builder, indent + 1, "biomes: []"); AppendScaffoldLine(builder, indent + 1, "altitude: null"); AppendScaffoldLine(builder, indent + 1, "distanceFromCenter: null"); AppendScaffoldLine(builder, indent + 1, "inDungeon: null"); AppendScaffoldLine(builder, indent + 1, "inForest: null"); } private static void AppendScaffoldStringLine(StringBuilder builder, int indent, string key, string? value) { if (value == null) { AppendScaffoldLine(builder, indent, key + ": null"); } else { AppendScaffoldLine(builder, indent, key + ": " + FormatYamlString(value)); } } private static void AppendScaffoldInlineListLine(StringBuilder builder, int indent, string key, List? values) { if (values == null || values.Count == 0) { AppendScaffoldLine(builder, indent, key + ": []"); } else { AppendScaffoldLine(builder, indent, key + ": [" + string.Join(", ", values.Select(FormatYamlString)) + "]"); } } private static void AppendScaffoldListEntryLine(StringBuilder builder, int indent, string key, string value) { AppendScaffoldLine(builder, indent, "- " + key + ": " + FormatYamlString(value)); } private static string BuildPrimaryOverrideConfigurationTemplate() { StringBuilder stringBuilder = new StringBuilder(); CommentedYamlTemplateSupport.AppendTemplateComment(stringBuilder, "Any file named " + PluginSettingsFacade.GetYamlDomainSupplementalPrefix("location") + "*.yml or " + PluginSettingsFacade.GetYamlDomainSupplementalPrefix("location") + "*.yaml is also loaded."); CommentedYamlTemplateSupport.AppendTemplateComment(stringBuilder, "Use " + PluginSettingsFacade.GetYamlDomainFilePrefix("location") + ".reference.yml to look up real location prefab names and run dns:full location to regenerate " + PluginSettingsFacade.GetYamlDomainFilePrefix("location") + ".full.yml."); CommentedYamlTemplateSupport.AppendTemplateComment(stringBuilder, "itemStands uses a YAML list. Omit path to apply one row to all relevant item stands for the location, or copy an exact itemStands.path from " + PluginSettingsFacade.GetYamlDomainFilePrefix("location") + ".reference.yml to target one stand."); CommentedYamlTemplateSupport.AppendTemplateComment(stringBuilder, "Vegvisir overrides are path-targeted by default. Copy the exact vegvisirs.path value from " + PluginSettingsFacade.GetYamlDomainFilePrefix("location") + ".reference.yml when a location has multiple Vegvisirs. Omit path only when exactly one live Vegvisir matches."); CommentedYamlTemplateSupport.AppendTemplateComment(stringBuilder, "RuneStone overrides are path-targeted by default. Copy the exact runestones.path value from " + PluginSettingsFacade.GetYamlDomainFilePrefix("location") + ".reference.yml when a location has multiple RuneStones. Omit path only when exactly one live RuneStone matches."); CommentedYamlTemplateSupport.AppendTemplateComment(stringBuilder, "Expand World clone aliases are matched exactly # ex) prefab: \"Dragonqueen:clone\" # quotes are required because ':' must stay inside one YAML string"); CommentedYamlTemplateSupport.AppendTemplateComment(stringBuilder, "offeringBowl data/fields/objects require Expand World Data and apply only when bossPrefab spawns a character # objects spawn at the resolved boss spawn point"); CommentedYamlTemplateSupport.AppendTemplateBlankLine(stringBuilder); CommentedYamlTemplateSupport.AppendTemplateComment(stringBuilder, "offeringBowl"); CommentedYamlTemplateSupport.AppendTemplateBlankLine(stringBuilder); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 0, "- prefab: Bonemass"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 1, "enabled: true"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 1, "conditions: # Static location filters only. Dynamic fields like timeOfDay/environments/global keys are ignored here"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "biomes: [] # ex) [Meadows, BlackForest] # Allowed biomes # EWD custom biome names also work when EWD is installed"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "altitude: null # ex) -1000~1000 # Range in world-height meters"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "distanceFromCenter: null # ex) 0~10000 # Range in meters from the world center"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "inDungeon: null # ex) true = dungeon only # false = overworld only # null or no field allows both"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "inForest: null # ex) true = forest only # false = outside forest only # null or no field allows both"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 1, "offeringBowl:"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "name: null # ex) '$piece_offerbowl' # Optional hover name"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "useItemText: null # ex) '$piece_offerbowl_offeritem' # Optional interaction text"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "usedAltarText: null # ex) '$msg_offerdone' # Optional completion text"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "cantOfferText: null # ex) '$msg_cantoffer' # Optional failure text"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "wrongOfferText: null # ex) '$msg_offerwrong' # Optional wrong-item text"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "incompleteOfferText: null # ex) '$msg_incompleteoffering' # Optional incomplete-offering text"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "bossItem: null # ex) WitheredBone # Required offering item prefab"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "bossItems: null # ex) 10 # Number of bossItem items required for one valid offering"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "bossPrefab: null # ex) Bonemass # Boss character prefab spawned after a valid offering"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "itemPrefab: null # ex) Wishbone # Optional item reward prefab instead of spawning a boss"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "setGlobalKey: null # ex) defeated_bonemass # Optional global key set after a valid offering"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "renderSpawnAreaGizmos: false # True draws the boss spawn search area while the altar is selected"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "alertOnSpawn: false # True calls BaseAI.Alert() on the spawned boss"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "spawnBossDelay: null # ex) 5 # Seconds to wait before spawning the boss"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "spawnBossDistance: null # ex) 0~40 # Range in meters of horizontal spawn distance from the altar"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "spawnBossMaxYDistance: null # ex) 9999 # Meters of vertical search distance when finding a spawn point"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "getSolidHeightMargin: null # ex) 1000 # Meters of terrain raycast margin used by the altar's solid-height search"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "enableSolidHeightCheck: true # True requires valid ground height before accepting a spawn point"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "spawnPointClearingRadius: 0 # Meters cleared around the final spawn point before boss spawn"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "spawnYOffset: 1 # Meters of vertical offset added to the chosen spawn position"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "useItemStands: false # True switches the offering bowl to nearby item stands instead of direct UseItem offerings"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "itemStandPrefix: null # ex) Boss # Optional object-name prefix used to select nearby item stands"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "itemStandMaxRange: 20 # Meters of max scan distance for nearby item stands"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "respawnMinutes: 0 # 0 disables cooldown # Minutes of altar cooldown"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "data: null # Optional Expand World Data entry applied to the character spawned through bossPrefab"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "fields: {} # ex) { Character.m_name: $enemy_bonemass, health: 5000 } # Expand World Data field overrides layered on top of data"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "objects: [] # ex) [Wood,0,0,0,1] # Expand World Data object entries spawned at the resolved boss spawn point"); CommentedYamlTemplateSupport.AppendTemplateBlankLine(stringBuilder); CommentedYamlTemplateSupport.AppendTemplateComment(stringBuilder, "itemStands"); CommentedYamlTemplateSupport.AppendTemplateBlankLine(stringBuilder); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 0, "- prefab: StartTemple"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 1, "enabled: true"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 1, "conditions: {} # Same static location-filter shape as the offeringBowl example above"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 1, "itemStands:"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 1, "- path: null # ex) BossStone_Eikthyr[0] # Optional exact itemStands.path from " + PluginSettingsFacade.GetYamlDomainFilePrefix("location") + ".reference.yml"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "name: null # ex) '$piece_itemstand' # Optional hover name"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "canBeRemoved: true # True allows players to remove the currently attached item"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "autoAttach: false # True automatically attaches compatible dropped items"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "orientationType: null # ex) Vertical # Optional ItemStand.Orientation name"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "supportedTypes: [] # ex) [OneHandedWeapon, TwoHandedWeapon] # Allowed ItemDrop.ItemType names"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "supportedItems: [] # ex) [TrophyDeer] # Explicitly allowed item prefabs"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "unsupportedItems: [] # ex) [TrophyDeer] # Explicitly blocked item prefabs"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "powerActivationDelay: null # ex) 2 # Seconds before guardianPower activates after use"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "guardianPower: null # ex) GP_Eikthyr # StatusEffect prefab name granted when this stand is used"); CommentedYamlTemplateSupport.AppendTemplateBlankLine(stringBuilder); CommentedYamlTemplateSupport.AppendTemplateComment(stringBuilder, "vegvisirs"); CommentedYamlTemplateSupport.AppendTemplateBlankLine(stringBuilder); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 0, "- prefab: SwampRuin1"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 1, "enabled: true"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 1, "conditions: {} # Same static location-filter shape as the offeringBowl example above"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 1, "vegvisirs:"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 1, "- path: null # ex) Vegvisir_Bonemass (1)[0] # Optional exact vegvisirs.path from " + PluginSettingsFacade.GetYamlDomainFilePrefix("location") + ".reference.yml"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "expectedLocations: [] # ex) [Vendor_BlackForest] # Optional validation list # When path is omitted this must match exactly one live Vegvisir"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "name: null # ex) '$piece_vegvisir' # Optional hover name"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "useText: null # ex) '$piece_register_location' # Optional interaction text"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "hoverName: null # ex) Pin # Optional secondary hover label"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "setsGlobalKey: null # ex) defeated_gdking # Optional global key set after interaction"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "setsPlayerKey: null # Optional per-player key set after interaction"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "locations: # One or more location discoveries triggered by this vegvisir"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "- locationName: null # ex) Vendor_BlackForest # Required location prefab name"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 3, "pinName: null # ex) Pin # Optional map pin label"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 3, "pinType: null # ex) Boss # Optional Minimap.PinType name"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 3, "discoverAll: false # True reveals every matching location instead of only the closest one"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 3, "showMap: true # True creates or updates a map pin for the discovered location"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 3, "weight: null # Optional weighted single-target pick when any vegvisir location defines weight"); CommentedYamlTemplateSupport.AppendTemplateBlankLine(stringBuilder); CommentedYamlTemplateSupport.AppendTemplateComment(stringBuilder, "runestones"); CommentedYamlTemplateSupport.AppendTemplateBlankLine(stringBuilder); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 0, "- prefab: Runestone_Greydwarfs"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 1, "enabled: true"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 1, "conditions: {} # Same static location-filter shape as the offeringBowl example above"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 1, "runestones:"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 1, "- path: null # ex) RuneStone[0] # Optional exact runestones.path from " + PluginSettingsFacade.GetYamlDomainFilePrefix("location") + ".reference.yml"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "expectedLocationName: null # Optional validation/disambiguation when path is omitted"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "expectedLabel: null # Optional validation/disambiguation by current RuneStone label"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "expectedTopic: null # Optional validation/disambiguation by current RuneStone topic"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "name: null # ex) 'Rune stone' # Optional hover name"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "topic: null # Optional TextViewer topic or localization key"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "label: null # Optional known-text label key"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "text: null # Optional TextViewer body or localization key"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "randomTexts: null # [] clears random texts # list entries replace the whole random text list"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "# - topic: null"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "# label: null"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "# text: null"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "locationName: null # Optional location prefab discovered on interaction"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "pinName: null # ex) Pin # Optional map pin label"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "pinType: null # ex) Boss # Optional Minimap.PinType name"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "showMap: null # True shows/creates the discovered location map pin"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "chance: null # Optional 0..1 pin chance rolled once per loaded RuneStone instance"); CommentedYamlTemplateSupport.AppendTemplateBlankLine(stringBuilder); CommentedYamlTemplateSupport.AppendTemplateComment(stringBuilder, "runestoneGlobalPins # Enable with BepInEx config: 1 - General / Enable Runestone Global Pins"); CommentedYamlTemplateSupport.AppendTemplateBlankLine(stringBuilder); CommentedYamlTemplateSupport.AppendActiveTemplateLine(stringBuilder, 0, "- runestoneGlobalPins:"); CommentedYamlTemplateSupport.AppendActiveTemplateLine(stringBuilder, 2, "targetLocations:"); AppendRunestoneGlobalPinTarget(stringBuilder, "Vendor_BlackForest", includeFieldComments: true); AppendRunestoneGlobalPinTarget(stringBuilder, "CombatRuin01"); AppendRunestoneGlobalPinTarget(stringBuilder, "Hildir_camp"); AppendRunestoneGlobalPinTarget(stringBuilder, "BogWitch_Camp"); AppendRunestoneGlobalPinTarget(stringBuilder, "SunkenCrypt4"); AppendRunestoneGlobalPinTarget(stringBuilder, "MountainCave02"); AppendRunestoneGlobalPinTarget(stringBuilder, "StoneHenge1"); AppendRunestoneGlobalPinTarget(stringBuilder, "StoneHenge3"); AppendRunestoneGlobalPinTarget(stringBuilder, "StoneHenge4"); AppendRunestoneGlobalPinTarget(stringBuilder, "StoneHenge5"); AppendRunestoneGlobalPinTarget(stringBuilder, "Mistlands_DvergrTownEntrance1"); AppendRunestoneGlobalPinTarget(stringBuilder, "Mistlands_DvergrTownEntrance2"); AppendRunestoneGlobalPinTarget(stringBuilder, "Mistlands_Excavation1"); AppendRunestoneGlobalPinTarget(stringBuilder, "Mistlands_Excavation2"); AppendRunestoneGlobalPinTarget(stringBuilder, "Mistlands_Excavation3"); AppendRunestoneGlobalPinTarget(stringBuilder, "PlaceofMystery1"); AppendRunestoneGlobalPinTarget(stringBuilder, "PlaceofMystery2"); AppendRunestoneGlobalPinTarget(stringBuilder, "PlaceofMystery3"); CommentedYamlTemplateSupport.AppendActiveTemplateBlankLine(stringBuilder); return stringBuilder.ToString(); } private static void AppendRunestoneGlobalPinTarget(StringBuilder builder, string locationName, bool includeFieldComments = false) { CommentedYamlTemplateSupport.AppendActiveTemplateLine(builder, 2, includeFieldComments ? ("- locationName: " + locationName + " # ZoneSystem location prefab name # Check expand_locations.yaml for locationNames") : ("- locationName: " + locationName)); CommentedYamlTemplateSupport.AppendActiveTemplateLine(builder, 3, includeFieldComments ? "chance: 0.5 # Final selection chance. Remaining chance means no pin; totals over 1 are normalized" : "chance: 0.5"); if (includeFieldComments) { CommentedYamlTemplateSupport.AppendActiveTemplateLine(builder, 3, "# normalized ex) three targets at 0.5 total 1.5, so each selected target has 0.5 / 1.5 = 33.3%"); } CommentedYamlTemplateSupport.AppendActiveTemplateLine(builder, 3, includeFieldComments ? "sourceBiomes: [] # Extra RuneStone source biomes allowed in addition to the target location's own biome" : "sourceBiomes: []"); CommentedYamlTemplateSupport.AppendActiveTemplateLine(builder, 3, includeFieldComments ? "pinName: null # Defaults to the target Location.m_discoverLabel, then locationName" : "pinName: null"); CommentedYamlTemplateSupport.AppendActiveTemplateLine(builder, 3, includeFieldComments ? "pinType: Icon3 # Options: Icon0, Icon1, Icon2, Icon3, Death, Bed, Icon4, Shout, None, Boss, Player, RandomEvent, Ping, EventArea, Hildir1, Hildir2, Hildir3" : "pinType: Icon3"); } } [HarmonyPatch(typeof(RuneStone), "Interact")] internal static class RuneStoneInteractPinChancePatch { private struct SuppressedLocationState { public bool Hold { get; set; } public bool Suppressed { get; set; } public string? OriginalLocationName { get; set; } } private static void Prefix(RuneStone __instance, bool hold, ref SuppressedLocationState __state) { __state.Hold = hold; __state.OriginalLocationName = __instance.m_locationName; if (!hold && LocationManager.ShouldSuppressRunestonePinDiscovery(__instance)) { __state.Suppressed = true; __instance.m_locationName = ""; } } private static void Postfix(RuneStone __instance, SuppressedLocationState __state) { if (__state.Suppressed) { __instance.m_locationName = __state.OriginalLocationName ?? ""; } LocationManager.TryApplyRunestoneGlobalPins(__instance, __state.Hold, __state.OriginalLocationName); } private static void Finalizer(RuneStone __instance, SuppressedLocationState __state) { if (__state.Suppressed) { __instance.m_locationName = __state.OriginalLocationName ?? ""; } } } internal static class LocationRunestoneGlobalPinsConfig { private const string ConfigSection = "1 - General"; private const string ConfigName = "Enable Runestone Global Pins"; private static ConfigEntry _enabled; internal static void Bind(DropNSpawnPlugin plugin) { _enabled = plugin.BindConfigEntry("1 - General", "Enable Runestone Global Pins", DropNSpawnPlugin.Toggle.On, "If on, pinless RuneStones can reveal one saved map pin from the DNS_location.yml runestoneGlobalPins table. Check DNS_location.yml for targetLocations examples and schema. The selected target rolls once per loaded RuneStone instance, and zone unload/reload can roll again.", synchronizedSetting: true, 100); } internal static bool IsEnabled() { ConfigEntry enabled = _enabled; if (enabled == null) { return false; } return enabled.Value == DropNSpawnPlugin.Toggle.On; } } internal static class OfferingBowlHoverInfoFormatter { private sealed class HoverInfoCacheEntry { public int RegistryVersion { get; set; } public float ExpiresAt { get; set; } public string Info { get; set; } = ""; } private static readonly OfferingBowl[] EmptyOfferingBowls = Array.Empty(); private static readonly List RegisteredOfferingBowls = new List(); private static readonly HashSet RegisteredOfferingBowlIds = new HashSet(); private static readonly Dictionary HoverInfoCacheByOfferingBowl = new Dictionary(); private const float HoverInfoCacheLifetimeSeconds = 1f; internal static string AppendInfo(string baseText, OfferingBowl? offeringBowl) { if (!PluginSettingsFacade.ShouldShowLocationProxyOfferingBowlHoverInfo() || (Object)(object)offeringBowl == (Object)null) { return baseText ?? ""; } string cachedInfo = GetCachedInfo(offeringBowl); if (cachedInfo.Length == 0) { return baseText ?? ""; } if (string.IsNullOrWhiteSpace(baseText)) { return cachedInfo; } return baseText + "\n" + cachedInfo; } internal static void RegisterOfferingBowl(OfferingBowl? offeringBowl) { if (!((Object)(object)offeringBowl == (Object)null) && RegisteredOfferingBowlIds.Add(((Object)offeringBowl).GetInstanceID())) { RegisteredOfferingBowls.Add(offeringBowl); } } internal static IReadOnlyList GetKnownOfferingBowls() { CleanupRegisteredOfferingBowls(); EnsureOfferingBowlRegistryPopulated(); if (RegisteredOfferingBowls.Count != 0) { return RegisteredOfferingBowls; } return EmptyOfferingBowls; } private static string GetCachedInfo(OfferingBowl offeringBowl) { float unscaledTime = Time.unscaledTime; CleanupExpiredHoverInfoCache(unscaledTime); int instanceID = ((Object)offeringBowl).GetInstanceID(); int registryVersion = AltarItemStandHoverInfoFormatter.GetRegistryVersion(); if (HoverInfoCacheByOfferingBowl.TryGetValue(instanceID, out HoverInfoCacheEntry value) && value.RegistryVersion == registryVersion && value.ExpiresAt >= unscaledTime) { return value.Info; } string text = BuildInfo(offeringBowl); HoverInfoCacheByOfferingBowl[instanceID] = new HoverInfoCacheEntry { RegistryVersion = registryVersion, ExpiresAt = unscaledTime + 1f, Info = text }; return text; } private static string BuildInfo(OfferingBowl offeringBowl) { string spawnedText = GetSpawnedText(offeringBowl); string requiredText = GetRequiredText(offeringBowl); if (spawnedText.Length == 0) { return requiredText; } if (requiredText.Length == 0) { return spawnedText; } return spawnedText + "\n" + requiredText; } private static string GetSpawnedText(OfferingBowl offeringBowl) { if ((Object)(object)offeringBowl.m_bossPrefab != (Object)null) { return GetCharacterDisplayName(offeringBowl.m_bossPrefab); } if ((Object)(object)offeringBowl.m_itemPrefab != (Object)null) { return GetItemDisplayName(offeringBowl.m_itemPrefab); } return ""; } private static string GetRequiredText(OfferingBowl offeringBowl) { if (offeringBowl.m_useItemStands) { return GetRequiredTextFromItemStands(offeringBowl); } if ((Object)(object)offeringBowl.m_bossItem == (Object)null) { return ""; } string itemDisplayName = GetItemDisplayName(offeringBowl.m_bossItem); if (itemDisplayName.Length == 0) { return ""; } int num = Math.Max(1, offeringBowl.m_bossItems); if (num <= 1) { return itemDisplayName; } return $"{itemDisplayName} x{num}"; } private static string GetRequiredTextFromItemStands(OfferingBowl offeringBowl) { Dictionary dictionary = new Dictionary(StringComparer.Ordinal); foreach (ItemStand displayRelevantItemStand in AltarItemStandHoverInfoFormatter.GetDisplayRelevantItemStands(offeringBowl)) { if (!((Object)(object)displayRelevantItemStand == (Object)null) && displayRelevantItemStand.m_supportedItems != null && displayRelevantItemStand.m_supportedItems.Count == 1) { string itemDisplayName = GetItemDisplayName(displayRelevantItemStand.m_supportedItems[0]); if (itemDisplayName.Length != 0) { dictionary[itemDisplayName] = ((!dictionary.TryGetValue(itemDisplayName, out var value)) ? 1 : (value + 1)); } } } if (dictionary.Count == 0) { return ""; } return string.Join(", ", dictionary.Select((KeyValuePair pair) => (pair.Value <= 1) ? pair.Key : $"{pair.Key} x{pair.Value}")); } private static string GetCharacterDisplayName(GameObject prefab) { Character val = default(Character); if (!prefab.TryGetComponent(ref val)) { return Localize(((Object)prefab).name); } return Localize(string.IsNullOrWhiteSpace(val.m_name) ? ((Object)prefab).name : val.m_name); } private static string GetItemDisplayName(ItemDrop itemDrop) { return Localize(itemDrop.m_itemData.m_shared.m_name); } private static string Localize(string text) { string text2; if (Localization.instance == null) { text2 = text; if (text2 == null) { return ""; } } else { text2 = Localization.instance.Localize(text ?? ""); } return text2; } private static void EnsureOfferingBowlRegistryPopulated() { if (RegisteredOfferingBowls.Count <= 0) { OfferingBowl[] array = Object.FindObjectsByType((FindObjectsSortMode)0); for (int i = 0; i < array.Length; i++) { RegisterOfferingBowl(array[i]); } } } private static void CleanupRegisteredOfferingBowls() { bool flag = false; for (int num = RegisteredOfferingBowls.Count - 1; num >= 0; num--) { if (!((Object)(object)RegisteredOfferingBowls[num] != (Object)null)) { RegisteredOfferingBowls.RemoveAt(num); flag = true; } } if (!flag) { return; } RegisteredOfferingBowls.RemoveAll((OfferingBowl offeringBowl) => (Object)(object)offeringBowl == (Object)null); RegisteredOfferingBowlIds.Clear(); foreach (OfferingBowl registeredOfferingBowl in RegisteredOfferingBowls) { if ((Object)(object)registeredOfferingBowl != (Object)null) { RegisteredOfferingBowlIds.Add(((Object)registeredOfferingBowl).GetInstanceID()); } } } private static void CleanupExpiredHoverInfoCache(float now) { if (HoverInfoCacheByOfferingBowl.Count == 0) { return; } List list = null; int registryVersion = AltarItemStandHoverInfoFormatter.GetRegistryVersion(); foreach (var (item, hoverInfoCacheEntry2) in HoverInfoCacheByOfferingBowl) { if (hoverInfoCacheEntry2.RegistryVersion != registryVersion || !(hoverInfoCacheEntry2.ExpiresAt >= now)) { if (list == null) { list = new List(); } list.Add(item); } } if (list == null) { return; } foreach (int item2 in list) { HoverInfoCacheByOfferingBowl.Remove(item2); } } } internal static class AltarItemStandHoverInfoFormatter { private sealed class RelevantOfferingBowlCacheEntry { public int RegistryVersion { get; set; } public float ExpiresAt { get; set; } public OfferingBowl? OfferingBowl { get; set; } } private sealed class RelevantItemStandCacheEntry { public int RegistryVersion { get; set; } public float ExpiresAt { get; set; } public IReadOnlyList ItemStands { get; set; } = EmptyItemStands; public IReadOnlyList DisplayItemStands { get; set; } = EmptyItemStands; } private static readonly ItemStand[] EmptyItemStands = Array.Empty(); private static readonly Dictionary RelevantOfferingBowlCacheByItemStand = new Dictionary(); private static readonly Dictionary RelevantItemStandCacheByOfferingBowl = new Dictionary(); private static readonly List RegisteredItemStands = new List(); private static readonly HashSet RegisteredItemStandIds = new HashSet(); private const float RelevantItemStandCacheLifetimeSeconds = 1f; private const float RelevantOfferingBowlCacheLifetimeSeconds = 1f; private static int _itemStandRegistryVersion; internal static int GetRegistryVersion() { return _itemStandRegistryVersion; } internal static string AppendInfo(string baseText, ItemStand? itemStand) { if (!PluginSettingsFacade.ShouldShowLocationProxyOfferingBowlHoverInfo() || (Object)(object)itemStand == (Object)null) { return baseText ?? ""; } if (!TryGetRelevantOfferingBowl(itemStand, out OfferingBowl _)) { return baseText ?? ""; } string text = BuildInfo(itemStand); if (text.Length == 0) { return baseText ?? ""; } if (string.IsNullOrWhiteSpace(baseText)) { return text; } return baseText + "\n" + text; } internal static void RegisterItemStand(ItemStand? itemStand) { if (!((Object)(object)itemStand == (Object)null) && RegisteredItemStandIds.Add(((Object)itemStand).GetInstanceID())) { RegisteredItemStands.Add(itemStand); _itemStandRegistryVersion++; } } internal static IReadOnlyList FindRelevantItemStands(OfferingBowl offeringBowl) { if ((Object)(object)offeringBowl == (Object)null || !offeringBowl.m_useItemStands) { return EmptyItemStands; } CleanupRegisteredItemStands(); float unscaledTime = Time.unscaledTime; CleanupExpiredRelevantItemStandCache(unscaledTime); int instanceID = ((Object)offeringBowl).GetInstanceID(); if (RelevantItemStandCacheByOfferingBowl.TryGetValue(instanceID, out RelevantItemStandCacheEntry value) && value.RegistryVersion == _itemStandRegistryVersion && value.ExpiresAt >= unscaledTime) { return value.ItemStands; } EnsureItemStandRegistryPopulated(); List list = new List(); HashSet hashSet = new HashSet(); if (TryGetOfferingBowlStructuralRoot(offeringBowl, out Transform root) && (Object)(object)root != (Object)null) { AddRelevantItemStands(root, offeringBowl, list, hashSet); } foreach (ItemStand registeredItemStand in RegisteredItemStands) { if (!((Object)(object)registeredItemStand == (Object)null) && hashSet.Add(((Object)registeredItemStand).GetInstanceID()) && IsRelevantToOfferingBowl(registeredItemStand, offeringBowl)) { list.Add(registeredItemStand); } } IReadOnlyList displayItemStands = BuildDisplayRelevantItemStands(list); Dictionary relevantItemStandCacheByOfferingBowl = RelevantItemStandCacheByOfferingBowl; RelevantItemStandCacheEntry obj = new RelevantItemStandCacheEntry { RegistryVersion = _itemStandRegistryVersion, ExpiresAt = unscaledTime + 1f }; IReadOnlyList itemStands; if (list.Count != 0) { IReadOnlyList readOnlyList = list; itemStands = readOnlyList; } else { IReadOnlyList readOnlyList = EmptyItemStands; itemStands = readOnlyList; } obj.ItemStands = itemStands; obj.DisplayItemStands = displayItemStands; relevantItemStandCacheByOfferingBowl[instanceID] = obj; if (list.Count != 0) { return list; } return EmptyItemStands; } internal static IReadOnlyList GetDisplayRelevantItemStands(OfferingBowl offeringBowl) { if ((Object)(object)offeringBowl == (Object)null || !offeringBowl.m_useItemStands) { return EmptyItemStands; } CleanupRegisteredItemStands(); float unscaledTime = Time.unscaledTime; CleanupExpiredRelevantItemStandCache(unscaledTime); int instanceID = ((Object)offeringBowl).GetInstanceID(); if (RelevantItemStandCacheByOfferingBowl.TryGetValue(instanceID, out RelevantItemStandCacheEntry value) && value.RegistryVersion == _itemStandRegistryVersion && value.ExpiresAt >= unscaledTime) { return value.DisplayItemStands; } IReadOnlyList readOnlyList = FindRelevantItemStands(offeringBowl); if (readOnlyList.Count <= 1) { return readOnlyList; } if (RelevantItemStandCacheByOfferingBowl.TryGetValue(instanceID, out value) && value.RegistryVersion == _itemStandRegistryVersion && value.ExpiresAt >= unscaledTime) { return value.DisplayItemStands; } return BuildDisplayRelevantItemStands(readOnlyList); } private static IReadOnlyList BuildDisplayRelevantItemStands(IReadOnlyList relevantItemStands) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) if (relevantItemStands.Count <= 1) { if (relevantItemStands.Count != 0) { return relevantItemStands; } return EmptyItemStands; } Dictionary<(int, int, int), ItemStand> dictionary = new Dictionary<(int, int, int), ItemStand>(); foreach (ItemStand relevantItemStand in relevantItemStands) { if (!((Object)(object)relevantItemStand == (Object)null)) { Vector3 position = ((Component)relevantItemStand).transform.position; (int, int, int) key = ((int)MathF.Round(position.x * 20f), (int)MathF.Round(position.y * 20f), (int)MathF.Round(position.z * 20f)); if (!dictionary.TryGetValue(key, out var value) || CompareDisplayPriority(relevantItemStand, value) > 0) { dictionary[key] = relevantItemStand; } } } if (dictionary.Count != 0) { return dictionary.Values.ToList(); } return EmptyItemStands; } private static string BuildInfo(ItemStand itemStand) { if (itemStand.m_supportedItems == null || itemStand.m_supportedItems.Count == 0) { return ""; } List list = (from item in itemStand.m_supportedItems where (Object)(object)item != (Object)null select Localize(item.m_itemData.m_shared.m_name) into name where !string.IsNullOrWhiteSpace(name) select name).Distinct(StringComparer.Ordinal).ToList(); if (list.Count == 0) { return ""; } return string.Join(", ", list); } internal static bool TryGetRelevantOfferingBowl(ItemStand itemStand, out OfferingBowl? offeringBowl) { offeringBowl = null; float unscaledTime = Time.unscaledTime; CleanupExpiredRelevantOfferingBowlCache(unscaledTime); int instanceID = ((Object)itemStand).GetInstanceID(); if (RelevantOfferingBowlCacheByItemStand.TryGetValue(instanceID, out RelevantOfferingBowlCacheEntry value) && value.RegistryVersion == _itemStandRegistryVersion && value.ExpiresAt >= unscaledTime) { offeringBowl = value.OfferingBowl; return (Object)(object)offeringBowl != (Object)null; } Location componentInParent = ((Component)itemStand).GetComponentInParent(true); if ((Object)(object)componentInParent == (Object)null) { if (TryGetDetachedStructureRoot(((Component)itemStand).transform, out Transform root) && (Object)(object)root != (Object)null) { offeringBowl = FindNearestRelevantOfferingBowl(itemStand, ((Component)root).GetComponentsInChildren(true)); if ((Object)(object)offeringBowl != (Object)null) { return true; } } offeringBowl = FindNearestRelevantOfferingBowl(itemStand, OfferingBowlHoverInfoFormatter.GetKnownOfferingBowls()); CacheRelevantOfferingBowl(instanceID, offeringBowl, unscaledTime); return (Object)(object)offeringBowl != (Object)null; } offeringBowl = FindNearestRelevantOfferingBowl(itemStand, ((Component)componentInParent).GetComponentsInChildren(true)); CacheRelevantOfferingBowl(instanceID, offeringBowl, unscaledTime); return (Object)(object)offeringBowl != (Object)null; } internal static bool TryResolveOfferingBowlContext(OfferingBowl? offeringBowl, out string locationPrefab, out Transform root) { //IL_007c: Unknown result type (might be due to invalid IL or missing references) locationPrefab = ""; root = null; if ((Object)(object)offeringBowl == (Object)null) { return false; } root = ((Component)offeringBowl).transform; Location componentInParent = ((Component)offeringBowl).GetComponentInParent(true); if ((Object)(object)componentInParent != (Object)null) { root = ((Component)componentInParent).transform; } if (TryGetDetachedStructureRoot(((Component)offeringBowl).transform, out Transform root2) && (Object)(object)root2 != (Object)null) { root = (((Object)(object)componentInParent != (Object)null) ? ((Component)componentInParent).transform : root2); } if (LocationManager.TryResolveRuntimeLocationPrefabName(componentInParent, out locationPrefab)) { return locationPrefab.Length > 0; } if (LocationManager.TryResolveZoneLocationPrefabName(((Component)offeringBowl).transform.position, out locationPrefab)) { return true; } LocationProxy componentInParent2 = ((Component)offeringBowl).GetComponentInParent(true); if ((Object)(object)componentInParent2 != (Object)null && LocationManager.TryResolveLocationProxyPrefabName(componentInParent2, out locationPrefab)) { return locationPrefab.Length > 0; } return false; } internal static bool IsRelevantToOfferingBowl(ItemStand? itemStand, OfferingBowl? offeringBowl) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)itemStand == (Object)null || (Object)(object)offeringBowl == (Object)null || !offeringBowl.m_useItemStands) { return false; } if (Vector3.Distance(((Component)offeringBowl).transform.position, ((Component)itemStand).transform.position) > offeringBowl.m_itemstandMaxRange) { return false; } return Utils.CustomStartsWith(((Object)((Component)itemStand).gameObject).name, offeringBowl.m_itemStandPrefix); } private static void AddRelevantItemStands(Transform root, OfferingBowl offeringBowl, List itemStands, HashSet seenIds) { ItemStand[] componentsInChildren = ((Component)root).GetComponentsInChildren(true); foreach (ItemStand val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && seenIds.Add(((Object)val).GetInstanceID()) && IsRelevantToOfferingBowl(val, offeringBowl)) { itemStands.Add(val); } } } private static OfferingBowl? FindNearestRelevantOfferingBowl(ItemStand itemStand, IEnumerable candidates) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) OfferingBowl result = null; float num = float.MaxValue; foreach (OfferingBowl candidate in candidates) { if (!((Object)(object)candidate == (Object)null) && IsRelevantToOfferingBowl(itemStand, candidate)) { float num2 = Vector3.SqrMagnitude(((Component)candidate).transform.position - ((Component)itemStand).transform.position); if (!(num2 >= num)) { num = num2; result = candidate; } } } return result; } private static int CompareDisplayPriority(ItemStand candidate, ItemStand existing) { return GetDisplayPriority(candidate).CompareTo(GetDisplayPriority(existing)); } private static int GetDisplayPriority(ItemStand itemStand) { int num = 0; if (((Component)itemStand).gameObject.activeInHierarchy) { num += 4; } if ((Object)(object)((Component)itemStand).GetComponentInParent(true) == (Object)null) { num += 2; } return num + (itemStand.m_supportedItems?.Count ?? 0); } private static bool TryGetOfferingBowlStructuralRoot(OfferingBowl offeringBowl, out Transform? root) { Location componentInParent = ((Component)offeringBowl).GetComponentInParent(true); root = ((componentInParent != null) ? ((Component)componentInParent).transform : null); if ((Object)(object)root != (Object)null) { return true; } return TryGetDetachedStructureRoot(((Component)offeringBowl).transform, out root); } internal static bool TryGetDetachedStructureRoot(Transform transform, out Transform? root) { if ((Object)(object)transform == (Object)null) { root = null; return false; } Transform val = transform; while ((Object)(object)val.parent != (Object)null) { Transform parent = val.parent; if ((Object)(object)((Component)parent).GetComponent() != (Object)null || (Object)(object)((Component)parent).GetComponent() != (Object)null || string.Equals(((Object)parent).name, "_ZoneCtrl(Clone)", StringComparison.Ordinal)) { break; } val = parent; } root = val; return (Object)(object)root != (Object)null; } private static string TrimCloneSuffix(string? name) { string text = (name ?? "").Trim(); if (text.EndsWith("(Clone)", StringComparison.Ordinal)) { text = text.Substring(0, text.Length - "(Clone)".Length).TrimEnd(); } return text; } private static string Localize(string text) { string text2; if (Localization.instance == null) { text2 = text; if (text2 == null) { return ""; } } else { text2 = Localization.instance.Localize(text ?? ""); } return text2; } private static void EnsureItemStandRegistryPopulated() { if (RegisteredItemStands.Count <= 0) { ItemStand[] array = Object.FindObjectsByType((FindObjectsSortMode)0); for (int i = 0; i < array.Length; i++) { RegisterItemStand(array[i]); } } } private static void CleanupRegisteredItemStands() { bool flag = false; for (int num = RegisteredItemStands.Count - 1; num >= 0; num--) { if (!((Object)(object)RegisteredItemStands[num] != (Object)null)) { RegisteredItemStands.RemoveAt(num); flag = true; } } if (!flag) { return; } RegisteredItemStandIds.Clear(); foreach (ItemStand registeredItemStand in RegisteredItemStands) { if ((Object)(object)registeredItemStand != (Object)null) { RegisteredItemStandIds.Add(((Object)registeredItemStand).GetInstanceID()); } } _itemStandRegistryVersion++; } private static void CacheRelevantOfferingBowl(int itemStandId, OfferingBowl? offeringBowl, float now) { RelevantOfferingBowlCacheByItemStand[itemStandId] = new RelevantOfferingBowlCacheEntry { RegistryVersion = _itemStandRegistryVersion, ExpiresAt = now + 1f, OfferingBowl = offeringBowl }; } private static void CleanupExpiredRelevantOfferingBowlCache(float now) { if (RelevantOfferingBowlCacheByItemStand.Count == 0) { return; } List list = null; foreach (var (item, relevantOfferingBowlCacheEntry2) in RelevantOfferingBowlCacheByItemStand) { if (relevantOfferingBowlCacheEntry2.RegistryVersion != _itemStandRegistryVersion || !(relevantOfferingBowlCacheEntry2.ExpiresAt >= now)) { if (list == null) { list = new List(); } list.Add(item); } } if (list == null) { return; } foreach (int item2 in list) { RelevantOfferingBowlCacheByItemStand.Remove(item2); } } private static void CleanupExpiredRelevantItemStandCache(float now) { if (RelevantItemStandCacheByOfferingBowl.Count == 0) { return; } List list = null; foreach (var (item, relevantItemStandCacheEntry2) in RelevantItemStandCacheByOfferingBowl) { if (!(relevantItemStandCacheEntry2.ExpiresAt >= now)) { if (list == null) { list = new List(); } list.Add(item); } } if (list == null) { return; } foreach (int item2 in list) { RelevantItemStandCacheByOfferingBowl.Remove(item2); } } } [HarmonyPatch(typeof(ZNetScene), "Awake")] internal static class ZNetSceneAwakePatch { private static void Postfix() { BossRulesManager.ClearRuntimeState(); DespawnRulesManager.MarkBootstrapScanDirty("ZNetScene.Awake"); DropNSpawnPlugin.QueueGameDataRefresh(DropNSpawnPlugin.ReloadDomain.All, "ZNetScene.Awake"); } } [HarmonyPatch(typeof(ObjectDB), "Awake")] internal static class ObjectDBAwakePatch { private static void Postfix() { DropNSpawnPlugin.QueueGameDataRefresh(DropNSpawnPlugin.ReloadDomain.All, "ObjectDB.Awake"); } } [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] internal static class ObjectDBCopyOtherDBPatch { private static void Postfix() { DropNSpawnPlugin.QueueGameDataRefresh(DropNSpawnPlugin.ReloadDomain.All, "ObjectDB.CopyOtherDB"); } } [HarmonyPatch(typeof(ZoneSystem), "Awake")] internal static class ZoneSystemAwakePatch { private static void Postfix() { DropNSpawnPlugin.QueueGameDataRefresh(DropNSpawnPlugin.ReloadDomain.Location, "ZoneSystem.Awake"); } } [HarmonyPatch(typeof(ZoneSystem), "Start")] internal static class ZoneSystemStartPatch { private static void Postfix() { DropNSpawnPlugin.QueueGameDataRefresh(DropNSpawnPlugin.ReloadDomain.Location | DropNSpawnPlugin.ReloadDomain.SpawnSystem, "ZoneSystem.Start"); } } [HarmonyPatch(typeof(Location), "Awake")] internal static class LocationAwakePatch { private static void Postfix(Location __instance) { LocationManager.TrackLocationInstance(__instance); if (PluginSettingsFacade.IsLocationDomainEnabled() && !DropNSpawnPlugin.IsGameDataRefreshDeferred(DropNSpawnPlugin.ReloadDomain.Location)) { LocationManager.QueueLocationReconcile(__instance); } } } [HarmonyPatch(typeof(Location), "OnDestroy")] internal static class LocationOnDestroyPatch { private static void Prefix(Location __instance) { SpawnerManager.UntrackLocationInstanceProvenance(__instance); LocationManager.UntrackLocationInstance(__instance); } } [HarmonyPatch(typeof(LocationProxy), "SpawnLocation")] internal static class LocationProxySpawnLocationPatch { private static readonly FieldRef InstanceRef = AccessTools.FieldRefAccess("m_instance"); private static readonly Dictionary SpawnCountsByProxy = new Dictionary(); private static void Postfix(LocationProxy __instance, bool __result) { //IL_0068: Unknown result type (might be due to invalid IL or missing references) if (!__result) { return; } int num = 1; if (PluginSettingsFacade.IsOfferingBowlDiagnosticsEnabled() && (Object)(object)__instance != (Object)null) { int instanceID = ((Object)__instance).GetInstanceID(); if (SpawnCountsByProxy.TryGetValue(instanceID, out var value)) { num = value + 1; } SpawnCountsByProxy[instanceID] = num; } if ((Object)(object)__instance != (Object)null && (Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && LocationManager.TryResolveZoneLocationPrefabName(((Component)__instance).transform.position, out string prefabName) && prefabName.Length > 0) { LocationManager.RecordLocationProxyResolvedPrefab(__instance, prefabName); } bool flag = PluginSettingsFacade.IsLocationDomainEnabled() && !DropNSpawnPlugin.IsGameDataRefreshDeferred(DropNSpawnPlugin.ReloadDomain.Location); bool flag2 = PluginSettingsFacade.IsSpawnerDomainEnabled() && !DropNSpawnPlugin.IsGameDataRefreshDeferred(DropNSpawnPlugin.ReloadDomain.Spawner); if (!flag && !flag2) { return; } GameObject val = (((Object)(object)__instance != (Object)null) ? InstanceRef.Invoke(__instance) : null); if (PluginSettingsFacade.IsOfferingBowlDiagnosticsEnabled()) { LocationManager.LogLocationProxySpawnDiagnostics(__instance, val, num, __result); } if (flag2) { SpawnerManager.RecordSpawnedLocationProxyProvenance(__instance, val); } if (flag) { LocationManager.QueueSpawnedLocationRootReconcile(val); if (LocationManager.HasRuntimeLocationAliasDemand()) { LocationManager.QueueLocationProxyObservation(__instance); } } } } [HarmonyPatch(typeof(LocationProxy), "SetLocation")] [HarmonyPriority(800)] internal static class LocationProxySetLocationAliasPatch { private static void Prefix(string location, ref string __state) { if (!LocationManager.TryGetPendingLocationProxyCreationPrefabName(out __state)) { __state = (location ?? "").Trim(); } } private static void Postfix(LocationProxy __instance, string __state) { if (__state.Length > 0) { LocationManager.RecordLocationProxyResolvedPrefab(__instance, __state); } if (PluginSettingsFacade.IsLocationDomainEnabled() && !DropNSpawnPlugin.IsGameDataRefreshDeferred(DropNSpawnPlugin.ReloadDomain.Location) && LocationManager.HasRuntimeLocationAliasDemand()) { LocationManager.QueueLocationProxyObservation(__instance); } } } [HarmonyPatch(typeof(LocationProxy), "OnDestroy")] internal static class LocationProxyOnDestroyPatch { private static void Prefix(LocationProxy __instance) { LocationManager.UntrackLocationProxy(__instance); } } [HarmonyPatch(typeof(ZoneSystem), "CreateLocationProxy")] [HarmonyPriority(800)] internal static class ZoneSystemCreateLocationProxyAliasContextPatch { private static void Prefix(ZoneLocation location, ref bool __state) { __state = false; string text = (location?.m_prefabName ?? location?.m_prefab.Name ?? "").Trim(); if (text.Length != 0) { LocationManager.BeginLocationProxyCreationContext(text); __state = true; } } private static void Finalizer(bool __state) { if (__state) { LocationManager.EndLocationProxyCreationContext(); } } } [HarmonyPatch(typeof(ZoneSystem), "SpawnLocation", new Type[] { typeof(ZoneLocation), typeof(int), typeof(Vector3), typeof(Quaternion), typeof(SpawnMode), typeof(List) })] internal static class ZoneSystemSpawnLocationContextPatch { private static void Prefix(ZoneLocation location, ref bool __state) { __state = false; if (PluginSettingsFacade.IsSpawnerDomainEnabled() && !DropNSpawnPlugin.IsGameDataRefreshDeferred(DropNSpawnPlugin.ReloadDomain.Spawner)) { SpawnerManager.BeginLocationSpawnContext(location); __state = true; } } private static void Finalizer(bool __state) { if (__state) { SpawnerManager.EndLocationSpawnContext(); } } } [HarmonyPatch(typeof(DungeonGenerator), "Generate", new Type[] { typeof(SpawnMode) })] internal static class DungeonGeneratorGenerateContextPatch { private static void Prefix(DungeonGenerator __instance, ref bool __state) { __state = false; if (PluginSettingsFacade.IsSpawnerDomainEnabled() && !DropNSpawnPlugin.IsGameDataRefreshDeferred(DropNSpawnPlugin.ReloadDomain.Spawner)) { __state = SpawnerManager.TryBeginDerivedLocationSpawnContext((Component?)(object)__instance); } } private static void Finalizer(bool __state) { if (__state) { SpawnerManager.EndLocationSpawnContext(); } } } [HarmonyPatch(typeof(DungeonGenerator), "Spawn")] internal static class DungeonGeneratorSpawnContextPatch { private static void Prefix(DungeonGenerator __instance, ref bool __state) { __state = false; if (PluginSettingsFacade.IsSpawnerDomainEnabled() && !DropNSpawnPlugin.IsGameDataRefreshDeferred(DropNSpawnPlugin.ReloadDomain.Spawner)) { __state = SpawnerManager.TryBeginDerivedLocationSpawnContext((Component?)(object)__instance); } } private static void Finalizer(bool __state) { if (__state) { SpawnerManager.EndLocationSpawnContext(); } } } [HarmonyPatch(typeof(OfferingBowl), "GetHoverText")] internal static class OfferingBowlGetHoverTextPatch { private static void Postfix(OfferingBowl __instance, ref string __result) { if (PluginSettingsFacade.IsLocationDomainEnabled() && !DropNSpawnPlugin.IsGameDataRefreshDeferred(DropNSpawnPlugin.ReloadDomain.Location) && (Object)(object)((Component)__instance).GetComponentInParent() == (Object)null) { LocationManager.QueueLooseOfferingBowlOverride(__instance); } __result = OfferingBowlHoverInfoFormatter.AppendInfo(__result, __instance); } } [HarmonyPatch(typeof(OfferingBowl), "Awake")] internal static class OfferingBowlAwakeRegistryPatch { private static void Postfix(OfferingBowl __instance) { OfferingBowlHoverInfoFormatter.RegisterOfferingBowl(__instance); LocationManager.LogOfferingBowlDiagnostics(__instance, "awake"); if (PluginSettingsFacade.IsLocationDomainEnabled() && !DropNSpawnPlugin.IsGameDataRefreshDeferred(DropNSpawnPlugin.ReloadDomain.Location) && (Object)(object)((Component)__instance).GetComponentInParent(true) == (Object)null) { LocationManager.QueueLooseOfferingBowlOverride(__instance); } } } [HarmonyPatch(typeof(OfferingBowl), "Start")] internal static class OfferingBowlStartDiagnosticsPatch { private static readonly Dictionary StartCountsByOfferingBowl = new Dictionary(); private static void Prefix(OfferingBowl __instance) { if (PluginSettingsFacade.IsOfferingBowlDiagnosticsEnabled() && !((Object)(object)__instance == (Object)null)) { int instanceID = ((Object)__instance).GetInstanceID(); int value = 1; if (StartCountsByOfferingBowl.TryGetValue(instanceID, out var value2)) { value = value2 + 1; } StartCountsByOfferingBowl[instanceID] = value; LocationManager.LogOfferingBowlDiagnostics(__instance, "start#" + value.ToString(CultureInfo.InvariantCulture)); } } } [HarmonyPatch(typeof(OfferingBowl), "Interact")] internal static class OfferingBowlInteractRespawnPatch { private static bool Prefix(OfferingBowl __instance, Humanoid user, bool hold, bool alt, ref bool __result) { if (!PluginSettingsFacade.IsLocationDomainEnabled()) { return true; } if (hold || !__instance.m_useItemStands) { return true; } if ((Object)(object)((Component)__instance).GetComponentInParent() == (Object)null) { LocationManager.EnsureLooseOfferingBowlOverride(__instance); } else if (LocationManager.HasRuntimeLocationAliasDemand()) { LocationManager.MaybeQueueRuntimeLocationAliasRefresh((Component?)(object)__instance); } LocationManager.OfferingBowlBlockResult result = LocationManager.EvaluateOfferingBowlBlock(__instance); if (!result.Blocked) { return true; } __result = true; LocationManager.NotifyOfferingBowlBlocked(__instance, user, result); return false; } } [HarmonyPatch(typeof(OfferingBowl), "UseItem")] internal static class OfferingBowlUseItemRespawnPatch { private static bool Prefix(OfferingBowl __instance, Humanoid user, ItemData item, ref bool __result, ref int __state) { __state = -1; if (!PluginSettingsFacade.IsLocationDomainEnabled()) { return true; } if (__instance.m_useItemStands) { return true; } if (PluginSettingsFacade.IsOfferingBowlDiagnosticsEnabled() && (Object)(object)user != (Object)null && item != null && !string.IsNullOrEmpty(item.m_shared?.m_name)) { string name = item.m_shared.m_name; __state = user.GetInventory().CountItems(name, -1, true); } if (LocationManager.HasRuntimeLocationAliasDemand()) { LocationManager.MaybeQueueRuntimeLocationAliasRefresh((Component?)(object)__instance); } LocationManager.OfferingBowlBlockResult result = LocationManager.EvaluateOfferingBowlBlock(__instance); if (!result.Blocked) { return true; } __result = true; LocationManager.NotifyOfferingBowlBlocked(__instance, user, result); return false; } private static void Postfix(OfferingBowl __instance, Humanoid user, ItemData item, bool __result, int __state) { if (PluginSettingsFacade.IsOfferingBowlDiagnosticsEnabled() && !((Object)(object)__instance == (Object)null) && !__instance.m_useItemStands && !((Object)(object)user == (Object)null) && item != null && !string.IsNullOrEmpty(item.m_shared?.m_name)) { string name = item.m_shared.m_name; int countAfter = user.GetInventory().CountItems(name, -1, true); LocationManager.LogOfferingBowlItemFlowDiagnostics(__instance, user, item, "UseItem", __state, countAfter, __result); } } } [HarmonyPatch(typeof(OfferingBowl), "SpawnBoss")] internal static class OfferingBowlSpawnBossRespawnPatch { private static readonly FieldRef BossSpawnPointRef = AccessTools.FieldRefAccess("m_bossSpawnPoint"); private static void Postfix(OfferingBowl __instance) { if (PluginSettingsFacade.IsLocationDomainEnabled()) { LocationManager.MarkOfferingBowlUsed(__instance); } } } [HarmonyPatch(typeof(OfferingBowl), "RPC_SpawnBoss")] internal static class OfferingBowlRpcSpawnBossServerValidationPatch { private static bool Prefix(OfferingBowl __instance) { if (!DropNSpawnPlugin.IsRuntimeServer() || !PluginSettingsFacade.IsLocationDomainEnabled()) { return true; } return !LocationManager.EvaluateOfferingBowlBlock(__instance).Blocked; } } [HarmonyPatch(typeof(OfferingBowl), "DelayedSpawnBoss")] internal static class OfferingBowlDelayedSpawnBossCllcPatch { private static readonly FieldRef BossSpawnPointRef = AccessTools.FieldRefAccess("m_bossSpawnPoint"); private static void Prefix(OfferingBowl __instance) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) if (DropNSpawnPlugin.IsRuntimeServer() && PluginSettingsFacade.IsLocationDomainEnabled()) { LocationManager.BeginOfferingBowlBossSpawnAttempt(__instance, BossSpawnPointRef.Invoke(__instance)); } } private static void Postfix(OfferingBowl __instance) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) if (DropNSpawnPlugin.IsRuntimeServer() && PluginSettingsFacade.IsLocationDomainEnabled()) { LocationManager.FinalizeOfferingBowlBossSpawnAttempt(__instance, BossSpawnPointRef.Invoke(__instance)); } } } [HarmonyPatch(typeof(OfferingBowl), "SpawnItem")] internal static class OfferingBowlSpawnItemRespawnPatch { private static void Postfix(OfferingBowl __instance, bool __result) { if (PluginSettingsFacade.IsLocationDomainEnabled() && __result) { LocationManager.MarkOfferingBowlUsed(__instance); } } } [HarmonyPatch(typeof(OfferingBowl), "RPC_BossSpawnInitiated")] internal static class OfferingBowlBossSpawnInitiatedRpcPatch { private static readonly FieldRef InteractUserRef = AccessTools.FieldRefAccess("m_interactUser"); internal static Humanoid? ResolveInteractUser(OfferingBowl offeringBowl) { Humanoid val = InteractUserRef.Invoke(offeringBowl); if ((Object)(object)val != (Object)null) { return val; } if ((Object)(object)Player.m_localPlayer == (Object)null) { return null; } InteractUserRef.Invoke(offeringBowl) = (Humanoid)(object)Player.m_localPlayer; return (Humanoid?)(object)Player.m_localPlayer; } private static bool Prefix(OfferingBowl __instance) { Humanoid val = ResolveInteractUser(__instance); if ((Object)(object)val == (Object)null) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("OfferingBowl '" + ((Object)((Component)__instance).gameObject).name + "' received RPC_BossSpawnInitiated without an interact user.")); return false; } ((Character)val).Message((MessageType)2, __instance.m_usedAltarText, 0, (Sprite)null); return false; } } [HarmonyPatch(typeof(OfferingBowl), "RPC_RemoveBossSpawnInventoryItems")] internal static class OfferingBowlRemoveBossSpawnInventoryItemsRpcPatch { private static readonly FieldRef UsedSpawnItemRef = AccessTools.FieldRefAccess("m_usedSpawnItem"); private static bool Prefix(OfferingBowl __instance) { //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) Humanoid val = OfferingBowlBossSpawnInitiatedRpcPatch.ResolveInteractUser(__instance); if ((Object)(object)val == (Object)null) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("OfferingBowl '" + ((Object)((Component)__instance).gameObject).name + "' received RPC_RemoveBossSpawnInventoryItems without an interact user.")); return false; } ItemData val2 = UsedSpawnItemRef.Invoke(__instance) ?? __instance.m_bossItem?.m_itemData; string text = val2?.m_shared?.m_name; int countBefore = -1; if (!string.IsNullOrEmpty(text)) { countBefore = val.GetInventory().CountItems(text, -1, true); val.GetInventory().RemoveItem(text, __instance.m_bossItems, -1, true); } int countAfter = ((!string.IsNullOrEmpty(text)) ? val.GetInventory().CountItems(text, -1, true) : (-1)); if (PluginSettingsFacade.IsOfferingBowlDiagnosticsEnabled()) { LocationManager.LogOfferingBowlItemFlowDiagnostics(__instance, val, val2, "RPC_RemoveBossSpawnInventoryItems", countBefore, countAfter); } if (val2 != null) { ((Character)val).ShowRemovedMessage(val2, __instance.m_bossItems); } ((Character)val).Message((MessageType)2, __instance.m_usedAltarText, 0, (Sprite)null); if (Object.op_Implicit((Object)(object)__instance.m_itemSpawnPoint)) { __instance.m_fuelAddedEffects.Create(__instance.m_itemSpawnPoint.position, ((Component)__instance).transform.rotation, (Transform)null, 1f, -1); } return false; } } [HarmonyPatch(typeof(ItemStand), "GetHoverText")] internal static class ItemStandGetHoverTextPatch { private static void Postfix(ItemStand __instance, ref string __result) { if (PluginSettingsFacade.IsLocationDomainEnabled() && !DropNSpawnPlugin.IsGameDataRefreshDeferred(DropNSpawnPlugin.ReloadDomain.Location) && (Object)(object)((Component)__instance).GetComponentInParent() == (Object)null) { LocationManager.QueueLooseItemStandOverride(__instance); } __result = AltarItemStandHoverInfoFormatter.AppendInfo(__result, __instance); } } [HarmonyPatch(typeof(ItemStand), "Interact")] internal static class ItemStandInteractLocationOverridePatch { private static void Prefix(ItemStand __instance) { if (!PluginSettingsFacade.IsLocationDomainEnabled() || DropNSpawnPlugin.IsGameDataRefreshDeferred(DropNSpawnPlugin.ReloadDomain.Location)) { return; } if ((Object)(object)((Component)__instance).GetComponentInParent() != (Object)null) { if (LocationManager.HasRuntimeLocationAliasDemand()) { LocationManager.MaybeQueueRuntimeLocationAliasRefresh((Component?)(object)__instance); } } else { LocationManager.EnsureLooseItemStandOverride(__instance); } } } [HarmonyPatch(typeof(ItemStand), "UseItem")] internal static class ItemStandUseItemLocationOverridePatch { private static void Prefix(ItemStand __instance) { if (!PluginSettingsFacade.IsLocationDomainEnabled() || DropNSpawnPlugin.IsGameDataRefreshDeferred(DropNSpawnPlugin.ReloadDomain.Location)) { return; } if ((Object)(object)((Component)__instance).GetComponentInParent() != (Object)null) { if (LocationManager.HasRuntimeLocationAliasDemand()) { LocationManager.MaybeQueueRuntimeLocationAliasRefresh((Component?)(object)__instance); } } else { LocationManager.EnsureLooseItemStandOverride(__instance); } } } [HarmonyPatch(typeof(ItemStand), "UseItem")] internal static class ItemStandUseItemBossStonePerPlayerPatch { private static bool Prefix(ItemStand __instance, Humanoid user, ItemData item, ref bool __result) { if (BossStonePerPlayerRuntime.TryHandleUseItem(__instance, user, item, out var result)) { __result = result; return false; } return true; } } [HarmonyPatch(typeof(ItemStand), "HaveAttachment")] internal static class ItemStandHaveAttachmentBossStonePerPlayerPatch { private static bool Prefix(ItemStand __instance, ref bool __result) { if (BossStonePerPlayerRuntime.TryOverrideHaveAttachment(__instance, out var result)) { __result = result; return false; } return true; } } [HarmonyPatch(typeof(ItemStand), "UpdateVisual")] internal static class ItemStandUpdateVisualBossStonePerPlayerPatch { private static bool Prefix(ItemStand __instance) { return !BossStonePerPlayerRuntime.TryOverrideUpdateVisual(__instance); } } [HarmonyPatch(typeof(Player), "Update")] internal static class PlayerUpdateForsakenPowerSelectionPatch { private static void Postfix(Player __instance) { ForsakenPowerSelectionRuntime.TryRotateSelection(__instance); } } [HarmonyPatch(typeof(Hud), "UpdateGuardianPower")] internal static class HudUpdateGuardianPowerForsakenPowerSelectionPatch { private static void Postfix(Player player) { ForsakenPowerSelectionRuntime.UpdateHudHint(Hud.instance, player); } } [HarmonyPatch(typeof(ItemStand), "Awake")] internal static class ItemStandAwakeLocationOverridePatch { private static void Postfix(ItemStand __instance) { AltarItemStandHoverInfoFormatter.RegisterItemStand(__instance); if (PluginSettingsFacade.IsLocationDomainEnabled() && !DropNSpawnPlugin.IsGameDataRefreshDeferred(DropNSpawnPlugin.ReloadDomain.Location) && (Object)(object)((Component)__instance).GetComponentInParent(true) == (Object)null) { LocationManager.QueueLooseItemStandOverride(__instance); } } } [HarmonyPatch(typeof(Piece), "Awake")] internal static class PieceAwakePatch { private static void Postfix(Piece __instance) { ObjectDropManager.QueueObjectInstanceReconcile(((Component)__instance).gameObject, clearCreatorRestrictedContainerContents: false, ObjectDropManager.LiveObjectComponentKind.Piece); } } [HarmonyPatch(typeof(Piece), "SetCreator")] internal static class PieceSetCreatorPatch { private static void Postfix(Piece __instance) { if (PluginSettingsFacade.IsObjectDomainEnabled()) { ObjectDropManager.ReconcilePieceInstance(__instance, __instance.GetCreator() != 0); } } } [HarmonyPatch(typeof(Piece), "OnDestroy")] internal static class PieceOnDestroyPatch { private static void Prefix(Piece __instance) { ObjectDropManager.UntrackObjectInstance(((Component)__instance).gameObject); } } [HarmonyPatch(typeof(ZNetView), "OnDestroy")] internal static class ZNetViewOnDestroyPatch { private static void Prefix(ZNetView __instance) { ObjectDropManager.UntrackObjectInstance(((Component)__instance).gameObject); SpawnArea component = ((Component)__instance).GetComponent(); if ((Object)(object)component != (Object)null) { SpawnerManager.UntrackSpawnAreaInstance(component); } } } [HarmonyPatch(typeof(Destructible), "Awake")] internal static class DestructibleAwakePatch { private static void Postfix(Destructible __instance) { ObjectDropManager.QueueObjectInstanceReconcile(((Component)__instance).gameObject, clearCreatorRestrictedContainerContents: false, ObjectDropManager.LiveObjectComponentKind.Destructible); } } [HarmonyPatch(typeof(Destructible), "GetDestructibleType")] internal static class DestructibleGetDestructibleTypePatch { private static void Prefix(Destructible __instance) { if (PluginSettingsFacade.IsObjectDomainEnabled()) { ObjectDropManager.ApplyLazyDestructibleTypeIfNeeded(__instance); } } } [HarmonyPatch(typeof(Destructible), "RPC_Damage")] internal static class DestructibleDamagePatch { private static void Prefix(Destructible __instance) { if (PluginSettingsFacade.IsObjectDomainEnabled()) { ObjectDropManager.ApplyLazyDestructibleScalarsIfNeeded(__instance); } } } [HarmonyPatch(typeof(Destructible), "Destroy")] internal static class DestructibleDestroyPatch { private static void Prefix(Destructible __instance, out GameObject? __state) { if (!PluginSettingsFacade.IsObjectDomainEnabled()) { __state = null; } else { __state = ObjectDropManager.OverrideConditionalDestructibleSpawnWhenDestroyed(__instance); } } private static void Postfix(Destructible __instance, GameObject? __state) { if ((Object)(object)__state != (Object)null) { __instance.m_spawnWhenDestroyed = __state; } } } [HarmonyPatch(typeof(DropOnDestroyed), "Awake")] internal static class DropOnDestroyedAwakePatch { private static void Postfix(DropOnDestroyed __instance) { ObjectDropManager.QueueObjectInstanceReconcile(((Component)__instance).gameObject, clearCreatorRestrictedContainerContents: false, ObjectDropManager.LiveObjectComponentKind.DropOnDestroyed); } } [HarmonyPatch(typeof(Container), "Awake")] internal static class ContainerAwakePatch { private static void Postfix(Container __instance) { ObjectDropManager.QueueObjectInstanceReconcile(((Component)__instance).gameObject, clearCreatorRestrictedContainerContents: false, ObjectDropManager.LiveObjectComponentKind.Container); } } [HarmonyPatch(typeof(Pickable), "Awake")] internal static class PickableAwakePatch { private static void Postfix(Pickable __instance) { if (!PluginSettingsFacade.IsObjectDomainEnabled()) { ObjectDropManager.TrackObjectInstance(((Component)__instance).gameObject); } else { ObjectDropManager.QueueObjectInstanceReconcile(((Component)__instance).gameObject, clearCreatorRestrictedContainerContents: false, ObjectDropManager.LiveObjectComponentKind.Pickable); } } } [HarmonyPatch(typeof(PickableItem), "Awake")] internal static class PickableItemAwakePatch { private static void Postfix(PickableItem __instance) { if (!PluginSettingsFacade.IsObjectDomainEnabled()) { ObjectDropManager.TrackObjectInstance(((Component)__instance).gameObject); } else { ObjectDropManager.QueueObjectInstanceReconcile(((Component)__instance).gameObject, clearCreatorRestrictedContainerContents: false, ObjectDropManager.LiveObjectComponentKind.PickableItem); } } } [HarmonyPatch(typeof(Fish), "Awake")] internal static class FishAwakePatch { private static void Postfix(Fish __instance) { ObjectDropManager.QueueObjectInstanceReconcile(((Component)__instance).gameObject, clearCreatorRestrictedContainerContents: false, ObjectDropManager.LiveObjectComponentKind.Fish); } } [HarmonyPatch(typeof(Container), "AddDefaultItems")] internal static class ContainerAddDefaultItemsPatch { private static void Prefix(Container __instance, out DropTable? __state) { if (!PluginSettingsFacade.IsObjectDomainEnabled()) { __state = null; } else { __state = ObjectDropManager.OverrideContainerDrops(__instance); } } private static void Postfix(Container __instance, DropTable? __state) { if (__state != null) { __instance.m_defaultItems = __state; } } } [HarmonyPatch(typeof(DropOnDestroyed), "OnDestroyed")] internal static class DropOnDestroyedPatch { private static void Prefix(DropOnDestroyed __instance, out DropTable? __state) { if (!PluginSettingsFacade.IsObjectDomainEnabled()) { __state = null; } else { __state = ObjectDropManager.OverrideConditionalDropOnDestroyed(__instance); } } private static void Postfix(DropOnDestroyed __instance, DropTable? __state) { if (__state != null) { __instance.m_dropWhenDestroyed = __state; } } } [HarmonyPatch(typeof(MineRock), "RPC_Hit")] internal static class MineRockHitPatch { private static void Prefix(MineRock __instance, out DropTable? __state) { if (!PluginSettingsFacade.IsObjectDomainEnabled()) { __state = null; return; } ObjectDropManager.ApplyLazyMineRockScalarsIfNeeded(__instance); __state = ObjectDropManager.OverrideConditionalMineRockDrops(__instance); } private static void Postfix(MineRock __instance, DropTable? __state) { if (__state != null) { __instance.m_dropItems = __state; } } } [HarmonyPatch(typeof(MineRock), "Start")] internal static class MineRockStartPatch { private static void Postfix(MineRock __instance) { ObjectDropManager.QueueObjectInstanceReconcile(((Component)__instance).gameObject, clearCreatorRestrictedContainerContents: false, ObjectDropManager.LiveObjectComponentKind.MineRock); } } [HarmonyPatch(typeof(MineRock5), "RPC_Damage")] internal static class MineRock5DamagePatch { private static void Prefix(MineRock5 __instance, out DropTable? __state) { if (!PluginSettingsFacade.IsObjectDomainEnabled()) { __state = null; return; } ObjectDropManager.ApplyLazyMineRock5ScalarsIfNeeded(__instance); __state = ObjectDropManager.OverrideConditionalMineRock5Drops(__instance); } private static void Postfix(MineRock5 __instance, DropTable? __state) { if (__state != null) { __instance.m_dropItems = __state; } } } [HarmonyPatch(typeof(MineRock5), "Awake")] internal static class MineRock5AwakePatch { private static void Postfix(MineRock5 __instance) { ObjectDropManager.QueueObjectInstanceReconcile(((Component)__instance).gameObject, clearCreatorRestrictedContainerContents: false, ObjectDropManager.LiveObjectComponentKind.MineRock5); } } [HarmonyPatch(typeof(TreeBase), "RPC_Damage")] internal static class TreeBaseDamagePatch { private static void Prefix(TreeBase __instance, out DropTable? __state) { if (!PluginSettingsFacade.IsObjectDomainEnabled()) { __state = null; return; } ObjectDropManager.ApplyLazyTreeBaseScalarsIfNeeded(__instance); __state = ObjectDropManager.OverrideConditionalTreeBaseDrops(__instance); } private static void Postfix(TreeBase __instance, DropTable? __state) { if (__state != null) { __instance.m_dropWhenDestroyed = __state; } } } [HarmonyPatch(typeof(TreeBase), "Awake")] internal static class TreeBaseAwakePatch { private static void Postfix(TreeBase __instance) { ObjectDropManager.QueueObjectInstanceReconcile(((Component)__instance).gameObject, clearCreatorRestrictedContainerContents: false, ObjectDropManager.LiveObjectComponentKind.TreeBase); } } [HarmonyPatch(typeof(TreeLog), "Destroy")] internal static class TreeLogDestroyPatch { private static void Prefix(TreeLog __instance, out DropTable? __state) { if (!PluginSettingsFacade.IsObjectDomainEnabled()) { __state = null; } else { __state = ObjectDropManager.OverrideConditionalTreeLogDrops(__instance); } } private static void Postfix(TreeLog __instance, DropTable? __state) { if (__state != null) { __instance.m_dropWhenDestroyed = __state; } } } [HarmonyPatch(typeof(TreeLog), "RPC_Damage")] internal static class TreeLogDamagePatch { private static void Prefix(TreeLog __instance) { if (PluginSettingsFacade.IsObjectDomainEnabled()) { ObjectDropManager.ApplyLazyTreeLogScalarsIfNeeded(__instance); } } } [HarmonyPatch(typeof(TreeLog), "Awake")] internal static class TreeLogAwakePatch { private static void Postfix(TreeLog __instance) { ObjectDropManager.QueueObjectInstanceReconcile(((Component)__instance).gameObject, clearCreatorRestrictedContainerContents: false, ObjectDropManager.LiveObjectComponentKind.TreeLog); } } [HarmonyPatch(typeof(CharacterDrop), "GenerateDropList")] internal static class CharacterDropGenerateDropListPatch { private readonly struct State { internal List? PreviousDrops { get; } internal bool HasOnePerPlayerScope { get; } internal State(List? previousDrops, bool hasOnePerPlayerScope) { PreviousDrops = previousDrops; HasOnePerPlayerScope = hasOnePerPlayerScope; } } private static void Prefix(CharacterDrop __instance, out State __state) { if (!PluginSettingsFacade.IsCharacterDomainEnabled()) { __state = new State(null, hasOnePerPlayerScope: false); } else { __state = new State(CharacterDropManager.OverrideConditionalDrops(__instance), CharacterDropManager.BeginOnePerPlayerNearbyPlayerScope(__instance)); } } private static void Postfix(CharacterDrop __instance, State __state) { if (__state.PreviousDrops != null) { __instance.m_drops = __state.PreviousDrops; } } private static Exception? Finalizer(State __state, Exception? __exception) { if (__state.HasOnePerPlayerScope) { CharacterDropManager.EndOnePerPlayerNearbyPlayerScope(); } return __exception; } } [HarmonyPatch(typeof(Character), "RPC_Damage")] internal static class CharacterRpcDamageBossTamedPressurePatch { private static void Prefix(Character __instance, HitData hit) { BossTamedPressureRuntime.ApplyDamageMultipliers(__instance, hit); } } [HarmonyPatch(typeof(ZNet), "GetNrOfPlayers")] internal static class ZNetGetNrOfPlayersPatch { private static bool Prefix(ref int __result) { if (!PluginSettingsFacade.IsCharacterDomainEnabled()) { return true; } if (!CharacterDropManager.TryGetScopedOnePerPlayerNearbyPlayerCount(out var playerCount)) { return true; } __result = playerCount; return false; } } [HarmonyPatch(typeof(CharacterDrop), "Start")] internal static class CharacterDropStartPatch { private static void Postfix(CharacterDrop __instance) { if (PluginSettingsFacade.IsCharacterDomainEnabled()) { CharacterDropManager.TrackCharacterDropInstance(__instance); } } } [HarmonyPatch] internal static class ZDOManCreateNewZdoDespawnPatch { private static MethodBase? TargetMethod() { return AccessTools.Method(typeof(ZDOMan), "CreateNewZDO", new Type[3] { typeof(ZDOID), typeof(Vector3), typeof(int) }, (Type[])null); } private static void Postfix(int prefabHashIn, ZDO __result) { DespawnRulesManager.QueueCreatedDespawnTarget(prefabHashIn, __result); } } [HarmonyPatch(typeof(Character), "Awake")] internal static class CharacterAwakeBossRulesPatch { private static void Postfix(Character __instance) { BossRulesManager.TrackBossCharacter(__instance); if (PluginSettingsFacade.IsCharacterDomainEnabled()) { DespawnRulesManager.TryTrackLoadedDespawnTarget(__instance); } } } [HarmonyPatch(typeof(Character), "OnDestroy")] internal static class CharacterOnDestroyCharacterDropPatch { private static void Postfix(Character __instance) { BossRulesManager.UntrackBossCharacter(__instance); CharacterDrop characterDrop = default(CharacterDrop); if ((Object)(object)__instance != (Object)null && ((Component)__instance).TryGetComponent(ref characterDrop)) { CharacterDropManager.UntrackCharacterDropInstance(characterDrop); } } } [HarmonyPatch(typeof(ZNetView), "ResetZDO")] internal static class ZNetViewResetZdoDespawnPatch { private static void Prefix(ZNetView __instance) { DespawnRulesManager.TryPersistDespawnCountdownBeforeResetZdo(__instance); } } [HarmonyPatch(typeof(CharacterDrop), "OnDeath")] internal static class CharacterDropOnDeathPatch { private static bool Prefix(CharacterDrop __instance) { if (!PluginSettingsFacade.IsCharacterDomainEnabled()) { return true; } return !CharacterDropManager.TryHandleConfiguredDeath(__instance); } } [HarmonyPatch(typeof(CharacterDrop), "DropItems")] internal static class CharacterDropDropItemsPatch { private static void Prefix(ref List> drops, Vector3 centerPos, float dropArea) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) if (PluginSettingsFacade.IsCharacterDomainEnabled()) { CharacterDropManager.ApplyGlobalDropInStack(ref drops, centerPos, dropArea); } } } [HarmonyPatch(typeof(SpawnArea), "Awake")] internal static class SpawnAreaAwakePatch { private static void Postfix(SpawnArea __instance) { if (PluginSettingsFacade.IsSpawnerDomainEnabled()) { SpawnerManager.HandleSpawnAreaInstanceAwake(__instance); } } } [HarmonyPatch(typeof(SpawnArea), "UpdateSpawn")] internal static class SpawnAreaUpdateSpawnPatch { private static bool Prefix(SpawnArea __instance) { if (!PluginSettingsFacade.IsSpawnerDomainEnabled()) { return true; } if (SpawnerManager.ShouldBlockClientSpawnerUpdate()) { return false; } return SpawnerManager.PrepareSpawnAreaForUpdate(__instance); } } [HarmonyPatch(typeof(SpawnArea), "SelectWeightedPrefab")] internal static class SpawnAreaSelectWeightedPrefabPatch { private static void Postfix(SpawnArea __instance, SpawnData __result) { if (PluginSettingsFacade.IsSpawnerDomainEnabled()) { SpawnerManager.RecordSelectedSpawnAreaPrefab(__instance, __result); } } } [HarmonyPatch(typeof(SpawnArea), "FindSpawnPoint")] internal static class SpawnAreaFindSpawnPointPatch { private static void Postfix(SpawnArea __instance, GameObject prefab, ref Vector3 point, bool __result) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) if (PluginSettingsFacade.IsSpawnerDomainEnabled()) { SpawnerManager.RecordSpawnAreaSpawnPoint(__instance, __result, point); if (__result) { SpawnerManager.InitializeSpawnAreaSpawnData(__instance, prefab, point); } } } } [HarmonyPatch(typeof(SpawnArea), "SpawnOne")] internal static class SpawnAreaSpawnOnePatch { private static readonly MethodInfo InstantiateGameObjectMethod = (from method in typeof(Object).GetMethods(BindingFlags.Static | BindingFlags.Public) where method.Name == "Instantiate" && method.IsGenericMethodDefinition select method).First(delegate(MethodInfo method) { ParameterInfo[] parameters = method.GetParameters(); return parameters.Length == 3 && parameters[2].ParameterType == typeof(Quaternion); }).MakeGenericMethod(typeof(GameObject)); private static void Prefix(SpawnArea __instance) { if (PluginSettingsFacade.IsSpawnerDomainEnabled()) { SpawnerManager.BeginSpawnAreaSpawnAttempt(__instance); } } [HarmonyTranspiler] private static IEnumerable Transpiler(IEnumerable instructions) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Expected O, but got Unknown //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Expected O, but got Unknown CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null); val.MatchForward(false, (CodeMatch[])(object)new CodeMatch[1] { new CodeMatch((OpCode?)OpCodes.Call, (object)InstantiateGameObjectMethod, (string)null) }); if (!val.IsValid) { DropNSpawnPlugin.DropNSpawnLogger.LogError((object)"Failed to locate SpawnArea.SpawnOne instantiate call for faction tracking."); return instructions; } return val.Advance(1).InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1] { new CodeInstruction(OpCodes.Dup, (object)null) }).InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1] { new CodeInstruction(OpCodes.Ldarg_0, (object)null) }) .InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1] { new CodeInstruction(OpCodes.Call, Transpilers.EmitDelegate>((Action)RecordSpawnedObject).operand) }) .InstructionEnumeration(); } private static void Postfix(SpawnArea __instance, bool __result) { if (PluginSettingsFacade.IsSpawnerDomainEnabled()) { SpawnerManager.FinalizeSpawnAreaSpawnAttempt(__instance, __result); } } private static void RecordSpawnedObject(GameObject spawnedObject, SpawnArea spawnArea) { SpawnerManager.RecordDirectSpawnAreaSpawnedObject(spawnArea, spawnedObject); } } [HarmonyPatch(typeof(CreatureSpawner), "Awake")] internal static class CreatureSpawnerAwakePatch { private static void Postfix(CreatureSpawner __instance) { if (PluginSettingsFacade.IsSpawnerDomainEnabled()) { SpawnerManager.HandleCreatureSpawnerInstanceAwake(__instance); } } } [HarmonyPatch(typeof(CreatureSpawner), "OnDestroy")] internal static class CreatureSpawnerOnDestroyPatch { private static void Prefix(CreatureSpawner __instance) { if (PluginSettingsFacade.IsSpawnerDomainEnabled()) { SpawnerManager.UntrackCreatureSpawnerInstance(__instance); } } } [HarmonyPatch(typeof(CreatureSpawner), "UpdateSpawner")] internal static class CreatureSpawnerUpdateSpawnerPatch { private static bool Prefix(CreatureSpawner __instance) { if (!PluginSettingsFacade.IsSpawnerDomainEnabled()) { return true; } if (SpawnerManager.ShouldBlockClientSpawnerUpdate()) { return false; } return SpawnerManager.PrepareCreatureSpawnerForUpdate(__instance); } } [HarmonyPatch(typeof(CreatureSpawner), "Spawn")] internal static class CreatureSpawnerSpawnPatch { private static void Prefix(CreatureSpawner __instance) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) if (PluginSettingsFacade.IsSpawnerDomainEnabled()) { Vector3 position = ((Component)__instance).transform.position; float y = default(float); if ((Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.FindFloor(position, ref y)) { position.y = y; } SpawnerManager.InitializeCreatureSpawnerSpawnData(__instance, __instance.m_creaturePrefab, position); } } private static void Postfix(CreatureSpawner __instance, ZNetView __result) { if (PluginSettingsFacade.IsSpawnerDomainEnabled()) { SpawnerManager.ApplyCreatureSpawnerSpawnOverrides(__instance, __result); } } } [HarmonyPatch(typeof(BaseAI), "Awake")] internal static class BaseAIAwakeFactionPatch { private static void Postfix(BaseAI __instance) { FactionIntegration.ApplyFromZdo(__instance); } } [HarmonyPatch(typeof(SpawnSystem), "Awake")] [HarmonyPriority(0)] internal static class SpawnSystemAwakePatch { private static void Prefix(SpawnSystem __instance) { SpawnSystemManager.PreAttachCompiledTableToAwakeningSystem(__instance); } private static void Postfix(SpawnSystem __instance) { SpawnSystemManager.OnSpawnSystemAwake(__instance); } } [HarmonyPatch(typeof(SpawnSystem), "OnDestroy")] internal static class SpawnSystemOnDestroyPatch { private static void Prefix(SpawnSystem __instance) { SpawnSystemManager.UntrackLiveSystem(__instance); } } [HarmonyPatch(typeof(SpawnSystem), "UpdateSpawning")] internal static class SpawnSystemUpdateSpawningRequiredGlobalKeyPatch { private static bool Prefix(SpawnSystem __instance, out bool __state) { __state = false; if (!PluginSettingsFacade.IsSpawnSystemDomainEnabled()) { return true; } if (SpawnSystemManager.ShouldBlockClientSpawnSystemUpdate(__instance)) { return false; } SpawnSystemManager.RefreshRuntimeTimeOfDayState(); __state = true; SpawnSystemManager.EnterRequiredGlobalKeyEvaluation(); return true; } private static Exception? Finalizer(bool __state, Exception? __exception) { if (__state) { SpawnSystemManager.ExitRequiredGlobalKeyEvaluation(); } return __exception; } } [HarmonyPatch(typeof(ZoneSystem), "GetGlobalKey", new Type[] { typeof(string) })] internal static class ZoneSystemGetGlobalKeyStringPatch { private static bool Prefix(ZoneSystem __instance, string name, ref bool __result) { if (!PluginSettingsFacade.IsSpawnSystemDomainEnabled()) { return true; } if (!SpawnSystemManager.TryEvaluateExtendedRequiredGlobalKey(__instance, name, out var result)) { return true; } __result = result; return false; } } [HarmonyPatch(typeof(ZoneSystem), "RPC_SetGlobalKey")] internal static class ZoneSystemRpcSetGlobalKeyPatch { private static void Prefix(ZoneSystem __instance, ref string name) { if (DropNSpawnPlugin.IsSourceOfTruth && PluginSettingsFacade.IsSpawnSystemDomainEnabled() && SpawnSystemManager.TryRewriteExtendedGlobalKeyMutation(__instance, name, out string rewrittenValue)) { name = rewrittenValue; } } } [HarmonyPatch(typeof(SpawnSystem), "Spawn")] internal static class SpawnSystemSpawnPatch { private static void Prefix(SpawnData critter, Vector3 spawnPoint, out bool __state) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) __state = false; if (PluginSettingsFacade.IsSpawnSystemDomainEnabled()) { __state = true; SpawnSystemCustomDataSupport.InitializeSpawn(critter, spawnPoint); } } private static void Postfix(SpawnData critter, Vector3 spawnPoint, bool __state) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) if (__state) { SpawnSystemManager.ConsumeExtendedRequiredGlobalKeyAfterSpawn(critter); SpawnSystemCustomDataSupport.SpawnObjects(critter, spawnPoint); } } private static Exception? Finalizer(SpawnData critter, bool __state, Exception? __exception) { return __exception; } } internal static class GeneratedFileWriter { internal static bool WriteAllTextIfChanged(string path, string content) { if (path == null) { throw new ArgumentNullException("path"); } if (content == null) { content = ""; } string directoryName = Path.GetDirectoryName(path); if (!string.IsNullOrEmpty(directoryName)) { Directory.CreateDirectory(directoryName); } if (File.Exists(path) && string.Equals(File.ReadAllText(path), content, StringComparison.Ordinal)) { return false; } File.WriteAllText(path, content); return true; } } internal static class ReferenceRefreshSupport { internal const string CurrentReferenceLogicVersion = "2026-03-26-full-rewrite-v1"; internal static string ComputeStableHashForKeys(IEnumerable keys) { StringBuilder stringBuilder = new StringBuilder(); foreach (string item in (from key in (keys ?? Enumerable.Empty()).Select(NormalizeKey) where key.Length > 0 select key).OrderBy((string key) => key, StringComparer.OrdinalIgnoreCase)) { stringBuilder.AppendLine(item); } return ComputeStableHash(stringBuilder.ToString()); } internal static bool TryReadYamlList(string path, IDeserializer deserializer, out List entries, out string error) { entries = new List(); error = ""; if (string.IsNullOrWhiteSpace(path) || !File.Exists(path)) { return false; } try { return TryDeserializeYamlList(File.ReadAllText(path), deserializer, out entries, out error); } catch (Exception ex) { error = ex.Message; entries = new List(); return false; } } internal static bool TryDeserializeYamlList(string content, IDeserializer deserializer, out List entries, out string error) { entries = new List(); error = ""; try { using StringReader input = new StringReader(content ?? ""); entries = deserializer.Deserialize>(input) ?? new List(); return true; } catch (Exception ex) { error = ex.Message; entries = new List(); return false; } } internal static List MergeMissingByKey(IEnumerable existingEntries, IEnumerable currentEntries, Func getKey, out int addedCount) { List list = existingEntries?.ToList() ?? new List(); HashSet hashSet = ToNormalizedKeySet(list.Select(getKey)); addedCount = 0; foreach (T item in currentEntries ?? Enumerable.Empty()) { string text = NormalizeKey(getKey(item)); if (text.Length != 0 && hashSet.Add(text)) { list.Add(item); addedCount++; } } return list; } internal static string SerializeReferenceSections(IEnumerable entries, Func getPrefabName, ISerializer serializer) { return PrefabOutputSections.SerializeReferenceSections(PrefabOutputSections.BuildSections(entries ?? Enumerable.Empty(), getPrefabName), serializer); } internal static HashSet ToNormalizedKeySet(IEnumerable keys) { HashSet hashSet = new HashSet(StringComparer.OrdinalIgnoreCase); foreach (string item in keys ?? Enumerable.Empty()) { string text = NormalizeKey(item); if (text.Length > 0) { hashSet.Add(text); } } return hashSet; } internal static string NormalizeKey(string? key) { return (key ?? "").Trim(); } internal static bool ShouldSkipAutoUpdate(string stateKey, string referencePath, string sourceSignature, string? logicVersion = null) { if (string.IsNullOrWhiteSpace(stateKey) || string.IsNullOrWhiteSpace(referencePath) || string.IsNullOrWhiteSpace(sourceSignature) || !File.Exists(referencePath)) { return false; } string path = ResolveAutoUpdateStatePath(stateKey); if (!File.Exists(path)) { return false; } try { string text = (logicVersion ?? "").Trim(); string[] array = File.ReadAllLines(path); if (array.Length < 2) { return false; } string a = (array[0] ?? "").Trim(); string a2 = (array[1] ?? "").Trim(); string a3 = ((array.Length >= 4) ? (array[3] ?? "").Trim() : ""); if (text.Length > 0 && !string.Equals(a3, text, StringComparison.Ordinal)) { return false; } return string.Equals(a, sourceSignature, StringComparison.Ordinal) && string.Equals(a2, BuildReferenceFileStamp(referencePath), StringComparison.Ordinal); } catch { return false; } } internal static bool ShouldSkipAutoUpdateByPrecheck(string stateKey, string referencePath, string precheckSignature, string? logicVersion = null) { if (string.IsNullOrWhiteSpace(stateKey) || string.IsNullOrWhiteSpace(referencePath) || string.IsNullOrWhiteSpace(precheckSignature) || !File.Exists(referencePath)) { return false; } string path = ResolveAutoUpdateStatePath(stateKey); if (!File.Exists(path)) { return false; } try { string text = (logicVersion ?? "").Trim(); string[] array = File.ReadAllLines(path); if (array.Length < 3) { return false; } string a = (array[1] ?? "").Trim(); string a2 = (array[2] ?? "").Trim(); string a3 = ((array.Length >= 4) ? (array[3] ?? "").Trim() : ""); if (text.Length > 0 && !string.Equals(a3, text, StringComparison.Ordinal)) { return false; } return string.Equals(a2, precheckSignature, StringComparison.Ordinal) && string.Equals(a, BuildReferenceFileStamp(referencePath), StringComparison.Ordinal); } catch { return false; } } internal static void RecordAutoUpdateState(string stateKey, string referencePath, string sourceSignature, string? precheckSignature = null, string? logicVersion = null) { if (string.IsNullOrWhiteSpace(stateKey) || string.IsNullOrWhiteSpace(referencePath) || string.IsNullOrWhiteSpace(sourceSignature) || !File.Exists(referencePath)) { return; } string autoUpdateStatePath = GetAutoUpdateStatePath(stateKey); string content = sourceSignature.Trim() + Environment.NewLine + BuildReferenceFileStamp(referencePath) + Environment.NewLine + (precheckSignature ?? "").Trim() + Environment.NewLine + (logicVersion ?? "").Trim() + Environment.NewLine; GeneratedFileWriter.WriteAllTextIfChanged(autoUpdateStatePath, content); string legacyAutoUpdateStatePath = GetLegacyAutoUpdateStatePath(stateKey); if (string.Equals(autoUpdateStatePath, legacyAutoUpdateStatePath, StringComparison.OrdinalIgnoreCase) || !File.Exists(legacyAutoUpdateStatePath)) { return; } try { File.Delete(legacyAutoUpdateStatePath); } catch { } } internal static string ComputeStableHash(string? value) { using SHA256 sHA = SHA256.Create(); byte[] bytes = Encoding.UTF8.GetBytes(value ?? ""); byte[] array = sHA.ComputeHash(bytes); StringBuilder stringBuilder = new StringBuilder(array.Length * 2); byte[] array2 = array; foreach (byte b in array2) { stringBuilder.Append(b.ToString("x2")); } return stringBuilder.ToString(); } private static string GetAutoUpdateStatePath(string stateKey) { string text = SanitizeFileName(stateKey); return Path.Combine(GetAutoUpdateStateDirectoryPath(), ".reference-state." + text + ".txt"); } private static string GetLegacyAutoUpdateStatePath(string stateKey) { string text = SanitizeFileName(stateKey); return Path.Combine(DropNSpawnPlugin.YamlConfigDirectoryPath, ".reference-state." + text + ".txt"); } private static string ResolveAutoUpdateStatePath(string stateKey) { string autoUpdateStatePath = GetAutoUpdateStatePath(stateKey); if (File.Exists(autoUpdateStatePath)) { return autoUpdateStatePath; } string legacyAutoUpdateStatePath = GetLegacyAutoUpdateStatePath(stateKey); if (!File.Exists(legacyAutoUpdateStatePath)) { return autoUpdateStatePath; } try { string directoryName = Path.GetDirectoryName(autoUpdateStatePath); if (!string.IsNullOrWhiteSpace(directoryName)) { Directory.CreateDirectory(directoryName); } File.Move(legacyAutoUpdateStatePath, autoUpdateStatePath); return autoUpdateStatePath; } catch { return legacyAutoUpdateStatePath; } } private static string GetAutoUpdateStateDirectoryPath() { return Path.Combine(DropNSpawnPlugin.YamlConfigDirectoryPath, "cache"); } private static string BuildReferenceFileStamp(string referencePath) { FileInfo fileInfo = new FileInfo(referencePath); return $"{fileInfo.Length}:{fileInfo.LastWriteTimeUtc.Ticks}"; } private static string SanitizeFileName(string value) { StringBuilder stringBuilder = new StringBuilder(value.Length); HashSet hashSet = Path.GetInvalidFileNameChars().ToHashSet(); foreach (char c in value) { stringBuilder.Append(hashSet.Contains(c) ? '_' : c); } return stringBuilder.ToString(); } } internal sealed class CharacterDropPrefabEntry { [YamlMember(Order = 1)] public string Prefab { get; set; } = ""; [YamlMember(Order = 2)] public bool Enabled { get; set; } = true; [YamlMember(Order = 3)] public ConditionsDefinition? Conditions { get; set; } [YamlMember(Order = 4)] public CharacterDropDefinition? CharacterDrop { get; set; } [YamlMember(Order = 5)] public DespawnDefinition? Despawn { get; set; } [YamlMember(Order = 6)] public BossTamedPressureDefinition? BossTamedPressure { get; set; } [YamlIgnore] public string RuleId { get; set; } = ""; [YamlIgnore] public string? SourcePath { get; set; } [YamlIgnore] public int SourceLine { get; set; } [YamlIgnore] public int SourceColumn { get; set; } } internal sealed class CharacterDropReferenceEntry { [YamlMember(Order = 1)] public string Prefab { get; set; } = ""; [YamlMember(Order = 2)] public CharacterDropDefinition? CharacterDrop { get; set; } } internal sealed class CharacterDropDefinition { [YamlMember(Order = 1)] public List? Drops { get; set; } } internal sealed class DespawnDefinition { [YamlMember(Order = 1)] public float? Range { get; set; } [YamlMember(Order = 2)] public float? Delay { get; set; } [YamlMember(Order = 3)] public List? Refunds { get; set; } } internal sealed class DespawnRefundEntryDefinition { [YamlMember(Order = 1)] public string Item { get; set; } = ""; [YamlMember(Order = 2)] public int? Amount { get; set; } } internal sealed class BossTamedPressureDefinition { [YamlMember(Order = 1)] public List? BossPrefabs { get; set; } [YamlMember(Order = 2)] public List? ExcludedBossPrefabs { get; set; } [YamlMember(Order = 3)] public BossTamedPressureTargetsDefinition? Targets { get; set; } [YamlMember(Order = 4)] public BossTamedPressurePressureDefinition? Pressure { get; set; } [YamlMember(Order = 5)] public string? Message { get; set; } [YamlMember(Order = 6)] public float? MessageInterval { get; set; } } internal sealed class BossTamedPressureTargetsDefinition { [YamlMember(Order = 1)] public float? Range { get; set; } [YamlMember(Order = 2)] public float? ScanInterval { get; set; } [YamlMember(Order = 3)] public int? MaxPerBoss { get; set; } [YamlMember(Order = 4)] public List? ExcludedTamedPrefabs { get; set; } [YamlMember(Order = 5)] public List? ExtraPressuredPrefabs { get; set; } } internal sealed class BossTamedPressurePressureDefinition { [YamlMember(Order = 1)] public float? DamageInterval { get; set; } [YamlMember(Order = 2)] public float? DamagePercentPerSecond { get; set; } [YamlMember(Order = 3)] public float? DamageMinBaseHealth { get; set; } [YamlMember(Order = 4)] public float? IncomingDamageMultiplier { get; set; } [YamlMember(Order = 5)] public float? OutgoingDamageMultiplier { get; set; } } internal sealed class CharacterDropEntryDefinition { [YamlMember(Order = 1)] public string Item { get; set; } = ""; [YamlMember(Order = 2)] public IntRangeDefinition? Amount { get; set; } [YamlIgnore] public int? AmountMin { get; set; } [YamlIgnore] public int? AmountMax { get; set; } [YamlMember(Order = 3)] public float? Chance { get; set; } [YamlMember(Order = 4)] public bool? DontScale { get; set; } [YamlMember(Order = 5)] public bool? LevelMultiplier { get; set; } [YamlMember(Order = 6)] public bool? OnePerPlayer { get; set; } [YamlMember(Order = 7)] public int? AmountLimit { get; set; } [YamlMember(Order = 8)] public bool? DropInStack { get; set; } } internal sealed class CompiledCharacterDropDefinition { public string Fingerprint { get; set; } = ""; public GameObject Prefab { get; set; } public int AmountMin { get; set; } public int AmountMax { get; set; } public float Chance { get; set; } public bool DontScale { get; set; } public bool LevelMultiplier { get; set; } public bool OnePerPlayer { get; set; } public int? AmountLimit { get; set; } public bool DropInStack { get; set; } } internal sealed class CompiledCharacterDropRule { public CharacterDropPrefabEntry Entry { get; set; } public List Drops { get; } = new List(); } internal sealed class CachedCharacterRuntimeDropResolution { public bool HasMatchedRuntimeRule { get; set; } public CompiledCharacterDropDefinition[] Definitions { get; set; } = Array.Empty(); public List? OverrideDrops { get; set; } public bool HasCustomDropHandling { get; set; } } internal sealed class CharacterRuntimeDropCacheState { public bool IsCacheable { get; set; } = true; public bool UsesLevel { get; set; } public bool UsesFaction { get; set; } public bool UsesState { get; set; } public bool UsesTimeOfDay { get; set; } public bool UsesRequiredEnvironments { get; set; } public bool UsesInsidePlayerBase { get; set; } public string[] RequiredGlobalKeys { get; set; } = Array.Empty(); public string[] ForbiddenGlobalKeys { get; set; } = Array.Empty(); public Dictionary ResolutionsBySignature { get; } = new Dictionary(); } internal sealed class CharacterCompiledState { public static CharacterCompiledState Empty { get; } = new CharacterCompiledState(); public Dictionary> RuntimeRulesByPrefab { get; } = new Dictionary>(StringComparer.OrdinalIgnoreCase); public Dictionary RuntimeDropCachesByPrefab { get; } = new Dictionary(StringComparer.OrdinalIgnoreCase); public Dictionary> StaticDropsByPrefab { get; } = new Dictionary>(StringComparer.OrdinalIgnoreCase); public Dictionary> StaticBuiltDropsByPrefab { get; } = new Dictionary>(StringComparer.OrdinalIgnoreCase); } internal sealed class CharacterDropItemSnapshot { public GameObject? ItemPrefab { get; set; } public int AmountMin { get; set; } public int AmountMax { get; set; } public float Chance { get; set; } public bool OnePerPlayer { get; set; } public bool LevelMultiplier { get; set; } public bool DontScale { get; set; } } internal sealed class CharacterDropSnapshot { public GameObject Prefab { get; set; } public List Drops { get; set; } = new List(); public List BuiltDrops { get; set; } = new List(); } internal sealed class PendingCharacterDropSnapshotBuildState { public int BuildVersion { get; set; } public int GameDataSignature { get; set; } public int SnapshotSignature { get; set; } public string Source { get; set; } = ""; public List Prefabs { get; } = new List(); public List Snapshots { get; } = new List(); public Dictionary SnapshotsByPrefab { get; } = new Dictionary(StringComparer.OrdinalIgnoreCase); public int NextIndex { get; set; } } internal static class CharacterDropRuntime { private static readonly List Snapshots = new List(); private static readonly Dictionary SnapshotsByPrefab = new Dictionary(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary> LiveCharacterDropsByPrefab = new Dictionary>(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary LiveCharacterDropPrefabsByInstance = new Dictionary(); private static int? _lastProcessedSnapshotSignature; private static int? _lastProcessedGameDataSignature; private static int? _lastBootstrappedLiveObjectsSceneSignature; private static int _snapshotBuildVersion; private static PendingCharacterDropSnapshotBuildState? _pendingSnapshotBuild; internal static void Reset() { Snapshots.Clear(); SnapshotsByPrefab.Clear(); LiveCharacterDropsByPrefab.Clear(); LiveCharacterDropPrefabsByInstance.Clear(); _lastProcessedSnapshotSignature = null; _lastProcessedGameDataSignature = null; _lastBootstrappedLiveObjectsSceneSignature = null; _pendingSnapshotBuild = null; _snapshotBuildVersion = 0; } internal static bool HasSnapshots() { return Snapshots.Count > 0; } internal static int SnapshotCount() { return Snapshots.Count; } internal static IReadOnlyList GetSnapshots() { return Snapshots; } internal static bool HasSnapshot(string prefabName) { if (!string.IsNullOrWhiteSpace(prefabName)) { return SnapshotsByPrefab.ContainsKey(prefabName); } return false; } internal static bool TryGetSnapshot(string prefabName, out CharacterDropSnapshot? snapshot) { return SnapshotsByPrefab.TryGetValue(prefabName ?? "", out snapshot); } internal static bool IsGameDataAlreadyProcessed(int gameDataSignature) { return _lastProcessedGameDataSignature == gameDataSignature; } internal static bool NeedsSnapshotBuild(int snapshotSignature) { if (_lastProcessedSnapshotSignature == snapshotSignature) { return Snapshots.Count == 0; } return true; } internal static void ScheduleSnapshotBuild(string source, int gameDataSignature, int snapshotSignature, IEnumerable prefabs) { if (_pendingSnapshotBuild == null || _pendingSnapshotBuild.GameDataSignature != gameDataSignature || _pendingSnapshotBuild.SnapshotSignature != snapshotSignature) { PendingCharacterDropSnapshotBuildState pendingCharacterDropSnapshotBuildState = new PendingCharacterDropSnapshotBuildState(); pendingCharacterDropSnapshotBuildState.BuildVersion = ++_snapshotBuildVersion; pendingCharacterDropSnapshotBuildState.GameDataSignature = gameDataSignature; pendingCharacterDropSnapshotBuildState.SnapshotSignature = snapshotSignature; pendingCharacterDropSnapshotBuildState.Source = source; pendingCharacterDropSnapshotBuildState.Prefabs.AddRange(prefabs); _pendingSnapshotBuild = pendingCharacterDropSnapshotBuildState; } } internal static bool HasPendingSnapshotBuildWork() { return _pendingSnapshotBuild != null; } internal static bool ProcessPendingSnapshotBuildStep(float deadline, Func captureSnapshot, Action onCompleted) { PendingCharacterDropSnapshotBuildState pendingSnapshotBuild = _pendingSnapshotBuild; if (pendingSnapshotBuild == null) { return false; } if (pendingSnapshotBuild.NextIndex >= pendingSnapshotBuild.Prefabs.Count) { CompletePendingSnapshotBuild(pendingSnapshotBuild, onCompleted); return true; } GameObject val = pendingSnapshotBuild.Prefabs[pendingSnapshotBuild.NextIndex]; pendingSnapshotBuild.NextIndex++; CharacterDropSnapshot characterDropSnapshot = (((Object)(object)val != (Object)null) ? captureSnapshot(val) : null); if (_pendingSnapshotBuild == null || _pendingSnapshotBuild != pendingSnapshotBuild) { return true; } if (characterDropSnapshot != null) { pendingSnapshotBuild.Snapshots.Add(characterDropSnapshot); if (!pendingSnapshotBuild.SnapshotsByPrefab.ContainsKey(((Object)characterDropSnapshot.Prefab).name)) { pendingSnapshotBuild.SnapshotsByPrefab.Add(((Object)characterDropSnapshot.Prefab).name, characterDropSnapshot); } } if (pendingSnapshotBuild.NextIndex >= pendingSnapshotBuild.Prefabs.Count && Time.realtimeSinceStartup <= deadline) { CompletePendingSnapshotBuild(pendingSnapshotBuild, onCompleted); } return true; } internal static void CaptureSnapshotsIfNeeded(IEnumerable prefabs, Func captureSnapshot) { if (Snapshots.Count > 0) { return; } foreach (GameObject prefab in prefabs) { CharacterDropSnapshot characterDropSnapshot = captureSnapshot(prefab); if (characterDropSnapshot != null) { Snapshots.Add(characterDropSnapshot); if (!SnapshotsByPrefab.ContainsKey(((Object)characterDropSnapshot.Prefab).name)) { SnapshotsByPrefab.Add(((Object)characterDropSnapshot.Prefab).name, characterDropSnapshot); } } } } internal static void RefreshSnapshots(IEnumerable prefabs, Func captureSnapshot) { Snapshots.Clear(); SnapshotsByPrefab.Clear(); _lastBootstrappedLiveObjectsSceneSignature = null; CaptureSnapshotsIfNeeded(prefabs, captureSnapshot); } internal static void RegisterLiveCharacterDrop(CharacterDrop characterDrop, string prefabName) { if ((Object)(object)characterDrop == (Object)null || string.IsNullOrWhiteSpace(prefabName)) { return; } if (LiveCharacterDropPrefabsByInstance.TryGetValue(characterDrop, out string value)) { if (string.Equals(value, prefabName, StringComparison.OrdinalIgnoreCase)) { return; } UnregisterLiveCharacterDrop(characterDrop, value); } LiveCharacterDropPrefabsByInstance[characterDrop] = prefabName; if (!LiveCharacterDropsByPrefab.TryGetValue(prefabName, out HashSet value2)) { value2 = new HashSet(); LiveCharacterDropsByPrefab[prefabName] = value2; } value2.Add(characterDrop); } internal static bool TryGetRegisteredPrefabName(CharacterDrop characterDrop, out string prefabName) { return LiveCharacterDropPrefabsByInstance.TryGetValue(characterDrop, out prefabName); } internal static void UnregisterLiveCharacterDrop(CharacterDrop characterDrop, string prefabName) { LiveCharacterDropPrefabsByInstance.Remove(characterDrop); if (LiveCharacterDropsByPrefab.TryGetValue(prefabName, out HashSet value)) { value.Remove(characterDrop); if (value.Count == 0) { LiveCharacterDropsByPrefab.Remove(prefabName); } } } internal static void BootstrapRegisteredCharacterDropsIfNeeded(int sceneSignature, IEnumerable liveCharacterDrops, Func getPrefabName, Func shouldRegisterPrefab, ISet? additionalPrefabs = null, bool forceRescan = false) { if (!forceRescan && _lastBootstrappedLiveObjectsSceneSignature == sceneSignature) { return; } CleanupRegisteredCharacterDrops(); foreach (CharacterDrop liveCharacterDrop in liveCharacterDrops) { if (!((Object)(object)liveCharacterDrop == (Object)null) && !((Object)(object)((Component)liveCharacterDrop).gameObject == (Object)null)) { string text = getPrefabName(liveCharacterDrop); if (text.Length != 0 && (shouldRegisterPrefab(text) || (additionalPrefabs != null && additionalPrefabs.Contains(text)))) { RegisterLiveCharacterDrop(liveCharacterDrop, text); } } } _lastBootstrappedLiveObjectsSceneSignature = sceneSignature; } internal static IReadOnlyList GetRegisteredCharacterDrops(HashSet? dirtyPrefabs = null) { CleanupRegisteredCharacterDrops(); HashSet visited = new HashSet(); List list = new List(); if (dirtyPrefabs == null) { foreach (HashSet value2 in LiveCharacterDropsByPrefab.Values) { AddRegisteredCharacterDrops(value2, visited, list); } return list; } foreach (string dirtyPrefab in dirtyPrefabs) { if (LiveCharacterDropsByPrefab.TryGetValue(dirtyPrefab, out HashSet value)) { AddRegisteredCharacterDrops(value, visited, list); } } return list; } private static void AddRegisteredCharacterDrops(IEnumerable characterDrops, ISet visited, ICollection registered) { foreach (CharacterDrop item in characterDrops ?? Enumerable.Empty()) { if ((Object)(object)item != (Object)null && (Object)(object)((Component)item).gameObject != (Object)null && visited.Add(item)) { registered.Add(item); } } } private static void CleanupRegisteredCharacterDrops() { List list = null; foreach (CharacterDrop item in LiveCharacterDropPrefabsByInstance.Keys.ToList()) { if ((Object)(object)item == (Object)null || (Object)(object)((Component)item).gameObject == (Object)null) { if (list == null) { list = new List(); } list.Add(item); } } if (list == null) { return; } foreach (CharacterDrop item2 in list) { if (LiveCharacterDropPrefabsByInstance.TryGetValue(item2, out string value)) { UnregisterLiveCharacterDrop(item2, value); } } } private static void CompletePendingSnapshotBuild(PendingCharacterDropSnapshotBuildState buildState, Action onCompleted) { if (_pendingSnapshotBuild == null || _pendingSnapshotBuild != buildState) { return; } Snapshots.Clear(); Snapshots.AddRange(buildState.Snapshots); SnapshotsByPrefab.Clear(); foreach (var (key, value) in buildState.SnapshotsByPrefab) { SnapshotsByPrefab[key] = value; } _lastBootstrappedLiveObjectsSceneSignature = null; _pendingSnapshotBuild = null; _lastProcessedSnapshotSignature = buildState.SnapshotSignature; _lastProcessedGameDataSignature = buildState.GameDataSignature; onCompleted(buildState.Source, buildState.GameDataSignature, buildState.SnapshotSignature); } } internal static class CharacterDropManager { private readonly struct InvalidEntryWarningSuppressionScope : IDisposable { private readonly bool _active; public InvalidEntryWarningSuppressionScope(bool active) { _active = active; if (_active) { _invalidEntryWarningSuppressionDepth++; } } public void Dispose() { if (_active) { _invalidEntryWarningSuppressionDepth--; } } } private sealed class ResolvedConfiguredDrop { public GameObject Prefab { get; set; } public int Amount { get; set; } public bool DropInStack { get; set; } } private sealed class SyncedCharacterConfigurationState { public List Configuration { get; } = new List(); public Dictionary> ActiveEntriesByPrefab { get; } = new Dictionary>(StringComparer.OrdinalIgnoreCase); public HashSet ConfiguredCharacterDropPrefabs { get; } = new HashSet(StringComparer.OrdinalIgnoreCase); public HashSet PrefabsWithCharacterDropOverrides { get; } = new HashSet(StringComparer.OrdinalIgnoreCase); public List BossTamedPressureRules { get; } = new List(); public Dictionary EntrySignaturesByPrefab { get; set; } = new Dictionary(StringComparer.OrdinalIgnoreCase); public string ConfigurationSignature { get; set; } = ""; } private sealed class ParsedCharacterConfigurationDocument { public List Configuration { get; } = new List(); public List Warnings { get; } = new List(); } private sealed class CharacterRuntimeContextSnapshot { public int Frame { get; set; } public int TimeOfDayPhaseMarker { get; set; } public string EnvironmentName { get; set; } = ""; public Dictionary GlobalKeyStates { get; } = new Dictionary(StringComparer.Ordinal); } private sealed class CharacterApplyOperations : IStandardBaselineDesiredStateOperations { public static CharacterApplyOperations Instance { get; } = new CharacterApplyOperations(); public string DomainKey => "character"; public BaselineDesiredStateCapabilities Capabilities => BaselineDesiredStateCapabilities.Validation | BaselineDesiredStateCapabilities.StaticBaseline | BaselineDesiredStateCapabilities.StaticApply | BaselineDesiredStateCapabilities.LiveApply | BaselineDesiredStateCapabilities.StaticRollback; public void Validate(CharacterDesiredState desiredState) { ValidateCharacterDesiredState(desiredState); } public void RestoreStaticBaseline(CharacterDesiredState desiredState) { RestoreCharacterStaticBaseline(desiredState); } public void ApplyDesiredStateToStaticBaseline(CharacterDesiredState desiredState) { ApplyCharacterDesiredStateToStaticBaseline(desiredState); } public void PrepareLiveBaseline(CharacterDesiredState desiredState) { PrepareCharacterLiveBaseline(desiredState); } public void ApplyDesiredStateToLive(CharacterDesiredState desiredState) { ApplyCharacterDesiredStateToLive(desiredState); } public void Commit(CharacterDesiredState desiredState) { RecordAppliedState(desiredState.GameDataSignature, desiredState.DomainEnabled, desiredState.CurrentEntrySignatures); } public void HandleFailure(CharacterDesiredState desiredState, StandardApplyFailureContext failureContext) { } } private sealed class CharacterDesiredState { public StandardDomainApplyPlan ApplyPlan { get; set; } public CharacterCompiledState CompiledState { get; set; } = CharacterCompiledState.Empty; public int GameDataSignature { get; set; } public Dictionary CurrentEntrySignatures { get; set; } = EmptyEntrySignatures; public bool DomainEnabled { get; set; } } [CompilerGenerated] private sealed class d__110 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private string <>2__current; private int <>l__initialThreadId; private IEnumerator <>7__wrap1; string IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__110(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(); } } <>7__wrap1 = 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_006a; case 1: <>1__state = -1; goto IL_006a; case 2: <>1__state = -1; goto IL_0093; case 3: { <>1__state = -3; break; } IL_006a: if (File.Exists(PrimaryOverrideConfigurationPathYaml)) { <>2__current = PrimaryOverrideConfigurationPathYaml; <>1__state = 2; return true; } goto IL_0093; IL_0093: <>7__wrap1 = EnumerateSupplementalOverrideConfigurationPaths().GetEnumerator(); <>1__state = -3; break; } if (<>7__wrap1.MoveNext()) { string current = <>7__wrap1.Current; <>2__current = current; <>1__state = 3; return true; } <>m__Finally1(); <>7__wrap1 = 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 (<>7__wrap1 != null) { <>7__wrap1.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; return this; } return new d__110(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__119 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private GameObject <>2__current; private int <>l__initialThreadId; private HashSet 5__2; private List.Enumerator <>7__wrap2; GameObject IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__119(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { switch (<>1__state) { case -3: case 1: try { } finally { <>m__Finally1(); } break; case -4: case 2: try { } finally { <>m__Finally2(); } break; } 5__2 = null; <>7__wrap2 = default(List.Enumerator); <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; 5__2 = new HashSet(); if ((Object)(object)ZNetScene.instance == (Object)null) { return false; } <>7__wrap2 = ZNetScene.instance.m_prefabs.GetEnumerator(); <>1__state = -3; goto IL_00bd; case 1: <>1__state = -3; goto IL_00bd; case 2: { <>1__state = -4; break; } IL_00bd: while (<>7__wrap2.MoveNext()) { GameObject current = <>7__wrap2.Current; if ((Object)(object)current != (Object)null && !((Object)current).name.StartsWith("JVLmock_", StringComparison.OrdinalIgnoreCase) && 5__2.Add(((Object)current).GetInstanceID())) { <>2__current = current; <>1__state = 1; return true; } } <>m__Finally1(); <>7__wrap2 = default(List.Enumerator); <>7__wrap2 = ZNetScene.instance.m_nonNetViewPrefabs.GetEnumerator(); <>1__state = -4; break; } while (<>7__wrap2.MoveNext()) { GameObject current2 = <>7__wrap2.Current; if ((Object)(object)current2 != (Object)null && !((Object)current2).name.StartsWith("JVLmock_", StringComparison.OrdinalIgnoreCase) && 5__2.Add(((Object)current2).GetInstanceID())) { <>2__current = current2; <>1__state = 2; return true; } } <>m__Finally2(); <>7__wrap2 = default(List.Enumerator); 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; ((IDisposable)<>7__wrap2).Dispose(); } private void <>m__Finally2() { <>1__state = -1; ((IDisposable)<>7__wrap2).Dispose(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; return this; } return new d__119(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__120 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private GameObject <>2__current; private int <>l__initialThreadId; private IEnumerator <>7__wrap1; GameObject IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__120(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(); } } <>7__wrap1 = null; <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>7__wrap1 = EnumeratePrefabs().GetEnumerator(); <>1__state = -3; break; case 1: <>1__state = -3; break; } while (<>7__wrap1.MoveNext()) { GameObject current = <>7__wrap1.Current; if ((Object)(object)current != (Object)null && (Object)(object)current.GetComponent() != (Object)null) { <>2__current = current; <>1__state = 1; return true; } } <>m__Finally1(); <>7__wrap1 = 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 (<>7__wrap1 != null) { <>7__wrap1.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; return this; } return new d__120(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } private const string ReferenceAutoUpdateStateKey = "character"; internal static readonly DomainModuleDefinition Module = new DomainModuleDefinition("character", DropNSpawnPlugin.ReloadDomain.Character, "character_yaml", 99, ShouldReloadForPath, ReloadConfiguration, OnGameDataReady, HandleExpandWorldDataReady, 10, DomainTransportProfile.SmallConfig, "character", "character", 10, (CharacterDropPrefabEntry entry) => entry.RuleId, ApplySyncedPayload, DomainWorkKinds.Runtime | DomainWorkKinds.SnapshotBuild, HasPendingSnapshotBuildWork, ProcessPendingSnapshotBuildStep, null, null, MarkSyncedPayloadPending, EnterPendingSyncedPayloadState); private static int _invalidEntryWarningSuppressionDepth; 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 Dictionary> ActiveEntriesByPrefab = new Dictionary>(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary CurrentEntrySignaturesByPrefab = new Dictionary(StringComparer.OrdinalIgnoreCase); private static readonly HashSet ConfiguredCharacterDropPrefabs = new HashSet(StringComparer.OrdinalIgnoreCase); private static readonly HashSet PrefabsWithCharacterDropOverrides = new HashSet(StringComparer.OrdinalIgnoreCase); private static readonly List BossTamedPressureRules = new List(); private static readonly HashSet InvalidEntryWarnings = new HashSet(StringComparer.OrdinalIgnoreCase); private static readonly FieldInfo? DropsEnabledField = AccessTools.Field(typeof(CharacterDrop), "m_dropsEnabled"); [ThreadStatic] private static CharacterDrop? OnePerPlayerScopeCharacterDrop; [ThreadStatic] private static int OnePerPlayerScopeDepth; private static List _configuration = new List(); private static string _configurationSignature = ""; private static bool _initialized; private static CharacterCompiledState _compiledState = CharacterCompiledState.Empty; private static string _compiledStateConfigurationSignature = ""; private static int? _compiledStateGameDataSignature; private static bool _referenceArtifactsAutoRefreshConsumed; private static readonly Dictionary _lastAppliedEntrySignaturesByPrefab = new Dictionary(StringComparer.OrdinalIgnoreCase); private static string _lastAppliedConfigurationSignature = ""; private static int? _lastAppliedGameDataSignature; private static bool? _lastAppliedDomainEnabled; private static bool _lastAppliedSynchronizedPayloadReady; private static bool _synchronizedPayloadReady; private static int? _lastCommittedAuthorityEpoch; private static CharacterRuntimeContextSnapshot? _runtimeContextSnapshot; private static int _cachedFrameGameDataSignatureFrame = -1; private static int _cachedFrameGameDataSignatureValue; private const string MockPrefabPrefix = "JVLmock_"; private const float ConfiguredDropGroundOffset = 0.2f; private const int MaxCachedRuntimeDropResolutionsPerPrefab = 32; private static readonly DomainConfigurationRuntime ConfigurationRuntime = new DomainConfigurationRuntime(new DomainLoadHooks(ParseLocalConfigurationDocuments, BuildSyncedConfigurationState, CommitSyncedConfigurationState, RejectLocalConfigurationPayload, (SyncedCharacterConfigurationState state) => state.Configuration.Count, LogPartiallyAcceptedLocalConfiguration, LogLocalConfigurationLoaded, OnSourceOfTruthPayloadUnchanged, delegate { ConfigurationDomainHost.PublishSyncedPayload(DropNSpawnPlugin.IsSourceOfTruth, Descriptor, _configuration, _configurationSignature); }), new DomainSyncHooks(delegate(out List configuration, out string payloadToken) { return ConfigurationDomainHost.TryGetSyncedEntries(Descriptor, out configuration, out payloadToken); }, (string payloadToken) => ConfigurationDomainHost.ShouldSkipSyncedPayload(LoadState, payloadToken, Volatile.Read(ref _synchronizedPayloadReady)), BuildSyncedConfigurationState, CommitSyncedConfigurationState, (SyncedCharacterConfigurationState state) => state.ActiveEntriesByPrefab.Count, "ServerSync:DropNSpawnCharacter", delegate { ConfigurationDomainHost.HandleWaitingForSyncedPayload(MarkSyncedPayloadPending, "Waiting for synchronized character override payload from the server."); }, LogSyncedCharacterConfigurationLoaded, LogSyncedCharacterConfigurationFailure)); private static readonly Dictionary EmptyEntrySignatures = new Dictionary(StringComparer.OrdinalIgnoreCase); private const float DespawnRefundDropArea = 0.5f; internal static DomainDescriptor Descriptor => Module.DescriptorTyped; internal static DomainTransportMetadata TransportMetadata => Module.TransportMetadataTyped; private static DomainLoadState LoadState => ConfigurationRuntime.LoadState; private static string ReferenceConfigurationPath => Path.Combine(DropNSpawnPlugin.YamlConfigDirectoryPath, PluginSettingsFacade.GetYamlDomainFilePrefix("character") + ".reference.yml"); private static string PrimaryOverrideConfigurationPathYml => Path.Combine(DropNSpawnPlugin.YamlConfigDirectoryPath, PluginSettingsFacade.GetYamlDomainFilePrefix("character") + ".yml"); private static string PrimaryOverrideConfigurationPathYaml => Path.Combine(DropNSpawnPlugin.YamlConfigDirectoryPath, PluginSettingsFacade.GetYamlDomainFilePrefix("character") + ".yaml"); private static string FullScaffoldConfigurationPath => Path.Combine(DropNSpawnPlugin.YamlConfigDirectoryPath, PluginSettingsFacade.GetYamlDomainFilePrefix("character") + ".full.yml"); internal static bool ShouldReloadForPath(string? path) { if (PluginSettingsFacade.IsEligibleOverrideConfigurationPath(path)) { return IsOverrideConfigurationFileName(Path.GetFileName(path ?? "")); } return false; } private static bool ShouldApplyLocally() { return PluginSettingsFacade.IsCharacterDomainEnabled(); } internal static void Initialize() { lock (Sync) { if (!_initialized) { LoadConfiguration(); _initialized = true; } } } internal static void ReloadConfiguration() { lock (Sync) { LoadConfiguration(); ApplyIfReady(); } } internal static void MarkSyncedPayloadPending() { lock (Sync) { ConfigurationRuntime.MarkSyncedPayloadPending(DropNSpawnPlugin.IsSourceOfTruth, delegate { Volatile.Write(ref _synchronizedPayloadReady, value: false); }); } } internal static void EnterPendingSyncedPayloadState() { lock (Sync) { Dictionary previousEntrySignatures = CloneCurrentEntrySignaturesByPrefab(); HashSet previouslyAppliedPrefabs = BuildLastAppliedPrefabs(); ConfigurationRuntime.EnterPendingSyncedPayloadState(DropNSpawnPlugin.IsSourceOfTruth, ResetLoadedConfigurationState, delegate { _configurationSignature = ""; _lastAppliedSynchronizedPayloadReady = false; RestoreSnapshots(previouslyAppliedPrefabs); RestoreTrackedCharacterDrops(previouslyAppliedPrefabs); RefreshVneiCompatibility(previousEntrySignatures); }); } } private static bool CanUseCurrentRuntimeState() { if (!DropNSpawnPlugin.IsSourceOfTruth && !Volatile.Read(ref _synchronizedPayloadReady)) { return _lastCommittedAuthorityEpoch == NetworkPayloadSyncSupport.CurrentAuthorityEpoch; } return true; } private static HashSet BuildLastAppliedPrefabs() { HashSet hashSet = new HashSet(StringComparer.OrdinalIgnoreCase); if (!_lastAppliedDomainEnabled.GetValueOrDefault()) { return hashSet; } foreach (string key in _lastAppliedEntrySignaturesByPrefab.Keys) { hashSet.Add(key); } return hashSet; } internal static bool HandleExpandWorldDataReady() { lock (Sync) { if (!DropNSpawnPlugin.IsSourceOfTruth) { return false; } string text = NetworkPayloadSyncSupport.ComputeCharacterConfigurationSignature(_configuration); if (string.Equals(text, _configurationSignature, StringComparison.Ordinal)) { return false; } _configurationSignature = text; ConfigurationDomainHost.PublishSyncedPayload(DropNSpawnPlugin.IsSourceOfTruth, Descriptor, _configuration, _configurationSignature); ApplyIfReady(); return true; } } internal static void ApplySyncedPayload() { lock (Sync) { Dictionary previousEntrySignatures = CloneCurrentEntrySignaturesByPrefab(); ConfigurationRuntime.ApplySyncedPayload(delegate { RefreshVneiCompatibility(previousEntrySignatures, CloneCurrentEntrySignaturesByPrefab()); ApplyIfReady(); }); } } internal static void OnGameDataReady(string source) { lock (Sync) { if (!_initialized) { Initialize(); } if (!IsGameDataReady()) { return; } int gameDataSignature = ComputeGameDataSignature(); if (!CharacterDropRuntime.IsGameDataAlreadyProcessed(gameDataSignature)) { int snapshotSignature = ComputeSnapshotSignature(); if (CharacterDropRuntime.NeedsSnapshotBuild(snapshotSignature)) { CharacterDropRuntime.ScheduleSnapshotBuild(source, gameDataSignature, snapshotSignature, EnumerateRelevantPrefabs()); } else { CompleteGameDataReadyLocked(source, gameDataSignature, snapshotSignature); } } } } internal static bool HasPendingSnapshotBuildWork() { lock (Sync) { return CharacterDropRuntime.HasPendingSnapshotBuildWork(); } } internal static bool ProcessPendingSnapshotBuildStep(float deadline) { lock (Sync) { return CharacterDropRuntime.ProcessPendingSnapshotBuildStep(deadline, CaptureSnapshot, CompleteGameDataReadyLocked); } } internal static bool TryWriteFullScaffoldConfigurationFile(out string path, out string error) { lock (Sync) { path = FullScaffoldConfigurationPath; error = ""; if (!IsGameDataReady() && !CharacterDropRuntime.HasSnapshots()) { error = "Character game data is not ready yet."; return false; } CaptureSnapshotsIfNeeded(); Directory.CreateDirectory(DropNSpawnPlugin.YamlConfigDirectoryPath); File.WriteAllText(path, BuildFullScaffoldConfigurationTemplate()); DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)("Wrote character full scaffold configuration to " + path + ".")); return true; } } internal static void RefreshReferenceConfigurationFile() { lock (Sync) { if (IsGameDataReady()) { CaptureSnapshotsIfNeeded(); WriteReferenceConfigurationFile(BuildReferenceConfigurationTemplate(), "Updated character reference configuration at " + ReferenceConfigurationPath + "."); ReferenceRefreshSupport.RecordAutoUpdateState("character", ReferenceConfigurationPath, ComputeReferenceSourceSignature(), null, "2026-03-26-full-rewrite-v1"); } } } private static bool IsGameDataReady() { if ((Object)(object)ZNetScene.instance != (Object)null) { return (Object)(object)ObjectDB.instance != (Object)null; } return false; } private static void EnsureReferenceArtifactsUpToDate() { if (!IsGameDataReady()) { return; } string sourceSignature = ComputeReferenceSourceSignature(); if (!File.Exists(ReferenceConfigurationPath)) { if (PluginSettingsFacade.ShouldAutoCreateMissingReferenceFiles()) { CaptureSnapshotsIfNeeded(); WriteReferenceConfigurationFile(BuildReferenceConfigurationTemplate(), "Created character reference configuration at " + ReferenceConfigurationPath + "."); ReferenceRefreshSupport.RecordAutoUpdateState("character", ReferenceConfigurationPath, sourceSignature, null, "2026-03-26-full-rewrite-v1"); } } else if (PluginSettingsFacade.ShouldAutoUpdateReferenceFiles() && !ReferenceRefreshSupport.ShouldSkipAutoUpdate("character", ReferenceConfigurationPath, sourceSignature, "2026-03-26-full-rewrite-v1")) { CaptureSnapshotsIfNeeded(); WriteReferenceConfigurationFile(BuildReferenceConfigurationTemplate(), "Updated character reference configuration at " + ReferenceConfigurationPath + "."); ReferenceRefreshSupport.RecordAutoUpdateState("character", ReferenceConfigurationPath, sourceSignature, null, "2026-03-26-full-rewrite-v1"); } } private static bool EnsurePrimaryOverrideConfigurationFileExists() { if (File.Exists(PrimaryOverrideConfigurationPathYml) || File.Exists(PrimaryOverrideConfigurationPathYaml) || EnumerateSupplementalOverrideConfigurationPaths().Any()) { return false; } if (!IsGameDataReady() || !CharacterDropRuntime.HasSnapshots()) { return false; } Directory.CreateDirectory(DropNSpawnPlugin.YamlConfigDirectoryPath); File.WriteAllText(PrimaryOverrideConfigurationPathYml, BuildPrimaryOverrideConfigurationTemplate()); DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)("Created character override configuration at " + PrimaryOverrideConfigurationPathYml + ".")); return true; } private static void LoadConfiguration() { Dictionary previousEntrySignatures = CloneCurrentEntrySignaturesByPrefab(); if (DropNSpawnPlugin.IsSourceOfTruth) { EnsurePrimaryOverrideConfigurationFileExists(); if (ConfigurationRuntime.ReloadSourceOfTruth(EnumerateOverrideConfigurationPaths().ToList()) == DomainReloadOutcome.Loaded) { RefreshVneiCompatibility(previousEntrySignatures); } } else if (ConfigurationRuntime.ReloadSynced() == DomainReloadOutcome.Loaded) { RefreshVneiCompatibility(previousEntrySignatures, CloneCurrentEntrySignaturesByPrefab()); } } private static void RefreshVneiCompatibility(Dictionary previousEntrySignatures) { RefreshVneiCompatibility(previousEntrySignatures, CloneCurrentEntrySignaturesByPrefab()); } private static void RefreshVneiCompatibility(Dictionary previousEntrySignatures, Dictionary currentEntrySignatures) { VneiCompatibility.RefreshCharacterPrefabs(BuildDirtyPrefabs(previousEntrySignatures, currentEntrySignatures)); } private static void CompleteGameDataReadyLocked(string source, int gameDataSignature, int snapshotSignature) { if (DropNSpawnPlugin.IsSourceOfTruth && !_referenceArtifactsAutoRefreshConsumed) { EnsureReferenceArtifactsUpToDate(); _referenceArtifactsAutoRefreshConsumed = true; } if (DropNSpawnPlugin.IsSourceOfTruth && EnsurePrimaryOverrideConfigurationFileExists()) { LoadConfiguration(); } ApplyIfReady(); DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)("Character drops processed after " + source + ".")); } private static void ResetLoadedConfigurationState() { ActiveEntriesByPrefab.Clear(); CurrentEntrySignaturesByPrefab.Clear(); ConfiguredCharacterDropPrefabs.Clear(); PrefabsWithCharacterDropOverrides.Clear(); InvalidEntryWarnings.Clear(); CharacterDropRuntime.Reset(); CharacterDespawnRuntime.Reset(); BossTamedPressureRules.Clear(); BossTamedPressureRuntime.Configure(Array.Empty()); _compiledState = CharacterCompiledState.Empty; _compiledStateConfigurationSignature = ""; _compiledStateGameDataSignature = null; _cachedFrameGameDataSignatureFrame = -1; _cachedFrameGameDataSignatureValue = 0; _configuration = new List(); Volatile.Write(ref _synchronizedPayloadReady, value: false); } private static List CloneAndNormalizeConfigurationEntries(List? configuration, string sourceName) { List list = NetworkPayloadSyncSupport.CloneEntries(Descriptor, configuration); foreach (CharacterDropPrefabEntry item in list) { NormalizeEntry(item); item.SourcePath = (string.IsNullOrWhiteSpace(item.SourcePath) ? sourceName : item.SourcePath); } return list; } private static List PrepareLocalConfigurationEntries(List? configuration, string sourceName, List warnings) { List list = CloneAndNormalizeConfigurationEntries(configuration, sourceName); List list2 = new List(); foreach (CharacterDropPrefabEntry item in list) { if (TryAcceptLocalConfigurationEntry(item, warnings)) { list2.Add(item); } } return list2; } private static bool TryAcceptLocalConfigurationEntry(CharacterDropPrefabEntry entry, List warnings) { if (!entry.Enabled) { return true; } string text = CreateConfigurationContext(entry); bool flag = entry.CharacterDrop != null; bool flag2 = entry.Despawn != null; if (entry.BossTamedPressure != null) { if (!string.IsNullOrWhiteSpace(entry.Prefab) || flag || flag2 || entry.Conditions != null) { warnings.Add("Entry '" + text + "' defines bossTamedPressure, which is a global character-domain block and must not be combined with prefab, conditions, characterDrop, or despawn."); return false; } return true; } if (string.IsNullOrWhiteSpace(entry.Prefab)) { warnings.Add("Entry '" + text + "' is missing required prefab."); return false; } if (!flag && !flag2) { warnings.Add("Entry '" + text + "' does not define characterDrop or despawn."); return false; } if (!TryResolveConfiguredCharacterPrefab(entry.Prefab, out var hasCharacterComponent, out var hasCharacterDropComponent)) { warnings.Add("Entry '" + text + "' references unknown character prefab '" + entry.Prefab + "'."); return false; } if (!hasCharacterComponent) { warnings.Add("Entry '" + text + "' references '" + entry.Prefab + "', but it is not a Character prefab."); return false; } if (flag && !hasCharacterDropComponent) { warnings.Add("Entry '" + text + "' references '" + entry.Prefab + "', but it is not a CharacterDrop prefab."); return false; } return true; } private static bool TryResolveConfiguredCharacterPrefab(string prefabName, out bool hasCharacterComponent, out bool hasCharacterDropComponent) { hasCharacterComponent = true; hasCharacterDropComponent = true; if ((Object)(object)ZNetScene.instance == (Object)null || string.IsNullOrWhiteSpace(prefabName)) { return true; } GameObject prefab = ZNetScene.instance.GetPrefab(prefabName.Trim()); if ((Object)(object)prefab == (Object)null) { hasCharacterComponent = false; hasCharacterDropComponent = false; return false; } hasCharacterComponent = (Object)(object)prefab.GetComponent() != (Object)null; hasCharacterDropComponent = (Object)(object)prefab.GetComponent() != (Object)null; return true; } private static SyncedCharacterConfigurationState BuildSyncedConfigurationState(List configuration, string sourceName) { using (BeginInvalidEntryWarningSuppressionForSyncedClientBuild(sourceName)) { SyncedCharacterConfigurationState syncedCharacterConfigurationState = new SyncedCharacterConfigurationState(); foreach (CharacterDropPrefabEntry item in CloneAndNormalizeConfigurationEntries(configuration, sourceName)) { if (item.BossTamedPressure != null) { syncedCharacterConfigurationState.Configuration.Add(item); if (item.Enabled) { syncedCharacterConfigurationState.BossTamedPressureRules.Add(item.BossTamedPressure); } } else if (!string.IsNullOrWhiteSpace(item.Prefab)) { RemoveEffectiveConfigurationEntry(syncedCharacterConfigurationState.Configuration, syncedCharacterConfigurationState.ActiveEntriesByPrefab, item.Prefab, item.RuleId); if (item.Enabled) { syncedCharacterConfigurationState.Configuration.Add(item); GetOrCreateActiveEntries(syncedCharacterConfigurationState.ActiveEntriesByPrefab, item.Prefab).Add(item); } } } foreach (string key in syncedCharacterConfigurationState.ActiveEntriesByPrefab.Keys) { syncedCharacterConfigurationState.ConfiguredCharacterDropPrefabs.Add(key); } RebuildCharacterDropOverridePrefabSet(syncedCharacterConfigurationState.ActiveEntriesByPrefab, syncedCharacterConfigurationState.PrefabsWithCharacterDropOverrides); syncedCharacterConfigurationState.ConfigurationSignature = NetworkPayloadSyncSupport.ComputeCharacterConfigurationSignature(syncedCharacterConfigurationState.Configuration); syncedCharacterConfigurationState.EntrySignaturesByPrefab = BuildActiveEntrySignaturesByPrefab(syncedCharacterConfigurationState.ActiveEntriesByPrefab); return syncedCharacterConfigurationState; } } private static void CommitSyncedConfigurationState(SyncedCharacterConfigurationState state, string payloadToken) { ResetLoadedConfigurationState(); _configuration = state.Configuration; foreach (var (key, value) in state.ActiveEntriesByPrefab) { ActiveEntriesByPrefab[key] = value; } ReplaceEntrySignatures(CurrentEntrySignaturesByPrefab, state.EntrySignaturesByPrefab); foreach (string configuredCharacterDropPrefab in state.ConfiguredCharacterDropPrefabs) { ConfiguredCharacterDropPrefabs.Add(configuredCharacterDropPrefab); } foreach (string prefabsWithCharacterDropOverride in state.PrefabsWithCharacterDropOverrides) { PrefabsWithCharacterDropOverrides.Add(prefabsWithCharacterDropOverride); } BossTamedPressureRules.Clear(); BossTamedPressureRules.AddRange(state.BossTamedPressureRules); BossTamedPressureRuntime.Configure(BossTamedPressureRules); _configurationSignature = state.ConfigurationSignature; LoadState.LastLoadedPayload = payloadToken; LoadState.LastRejectedPayload = ""; LoadState.PendingStrictPayload = ""; LoadState.LastRejectedValidationKey = ""; Volatile.Write(ref _synchronizedPayloadReady, value: true); _lastCommittedAuthorityEpoch = (DropNSpawnPlugin.IsSourceOfTruth ? null : new int?(NetworkPayloadSyncSupport.CurrentAuthorityEpoch)); } private static LocalLoadResult ParseLocalConfigurationDocuments(List documents) { List list = new List(); List list2 = new List(); List list3 = new List(); int num = 0; int num2 = 0; foreach (ConfigurationLoadSupport.LocalYamlDocument document in documents) { if (document.ReadError != null) { list2.Add("Failed to read " + document.Path + ". " + document.ReadError); continue; } try { ParsedCharacterConfigurationDocument parsedCharacterConfigurationDocument = ParseConfiguration(document.Yaml ?? "", document.Path); list3.AddRange(parsedCharacterConfigurationDocument.Warnings); num += parsedCharacterConfigurationDocument.Configuration.Count; List collection = PrepareLocalConfigurationEntries(parsedCharacterConfigurationDocument.Configuration, document.Path, list3); list.AddRange(collection); num2++; } catch (Exception ex) { list2.Add($"Failed to parse {document.Path}{FormatYamlExceptionLocation(ex)}. Character override YAML must start with a root list like '- prefab: ...'. {ex}"); } } return new LocalLoadResult { Entries = list, Errors = list2, Warnings = list3, ParsedEntryCount = num, LoadedFileCount = num2 }; } private static void RejectLocalConfigurationPayload(string payload, IEnumerable errors) { if (string.Equals(LoadState.LastRejectedPayload, payload, StringComparison.Ordinal)) { return; } LoadState.LastRejectedPayload = payload; LoadState.PendingStrictPayload = ""; LoadState.LastRejectedValidationKey = ""; DropNSpawnPlugin.DropNSpawnLogger.LogError((object)"Rejected character reload. Keeping the previous authoritative character configuration."); foreach (string item in errors.Where((string message) => !string.IsNullOrWhiteSpace(message)).Distinct(StringComparer.OrdinalIgnoreCase)) { DropNSpawnPlugin.DropNSpawnLogger.LogError((object)item); } } private static void LoadLocalConfiguration(List documents) { if (documents.Count == 0) { DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)"Loaded 0 character drop configuration(s) from 0 override file(s)."); return; } int num = 0; int num2 = 0; List list = new List(); foreach (ConfigurationLoadSupport.LocalYamlDocument document in documents) { if (document.ReadError != null) { DropNSpawnPlugin.DropNSpawnLogger.LogError((object)("Failed to read " + document.Path + ". " + document.ReadError)); continue; } try { ParsedCharacterConfigurationDocument parsedCharacterConfigurationDocument = ParseConfiguration(document.Yaml ?? "", document.Path); list.AddRange(parsedCharacterConfigurationDocument.Warnings); num2 += parsedCharacterConfigurationDocument.Configuration.Count; MergeConfiguration(PrepareLocalConfigurationEntries(parsedCharacterConfigurationDocument.Configuration, document.Path, list)); num++; } catch (Exception ex) { DropNSpawnPlugin.DropNSpawnLogger.LogError((object)$"Failed to parse {document.Path}{FormatYamlExceptionLocation(ex)}. Character override YAML must start with a root list like '- prefab: ...'. {ex}"); } } if (list.Count > 0) { LogPartiallyAcceptedLocalConfiguration(num2, _configuration.Count, list); } DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)$"Loaded {ActiveEntriesByPrefab.Count} character drop configuration(s) from {num} override file(s)."); } private static void MergeConfiguration(List configuration) { foreach (CharacterDropPrefabEntry entry2 in configuration) { if (entry2.BossTamedPressure != null) { _configuration.RemoveAll((CharacterDropPrefabEntry existing) => existing.BossTamedPressure != null && string.Equals(existing.RuleId, entry2.RuleId, StringComparison.Ordinal)); if (entry2.Enabled) { _configuration.Add(entry2); } } else if (!string.IsNullOrWhiteSpace(entry2.Prefab)) { RemoveEffectiveConfigurationEntry(entry2.Prefab, entry2.RuleId); if (entry2.Enabled) { _configuration.Add(entry2); GetOrCreateActiveEntries(entry2.Prefab).Add(entry2); } } } BossTamedPressureRules.Clear(); BossTamedPressureRules.AddRange(from entry in _configuration where entry.Enabled && entry.BossTamedPressure != null select entry.BossTamedPressure); BossTamedPressureRuntime.Configure(BossTamedPressureRules); ConfiguredCharacterDropPrefabs.Clear(); foreach (string key in ActiveEntriesByPrefab.Keys) { ConfiguredCharacterDropPrefabs.Add(key); } RebuildCharacterDropOverridePrefabSet(ActiveEntriesByPrefab, PrefabsWithCharacterDropOverrides); } private static void RebuildCharacterDropOverridePrefabSet(Dictionary> activeEntriesByPrefab, HashSet target) { target.Clear(); foreach (var (item, source) in activeEntriesByPrefab) { if (source.Any((CharacterDropPrefabEntry entry) => entry.CharacterDrop != null)) { target.Add(item); } } } private static bool RemoveEffectiveConfigurationEntry(string prefabName, string ruleId) { return RemoveEffectiveConfigurationEntry(_configuration, ActiveEntriesByPrefab, prefabName, ruleId); } private static bool RemoveEffectiveConfigurationEntry(List configuration, Dictionary> activeEntriesByPrefab, string prefabName, string ruleId) { bool result = false; for (int num = configuration.Count - 1; num >= 0; num--) { CharacterDropPrefabEntry characterDropPrefabEntry = configuration[num]; if (string.Equals(characterDropPrefabEntry.Prefab, prefabName, StringComparison.OrdinalIgnoreCase) && string.Equals(characterDropPrefabEntry.RuleId, ruleId, StringComparison.Ordinal)) { configuration.RemoveAt(num); result = true; } } if (activeEntriesByPrefab.TryGetValue(prefabName, out List 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); } } return result; } private static ParsedCharacterConfigurationDocument ParseConfiguration(string yaml, string? sourcePath) { ParsedCharacterConfigurationDocument parsedCharacterConfigurationDocument = new ParsedCharacterConfigurationDocument(); if (string.IsNullOrWhiteSpace(yaml)) { return parsedCharacterConfigurationDocument; } checked { using StringReader input = new StringReader(yaml); YamlStream yamlStream = new YamlStream(); yamlStream.Load(input); if (yamlStream.Documents.Count == 0) { return parsedCharacterConfigurationDocument; } YamlSequenceNode obj = yamlStream.Documents[0].RootNode as YamlSequenceNode; if (obj == null) { Mark start = yamlStream.Documents[0].RootNode.Start; Mark end = yamlStream.Documents[0].RootNode.End; throw new YamlException(in start, in end, "Character override YAML root must be a sequence."); } foreach (YamlNode child in obj.Children) { if (!(child is YamlMappingNode yamlMappingNode)) { parsedCharacterConfigurationDocument.Warnings.Add("Skipped character YAML node at " + FormatYamlNodeLocation(sourcePath, child.Start) + ". Expected a list item object like '- prefab: Fox' but found " + DescribeYamlNode(child) + "."); continue; } try { string input2 = SerializeYamlNode(yamlMappingNode); CharacterDropPrefabEntry characterDropPrefabEntry = Deserializer.Deserialize(input2) ?? new CharacterDropPrefabEntry(); characterDropPrefabEntry.SourceLine = (int)yamlMappingNode.Start.Line; characterDropPrefabEntry.SourceColumn = (int)yamlMappingNode.Start.Column; parsedCharacterConfigurationDocument.Configuration.Add(characterDropPrefabEntry); } catch (Exception ex) { parsedCharacterConfigurationDocument.Warnings.Add("Skipped invalid character entry at " + FormatYamlNodeLocation(sourcePath, yamlMappingNode.Start) + ". " + FormatEntryParseFailure(ex)); } } return parsedCharacterConfigurationDocument; } } private static string SerializeYamlNode(YamlNode node) { YamlStream yamlStream = new YamlStream(new YamlDocument(node)); using StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture); yamlStream.Save(stringWriter, assignAnchors: false); return stringWriter.ToString(); } private static string DescribeYamlNode(YamlNode node) { if (node is YamlScalarNode yamlScalarNode) { string text = yamlScalarNode.Value ?? ""; if (text.Length != 0) { return "scalar '" + text + "'"; } return "an empty scalar"; } if (node is YamlSequenceNode) { return "a nested sequence"; } if (node is YamlMappingNode) { return "a mapping"; } return "an unknown YAML node"; } private static string FormatYamlNodeLocation(string? sourcePath, Mark mark) { string text = (string.IsNullOrWhiteSpace(sourcePath) ? "inline YAML" : Path.GetFileName(sourcePath)); if (mark.Line > 0) { text = text + ":" + mark.Line.ToString(CultureInfo.InvariantCulture); } return text; } private static string FormatEntryParseFailure(Exception ex) { if (ex is YamlException ex2) { return ex2.Message; } return ex.Message; } private static void NormalizeEntry(CharacterDropPrefabEntry entry) { entry.Prefab = (entry.Prefab ?? "").Trim(); if (entry.CharacterDrop != null) { CharacterDropDefinition characterDrop = entry.CharacterDrop; if (characterDrop.Drops == null) { List list2 = (characterDrop.Drops = new List()); } foreach (CharacterDropEntryDefinition drop in entry.CharacterDrop.Drops) { drop.Item = (drop.Item ?? "").Trim(); IntRangeDefinition? amount = drop.Amount; if (amount != null && amount.HasValues()) { drop.AmountMin = RangeFormatting.GetMin(drop.Amount, drop.AmountMin); drop.AmountMax = RangeFormatting.GetMax(drop.Amount, drop.AmountMin, drop.AmountMax); } } } if (entry.Despawn != null) { entry.Despawn.Range = (entry.Despawn.Range.HasValue ? new float?(Mathf.Clamp(entry.Despawn.Range.Value, 0f, 128f)) : null); entry.Despawn.Delay = (entry.Despawn.Delay.HasValue ? new float?(Mathf.Clamp(entry.Despawn.Delay.Value, 0f, 300f)) : null); IEnumerable refunds = entry.Despawn.Refunds; foreach (DespawnRefundEntryDefinition item in refunds ?? Enumerable.Empty()) { item.Item = (item.Item ?? "").Trim(); item.Amount = Math.Max(1, item.Amount.GetValueOrDefault(1)); } } if (entry.BossTamedPressure != null) { NormalizeBossTamedPressure(entry.BossTamedPressure); } entry.RuleId = NormalizeOptionalRuleId(entry.RuleId) ?? BuildRuleId(entry); } private static void NormalizeBossTamedPressure(BossTamedPressureDefinition definition) { definition.BossPrefabs = NormalizeStringList(definition.BossPrefabs); definition.ExcludedBossPrefabs = NormalizeStringList(definition.ExcludedBossPrefabs); if (definition.Targets != null) { definition.Targets.Range = (definition.Targets.Range.HasValue ? new float?(Mathf.Clamp(definition.Targets.Range.Value, 0f, 128f)) : null); definition.Targets.ScanInterval = (definition.Targets.ScanInterval.HasValue ? new float?(Mathf.Clamp(definition.Targets.ScanInterval.Value, 0.25f, 30f)) : null); definition.Targets.MaxPerBoss = (definition.Targets.MaxPerBoss.HasValue ? new int?(Math.Max(1, Math.Min(definition.Targets.MaxPerBoss.Value, 128))) : null); definition.Targets.ExcludedTamedPrefabs = NormalizeStringList(definition.Targets.ExcludedTamedPrefabs); definition.Targets.ExtraPressuredPrefabs = NormalizeStringList(definition.Targets.ExtraPressuredPrefabs); } if (definition.Pressure != null) { definition.Pressure.DamageInterval = (definition.Pressure.DamageInterval.HasValue ? new float?(Mathf.Clamp(definition.Pressure.DamageInterval.Value, 0.25f, 30f)) : null); definition.Pressure.DamagePercentPerSecond = (definition.Pressure.DamagePercentPerSecond.HasValue ? new float?(Mathf.Clamp(definition.Pressure.DamagePercentPerSecond.Value, 0f, 1f)) : null); definition.Pressure.DamageMinBaseHealth = (definition.Pressure.DamageMinBaseHealth.HasValue ? new float?(Mathf.Clamp(definition.Pressure.DamageMinBaseHealth.Value, 0f, 100000f)) : null); definition.Pressure.IncomingDamageMultiplier = (definition.Pressure.IncomingDamageMultiplier.HasValue ? new float?(Mathf.Clamp(definition.Pressure.IncomingDamageMultiplier.Value, 0f, 10f)) : null); definition.Pressure.OutgoingDamageMultiplier = (definition.Pressure.OutgoingDamageMultiplier.HasValue ? new float?(Mathf.Clamp(definition.Pressure.OutgoingDamageMultiplier.Value, 0f, 10f)) : null); } definition.Message = definition.Message?.Trim(); definition.MessageInterval = (definition.MessageInterval.HasValue ? new float?(Mathf.Clamp(definition.MessageInterval.Value, 0f, 300f)) : null); } private static List? NormalizeStringList(List? values) { return (from value in values?.Select((string value) => (value ?? "").Trim()) where value.Length > 0 select value).Distinct(StringComparer.OrdinalIgnoreCase).ToList(); } private static string BuildRuleId(CharacterDropPrefabEntry entry) { CharacterDropPrefabEntry entry2 = new CharacterDropPrefabEntry { Prefab = entry.Prefab, Enabled = true, Conditions = entry.Conditions, CharacterDrop = entry.CharacterDrop, Despawn = entry.Despawn, BossTamedPressure = entry.BossTamedPressure }; return entry.Prefab + ":" + NetworkPayloadSyncSupport.ComputeCharacterEntryIdentitySignature(entry2); } private static string? NormalizeOptionalRuleId(string? ruleId) { if (ruleId == null) { return null; } string text = ruleId.Trim(); if (text.Length != 0) { return text; } return null; } private static List GetOrCreateActiveEntries(string prefabName) { if (!ActiveEntriesByPrefab.TryGetValue(prefabName, out List value)) { value = new List(); ActiveEntriesByPrefab[prefabName] = value; } return value; } private static bool HasCustomDropHandling(List? drops) { return drops?.Any((CharacterDropEntryDefinition drop) => (drop.AmountLimit.HasValue && drop.AmountLimit.Value >= 0) || drop.DropInStack.GetValueOrDefault()) ?? false; } private static bool HasCustomDropHandling(IReadOnlyList? drops) { return drops?.Any((CompiledCharacterDropDefinition drop) => (drop.AmountLimit.HasValue && drop.AmountLimit.Value >= 0) || drop.DropInStack) ?? false; } internal static void ApplyGlobalDropInStack(ref List> drops, Vector3 centerPos, float dropArea) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) if (!PluginSettingsFacade.IsGlobalCharacterDropInStackEnabled() || drops.Count == 0) { return; } List> list = new List>(drops.Count); bool flag = false; foreach (KeyValuePair drop in drops) { if (!ShouldDropInStack(drop.Key, drop.Value, explicitDropInStack: false)) { list.Add(drop); continue; } SpawnStackedDrops(drop.Key, drop.Value, centerPos, dropArea); flag = true; } if (flag) { drops = list; } } internal static List? OverrideConditionalDrops(CharacterDrop characterDrop) { CachedCharacterRuntimeDropResolution resolution; lock (Sync) { if (!TryResolveRuntimeDropResolutionLocked(characterDrop, out Character _, out resolution) || resolution == null || !resolution.HasMatchedRuntimeRule || resolution.OverrideDrops == null) { return null; } } List drops = characterDrop.m_drops; characterDrop.m_drops = resolution.OverrideDrops; return drops; } internal static bool TryHandleConfiguredDeath(CharacterDrop characterDrop) { //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) Character character; CachedCharacterRuntimeDropResolution resolution; lock (Sync) { if (!TryResolveRuntimeDropResolutionLocked(characterDrop, out character, out resolution) || (Object)(object)character == (Object)null || resolution == null || !resolution.HasMatchedRuntimeRule) { return false; } } object obj = DropsEnabledField?.GetValue(characterDrop); if (obj is bool && !(bool)obj) { return true; } if (!resolution.HasCustomDropHandling) { return false; } List list = GenerateConfiguredDrops(character, resolution.Definitions); if (list.Count == 0) { return true; } Vector3 centerPos = character.GetCenterPoint() + ((Component)characterDrop).transform.TransformVector(characterDrop.m_spawnOffset); DropConfiguredItems(list, centerPos, 0.5f); return true; } internal static bool BeginOnePerPlayerNearbyPlayerScope(CharacterDrop characterDrop) { if (PluginSettingsFacade.GetCharacterDropOnePerPlayerNearbyRange() <= 0f) { return false; } if (OnePerPlayerScopeDepth == 0) { OnePerPlayerScopeCharacterDrop = characterDrop; } OnePerPlayerScopeDepth++; return true; } internal static void EndOnePerPlayerNearbyPlayerScope() { if (OnePerPlayerScopeDepth > 0) { OnePerPlayerScopeDepth--; if (OnePerPlayerScopeDepth == 0) { OnePerPlayerScopeCharacterDrop = null; } } } internal static bool TryGetScopedOnePerPlayerNearbyPlayerCount(out int playerCount) { playerCount = 0; float characterDropOnePerPlayerNearbyRange = PluginSettingsFacade.GetCharacterDropOnePerPlayerNearbyRange(); if (characterDropOnePerPlayerNearbyRange <= 0f || OnePerPlayerScopeDepth <= 0 || (Object)(object)OnePerPlayerScopeCharacterDrop == (Object)null) { return false; } playerCount = CountNearbyPlayers(OnePerPlayerScopeCharacterDrop, null, characterDropOnePerPlayerNearbyRange); return true; } [IteratorStateMachine(typeof(d__110))] private static IEnumerable EnumerateOverrideConfigurationPaths() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__110(-2); } private static IEnumerable EnumerateSupplementalOverrideConfigurationPaths() { return DomainConfigurationFileSupport.EnumerateSupplementalOverrideConfigurationPaths("character", IsOverrideConfigurationFileName); } private static bool IsOverrideConfigurationFileName(string fileName) { if (string.IsNullOrWhiteSpace(fileName)) { return false; } if (!fileName.Equals(PluginSettingsFacade.GetYamlDomainFilePrefix("character") + ".yml", StringComparison.OrdinalIgnoreCase) && !fileName.Equals(PluginSettingsFacade.GetYamlDomainFilePrefix("character") + ".yaml", StringComparison.OrdinalIgnoreCase)) { if (fileName.StartsWith(PluginSettingsFacade.GetYamlDomainSupplementalPrefix("character"), StringComparison.OrdinalIgnoreCase)) { if (!fileName.EndsWith(".yml", StringComparison.OrdinalIgnoreCase)) { return fileName.EndsWith(".yaml", StringComparison.OrdinalIgnoreCase); } return true; } return false; } return true; } private static void CaptureSnapshotsIfNeeded() { int num = CharacterDropRuntime.SnapshotCount(); CharacterDropRuntime.CaptureSnapshotsIfNeeded(EnumerateRelevantPrefabs(), CaptureSnapshot); if (num == 0 && CharacterDropRuntime.SnapshotCount() > 0) { DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)$"Captured {CharacterDropRuntime.SnapshotCount()} character drop prefab snapshot(s)."); } } private static void RefreshSnapshots() { CharacterDropRuntime.RefreshSnapshots(EnumerateRelevantPrefabs(), CaptureSnapshot); if (CharacterDropRuntime.SnapshotCount() > 0) { DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)$"Captured {CharacterDropRuntime.SnapshotCount()} character drop prefab snapshot(s)."); } } private static void EnsureCompiledState() { if (IsGameDataReady()) { int num = ComputeGameDataSignature(); if (_compiledStateGameDataSignature != num || !string.Equals(_compiledStateConfigurationSignature, _configurationSignature, StringComparison.Ordinal)) { _compiledState = BuildCompiledState(); _compiledStateGameDataSignature = num; _compiledStateConfigurationSignature = _configurationSignature; } } } private static CharacterCompiledState BuildCompiledState() { CharacterCompiledState characterCompiledState = new CharacterCompiledState(); foreach (KeyValuePair> item in ActiveEntriesByPrefab) { item.Deconstruct(out var key, out var value); string key2 = key; List list = value; SortedDictionary sortedDictionary = new SortedDictionary(StringComparer.Ordinal); List list2 = new List(); CharacterRuntimeDropCacheState characterRuntimeDropCacheState = new CharacterRuntimeDropCacheState(); HashSet destination = null; HashSet destination2 = null; foreach (CharacterDropPrefabEntry item2 in list) { if (item2.CharacterDrop == null) { continue; } CompiledCharacterDropRule compiledCharacterDropRule = CompileCharacterDropRule(item2); if (compiledCharacterDropRule.Drops.Count == 0) { continue; } bool flag = DropConditionEvaluator.HasCharacterConditions(item2.Conditions); CompiledCharacterDropRule compiledCharacterDropRule2 = null; foreach (CompiledCharacterDropDefinition drop in compiledCharacterDropRule.Drops) { if (!flag && !RequiresRuntimeCharacterDropHandling(drop)) { CollectionExtensions.TryAdd((IDictionary)sortedDictionary, drop.Fingerprint, drop); continue; } if (compiledCharacterDropRule2 == null) { compiledCharacterDropRule2 = new CompiledCharacterDropRule { Entry = item2 }; } compiledCharacterDropRule2.Drops.Add(drop); } if (compiledCharacterDropRule2 != null && compiledCharacterDropRule2.Drops.Count > 0) { list2.Add(compiledCharacterDropRule2); ConditionsDefinition conditions = item2.Conditions; characterRuntimeDropCacheState.UsesLevel |= (conditions != null && (conditions.Level?.HasValues()).GetValueOrDefault()) || (conditions != null && conditions.MinLevel.HasValue) || (conditions?.MaxLevel.HasValue ?? false); characterRuntimeDropCacheState.UsesFaction |= HasConfiguredConditionValues(conditions?.Factions); characterRuntimeDropCacheState.UsesState |= HasConfiguredConditionValues(conditions?.States); characterRuntimeDropCacheState.UsesTimeOfDay |= conditions?.TimeOfDay != null; characterRuntimeDropCacheState.UsesRequiredEnvironments |= HasConfiguredConditionValues(conditions?.RequiredEnvironments); characterRuntimeDropCacheState.UsesInsidePlayerBase |= conditions?.InsidePlayerBase.HasValue ?? false; characterRuntimeDropCacheState.IsCacheable &= !DropConditionEvaluator.HasStaticConditions(conditions); AddNormalizedConditionValues(conditions?.RequiredGlobalKeys, ref destination); AddNormalizedConditionValues(conditions?.ForbiddenGlobalKeys, ref destination2); } } if (list2.Count > 0) { characterCompiledState.RuntimeRulesByPrefab[key2] = list2; characterRuntimeDropCacheState.RequiredGlobalKeys = destination?.ToArray() ?? Array.Empty(); characterRuntimeDropCacheState.ForbiddenGlobalKeys = destination2?.ToArray() ?? Array.Empty(); characterCompiledState.RuntimeDropCachesByPrefab[key2] = characterRuntimeDropCacheState; } if (sortedDictionary.Count > 0) { List list3 = sortedDictionary.Values.ToList(); characterCompiledState.StaticDropsByPrefab[key2] = list3; characterCompiledState.StaticBuiltDropsByPrefab[key2] = BuildDrops(list3); } } return characterCompiledState; } private static CompiledCharacterDropRule CompileCharacterDropRule(CharacterDropPrefabEntry entry) { CompiledCharacterDropRule compiledCharacterDropRule = new CompiledCharacterDropRule { Entry = entry }; IEnumerable enumerable = entry.CharacterDrop?.Drops; foreach (CharacterDropEntryDefinition item in enumerable ?? Enumerable.Empty()) { if (TryCompileCharacterDropDefinition(entry, item, out CompiledCharacterDropDefinition compiledDefinition)) { compiledCharacterDropRule.Drops.Add(compiledDefinition); } } return compiledCharacterDropRule; } private static bool TryCompileCharacterDropDefinition(CharacterDropPrefabEntry entry, CharacterDropEntryDefinition definition, out CompiledCharacterDropDefinition compiledDefinition) { compiledDefinition = null; string text = BuildCompiledDropContext(entry); string text2 = (definition.Item ?? "").Trim(); if (text2.Length == 0) { WarnInvalidEntry("Entry '" + text + "' contains a character drop without an item name."); return false; } GameObject val = ResolveItemPrefab(text2, text); if ((Object)(object)val == (Object)null) { return false; } int num = Math.Max(1, definition.AmountMin.GetValueOrDefault(1)); int amountMax = Math.Max(num, definition.AmountMax ?? definition.AmountMin.GetValueOrDefault(1)); compiledDefinition = new CompiledCharacterDropDefinition { Fingerprint = BuildDropRowFingerprint(definition), Prefab = val, AmountMin = num, AmountMax = amountMax, Chance = Mathf.Max(0f, definition.Chance.GetValueOrDefault(1f)), DontScale = definition.DontScale.GetValueOrDefault(), LevelMultiplier = definition.LevelMultiplier.GetValueOrDefault(true), OnePerPlayer = definition.OnePerPlayer.GetValueOrDefault(), AmountLimit = ((definition.AmountLimit.HasValue && definition.AmountLimit.Value >= 0) ? new int?(definition.AmountLimit.Value) : null), DropInStack = definition.DropInStack.GetValueOrDefault() }; return true; } [IteratorStateMachine(typeof(d__119))] private static IEnumerable EnumeratePrefabs() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__119(-2); } [IteratorStateMachine(typeof(d__120))] private static IEnumerable EnumerateRelevantPrefabs() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__120(-2); } private static int ComputeGameDataSignature() { if (!IsGameDataReady() || (Object)(object)ZNetScene.instance == (Object)null || (Object)(object)ObjectDB.instance == (Object)null) { return 0; } int frameCount = Time.frameCount; if (_cachedFrameGameDataSignatureFrame == frameCount) { return _cachedFrameGameDataSignatureValue; } int num = HashGameObjectCollection(HashGameObjectCollection((17 * 31 + ((Object)ZNetScene.instance).GetInstanceID()) * 31 + ((Object)ObjectDB.instance).GetInstanceID(), EnumerateRelevantPrefabs()), ObjectDB.instance.m_items); _cachedFrameGameDataSignatureFrame = frameCount; _cachedFrameGameDataSignatureValue = num; return num; } private static int ComputeLiveRegistrySceneSignature() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) int num = 17; num = num * 31 + SceneManager.sceneCount; for (int i = 0; i < SceneManager.sceneCount; i++) { Scene sceneAt = SceneManager.GetSceneAt(i); num = num * 31 + ((Scene)(ref sceneAt)).handle; num = num * 31 + (((Scene)(ref sceneAt)).isLoaded ? 1 : 0); } return num; } private static int ComputeSnapshotSignature() { if (!IsGameDataReady() || (Object)(object)ZNetScene.instance == (Object)null || (Object)(object)ObjectDB.instance == (Object)null) { return 0; } return HashNamedGameObjectCollection(HashNamedGameObjectCollection(17, EnumerateRelevantPrefabs()), ObjectDB.instance.m_items); } private static string ComputeReferenceSourceSignature() { return ReferenceRefreshSupport.ComputeStableHashForKeys(from prefab in EnumerateRelevantPrefabs() select ((Object)prefab).name); } private static int HashGameObjectCollection(int hash, IEnumerable prefabs) { foreach (GameObject prefab in prefabs) { hash = hash * 31 + (((Object)(object)prefab != (Object)null) ? ((Object)prefab).GetInstanceID() : 0); } return hash; } private static int HashNamedGameObjectCollection(int hash, IEnumerable prefabs) { List list = (from prefab in prefabs where (Object)(object)prefab != (Object)null select ((Object)prefab).name).OrderBy((string name) => name, StringComparer.Ordinal).ToList(); hash = hash * 31 + list.Count; foreach (string item in list) { hash = hash * 31 + item.GetHashCode(); } return hash; } private static CharacterDropSnapshot? CaptureSnapshot(GameObject prefab) { CharacterDrop component = prefab.GetComponent(); if ((Object)(object)component == (Object)null) { return null; } return new CharacterDropSnapshot { Prefab = prefab, Drops = CloneSnapshotDrops(component.m_drops), BuiltDrops = CloneDrops(component.m_drops) }; } private static void ApplyIfReady() { if (!IsGameDataReady() || (!DropNSpawnPlugin.IsSourceOfTruth && !Volatile.Read(ref _synchronizedPayloadReady))) { return; } if (!CharacterDropRuntime.HasSnapshots()) { int gameDataSignature = ComputeGameDataSignature(); int snapshotSignature = ComputeSnapshotSignature(); if (CharacterDropRuntime.NeedsSnapshotBuild(snapshotSignature)) { CharacterDropRuntime.ScheduleSnapshotBuild("character apply gate", gameDataSignature, snapshotSignature, EnumerateRelevantPrefabs()); } return; } int num = ComputeGameDataSignature(); if (!CharacterDropRuntime.IsGameDataAlreadyProcessed(num)) { int snapshotSignature2 = ComputeSnapshotSignature(); CharacterDropRuntime.ScheduleSnapshotBuild("character apply gate", num, snapshotSignature2, EnumerateRelevantPrefabs()); return; } bool flag = ShouldApplyLocally(); Dictionary currentEntrySignatures = CloneCurrentEntrySignaturesByPrefab(); if (!StandardDomainApplySupport.IsAlreadyApplied(_lastAppliedGameDataSignature, num, _lastAppliedDomainEnabled, flag, _lastAppliedConfigurationSignature, _configurationSignature) || _lastAppliedSynchronizedPayloadReady != Volatile.Read(ref _synchronizedPayloadReady)) { RunApplyCoordinator(num, flag, currentEntrySignatures); } } private static void RecordAppliedState(int gameDataSignature, bool domainEnabled, Dictionary currentEntrySignatures) { _lastAppliedGameDataSignature = gameDataSignature; _lastAppliedDomainEnabled = domainEnabled; _lastAppliedConfigurationSignature = _configurationSignature; _lastAppliedSynchronizedPayloadReady = Volatile.Read(ref _synchronizedPayloadReady); ReplaceEntrySignatures(_lastAppliedEntrySignaturesByPrefab, currentEntrySignatures); DespawnRulesManager.MarkBootstrapScanDirty("character apply committed"); } private static void RestoreSnapshots(HashSet? targetPrefabs = null) { if (targetPrefabs == null) { foreach (CharacterDropSnapshot snapshot2 in CharacterDropRuntime.GetSnapshots()) { RestoreSnapshot(snapshot2); } return; } foreach (string targetPrefab in targetPrefabs) { if (CharacterDropRuntime.TryGetSnapshot(targetPrefab, out CharacterDropSnapshot snapshot) && snapshot != null) { RestoreSnapshot(snapshot); } } } private static void RestoreTrackedCharacterDrops(HashSet prefabs) { if (prefabs.Count == 0 || !IsGameDataReady() || !CharacterDropRuntime.HasSnapshots()) { return; } BootstrapRegisteredCharacterDropsIfNeeded(prefabs, forceRescan: true); foreach (CharacterDrop registeredCharacterDrop in GetRegisteredCharacterDrops()) { string prefabName = GetPrefabName(((Component)registeredCharacterDrop).gameObject); if (prefabs.Contains(prefabName) && CharacterDropRuntime.TryGetSnapshot(prefabName, out CharacterDropSnapshot snapshot) && snapshot != null) { registeredCharacterDrop.m_drops = snapshot.BuiltDrops; } } } private static void RestoreSnapshot(CharacterDropSnapshot snapshot) { CharacterDrop val = default(CharacterDrop); if (!((Object)(object)snapshot.Prefab == (Object)null) && snapshot.Prefab.TryGetComponent(ref val)) { val.m_drops = snapshot.BuiltDrops; } } private static void ValidateConfiguredPrefabs() { foreach (var (text2, list2) in ActiveEntriesByPrefab) { if (CharacterDropRuntime.HasSnapshot(text2)) { continue; } foreach (CharacterDropPrefabEntry item in list2) { WarnInvalidEntry("Character prefab '" + text2 + "' from " + DescribeEntrySource(item) + " was not found in ZNetScene."); } } } private static void ApplyCurrentStateToTrackedCharacterDrop(CharacterDrop characterDrop) { if ((Object)(object)characterDrop == (Object)null || (Object)(object)((Component)characterDrop).gameObject == (Object)null || !IsGameDataReady() || !CharacterDropRuntime.HasSnapshots()) { return; } string prefabName = GetPrefabName(((Component)characterDrop).gameObject); if (!PrefabsWithCharacterDropOverrides.Contains(prefabName)) { return; } int currentGameDataSignature = ComputeGameDataSignature(); bool flag = ShouldApplyLocally(); if (!StandardDomainApplySupport.IsAlreadyApplied(_lastAppliedGameDataSignature, currentGameDataSignature, _lastAppliedDomainEnabled, flag, _lastAppliedConfigurationSignature, _configurationSignature) || _lastAppliedSynchronizedPayloadReady != Volatile.Read(ref _synchronizedPayloadReady) || !CharacterDropRuntime.TryGetSnapshot(prefabName, out CharacterDropSnapshot snapshot) || snapshot == null) { return; } characterDrop.m_drops = snapshot.BuiltDrops; if (flag) { EnsureCompiledState(); if (_compiledState.StaticBuiltDropsByPrefab.TryGetValue(prefabName, out List value) && value.Count != 0) { characterDrop.m_drops = value; } } } internal static void TrackCharacterDropInstance(CharacterDrop? characterDrop) { if ((Object)(object)characterDrop == (Object)null || (Object)(object)((Component)characterDrop).gameObject == (Object)null) { return; } string prefabName = GetPrefabName(((Component)characterDrop).gameObject); if (!PrefabsWithCharacterDropOverrides.Contains(prefabName)) { return; } lock (Sync) { if (PrefabsWithCharacterDropOverrides.Contains(prefabName)) { RegisterLiveCharacterDrop(characterDrop); ApplyCurrentStateToTrackedCharacterDrop(characterDrop); } } } internal static void UntrackCharacterDropInstance(CharacterDrop? characterDrop) { lock (Sync) { if (!((Object)(object)characterDrop == (Object)null) && CharacterDropRuntime.TryGetRegisteredPrefabName(characterDrop, out string prefabName)) { UnregisterLiveCharacterDrop(characterDrop, prefabName); } } } private static void BootstrapRegisteredCharacterDropsIfNeeded(HashSet? additionalPrefabs = null, bool forceRescan = false) { if (PrefabsWithCharacterDropOverrides.Count != 0 || (additionalPrefabs != null && additionalPrefabs.Count != 0)) { CharacterDropRuntime.BootstrapRegisteredCharacterDropsIfNeeded(ComputeLiveRegistrySceneSignature(), Object.FindObjectsByType((FindObjectsSortMode)0), (CharacterDrop characterDrop) => GetPrefabName(((Component)characterDrop).gameObject), ShouldRegisterBootstrappedCharacterDropPrefab, additionalPrefabs, forceRescan); } } private static IEnumerable GetRegisteredCharacterDrops() { return CharacterDropRuntime.GetRegisteredCharacterDrops(); } private static Dictionary CloneCurrentEntrySignaturesByPrefab() { return new Dictionary(CurrentEntrySignaturesByPrefab, StringComparer.OrdinalIgnoreCase); } private static Dictionary BuildActiveEntrySignaturesByPrefab(Dictionary> activeEntriesByPrefab) { return DomainEntrySignatureSupport.BuildSignaturesByKey(activeEntriesByPrefab, (List entries) => NetworkPayloadSyncSupport.ComputeCharacterConfigurationSignature(entries.OrderBy((CharacterDropPrefabEntry entry) => entry.RuleId, StringComparer.Ordinal).ToList())); } private static bool TryBuildEffectiveCustomDropDefinitions(IEnumerable entries, Character character, out List definitions) { SortedDictionary sortedDictionary = new SortedDictionary(StringComparer.Ordinal); bool result = false; foreach (CharacterDropPrefabEntry item in entries ?? Enumerable.Empty()) { if (!EntryMatchesCharacter(item, character) || item.CharacterDrop == null) { continue; } result = true; IEnumerable enumerable = item.CharacterDrop?.Drops; foreach (CharacterDropEntryDefinition item2 in enumerable ?? Enumerable.Empty()) { string text = BuildDropRowFingerprint(item2); CollectionExtensions.TryAdd((IDictionary)sortedDictionary, text, item2); } } definitions = sortedDictionary.Values.ToList(); return result; } private static bool TryBuildEffectiveCustomDropDefinitions(IEnumerable rules, Character character, out List definitions) { SortedDictionary sortedDictionary = new SortedDictionary(StringComparer.Ordinal); bool result = false; foreach (CompiledCharacterDropRule item in rules ?? Enumerable.Empty()) { if (!EntryMatchesCharacter(item.Entry, character)) { continue; } result = true; foreach (CompiledCharacterDropDefinition drop in item.Drops) { CollectionExtensions.TryAdd((IDictionary)sortedDictionary, drop.Fingerprint, drop); } } definitions = sortedDictionary.Values.ToList(); return result; } private static bool TryBuildEffectiveRuntimeDropDefinitions(IEnumerable? staticDefinitions, IEnumerable runtimeRules, Character character, out List definitions) { SortedDictionary sortedDictionary = new SortedDictionary(StringComparer.Ordinal); foreach (CompiledCharacterDropDefinition item in staticDefinitions ?? Enumerable.Empty()) { CollectionExtensions.TryAdd((IDictionary)sortedDictionary, item.Fingerprint, item); } bool result = false; foreach (CompiledCharacterDropRule item2 in runtimeRules ?? Enumerable.Empty()) { if (!EntryMatchesCharacter(item2.Entry, character)) { continue; } result = true; foreach (CompiledCharacterDropDefinition drop in item2.Drops) { CollectionExtensions.TryAdd((IDictionary)sortedDictionary, drop.Fingerprint, drop); } } definitions = sortedDictionary.Values.ToList(); return result; } private static bool TryResolveRuntimeDropResolutionLocked(CharacterDrop characterDrop, out Character? character, out CachedCharacterRuntimeDropResolution? resolution) { resolution = null; character = null; if (!CanUseCurrentRuntimeState()) { return false; } string prefabName = GetPrefabName(((Component)characterDrop).gameObject); EnsureCompiledState(); if (!_compiledState.RuntimeRulesByPrefab.TryGetValue(prefabName, out List value) || value.Count == 0) { return false; } character = ((Component)characterDrop).GetComponent(); if ((Object)(object)character == (Object)null) { return false; } CharacterRuntimeDropCacheState value2; CharacterRuntimeDropCacheState characterRuntimeDropCacheState = (_compiledState.RuntimeDropCachesByPrefab.TryGetValue(prefabName, out value2) ? value2 : null); if (characterRuntimeDropCacheState != null && characterRuntimeDropCacheState.IsCacheable) { int num = ComputeCachedRuntimeDropSignature(character, characterRuntimeDropCacheState); if (characterRuntimeDropCacheState.ResolutionsBySignature.TryGetValue(num, out resolution)) { return resolution.HasMatchedRuntimeRule; } resolution = BuildRuntimeDropResolution(_compiledState.StaticDropsByPrefab.TryGetValue(prefabName, out List value3) ? value3 : null, value, character); StoreCachedRuntimeDropResolution(characterRuntimeDropCacheState, num, resolution); return resolution.HasMatchedRuntimeRule; } resolution = BuildRuntimeDropResolution(_compiledState.StaticDropsByPrefab.TryGetValue(prefabName, out List value4) ? value4 : null, value, character); return resolution.HasMatchedRuntimeRule; } private static CachedCharacterRuntimeDropResolution BuildRuntimeDropResolution(IReadOnlyList? staticDefinitions, IReadOnlyList runtimeRules, Character character) { if (!TryBuildEffectiveRuntimeDropDefinitions(staticDefinitions, runtimeRules, character, out List definitions)) { return new CachedCharacterRuntimeDropResolution { HasMatchedRuntimeRule = false }; } CompiledCharacterDropDefinition[] array = definitions.ToArray(); return new CachedCharacterRuntimeDropResolution { HasMatchedRuntimeRule = true, Definitions = array, OverrideDrops = BuildDrops(array), HasCustomDropHandling = HasCustomDropHandling(array) }; } private static void StoreCachedRuntimeDropResolution(CharacterRuntimeDropCacheState cacheState, int runtimeSignature, CachedCharacterRuntimeDropResolution resolution) { if (cacheState.ResolutionsBySignature.Count >= 32 && !cacheState.ResolutionsBySignature.ContainsKey(runtimeSignature)) { cacheState.ResolutionsBySignature.Clear(); } cacheState.ResolutionsBySignature[runtimeSignature] = resolution; } private static int ComputeCachedRuntimeDropSignature(Character character, CharacterRuntimeDropCacheState cacheState) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected I4, but got Unknown //IL_0133: Unknown result type (might be due to invalid IL or missing references) int num = 17; if (cacheState.UsesLevel) { num = CombineCachedRuntimeDropSignature(num, character.GetLevel()); } if (cacheState.UsesFaction) { num = CombineCachedRuntimeDropSignature(num, (int)character.GetFaction()); } if (cacheState.UsesState) { num = CombineCachedRuntimeDropSignature(num, character.IsTamed()); MonsterAI component = ((Component)character).GetComponent(); num = CombineCachedRuntimeDropSignature(num, (Object)(object)component != (Object)null && component.IsEventCreature()); } if (cacheState.UsesTimeOfDay || cacheState.UsesRequiredEnvironments || cacheState.RequiredGlobalKeys.Length != 0 || cacheState.ForbiddenGlobalKeys.Length != 0) { CharacterRuntimeContextSnapshot orCreateRuntimeContextSnapshot = GetOrCreateRuntimeContextSnapshot(); if (cacheState.UsesTimeOfDay) { num = CombineCachedRuntimeDropSignature(num, orCreateRuntimeContextSnapshot.TimeOfDayPhaseMarker); } if (cacheState.UsesRequiredEnvironments) { num = CombineCachedRuntimeDropSignature(num, orCreateRuntimeContextSnapshot.EnvironmentName); } string[] requiredGlobalKeys = cacheState.RequiredGlobalKeys; foreach (string text in requiredGlobalKeys) { num = CombineCachedRuntimeDropSignature(num, text); num = CombineCachedRuntimeDropSignature(num, GetCachedRuntimeDropGlobalKeyState(orCreateRuntimeContextSnapshot, text)); } requiredGlobalKeys = cacheState.ForbiddenGlobalKeys; foreach (string text2 in requiredGlobalKeys) { num = CombineCachedRuntimeDropSignature(num, text2); num = CombineCachedRuntimeDropSignature(num, GetCachedRuntimeDropGlobalKeyState(orCreateRuntimeContextSnapshot, text2)); } } if (cacheState.UsesInsidePlayerBase) { bool value = (Object)(object)EffectArea.IsPointInsideArea(((Component)character).transform.position, (Type)4, 0f) != (Object)null; num = CombineCachedRuntimeDropSignature(num, value); } return num; } private static CharacterRuntimeContextSnapshot GetOrCreateRuntimeContextSnapshot() { int frameCount = Time.frameCount; if (_runtimeContextSnapshot != null && _runtimeContextSnapshot.Frame == frameCount) { return _runtimeContextSnapshot; } CharacterRuntimeContextSnapshot obj = new CharacterRuntimeContextSnapshot { Frame = frameCount, TimeOfDayPhaseMarker = TimeOfDayFormatting.GetCurrentRuntimePhaseMarker() }; EnvMan instance = EnvMan.instance; obj.EnvironmentName = ((instance == null) ? null : instance.GetCurrentEnvironment()?.m_name) ?? ""; _runtimeContextSnapshot = obj; return _runtimeContextSnapshot; } private static bool GetCachedRuntimeDropGlobalKeyState(CharacterRuntimeContextSnapshot runtimeContext, string key) { if (runtimeContext.GlobalKeyStates.TryGetValue(key, out var value)) { return value; } value = (Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetGlobalKey(key); runtimeContext.GlobalKeyStates[key] = value; return value; } private static int CombineCachedRuntimeDropSignature(int current, bool value) { return current * 31 + (value ? 1 : 0); } private static int CombineCachedRuntimeDropSignature(int current, int value) { return current * 31 + value; } private static int CombineCachedRuntimeDropSignature(int current, string value) { return current * 31 + (value?.GetHashCode() ?? 0); } private static bool HasConfiguredConditionValues(IEnumerable? values) { if (values == null) { return false; } foreach (string value in values) { if (!string.IsNullOrWhiteSpace(value)) { return true; } } return false; } private static void AddNormalizedConditionValues(IEnumerable? values, ref HashSet? destination) { if (values == null) { return; } foreach (string value in values) { string text = (value ?? "").Trim(); if (text.Length != 0) { if (destination == null) { destination = new HashSet(StringComparer.Ordinal); } destination.Add(text); } } } private static bool RequiresRuntimeCharacterDropHandling(CompiledCharacterDropDefinition definition) { if (!definition.AmountLimit.HasValue) { return definition.DropInStack; } return true; } private static bool EntryMatchesCharacter(CharacterDropPrefabEntry? entry, Character character) { if (entry != null) { return DropConditionEvaluator.AreSatisfied(character, entry.Conditions); } return false; } private static string BuildDropRowFingerprint(CharacterDropEntryDefinition definition) { return NetworkPayloadSyncSupport.ComputeCharacterDropRowSignature(new CharacterDropEntryDefinition { Item = (definition.Item ?? "").Trim(), AmountMin = Math.Max(1, definition.AmountMin.GetValueOrDefault(1)), AmountMax = Math.Max(Math.Max(1, definition.AmountMin.GetValueOrDefault(1)), definition.AmountMax ?? definition.AmountMin.GetValueOrDefault(1)), Chance = Mathf.Max(0f, definition.Chance.GetValueOrDefault(1f)), OnePerPlayer = definition.OnePerPlayer.GetValueOrDefault(), LevelMultiplier = definition.LevelMultiplier.GetValueOrDefault(true), DontScale = definition.DontScale.GetValueOrDefault(), AmountLimit = ((definition.AmountLimit.HasValue && definition.AmountLimit.Value >= 0) ? new int?(definition.AmountLimit.Value) : null), DropInStack = definition.DropInStack.GetValueOrDefault() }); } private static bool HasAddedPrefabs(Dictionary previous, Dictionary current) { foreach (string key in current.Keys) { if (!previous.ContainsKey(key)) { return true; } } return false; } private static HashSet BuildDirtyPrefabs(Dictionary previous, Dictionary current) { return DomainDictionaryDiffSupport.BuildDirtyKeys(previous, current); } private static void ReplaceEntrySignatures(Dictionary target, Dictionary source) { DomainDictionaryDiffSupport.ReplaceEntries(target, source); } private static void RegisterLiveCharacterDrop(CharacterDrop characterDrop) { if (!((Object)(object)characterDrop == (Object)null) && !((Object)(object)((Component)characterDrop).gameObject == (Object)null)) { string prefabName = GetPrefabName(((Component)characterDrop).gameObject); if (prefabName.Length != 0) { CharacterDropRuntime.RegisterLiveCharacterDrop(characterDrop, prefabName); } } } private static bool ShouldRegisterBootstrappedCharacterDropPrefab(string prefabName) { if (prefabName.Length > 0) { return PrefabsWithCharacterDropOverrides.Contains(prefabName); } return false; } private static List GetOrCreateActiveEntries(Dictionary> activeEntriesByPrefab, string prefabName) { if (!activeEntriesByPrefab.TryGetValue(prefabName, out List value)) { value = (activeEntriesByPrefab[prefabName] = new List()); } return value; } private static IEnumerable GetRegisteredCharacterDrops(HashSet dirtyPrefabs) { return CharacterDropRuntime.GetRegisteredCharacterDrops(dirtyPrefabs); } private static void UnregisterLiveCharacterDrop(CharacterDrop characterDrop, string prefabName) { CharacterDropRuntime.UnregisterLiveCharacterDrop(characterDrop, prefabName); } private static List CloneSnapshotDrops(List drops) { List list = new List(drops.Count); foreach (Drop drop in drops) { list.Add(new CharacterDropItemSnapshot { ItemPrefab = drop.m_prefab, AmountMin = drop.m_amountMin, AmountMax = drop.m_amountMax, Chance = drop.m_chance, OnePerPlayer = drop.m_onePerPlayer, LevelMultiplier = drop.m_levelMultiplier, DontScale = drop.m_dontScale }); } return list; } private static List CloneDrops(List drops) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected O, but got Unknown List list = new List(drops.Count); foreach (Drop drop in drops) { list.Add(new Drop { m_prefab = drop.m_prefab, m_amountMin = drop.m_amountMin, m_amountMax = drop.m_amountMax, m_chance = drop.m_chance, m_onePerPlayer = drop.m_onePerPlayer, m_levelMultiplier = drop.m_levelMultiplier, m_dontScale = drop.m_dontScale }); } return list; } private static List BuildDrops(List snapshots) { return ((IEnumerable)snapshots).Select((Func)((CharacterDropItemSnapshot drop) => new Drop { m_prefab = drop.ItemPrefab, m_amountMin = drop.AmountMin, m_amountMax = drop.AmountMax, m_chance = drop.Chance, m_onePerPlayer = drop.OnePerPlayer, m_levelMultiplier = drop.LevelMultiplier, m_dontScale = drop.DontScale })).ToList(); } private static List BuildDrops(IReadOnlyList definitions) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Expected O, but got Unknown List list = new List(definitions.Count); foreach (CompiledCharacterDropDefinition definition in definitions) { list.Add(new Drop { m_prefab = definition.Prefab, m_amountMin = definition.AmountMin, m_amountMax = definition.AmountMax, m_chance = definition.Chance, m_onePerPlayer = definition.OnePerPlayer, m_levelMultiplier = definition.LevelMultiplier, m_dontScale = definition.DontScale }); } return list; } private static List BuildDrops(List definitions, string context) { //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Expected O, but got Unknown List list = new List(); foreach (CharacterDropEntryDefinition definition in definitions) { string text = (definition.Item ?? "").Trim(); if (text.Length == 0) { WarnInvalidEntry("Entry '" + context + "' contains a character drop without an item name."); continue; } GameObject val = ResolveItemPrefab(text, context); if (!((Object)(object)val == (Object)null)) { list.Add(new Drop { m_prefab = val, m_amountMin = Math.Max(1, definition.AmountMin.GetValueOrDefault(1)), m_amountMax = Math.Max(Math.Max(1, definition.AmountMin.GetValueOrDefault(1)), definition.AmountMax ?? definition.AmountMin.GetValueOrDefault(1)), m_chance = Mathf.Max(0f, definition.Chance.GetValueOrDefault(1f)), m_onePerPlayer = definition.OnePerPlayer.GetValueOrDefault(), m_levelMultiplier = definition.LevelMultiplier.GetValueOrDefault(true), m_dontScale = definition.DontScale.GetValueOrDefault() }); } } return list; } private static List GenerateConfiguredDrops(Character character, List definitions, string context) { List list = new List(); int num = Mathf.Max(1, (int)Mathf.Pow(2f, (float)(character.GetLevel() - 1))); int onePerPlayerDropCount = GetOnePerPlayerDropCount(character); foreach (CharacterDropEntryDefinition definition in definitions) { string text = (definition.Item ?? "").Trim(); if (text.Length == 0) { WarnInvalidEntry("Entry '" + context + "' contains a character drop without an item name."); continue; } GameObject val = ResolveItemPrefab(text, context); if ((Object)(object)val == (Object)null) { continue; } float num2 = Mathf.Max(0f, definition.Chance.GetValueOrDefault(1f)); if (definition.LevelMultiplier.GetValueOrDefault(true)) { num2 *= (float)num; } if (!(Random.value > num2)) { int num3 = Math.Max(1, definition.AmountMin.GetValueOrDefault(1)); int num4 = Math.Max(num3, definition.AmountMax ?? definition.AmountMin.GetValueOrDefault(1)); int num5 = (definition.DontScale.GetValueOrDefault() ? Random.Range(num3, num4) : Game.instance.ScaleDrops(val, num3, num4)); if (definition.LevelMultiplier.GetValueOrDefault(true)) { num5 *= num; } if (definition.OnePerPlayer.GetValueOrDefault()) { num5 = onePerPlayerDropCount; } num5 = Math.Min(num5, 100); if (definition.AmountLimit.HasValue && definition.AmountLimit.Value >= 0) { num5 = Math.Min(num5, definition.AmountLimit.Value); } if (num5 > 0) { list.Add(new ResolvedConfiguredDrop { Prefab = val, Amount = num5, DropInStack = definition.DropInStack.GetValueOrDefault() }); } } } return list; } private static List GenerateConfiguredDrops(Character character, IReadOnlyList definitions) { List list = new List(); int num = Mathf.Max(1, (int)Mathf.Pow(2f, (float)(character.GetLevel() - 1))); int onePerPlayerDropCount = GetOnePerPlayerDropCount(character); foreach (CompiledCharacterDropDefinition definition in definitions) { float num2 = definition.Chance; if (definition.LevelMultiplier) { num2 *= (float)num; } if (!(Random.value > num2)) { int num3 = (definition.DontScale ? Random.Range(definition.AmountMin, definition.AmountMax) : Game.instance.ScaleDrops(definition.Prefab, definition.AmountMin, definition.AmountMax)); if (definition.LevelMultiplier) { num3 *= num; } if (definition.OnePerPlayer) { num3 = onePerPlayerDropCount; } num3 = Math.Min(num3, 100); if (definition.AmountLimit.HasValue) { num3 = Math.Min(num3, definition.AmountLimit.Value); } if (num3 > 0) { list.Add(new ResolvedConfiguredDrop { Prefab = definition.Prefab, Amount = num3, DropInStack = definition.DropInStack }); } } } return list; } private static int GetOnePerPlayerDropCount(Character character) { float characterDropOnePerPlayerNearbyRange = PluginSettingsFacade.GetCharacterDropOnePerPlayerNearbyRange(); CharacterDrop characterDrop = default(CharacterDrop); if (characterDropOnePerPlayerNearbyRange > 0f && ((Component)character).TryGetComponent(ref characterDrop)) { return CountNearbyPlayers(characterDrop, character, characterDropOnePerPlayerNearbyRange); } if (!((Object)(object)ZNet.instance != (Object)null)) { return 1; } return ZNet.instance.GetNrOfPlayers(); } private static int CountNearbyPlayers(CharacterDrop characterDrop, Character? character, float range) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) if (character == null) { character = ((Component)characterDrop).GetComponent(); } Vector3 point = (((Object)(object)character != (Object)null) ? character.GetCenterPoint() : ((Component)characterDrop).transform.position); bool livingPlayersOnly = PluginSettingsFacade.IsCharacterDropOnePerPlayerNearbyRangeLivingPlayersOnly(); return SceneProximityQueries.CountPlayersInRangeXZ(point, range, livingPlayersOnly); } private static void DropConfiguredItems(List drops, Vector3 centerPos, float dropArea) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) List> list = new List>(); foreach (ResolvedConfiguredDrop drop in drops) { if (!ShouldDropInStack(drop.Prefab, drop.Amount, drop.DropInStack)) { list.Add(new KeyValuePair(drop.Prefab, drop.Amount)); } else { SpawnStackedDrops(drop.Prefab, drop.Amount, centerPos, dropArea); } } if (list.Count > 0) { SpawnConfiguredLooseDrops(list, centerPos, dropArea); } } private static bool ShouldDropInStack(GameObject prefab, int amount, bool explicitDropInStack) { ItemDrop val = default(ItemDrop); if ((Object)(object)prefab == (Object)null || !prefab.TryGetComponent(ref val) || val.m_itemData.m_shared.m_maxStackSize <= 1 || PluginSettingsFacade.IsCharacterDropInStackBlacklisted(((Object)prefab).name)) { return false; } if (!explicitDropInStack) { if (PluginSettingsFacade.IsGlobalCharacterDropInStackEnabled()) { return amount > 1; } return false; } return true; } private static void SpawnStackedDrops(GameObject prefab, int amount, Vector3 centerPos, float dropArea) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) ItemDrop val = default(ItemDrop); if (amount > 0 && prefab.TryGetComponent(ref val)) { int num = amount; int val2 = Math.Max(1, val.m_itemData.m_shared.m_maxStackSize); while (num > 0) { int num2 = Math.Min(num, val2); SpawnStackedItem(prefab, num2, centerPos, dropArea); num -= num2; } } } private static void SpawnStackedItem(GameObject prefab, int stackSize, Vector3 centerPos, float dropArea) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0064: 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_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) Quaternion val = Quaternion.Euler(0f, (float)Random.Range(0, 360), 0f); Vector3 val2 = ResolveConfiguredDropSpawnPoint(centerPos, dropArea); GameObject obj = Object.Instantiate(prefab, val2, val); ItemDrop val3 = default(ItemDrop); if (obj.TryGetComponent(ref val3)) { ItemDrop.OnCreateNew(val3); val3.SetStack(stackSize); val3.m_itemData.m_worldLevel = (byte)Game.m_worldLevel; } Rigidbody val4 = default(Rigidbody); if (obj.TryGetComponent(ref val4)) { Vector3 insideUnitSphere = Random.insideUnitSphere; if (insideUnitSphere.y < 0f) { insideUnitSphere.y = 0f - insideUnitSphere.y; } val4.AddForce(insideUnitSphere * 5f, (ForceMode)2); } } private static void SpawnConfiguredLooseDrops(List> drops, Vector3 centerPos, float dropArea) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) foreach (KeyValuePair drop in drops) { for (int i = 0; i < drop.Value; i++) { SpawnConfiguredLooseItem(drop.Key, centerPos, dropArea); } } } private static void SpawnConfiguredLooseItem(GameObject prefab, Vector3 centerPos, float dropArea) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0075: 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_0067: Unknown result type (might be due to invalid IL or missing references) Quaternion val = Quaternion.Euler(0f, (float)Random.Range(0, 360), 0f); Vector3 val2 = ResolveConfiguredDropSpawnPoint(centerPos, dropArea); GameObject obj = Object.Instantiate(prefab, val2, val); ItemDrop val3 = default(ItemDrop); if (obj.TryGetComponent(ref val3)) { val3.m_itemData.m_worldLevel = (byte)Game.m_worldLevel; } Rigidbody val4 = default(Rigidbody); if (obj.TryGetComponent(ref val4)) { Vector3 insideUnitSphere = Random.insideUnitSphere; if (insideUnitSphere.y < 0f) { insideUnitSphere.y = 0f - insideUnitSphere.y; } val4.AddForce(insideUnitSphere * 5f, (ForceMode)2); } } private static Vector3 ResolveConfiguredDropSpawnPoint(Vector3 centerPos, float dropArea) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) Vector2 val = Random.insideUnitCircle * dropArea; Vector3 point = centerPos + new Vector3(val.x, 0f, val.y); TrySnapConfiguredDropSpawnPointToGround(ref point); return point; } private static bool TrySnapConfiguredDropSpawnPointToGround(ref Vector3 point) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) float num = default(float); if ((Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetSolidHeight(point, ref num, 1000)) { point.y = num + 0.2f; return true; } if (WorldGenerator.instance != null) { point.y = WorldGenerator.instance.GetHeight(point.x, point.z) + 0.2f; return true; } return false; } private static string FormatYamlBool(bool value) { if (!value) { return "false"; } return "true"; } private static string FormatYamlFloat(float value) { return value.ToString("0.###", CultureInfo.InvariantCulture); } private static string FormatYamlString(string value) { if (value.Length == 0) { return "''"; } if (!char.IsWhiteSpace(value[0]) && !char.IsWhiteSpace(value[value.Length - 1]) && value.IndexOfAny(new char[17] { ':', '#', '{', '}', '[', ']', ',', '\'', '"', '&', '*', '!', '|', '>', '%', '@', '`' }) < 0 && value[0] != '-' && value[0] != '?' && !string.Equals(value, "null", StringComparison.OrdinalIgnoreCase) && !string.Equals(value, "true", StringComparison.OrdinalIgnoreCase) && !string.Equals(value, "false", StringComparison.OrdinalIgnoreCase)) { return value; } return "'" + value.Replace("'", "''") + "'"; } private static CharacterDropPrefabEntry BuildConfigurationEntry(CharacterDropSnapshot snapshot) { List list = (from drop in snapshot.Drops select new { Name = NormalizeReferenceItemName(drop.ItemPrefab), Drop = drop } into entry where !string.IsNullOrWhiteSpace(entry.Name) select new CharacterDropEntryDefinition { Item = entry.Name, Amount = RangeFormatting.FromReference(entry.Drop.AmountMin, entry.Drop.AmountMax, 1, 1), Chance = (IsReferenceDefault(entry.Drop.Chance, 1f) ? null : new float?(entry.Drop.Chance)), OnePerPlayer = (entry.Drop.OnePerPlayer ? new bool?(true) : null), LevelMultiplier = (entry.Drop.LevelMultiplier ? null : new bool?(false)), DontScale = (entry.Drop.DontScale ? new bool?(true) : null) }).ToList(); return new CharacterDropPrefabEntry { Prefab = ((Object)snapshot.Prefab).name, Enabled = true, CharacterDrop = new CharacterDropDefinition { Drops = ((list.Count > 0) ? list : null) } }; } private static bool IsReferenceDefault(float value, float defaultValue) { return Math.Abs(value - defaultValue) < 0.0001f; } private static IntRangeDefinition? GetAmountRange(CharacterDropEntryDefinition definition) { return definition.Amount ?? RangeFormatting.From(definition.AmountMin, definition.AmountMax ?? definition.AmountMin); } private static string? NormalizeReferenceItemName(GameObject? itemPrefab) { if ((Object)(object)itemPrefab == (Object)null) { return null; } string name = ((Object)itemPrefab).name; if (!name.StartsWith("JVLmock_", StringComparison.OrdinalIgnoreCase)) { return name; } string text = name.Substring("JVLmock_".Length); if (string.IsNullOrWhiteSpace(text)) { return null; } ObjectDB instance = ObjectDB.instance; if (!((Object)(object)((instance != null) ? instance.GetItemPrefab(text) : null) != (Object)null)) { ZNetScene instance2 = ZNetScene.instance; if (!((Object)(object)((instance2 != null) ? instance2.GetPrefab(text) : null) != (Object)null)) { return null; } } return text; } private static GameObject? ResolveItemPrefab(string itemName, string context) { string text = (itemName ?? "").Trim(); if (text.Length == 0) { WarnInvalidEntry("Entry '" + context + "' references an empty item prefab name."); return null; } ObjectDB instance = ObjectDB.instance; object obj = ((instance != null) ? instance.GetItemPrefab(text) : null); if (obj == null) { ZNetScene instance2 = ZNetScene.instance; obj = ((instance2 != null) ? instance2.GetPrefab(text) : null); } GameObject val = (GameObject)obj; if ((Object)(object)val == (Object)null) { WarnInvalidEntry("Entry '" + context + "' references unknown item prefab '" + text + "'."); return null; } ItemDrop val2 = default(ItemDrop); if (!val.TryGetComponent(ref val2)) { WarnInvalidEntry("Entry '" + context + "' references '" + text + "', but it is not an item prefab."); return null; } return val; } private static string GetPrefabName(GameObject gameObject) { if ((Object)(object)gameObject == (Object)null) { return ""; } ZNetView component = gameObject.GetComponent(); 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 ((Object)prefab).name; } } string prefabName = Utils.GetPrefabName(gameObject); if (!string.IsNullOrWhiteSpace(prefabName)) { return prefabName; } string name = ((Object)gameObject).name; if (name.EndsWith("(Clone)", StringComparison.Ordinal)) { string text = name; int length = "(Clone)".Length; return text.Substring(0, text.Length - length).TrimEnd(); } return name; } private static void WarnInvalidEntry(string message) { if (_invalidEntryWarningSuppressionDepth <= 0 && !ShouldSuppressServerSourcedInvalidEntryWarning(message) && InvalidEntryWarnings.Add(message)) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)message); } } private static void LogPartiallyAcceptedLocalConfiguration(int totalEntries, int acceptedEntries, IEnumerable warnings) { int num = Math.Max(0, totalEntries - acceptedEntries); DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("Skipped " + num.ToString(CultureInfo.InvariantCulture) + " invalid character entr" + ((num == 1) ? "y" : "ies") + " and kept " + acceptedEntries.ToString(CultureInfo.InvariantCulture) + " valid entr" + ((acceptedEntries == 1) ? "y" : "ies") + ".")); foreach (string item in warnings.Where((string message) => !string.IsNullOrWhiteSpace(message)).Distinct(StringComparer.OrdinalIgnoreCase)) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)item); } } private static void LogLocalConfigurationLoaded(int acceptedEntryCount, int loadedFileCount) { DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)$"Loaded {acceptedEntryCount} character drop configuration(s) from {loadedFileCount} override file(s)."); } private static void OnSourceOfTruthPayloadUnchanged() { if (!NetworkPayloadSyncSupport.IsPayloadCurrent(Descriptor, _configurationSignature)) { ConfigurationDomainHost.PublishSyncedPayload(DropNSpawnPlugin.IsSourceOfTruth, Descriptor, _configuration, _configurationSignature); } } private static void LogSyncedCharacterConfigurationLoaded(string payloadToken, int acceptedEntryCount) { DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)$"Loaded {acceptedEntryCount} synchronized character configuration(s) from the server."); } private static void LogSyncedCharacterConfigurationFailure(string payloadToken, Exception ex) { DropNSpawnPlugin.DropNSpawnLogger.LogError((object)$"Failed to deserialize synchronized character payload DTO. {ex}"); } private static InvalidEntryWarningSuppressionScope BeginInvalidEntryWarningSuppressionForSyncedClientBuild(string sourceName) { if (DropNSpawnPlugin.IsSourceOfTruth || !sourceName.StartsWith("ServerSync:", StringComparison.Ordinal)) { return default(InvalidEntryWarningSuppressionScope); } return new InvalidEntryWarningSuppressionScope(active: true); } private static bool ShouldSuppressServerSourcedInvalidEntryWarning(string message) { if (!DropNSpawnPlugin.IsSourceOfTruth) { return message.IndexOf("ServerSync:", StringComparison.Ordinal) >= 0; } return false; } private static string CreateConfigurationContext(CharacterDropPrefabEntry entry) { return (string.IsNullOrWhiteSpace(entry.Prefab) ? "" : entry.Prefab) + " @ " + DescribeEntrySource(entry); } private static string DescribeEntrySource(CharacterDropPrefabEntry entry) { string text = DescribeEntrySource(entry.SourcePath); if (entry.SourceLine > 0) { text = text + ":" + entry.SourceLine.ToString(CultureInfo.InvariantCulture); } return text; } private static string DescribeEntrySource(string? sourcePath) { string text = sourcePath ?? ""; if (text.Length == 0) { return "unknown source"; } text.StartsWith("ServerSync:", StringComparison.Ordinal); return text; } private static string FormatYamlExceptionLocation(Exception ex) { if (!(ex is YamlException ex2)) { return ""; } Mark start = ex2.Start; if (start.Line <= 0) { return ""; } return " at line " + start.Line.ToString(CultureInfo.InvariantCulture); } private static string BuildCompiledDropContext(CharacterDropPrefabEntry entry) { string text = (string.IsNullOrWhiteSpace(entry.Prefab) ? "" : entry.Prefab); string text2 = (string.IsNullOrWhiteSpace(entry.RuleId) ? "" : entry.RuleId); return text + "/" + text2 + "@" + DescribeEntrySource(entry); } internal static int ComputeGameDataSignatureForDespawnRuntime() { return ComputeGameDataSignature(); } internal static IEnumerable EnumeratePrefabsForDespawnRuntime() { return EnumeratePrefabs(); } internal static string GetPrefabNameForDespawnRuntime(GameObject prefab) { return GetPrefabName(prefab); } internal static string BuildCompiledDropContextForDespawnRuntime(CharacterDropPrefabEntry entry) { return BuildCompiledDropContext(entry); } internal static GameObject? ResolveItemPrefabForDespawnRuntime(string itemName, string context) { return ResolveItemPrefab(itemName, context); } internal static void WarnInvalidEntryForDespawnRuntime(string message) { WarnInvalidEntry(message); } private static void RunApplyCoordinator(int gameDataSignature, bool domainEnabled, Dictionary currentEntrySignatures) { CharacterDesiredState characterDesiredState = BuildCharacterDesiredState(gameDataSignature, domainEnabled, currentEntrySignatures); _ = StandardBaselineDesiredStateCoordinator.Run(characterDesiredState.ApplyPlan, characterDesiredState, CharacterApplyOperations.Instance).Success; } private static CharacterDesiredState BuildCharacterDesiredState(int gameDataSignature, bool domainEnabled, Dictionary currentEntrySignatures) { bool canUseTargetedLiveReload = _lastAppliedGameDataSignature == gameDataSignature && _lastAppliedDomainEnabled.GetValueOrDefault() && !HasAddedPrefabs(_lastAppliedEntrySignaturesByPrefab, currentEntrySignatures); EnsureCompiledState(); return new CharacterDesiredState { GameDataSignature = gameDataSignature, ApplyPlan = StandardDomainApplySupport.BuildPlan(_lastAppliedGameDataSignature, gameDataSignature, _lastAppliedDomainEnabled, domainEnabled, _lastAppliedEntrySignaturesByPrefab, currentEntrySignatures, EmptyEntrySignatures, canUseTargetedLiveReload), CurrentEntrySignatures = currentEntrySignatures, CompiledState = _compiledState, DomainEnabled = domainEnabled }; } private static void RestoreCharacterStaticBaseline(CharacterDesiredState desiredState) { RestoreSnapshots(); } private static void ValidateCharacterDesiredState(CharacterDesiredState desiredState) { ValidateConfiguredPrefabs(); } private static void ApplyCharacterDesiredStateToStaticBaseline(CharacterDesiredState desiredState) { if (!desiredState.DomainEnabled) { return; } IEnumerable enumerable; if (desiredState.ApplyPlan.DirtyKeys == null) { IEnumerable keys = desiredState.CompiledState.StaticDropsByPrefab.Keys; enumerable = keys; } else { IEnumerable keys = desiredState.ApplyPlan.DirtyKeys; enumerable = keys; } CharacterDrop val = default(CharacterDrop); foreach (string item in enumerable) { if (desiredState.CompiledState.StaticBuiltDropsByPrefab.TryGetValue(item, out List value) && value.Count != 0 && CharacterDropRuntime.TryGetSnapshot(item, out CharacterDropSnapshot snapshot) && snapshot != null && !((Object)(object)snapshot.Prefab == (Object)null) && snapshot.Prefab.TryGetComponent(ref val)) { val.m_drops = value; } } } private static void PrepareCharacterLiveBaseline(CharacterDesiredState desiredState) { } private static void ApplyCharacterDesiredStateToLive(CharacterDesiredState desiredState) { BootstrapRegisteredCharacterDropsIfNeeded(desiredState.ApplyPlan.DirtyKeys, desiredState.ApplyPlan.DirtyKeys != null); foreach (CharacterDrop item in (desiredState.ApplyPlan.DirtyKeys == null) ? GetRegisteredCharacterDrops() : GetRegisteredCharacterDrops(desiredState.ApplyPlan.DirtyKeys)) { if ((Object)(object)item == (Object)null || (Object)(object)((Component)item).gameObject == (Object)null) { continue; } RegisterLiveCharacterDrop(item); string prefabName = GetPrefabName(((Component)item).gameObject); if (CharacterDropRuntime.TryGetSnapshot(prefabName, out CharacterDropSnapshot snapshot) && snapshot != null) { item.m_drops = snapshot.BuiltDrops; if (desiredState.DomainEnabled && desiredState.CompiledState.StaticBuiltDropsByPrefab.TryGetValue(prefabName, out List value) && value.Count != 0) { item.m_drops = value; } } } } internal static bool IsDespawnTrackingRuleLookupReady() { lock (Sync) { return IsGameDataReady(); } } internal static bool IsEligibleDespawnTrackingPrefabName(string prefabName) { lock (Sync) { if (!IsGameDataReady() || string.IsNullOrWhiteSpace(prefabName)) { return false; } return CharacterDespawnRuntime.IsEligibleDespawnTrackingPrefabName(prefabName, _configurationSignature, ActiveEntriesByPrefab); } } internal static bool IsEligibleDespawnTrackingPrefabHash(int prefabHash) { lock (Sync) { if (!IsGameDataReady() || prefabHash == 0) { return false; } return CharacterDespawnRuntime.IsEligibleDespawnTrackingPrefabHash(prefabHash, _configurationSignature, ActiveEntriesByPrefab); } } internal static IReadOnlyList GetDespawnBootstrapPrefabOrder() { lock (Sync) { if (!IsGameDataReady()) { return Array.Empty(); } return CharacterDespawnRuntime.GetDespawnBootstrapPrefabOrder(_configurationSignature, ActiveEntriesByPrefab); } } internal static bool TryResolveDespawnTrackingRule(string prefabName, out float? rangeOverride, out float? delayOverride, out IReadOnlyCollection refunds) { lock (Sync) { rangeOverride = null; delayOverride = null; refunds = (IReadOnlyCollection)(object)Array.Empty(); if (!IsGameDataReady() || string.IsNullOrWhiteSpace(prefabName)) { return false; } return CharacterDespawnRuntime.TryResolveDespawnTrackingRule(prefabName, _configurationSignature, ActiveEntriesByPrefab, out rangeOverride, out delayOverride, out refunds); } } internal static bool TryResolveDespawnTrackingRule(int prefabHash, out string prefabName, out float? rangeOverride, out float? delayOverride, out IReadOnlyCollection refunds) { lock (Sync) { prefabName = ""; rangeOverride = null; delayOverride = null; refunds = (IReadOnlyCollection)(object)Array.Empty(); if (!IsGameDataReady() || prefabHash == 0) { return false; } return CharacterDespawnRuntime.TryResolveDespawnTrackingRule(prefabHash, _configurationSignature, ActiveEntriesByPrefab, out prefabName, out rangeOverride, out delayOverride, out refunds); } } private static List ResolveConfiguredDespawnRefundDrops(IReadOnlyCollection refunds) { if (refunds.Count == 0) { return new List(); } List list = new List(refunds.Count); foreach (DespawnRefundDrop refund in refunds) { if (!((Object)(object)refund.Prefab == (Object)null) && refund.Amount > 0) { list.Add(new ResolvedConfiguredDrop { Prefab = refund.Prefab, Amount = refund.Amount, DropInStack = false }); } } return list; } internal static bool TryExecuteConfiguredDespawnRefunds(Vector3 centerPos, IReadOnlyCollection refunds) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) List list = ResolveConfiguredDespawnRefundDrops(refunds); if (list.Count == 0) { return refunds.Count == 0; } try { DropConfiguredItems(list, centerPos, 0.5f); return true; } catch (Exception ex) { if (PluginSettingsFacade.IsDespawnDiagnosticsEnabled()) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)$"[Despawn] Failed to execute configured despawn refunds at {centerPos.x:F1},{centerPos.y:F1},{centerPos.z:F1}: {ex.Message}"); } return false; } } private static List> BuildConfigurationTemplate() { return PrefabOutputSections.BuildSections(CharacterDropRuntime.GetSnapshots().Select(BuildConfigurationEntry), (CharacterDropPrefabEntry entry) => entry.Prefab); } private static string BuildReferenceConfigurationTemplate() { return PrefabOutputSections.SerializeReferenceSections((from section in BuildConfigurationTemplate() select new PrefabOwnerSection(section.OwnerName, section.Entries.Select((CharacterDropPrefabEntry entry) => new CharacterDropReferenceEntry { Prefab = entry.Prefab, CharacterDrop = entry.CharacterDrop }).ToList())).ToList(), Serializer); } private static string SerializeReferenceEntries(IEnumerable entries) { return ReferenceRefreshSupport.SerializeReferenceSections(entries, (CharacterDropReferenceEntry entry) => entry.Prefab, Serializer); } private static void WriteReferenceConfigurationFile(string content, string logMessage) { Directory.CreateDirectory(DropNSpawnPlugin.YamlConfigDirectoryPath); GeneratedFileWriter.WriteAllTextIfChanged(ReferenceConfigurationPath, content); DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)logMessage); } private static string BuildFullScaffoldConfigurationTemplate() { StringBuilder stringBuilder = new StringBuilder(); bool flag = false; foreach (PrefabOwnerSection item in BuildConfigurationTemplate()) { foreach (CharacterDropPrefabEntry entry in item.Entries) { if (flag) { AppendScaffoldBlankLine(stringBuilder); } AppendScaffoldCharacterEntry(stringBuilder, entry); flag = true; } } if (!flag) { return "[]" + Environment.NewLine; } return stringBuilder.ToString(); } private static void AppendScaffoldCharacterEntry(StringBuilder builder, CharacterDropPrefabEntry entry) { AppendScaffoldListEntryLine(builder, 0, "prefab", entry.Prefab); AppendScaffoldLine(builder, 1, "enabled: " + FormatYamlBool(entry.Enabled)); AppendScaffoldConditionsBlock(builder, 1); AppendScaffoldLine(builder, 1, "characterDrop:"); List list = entry.CharacterDrop?.Drops ?? new List(); if (list.Count > 0) { AppendScaffoldLine(builder, 2, "drops:"); { foreach (CharacterDropEntryDefinition item in list) { AppendScaffoldCharacterDropEntry(builder, 3, item); } return; } } AppendScaffoldLine(builder, 2, "drops: []"); } private static void AppendScaffoldCharacterDropEntry(StringBuilder builder, int indent, CharacterDropEntryDefinition definition) { AppendScaffoldListEntryLine(builder, indent, "item", definition.Item); AppendScaffoldLine(builder, indent + 1, "amount: " + RangeFormatting.FormatInlineObject(GetAmountRange(definition) ?? RangeFormatting.From(1, 1))); AppendScaffoldLine(builder, indent + 1, "chance: " + FormatYamlFloat(definition.Chance.GetValueOrDefault(1f))); AppendScaffoldLine(builder, indent + 1, "dontScale: " + FormatYamlBool(definition.DontScale.GetValueOrDefault())); AppendScaffoldLine(builder, indent + 1, "levelMultiplier: " + FormatYamlBool(definition.LevelMultiplier.GetValueOrDefault(true))); AppendScaffoldLine(builder, indent + 1, "onePerPlayer: " + FormatYamlBool(definition.OnePerPlayer.GetValueOrDefault())); AppendScaffoldNullableIntLine(builder, indent + 1, "amountLimit", definition.AmountLimit); AppendScaffoldLine(builder, indent + 1, "dropInStack: " + FormatYamlBool(definition.DropInStack.GetValueOrDefault())); } private static void AppendScaffoldComment(StringBuilder builder, string text) { builder.Append("# "); builder.AppendLine(text); } private static void AppendScaffoldLine(StringBuilder builder, int indent, string text) { builder.Append(' ', indent * 2); builder.AppendLine(text); } private static void AppendScaffoldBlankLine(StringBuilder builder) { builder.AppendLine(); } private static void AppendScaffoldConditionsBlock(StringBuilder builder, int indent) { AppendScaffoldLine(builder, indent, "conditions:"); AppendScaffoldLine(builder, indent + 1, "level: null"); AppendScaffoldLine(builder, indent + 1, "altitude: null"); AppendScaffoldLine(builder, indent + 1, "distanceFromCenter: null"); AppendScaffoldLine(builder, indent + 1, "biomes: []"); AppendScaffoldLine(builder, indent + 1, "locations: []"); AppendScaffoldLine(builder, indent + 1, "timeOfDay: null"); AppendScaffoldLine(builder, indent + 1, "requiredEnvironments: []"); AppendScaffoldLine(builder, indent + 1, "requiredGlobalKeys: []"); AppendScaffoldLine(builder, indent + 1, "forbiddenGlobalKeys: []"); AppendScaffoldLine(builder, indent + 1, "states: []"); AppendScaffoldLine(builder, indent + 1, "factions: []"); AppendScaffoldLine(builder, indent + 1, "inForest: null"); AppendScaffoldLine(builder, indent + 1, "inDungeon: null"); AppendScaffoldLine(builder, indent + 1, "insidePlayerBase: null"); } private static void AppendScaffoldNullableIntLine(StringBuilder builder, int indent, string key, int? value) { if (value.HasValue) { AppendScaffoldLine(builder, indent, $"{key}: {value.Value}"); } else { AppendScaffoldLine(builder, indent, key + ": null"); } } private static void AppendScaffoldListEntryLine(StringBuilder builder, int indent, string key, string? value) { if (value == null) { AppendScaffoldLine(builder, indent, "- " + key + ": null"); } else { AppendScaffoldLine(builder, indent, "- " + key + ": " + FormatYamlString(value)); } } private static string BuildPrimaryOverrideConfigurationTemplate() { StringBuilder stringBuilder = new StringBuilder(); AppendTemplateComment(stringBuilder, "Any file named " + PluginSettingsFacade.GetYamlDomainSupplementalPrefix("character") + "*.yml or " + PluginSettingsFacade.GetYamlDomainSupplementalPrefix("character") + "*.yaml is also loaded # ex) " + PluginSettingsFacade.GetYamlDomainFilePrefix("character") + "_rand1.yml, " + PluginSettingsFacade.GetYamlDomainFilePrefix("character") + "_rand2.yaml"); AppendTemplateComment(stringBuilder, "Use " + PluginSettingsFacade.GetYamlDomainFilePrefix("character") + ".reference.yml to look up real prefab names and reference values, and run dns:full character for exhaustive field examples"); AppendTemplateBlankLine(stringBuilder); AppendTemplateComment(stringBuilder, "characterDrop"); AppendTemplateBlankLine(stringBuilder); AppendTemplateLine(stringBuilder, 0, "- prefab: Greydwarf"); AppendTemplateLine(stringBuilder, 1, "enabled: true"); AppendTemplateLine(stringBuilder, 1, "conditions: # If these conditions fail, this custom entry is ignored and the original drops are used"); AppendTemplateLine(stringBuilder, 2, "level: null # ex) 1~3"); AppendTemplateLine(stringBuilder, 2, "altitude: null # ex) -1000~1000 # Range in world-height meters"); AppendTemplateLine(stringBuilder, 2, "distanceFromCenter: null # ex) 0~10000 # Range in meters from the world center"); AppendTemplateLine(stringBuilder, 2, "biomes: [] # ex) [BlackForest, Mistlands]"); AppendTemplateLine(stringBuilder, 2, "locations: [] # ex) [Hildir_camp]"); AppendTemplateLine(stringBuilder, 2, "timeOfDay: null # ex) [day, afternoon, night] # day contains afternoon"); AppendTemplateLine(stringBuilder, 2, "requiredEnvironments: [] # ex) [Clear, Rain]"); AppendTemplateLine(stringBuilder, 2, "requiredGlobalKeys: [] # ex) [defeated_eikthyr, defeated_gdking]"); AppendTemplateLine(stringBuilder, 2, "forbiddenGlobalKeys: [] # ex) [nomap, defeated_bonemass]"); AppendTemplateLine(stringBuilder, 2, "states: [] # ex) [Default, Tamed, Event]"); AppendTemplateLine(stringBuilder, 2, "factions: [] # ex) [ForestMonsters, Demon]"); AppendTemplateLine(stringBuilder, 2, "inForest: null # true = forest only # false = outside forest only # null or no field allows both"); AppendTemplateLine(stringBuilder, 2, "inDungeon: null # true = dungeon only # false = overworld only # null or no field allows both"); AppendTemplateLine(stringBuilder, 2, "insidePlayerBase: null # true = near player base only # false = away from player base only # null or no field allows both"); AppendTemplateLine(stringBuilder, 1, "characterDrop:"); AppendTemplateLine(stringBuilder, 2, "drops: # Set drops: [] to disable character drops for an entry"); AppendTemplateLine(stringBuilder, 2, "- item: null # ex) Resin"); AppendTemplateLine(stringBuilder, 3, "amount: 1~1 # ex) 1~3 # Range of item amount"); AppendTemplateLine(stringBuilder, 3, "chance: 1 # Chance from 0 to 1 for this item on each roll"); AppendTemplateLine(stringBuilder, 3, "dontScale: false # True skips the game's built-in drop scaling for the base amount roll"); AppendTemplateLine(stringBuilder, 3, "levelMultiplier: true # True multiplies the calculated amount by character level when supported"); AppendTemplateLine(stringBuilder, 3, "onePerPlayer: false # True uses nearby player count as the final amount # Configure check range in config"); AppendTemplateLine(stringBuilder, 3, "amountLimit: null # ex) 2 # Integer cap on the final amount"); AppendTemplateLine(stringBuilder, 3, "dropInStack: false # True spawns one stacked drop instead of many singles"); AppendTemplateLine(stringBuilder, 1, "despawn: # Optional unconditional no-player despawn rule for this prefab # top-level conditions do not apply to despawn"); AppendTemplateLine(stringBuilder, 2, "range: 64 # Optional override; falls back to Default Despawn Range config"); AppendTemplateLine(stringBuilder, 2, "delay: 90 # Optional override; falls back to Default Despawn Delay Seconds config"); AppendTemplateLine(stringBuilder, 2, "refunds: # Optional items dropped when this despawn rule removes the prefab"); AppendTemplateLine(stringBuilder, 2, "- item: null # ex) TrophyDeer"); AppendTemplateLine(stringBuilder, 3, "amount: 1 # ex) 2"); AppendTemplateBlankLine(stringBuilder); AppendTemplateComment(stringBuilder, "bossTamedPressure # Enable with BepInEx config: 2 - Boss / Enable Boss Tamed Pressure"); AppendActiveTemplateBlankLine(stringBuilder); AppendActiveTemplateLine(stringBuilder, 0, "- bossTamedPressure:"); AppendActiveTemplateLine(stringBuilder, 2, "bossPrefabs: [] # Extra source boss prefabs added to the auto-detected boss set"); AppendActiveTemplateLine(stringBuilder, 2, "excludedBossPrefabs: [] # Boss prefabs to ignore from auto-detected and bossPrefabs sources"); AppendActiveTemplateLine(stringBuilder, 2, "targets:"); AppendActiveTemplateLine(stringBuilder, 3, "range: 32 # Clamp: 0~128. Horizontal XZ range around each boss"); AppendActiveTemplateLine(stringBuilder, 3, "scanInterval: 5 # Clamp: 0.25~30. Seconds between boss/tamed range scans"); AppendActiveTemplateLine(stringBuilder, 3, "maxPerBoss: 4 # Clamp: 1~128. Maximum pressured targets per boss per scan"); AppendActiveTemplateLine(stringBuilder, 3, "excludedTamedPrefabs: [] # Tamed MonsterAI prefabs excluded from the default pressured target set"); AppendActiveTemplateLine(stringBuilder, 3, "extraPressuredPrefabs: [] # Character prefabs pressured even when not tamed"); AppendActiveTemplateLine(stringBuilder, 2, "pressure:"); AppendActiveTemplateLine(stringBuilder, 3, "damageInterval: 1 # Clamp: 0.25~30. Seconds between periodic damage ticks; each tick applies damagePercentPerSecond * damageInterval at once"); AppendActiveTemplateLine(stringBuilder, 3, "damagePercentPerSecond: 0.01 # Clamp: 0~1. 0.01 = 1% of max health per second"); AppendActiveTemplateLine(stringBuilder, 3, "damageMinBaseHealth: 100 # Clamp: 0~100000. Minimum max-health basis for periodic damage"); AppendActiveTemplateLine(stringBuilder, 3, "incomingDamageMultiplier: 1.25 # Clamp: 0~10. Multiplies damage received while affected"); AppendActiveTemplateLine(stringBuilder, 3, "outgoingDamageMultiplier: 0.75 # Clamp: 0~10. Multiplies damage dealt while affected"); AppendActiveTemplateLine(stringBuilder, 2, "message: null # Defaults to \"Tamed creatures near a boss are weakened.\"; empty string disables messages"); AppendActiveTemplateLine(stringBuilder, 2, "messageInterval: 5 # Clamp: 0~300. Per-player message cooldown in seconds"); AppendActiveTemplateBlankLine(stringBuilder); return stringBuilder.ToString(); } private static void AppendCharacterTemplateEntry(StringBuilder builder, CharacterDropPrefabEntry entry) { AppendTemplateComment(builder, "----- " + entry.Prefab + " -----"); AppendTemplateLine(builder, 0, "- prefab: " + entry.Prefab); AppendTemplateLine(builder, 1, "enabled: " + FormatYamlBool(entry.Enabled)); AppendOptionalCharacterConditions(builder, 1); AppendTemplateLine(builder, 1, "characterDrop:"); AppendTemplateLine(builder, 2, "drops:"); if (entry.CharacterDrop?.Drops != null && entry.CharacterDrop.Drops.Count > 0) { foreach (CharacterDropEntryDefinition drop in entry.CharacterDrop.Drops) { AppendCharacterDropEntryTemplate(builder, 2, drop); } } else { AppendOptionalCharacterDropEntryTemplate(builder, 2); } AppendTemplateNestedLine(builder, 1, "despawn:"); AppendTemplateNestedLine(builder, 2, "range: 64"); AppendTemplateNestedLine(builder, 2, "delay: 90"); AppendTemplateNestedLine(builder, 2, "refunds:"); AppendTemplateNestedLine(builder, 2, "- item: TrophyDeer"); AppendTemplateNestedLine(builder, 3, "amount: 2"); AppendTemplateBlankLine(builder); } private static void AppendCharacterDropEntryTemplate(StringBuilder builder, int indent, CharacterDropEntryDefinition definition) { AppendTemplateLine(builder, indent, "- item: " + definition.Item); AppendTemplateLine(builder, indent + 1, "amount: " + RangeFormatting.FormatShorthand(GetAmountRange(definition) ?? RangeFormatting.From(1, 1))); AppendTemplateLine(builder, indent + 1, "chance: " + FormatYamlFloat(definition.Chance.GetValueOrDefault(1f))); AppendTemplateLine(builder, indent + 1, "dontScale: " + FormatYamlBool(definition.DontScale.GetValueOrDefault())); AppendTemplateLine(builder, indent + 1, "levelMultiplier: " + FormatYamlBool(definition.LevelMultiplier.GetValueOrDefault(true))); AppendTemplateLine(builder, indent + 1, "onePerPlayer: " + FormatYamlBool(definition.OnePerPlayer.GetValueOrDefault())); AppendTemplateNestedLine(builder, indent + 1, "amountLimit: 1"); AppendTemplateNestedLine(builder, indent + 1, "dropInStack: true"); } private static void AppendOptionalCharacterDropEntryTemplate(StringBuilder builder, int indent) { AppendTemplateNestedLine(builder, indent, "- item: Resin"); AppendTemplateNestedLine(builder, indent + 1, "amount: 1~2"); AppendTemplateNestedLine(builder, indent + 1, "chance: 1"); AppendTemplateNestedLine(builder, indent + 1, "dontScale: false"); AppendTemplateNestedLine(builder, indent + 1, "levelMultiplier: true"); AppendTemplateNestedLine(builder, indent + 1, "onePerPlayer: false"); AppendTemplateNestedLine(builder, indent + 1, "amountLimit: 1"); AppendTemplateNestedLine(builder, indent + 1, "dropInStack: true"); } private static void AppendOptionalCharacterConditions(StringBuilder builder, int indent, bool nested = false) { AppendConditionTemplateLine(builder, indent, "conditions:", nested); AppendConditionTemplateLine(builder, indent + 1, "level: 1~3", nested); AppendConditionTemplateLine(builder, indent + 1, "altitude: -1000~1000", nested); AppendConditionTemplateLine(builder, indent + 1, "distanceFromCenter: 0~10000", nested); AppendConditionTemplateLine(builder, indent + 1, "inForest: true", nested); AppendConditionTemplateLine(builder, indent + 1, "inDungeon: false", nested); AppendConditionTemplateLine(builder, indent + 1, "insidePlayerBase: false", nested); AppendConditionTemplateLine(builder, indent + 1, "biomes: [BlackForest, Mistlands]", nested); AppendConditionTemplateLine(builder, indent + 1, "locations: [Hildir_camp]", nested); AppendConditionTemplateLine(builder, indent + 1, "timeOfDay: [night]", nested); AppendConditionTemplateLine(builder, indent + 1, "requiredEnvironments: [Rain]", nested); AppendConditionTemplateLine(builder, indent + 1, "requiredGlobalKeys: [defeated_gdking]", nested); AppendConditionTemplateLine(builder, indent + 1, "forbiddenGlobalKeys: [nomap]", nested); AppendConditionTemplateLine(builder, indent + 1, "states: [Default, Event]", nested); AppendConditionTemplateLine(builder, indent + 1, "factions: [ForestMonsters]", nested); } private static void AppendConditionTemplateLine(StringBuilder builder, int indent, string text, bool nested) { AppendTemplateNestedLine(builder, indent, text); } private static void AppendTemplateComment(StringBuilder builder, string text) { builder.Append("# "); builder.AppendLine(text); } private static void AppendTemplateLine(StringBuilder builder, int indent, string text) { builder.Append("# "); builder.Append(' ', indent * 2); builder.AppendLine(text); } private static void AppendTemplateNestedLine(StringBuilder builder, int indent, string text) { builder.Append("# "); builder.Append(' ', indent * 2); builder.Append("# "); builder.AppendLine(text); } private static void AppendActiveTemplateLine(StringBuilder builder, int indent, string text) { builder.Append(' ', indent * 2); builder.AppendLine(text); } private static void AppendActiveTemplateBlankLine(StringBuilder builder) { builder.AppendLine(); } private static void AppendTemplateBlankLine(StringBuilder builder) { builder.AppendLine("#"); } internal static bool HasVneiRelevantEntries(string prefabName) { lock (Sync) { List value; return ActiveEntriesByPrefab.TryGetValue(prefabName ?? "", out value) && value.Any(HasVneiRelevantDrops); } } internal static bool TryGetVneiDisplayResults(CharacterDrop characterDrop, out List results) { lock (Sync) { results = new List(); if ((Object)(object)characterDrop == (Object)null) { return false; } GameObject gameObject = ((Component)characterDrop).gameObject; string text = ((gameObject != null) ? ((Object)gameObject).name : null) ?? ""; List value; List list = (ActiveEntriesByPrefab.TryGetValue(text, out value) ? value.Where(HasVneiRelevantDrops).ToList() : null); bool flag = list != null && list.Count > 0; CharacterDropSnapshot snapshot; List list2 = (CharacterDropRuntime.TryGetSnapshot(text, out snapshot) ? snapshot.Drops : CloneSnapshotDrops(characterDrop.m_drops)); if (!flag && list2.Count == 0) { return false; } bool num = list?.Any((CharacterDropPrefabEntry entry) => !DropConditionEvaluator.HasCharacterConditions(entry.Conditions)) ?? false; HashSet seen = new HashSet(StringComparer.Ordinal); if (!num) { foreach (CharacterDropItemSnapshot item in list2) { AddVneiSnapshotDrop(results, seen, item); } } IEnumerable enumerable = list; foreach (CharacterDropPrefabEntry item2 in enumerable ?? Enumerable.Empty()) { IEnumerable enumerable2 = item2.CharacterDrop?.Drops; foreach (CharacterDropEntryDefinition item3 in enumerable2 ?? Enumerable.Empty()) { AddVneiConfiguredDrop(results, seen, item3, text + "/characterDrop"); } } return flag || list2.Count > 0; } } private static bool HasVneiRelevantDrops(CharacterDropPrefabEntry entry) { if (entry == null) { return false; } return entry.CharacterDrop?.Drops?.Count > 0; } private static void AddVneiSnapshotDrop(List results, HashSet seen, CharacterDropItemSnapshot drop) { if (!((Object)(object)drop.ItemPrefab == (Object)null)) { string item = string.Format("{0}\n{1}\n{2}\n{3}", ((Object)drop.ItemPrefab).name, drop.AmountMin, drop.AmountMax, drop.Chance.ToString("R")); if (seen.Add(item)) { results.Add(new VneiRecipeResult(((Object)drop.ItemPrefab).name, 1, 1, 1f, Math.Max(1, drop.AmountMin), Math.Max(Math.Max(1, drop.AmountMin), drop.AmountMax), Mathf.Clamp01(drop.Chance))); } } } private static void AddVneiConfiguredDrop(List results, HashSet seen, CharacterDropEntryDefinition definition, string context) { string text = (definition.Item ?? "").Trim(); if (text.Length == 0) { return; } GameObject val = ResolveItemPrefab(text, context); if (!((Object)(object)val == (Object)null)) { int num = Math.Max(1, definition.AmountMin.GetValueOrDefault(1)); int max = Math.Max(num, definition.AmountMax ?? definition.AmountMin.GetValueOrDefault(1)); float chance = Mathf.Clamp01(definition.Chance.GetValueOrDefault(1f)); string item = BuildDropRowFingerprint(definition); if (seen.Add(item)) { results.Add(new VneiRecipeResult(((Object)val).name, 1, 1, 1f, num, max, chance)); } } } } internal static class CharacterBossPolicyRuntime { private sealed class RuntimeState { public static RuntimeState Empty { get; } = new RuntimeState(); public HashSet AutoDetectedBossPrefabs { get; } = new HashSet(StringComparer.OrdinalIgnoreCase); public HashSet AutoDetectedBossPrefabHashes { get; } = new HashSet(); } private static RuntimeState _runtimeState = RuntimeState.Empty; private static int? _runtimeConfigurationGameDataSignature; internal static void Reset() { _runtimeState = RuntimeState.Empty; _runtimeConfigurationGameDataSignature = null; } internal static IReadOnlyCollection GetAutoDetectedBossPrefabNames() { EnsureRuntimeState(); return _runtimeState.AutoDetectedBossPrefabs; } internal static bool IsAutoDetectedBossPrefab(string prefabName) { if (string.IsNullOrWhiteSpace(prefabName)) { return false; } EnsureRuntimeState(); return _runtimeState.AutoDetectedBossPrefabs.Contains(prefabName); } internal static bool IsAutoDetectedBossPrefab(int prefabHash) { if (prefabHash == 0) { return false; } EnsureRuntimeState(); return _runtimeState.AutoDetectedBossPrefabHashes.Contains(prefabHash); } private static void EnsureRuntimeState() { int num = CharacterDropManager.ComputeGameDataSignatureForDespawnRuntime(); if (_runtimeConfigurationGameDataSignature != num) { _runtimeState = BuildRuntimeState(); _runtimeConfigurationGameDataSignature = num; } } private static RuntimeState BuildRuntimeState() { RuntimeState runtimeState = new RuntimeState(); foreach (GameObject item in CharacterDropManager.EnumeratePrefabsForDespawnRuntime()) { if (IsBossPrefab(item)) { string prefabNameForDespawnRuntime = CharacterDropManager.GetPrefabNameForDespawnRuntime(item); if (!string.IsNullOrWhiteSpace(prefabNameForDespawnRuntime)) { runtimeState.AutoDetectedBossPrefabs.Add(prefabNameForDespawnRuntime); runtimeState.AutoDetectedBossPrefabHashes.Add(StringExtensionMethods.GetStableHashCode(prefabNameForDespawnRuntime)); } } } return runtimeState; } private static bool IsBossPrefab(GameObject? prefab) { Character val = default(Character); if ((Object)(object)prefab != (Object)null && prefab.TryGetComponent(ref val)) { return val.IsBoss(); } return false; } } internal static class BossTamedPressureRuntime { private sealed class Rule { public HashSet BossPrefabs { get; } = new HashSet(StringComparer.OrdinalIgnoreCase); public HashSet ExcludedBossPrefabs { get; } = new HashSet(StringComparer.OrdinalIgnoreCase); public HashSet ExcludedTamedPrefabs { get; } = new HashSet(StringComparer.OrdinalIgnoreCase); public HashSet ExtraPressuredPrefabs { get; } = new HashSet(StringComparer.OrdinalIgnoreCase); public HashSet BossPrefabHashes { get; } = new HashSet(); public HashSet ExcludedBossPrefabHashes { get; } = new HashSet(); public HashSet ExcludedTamedPrefabHashes { get; } = new HashSet(); public HashSet ExtraPressuredPrefabHashes { get; } = new HashSet(); public float Range { get; set; } public float ScanInterval { get; set; } public float DamageInterval { get; set; } public int MaxTargetsPerBoss { get; set; } public float PercentMaxHealthPerSecond { get; set; } public float MinBaseHealth { get; set; } public float IncomingDamageMultiplier { get; set; } public float OutgoingDamageMultiplier { get; set; } public string? Message { get; set; } public float MessageInterval { get; set; } public double NextScanAt { get; set; } public double NextDamageAt { get; set; } public Dictionary Targets { get; } = new Dictionary(); public Dictionary NextMessageByPlayer { get; } = new Dictionary(); } private sealed class BossCandidate { public Character Character { get; set; } public Vector3 Position { get; set; } } private sealed class TargetCandidate { public Character Character { get; set; } public Vector3 Position { get; set; } public int Order { get; set; } } private sealed class TrackedTarget { public Character Character { get; set; } public double ExpiresAt { get; set; } } private readonly struct BucketKey : IEquatable { public int X { get; } public int Z { get; } public BucketKey(int x, int z) { X = x; Z = z; } public bool Equals(BucketKey other) { if (X == other.X) { return Z == other.Z; } return false; } public override bool Equals(object? obj) { if (obj is BucketKey other) { return Equals(other); } return false; } public override int GetHashCode() { return (X * 397) ^ Z; } } private const float DefaultRange = 24f; private const float DefaultScanInterval = 2f; private const float DefaultDamageInterval = 1f; private const int DefaultMaxTargetsPerBoss = 6; private const float DefaultPercentMaxHealthPerSecond = 0.007f; private const float DefaultMinBaseHealth = 300f; private const float DefaultIncomingDamageMultiplier = 1f; private const float DefaultOutgoingDamageMultiplier = 1f; private const float DefaultMessageInterval = 8f; private const string DefaultMessage = "Tamed creatures near a boss are weakened."; private static readonly int ActiveUntilKey = StringExtensionMethods.GetStableHashCode("DropNSpawn_BossTamedPressure_Until"); private static readonly int IncomingMultiplierKey = StringExtensionMethods.GetStableHashCode("DropNSpawn_BossTamedPressure_Incoming"); private static readonly int OutgoingMultiplierKey = StringExtensionMethods.GetStableHashCode("DropNSpawn_BossTamedPressure_Outgoing"); private static readonly int GenerationKey = StringExtensionMethods.GetStableHashCode("DropNSpawn_BossTamedPressure_Generation"); private static readonly List Rules = new List(); private static int CurrentGeneration = 1; internal static void Configure(IEnumerable definitions) { AdvanceGeneration(); Rules.Clear(); foreach (BossTamedPressureDefinition item in definitions ?? Enumerable.Empty()) { Rules.Add(CompileRule(item)); } } internal static void ExecuteServerTick() { if (!DropNSpawnPlugin.IsRuntimeServer() || !PluginSettingsFacade.IsCharacterDomainEnabled() || !PluginSettingsFacade.IsBossTamedPressureEnabled() || Rules.Count == 0 || (Object)(object)ZNet.instance == (Object)null) { return; } double timeSeconds = GetTimeSeconds(); foreach (Rule rule in Rules) { if (timeSeconds >= rule.NextScanAt) { ScanRule(rule, timeSeconds); rule.NextScanAt = timeSeconds + (double)rule.ScanInterval; } if (timeSeconds >= rule.NextDamageAt) { ApplyPeriodicDamage(rule, timeSeconds); rule.NextDamageAt = timeSeconds + (double)rule.DamageInterval; } } } internal static void ApplyDamageMultipliers(Character? victim, HitData? hit) { if (!((Object)(object)victim == (Object)null) && hit != null && hit.HaveAttacker() && PluginSettingsFacade.IsCharacterDomainEnabled() && PluginSettingsFacade.IsBossTamedPressureEnabled() && Rules.Count != 0) { double timeSeconds = GetTimeSeconds(); float num = 1f; if (TryGetCharacterZdo(victim, out ZDO zdo) && TryGetActiveMultiplier(zdo, IncomingMultiplierKey, timeSeconds, out var multiplier)) { num *= multiplier; } ZDO val = ResolveAttackerZdo(hit); if (val != null && TryGetActiveMultiplier(val, OutgoingMultiplierKey, timeSeconds, out var multiplier2)) { num *= multiplier2; } if (!Mathf.Approximately(num, 1f)) { hit.ApplyModifier(Mathf.Max(0f, num)); } } } internal static string BuildRuleKey(BossTamedPressureDefinition definition) { return string.Join("|", string.Join(",", definition.BossPrefabs ?? new List()), string.Join(",", definition.ExcludedBossPrefabs ?? new List()), definition.Targets?.Range?.ToString("R") ?? "", definition.Targets?.ScanInterval?.ToString("R") ?? "", definition.Targets?.MaxPerBoss?.ToString() ?? "", string.Join(",", definition.Targets?.ExcludedTamedPrefabs ?? new List()), string.Join(",", definition.Targets?.ExtraPressuredPrefabs ?? new List()), definition.Pressure?.DamageInterval?.ToString("R") ?? "", definition.Pressure?.DamagePercentPerSecond?.ToString("R") ?? "", definition.Pressure?.DamageMinBaseHealth?.ToString("R") ?? "", definition.Pressure?.IncomingDamageMultiplier?.ToString("R") ?? "", definition.Pressure?.OutgoingDamageMultiplier?.ToString("R") ?? "", definition.Message ?? "", definition.MessageInterval?.ToString("R") ?? ""); } private static Rule CompileRule(BossTamedPressureDefinition definition) { BossTamedPressureTargetsDefinition targets = definition.Targets; BossTamedPressurePressureDefinition pressure = definition.Pressure; Rule rule = new Rule { Range = (targets?.Range).GetValueOrDefault(24f), ScanInterval = (targets?.ScanInterval).GetValueOrDefault(2f), DamageInterval = (pressure?.DamageInterval).GetValueOrDefault(1f), MaxTargetsPerBoss = (targets?.MaxPerBoss).GetValueOrDefault(6), PercentMaxHealthPerSecond = (pressure?.DamagePercentPerSecond).GetValueOrDefault(0.007f), MinBaseHealth = (pressure?.DamageMinBaseHealth).GetValueOrDefault(300f), IncomingDamageMultiplier = (pressure?.IncomingDamageMultiplier).GetValueOrDefault(1f), OutgoingDamageMultiplier = (pressure?.OutgoingDamageMultiplier).GetValueOrDefault(1f), Message = (definition.Message ?? "Tamed creatures near a boss are weakened."), MessageInterval = definition.MessageInterval.GetValueOrDefault(8f) }; AddAll(rule.BossPrefabs, rule.BossPrefabHashes, definition.BossPrefabs); AddAll(rule.ExcludedBossPrefabs, rule.ExcludedBossPrefabHashes, definition.ExcludedBossPrefabs); AddAll(rule.ExcludedTamedPrefabs, rule.ExcludedTamedPrefabHashes, targets?.ExcludedTamedPrefabs); AddAll(rule.ExtraPressuredPrefabs, rule.ExtraPressuredPrefabHashes, targets?.ExtraPressuredPrefabs); return rule; } private static void ScanRule(Rule rule, double now) { //IL_0083: Unknown result type (might be due to invalid IL or missing references) List allCharacters = Character.GetAllCharacters(); if (allCharacters == null || allCharacters.Count == 0) { return; } float bucketSize = Mathf.Max(rule.Range, 1f); List list = new List(); BuildBossCandidates(rule, allCharacters, list); if (list.Count == 0) { return; } Dictionary> dictionary = new Dictionary>(); BuildTargetBuckets(rule, allCharacters, bucketSize, dictionary); if (dictionary.Count == 0) { return; } float rangeSqr = rule.Range * rule.Range; List list2 = new List(); foreach (BossCandidate item in list) { CollectTargetsNearBoss(rule, dictionary, bucketSize, item.Position, rangeSqr, list2); if (list2.Count == 0) { continue; } if (list2.Count > 1) { list2.Sort((TargetCandidate left, TargetCandidate right) => left.Order.CompareTo(right.Order)); } int num = 0; foreach (TargetCandidate item2 in list2) { if (item2.Character != item.Character && IsValidCharacter(item2.Character)) { TrackTarget(rule, item2.Character, now); num++; if (num >= rule.MaxTargetsPerBoss) { break; } } } } } private static void BuildBossCandidates(Rule rule, List characters, List bosses) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < characters.Count; i++) { Character val = characters[i]; if (IsValidCharacter(val) && TryGetCharacterZdo(val, out ZDO zdo)) { int prefab = zdo.GetPrefab(); if (IsBossSource(rule, val, prefab)) { bosses.Add(new BossCandidate { Character = val, Position = val.GetCenterPoint() }); } } } } private static void BuildTargetBuckets(Rule rule, List characters, float bucketSize, Dictionary> targetBuckets) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < characters.Count; i++) { Character val = characters[i]; if (!IsValidCharacter(val) || !TryGetCharacterZdo(val, out ZDO zdo)) { continue; } int prefab = zdo.GetPrefab(); if (IsEligiblePressureTarget(rule, val, zdo, prefab)) { Vector3 position = ((Component)val).transform.position; TargetCandidate item = new TargetCandidate { Character = val, Position = position, Order = i }; BucketKey bucketKey = GetBucketKey(position, bucketSize); if (!targetBuckets.TryGetValue(bucketKey, out List value)) { value = (targetBuckets[bucketKey] = new List()); } value.Add(item); } } } private static void CollectTargetsNearBoss(Rule rule, Dictionary> targetBuckets, float bucketSize, Vector3 bossPosition, float rangeSqr, List nearbyTargets) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0084: 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) nearbyTargets.Clear(); int bucketCoordinate = GetBucketCoordinate(bossPosition.x - rule.Range, bucketSize); int bucketCoordinate2 = GetBucketCoordinate(bossPosition.x + rule.Range, bucketSize); int bucketCoordinate3 = GetBucketCoordinate(bossPosition.z - rule.Range, bucketSize); int bucketCoordinate4 = GetBucketCoordinate(bossPosition.z + rule.Range, bucketSize); for (int i = bucketCoordinate; i <= bucketCoordinate2; i++) { for (int j = bucketCoordinate3; j <= bucketCoordinate4; j++) { if (!targetBuckets.TryGetValue(new BucketKey(i, j), out List value)) { continue; } foreach (TargetCandidate item in value) { if (IsWithinHorizontalRange(bossPosition, item.Position, rangeSqr)) { nearbyTargets.Add(item); } } } } } private static void TrackTarget(Rule rule, Character target, double now) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) if (TryGetCharacterZdo(target, out ZDO zdo)) { ZDOID uid = zdo.m_uid; double num = now + (double)rule.ScanInterval + 0.5; rule.Targets[uid] = new TrackedTarget { Character = target, ExpiresAt = num }; float @float = zdo.GetFloat(ActiveUntilKey, 0f); float num2 = (float)Math.Max(@float, num); zdo.Set(ActiveUntilKey, num2); float num3 = rule.IncomingDamageMultiplier; float num4 = rule.OutgoingDamageMultiplier; if ((double)@float > now && zdo.GetInt(GenerationKey, 0) == CurrentGeneration) { num3 = Math.Max(zdo.GetFloat(IncomingMultiplierKey, 1f), num3); num4 = Math.Min(zdo.GetFloat(OutgoingMultiplierKey, 1f), num4); } zdo.Set(GenerationKey, CurrentGeneration, false); zdo.Set(IncomingMultiplierKey, Mathf.Clamp(num3, 0f, 10f)); zdo.Set(OutgoingMultiplierKey, Mathf.Clamp(num4, 0f, 10f)); } } private static void ApplyPeriodicDamage(Rule rule, double now) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Expected O, but got Unknown if (rule.PercentMaxHealthPerSecond <= 0f || rule.DamageInterval <= 0f) { RemoveExpiredTargets(rule, now); return; } ZDOID[] array = rule.Targets.Keys.ToArray(); foreach (ZDOID key in array) { if (!rule.Targets.TryGetValue(key, out TrackedTarget value) || value.ExpiresAt < now || !IsEligiblePressureTarget(rule, value.Character)) { rule.Targets.Remove(key); continue; } float num = Mathf.Max(value.Character.GetMaxHealth(), rule.MinBaseHealth) * rule.PercentMaxHealthPerSecond * rule.DamageInterval; if (!(num <= 0f)) { HitData val = new HitData { m_hitType = (HitType)0 }; val.m_damage.m_damage = num; value.Character.Damage(val); TrySendMessage(rule, value.Character, now); } } } private static void RemoveExpiredTargets(Rule rule, double now) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) ZDOID[] array = rule.Targets.Keys.ToArray(); foreach (ZDOID key in array) { if (!rule.Targets.TryGetValue(key, out TrackedTarget value) || value.ExpiresAt < now) { rule.Targets.Remove(key); } } } private static bool IsBossSource(Rule rule, Character character, int prefabHash) { if (prefabHash == 0 || rule.ExcludedBossPrefabHashes.Contains(prefabHash)) { return false; } if (!character.IsBoss() && !CharacterBossPolicyRuntime.IsAutoDetectedBossPrefab(prefabHash)) { return rule.BossPrefabHashes.Contains(prefabHash); } return true; } private static bool IsEligiblePressureTarget(Rule rule, Character? character) { if (!IsValidCharacter(character) || character.IsPlayer() || !TryGetCharacterZdo(character, out ZDO zdo)) { return false; } return IsEligiblePressureTarget(rule, character, zdo, zdo.GetPrefab()); } private static bool IsEligiblePressureTarget(Rule rule, Character character, ZDO zdo, int prefabHash) { if (zdo == null || character.IsPlayer()) { return false; } if (rule.ExtraPressuredPrefabHashes.Count <= 0 && rule.ExcludedTamedPrefabHashes.Count <= 0) { return IsTamedMonsterAi(character); } if (prefabHash == 0) { return false; } if (rule.ExtraPressuredPrefabHashes.Contains(prefabHash)) { return true; } if (IsTamedMonsterAi(character)) { return !rule.ExcludedTamedPrefabHashes.Contains(prefabHash); } return false; } private static bool IsTamedMonsterAi(Character character) { if (character.IsTamed()) { return (Object)(object)((Component)character).GetComponent() != (Object)null; } return false; } private static bool IsWithinHorizontalRange(Vector3 origin, Vector3 target, float rangeSqr) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) float num = target.x - origin.x; float num2 = target.z - origin.z; return num * num + num2 * num2 <= rangeSqr; } private static BucketKey GetBucketKey(Vector3 position, float bucketSize) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) return new BucketKey(GetBucketCoordinate(position.x, bucketSize), GetBucketCoordinate(position.z, bucketSize)); } private static int GetBucketCoordinate(float value, float bucketSize) { return Mathf.FloorToInt(value / bucketSize); } private static bool IsValidCharacter(Character? character) { if ((Object)(object)character != (Object)null && (Object)(object)((Component)character).gameObject != (Object)null) { return !character.IsDead(); } return false; } private static bool TryGetCharacterZdo(Character character, [NotNullWhen(true)] out ZDO? zdo) { object obj; if (character == null) { obj = null; } else { ZNetView nview = character.m_nview; obj = ((nview != null) ? nview.GetZDO() : null); } zdo = (ZDO?)obj; return zdo != null; } private static ZDO? ResolveAttackerZdo(HitData hit) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) Character attacker = hit.GetAttacker(); if ((Object)(object)attacker != (Object)null && TryGetCharacterZdo(attacker, out ZDO zdo)) { return zdo; } if (((ZDOID)(ref hit.m_attacker)).IsNone()) { return null; } ZDOMan instance = ZDOMan.instance; if (instance == null) { return null; } return instance.GetZDO(hit.m_attacker); } private static bool TryGetActiveMultiplier(ZDO zdo, int multiplierKey, double now, out float multiplier) { multiplier = 1f; if (zdo.GetInt(GenerationKey, 0) != CurrentGeneration || (double)zdo.GetFloat(ActiveUntilKey, 0f) <= now) { return false; } multiplier = Mathf.Clamp(zdo.GetFloat(multiplierKey, 1f), 0f, 10f); return !Mathf.Approximately(multiplier, 1f); } private static void TrySendMessage(Rule rule, Character target, double now) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrWhiteSpace(rule.Message) || !SceneProximityQueries.TryFindNearestLivingPlayerInRangeXZ(target.GetCenterPoint(), Mathf.Max(rule.Range, 32f), out var playerId) || playerId == 0L) { return; } float num = Mathf.Max(rule.MessageInterval, rule.DamageInterval); if (rule.NextMessageByPlayer.TryGetValue(playerId, out var value) && now < value) { return; } rule.NextMessageByPlayer[playerId] = now + (double)num; if (playerId == ZNet.GetUID() && (Object)(object)Player.m_localPlayer != (Object)null) { ((Character)Player.m_localPlayer).Message((MessageType)1, rule.Message, 0, (Sprite)null); return; } ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != null) { instance.InvokeRoutedRPC(playerId, "ShowMessage", new object[2] { 1, rule.Message }); } } private static double GetTimeSeconds() { ZNet instance = ZNet.instance; if (instance == null) { return Time.time; } return instance.GetTimeSeconds(); } private static void AdvanceGeneration() { CurrentGeneration++; if (CurrentGeneration <= 0) { CurrentGeneration = 1; } } private static void AddAll(HashSet target, HashSet hashes, IEnumerable? values) { if (values == null) { return; } foreach (string value in values) { string text = (value ?? "").Trim(); if (text.Length > 0) { target.Add(text); hashes.Add(StringExtensionMethods.GetStableHashCode(text)); } } } } internal static class CharacterDespawnRuntime { private sealed class CompiledDespawnRefundDefinition { public GameObject Prefab { get; set; } public int Amount { get; set; } } private sealed class CompiledDespawnRule { public CharacterDropPrefabEntry Entry { get; set; } public float? RangeOverride { get; set; } public float? DelayOverride { get; set; } public List Refunds { get; } = new List(); public IReadOnlyList ResolvedRefunds { get; set; } = Array.Empty(); } private sealed class RuntimeState { public static RuntimeState Empty { get; } = new RuntimeState(); public Dictionary RulesByPrefab { get; } = new Dictionary(StringComparer.OrdinalIgnoreCase); public Dictionary RulesByPrefabHash { get; } = new Dictionary(); public Dictionary PrefabNamesByHash { get; } = new Dictionary(); public HashSet BootstrapPrefabs { get; } = new HashSet(StringComparer.OrdinalIgnoreCase); public IReadOnlyList BootstrapPrefabOrder { get; set; } = Array.Empty(); } private static readonly HashSet LoggedSkippedConditionalDespawnEntries = new HashSet(StringComparer.Ordinal); private static RuntimeState _runtimeState = RuntimeState.Empty; private static string _runtimeConfigurationSignature = ""; private static int? _runtimeConfigurationGameDataSignature; internal static void Reset() { CharacterBossPolicyRuntime.Reset(); _runtimeState = RuntimeState.Empty; _runtimeConfigurationSignature = ""; _runtimeConfigurationGameDataSignature = null; } internal static IReadOnlyList GetDespawnBootstrapPrefabOrder(string configurationSignature, IReadOnlyDictionary> activeEntriesByPrefab) { EnsureRuntimeState(configurationSignature, activeEntriesByPrefab); return _runtimeState.BootstrapPrefabOrder; } internal static bool TryResolveDespawnTrackingRule(string prefabName, string configurationSignature, IReadOnlyDictionary> activeEntriesByPrefab, out float? rangeOverride, out float? delayOverride, out IReadOnlyCollection refunds) { rangeOverride = null; delayOverride = null; refunds = (IReadOnlyCollection)(object)Array.Empty(); if (string.IsNullOrWhiteSpace(prefabName)) { return false; } EnsureRuntimeState(configurationSignature, activeEntriesByPrefab); if (_runtimeState.RulesByPrefab.TryGetValue(prefabName, out CompiledDespawnRule value)) { rangeOverride = value.RangeOverride; delayOverride = value.DelayOverride; refunds = value.ResolvedRefunds; return true; } return CharacterBossPolicyRuntime.IsAutoDetectedBossPrefab(prefabName); } internal static bool IsEligibleDespawnTrackingPrefabName(string prefabName, string configurationSignature, IReadOnlyDictionary> activeEntriesByPrefab) { if (string.IsNullOrWhiteSpace(prefabName)) { return false; } EnsureRuntimeState(configurationSignature, activeEntriesByPrefab); return _runtimeState.BootstrapPrefabs.Contains(prefabName); } internal static bool TryResolveDespawnTrackingRule(int prefabHash, string configurationSignature, IReadOnlyDictionary> activeEntriesByPrefab, out string prefabName, out float? rangeOverride, out float? delayOverride, out IReadOnlyCollection refunds) { prefabName = ""; rangeOverride = null; delayOverride = null; refunds = (IReadOnlyCollection)(object)Array.Empty(); if (prefabHash == 0) { return false; } EnsureRuntimeState(configurationSignature, activeEntriesByPrefab); if (!_runtimeState.PrefabNamesByHash.TryGetValue(prefabHash, out prefabName) || string.IsNullOrWhiteSpace(prefabName)) { prefabName = ResolvePrefabName(prefabHash); } if (_runtimeState.RulesByPrefabHash.TryGetValue(prefabHash, out CompiledDespawnRule value)) { rangeOverride = value.RangeOverride; delayOverride = value.DelayOverride; refunds = value.ResolvedRefunds; return !string.IsNullOrWhiteSpace(prefabName); } if (CharacterBossPolicyRuntime.IsAutoDetectedBossPrefab(prefabHash)) { return !string.IsNullOrWhiteSpace(prefabName); } return false; } internal static bool IsEligibleDespawnTrackingPrefabHash(int prefabHash, string configurationSignature, IReadOnlyDictionary> activeEntriesByPrefab) { if (prefabHash == 0) { return false; } EnsureRuntimeState(configurationSignature, activeEntriesByPrefab); if (!_runtimeState.RulesByPrefabHash.ContainsKey(prefabHash)) { return CharacterBossPolicyRuntime.IsAutoDetectedBossPrefab(prefabHash); } return true; } private static void EnsureRuntimeState(string configurationSignature, IReadOnlyDictionary> activeEntriesByPrefab) { int num = CharacterDropManager.ComputeGameDataSignatureForDespawnRuntime(); if (_runtimeConfigurationGameDataSignature != num || !string.Equals(_runtimeConfigurationSignature, configurationSignature, StringComparison.Ordinal)) { _runtimeState = BuildRuntimeState(activeEntriesByPrefab); _runtimeConfigurationGameDataSignature = num; _runtimeConfigurationSignature = configurationSignature; } } private static RuntimeState BuildRuntimeState(IReadOnlyDictionary> activeEntriesByPrefab) { RuntimeState runtimeState = new RuntimeState(); foreach (string autoDetectedBossPrefabName in CharacterBossPolicyRuntime.GetAutoDetectedBossPrefabNames()) { runtimeState.BootstrapPrefabs.Add(autoDetectedBossPrefabName); runtimeState.PrefabNamesByHash[StringExtensionMethods.GetStableHashCode(autoDetectedBossPrefabName)] = autoDetectedBossPrefabName; } foreach (var (text2, list2) in activeEntriesByPrefab) { foreach (CharacterDropPrefabEntry item in list2) { if (TryCompileDespawnRule(item, out CompiledDespawnRule compiledRule)) { if (runtimeState.RulesByPrefab.TryGetValue(text2, out CompiledDespawnRule value)) { CharacterDropManager.WarnInvalidEntryForDespawnRuntime("Character prefab '" + text2 + "' defines multiple unconditional despawn rules. The later entry '" + CharacterDropManager.BuildCompiledDropContextForDespawnRuntime(item) + "' will override the earlier entry '" + CharacterDropManager.BuildCompiledDropContextForDespawnRuntime(value.Entry) + "'."); } runtimeState.RulesByPrefab[text2] = compiledRule; runtimeState.RulesByPrefabHash[StringExtensionMethods.GetStableHashCode(text2)] = compiledRule; runtimeState.PrefabNamesByHash[StringExtensionMethods.GetStableHashCode(text2)] = text2; runtimeState.BootstrapPrefabs.Add(text2); } } } runtimeState.BootstrapPrefabOrder = runtimeState.BootstrapPrefabs.OrderBy((string prefabName) => prefabName, StringComparer.OrdinalIgnoreCase).ToArray(); return runtimeState; } private static bool TryCompileDespawnRule(CharacterDropPrefabEntry entry, out CompiledDespawnRule compiledRule) { compiledRule = null; if (entry.Despawn == null) { return false; } if (DropConditionEvaluator.HasCharacterConditions(entry.Conditions)) { WarnUnsupportedConditionalDespawn(entry); return false; } DespawnDefinition despawn = entry.Despawn; string text = CharacterDropManager.BuildCompiledDropContextForDespawnRuntime(entry) + "/despawn"; CompiledDespawnRule compiledDespawnRule = new CompiledDespawnRule { Entry = entry, RangeOverride = despawn.Range, DelayOverride = despawn.Delay }; IEnumerable refunds = despawn.Refunds; foreach (DespawnRefundEntryDefinition item in refunds ?? Enumerable.Empty()) { string text2 = (item.Item ?? "").Trim(); if (text2.Length == 0) { CharacterDropManager.WarnInvalidEntryForDespawnRuntime("Entry '" + text + "' contains a despawn refund without an item name."); continue; } GameObject val = CharacterDropManager.ResolveItemPrefabForDespawnRuntime(text2, text); if (!((Object)(object)val == (Object)null)) { compiledDespawnRule.Refunds.Add(new CompiledDespawnRefundDefinition { Prefab = val, Amount = Math.Max(1, item.Amount.GetValueOrDefault(1)) }); } } compiledDespawnRule.ResolvedRefunds = BuildResolvedDespawnRefunds(compiledDespawnRule.Refunds); compiledRule = compiledDespawnRule; return true; } private static string ResolvePrefabName(int prefabHash) { if (prefabHash == 0 || (Object)(object)ZNetScene.instance == (Object)null) { return ""; } GameObject prefab = ZNetScene.instance.GetPrefab(prefabHash); if (!((Object)(object)prefab != (Object)null)) { return ""; } return ((Object)prefab).name; } private static IReadOnlyList BuildResolvedDespawnRefunds(IReadOnlyList refunds) { if (refunds.Count == 0) { return Array.Empty(); } DespawnRefundDrop[] array = new DespawnRefundDrop[refunds.Count]; for (int i = 0; i < refunds.Count; i++) { CompiledDespawnRefundDefinition compiledDespawnRefundDefinition = refunds[i]; array[i] = new DespawnRefundDrop(compiledDespawnRefundDefinition.Prefab, compiledDespawnRefundDefinition.Amount); } return array; } private static void WarnUnsupportedConditionalDespawn(CharacterDropPrefabEntry entry) { string text = CharacterDropManager.BuildCompiledDropContextForDespawnRuntime(entry); if (LoggedSkippedConditionalDespawnEntries.Add(text)) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("Entry '" + text + "' defines despawn with character conditions. Conditional despawn overrides are not supported because despawn is prefab-wide; conditions on this entry still apply to characterDrop, but the despawn block is skipped. Move despawn to an unconditional entry if it should apply. Boss prefabs without a usable explicit rule will continue using default auto-despawn settings, while non-boss prefabs without a usable explicit rule will not be tracked for despawn.")); } } } internal static class CommentedYamlTemplateSupport { internal static void AppendTemplateComment(StringBuilder builder, string text) { builder.Append("# "); builder.AppendLine(text); } internal static void AppendTemplateLine(StringBuilder builder, int indent, string text) { builder.Append("# "); builder.Append(' ', indent * 2); builder.AppendLine(text); } internal static void AppendTemplateNestedLine(StringBuilder builder, int indent, string text) { builder.Append("# "); builder.Append(' ', indent * 2); builder.Append("# "); builder.AppendLine(text); } internal static void AppendActiveTemplateLine(StringBuilder builder, int indent, string text) { builder.Append(' ', indent * 2); builder.AppendLine(text); } internal static void AppendActiveTemplateBlankLine(StringBuilder builder) { builder.AppendLine(); } internal static void AppendTemplateBlankLine(StringBuilder builder) { builder.AppendLine("#"); } } internal static class ConfigurationEntryCloneSupport { internal static ConditionsDefinition? CloneConditions(ConditionsDefinition? source) { if (source == null) { return null; } return new ConditionsDefinition { Level = CloneIntRange(source.Level), Altitude = CloneFloatRange(source.Altitude), MinLevel = source.MinLevel, MaxLevel = source.MaxLevel, MinAltitude = source.MinAltitude, MaxAltitude = source.MaxAltitude, DistanceFromCenter = CloneFloatRange(source.DistanceFromCenter), MinDistanceFromCenter = source.MinDistanceFromCenter, MaxDistanceFromCenter = source.MaxDistanceFromCenter, Biomes = CloneStringList(source.Biomes), ResolvedBiomeMask = source.ResolvedBiomeMask, Locations = CloneStringList(source.Locations), TimeOfDay = CloneTimeOfDay(source.TimeOfDay), RequiredEnvironments = CloneStringList(source.RequiredEnvironments), RequiredGlobalKeys = CloneStringList(source.RequiredGlobalKeys), ForbiddenGlobalKeys = CloneStringList(source.ForbiddenGlobalKeys), States = CloneStringList(source.States), Factions = CloneStringList(source.Factions), InForest = source.InForest, InDungeon = source.InDungeon, InsidePlayerBase = source.InsidePlayerBase }; } internal static CharacterDropDefinition? CloneCharacterDropDefinition(CharacterDropDefinition? source) { if (source == null) { return null; } return new CharacterDropDefinition { Drops = CloneList(source.Drops, CloneCharacterDropEntryDefinition) }; } private static CharacterDropEntryDefinition CloneCharacterDropEntryDefinition(CharacterDropEntryDefinition source) { return new CharacterDropEntryDefinition { Item = source.Item, Amount = CloneIntRange(source.Amount), AmountMin = source.AmountMin, AmountMax = source.AmountMax, Chance = source.Chance, DontScale = source.DontScale, LevelMultiplier = source.LevelMultiplier, OnePerPlayer = source.OnePerPlayer, AmountLimit = source.AmountLimit, DropInStack = source.DropInStack }; } internal static DespawnDefinition? CloneDespawnDefinition(DespawnDefinition? source) { if (source == null) { return null; } return new DespawnDefinition { Range = source.Range, Delay = source.Delay, Refunds = CloneList(source.Refunds, CloneDespawnRefundEntryDefinition) }; } internal static DespawnRefundEntryDefinition CloneDespawnRefundEntryDefinition(DespawnRefundEntryDefinition source) { return new DespawnRefundEntryDefinition { Item = source.Item, Amount = source.Amount }; } internal static BossTamedPressureDefinition? CloneBossTamedPressureDefinition(BossTamedPressureDefinition? source) { if (source == null) { return null; } return new BossTamedPressureDefinition { BossPrefabs = CloneStringList(source.BossPrefabs), ExcludedBossPrefabs = CloneStringList(source.ExcludedBossPrefabs), Targets = CloneBossTamedPressureTargetsDefinition(source.Targets), Pressure = CloneBossTamedPressurePressureDefinition(source.Pressure), Message = source.Message, MessageInterval = source.MessageInterval }; } internal static BossTamedPressureTargetsDefinition? CloneBossTamedPressureTargetsDefinition(BossTamedPressureTargetsDefinition? source) { if (source == null) { return null; } return new BossTamedPressureTargetsDefinition { Range = source.Range, ScanInterval = source.ScanInterval, MaxPerBoss = source.MaxPerBoss, ExcludedTamedPrefabs = CloneStringList(source.ExcludedTamedPrefabs), ExtraPressuredPrefabs = CloneStringList(source.ExtraPressuredPrefabs) }; } internal static BossTamedPressurePressureDefinition? CloneBossTamedPressurePressureDefinition(BossTamedPressurePressureDefinition? source) { if (source == null) { return null; } return new BossTamedPressurePressureDefinition { DamageInterval = source.DamageInterval, DamagePercentPerSecond = source.DamagePercentPerSecond, DamageMinBaseHealth = source.DamageMinBaseHealth, IncomingDamageMultiplier = source.IncomingDamageMultiplier, OutgoingDamageMultiplier = source.OutgoingDamageMultiplier }; } internal static SpawnAreaDefinition? CloneSpawnAreaDefinition(SpawnAreaDefinition? source) { if (source == null) { return null; } return new SpawnAreaDefinition { LevelUpChance = source.LevelUpChance, SpawnInterval = source.SpawnInterval, TriggerDistance = source.TriggerDistance, SetPatrolSpawnPoint = source.SetPatrolSpawnPoint, SpawnRadius = source.SpawnRadius, NearRadius = source.NearRadius, FarRadius = source.FarRadius, MaxNear = source.MaxNear, MaxTotal = source.MaxTotal, MaxTotalSpawns = source.MaxTotalSpawns, OnGroundOnly = source.OnGroundOnly, Creatures = CloneList(source.Creatures, CloneSpawnAreaSpawnDefinition) }; } private static SpawnAreaSpawnDefinition CloneSpawnAreaSpawnDefinition(SpawnAreaSpawnDefinition source) { return new SpawnAreaSpawnDefinition { Creature = source.Creature, Weight = source.Weight, Level = CloneIntRange(source.Level), MinLevel = source.MinLevel, MaxLevel = source.MaxLevel, Faction = source.Faction, Data = source.Data, Fields = CloneStringDictionary(source.Fields), Objects = CloneStringList(source.Objects) }; } internal static CreatureSpawnerDefinition? CloneCreatureSpawnerDefinition(CreatureSpawnerDefinition? source) { if (source == null) { return null; } return new CreatureSpawnerDefinition { Creature = source.Creature, TimeOfDay = CloneTimeOfDay(source.TimeOfDay), RequiredGlobalKey = source.RequiredGlobalKey, BlockingGlobalKey = source.BlockingGlobalKey, Level = CloneIntRange(source.Level), MinLevel = source.MinLevel, MaxLevel = source.MaxLevel, LevelUpChance = source.LevelUpChance, RespawnTimeMinutes = source.RespawnTimeMinutes, SpawnCheckInterval = source.SpawnCheckInterval, SpawnGroupId = source.SpawnGroupId, SpawnGroupRadius = source.SpawnGroupRadius, SpawnerWeight = source.SpawnerWeight, MaxGroupSpawned = source.MaxGroupSpawned, TriggerDistance = source.TriggerDistance, TriggerNoise = source.TriggerNoise, RequireSpawnArea = source.RequireSpawnArea, AllowInsidePlayerBase = source.AllowInsidePlayerBase, WakeUpAnimation = source.WakeUpAnimation, SetPatrolSpawnPoint = source.SetPatrolSpawnPoint, Faction = source.Faction, Data = source.Data, Fields = CloneStringDictionary(source.Fields), Objects = CloneStringList(source.Objects) }; } internal static LocationOfferingBowlDefinition? CloneLocationOfferingBowlDefinition(LocationOfferingBowlDefinition? source) { if (source == null) { return null; } return new LocationOfferingBowlDefinition { Name = source.Name, UseItemText = source.UseItemText, UsedAltarText = source.UsedAltarText, CantOfferText = source.CantOfferText, WrongOfferText = source.WrongOfferText, IncompleteOfferText = source.IncompleteOfferText, BossItem = source.BossItem, BossItems = source.BossItems, BossPrefab = source.BossPrefab, ItemPrefab = source.ItemPrefab, SetGlobalKey = source.SetGlobalKey, RenderSpawnAreaGizmos = source.RenderSpawnAreaGizmos, AlertOnSpawn = source.AlertOnSpawn, SpawnBossDelay = source.SpawnBossDelay, SpawnBossDistance = CloneFloatRange(source.SpawnBossDistance), SpawnBossMaxDistance = source.SpawnBossMaxDistance, SpawnBossMinDistance = source.SpawnBossMinDistance, SpawnBossMaxYDistance = source.SpawnBossMaxYDistance, GetSolidHeightMargin = source.GetSolidHeightMargin, EnableSolidHeightCheck = source.EnableSolidHeightCheck, SpawnPointClearingRadius = source.SpawnPointClearingRadius, SpawnYOffset = source.SpawnYOffset, UseItemStands = source.UseItemStands, ItemStandPrefix = source.ItemStandPrefix, ItemStandMaxRange = source.ItemStandMaxRange, RespawnMinutes = source.RespawnMinutes, Data = source.Data, Fields = CloneStringDictionary(source.Fields), Objects = CloneStringList(source.Objects) }; } internal static LocationVegvisirDefinition CloneLocationVegvisirDefinition(LocationVegvisirDefinition source) { return new LocationVegvisirDefinition { Path = source.Path, ExpectedLocations = CloneStringList(source.ExpectedLocations), Name = source.Name, UseText = source.UseText, HoverName = source.HoverName, SetsGlobalKey = source.SetsGlobalKey, SetsPlayerKey = source.SetsPlayerKey, Locations = CloneList(source.Locations, CloneLocationVegvisirTargetDefinition) }; } internal static LocationRunestoneDefinition CloneLocationRunestoneDefinition(LocationRunestoneDefinition source) { return new LocationRunestoneDefinition { Path = source.Path, ExpectedLocationName = source.ExpectedLocationName, ExpectedLabel = source.ExpectedLabel, ExpectedTopic = source.ExpectedTopic, Name = source.Name, Topic = source.Topic, Label = source.Label, Text = source.Text, RandomTexts = CloneList(source.RandomTexts, CloneLocationRunestoneTextDefinition), LocationName = source.LocationName, PinName = source.PinName, PinType = source.PinType, ShowMap = source.ShowMap, Chance = source.Chance }; } internal static LocationRunestoneGlobalPinsDefinition? CloneLocationRunestoneGlobalPinsDefinition(LocationRunestoneGlobalPinsDefinition? source) { if (source == null) { return null; } return new LocationRunestoneGlobalPinsDefinition { TargetLocations = CloneList(source.TargetLocations, CloneLocationRunestoneGlobalPinTargetDefinition) }; } private static LocationRunestoneGlobalPinTargetDefinition CloneLocationRunestoneGlobalPinTargetDefinition(LocationRunestoneGlobalPinTargetDefinition source) { return new LocationRunestoneGlobalPinTargetDefinition { LocationName = source.LocationName, Chance = source.Chance, SourceBiomes = CloneStringList(source.SourceBiomes), PinName = source.PinName, PinType = source.PinType }; } internal static LocationItemStandDefinition CloneLocationItemStandDefinition(LocationItemStandDefinition source) { return new LocationItemStandDefinition { Path = source.Path, Name = source.Name, CanBeRemoved = source.CanBeRemoved, AutoAttach = source.AutoAttach, OrientationType = source.OrientationType, SupportedTypes = CloneStringList(source.SupportedTypes), SupportedItems = CloneStringList(source.SupportedItems), UnsupportedItems = CloneStringList(source.UnsupportedItems), PowerActivationDelay = source.PowerActivationDelay, GuardianPower = source.GuardianPower }; } private static LocationVegvisirTargetDefinition CloneLocationVegvisirTargetDefinition(LocationVegvisirTargetDefinition source) { return new LocationVegvisirTargetDefinition { LocationName = source.LocationName, PinName = source.PinName, PinType = source.PinType, DiscoverAll = source.DiscoverAll, ShowMap = source.ShowMap, Weight = source.Weight }; } private static LocationRunestoneTextDefinition CloneLocationRunestoneTextDefinition(LocationRunestoneTextDefinition source) { return new LocationRunestoneTextDefinition { Topic = source.Topic, Label = source.Label, Text = source.Text }; } private static IntRangeDefinition? CloneIntRange(IntRangeDefinition? source) { if (source == null) { return null; } return new IntRangeDefinition { Min = source.Min, Max = source.Max }; } private static FloatRangeDefinition? CloneFloatRange(FloatRangeDefinition? source) { if (source == null) { return null; } return new FloatRangeDefinition { Min = source.Min, Max = source.Max }; } private static TimeOfDayDefinition? CloneTimeOfDay(TimeOfDayDefinition? source) { if (source == null) { return null; } return new TimeOfDayDefinition { Values = (source.Values?.ToList() ?? new List()) }; } private static List? CloneList(List? source, Func cloneItem) { if (source == null) { return null; } List list = new List(source.Count); foreach (T item in source) { list.Add(cloneItem(item)); } return list; } private static List? CloneStringList(List? source) { return source?.ToList(); } private static Dictionary? CloneStringDictionary(Dictionary? source) { if (source != null) { return new Dictionary(source); } return null; } internal static DropTableDefinition? CloneDropTableDefinition(DropTableDefinition? source) { if (source == null) { return null; } DropTableDefinition dropTableDefinition = new DropTableDefinition(); CopyDropTablePayload(source, dropTableDefinition); return dropTableDefinition; } internal static DamageableDropTableDefinition? CloneDamageableDropTableDefinition(DamageableDropTableDefinition? source) { if (source == null) { return null; } DamageableDropTableDefinition damageableDropTableDefinition = new DamageableDropTableDefinition { Health = source.Health, MinToolTier = source.MinToolTier }; CopyDropTablePayload(source, damageableDropTableDefinition); return damageableDropTableDefinition; } private static void CopyDropTablePayload(DropTablePayloadDefinition source, DropTablePayloadDefinition target) { target.Rolls = CloneIntRange(source.Rolls); target.DropMin = source.DropMin; target.DropMax = source.DropMax; target.DropChance = source.DropChance; target.OneOfEach = source.OneOfEach; target.Drops = CloneList(source.Drops, CloneDropEntryDefinition); } private static DropEntryDefinition CloneDropEntryDefinition(DropEntryDefinition source) { return new DropEntryDefinition { Item = source.Item, Stack = CloneIntRange(source.Stack), StackMin = source.StackMin, StackMax = source.StackMax, Weight = source.Weight, DontScale = source.DontScale }; } internal static DestructibleDefinition? CloneDestructibleDefinition(DestructibleDefinition? source) { if (source == null) { return null; } return new DestructibleDefinition { Health = source.Health, MinToolTier = source.MinToolTier, DestructibleType = source.DestructibleType, SpawnWhenDestroyed = source.SpawnWhenDestroyed }; } internal static PickableDefinition? ClonePickableDefinition(PickableDefinition? source) { if (source == null) { return null; } return new PickableDefinition { OverrideName = source.OverrideName, Drop = ClonePickableDropDefinition(source.Drop), ExtraDrops = CloneDropTablePayloadDefinition(source.ExtraDrops) }; } private static PickableDropDefinition? ClonePickableDropDefinition(PickableDropDefinition? source) { if (source == null) { return null; } return new PickableDropDefinition { Item = source.Item, Amount = source.Amount, MinAmountScaled = source.MinAmountScaled, DontScale = source.DontScale }; } private static DropTablePayloadDefinition? CloneDropTablePayloadDefinition(DropTablePayloadDefinition? source) { if (source == null) { return null; } DropTablePayloadDefinition dropTablePayloadDefinition = new DropTablePayloadDefinition(); CopyDropTablePayload(source, dropTablePayloadDefinition); return dropTablePayloadDefinition; } internal static PickableItemDefinition? ClonePickableItemDefinition(PickableItemDefinition? source) { if (source == null) { return null; } return new PickableItemDefinition { RandomDrops = CloneList(source.RandomDrops, CloneRandomPickableItemDefinition), Drop = ClonePickableItemDropDefinition(source.Drop) }; } private static PickableItemDropDefinition? ClonePickableItemDropDefinition(PickableItemDropDefinition? source) { if (source == null) { return null; } return new PickableItemDropDefinition { Item = source.Item, Stack = source.Stack }; } private static RandomPickableItemDefinition CloneRandomPickableItemDefinition(RandomPickableItemDefinition source) { return new RandomPickableItemDefinition { Item = source.Item, Stack = CloneIntRange(source.Stack), StackMin = source.StackMin, StackMax = source.StackMax, Weight = source.Weight }; } internal static FishDefinition? CloneFishDefinition(FishDefinition? source) { if (source == null) { return null; } return new FishDefinition { ExtraDrops = CloneDropTablePayloadDefinition(source.ExtraDrops) }; } internal static SpawnSystemSpawnDefinition? CloneSpawnSystemSpawnDefinition(SpawnSystemSpawnDefinition? source) { if (source == null) { return null; } return new SpawnSystemSpawnDefinition { Name = source.Name, HuntPlayer = source.HuntPlayer, Level = CloneIntRange(source.Level), MinLevel = source.MinLevel, MaxLevel = source.MaxLevel, OverrideLevelUpChance = source.OverrideLevelUpChance, LevelUpMinCenterDistance = source.LevelUpMinCenterDistance, GroundOffset = source.GroundOffset, GroundOffsetRandom = source.GroundOffsetRandom, SpawnInterval = source.SpawnInterval, SpawnChance = source.SpawnChance, SpawnRadius = CloneFloatRange(source.SpawnRadius), SpawnRadiusMin = source.SpawnRadiusMin, SpawnRadiusMax = source.SpawnRadiusMax, GroupSize = CloneIntRange(source.GroupSize), GroupSizeMin = source.GroupSizeMin, GroupSizeMax = source.GroupSizeMax, GroupRadius = source.GroupRadius }; } internal static SpawnSystemConditionsDefinition? CloneSpawnSystemConditionsDefinition(SpawnSystemConditionsDefinition? source) { if (source == null) { return null; } return new SpawnSystemConditionsDefinition { NoSpawnRadius = source.NoSpawnRadius, MaxSpawned = source.MaxSpawned, Tilt = CloneFloatRange(source.Tilt), MinTilt = source.MinTilt, MaxTilt = source.MaxTilt, Altitude = CloneFloatRange(source.Altitude), MinAltitude = source.MinAltitude, MaxAltitude = source.MaxAltitude, OceanDepth = CloneFloatRange(source.OceanDepth), MinOceanDepth = source.MinOceanDepth, MaxOceanDepth = source.MaxOceanDepth, DistanceFromCenter = CloneFloatRange(source.DistanceFromCenter), MinDistanceFromCenter = source.MinDistanceFromCenter, MaxDistanceFromCenter = source.MaxDistanceFromCenter, Biomes = CloneStringList(source.Biomes), ResolvedBiomeMask = source.ResolvedBiomeMask, BiomeAreas = CloneStringList(source.BiomeAreas), TimeOfDay = CloneTimeOfDay(source.TimeOfDay), RequiredEnvironments = CloneStringList(source.RequiredEnvironments), RequiredGlobalKey = source.RequiredGlobalKey, InLava = source.InLava, InForest = source.InForest, InsidePlayerBase = source.InsidePlayerBase, CanSpawnCloseToPlayer = source.CanSpawnCloseToPlayer }; } internal static SpawnSystemModifiersDefinition? CloneSpawnSystemModifiersDefinition(SpawnSystemModifiersDefinition? source) { if (source == null) { return null; } return new SpawnSystemModifiersDefinition { Fields = CloneStringDictionary(source.Fields), Objects = CloneStringList(source.Objects), Data = source.Data, Faction = source.Faction }; } } internal enum DomainReloadOutcome { NoChange, Loaded, Rejected, DeferredStrictValidation, WaitingForPayload, Failed } internal sealed class DomainLoadState { internal string LastLoadedPayload { get; set; } = ""; internal string LastRejectedPayload { get; set; } = ""; internal string PendingStrictPayload { get; set; } = ""; internal string LastRejectedValidationKey { get; set; } = ""; } internal sealed class LocalLoadResult { internal List Entries { get; set; } = new List(); internal List Errors { get; set; } = new List(); internal List Warnings { get; set; } = new List(); internal int ParsedEntryCount { get; set; } internal int LoadedFileCount { get; set; } } internal sealed class StrictValidationResult { internal List Entries { get; set; } = new List(); internal List Warnings { get; set; } = new List(); } internal delegate bool TryGetSyncedEntriesDelegate(out List entries, out string payloadToken); internal sealed class DomainLoadHooks { internal Func, LocalLoadResult> ParseLocalDocuments { get; } internal Func, string, TState> BuildSyncedState { get; } internal Action CommitState { get; } internal Action> RejectLocalPayload { get; } internal Func GetAcceptedEntryCount { get; } internal Action>? LogPartiallyAcceptedLocalConfiguration { get; } internal Action? LogLocalLoadSuccess { get; } internal Action? OnUnchangedPayload { get; } internal Action? PublishCommittedState { get; } internal Func, bool>? CanStrictValidateNow { get; } internal Func, StrictValidationResult>? StrictValidateLocal { get; } internal DomainLoadHooks(Func, LocalLoadResult> parseLocalDocuments, Func, string, TState> buildSyncedState, Action commitState, Action> rejectLocalPayload, Func getAcceptedEntryCount, Action>? logPartiallyAcceptedLocalConfiguration = null, Action? logLocalLoadSuccess = null, Action? onUnchangedPayload = null, Action? publishCommittedState = null, Func, bool>? canStrictValidateNow = null, Func, StrictValidationResult>? strictValidateLocal = null) { ParseLocalDocuments = parseLocalDocuments; BuildSyncedState = buildSyncedState; CommitState = commitState; RejectLocalPayload = rejectLocalPayload; GetAcceptedEntryCount = getAcceptedEntryCount; LogPartiallyAcceptedLocalConfiguration = logPartiallyAcceptedLocalConfiguration; LogLocalLoadSuccess = logLocalLoadSuccess; OnUnchangedPayload = onUnchangedPayload; PublishCommittedState = publishCommittedState; CanStrictValidateNow = canStrictValidateNow; StrictValidateLocal = strictValidateLocal; } } internal sealed class DomainSyncHooks { internal TryGetSyncedEntriesDelegate TryGetSyncedEntries { get; } internal Func ShouldSkipPayload { get; } internal Func, string, TState> BuildSyncedState { get; } internal Action CommitState { get; } internal Func GetAcceptedEntryCount { get; } internal string SourceName { get; } internal Action? OnWaitingForPayload { get; } internal Action? LogSyncedLoadSuccess { get; } internal Action? LogSyncedLoadFailure { get; } internal DomainSyncHooks(TryGetSyncedEntriesDelegate tryGetSyncedEntries, Func shouldSkipPayload, Func, string, TState> buildSyncedState, Action commitState, Func getAcceptedEntryCount, string sourceName, Action? onWaitingForPayload = null, Action? logSyncedLoadSuccess = null, Action? logSyncedLoadFailure = null) { TryGetSyncedEntries = tryGetSyncedEntries; ShouldSkipPayload = shouldSkipPayload; BuildSyncedState = buildSyncedState; CommitState = commitState; GetAcceptedEntryCount = getAcceptedEntryCount; SourceName = sourceName; OnWaitingForPayload = onWaitingForPayload; LogSyncedLoadSuccess = logSyncedLoadSuccess; LogSyncedLoadFailure = logSyncedLoadFailure; } } internal sealed class DomainConfigurationRuntime { private readonly DomainLoadHooks _loadHooks; private readonly DomainSyncHooks _syncHooks; internal DomainLoadState LoadState { get; } = new DomainLoadState(); internal DomainConfigurationRuntime(DomainLoadHooks loadHooks, DomainSyncHooks syncHooks) { _loadHooks = loadHooks ?? throw new ArgumentNullException("loadHooks"); _syncHooks = syncHooks ?? throw new ArgumentNullException("syncHooks"); } internal DomainReloadOutcome ReloadSourceOfTruth(List overridePaths) { return ConfigurationDomainHost.RunSourceOfTruthReload(LoadState, overridePaths, _loadHooks); } internal DomainReloadOutcome ReloadSynced() { return ConfigurationDomainHost.RunSyncedReload(_syncHooks); } internal void ResetLoadState() { ConfigurationDomainHost.ResetLoadState(LoadState); } internal void MarkSyncedPayloadPending(bool isSourceOfTruth, Action? onClientPending = null) { if (!isSourceOfTruth) { onClientPending?.Invoke(); } } internal void EnterPendingSyncedPayloadState(bool isSourceOfTruth, Action? beforeResetLoadState = null, Action? afterResetLoadState = null) { if (!isSourceOfTruth) { beforeResetLoadState?.Invoke(); ResetLoadState(); afterResetLoadState?.Invoke(); } } internal bool ApplySyncedPayload(Action? onLoaded = null) { if (ReloadSynced() != DomainReloadOutcome.Loaded) { return false; } onLoaded?.Invoke(); return true; } } internal static class ConfigurationDomainHost { internal static void PublishSyncedPayload(bool isSourceOfTruth, DomainDescriptor descriptor, List entries, string payloadSignature) { if (isSourceOfTruth) { DropNSpawnPlugin.PublishSyncedPayload(descriptor, entries, payloadSignature); } } internal static bool TryGetSyncedEntries(DomainDescriptor descriptor, out List entries, out string payloadToken, Action? onPayloadAvailable = null) { bool num = DropNSpawnPlugin.TryGetSyncedEntries(descriptor, out entries, out payloadToken); if (num) { onPayloadAvailable?.Invoke(); } return num; } internal static bool ShouldSkipSyncedPayload(DomainLoadState loadState, string payloadToken, bool isPayloadReady) { if (isPayloadReady) { return string.Equals(loadState.LastLoadedPayload, payloadToken, StringComparison.Ordinal); } return false; } internal static void HandleWaitingForSyncedPayload(Action markPending, string? debugMessage = null, Action? onWaiting = null) { markPending?.Invoke(); onWaiting?.Invoke(); if (!string.IsNullOrWhiteSpace(debugMessage)) { DropNSpawnPlugin.DropNSpawnLogger.LogDebug((object)debugMessage); } } internal static void ResetLoadState(DomainLoadState loadState) { if (loadState != null) { loadState.LastLoadedPayload = ""; loadState.LastRejectedPayload = ""; loadState.PendingStrictPayload = ""; loadState.LastRejectedValidationKey = ""; } } internal static DomainReloadOutcome RunSourceOfTruthReload(DomainLoadState loadState, List overridePaths, DomainLoadHooks hooks) { List list = ConfigurationLoadSupport.ReadLocalYamlDocuments(overridePaths); string text = ConfigurationLoadSupport.BuildLocalPayload(list); bool flag = loadState.PendingStrictPayload.Length > 0 && string.Equals(loadState.PendingStrictPayload, text, StringComparison.Ordinal); if (string.Equals(loadState.LastLoadedPayload, text, StringComparison.Ordinal) && !flag) { loadState.LastRejectedPayload = ""; loadState.PendingStrictPayload = ""; hooks.OnUnchangedPayload?.Invoke(); return DomainReloadOutcome.NoChange; } LocalLoadResult localLoadResult = hooks.ParseLocalDocuments(list); if (localLoadResult.Errors.Count > 0) { loadState.PendingStrictPayload = ""; hooks.RejectLocalPayload(text, localLoadResult.Errors); return DomainReloadOutcome.Rejected; } List entries = localLoadResult.Entries; List list2 = ((localLoadResult.Warnings.Count > 0) ? new List(localLoadResult.Warnings) : new List()); if (hooks.CanStrictValidateNow != null && hooks.StrictValidateLocal != null) { if (!hooks.CanStrictValidateNow(entries)) { loadState.PendingStrictPayload = text; return DomainReloadOutcome.DeferredStrictValidation; } loadState.PendingStrictPayload = ""; StrictValidationResult strictValidationResult = hooks.StrictValidateLocal(entries); entries = strictValidationResult.Entries; if (strictValidationResult.Warnings.Count > 0) { list2.AddRange(strictValidationResult.Warnings); } } TState val = hooks.BuildSyncedState(entries, ""); hooks.CommitState(val, text); int num = hooks.GetAcceptedEntryCount(val); if (list2.Count > 0) { hooks.LogPartiallyAcceptedLocalConfiguration?.Invoke(localLoadResult.ParsedEntryCount, num, list2); } hooks.LogLocalLoadSuccess?.Invoke(num, localLoadResult.LoadedFileCount); hooks.PublishCommittedState?.Invoke(); return DomainReloadOutcome.Loaded; } internal static DomainReloadOutcome RunSyncedReload(DomainSyncHooks hooks) { if (!hooks.TryGetSyncedEntries(out var entries, out var payloadToken)) { hooks.OnWaitingForPayload?.Invoke(); return DomainReloadOutcome.WaitingForPayload; } if (hooks.ShouldSkipPayload(payloadToken)) { return DomainReloadOutcome.NoChange; } try { TState val = hooks.BuildSyncedState(entries, hooks.SourceName); hooks.CommitState(val, payloadToken); hooks.LogSyncedLoadSuccess?.Invoke(payloadToken, hooks.GetAcceptedEntryCount(val)); return DomainReloadOutcome.Loaded; } catch (Exception arg) { hooks.LogSyncedLoadFailure?.Invoke(payloadToken, arg); return DomainReloadOutcome.Failed; } } } internal static class DomainConfigurationFileSupport { internal static IEnumerable EnumerateSupplementalOverrideConfigurationPaths(string domain, Func isOverrideFileName) { return PluginSettingsFacade.EnumerateSupplementalOverrideConfigurationPaths(PluginSettingsFacade.GetYamlDomainSupplementalPrefix(domain) + "*.*", isOverrideFileName); } internal static string? GetPreferredPrimaryOverridePath(string primaryYmlPath, string primaryYamlPath, Action warn) { bool flag = File.Exists(primaryYmlPath); bool flag2 = File.Exists(primaryYamlPath); if (!flag && !flag2) { return null; } if (flag && flag2) { warn("Both '" + Path.GetFileName(primaryYmlPath) + "' and '" + Path.GetFileName(primaryYamlPath) + "' exist. Using '" + Path.GetFileName(primaryYmlPath) + "'."); } if (!flag) { return primaryYamlPath; } return primaryYmlPath; } } [Flags] internal enum DomainWorkKinds { None = 0, Runtime = 1, SnapshotBuild = 2, Reconcile = 4 } internal abstract class DomainRegistration { internal DomainDescriptor Descriptor { get; } internal DomainTransportMetadata TransportMetadata { get; } internal DomainWorkKinds WorkKinds { get; } protected DomainRegistration(DomainDescriptor descriptor, DomainTransportMetadata transportMetadata, DomainWorkKinds workKinds) { Descriptor = descriptor ?? throw new ArgumentNullException("descriptor"); TransportMetadata = transportMetadata ?? throw new ArgumentNullException("transportMetadata"); WorkKinds = workKinds; } } internal class DomainRegistration : DomainRegistration { internal DomainDescriptor DescriptorTyped { get; } internal DomainTransportMetadata TransportMetadataTyped { get; } internal DomainRegistration(DomainDescriptor descriptor, DomainTransportMetadata transportMetadata, DomainWorkKinds workKinds) : base(descriptor, transportMetadata, workKinds) { DescriptorTyped = descriptor; TransportMetadataTyped = transportMetadata; } } internal sealed class DomainModuleDefinition : DomainRegistration { internal DomainModuleDefinition(string domainKey, DropNSpawnPlugin.ReloadDomain reloadDomain, string manifestSettingKey, int manifestPriority, Func shouldReloadForPath, Action reload, Action onGameDataReady, Func handleExpandWorldDataReady, int dtoVersion, DomainTransportProfile transportProfile, string displayName, string cacheDirectoryName, int clientRequestPriority, Func keySelector, Action applyPayloadAction, DomainWorkKinds workKinds, Func? hasPendingSnapshotBuildWork = null, Func? processPendingSnapshotBuildStep = null, Func? hasPendingReconcileWork = null, Func? processPendingReconcileStep = null, Action? beforeClientManifestChanged = null, Action? onClientAuthorityCutover = null, DomainTransportHooks? hooks = null) : this(CreateDescriptor(domainKey, reloadDomain, manifestSettingKey, manifestPriority, shouldReloadForPath, reload, onGameDataReady, handleExpandWorldDataReady, hasPendingSnapshotBuildWork, processPendingSnapshotBuildStep, hasPendingReconcileWork, processPendingReconcileStep, beforeClientManifestChanged, onClientAuthorityCutover), dtoVersion, transportProfile, displayName, cacheDirectoryName, clientRequestPriority, keySelector, applyPayloadAction, workKinds, hooks) { } private DomainModuleDefinition(DomainDescriptor descriptor, int dtoVersion, DomainTransportProfile transportProfile, string displayName, string cacheDirectoryName, int clientRequestPriority, Func keySelector, Action applyPayloadAction, DomainWorkKinds workKinds, DomainTransportHooks? hooks) : base(descriptor, new DomainTransportMetadata(descriptor, dtoVersion, transportProfile, displayName, cacheDirectoryName, clientRequestPriority, keySelector, applyPayloadAction, hooks), workKinds) { } private static DomainDescriptor CreateDescriptor(string domainKey, DropNSpawnPlugin.ReloadDomain reloadDomain, string manifestSettingKey, int manifestPriority, Func shouldReloadForPath, Action reload, Action onGameDataReady, Func handleExpandWorldDataReady, Func? hasPendingSnapshotBuildWork, Func? processPendingSnapshotBuildStep, Func? hasPendingReconcileWork, Func? processPendingReconcileStep, Action? beforeClientManifestChanged, Action? onClientAuthorityCutover) { return new DomainDescriptor(domainKey, reloadDomain, manifestSettingKey, manifestPriority, shouldReloadForPath, reload, onGameDataReady, handleExpandWorldDataReady, hasPendingSnapshotBuildWork, processPendingSnapshotBuildStep, hasPendingReconcileWork, processPendingReconcileStep, beforeClientManifestChanged, onClientAuthorityCutover); } } internal abstract class DomainDescriptor { internal string DomainKey { get; } internal DropNSpawnPlugin.ReloadDomain ReloadDomain { get; } internal string ManifestSettingKey { get; } internal int ManifestPriority { get; } internal Func ShouldReloadForPath { get; } internal Action Reload { get; } internal Action OnGameDataReady { get; } internal Func HandleExpandWorldDataReady { get; } internal Func? HasPendingSnapshotBuildWork { get; } internal Func? ProcessPendingSnapshotBuildStep { get; } internal Func? HasPendingReconcileWork { get; } internal Func? ProcessPendingReconcileStep { get; } internal Action? BeforeClientManifestChanged { get; } internal Action? OnClientAuthorityCutover { get; } protected DomainDescriptor(string domainKey, DropNSpawnPlugin.ReloadDomain reloadDomain, string manifestSettingKey, int manifestPriority, Func shouldReloadForPath, Action reload, Action onGameDataReady, Func handleExpandWorldDataReady, Func? hasPendingSnapshotBuildWork = null, Func? processPendingSnapshotBuildStep = null, Func? hasPendingReconcileWork = null, Func? processPendingReconcileStep = null, Action? beforeClientManifestChanged = null, Action? onClientAuthorityCutover = null) { DomainKey = domainKey ?? ""; ReloadDomain = reloadDomain; ManifestSettingKey = manifestSettingKey ?? ""; ManifestPriority = manifestPriority; ShouldReloadForPath = shouldReloadForPath; Reload = reload; OnGameDataReady = onGameDataReady; HandleExpandWorldDataReady = handleExpandWorldDataReady; HasPendingSnapshotBuildWork = hasPendingSnapshotBuildWork; ProcessPendingSnapshotBuildStep = processPendingSnapshotBuildStep; HasPendingReconcileWork = hasPendingReconcileWork; ProcessPendingReconcileStep = processPendingReconcileStep; BeforeClientManifestChanged = beforeClientManifestChanged; OnClientAuthorityCutover = onClientAuthorityCutover; } internal abstract void HandleManifestChanged(string manifestRaw); } internal sealed class DomainDescriptor : DomainDescriptor { internal DomainDescriptor(string domainKey, DropNSpawnPlugin.ReloadDomain reloadDomain, string manifestSettingKey, int manifestPriority, Func shouldReloadForPath, Action reload, Action onGameDataReady, Func handleExpandWorldDataReady, Func? hasPendingSnapshotBuildWork = null, Func? processPendingSnapshotBuildStep = null, Func? hasPendingReconcileWork = null, Func? processPendingReconcileStep = null, Action? beforeClientManifestChanged = null, Action? onClientAuthorityCutover = null) : base(domainKey, reloadDomain, manifestSettingKey, manifestPriority, shouldReloadForPath, reload, onGameDataReady, handleExpandWorldDataReady, hasPendingSnapshotBuildWork, processPendingSnapshotBuildStep, hasPendingReconcileWork, processPendingReconcileStep, beforeClientManifestChanged, onClientAuthorityCutover) { } internal override void HandleManifestChanged(string manifestRaw) { NetworkPayloadSyncSupport.HandleManifestChanged(this, manifestRaw); } } internal static class DomainRegistry { internal static readonly DomainRegistration[] AllRegistrations; internal static readonly DomainDescriptor[] RuntimeDomains; internal static readonly DomainDescriptor[] SnapshotBuildDomains; internal static readonly DomainDescriptor[] ReconcileDomains; internal static readonly DomainTransportMetadata[] Transports; static DomainRegistry() { AllRegistrations = new DomainRegistration[5] { ObjectDropManager.Module, CharacterDropManager.Module, SpawnerManager.Module, LocationManager.Module, SpawnSystemManager.Module }; RuntimeDomains = SelectDescriptors(DomainWorkKinds.Runtime); SnapshotBuildDomains = SelectDescriptors(DomainWorkKinds.SnapshotBuild); ReconcileDomains = SelectDescriptors(DomainWorkKinds.Reconcile); Transports = AllRegistrations.Select((DomainRegistration registration) => registration.TransportMetadata).ToArray(); ValidateWorkHooks(SnapshotBuildDomains, DomainWorkKinds.SnapshotBuild); ValidateWorkHooks(ReconcileDomains, DomainWorkKinds.Reconcile); } private static DomainDescriptor[] SelectDescriptors(DomainWorkKinds workKind) { return (from registration in AllRegistrations where (registration.WorkKinds & workKind) != 0 select registration.Descriptor).ToArray(); } private static void ValidateWorkHooks(DomainDescriptor[] domains, DomainWorkKinds workKind) { foreach (DomainDescriptor domainDescriptor in domains) { if (workKind switch { DomainWorkKinds.SnapshotBuild => (domainDescriptor.HasPendingSnapshotBuildWork != null && domainDescriptor.ProcessPendingSnapshotBuildStep != null) ? 1 : 0, DomainWorkKinds.Reconcile => (domainDescriptor.HasPendingReconcileWork != null && domainDescriptor.ProcessPendingReconcileStep != null) ? 1 : 0, _ => 1, } == 0) { throw new InvalidOperationException($"Domain '{domainDescriptor.DomainKey}' is registered for {workKind} work without the required coordinator hooks."); } } } } internal enum DomainTransportProfile { SmallConfig, MediumConfig, LargeConfig, LargeWithArtifacts } internal abstract class DomainTransportMetadata { internal string DomainKey { get; } internal int DtoVersion { get; } internal DomainTransportProfile TransportProfile { get; } internal string DisplayName { get; } internal string CacheDirectoryName { get; } internal int ClientRequestPriority { get; } internal DomainTransportHooks Hooks { get; } protected DomainTransportMetadata(string domainKey, int dtoVersion, DomainTransportProfile transportProfile, string displayName, string cacheDirectoryName, int clientRequestPriority, DomainTransportHooks? hooks) { DomainKey = domainKey ?? ""; DtoVersion = Math.Max(0, dtoVersion); TransportProfile = transportProfile; DisplayName = displayName ?? ""; CacheDirectoryName = cacheDirectoryName ?? ""; ClientRequestPriority = clientRequestPriority; Hooks = hooks ?? DomainTransportHooks.NoOp; } } internal sealed class DomainTransportMetadata : DomainTransportMetadata { internal DomainDescriptor Domain { get; } internal Func KeySelector { get; } internal Action ApplyPayloadAction { get; } internal DomainTransportMetadata(DomainDescriptor domain, int dtoVersion, DomainTransportProfile transportProfile, string displayName, string cacheDirectoryName, int clientRequestPriority, Func keySelector, Action applyPayloadAction, DomainTransportHooks? hooks = null) : base(domain?.DomainKey ?? "", dtoVersion, transportProfile, displayName, cacheDirectoryName, clientRequestPriority, hooks) { Domain = domain ?? throw new ArgumentNullException("domain"); KeySelector = keySelector ?? throw new ArgumentNullException("keySelector"); ApplyPayloadAction = applyPayloadAction ?? throw new ArgumentNullException("applyPayloadAction"); } } internal static class DomainDictionaryDiffSupport { internal static HashSet BuildDirtyKeys(IReadOnlyDictionary previous, IReadOnlyDictionary current) { HashSet hashSet = new HashSet(StringComparer.OrdinalIgnoreCase); foreach (var (text3, b) in current) { if (!previous.TryGetValue(text3, out string value) || !string.Equals(value, b, StringComparison.Ordinal)) { hashSet.Add(text3); } } foreach (string key in previous.Keys) { if (!current.ContainsKey(key)) { hashSet.Add(key); } } return hashSet; } internal static void ReplaceEntries(Dictionary target, IReadOnlyDictionary source) { target.Clear(); foreach (KeyValuePair item in source) { item.Deconstruct(out var key, out var value); string key2 = key; TValue value2 = value; target[key2] = value2; } } } internal static class DomainEntrySignatureSupport { internal static Dictionary BuildSignaturesByKey(IEnumerable>>? entriesByKey, Func, string> computeSignature) { Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); if (entriesByKey == null) { return dictionary; } foreach (KeyValuePair> item in entriesByKey) { item.Deconstruct(out var key, out var value); string key2 = key; List arg = value; dictionary[key2] = computeSignature(arg); } return dictionary; } } internal enum StandardApplyStage { None, Validate, RestoreStaticBaseline, ApplyStaticBaseline, PrepareLiveBaseline, ApplyLive, Commit, RollbackStaticBaseline } [Flags] internal enum BaselineDesiredStateCapabilities { None = 0, Validation = 1, StaticBaseline = 2, StaticApply = 4, LiveBaseline = 8, LiveApply = 0x10, StaticRollback = 0x20 } internal readonly struct StandardApplyFailureContext { internal StandardApplyStage FailedStage { get; } internal Exception Error { get; } internal bool RollbackAttempted { get; } internal bool RollbackSucceeded { get; } internal bool LiveStageFailed { get; } internal long ElapsedMilliseconds { get; } internal StandardApplyFailureContext(StandardApplyStage failedStage, Exception error, bool rollbackAttempted, bool rollbackSucceeded, bool liveStageFailed, long elapsedMilliseconds) { FailedStage = failedStage; Error = error; RollbackAttempted = rollbackAttempted; RollbackSucceeded = rollbackSucceeded; LiveStageFailed = liveStageFailed; ElapsedMilliseconds = elapsedMilliseconds; } } internal readonly struct StandardApplyOutcome { internal bool Success { get; } internal StandardApplyStage CompletedStage { get; } internal bool LiveApplied { get; } internal bool RollbackAttempted { get; } internal bool RollbackSucceeded { get; } internal long ElapsedMilliseconds { get; } internal Exception? Error { get; } internal StandardApplyOutcome(bool success, StandardApplyStage completedStage, bool liveApplied, bool rollbackAttempted, bool rollbackSucceeded, long elapsedMilliseconds, Exception? error = null) { Success = success; CompletedStage = completedStage; LiveApplied = liveApplied; RollbackAttempted = rollbackAttempted; RollbackSucceeded = rollbackSucceeded; ElapsedMilliseconds = elapsedMilliseconds; Error = error; } } internal interface IStandardBaselineDesiredStateOperations { string DomainKey { get; } BaselineDesiredStateCapabilities Capabilities { get; } void Validate(TDesiredState desiredState); void RestoreStaticBaseline(TDesiredState desiredState); void ApplyDesiredStateToStaticBaseline(TDesiredState desiredState); void PrepareLiveBaseline(TDesiredState desiredState); void ApplyDesiredStateToLive(TDesiredState desiredState); void Commit(TDesiredState desiredState); void HandleFailure(TDesiredState desiredState, StandardApplyFailureContext failureContext); } internal static class StandardBaselineDesiredStateCoordinator { internal static StandardApplyOutcome Run(StandardDomainApplyPlan applyPlan, TDesiredState desiredState, IStandardBaselineDesiredStateOperations operations) { Stopwatch stopwatch = Stopwatch.StartNew(); BaselineDesiredStateCapabilities capabilities = operations.Capabilities; StandardApplyStage standardApplyStage = StandardApplyStage.None; bool liveApplied = false; try { if ((capabilities & BaselineDesiredStateCapabilities.Validation) != 0) { standardApplyStage = StandardApplyStage.Validate; operations.Validate(desiredState); } if ((capabilities & BaselineDesiredStateCapabilities.StaticBaseline) != 0) { standardApplyStage = StandardApplyStage.RestoreStaticBaseline; operations.RestoreStaticBaseline(desiredState); } if ((capabilities & BaselineDesiredStateCapabilities.StaticApply) != 0) { standardApplyStage = StandardApplyStage.ApplyStaticBaseline; operations.ApplyDesiredStateToStaticBaseline(desiredState); } if (!applyPlan.ShouldSkipLiveReload && applyPlan.NeedsLiveReload) { if ((capabilities & BaselineDesiredStateCapabilities.LiveBaseline) != 0) { standardApplyStage = StandardApplyStage.PrepareLiveBaseline; operations.PrepareLiveBaseline(desiredState); } if ((capabilities & BaselineDesiredStateCapabilities.LiveApply) != 0) { standardApplyStage = StandardApplyStage.ApplyLive; operations.ApplyDesiredStateToLive(desiredState); liveApplied = true; } } standardApplyStage = StandardApplyStage.Commit; operations.Commit(desiredState); stopwatch.Stop(); return new StandardApplyOutcome(success: true, StandardApplyStage.Commit, liveApplied, rollbackAttempted: false, rollbackSucceeded: false, stopwatch.ElapsedMilliseconds); } catch (Exception ex2) { stopwatch.Stop(); StandardApplyStage standardApplyStage2 = standardApplyStage; bool rollbackAttempted = false; bool rollbackSucceeded = false; if (standardApplyStage2 == StandardApplyStage.ApplyStaticBaseline && (capabilities & BaselineDesiredStateCapabilities.StaticRollback) != 0 && (capabilities & BaselineDesiredStateCapabilities.StaticBaseline) != 0) { rollbackAttempted = true; try { operations.RestoreStaticBaseline(desiredState); rollbackSucceeded = true; } catch (Exception ex) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("Static rollback failed for domain '" + operations.DomainKey + "' after apply failure. " + ex.Message)); DropNSpawnPlugin.DropNSpawnLogger.LogError((object)ex); } } DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)$"Apply coordinator failed for domain '{operations.DomainKey}' at stage '{standardApplyStage2}' after {stopwatch.ElapsedMilliseconds} ms. {ex2.Message}"); DropNSpawnPlugin.DropNSpawnLogger.LogError((object)ex2); try { operations.HandleFailure(desiredState, new StandardApplyFailureContext(standardApplyStage2, ex2, rollbackAttempted, rollbackSucceeded, standardApplyStage2 == StandardApplyStage.PrepareLiveBaseline || standardApplyStage2 == StandardApplyStage.ApplyLive, stopwatch.ElapsedMilliseconds)); } catch (Exception ex3) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("Failure handler failed for domain '" + operations.DomainKey + "'. " + ex3.Message)); DropNSpawnPlugin.DropNSpawnLogger.LogError((object)ex3); } return new StandardApplyOutcome(success: false, standardApplyStage2, liveApplied, rollbackAttempted, rollbackSucceeded, stopwatch.ElapsedMilliseconds, ex2); } } } internal readonly struct StandardDomainApplyPlan { internal bool SameGameData { get; } internal bool PreviousDomainEnabled { get; } internal bool ShouldSkipLiveReload { get; } internal bool NeedsLiveReload { get; } internal HashSet? DirtyKeys { get; } internal StandardDomainApplyPlan(bool sameGameData, bool previousDomainEnabled, bool shouldSkipLiveReload, bool needsLiveReload, HashSet? dirtyKeys) { SameGameData = sameGameData; PreviousDomainEnabled = previousDomainEnabled; ShouldSkipLiveReload = shouldSkipLiveReload; NeedsLiveReload = needsLiveReload; DirtyKeys = dirtyKeys; } } internal static class StandardDomainApplySupport { internal static bool IsAlreadyApplied(int? lastAppliedGameDataSignature, int currentGameDataSignature, bool? lastAppliedDomainEnabled, bool currentDomainEnabled, string lastAppliedConfigurationSignature, string currentConfigurationSignature) { if (lastAppliedGameDataSignature == currentGameDataSignature && lastAppliedDomainEnabled.HasValue && lastAppliedDomainEnabled.Value == currentDomainEnabled) { return string.Equals(lastAppliedConfigurationSignature, currentConfigurationSignature, StringComparison.Ordinal); } return false; } internal static StandardDomainApplyPlan BuildPlan(int? lastAppliedGameDataSignature, int currentGameDataSignature, bool? lastAppliedDomainEnabled, bool currentDomainEnabled, IReadOnlyDictionary lastAppliedEntrySignatures, IReadOnlyDictionary currentEntrySignatures, IReadOnlyDictionary emptyEntrySignatures, bool canUseTargetedLiveReload) { bool flag = lastAppliedGameDataSignature == currentGameDataSignature; bool valueOrDefault = lastAppliedDomainEnabled.GetValueOrDefault(); IReadOnlyDictionary previous = (valueOrDefault ? lastAppliedEntrySignatures : emptyEntrySignatures); IReadOnlyDictionary readOnlyDictionary = (currentDomainEnabled ? currentEntrySignatures : emptyEntrySignatures); HashSet dirtyKeys = ((flag && canUseTargetedLiveReload) ? DomainDictionaryDiffSupport.BuildDirtyKeys(previous, readOnlyDictionary) : null); return new StandardDomainApplyPlan(flag, valueOrDefault, flag && lastAppliedDomainEnabled == false && !currentDomainEnabled, valueOrDefault || readOnlyDictionary.Count > 0, dirtyKeys); } } internal static class ConfigurationLoadSupport { internal sealed class LocalYamlDocument { internal string Path { get; set; } = ""; internal string? Yaml { get; set; } internal string? ReadError { get; set; } } internal static List ReadLocalYamlDocuments(IEnumerable paths) { List list = new List(); foreach (string path in paths) { try { list.Add(new LocalYamlDocument { Path = path, Yaml = File.ReadAllText(path) }); } catch (Exception ex) { list.Add(new LocalYamlDocument { Path = path, ReadError = ex.GetType().Name + ": " + ex.Message }); } } return list; } internal static string BuildLocalPayload(IEnumerable documents) { StringBuilder stringBuilder = new StringBuilder(); foreach (LocalYamlDocument document in documents) { stringBuilder.Append(">>> ").Append(document.Path).AppendLine(); if (document.ReadError != null) { stringBuilder.Append("!read-error ").AppendLine(document.ReadError); } else { stringBuilder.Append(document.Yaml); } stringBuilder.AppendLine(); stringBuilder.AppendLine("<<<"); } return stringBuilder.ToString(); } } internal static class CreatureManagerSpawnReferenceSupport { private enum ProviderKind { CreatureManagerTemplate, JotunnCreatureManager } internal sealed class ReferenceSnapshot { public List Projections { get; set; } = new List(); public string Signature { get; set; } = ""; } internal sealed class ReferenceProjection { public CanonicalSpawnSystemEntry Entry { get; set; } public string SignatureToken { get; set; } = ""; public string SourceKey { get; set; } = ""; } private sealed class ProviderHandle { public ProviderKind Kind { get; set; } public Assembly Assembly { get; set; } public string AssemblyName { get; set; } = ""; public Type CreatureType { get; set; } public Type? ManagerType { get; set; } public Type? InternalNameAttributeType { get; set; } public PropertyInfo? ManagerInstanceProperty { get; set; } public FieldInfo? ManagerCreaturesField { get; set; } public PropertyInfo? ManagerCreaturesProperty { get; set; } public FieldInfo? RegisteredCreaturesField { get; set; } public FieldInfo? CreatureConfigsField { get; set; } } private enum SpawnMode { Default, Custom, Disabled } private static readonly object Sync = new object(); private static readonly ISerializer SignatureSerializer = new SerializerBuilder().WithNamingConvention(CamelCaseNamingConvention.Instance).ConfigureDefaultValuesHandling(DefaultValuesHandling.OmitNull | DefaultValuesHandling.OmitDefaults).Build(); private static string _providerAssemblySignature = ""; private static List _providerCache = new List(); private static string _snapshotAssemblySignature = ""; private static ReferenceSnapshot? _snapshotCache; internal static void InvalidateProviderCache() { lock (Sync) { _providerAssemblySignature = ""; _providerCache = new List(); InvalidateSnapshotUnsafe(); } } internal static void InvalidateSnapshot() { lock (Sync) { InvalidateSnapshotUnsafe(); } } internal static ReferenceSnapshot GetReferenceSnapshot(bool forceRefresh = false) { lock (Sync) { Assembly[] array = (from assembly in AppDomain.CurrentDomain.GetAssemblies() where !assembly.IsDynamic select assembly).ToArray(); string text = ReferenceRefreshSupport.ComputeStableHashForKeys(array.Select((Assembly assembly) => assembly.FullName ?? assembly.GetName().Name ?? "")); List providers = GetProviders(array, text); if (!forceRefresh && _snapshotCache != null && string.Equals(_snapshotAssemblySignature, text, StringComparison.Ordinal)) { return _snapshotCache; } List list = new List(); foreach (ProviderHandle item in providers) { list.AddRange(CollectReferenceProjections(item)); } ReferenceSnapshot obj = new ReferenceSnapshot { Projections = list, Signature = ReferenceRefreshSupport.ComputeStableHashForKeys(list.Select((ReferenceProjection projection) => projection.SignatureToken)) }; _snapshotAssemblySignature = text; _snapshotCache = obj; return obj; } } private static void InvalidateSnapshotUnsafe() { _snapshotAssemblySignature = ""; _snapshotCache = null; } private static List GetProviders(Assembly[] assemblies, string assemblySignature) { if (string.Equals(_providerAssemblySignature, assemblySignature, StringComparison.Ordinal)) { return _providerCache; } List list = new List(); foreach (Assembly assembly in assemblies) { Type type = SafeGetType(assembly, "CreatureManager.Creature"); if (!(type == null)) { FieldInfo fieldInfo = TryGetTypeField(type, "registeredCreatures"); if (!(fieldInfo == null)) { list.Add(new ProviderHandle { Kind = ProviderKind.CreatureManagerTemplate, Assembly = assembly, AssemblyName = (assembly.GetName().Name ?? assembly.FullName ?? "Unknown / Untracked"), CreatureType = type, InternalNameAttributeType = SafeGetType(assembly, "CreatureManager.InternalName"), RegisteredCreaturesField = fieldInfo, CreatureConfigsField = TryGetTypeField(type, "creatureConfigs") }); } } } ProviderHandle providerHandle = TryCreateJotunnProvider(assemblies); if (providerHandle != null) { list.Add(providerHandle); } _providerAssemblySignature = assemblySignature; _providerCache = list; return _providerCache; } private static List CollectReferenceProjections(ProviderHandle provider) { if (provider.Kind != ProviderKind.JotunnCreatureManager) { return CollectCreatureManagerTemplateReferenceProjections(provider); } return CollectJotunnReferenceProjections(provider); } private static ProviderHandle? TryCreateJotunnProvider(IEnumerable assemblies) { foreach (Assembly assembly in assemblies) { Type type = SafeGetType(assembly, "Jotunn.Managers.CreatureManager"); Type type2 = SafeGetType(assembly, "Jotunn.Entities.CustomCreature"); if (!(type == null) && !(type2 == null)) { PropertyInfo propertyInfo = TryGetTypeProperty(type, "Instance"); FieldInfo fieldInfo = TryGetTypeField(type, "Creatures"); PropertyInfo propertyInfo2 = TryGetTypeProperty(type, "Creatures"); if (!(propertyInfo == null) && (!(fieldInfo == null) || !(propertyInfo2 == null))) { return new ProviderHandle { Kind = ProviderKind.JotunnCreatureManager, Assembly = assembly, AssemblyName = (assembly.GetName().Name ?? assembly.FullName ?? "Unknown / Untracked"), CreatureType = type2, ManagerType = type, ManagerInstanceProperty = propertyInfo, ManagerCreaturesField = fieldInfo, ManagerCreaturesProperty = propertyInfo2 }; } } } return null; } private static List CollectJotunnReferenceProjections(ProviderHandle provider) { List list = new List(); object obj = provider.ManagerInstanceProperty?.GetValue(null, null); if (obj == null) { return list; } foreach (object item in GetEnumerable(provider.ManagerCreaturesField?.GetValue(obj) ?? provider.ManagerCreaturesProperty?.GetValue(obj, null))) { if (item == null || !TryGetRawMemberValue(item, "Prefab", out object value)) { continue; } GameObject val = (GameObject)((value is GameObject) ? value : null); if (val == null || string.IsNullOrWhiteSpace(((Object)val).name)) { continue; } string text = ResolveJotunnSourceKey(item, provider.AssemblyName); IEnumerable enumerable = Enumerable.Empty(); if (TryGetRawMemberValue(item, "Spawns", out object value2)) { enumerable = GetEnumerable(value2); } foreach (object item2 in enumerable) { SpawnData val2 = (SpawnData)((item2 is SpawnData) ? item2 : null); if (val2 != null) { CanonicalSpawnSystemEntry canonicalSpawnSystemEntry = SpawnSystemManager.CreateReferenceEntryForExternalProjection(val2, ((Object)val).name); if (!string.IsNullOrWhiteSpace(canonicalSpawnSystemEntry.Prefab)) { canonicalSpawnSystemEntry.ReferenceOwnerName = text; list.Add(new ReferenceProjection { Entry = canonicalSpawnSystemEntry, SignatureToken = text + ":" + SignatureSerializer.Serialize(canonicalSpawnSystemEntry).TrimEnd('\r', '\n'), SourceKey = text }); } } } } return list; } private static string ResolveJotunnSourceKey(object creature, string fallback) { if (TryGetRawMemberValue(creature, "SourceMod", out object value) && value != null) { if (TryGetRawMemberValue(value, "GUID", out object value2)) { string text = NormalizeOptionalString(value2?.ToString()); string text2 = ResolvePluginOwnerName(text); if (!string.IsNullOrWhiteSpace(text2)) { return text2; } if (!string.IsNullOrWhiteSpace(text)) { return text; } } if (TryGetRawMemberValue(value, "Name", out object value3)) { string text3 = NormalizeOptionalString(value3?.ToString()); if (!string.IsNullOrWhiteSpace(text3)) { return text3; } } } return fallback; } private static string? ResolvePluginOwnerName(string? pluginGuid) { string text = NormalizeOptionalString(pluginGuid) ?? ""; if (text.Length == 0) { return null; } if (Chainloader.PluginInfos.TryGetValue(text, out var value)) { string text2 = NormalizeOptionalString(value.Metadata.Name) ?? ""; if (text2.Length > 0) { return text2; } return text; } return null; } private static List CollectCreatureManagerTemplateReferenceProjections(ProviderHandle provider) { List list = new List(); IEnumerable enumerable = GetEnumerable(provider.RegisteredCreaturesField?.GetValue(null)); IDictionary dictionary = provider.CreatureConfigsField?.GetValue(null) as IDictionary; foreach (object item in enumerable) { if (item == null || !TryGetRawMemberValue(item, "Prefab", out object value)) { continue; } GameObject val = (GameObject)((value is GameObject) ? value : null); if (val == null || string.IsNullOrWhiteSpace(((Object)val).name)) { continue; } object creatureConfig = null; if (dictionary != null && dictionary.Contains(item)) { creatureConfig = dictionary[item]; } SpawnMode spawnMode = ResolveSpawnMode(creatureConfig); if (spawnMode != SpawnMode.Disabled && GetBoolEffective(item, creatureConfig, spawnMode, "CanSpawn", fallbackValue: true)) { CanonicalSpawnSystemEntry canonicalSpawnSystemEntry = BuildReferenceEntry(provider, ((Object)val).name, item, creatureConfig, spawnMode); if (!string.IsNullOrWhiteSpace(canonicalSpawnSystemEntry.Prefab)) { canonicalSpawnSystemEntry.ReferenceOwnerName = provider.AssemblyName; list.Add(new ReferenceProjection { Entry = canonicalSpawnSystemEntry, SignatureToken = provider.AssemblyName + ":" + SignatureSerializer.Serialize(canonicalSpawnSystemEntry).TrimEnd('\r', '\n'), SourceKey = provider.AssemblyName }); } } } return list; } private static CanonicalSpawnSystemEntry BuildReferenceEntry(ProviderHandle provider, string prefabName, object creature, object? creatureConfig, SpawnMode spawnMode) { //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) CanonicalSpawnSystemEntry obj = new CanonicalSpawnSystemEntry { Prefab = prefabName, Enabled = true }; SpawnSystemSpawnDefinition spawnSystemSpawnDefinition = new SpawnSystemSpawnDefinition(); SpawnSystemConditionsDefinition spawnSystemConditionsDefinition = new SpawnSystemConditionsDefinition(); SpawnSystemModifiersDefinition spawnSystemModifiersDefinition = new SpawnSystemModifiersDefinition(); bool flag = false; bool flag2 = false; bool flag3 = false; if (TryGetFloatEffective(creature, creatureConfig, spawnMode, "CheckSpawnInterval", out var value)) { spawnSystemSpawnDefinition.SpawnInterval = value; flag = true; } if (TryGetFloatEffective(creature, creatureConfig, spawnMode, "SpawnChance", out var value2)) { spawnSystemSpawnDefinition.SpawnChance = value2; flag = true; } if (TryGetFloatRangeEffective(creature, creatureConfig, spawnMode, "GroupSize", out var min, out var max)) { spawnSystemSpawnDefinition.GroupSize = RangeFormatting.From((int)Math.Round(min), (int)Math.Round(max)); flag = true; } if (TryGetFloatEffective(creature, creatureConfig, spawnMode, "SpawnAltitude", out var value3)) { spawnSystemSpawnDefinition.GroundOffset = value3; flag = true; } if (GetBoolEffective(creature, creatureConfig, spawnMode, "AttackImmediately", fallbackValue: false)) { spawnSystemSpawnDefinition.HuntPlayer = true; flag = true; } if (!GetBoolEffective(creature, creatureConfig, spawnMode, "CanHaveStars", fallbackValue: true)) { spawnSystemSpawnDefinition.Level = RangeFormatting.From(1, 1); flag = true; } if (TryGetFloatEffective(creature, creatureConfig, spawnMode, "Maximum", out var value4)) { spawnSystemConditionsDefinition.MaxSpawned = (int)Math.Round(value4); flag2 = true; } if (TryGetFloatRangeEffective(creature, creatureConfig, spawnMode, "RequiredAltitude", out var min2, out var max2)) { spawnSystemConditionsDefinition.Altitude = RangeFormatting.From(min2, max2); flag2 = true; } if (TryGetFloatRangeEffective(creature, creatureConfig, spawnMode, "RequiredOceanDepth", out var min3, out var max3)) { spawnSystemConditionsDefinition.OceanDepth = RangeFormatting.From(min3, max3); flag2 = true; } if (TryGetEffectiveMemberValue(creature, creatureConfig, spawnMode, "SpecificSpawnTime", out object value5)) { TimeOfDayDefinition timeOfDayDefinition = ConvertTimeOfDayDefinition(value5); if (timeOfDayDefinition != null) { spawnSystemConditionsDefinition.TimeOfDay = timeOfDayDefinition; flag2 = true; } } if (TryGetEffectiveMemberValue(creature, creatureConfig, spawnMode, "Biome", out object value6) && value6 is Biome val && (int)val != 0) { spawnSystemConditionsDefinition.Biomes = ConvertBiomes(val); flag2 = true; } if (TryGetEffectiveMemberValue(creature, creatureConfig, spawnMode, "SpecificSpawnArea", out object value7)) { List list = ConvertBiomeAreas(value7); if (list != null) { spawnSystemConditionsDefinition.BiomeAreas = list; flag2 = true; } } if (TryGetEffectiveMemberValue(creature, creatureConfig, spawnMode, "RequiredWeather", out object value8)) { List list2 = ConvertRequiredEnvironments(provider, value8); if (list2 != null && list2.Count > 0) { spawnSystemConditionsDefinition.RequiredEnvironments = list2; flag2 = true; } } if (TryGetEffectiveMemberValue(creature, creatureConfig, spawnMode, "RequiredGlobalKey", out object value9)) { string text = ConvertInternalName(provider, value9); if (!string.IsNullOrWhiteSpace(text)) { spawnSystemConditionsDefinition.RequiredGlobalKey = text; flag2 = true; } } if (TryGetEffectiveMemberValue(creature, creatureConfig, spawnMode, "ForestSpawn", out object value10)) { bool? inForest = ConvertForestToggle(value10); if (inForest.HasValue) { spawnSystemConditionsDefinition.InForest = inForest; flag2 = true; } } if (TryGetEffectiveMemberValue(creature, creatureConfig, spawnMode, "CreatureFaction", out object value11)) { string text2 = NormalizeOptionalString(value11?.ToString()); if (!string.IsNullOrWhiteSpace(text2)) { spawnSystemModifiersDefinition.Faction = text2; flag3 = true; } } obj.SpawnSystem = (flag ? spawnSystemSpawnDefinition : null); obj.Conditions = (flag2 ? spawnSystemConditionsDefinition : null); obj.Modifiers = (flag3 ? spawnSystemModifiersDefinition : null); return obj; } private static SpawnMode ResolveSpawnMode(object? creatureConfig) { if (!TryGetWrappedMemberValue(creatureConfig, "Spawn", out object value)) { return SpawnMode.Default; } string text = NormalizeOptionalString(value?.ToString()) ?? ""; if (text.Equals("Disabled", StringComparison.OrdinalIgnoreCase)) { return SpawnMode.Disabled; } if (text.Equals("Custom", StringComparison.OrdinalIgnoreCase)) { return SpawnMode.Custom; } return SpawnMode.Default; } private static IEnumerable GetEnumerable(object? value) { if (value is string || !(value is IEnumerable result)) { return Array.Empty(); } return result; } private static bool TryGetEffectiveMemberValue(object creature, object? creatureConfig, SpawnMode spawnMode, string memberName, out object? value) { value = null; if (spawnMode == SpawnMode.Custom && TryGetWrappedMemberValue(creatureConfig, memberName, out value)) { return true; } if (TryGetMemberValue(creature, memberName, out value)) { return true; } if (spawnMode != 0 && TryGetWrappedMemberValue(creatureConfig, memberName, out value)) { return true; } value = null; return false; } private static bool GetBoolEffective(object creature, object? creatureConfig, SpawnMode spawnMode, string memberName, bool fallbackValue) { if (!TryGetEffectiveMemberValue(creature, creatureConfig, spawnMode, memberName, out object value) || !TryConvertToBool(value, out var parsed)) { return fallbackValue; } return parsed; } private static bool TryGetFloatEffective(object creature, object? creatureConfig, SpawnMode spawnMode, string memberName, out float value) { if (TryGetEffectiveMemberValue(creature, creatureConfig, spawnMode, memberName, out object value2) && TryConvertToFloat(value2, out value)) { return true; } value = 0f; return false; } private static bool TryGetFloatRangeEffective(object creature, object? creatureConfig, SpawnMode spawnMode, string memberName, out float min, out float max) { if (TryGetEffectiveMemberValue(creature, creatureConfig, spawnMode, memberName, out object value) && TryReadRange(value, out min, out max)) { return true; } min = 0f; max = 0f; return false; } private static bool TryReadRange(object? value, out float min, out float max) { min = 0f; max = 0f; if (value == null) { return false; } value.GetType(); if (!TryGetRawMemberValue(value, "min", out object value2) || !TryGetRawMemberValue(value, "max", out object value3) || !TryConvertToFloat(value2, out min) || !TryConvertToFloat(value3, out max)) { return false; } return true; } private static bool TryGetWrappedMemberValue(object? instance, string memberName, out object? value) { value = null; if (!TryGetRawMemberValue(instance, memberName, out object value2)) { return false; } value = UnwrapConfigValue(value2); return true; } private static bool TryGetMemberValue(object? instance, string memberName, out object? value) { value = null; if (!TryGetRawMemberValue(instance, memberName, out object value2)) { return false; } value = UnwrapConfigValue(value2); return true; } private static bool TryGetRawMemberValue(object? instance, string memberName, out object? value) { string memberName2 = memberName; value = null; if (instance == null || string.IsNullOrWhiteSpace(memberName2)) { return false; } Type type = instance.GetType(); FieldInfo fieldInfo = type.GetField(memberName2, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) ?? type.GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((FieldInfo candidate) => string.Equals(candidate.Name, memberName2, StringComparison.OrdinalIgnoreCase)); if (fieldInfo != null) { value = fieldInfo.GetValue(instance); return true; } PropertyInfo propertyInfo = type.GetProperty(memberName2, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) ?? type.GetProperties(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((PropertyInfo candidate) => string.Equals(candidate.Name, memberName2, StringComparison.OrdinalIgnoreCase)); if (propertyInfo == null || !propertyInfo.CanRead) { return false; } value = propertyInfo.GetValue(instance, null); return true; } private static object? UnwrapConfigValue(object? value) { object obj = value; for (int i = 0; i < 4; i++) { if (obj == null) { break; } if (obj is string || obj.GetType().IsPrimitive || obj.GetType().IsEnum) { return obj; } ConfigEntryBase val = (ConfigEntryBase)((obj is ConfigEntryBase) ? obj : null); if (val != null) { return val.BoxedValue; } MethodInfo method = obj.GetType().GetMethod("get", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); if (method != null && method.ReturnType != typeof(void)) { obj = method.Invoke(obj, null); continue; } PropertyInfo property = obj.GetType().GetProperty("BoxedValue", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.CanRead) { obj = property.GetValue(obj, null); continue; } PropertyInfo property2 = obj.GetType().GetProperty("Value", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (!(property2 != null) || !property2.CanRead) { break; } obj = property2.GetValue(obj, null); } return obj; } private static bool TryConvertToBool(object? value, out bool parsed) { if (!(value is bool flag)) { if (value is string value2 && bool.TryParse(value2, out var result)) { parsed = result; return true; } parsed = false; return false; } bool flag2 = flag; parsed = flag2; return true; } private static bool TryConvertToFloat(object? value, out float parsed) { if (!(value is byte b)) { if (!(value is short num)) { if (!(value is int num2)) { if (!(value is long num3)) { if (!(value is float num4)) { if (!(value is double num5)) { if (!(value is decimal num6)) { if (value is string s && float.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { parsed = result; return true; } parsed = 0f; return false; } decimal num7 = num6; parsed = (float)num7; return true; } double num8 = num5; parsed = (float)num8; return true; } float num9 = num4; parsed = num9; return true; } long num10 = num3; parsed = num10; return true; } int num11 = num2; parsed = num11; return true; } short num12 = num; parsed = num12; return true; } byte b2 = b; parsed = (int)b2; return true; } private static TimeOfDayDefinition? ConvertTimeOfDayDefinition(object? value) { string text = NormalizeOptionalString(value?.ToString()) ?? ""; if (text.Length == 0) { return null; } if (text.Equals("Day", StringComparison.OrdinalIgnoreCase)) { return new TimeOfDayDefinition { Values = new List { "day" } }; } if (text.Equals("Night", StringComparison.OrdinalIgnoreCase)) { return new TimeOfDayDefinition { Values = new List { "night" } }; } if (text.Equals("Always", StringComparison.OrdinalIgnoreCase)) { return new TimeOfDayDefinition { Values = new List { "day", "night" } }; } return null; } private static List? ConvertBiomeAreas(object? value) { string text = NormalizeOptionalString(value?.ToString()) ?? ""; if (text.Length == 0) { return null; } if (text.Equals("Everywhere", StringComparison.OrdinalIgnoreCase)) { return new List { "Everything" }; } if (text.Equals("Center", StringComparison.OrdinalIgnoreCase)) { return new List { "Median" }; } if (text.Equals("Edge", StringComparison.OrdinalIgnoreCase)) { return new List { "Edge" }; } return null; } private static bool? ConvertForestToggle(object? value) { string text = NormalizeOptionalString(value?.ToString()) ?? ""; if (text.Length == 0) { return null; } if (text.Equals("Yes", StringComparison.OrdinalIgnoreCase)) { return true; } if (text.Equals("No", StringComparison.OrdinalIgnoreCase)) { return false; } return null; } private static List ConvertBiomes(Biome biomes) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Invalid comparison between Unknown and I4 //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) if ((int)biomes == 895) { return new List { "All" }; } List list = new List(); foreach (Biome value in Enum.GetValues(typeof(Biome))) { Biome val = value; if ((int)val != 0 && (int)val != 895 && (Biome)(biomes & val) == val) { list.Add(((object)(Biome)(ref val)).ToString()); } } return list; } private static List? ConvertRequiredEnvironments(ProviderHandle provider, object? value) { if (value == null || !value.GetType().IsEnum) { return null; } List list = new List(); ulong num = Convert.ToUInt64(value, CultureInfo.InvariantCulture); FieldInfo[] fields = value.GetType().GetFields(BindingFlags.Static | BindingFlags.Public); foreach (FieldInfo fieldInfo in fields) { object value2 = fieldInfo.GetValue(null); if (value2 == null) { continue; } ulong num2 = Convert.ToUInt64(value2, CultureInfo.InvariantCulture); if (num2 != 0L && (num & num2) == num2) { string internalName = GetInternalName(provider, fieldInfo); if (!string.IsNullOrWhiteSpace(internalName)) { list.Add(internalName); } } } if (list.Count != 0) { return list.Distinct(StringComparer.OrdinalIgnoreCase).ToList(); } return null; } private static string? ConvertInternalName(ProviderHandle provider, object? value) { if (value == null || !value.GetType().IsEnum) { return NormalizeOptionalString(value?.ToString()); } string text = value.ToString(); if (string.IsNullOrWhiteSpace(text)) { return null; } FieldInfo field = value.GetType().GetField(text, BindingFlags.Static | BindingFlags.Public); if (field == null) { return null; } return NormalizeOptionalString(GetInternalName(provider, field)); } private static string? GetInternalName(ProviderHandle provider, MemberInfo member) { if (provider.InternalNameAttributeType == null) { return member.Name; } object obj = member.GetCustomAttributes(provider.InternalNameAttributeType, inherit: false).FirstOrDefault(); if (obj == null) { return member.Name; } if (TryGetRawMemberValue(obj, "internalName", out object value)) { return NormalizeOptionalString(value?.ToString()); } return member.Name; } private static string? NormalizeOptionalString(string? value) { string text = (value ?? "").Trim(); if (text.Length != 0) { return text; } return null; } private static Type? SafeGetType(Assembly assembly, string fullTypeName) { try { return assembly.GetType(fullTypeName, throwOnError: false, ignoreCase: false); } catch { return null; } } private static PropertyInfo? TryGetTypeProperty(Type? type, string memberName) { string memberName2 = memberName; if (type == null || string.IsNullOrWhiteSpace(memberName2)) { return null; } Type type2 = type; while (type2 != null) { PropertyInfo propertyInfo = type2.GetProperty(memberName2, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) ?? type2.GetProperties(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((PropertyInfo candidate) => string.Equals(candidate.Name, memberName2, StringComparison.OrdinalIgnoreCase)); if (propertyInfo != null) { return propertyInfo; } type2 = type2.BaseType; } return null; } private static FieldInfo? TryGetTypeField(Type? type, string memberName) { string memberName2 = memberName; if (type == null || string.IsNullOrWhiteSpace(memberName2)) { return null; } Type type2 = type; while (type2 != null) { FieldInfo fieldInfo = type2.GetField(memberName2, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) ?? type2.GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((FieldInfo candidate) => string.Equals(candidate.Name, memberName2, StringComparison.OrdinalIgnoreCase)); if (fieldInfo != null) { return fieldInfo; } type2 = type2.BaseType; } return null; } } internal static class BiomeResolutionSupport { private static readonly Dictionary VanillaBiomeLookup = BuildVanillaBiomeLookup(); private static readonly Type? ExpandWorldDataBiomeManagerType = Type.GetType("ExpandWorldData.BiomeManager, ExpandWorldData"); private static readonly Type? ExpandWorldDataDataManagerType = Type.GetType("ExpandWorldData.DataManager, ExpandWorldData"); private static readonly PropertyInfo? ExpandWorldDataIsReadyProperty = ExpandWorldDataDataManagerType?.GetProperty("IsReady", BindingFlags.Static | BindingFlags.Public); private static readonly MethodInfo? ExpandWorldDataTryGetBiomeMethod = Type.GetType("ExpandWorldData.BiomeManager, ExpandWorldData")?.GetMethod("TryGetBiome", BindingFlags.Static | BindingFlags.Public, null, new Type[2] { typeof(string), typeof(Biome).MakeByRefType() }, null); private static readonly MethodInfo? ExpandWorldDataTryGetDisplayNameMethod = ExpandWorldDataBiomeManagerType?.GetMethod("TryGetDisplayName", BindingFlags.Static | BindingFlags.Public, null, new Type[2] { typeof(Biome), typeof(string).MakeByRefType() }, null); internal static bool TryResolveBiomeToken(string? configuredBiome, out Biome biome) { string text = (configuredBiome ?? "").Trim(); if (text.Length == 0) { biome = (Biome)0; return false; } if (string.Equals(text, "All", StringComparison.OrdinalIgnoreCase)) { biome = (Biome)895; return true; } if (int.TryParse(text, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) && result != 0) { biome = (Biome)result; return true; } if (Enum.TryParse(text, ignoreCase: true, out biome)) { return true; } if (VanillaBiomeLookup.TryGetValue(NormalizeBiomeToken(text), out biome)) { return true; } if (TryResolveExpandWorldDataBiome(text, out biome)) { return true; } biome = (Biome)0; return false; } internal static bool MatchesBiome(Biome currentBiome, string? configuredBiome) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Invalid comparison between Unknown and I4 if (TryResolveBiomeToken(configuredBiome, out var biome)) { return (currentBiome & biome) > 0; } return false; } internal static bool TryResolveBiomeMask(IEnumerable? configuredBiomes, out Biome biomeMask) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected I4, but got Unknown biomeMask = (Biome)0; bool result = false; foreach (string item in configuredBiomes ?? Array.Empty()) { string text = (item ?? "").Trim(); if (text.Length != 0) { result = true; if (!TryResolveBiomeToken(text, out var biome)) { biomeMask = (Biome)0; return false; } if ((int)biome == 895) { biomeMask = (Biome)895; return true; } biomeMask |= biome; } } return result; } internal static Biome? ResolveBiomeMaskOrNull(IEnumerable? configuredBiomes) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) if (!TryResolveBiomeMask(configuredBiomes, out var biomeMask)) { return null; } return biomeMask; } internal static string GetBiomeDisplayName(Biome biome) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected I4, but got Unknown if (TryGetExpandWorldDataBiomeDisplayName(biome, out string displayName)) { return displayName; } return Enum.GetName(typeof(Biome), biome) ?? ((int)biome).ToString(CultureInfo.InvariantCulture); } internal static bool IsExpandWorldDataPresent() { if (!(ExpandWorldDataTryGetBiomeMethod != null)) { return ExpandWorldDataIsReadyProperty != null; } return true; } internal static bool IsExpandWorldDataReadyOrUnavailable() { if (ExpandWorldDataIsReadyProperty == null) { return true; } try { return (ExpandWorldDataIsReadyProperty.GetValue(null) as bool?).GetValueOrDefault(true); } catch { return true; } } internal static bool ShouldWaitForExpandWorldDataBiomeResolution(IEnumerable? configuredBiomes, Biome? resolvedBiomeMask) { if (resolvedBiomeMask.HasValue || !IsExpandWorldDataPresent() || IsExpandWorldDataReadyOrUnavailable()) { return false; } Biome biomeMask; return !TryResolveBiomeMask(configuredBiomes, out biomeMask); } internal static string NormalizeBiomeToken(string? value) { StringBuilder stringBuilder = new StringBuilder(); string text = (value ?? "").Trim(); foreach (char c in text) { if (char.IsLetterOrDigit(c)) { stringBuilder.Append(char.ToLowerInvariant(c)); } } return stringBuilder.ToString(); } private static Dictionary BuildVanillaBiomeLookup() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); foreach (Biome value2 in Enum.GetValues(typeof(Biome))) { Biome value = value2; dictionary[NormalizeBiomeToken(((object)(Biome)(ref value)).ToString())] = value; } dictionary["ashlands"] = (Biome)32; return dictionary; } private static bool TryResolveExpandWorldDataBiome(string configuredBiome, out Biome biome) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Expected I4, but got Unknown if (ExpandWorldDataTryGetBiomeMethod == null) { biome = (Biome)0; return false; } object[] array = new object[2] { configuredBiome, (object)(Biome)0 }; object obj = ExpandWorldDataTryGetBiomeMethod.Invoke(null, array); bool flag = default(bool); int num; if (obj is bool) { flag = (bool)obj; num = 1; } else { num = 0; } if (((uint)num & (flag ? 1u : 0u)) != 0 && array[1] is Biome val) { biome = (Biome)(int)val; return true; } biome = (Biome)0; return false; } private static bool TryGetExpandWorldDataBiomeDisplayName(Biome biome, out string displayName) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) displayName = ""; if (ExpandWorldDataTryGetDisplayNameMethod == null) { return false; } object[] array = new object[2] { biome, null }; object obj = ExpandWorldDataTryGetDisplayNameMethod.Invoke(null, array); bool flag = default(bool); int num; if (obj is bool) { flag = (bool)obj; num = 1; } else { num = 0; } if (((uint)num & (flag ? 1u : 0u)) != 0 && array[1] is string text && !string.IsNullOrWhiteSpace(text)) { displayName = text; return true; } return false; } } internal sealed class ConditionsDefinition { [YamlMember(Order = 1)] public IntRangeDefinition? Level { get; set; } [YamlMember(Order = 2)] public FloatRangeDefinition? Altitude { get; set; } [YamlIgnore] public int? MinLevel { get; set; } [YamlIgnore] public int? MaxLevel { get; set; } [YamlIgnore] public float? MinAltitude { get; set; } [YamlIgnore] public float? MaxAltitude { get; set; } [YamlMember(Order = 3)] public FloatRangeDefinition? DistanceFromCenter { get; set; } [YamlIgnore] public float? MinDistanceFromCenter { get; set; } [YamlIgnore] public float? MaxDistanceFromCenter { get; set; } [YamlMember(Order = 4)] public List? Biomes { get; set; } [YamlIgnore] public Biome? ResolvedBiomeMask { get; set; } [YamlMember(Order = 5)] public List? Locations { get; set; } [YamlMember(Order = 6)] public TimeOfDayDefinition? TimeOfDay { get; set; } [YamlMember(Order = 7)] public List? RequiredEnvironments { get; set; } [YamlMember(Order = 8)] public List? RequiredGlobalKeys { get; set; } [YamlMember(Order = 9)] public List? ForbiddenGlobalKeys { get; set; } [YamlMember(Order = 10)] public List? States { get; set; } [YamlMember(Order = 11)] public List? Factions { get; set; } [YamlMember(Order = 12)] public bool? InForest { get; set; } [YamlMember(Order = 13)] public bool? InDungeon { get; set; } [YamlMember(Order = 14)] public bool? InsidePlayerBase { get; set; } } internal static class DropConditionEvaluator { private enum CachedLocationResolutionMode { Stable, Spatial } private sealed class CachedLocationResolution { public int Epoch { get; set; } public Vector2i Zone { get; set; } public Vector3 Position { get; set; } public string LocationName { get; set; } = ""; public bool HasLocationName { get; set; } public CachedLocationResolutionMode Mode { get; set; } } private static readonly Dictionary CachedLocationResolutionsByObjectId = new Dictionary(); private const int MaxCachedLocationResolutions = 4096; private const float SpatialResolutionReuseDistanceSqr = 1f; private static int _locationResolutionEpoch; private static int _lastLocationResolutionZoneSystemId; private static int _lastLocationResolutionLocationInstanceCount = -1; internal static bool HasConditions(ConditionsDefinition? conditions) { if (conditions != null) { if (!conditions.ResolvedBiomeMask.HasValue && !HasAnyValues(conditions.Biomes) && !HasAnyValues(conditions.RequiredGlobalKeys) && !HasAnyValues(conditions.ForbiddenGlobalKeys) && !HasAnyValues(conditions.Locations) && conditions.TimeOfDay == null && !HasAnyValues(conditions.RequiredEnvironments) && !conditions.InDungeon.HasValue && !conditions.InForest.HasValue) { FloatRangeDefinition? distanceFromCenter = conditions.DistanceFromCenter; if ((distanceFromCenter == null || !distanceFromCenter.HasValues()) && !conditions.MinDistanceFromCenter.HasValue && !conditions.MaxDistanceFromCenter.HasValue) { FloatRangeDefinition? altitude = conditions.Altitude; if ((altitude == null || !altitude.HasValues()) && !conditions.MinAltitude.HasValue && !conditions.MaxAltitude.HasValue) { return conditions.InsidePlayerBase.HasValue; } } } return true; } return false; } internal static bool HasDynamicConditions(ConditionsDefinition? conditions) { if (conditions != null) { if (!HasAnyValues(conditions.RequiredGlobalKeys) && !HasAnyValues(conditions.ForbiddenGlobalKeys) && conditions.TimeOfDay == null && !HasAnyValues(conditions.RequiredEnvironments)) { return conditions.InsidePlayerBase.HasValue; } return true; } return false; } internal static bool HasStaticConditions(ConditionsDefinition? conditions) { if (conditions != null) { if (!conditions.ResolvedBiomeMask.HasValue && !HasAnyValues(conditions.Biomes) && !HasAnyValues(conditions.Locations) && !conditions.InDungeon.HasValue && !conditions.InForest.HasValue) { FloatRangeDefinition? distanceFromCenter = conditions.DistanceFromCenter; if ((distanceFromCenter == null || !distanceFromCenter.HasValues()) && !conditions.MinDistanceFromCenter.HasValue && !conditions.MaxDistanceFromCenter.HasValue) { FloatRangeDefinition? altitude = conditions.Altitude; if ((altitude == null || !altitude.HasValues()) && !conditions.MinAltitude.HasValue) { return conditions.MaxAltitude.HasValue; } } } return true; } return false; } internal static bool HasCharacterConditions(ConditionsDefinition? conditions) { if (!HasConditions(conditions)) { if (conditions != null) { IntRangeDefinition? level = conditions.Level; if ((level == null || !level.HasValues()) && !conditions.MinLevel.HasValue && !conditions.MaxLevel.HasValue && !HasAnyValues(conditions.States)) { return HasAnyValues(conditions.Factions); } return true; } return false; } return true; } internal static bool AreSatisfied(GameObject gameObject, ConditionsDefinition? conditions) { return AreSatisfied(gameObject, conditions, null); } internal static bool AreSatisfied(GameObject gameObject, ConditionsDefinition? conditions, string? resolvedLocationName) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_0255: Unknown result type (might be due to invalid IL or missing references) //IL_025b: Unknown result type (might be due to invalid IL or missing references) //IL_0260: Unknown result type (might be due to invalid IL or missing references) //IL_0236: Unknown result type (might be due to invalid IL or missing references) //IL_02f4: Unknown result type (might be due to invalid IL or missing references) //IL_030e: Unknown result type (might be due to invalid IL or missing references) //IL_0330: Unknown result type (might be due to invalid IL or missing references) if (!HasConditions(conditions)) { return true; } Vector3 position = gameObject.transform.position; if (HasBiomeCondition(conditions)) { WorldGenerator instance = WorldGenerator.instance; if (!MatchesBiomeCondition((instance != null) ? instance.GetBiome(position) : Heightmap.FindBiome(position), conditions)) { return false; } } if (HasAnyValues(conditions.RequiredGlobalKeys)) { if ((Object)(object)ZoneSystem.instance == (Object)null) { return false; } foreach (string requiredGlobalKey in conditions.RequiredGlobalKeys) { string text = (requiredGlobalKey ?? "").Trim(); if (text.Length != 0 && !ZoneSystem.instance.GetGlobalKey(text)) { return false; } } } if (HasAnyValues(conditions.ForbiddenGlobalKeys) && (Object)(object)ZoneSystem.instance != (Object)null) { foreach (string forbiddenGlobalKey in conditions.ForbiddenGlobalKeys) { string text2 = (forbiddenGlobalKey ?? "").Trim(); if (text2.Length != 0 && ZoneSystem.instance.GetGlobalKey(text2)) { return false; } } } if (HasAnyValues(conditions.Locations)) { string text3 = ResolveLocationName(gameObject, position, resolvedLocationName); if (string.IsNullOrWhiteSpace(text3)) { return false; } string resolvedLocation = text3; if (!conditions.Locations.Any((string name) => MatchesName(resolvedLocation, name))) { return false; } } if (conditions.TimeOfDay != null && !MatchesTimeOfDay(conditions.TimeOfDay)) { return false; } if (HasAnyValues(conditions.RequiredEnvironments)) { EnvMan instance2 = EnvMan.instance; string text4 = ((instance2 == null) ? null : instance2.GetCurrentEnvironment()?.m_name); if (string.IsNullOrWhiteSpace(text4)) { return false; } string resolvedEnvironment = text4; if (!conditions.RequiredEnvironments.Any((string name) => MatchesName(resolvedEnvironment, name))) { return false; } } if (conditions.InDungeon.HasValue && Character.InInterior(position) != conditions.InDungeon.Value) { return false; } if (conditions.InForest.HasValue && WorldGenerator.InForest(position) != conditions.InForest.Value) { return false; } Vector2 val = new Vector2(position.x, position.z); float magnitude = ((Vector2)(ref val)).magnitude; float? min = RangeFormatting.GetMin(conditions.DistanceFromCenter, conditions.MinDistanceFromCenter); float? max = RangeFormatting.GetMax(conditions.DistanceFromCenter, conditions.MinDistanceFromCenter, conditions.MaxDistanceFromCenter); if (min.HasValue && magnitude < min.Value) { return false; } if (max.HasValue && magnitude > max.Value) { return false; } float? min2 = RangeFormatting.GetMin(conditions.Altitude, conditions.MinAltitude); float? max2 = RangeFormatting.GetMax(conditions.Altitude, conditions.MinAltitude, conditions.MaxAltitude); if (min2.HasValue && position.y < min2.Value) { return false; } if (max2.HasValue && position.y > max2.Value) { return false; } if (conditions.InsidePlayerBase.HasValue && (Object)(object)EffectArea.IsPointInsideArea(position, (Type)4, 0f) != (Object)null != conditions.InsidePlayerBase.Value) { return false; } return true; } internal static bool AreStaticConditionsSatisfied(GameObject gameObject, ConditionsDefinition? conditions, string? resolvedLocationName = null) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) if (!HasStaticConditions(conditions)) { return true; } Vector3 position = gameObject.transform.position; if (HasBiomeCondition(conditions)) { WorldGenerator instance = WorldGenerator.instance; if (!MatchesBiomeCondition((instance != null) ? instance.GetBiome(position) : Heightmap.FindBiome(position), conditions)) { return false; } } if (HasAnyValues(conditions.Locations)) { string text = ResolveLocationName(gameObject, position, resolvedLocationName); if (string.IsNullOrWhiteSpace(text)) { return false; } string resolvedLocation = text; if (!conditions.Locations.Any((string name) => MatchesName(resolvedLocation, name))) { return false; } } if (conditions.InDungeon.HasValue && Character.InInterior(position) != conditions.InDungeon.Value) { return false; } if (conditions.InForest.HasValue && WorldGenerator.InForest(position) != conditions.InForest.Value) { return false; } Vector2 val = new Vector2(position.x, position.z); float magnitude = ((Vector2)(ref val)).magnitude; float? min = RangeFormatting.GetMin(conditions.DistanceFromCenter, conditions.MinDistanceFromCenter); float? max = RangeFormatting.GetMax(conditions.DistanceFromCenter, conditions.MinDistanceFromCenter, conditions.MaxDistanceFromCenter); if (min.HasValue && magnitude < min.Value) { return false; } if (max.HasValue && magnitude > max.Value) { return false; } float? min2 = RangeFormatting.GetMin(conditions.Altitude, conditions.MinAltitude); float? max2 = RangeFormatting.GetMax(conditions.Altitude, conditions.MinAltitude, conditions.MaxAltitude); if (min2.HasValue && position.y < min2.Value) { return false; } if (max2.HasValue && position.y > max2.Value) { return false; } return true; } internal static string? GetResolvedLocationNameForConditions(GameObject gameObject) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)gameObject == (Object)null) { return null; } return ResolveLocationName(gameObject, gameObject.transform.position, null); } internal static bool AreDynamicConditionsSatisfied(ConditionsDefinition? conditions, int timeOfDayPhaseMarker, string? environmentName, bool isInsidePlayerBase, Func getGlobalKeyState) { if (!HasDynamicConditions(conditions)) { return true; } if (HasAnyValues(conditions.RequiredGlobalKeys)) { foreach (string requiredGlobalKey in conditions.RequiredGlobalKeys) { string text = (requiredGlobalKey ?? "").Trim(); if (text.Length != 0 && !getGlobalKeyState(text)) { return false; } } } if (HasAnyValues(conditions.ForbiddenGlobalKeys)) { foreach (string forbiddenGlobalKey in conditions.ForbiddenGlobalKeys) { string text2 = (forbiddenGlobalKey ?? "").Trim(); if (text2.Length != 0 && getGlobalKeyState(text2)) { return false; } } } if (conditions.TimeOfDay != null && !MatchesTimeOfDay(conditions.TimeOfDay, timeOfDayPhaseMarker)) { return false; } if (HasAnyValues(conditions.RequiredEnvironments)) { string resolvedEnvironment = (environmentName ?? "").Trim(); if (resolvedEnvironment.Length == 0 || !conditions.RequiredEnvironments.Any((string name) => MatchesName(resolvedEnvironment, name))) { return false; } } if (conditions.InsidePlayerBase.HasValue && isInsidePlayerBase != conditions.InsidePlayerBase.Value) { return false; } return true; } internal static bool AreSatisfied(Character character, ConditionsDefinition? conditions) { //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) Character character2 = character; if (!HasCharacterConditions(conditions)) { return true; } if ((Object)(object)character2 == (Object)null) { return false; } if (!AreSatisfied(((Component)character2).gameObject, conditions)) { return false; } int? min = RangeFormatting.GetMin(conditions.Level, conditions.MinLevel); int? max = RangeFormatting.GetMax(conditions.Level, conditions.MinLevel, conditions.MaxLevel); if (min.HasValue && character2.GetLevel() < min.Value) { return false; } if (max.HasValue && character2.GetLevel() > max.Value) { return false; } if (HasAnyValues(conditions.Factions)) { Faction currentFaction = character2.GetFaction(); if (!conditions.Factions.Any((string name) => MatchesFaction(currentFaction, name))) { return false; } } if (HasAnyValues(conditions.States) && !conditions.States.Any((string name) => MatchesCreatureState(character2, name))) { return false; } return true; } private static bool HasAnyValues(List? values) { return values?.Any((string value) => !string.IsNullOrWhiteSpace(value)) ?? false; } private static bool HasBiomeCondition(ConditionsDefinition? conditions) { if (conditions != null) { if (!conditions.ResolvedBiomeMask.HasValue) { return HasAnyValues(conditions.Biomes); } return true; } return false; } private static bool MatchesBiomeCondition(Biome currentBiome, ConditionsDefinition? conditions) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Invalid comparison between Unknown and I4 if (conditions != null && conditions.ResolvedBiomeMask.HasValue) { return (currentBiome & conditions.ResolvedBiomeMask.Value) > 0; } if (conditions == null) { return false; } return (conditions.Biomes?.Any((string name) => MatchesBiome(currentBiome, name))).GetValueOrDefault(); } private static bool MatchesBiome(Biome currentBiome, string configuredBiome) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return BiomeResolutionSupport.MatchesBiome(currentBiome, configuredBiome); } private static bool MatchesName(string currentValue, string configuredValue) { string text = (configuredValue ?? "").Trim(); if (text.Length > 0) { return string.Equals(currentValue, text, StringComparison.OrdinalIgnoreCase); } return false; } private static bool MatchesTimeOfDay(TimeOfDayDefinition configuredTimeOfDay) { return TimeOfDayFormatting.MatchesCurrentTime(configuredTimeOfDay); } private static bool MatchesTimeOfDay(TimeOfDayDefinition configuredTimeOfDay, int phaseMarker) { if (!configuredTimeOfDay.HasValues()) { return false; } return configuredTimeOfDay.Values.Any((string value) => MatchesTimeOfDayToken(value, phaseMarker)); } private static bool MatchesTimeOfDayToken(string token, int phaseMarker) { return (token ?? "").Trim().ToLowerInvariant() switch { "day" => phaseMarker == 1 || phaseMarker == 2, "afternoon" => phaseMarker == 2, "night" => phaseMarker == 0, _ => false, }; } private static bool MatchesFaction(Faction currentFaction, string configuredFaction) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return FactionIntegration.Matches(currentFaction, configuredFaction); } private static bool MatchesCreatureState(Character character, string configuredState) { string text = (configuredState ?? "").Trim().ToLowerInvariant(); if (text.Length == 0) { return false; } bool flag = character.IsTamed(); MonsterAI component = ((Component)character).GetComponent(); bool flag2 = (Object)(object)component != (Object)null && component.IsEventCreature(); return text switch { "default" => !flag && !flag2, "tamed" => flag, "event" => flag2, _ => false, }; } private static string? ResolveLocationName(GameObject? gameObject, Vector3 position, string? explicitLocationName) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0064: 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_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) string text = (explicitLocationName ?? "").Trim(); if (text.Length > 0) { return text; } EnsureLocationResolutionCacheState(); if (SpawnerManager.TryGetResolvedLocationNameForConditions(gameObject, out string locationPrefab) && !string.IsNullOrWhiteSpace(locationPrefab)) { CacheResolvedLocationName(gameObject, position, locationPrefab, CachedLocationResolutionMode.Stable); return locationPrefab; } string owningLocationName = GetOwningLocationName(gameObject); if (!string.IsNullOrWhiteSpace(owningLocationName)) { CacheResolvedLocationName(gameObject, position, owningLocationName, CachedLocationResolutionMode.Stable); return owningLocationName; } if (TryGetCachedLocationResolution(gameObject, position, out string locationName)) { return locationName; } string zoneMatchedLocationName = GetZoneMatchedLocationName(position); if (!string.IsNullOrWhiteSpace(zoneMatchedLocationName)) { CacheResolvedLocationName(gameObject, position, zoneMatchedLocationName, CachedLocationResolutionMode.Spatial); return zoneMatchedLocationName; } string locationName2 = GetLocationName(position); CacheResolvedLocationName(gameObject, position, locationName2, CachedLocationResolutionMode.Spatial); return locationName2; } private static string? GetOwningLocationName(GameObject? gameObject) { if ((Object)(object)gameObject == (Object)null) { return null; } Location componentInParent = gameObject.GetComponentInParent(true); if ((Object)(object)componentInParent != (Object)null && LocationManager.TryResolveRuntimeLocationPrefabName(componentInParent, out string prefabName) && !string.IsNullOrWhiteSpace(prefabName)) { return prefabName; } if (!((Object)(object)componentInParent != (Object)null)) { return null; } return GetLocationName(componentInParent); } private static string? GetLocationName(Vector3 position) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) Location location = Location.GetLocation(position, true); if ((Object)(object)location != (Object)null && LocationManager.TryResolveRuntimeLocationPrefabName(location, out string prefabName) && !string.IsNullOrWhiteSpace(prefabName)) { return prefabName; } if (!((Object)(object)location != (Object)null)) { return null; } return GetLocationName(location); } private static string? GetZoneMatchedLocationName(Vector3 position) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0061: 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) if ((Object)(object)ZoneSystem.instance == (Object)null) { return null; } Vector2i zone = ZoneSystem.GetZone(position); if (!ZoneSystem.instance.m_locationInstances.TryGetValue(zone, out var value)) { return null; } float num = Mathf.Max(value.m_location.m_exteriorRadius, value.m_location.m_interiorRadius); if (num <= 0f || Utils.DistanceXZ(value.m_position, position) > num) { return null; } Location zoneLocation = Location.GetZoneLocation(position); if ((Object)(object)zoneLocation != (Object)null && LocationManager.TryResolveRuntimeLocationPrefabName(zoneLocation, out string prefabName) && !string.IsNullOrWhiteSpace(prefabName)) { return prefabName; } string text = (value.m_location.m_prefab.Name ?? "").Trim(); if (text.Length <= 0) { return null; } return text; } private static void EnsureLocationResolutionCacheState() { int num = (((Object)(object)ZoneSystem.instance != (Object)null) ? ((Object)ZoneSystem.instance).GetInstanceID() : 0); int num2 = ZoneSystem.instance?.m_locationInstances.Count ?? 0; if (_lastLocationResolutionZoneSystemId != num || _lastLocationResolutionLocationInstanceCount != num2) { _locationResolutionEpoch++; CachedLocationResolutionsByObjectId.Clear(); _lastLocationResolutionZoneSystemId = num; _lastLocationResolutionLocationInstanceCount = num2; } } private static bool TryGetCachedLocationResolution(GameObject? gameObject, Vector3 position, out string? locationName) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) locationName = null; if ((Object)(object)gameObject == (Object)null) { return false; } if (!CachedLocationResolutionsByObjectId.TryGetValue(((Object)gameObject).GetInstanceID(), out CachedLocationResolution value)) { return false; } Vector2i zone = ZoneSystem.GetZone(position); if (value.Epoch != _locationResolutionEpoch || value.Zone != zone) { return false; } if (value.Mode == CachedLocationResolutionMode.Spatial) { Vector3 val = position - value.Position; if (val.x * val.x + val.z * val.z > 1f) { return false; } } locationName = (value.HasLocationName ? value.LocationName : null); return true; } private static void CacheResolvedLocationName(GameObject? gameObject, Vector3 position, string? locationName, CachedLocationResolutionMode mode) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)gameObject == (Object)null)) { if (CachedLocationResolutionsByObjectId.Count >= 4096) { CachedLocationResolutionsByObjectId.Clear(); _locationResolutionEpoch++; } CachedLocationResolutionsByObjectId[((Object)gameObject).GetInstanceID()] = new CachedLocationResolution { Epoch = _locationResolutionEpoch, Zone = ZoneSystem.GetZone(position), Position = position, LocationName = (locationName ?? "").Trim(), HasLocationName = !string.IsNullOrWhiteSpace(locationName), Mode = mode }; } } private static string? GetLocationName(Location location) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) if (LocationManager.TryResolveRuntimeLocationPrefabName(location, out string prefabName) && !string.IsNullOrWhiteSpace(prefabName)) { return prefabName; } if ((Object)(object)ZoneSystem.instance != (Object)null) { Vector2i zone = ZoneSystem.GetZone(((Component)location).transform.position); if (ZoneSystem.instance.m_locationInstances.TryGetValue(zone, out var value)) { string text = (value.m_location.m_prefab.Name ?? "").Trim(); if (text.Length > 0) { return text; } } } return TrimCloneSuffix(((Object)((Component)location).gameObject).name); } private static string TrimCloneSuffix(string name) { if (!name.EndsWith("(Clone)", StringComparison.Ordinal)) { return name; } return name.Substring(0, name.Length - "(Clone)".Length); } } internal static class DropNSpawnConsoleCommands { [CompilerGenerated] private static class <>O { public static ConsoleEvent <0>__WriteFullScaffoldFiles; public static ConsoleOptionsFetcher <1>__GetScopedDomainTabOptions; public static ConsoleEvent <2>__WriteReferenceFiles; public static ConsoleEvent <3>__InspectRuntimeTarget; public static ConsoleOptionsFetcher <4>__GetInspectTabOptions; public static ConsoleEvent <5>__HandleBossStoneCommand; public static ConsoleOptionsFetcher <6>__GetBossStoneTabOptions; } private const string WriteFullCommandName = "dns:full"; private const string WriteReferenceCommandName = "dns:reference"; private const string InspectCommandName = "dns:inspect"; private const string BossStoneCommandName = "dns:bossstone"; private static readonly List ScopedDomainTabOptions = new List { "object", "character", "spawner", "location", "spawnsystem", "all" }; private static readonly List InspectTabOptions = new List { "spawner", "bossstone" }; private static readonly List BossStoneTabOptions = new List { "reset" }; private static bool _registered; internal static void Register() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Expected O, but got Unknown //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Expected O, but got Unknown //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Expected O, but got Unknown //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Expected O, but got Unknown //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Expected O, but got Unknown //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Expected O, but got Unknown //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Expected O, but got Unknown if (!_registered) { _registered = true; object obj = <>O.<0>__WriteFullScaffoldFiles; if (obj == null) { ConsoleEvent val = WriteFullScaffoldFiles; <>O.<0>__WriteFullScaffoldFiles = val; obj = (object)val; } object obj2 = <>O.<1>__GetScopedDomainTabOptions; if (obj2 == null) { ConsoleOptionsFetcher val2 = GetScopedDomainTabOptions; <>O.<1>__GetScopedDomainTabOptions = val2; obj2 = (object)val2; } new ConsoleCommand("dns:full", "Write non-loaded full scaffold YAML files for object/character/spawner/location/spawnsystem entries with explicit defaults.", (ConsoleEvent)obj, false, false, false, false, false, (ConsoleOptionsFetcher)obj2, false, false, false); object obj3 = <>O.<2>__WriteReferenceFiles; if (obj3 == null) { ConsoleEvent val3 = WriteReferenceFiles; <>O.<2>__WriteReferenceFiles = val3; obj3 = (object)val3; } object obj4 = <>O.<1>__GetScopedDomainTabOptions; if (obj4 == null) { ConsoleOptionsFetcher val4 = GetScopedDomainTabOptions; <>O.<1>__GetScopedDomainTabOptions = val4; obj4 = (object)val4; } new ConsoleCommand("dns:reference", "Write current generated reference YAML files for object/character/spawner/location/spawnsystem.", (ConsoleEvent)obj3, false, false, false, false, false, (ConsoleOptionsFetcher)obj4, false, false, false); object obj5 = <>O.<3>__InspectRuntimeTarget; if (obj5 == null) { ConsoleEvent val5 = InspectRuntimeTarget; <>O.<3>__InspectRuntimeTarget = val5; obj5 = (object)val5; } object obj6 = <>O.<4>__GetInspectTabOptions; if (obj6 == null) { ConsoleOptionsFetcher val6 = GetInspectTabOptions; <>O.<4>__GetInspectTabOptions = val6; obj6 = (object)val6; } new ConsoleCommand("dns:inspect", "Inspect the current hovered/aimed runtime target. Currently supports: spawner, bossstone.", (ConsoleEvent)obj5, false, false, false, false, false, (ConsoleOptionsFetcher)obj6, false, false, false); object obj7 = <>O.<5>__HandleBossStoneCommand; if (obj7 == null) { ConsoleEvent val7 = HandleBossStoneCommand; <>O.<5>__HandleBossStoneCommand = val7; obj7 = (object)val7; } object obj8 = <>O.<6>__GetBossStoneTabOptions; if (obj8 == null) { ConsoleOptionsFetcher val8 = GetBossStoneTabOptions; <>O.<6>__GetBossStoneTabOptions = val8; obj8 = (object)val8; } new ConsoleCommand("dns:bossstone", "Reset per-player boss stone state. Syntax: dns:bossstone reset ", (ConsoleEvent)obj7, true, false, false, false, false, (ConsoleOptionsFetcher)obj8, false, false, true); } } private static List GetScopedDomainTabOptions() { return ScopedDomainTabOptions; } private static List GetInspectTabOptions() { return InspectTabOptions; } private static List GetBossStoneTabOptions() { return BossStoneTabOptions; } private static void WriteFullScaffoldFiles(ConsoleEventArgs args) { if (!TryParseScope(args, "dns:full", out var includeObject, out var includeCharacter, out var includeSpawner, out var includeLocation, out var includeSpawnSystem)) { return; } if (includeObject) { if (ObjectDropManager.TryWriteFullScaffoldConfigurationFile(out string path, out string error)) { Terminal context = args.Context; if (context != null) { context.AddString("Wrote object full scaffold to " + path); } } else { Terminal context2 = args.Context; if (context2 != null) { context2.AddString(error); } } } if (includeCharacter) { if (CharacterDropManager.TryWriteFullScaffoldConfigurationFile(out string path2, out string error2)) { Terminal context3 = args.Context; if (context3 != null) { context3.AddString("Wrote character full scaffold to " + path2); } } else { Terminal context4 = args.Context; if (context4 != null) { context4.AddString(error2); } } } if (includeSpawner) { if (SpawnerManager.TryWriteFullScaffoldConfigurationFile(out string path3, out string error3)) { Terminal context5 = args.Context; if (context5 != null) { context5.AddString("Wrote spawner full scaffold to " + path3); } } else { Terminal context6 = args.Context; if (context6 != null) { context6.AddString(error3); } } } if (includeLocation) { if (LocationManager.TryWriteFullScaffoldConfigurationFile(out string path4, out string error4)) { Terminal context7 = args.Context; if (context7 != null) { context7.AddString("Wrote location full scaffold to " + path4); } } else { Terminal context8 = args.Context; if (context8 != null) { context8.AddString(error4); } } } if (!includeSpawnSystem) { return; } if (SpawnSystemManager.TryWriteFullScaffoldConfigurationFile(out string path5, out string error5)) { Terminal context9 = args.Context; if (context9 != null) { context9.AddString("Wrote spawnsystem full scaffold to " + path5); } } else { Terminal context10 = args.Context; if (context10 != null) { context10.AddString(error5); } } } private static void WriteReferenceFiles(ConsoleEventArgs args) { if (!TryParseScope(args, "dns:reference", out var includeObject, out var includeCharacter, out var includeSpawner, out var includeLocation, out var includeSpawnSystem)) { return; } if (includeObject) { ObjectDropManager.RefreshReferenceConfigurationFile(); Terminal context = args.Context; if (context != null) { context.AddString("Updated object reference configuration."); } } if (includeCharacter) { CharacterDropManager.RefreshReferenceConfigurationFile(); Terminal context2 = args.Context; if (context2 != null) { context2.AddString("Updated character reference configuration."); } } if (includeSpawner) { SpawnerManager.RefreshReferenceConfigurationFile(); Terminal context3 = args.Context; if (context3 != null) { context3.AddString("Updated spawner reference configuration."); } } if (includeLocation) { LocationManager.RefreshReferenceConfigurationFile(); Terminal context4 = args.Context; if (context4 != null) { context4.AddString("Updated location reference configuration."); } } if (!includeSpawnSystem) { return; } if (SpawnSystemManager.TryWriteReferenceConfigurationFile(out string path, out string error)) { Terminal context5 = args.Context; if (context5 != null) { context5.AddString("Wrote spawnsystem reference to " + path); } } else { Terminal context6 = args.Context; if (context6 != null) { context6.AddString(error); } } } private static void InspectRuntimeTarget(ConsoleEventArgs args) { string text = ((args.Length >= 2) ? (args[1] ?? "").Trim().ToLowerInvariant() : ""); string[] lines2; string error2; if (!(text == "spawner")) { if (text == "bossstone") { if (BossStonePerPlayerRuntime.TryInspectCurrentTarget(out string[] lines, out string error)) { string[] array = lines; foreach (string text2 in array) { Terminal context = args.Context; if (context != null) { context.AddString(text2); } } } else { Terminal context2 = args.Context; if (context2 != null) { context2.AddString(error); } } } else { Terminal context3 = args.Context; if (context3 != null) { context3.AddString("Syntax: dns:inspect spawner"); } Terminal context4 = args.Context; if (context4 != null) { context4.AddString("Syntax: dns:inspect bossstone"); } } } else if (SpawnerManager.TryInspectCurrentTarget(out lines2, out error2)) { string[] array = lines2; foreach (string text3 in array) { Terminal context5 = args.Context; if (context5 != null) { context5.AddString(text3); } } } else { Terminal context6 = args.Context; if (context6 != null) { context6.AddString(error2); } } } private static void HandleBossStoneCommand(ConsoleEventArgs args) { if (((args.Length >= 2) ? (args[1] ?? "").Trim().ToLowerInvariant() : "") == "reset") { if (BossStonePerPlayerRuntime.TryRequestReset((args.FullLine.Length > "dns:bossstone reset".Length) ? args.FullLine.Substring("dns:bossstone reset".Length).Trim() : "", out string message)) { Terminal context = args.Context; if (context != null) { context.AddString(message); } } else { Terminal context2 = args.Context; if (context2 != null) { context2.AddString(message); } } } else { Terminal context3 = args.Context; if (context3 != null) { context3.AddString("Syntax: dns:bossstone reset "); } } } private static bool TryParseScope(ConsoleEventArgs args, string commandName, out bool includeObject, out bool includeCharacter, out bool includeSpawner, out bool includeLocation, out bool includeSpawnSystem) { string text = ((args.Length >= 2) ? (args[1] ?? "").Trim().ToLowerInvariant() : "all"); if (text.Length == 0) { text = "all"; } switch (text) { case "all": includeObject = true; includeCharacter = true; includeSpawner = true; includeLocation = true; includeSpawnSystem = true; return true; case "object": includeObject = true; includeCharacter = false; includeSpawner = false; includeLocation = false; includeSpawnSystem = false; return true; case "character": includeObject = false; includeCharacter = true; includeSpawner = false; includeLocation = false; includeSpawnSystem = false; return true; case "spawner": includeObject = false; includeCharacter = false; includeSpawner = true; includeLocation = false; includeSpawnSystem = false; return true; case "location": includeObject = false; includeCharacter = false; includeSpawner = false; includeLocation = true; includeSpawnSystem = false; return true; case "spawnsystem": includeObject = false; includeCharacter = false; includeSpawner = false; includeLocation = false; includeSpawnSystem = true; return true; default: { includeObject = false; includeCharacter = false; includeSpawner = false; includeLocation = false; includeSpawnSystem = false; Terminal context = args.Context; if (context != null) { context.AddString("Syntax: " + commandName + " [object|character|spawner|location|spawnsystem|all]"); } return false; } } } } internal static class ExpandWorldFieldOverrideSupport { private static readonly int HashDamage = StringExtensionMethods.GetStableHashCode("damage"); private static readonly HashSet KnownFloatHashes = new HashSet { ZDOVars.s_randomSkillFactor, HashDamage, ZDOVars.s_health, ZDOVars.s_maxHealth, ZDOVars.s_noise }; private static readonly HashSet KnownIntHashes = new HashSet { ZDOVars.s_level, ZDOVars.s_seed, ZDOVars.s_lovePoints }; private static readonly HashSet KnownLongHashes = new HashSet { ZDOVars.s_spawnTime, ZDOVars.s_worldTimeHash, ZDOVars.s_pregnant }; private static readonly HashSet KnownBoolHashes = new HashSet { StringExtensionMethods.GetStableHashCode("bosscount"), ZDOVars.s_isBlockingHash, ZDOVars.s_tamed, ZDOVars.s_aggravated, ZDOVars.s_alert, ZDOVars.s_shownAlertMessage, ZDOVars.s_huntPlayer, ZDOVars.s_patrol, ZDOVars.s_despawnInDay, ZDOVars.s_eventCreature, ZDOVars.s_sleeping, ZDOVars.s_haveSaddleHash }; private static readonly HashSet KnownVectorHashes = new HashSet { ZDOVars.s_bodyVelocity, ZDOVars.s_spawnPoint, ZDOVars.s_patrolPoint }; private static readonly HashSet KnownStringHashes = new HashSet { ZDOVars.s_tamedName, ZDOVars.s_tamedNameAuthor }; internal static void AddFieldOverrides(DataEntry customData, GameObject prefab, Dictionary configuredFields) { Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); Dictionary> dictionary2 = new Dictionary>(StringComparer.OrdinalIgnoreCase); foreach (KeyValuePair configuredField in configuredFields) { object obj; string text3; (obj, text3) = (KeyValuePair)(ref configuredField); if (obj == null) { obj = ""; } string text4 = ((string)obj).Trim(); string value = text3 ?? ""; if (text4.Length == 0) { continue; } int stableHashCode = StringExtensionMethods.GetStableHashCode(text4); if (TryInsertKnownOverride(customData, stableHashCode, value)) { continue; } string[] array = text4.Split(new char[1] { '.' }, 2); if (array.Length == 2) { if (!TryInsertTypedOverride(customData, array[0], array[1], value)) { if (!dictionary2.TryGetValue(array[0], out var value2)) { value2 = new Dictionary(StringComparer.OrdinalIgnoreCase); dictionary2[array[0]] = value2; } value2[array[1]] = value; value2["m_" + array[1]] = value; } } else { dictionary[text4] = value; dictionary["m_" + text4] = value; } } prefab.GetComponentsInChildren(ZNetView.m_tempComponents); foreach (MonoBehaviour tempComponent in ZNetView.m_tempComponents) { Type type = ((object)tempComponent).GetType(); string name = type.Name; FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public); foreach (FieldInfo fieldInfo in fields) { if (dictionary2.TryGetValue(name, out var value3) && value3.TryGetValue(fieldInfo.Name, out var value4)) { InsertReflectedField(customData, (Component)(object)tempComponent, fieldInfo, value4); } if (dictionary.TryGetValue(fieldInfo.Name, out var value5)) { InsertReflectedField(customData, (Component)(object)tempComponent, fieldInfo, value5); } } } ZNetView.m_tempComponents.Clear(); } private static bool TryInsertKnownOverride(DataEntry customData, int hash, string value) { if (KnownFloatHashes.Contains(hash)) { DataEntry val = customData; if (val.Floats == null) { val.Floats = new Dictionary(); } if (hash == HashDamage) { hash = ZDOVars.s_randomSkillFactor; } customData.Floats[hash] = DataValue.Float(value); return true; } if (KnownIntHashes.Contains(hash)) { DataEntry val = customData; if (val.Ints == null) { val.Ints = new Dictionary(); } customData.Ints[hash] = DataValue.Int(value); return true; } if (KnownLongHashes.Contains(hash)) { DataEntry val = customData; if (val.Longs == null) { val.Longs = new Dictionary(); } customData.Longs[hash] = DataValue.Long(value); return true; } if (KnownBoolHashes.Contains(hash)) { DataEntry val = customData; if (val.Bools == null) { val.Bools = new Dictionary(); } customData.Bools[hash] = DataValue.Bool(value); return true; } if (KnownVectorHashes.Contains(hash)) { DataEntry val = customData; if (val.Vecs == null) { val.Vecs = new Dictionary(); } customData.Vecs[hash] = DataValue.Vector3(value); return true; } if (KnownStringHashes.Contains(hash)) { DataEntry val = customData; if (val.Strings == null) { val.Strings = new Dictionary(); } customData.Strings[hash] = DataValue.String(value); return true; } return false; } private static bool TryInsertTypedOverride(DataEntry customData, string rawPrefix, string rawKey, string value) { string text = (rawKey ?? "").Trim(); if (text.Length == 0) { return false; } int stableHashCode = StringExtensionMethods.GetStableHashCode(text); switch ((rawPrefix ?? "").Trim().ToLowerInvariant()) { case "int": { DataEntry val = customData; if (val.Ints == null) { val.Ints = new Dictionary(); } customData.Ints[stableHashCode] = DataValue.Int(value); return true; } case "float": { DataEntry val = customData; if (val.Floats == null) { val.Floats = new Dictionary(); } customData.Floats[stableHashCode] = DataValue.Float(value); return true; } case "bool": { DataEntry val = customData; if (val.Bools == null) { val.Bools = new Dictionary(); } customData.Bools[stableHashCode] = DataValue.Bool(value); return true; } case "long": { DataEntry val = customData; if (val.Longs == null) { val.Longs = new Dictionary(); } customData.Longs[stableHashCode] = DataValue.Long(value); return true; } case "vec": { DataEntry val = customData; if (val.Vecs == null) { val.Vecs = new Dictionary(); } customData.Vecs[stableHashCode] = DataValue.Vector3(value); return true; } case "quat": { DataEntry val = customData; if (val.Quats == null) { val.Quats = new Dictionary(); } customData.Quats[stableHashCode] = DataValue.Quaternion(value); return true; } case "string": { DataEntry val = customData; if (val.Strings == null) { val.Strings = new Dictionary(); } customData.Strings[stableHashCode] = DataValue.String(value); return true; } default: return false; } } private static void InsertReflectedField(DataEntry customData, Component component, FieldInfo field, string value) { int stableHashCode = StringExtensionMethods.GetStableHashCode(((object)component).GetType().Name + "." + field.Name); DataEntry val = customData; if (val.Ints == null) { val.Ints = new Dictionary(); } customData.Ints[StringExtensionMethods.GetStableHashCode("HasFields")] = DataValue.Simple(1); customData.Ints[StringExtensionMethods.GetStableHashCode("HasFields" + ((object)component).GetType().Name)] = DataValue.Simple(1); if (field.FieldType == typeof(int)) { customData.Ints[stableHashCode] = DataValue.Int(value); } else if (field.FieldType == typeof(float)) { val = customData; if (val.Floats == null) { val.Floats = new Dictionary(); } customData.Floats[stableHashCode] = DataValue.Float(value); } else if (field.FieldType == typeof(bool)) { val = customData; if (val.Bools == null) { val.Bools = new Dictionary(); } customData.Bools[stableHashCode] = DataValue.Bool(value); } else if (field.FieldType == typeof(long)) { val = customData; if (val.Longs == null) { val.Longs = new Dictionary(); } customData.Longs[stableHashCode] = DataValue.Long(value); } else if (field.FieldType == typeof(Vector3)) { val = customData; if (val.Vecs == null) { val.Vecs = new Dictionary(); } customData.Vecs[stableHashCode] = DataValue.Vector3(value); } else if (field.FieldType == typeof(Quaternion)) { val = customData; if (val.Quats == null) { val.Quats = new Dictionary(); } customData.Quats[stableHashCode] = DataValue.Quaternion(value); } else { val = customData; if (val.Strings == null) { val.Strings = new Dictionary(); } customData.Strings[stableHashCode] = DataValue.String(value); } } } internal sealed class ExpandWorldSpawnDataPayload { internal DataEntry? Data { get; } internal List? Objects { get; } internal bool HasData => Data != null; internal bool HasObjects { get { List objects = Objects; if (objects != null) { return objects.Count > 0; } return false; } } internal ExpandWorldSpawnDataPayload(DataEntry? data, List? objects) { Data = data; Objects = objects; } } internal static class ExpandWorldSpawnDataSupport { internal static ExpandWorldSpawnDataPayload? BuildPayload(GameObject? prefab, string? dataName, Dictionary? fields, List? objects, string context) { DataEntry val = BuildCustomData(prefab, dataName, fields, context); List list = BuildCustomObjects(objects, context); if (val == null && (list == null || list.Count == 0)) { return null; } return new ExpandWorldSpawnDataPayload(val, list); } internal static void InitializeSpawn(GameObject? prefab, Vector3 spawnPoint, ExpandWorldSpawnDataPayload? payload) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)prefab == (Object)null) && payload?.Data != null) { DataHelper.Init(prefab, spawnPoint, Quaternion.identity, (Vector3?)null, payload.Data); } } internal static void SpawnObjects(Vector3 spawnPoint, ExpandWorldSpawnDataPayload? payload) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) if (payload?.Objects == null || payload.Objects.Count == 0) { return; } foreach (BlueprintObject @object in payload.Objects) { if (!(@object.Chance < 1f) || !(Random.value > @object.Chance)) { Spawn.BPO(@object, spawnPoint, Quaternion.identity, Vector3.one, (Func)ObjectDataIdentity, (Func)ObjectPrefabIdentity, (List)null); } } } private static DataEntry? BuildCustomData(GameObject? prefab, string? dataName, Dictionary? fields, string context) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown DataEntry val = null; if (!string.IsNullOrWhiteSpace(dataName)) { val = DataHelper.Get(dataName.Trim(), "DropNSpawn_spawn:" + context); } Dictionary dictionary = NormalizeConfiguredFields(fields); if (dictionary == null) { return val; } if ((Object)(object)prefab == (Object)null) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("Entry '" + context + "' configured fields but no spawn prefab was available. The fields block was ignored.")); return val; } DataEntry val2 = new DataEntry(); ExpandWorldFieldOverrideSupport.AddFieldOverrides(val2, prefab, dictionary); return DataHelper.Merge(val, val2); } private static Dictionary? NormalizeConfiguredFields(Dictionary? values) { if (values == null) { return null; } Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); foreach (KeyValuePair value in values) { object obj; string text3; (obj, text3) = (KeyValuePair)(ref value); if (obj == null) { obj = ""; } string text4 = ((string)obj).Trim(); if (text4.Length != 0) { dictionary[text4] = (text3 ?? "").Trim(); } } if (dictionary.Count != 0) { return dictionary; } return null; } private static List? BuildCustomObjects(List? configuredObjects, string context) { if (configuredObjects == null || configuredObjects.Count == 0) { return null; } List list = new List(); foreach (string configuredObject in configuredObjects) { if (TryParseObjectDefinition(configuredObject, context, out BlueprintObject obj)) { list.Add(obj); } } if (list.Count != 0) { return list; } return null; } private static bool TryParseObjectDefinition(string? rawDefinition, string context, out BlueprintObject? obj) { //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Expected O, but got Unknown obj = null; if (string.IsNullOrWhiteSpace(rawDefinition)) { return false; } string[] array = (from part in rawDefinition.Split(',') select part.Trim()).ToArray(); if (array.Length == 0 || array[0].Length == 0) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("Entry '" + context + "' contains an invalid objects entry '" + rawDefinition + "'. Expected format: Prefab,posX,posZ,posY,chance,data.")); return false; } if (!TryParseObjectFloat(array, 1, 0f, context, rawDefinition, out var value) || !TryParseObjectFloat(array, 2, 0f, context, rawDefinition, out var value2) || !TryParseObjectFloat(array, 3, 0f, context, rawDefinition, out var value3) || !TryParseObjectFloat(array, 4, 1f, context, rawDefinition, out var value4)) { return false; } DataEntry val = DataHelper.Get((array.Length > 5) ? array[5] : "", "DropNSpawn_spawn:" + context); obj = new BlueprintObject(array[0], new Vector3(value, value3, value2), Quaternion.identity, Vector3.one, val, value4, false); return true; } private static bool TryParseObjectFloat(string[] split, int index, float defaultValue, string context, string rawDefinition, out float value) { value = defaultValue; if (index >= split.Length || split[index].Length == 0) { return true; } if (float.TryParse(split[index], NumberStyles.Any, CultureInfo.InvariantCulture, out value)) { return true; } DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("Entry '" + context + "' contains an invalid objects entry '" + rawDefinition + "'. '" + split[index] + "' is not a valid number.")); return false; } private static DataEntry? ObjectDataIdentity(DataEntry? data, string prefab) { return data; } private static string ObjectPrefabIdentity(string prefab) { return prefab; } } internal static class ExampleContentWriter { private const string CharacterSampleFileName = "DNS_character.sample.yml"; private const string ObjectSampleFileName = "DNS_object.sample.yml"; private const string SpawnerSampleFileName = "DNS_spawner.sample.yml"; private const string LocationSampleFileName = "DNS_location.sample.yml"; private const string SpawnSystemSampleFileName = "DNS_spawnsystem.sample.yml"; private const string ReadmeContent = "Across all field types, `field: null` or omitting the field usually means the field is unspecified.\n\nMore broadly, it falls back to that field's default behavior, and the exact effect depends on the field.\n\nFor list, map/object, and string fields respectively, `[]`, `{}`, and `''` explicitly assign an empty list, empty object, or empty string, and their exact effect depends on the field.\n\n# `biomes: then indented - BlackForest and - Mistlands on separate lines` is another supported format for Block list\n\nRange shorthand uses 1, 1~5, and ~5. Note: 1~ currently resolves to 1 because open-ended max is not supported.\n\nfaction accepts vanilla Character.Faction names and ExpandWorldFactions custom faction names.\n"; private const string CharacterConditionContent = "# Character-domain coexistence samples.\n# Safe here as a .sample.yml file. Copy rows into the active override file, or rename this file to a DNS__*.yml name to load it.\n# Character conditions are top-level only.\n# Every matching entry for the same prefab contributes drops.\n# Identical drop rows are deduped.\n\n- prefab: Boar\n enabled: true\n conditions:\n biomes: [Meadows]\n characterDrop:\n drops:\n - item: LeatherScraps\n amount: 1~2\n chance: 1\n\n- prefab: Boar\n enabled: true\n conditions:\n biomes: [Meadows]\n timeOfDay: [night]\n characterDrop:\n drops:\n - item: Coins\n amount: 1~3\n chance: 0.25\n\n- prefab: Skeleton\n enabled: true\n conditions:\n biomes: [BlackForest]\n requiredGlobalKeys: [defeated_gdking]\n characterDrop:\n drops:\n - item: BoneFragments\n amount: 2~4\n chance: 1\n"; private const string ObjectConditionContent = "# Object-domain coexistence progression\n# Safe here as a .sample.yml file. Copy rows into the active override file, or rename this file to a DNS__*.yml name to load it.\n# Drop-table style payloads merge matching rows.\n# Scalar-style payloads are applied in order, so later matching entries override earlier values.\n\n- prefab: TreasureChest_meadows\n enabled: true\n conditions:\n biomes: [Meadows]\n container:\n rolls: 1~2\n drops:\n - item: Coins\n stack: 10~20\n weight: 1\n\n- prefab: RaspberryBush\n enabled: true\n conditions:\n biomes: [Meadows]\n pickable:\n overrideName: Berry Bush\n drop:\n item: Raspberry\n amount: 3\n minAmountScaled: 1\n\n- prefab: MineRock_Copper\n enabled: true\n conditions:\n locations: [CopperDeposit]\n mineRock:\n rolls: 2~3\n drops:\n - item: CopperOre\n stack: 2~4\n weight: 1\n"; private const string LocationConditionContent = "# Location-domain coexistence samples.\n# Safe here as a .sample.yml file. Copy rows into the active override file, or rename this file to a DNS__*.yml name to load it.\n# Location conditions are static location filters only: biomes, altitude, distanceFromCenter, inForest, and inDungeon.\n# Ranges may use inline form such as `distanceFromCenter: 1000~4000`.\n# offeringBowl, itemStands, vegvisirs, and runestones use sequential override.\n\n- prefab: Eikthyrnir\n enabled: true\n conditions:\n biomes: [Meadows]\n offeringBowl:\n respawnMinutes: 2\n alertOnSpawn: true\n\n- prefab: StartTemple\n enabled: true\n itemStands:\n - path: null\n canBeRemoved: false\n autoAttach: true\n\n- prefab: SwampRuin1\n enabled: true\n vegvisirs:\n - path: null\n locations:\n - locationName: Vendor_BlackForest\n showMap: true\n\n- prefab: Runestone_Greydwarfs\n enabled: true\n runestones:\n - path: null\n topic: '$tutorial_greydwarfs_topic'\n label: '$tutorial_greydwarfs'\n text: '$tutorial_greydwarfs_text'\n randomTexts: []\n"; private const string SpawnerConditionContent = "# Spawner-domain coexistence samples.\n# Safe here as a .sample.yml file. Copy rows into the active override file, or rename this file to a DNS__*.yml name to load it.\n# Use top-level `location` to scope one location-bound spawner.\n# Only the most specific passing entry is applied.\n\n- prefab: Spawner_GreydwarfNest\n enabled: true\n spawnArea:\n spawnInterval: 30\n maxNear: 4\n creatures:\n - creature: Greydwarf\n weight: 1\n\n- prefab: Spawner_GreydwarfNest\n enabled: true\n location: Greydwarf_camp1\n spawnArea:\n spawnInterval: 15\n maxNear: 6\n creatures:\n - creature: Greydwarf_Elite\n weight: 1\n\n- prefab: Spawner_Boar\n enabled: true\n creatureSpawner:\n creature: Boar\n level: 1~2\n spawnCheckInterval: 5\n triggerDistance: 60\n"; private const string SpawnSystemConditionContent = "# SpawnSystem-domain coexistence samples.\n# Safe here as a .sample.yml file. Copy rows into DNS_spawnsystem.yml one by one.\n# IMPORTANT: spawnsystem overrides replace the live world spawn table with the rows you load.\n# Every loaded entry becomes its own native SpawnSystem row.\n\n- prefab: Boar\n enabled: true\n spawnSystem:\n name: Boar meadows day\n spawnInterval: 150\n spawnChance: 50\n groupSize: 1~3\n groupRadius: 5\n conditions:\n altitude: 0~1000\n biomes: [Meadows]\n biomeAreas: [Edge, Median]\n timeOfDay: [day]\n\n- prefab: Neck\n enabled: true\n spawnSystem:\n name: Neck rain\n spawnInterval: 120\n spawnChance: 40\n groupSize: 2~4\n groupRadius: 5\n conditions:\n altitude: -1.5~0.5\n biomes: [Meadows]\n requiredEnvironments: [Rain, LightRain]\n\n- prefab: Greydwarf\n enabled: true\n spawnSystem:\n name: Greydwarf night\n spawnInterval: 120\n spawnChance: 30\n groupSize: 2~3\n conditions:\n biomes: [BlackForest]\n timeOfDay: [night]\n modifiers:\n faction: ForestMonsters\n"; private static string ExamplesDirectoryPath => Path.Combine(DropNSpawnPlugin.YamlConfigDirectoryPath, "examples"); internal static void EnsureDefaultExampleFiles() { EnsureExampleFile("README.md", "Across all field types, `field: null` or omitting the field usually means the field is unspecified.\n\nMore broadly, it falls back to that field's default behavior, and the exact effect depends on the field.\n\nFor list, map/object, and string fields respectively, `[]`, `{}`, and `''` explicitly assign an empty list, empty object, or empty string, and their exact effect depends on the field.\n\n# `biomes: then indented - BlackForest and - Mistlands on separate lines` is another supported format for Block list\n\nRange shorthand uses 1, 1~5, and ~5. Note: 1~ currently resolves to 1 because open-ended max is not supported.\n\nfaction accepts vanilla Character.Faction names and ExpandWorldFactions custom faction names.\n"); EnsureExampleFile("DNS_character.sample.yml", "# Character-domain coexistence samples.\n# Safe here as a .sample.yml file. Copy rows into the active override file, or rename this file to a DNS__*.yml name to load it.\n# Character conditions are top-level only.\n# Every matching entry for the same prefab contributes drops.\n# Identical drop rows are deduped.\n\n- prefab: Boar\n enabled: true\n conditions:\n biomes: [Meadows]\n characterDrop:\n drops:\n - item: LeatherScraps\n amount: 1~2\n chance: 1\n\n- prefab: Boar\n enabled: true\n conditions:\n biomes: [Meadows]\n timeOfDay: [night]\n characterDrop:\n drops:\n - item: Coins\n amount: 1~3\n chance: 0.25\n\n- prefab: Skeleton\n enabled: true\n conditions:\n biomes: [BlackForest]\n requiredGlobalKeys: [defeated_gdking]\n characterDrop:\n drops:\n - item: BoneFragments\n amount: 2~4\n chance: 1\n", "character.sample.yml", "DNS_character.conditions.sample.yml"); EnsureExampleFile("DNS_object.sample.yml", "# Object-domain coexistence progression\n# Safe here as a .sample.yml file. Copy rows into the active override file, or rename this file to a DNS__*.yml name to load it.\n# Drop-table style payloads merge matching rows.\n# Scalar-style payloads are applied in order, so later matching entries override earlier values.\n\n- prefab: TreasureChest_meadows\n enabled: true\n conditions:\n biomes: [Meadows]\n container:\n rolls: 1~2\n drops:\n - item: Coins\n stack: 10~20\n weight: 1\n\n- prefab: RaspberryBush\n enabled: true\n conditions:\n biomes: [Meadows]\n pickable:\n overrideName: Berry Bush\n drop:\n item: Raspberry\n amount: 3\n minAmountScaled: 1\n\n- prefab: MineRock_Copper\n enabled: true\n conditions:\n locations: [CopperDeposit]\n mineRock:\n rolls: 2~3\n drops:\n - item: CopperOre\n stack: 2~4\n weight: 1\n", "object.sample.yml", "DNS_object.conditions.sample.yml"); EnsureExampleFile("DNS_spawner.sample.yml", "# Spawner-domain coexistence samples.\n# Safe here as a .sample.yml file. Copy rows into the active override file, or rename this file to a DNS__*.yml name to load it.\n# Use top-level `location` to scope one location-bound spawner.\n# Only the most specific passing entry is applied.\n\n- prefab: Spawner_GreydwarfNest\n enabled: true\n spawnArea:\n spawnInterval: 30\n maxNear: 4\n creatures:\n - creature: Greydwarf\n weight: 1\n\n- prefab: Spawner_GreydwarfNest\n enabled: true\n location: Greydwarf_camp1\n spawnArea:\n spawnInterval: 15\n maxNear: 6\n creatures:\n - creature: Greydwarf_Elite\n weight: 1\n\n- prefab: Spawner_Boar\n enabled: true\n creatureSpawner:\n creature: Boar\n level: 1~2\n spawnCheckInterval: 5\n triggerDistance: 60\n", "spawner.sample.yml", "DNS_spawner.conditions.sample.yml"); EnsureExampleFile("DNS_location.sample.yml", "# Location-domain coexistence samples.\n# Safe here as a .sample.yml file. Copy rows into the active override file, or rename this file to a DNS__*.yml name to load it.\n# Location conditions are static location filters only: biomes, altitude, distanceFromCenter, inForest, and inDungeon.\n# Ranges may use inline form such as `distanceFromCenter: 1000~4000`.\n# offeringBowl, itemStands, vegvisirs, and runestones use sequential override.\n\n- prefab: Eikthyrnir\n enabled: true\n conditions:\n biomes: [Meadows]\n offeringBowl:\n respawnMinutes: 2\n alertOnSpawn: true\n\n- prefab: StartTemple\n enabled: true\n itemStands:\n - path: null\n canBeRemoved: false\n autoAttach: true\n\n- prefab: SwampRuin1\n enabled: true\n vegvisirs:\n - path: null\n locations:\n - locationName: Vendor_BlackForest\n showMap: true\n\n- prefab: Runestone_Greydwarfs\n enabled: true\n runestones:\n - path: null\n topic: '$tutorial_greydwarfs_topic'\n label: '$tutorial_greydwarfs'\n text: '$tutorial_greydwarfs_text'\n randomTexts: []\n", "location.sample.yml", "DNS_location.conditions.sample.yml"); EnsureExampleFile("DNS_spawnsystem.sample.yml", "# SpawnSystem-domain coexistence samples.\n# Safe here as a .sample.yml file. Copy rows into DNS_spawnsystem.yml one by one.\n# IMPORTANT: spawnsystem overrides replace the live world spawn table with the rows you load.\n# Every loaded entry becomes its own native SpawnSystem row.\n\n- prefab: Boar\n enabled: true\n spawnSystem:\n name: Boar meadows day\n spawnInterval: 150\n spawnChance: 50\n groupSize: 1~3\n groupRadius: 5\n conditions:\n altitude: 0~1000\n biomes: [Meadows]\n biomeAreas: [Edge, Median]\n timeOfDay: [day]\n\n- prefab: Neck\n enabled: true\n spawnSystem:\n name: Neck rain\n spawnInterval: 120\n spawnChance: 40\n groupSize: 2~4\n groupRadius: 5\n conditions:\n altitude: -1.5~0.5\n biomes: [Meadows]\n requiredEnvironments: [Rain, LightRain]\n\n- prefab: Greydwarf\n enabled: true\n spawnSystem:\n name: Greydwarf night\n spawnInterval: 120\n spawnChance: 30\n groupSize: 2~3\n conditions:\n biomes: [BlackForest]\n timeOfDay: [night]\n modifiers:\n faction: ForestMonsters\n", "spawnsystem.sample.yml", "DNS_spawnsystem.conditions.sample.yml"); } private static void EnsureExampleFile(string fileName, string defaultContent, params string[] legacyFileNames) { string text = Path.Combine(ExamplesDirectoryPath, fileName); Directory.CreateDirectory(ExamplesDirectoryPath); foreach (string text2 in legacyFileNames) { if (!string.IsNullOrWhiteSpace(text2) && TryMoveLegacyExampleFile(Path.Combine(ExamplesDirectoryPath, text2), text)) { break; } } if (!File.Exists(text)) { File.WriteAllText(text, defaultContent); } } private static bool TryMoveLegacyExampleFile(string legacyPath, string currentPath) { if (!File.Exists(legacyPath)) { return false; } if (File.Exists(currentPath)) { File.Delete(legacyPath); return true; } File.Move(legacyPath, currentPath); return true; } } internal static class FactionIntegration { private static readonly string NativeFactionList = string.Join(", ", Enum.GetNames(typeof(Faction))); private static readonly object Sync = new object(); private static readonly HashSet WarningCache = new HashSet(StringComparer.OrdinalIgnoreCase); private static readonly int HashFaction = StringExtensionMethods.GetStableHashCode("faction"); private static readonly FieldRef BaseAiNviewRef = AccessTools.FieldRefAccess("m_nview"); private static readonly FieldRef BaseAiCharacterRef = AccessTools.FieldRefAccess("m_character"); private static bool _resolved; private static MethodInfo? _tryGetFactionMethod; private static MethodInfo? _baseAiSetupMethod; internal static bool HasFaction(string? configuredFaction) { return !string.IsNullOrWhiteSpace(configuredFaction); } internal static string? Normalize(string? configuredFaction) { string text = (configuredFaction ?? "").Trim(); if (text.Length <= 0) { return null; } return text; } internal static string GetNativeFactionList() { return NativeFactionList; } internal static bool Matches(Faction currentFaction, string? configuredFaction) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) string text = Normalize(configuredFaction); if (text != null && TryResolveFaction(text, out var faction)) { return currentFaction == faction; } return false; } internal static void Apply(Character? character, string? configuredFaction, string context) { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Expected I4, but got Unknown string text = Normalize(configuredFaction); if ((Object)(object)character == (Object)null || text == null) { return; } if (!TryResolveFaction(text, out var faction)) { WarnOnce("invalid-faction:" + text, "Entry '" + context + "' uses invalid faction '" + text + "'. Use a vanilla Character.Faction value or an ExpandWorldFactions custom faction name."); return; } character.m_faction = faction; ZNetView component = ((Component)character).GetComponent(); ZDO val = ((component != null) ? component.GetZDO() : null); if (val != null) { val.Set(HashFaction, text); val.Set(HashFaction, (int)faction, false); } RefreshBaseAi(((Component)character).GetComponent()); } internal static void ApplyFromZdo(BaseAI? baseAi) { //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)baseAi == (Object)null || TryInvokeExpandWorldFactionsSetup(baseAi)) { return; } Character val = BaseAiCharacterRef.Invoke(baseAi); if ((Object)(object)val == (Object)null) { return; } ZNetView obj = BaseAiNviewRef.Invoke(baseAi); ZDO val2 = ((obj != null) ? obj.GetZDO() : null); if (val2 == null) { return; } string @string = val2.GetString(HashFaction, ""); if (!string.IsNullOrWhiteSpace(@string)) { if (TryResolveFaction(@string, out var faction)) { val.m_faction = faction; } return; } int @int = val2.GetInt(HashFaction, 0); if (@int != 0) { val.m_faction = (Faction)@int; } } private static void RefreshBaseAi(BaseAI? baseAi) { if (!((Object)(object)baseAi == (Object)null)) { TryInvokeExpandWorldFactionsSetup(baseAi); } } private static bool TryResolveFaction(string configuredFaction, out Faction faction) { //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected I4, but got Unknown faction = (Faction)0; if (Enum.TryParse(configuredFaction, ignoreCase: true, out faction)) { return true; } lock (Sync) { TryResolveApi(); if (_tryGetFactionMethod == null) { return false; } try { object[] array = new object[2] { configuredFaction, null }; object obj = _tryGetFactionMethod.Invoke(null, array); if (obj is bool && (bool)obj) { obj = array[1]; if (obj is Faction) { Faction val = (Faction)obj; faction = (Faction)(int)val; return true; } } } catch (Exception ex) { WarnOnce("faction-resolve-error", "Failed to resolve ExpandWorldFactions faction names. " + ex.Message); } return false; } } private static bool TryInvokeExpandWorldFactionsSetup(BaseAI baseAi) { lock (Sync) { TryResolveApi(); if (_baseAiSetupMethod == null) { return false; } try { _baseAiSetupMethod.Invoke(null, new object[1] { baseAi }); return true; } catch (Exception ex) { WarnOnce("faction-setup-error", "Failed to refresh ExpandWorldFactions BaseAI state. " + ex.Message); return false; } } } private static void TryResolveApi() { if (_resolved) { return; } _resolved = true; Type type = SafeTypeLookup.FindLoadedType("ExpandWorldData.Factions.FactionManager", "ExpandWorldFactions"); if (type != null) { MethodInfo[] methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public); foreach (MethodInfo methodInfo in methods) { if (!(methodInfo.Name != "TryGetFaction")) { ParameterInfo[] parameters = methodInfo.GetParameters(); if (parameters.Length == 2 && parameters[0].ParameterType == typeof(string) && parameters[1].IsOut) { _tryGetFactionMethod = methodInfo; break; } } } } _baseAiSetupMethod = SafeTypeLookup.FindLoadedType("ExpandWorldData.Factions.BaseAIAwake", "ExpandWorldFactions")?.GetMethod("Setup", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(BaseAI) }, null); } private static void WarnOnce(string key, string message) { if (WarningCache.Add(key)) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)message); } } } internal static class NetworkPayloadSyncSupport { private readonly struct DomainTransportPolicy { public int ChunkSizeBytes { get; } public int PublishedCacheBudgetBytes { get; } public bool UsesLargeRequestLane { get; } public bool SupportsDeltaTransfers { get; } public bool EnableArtifactPrewarm { get; } public float MaxDeltaChangedEntryRatio { get; } public float MaxDeltaCompressedSizeRatio { get; } public int MaxOutboundChunkBytesPerFrame => ChunkSizeBytes * 2; public DomainTransportPolicy(int chunkSizeBytes, int publishedCacheBudgetBytes, bool usesLargeRequestLane, bool supportsDeltaTransfers, bool enableArtifactPrewarm, float maxDeltaChangedEntryRatio, float maxDeltaCompressedSizeRatio) { ChunkSizeBytes = Math.Max(1, chunkSizeBytes); PublishedCacheBudgetBytes = Math.Max(0, publishedCacheBudgetBytes); UsesLargeRequestLane = usesLargeRequestLane; SupportsDeltaTransfers = supportsDeltaTransfers; EnableArtifactPrewarm = enableArtifactPrewarm; MaxDeltaChangedEntryRatio = Math.Max(0f, maxDeltaChangedEntryRatio); MaxDeltaCompressedSizeRatio = Math.Max(0f, maxDeltaCompressedSizeRatio); } } private sealed class PayloadManifest { public string Hash { get; set; } = ""; public int CompressedSize { get; set; } public int ChunkCount { get; set; } public int? EntryCount { get; set; } public bool IsEmpty => Hash.Length == 0; public string Serialize() { if (!IsEmpty) { return string.Format(CultureInfo.InvariantCulture, "v2|{0}|{1}|{2}|{3}", Hash, CompressedSize, ChunkCount, Math.Max(0, EntryCount.GetValueOrDefault())); } return ""; } public static bool TryParse(string? raw, out PayloadManifest manifest) { manifest = new PayloadManifest(); if (string.IsNullOrWhiteSpace(raw)) { return true; } string[] array = (raw ?? "").Split('|'); bool num = array.Length == 4 && string.Equals(array[0], "v1", StringComparison.Ordinal); bool flag = array.Length == 5 && string.Equals(array[0], "v2", StringComparison.Ordinal); if (!num && !flag) { return false; } if (!int.TryParse(array[2], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) || !int.TryParse(array[3], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2)) { return false; } int? entryCount = null; if (flag) { if (!int.TryParse(array[4], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result3)) { return false; } entryCount = Math.Max(0, result3); } manifest = new PayloadManifest { Hash = (array[1] ?? ""), CompressedSize = Math.Max(0, result), ChunkCount = Math.Max(0, result2), EntryCount = entryCount }; return true; } } private sealed class PayloadSignatureBuilder { private readonly StringBuilder _builder = new StringBuilder(); internal void WriteBool(bool value) { _builder.Append(value ? "T;" : "F;"); } internal void WriteInt(int value) { _builder.Append('I').Append(value.ToString(CultureInfo.InvariantCulture)).Append(';'); } internal void WriteFloat(float value) { _builder.Append('R').Append(value.ToString("R", CultureInfo.InvariantCulture)).Append(';'); } internal void WriteString(string value) { string text = value ?? ""; _builder.Append('S').Append(text.Length.ToString(CultureInfo.InvariantCulture)).Append(':') .Append(text) .Append(';'); } internal string ComputeHash() { return ReferenceRefreshSupport.ComputeStableHash(_builder.ToString()); } } private interface IDomainTransport { string DomainKey { get; } bool UsesLargeRequestLane { get; } int ClientRequestPriority { get; } int PublishedCacheBytes { get; } int PublishedPayloadHistoryItemCount { get; } int PublishedTransferArtifactCount { get; } bool HasWaitingRequest(); int CountClientRequestInFlight(bool usesLargeRequestLane); bool TryStartDesiredPayloadRequest(); void UpdatePinnedOutboundTransferReferences(OutboundTransferState? previousState, OutboundTransferState? nextState); void EnqueuePublishedPayloadChunks(long sender, string requestedHash, string baseHash, long requestId); void ReceivePayloadChunk(long sender, string hash, long requestId, int transferKind, string baseHash, int chunkIndex, int chunkCount, int compressedSize, byte[] chunkBytes); bool TryTrimPublishedCacheOnce(); void ClearPinnedCacheReferences(); void ResetState(); } private sealed class DomainTransport : IDomainTransport { public string LastPublishedSignature = ""; public string LastPublishedManifest = ""; public byte[]? PublishedPayloadBytes; public byte[]? PublishedCompressedBytes; public PayloadEntryIndex? PublishedPayloadIndex; public PayloadManifest PublishedPayloadManifest = new PayloadManifest(); public int PublishedPayloadHistoryBytes; public string DesiredManifest = ""; public PayloadManifest DesiredPayloadManifest = new PayloadManifest(); public string InvalidDesiredManifest = ""; public string BlockedManifestHash = ""; public string BlockedManifestReason = ""; public string FullFallbackAttemptedHash = ""; public string AvailableHash = ""; public byte[]? AvailablePayloadBytes; public List? AvailableEntries; public PayloadEntryIndex? AvailablePayloadIndex; public PendingInboundTransfer? PendingTransfer; public long NextRequestId; public bool RequestInFlight; public float RequestStartedAt; public string LastWaitingLogHash = ""; public bool ProcessingInFlight; public string ProcessingHash = ""; public int ProcessingVersion; public int PublishedTransferArtifactBytes; public int PublishedCacheBytes; public int PublishVersion; public bool PublishInFlight; public string PendingPublishedSignature = ""; public DomainTransportMetadata Metadata { get; } public DomainTransportPolicy TransportPolicy { get; } public string DomainKey { get; } public string DisplayName { get; } public string CacheDirectoryName { get; } public bool UsesLargeRequestLane { get; } public int PublishedCacheBudgetBytes { get; } public int ChunkSizeBytes { get; } public bool SupportsDeltaTransfers { get; } public bool EnableArtifactPrewarm { get; } public DomainCodec Codec { get; } public Func, string> SignatureBuilder { get; } public Func EntrySignatureBuilder { get; } public Func, byte[]> Serializer { get; } public Func> Deserializer { get; } public Func KeySelector { get; } public Action ReloadAction { get; } public Dictionary> PublishedPayloadHistory { get; } = new Dictionary>(StringComparer.Ordinal); public LinkedList PublishedPayloadHistoryLru { get; } = new LinkedList(); public Dictionary PublishedTransferArtifacts { get; } = new Dictionary(StringComparer.Ordinal); public LinkedList PublishedTransferArtifactLru { get; } = new LinkedList(); public Dictionary PinnedPayloadHashRefCounts { get; } = new Dictionary(StringComparer.Ordinal); public Dictionary PinnedArtifactKeyRefCounts { get; } = new Dictionary(StringComparer.Ordinal); public HashSet PendingArtifactBuildKeys { get; } = new HashSet(StringComparer.Ordinal); int IDomainTransport.PublishedCacheBytes => PublishedCacheBytes; bool IDomainTransport.UsesLargeRequestLane => UsesLargeRequestLane; int IDomainTransport.ClientRequestPriority => Metadata.ClientRequestPriority; int IDomainTransport.PublishedPayloadHistoryItemCount => PublishedPayloadHistory.Count; int IDomainTransport.PublishedTransferArtifactCount => PublishedTransferArtifacts.Count; public DomainTransport(DomainTransportMetadata metadata, DomainCodec codec) { Metadata = metadata ?? throw new ArgumentNullException("metadata"); TransportPolicy = ResolveTransportPolicy(metadata.TransportProfile); DomainKey = metadata.DomainKey; DisplayName = metadata.DisplayName; CacheDirectoryName = metadata.CacheDirectoryName; UsesLargeRequestLane = TransportPolicy.UsesLargeRequestLane; PublishedCacheBudgetBytes = TransportPolicy.PublishedCacheBudgetBytes; ChunkSizeBytes = TransportPolicy.ChunkSizeBytes; SupportsDeltaTransfers = TransportPolicy.SupportsDeltaTransfers; EnableArtifactPrewarm = TransportPolicy.EnableArtifactPrewarm; Codec = codec; SignatureBuilder = codec.SignatureBuilder; EntrySignatureBuilder = codec.EntrySignatureBuilder; Serializer = codec.Serializer; Deserializer = codec.Deserializer; KeySelector = metadata.KeySelector; ReloadAction = metadata.ApplyPayloadAction; } bool IDomainTransport.HasWaitingRequest() { return HasWaitingRequestLocked(this); } int IDomainTransport.CountClientRequestInFlight(bool usesLargeRequestLane) { return CountClientRequestInFlightLocked(this, usesLargeRequestLane); } bool IDomainTransport.TryStartDesiredPayloadRequest() { return TryStartDesiredPayloadRequestLocked(this); } void IDomainTransport.UpdatePinnedOutboundTransferReferences(OutboundTransferState? previousState, OutboundTransferState? nextState) { UpdatePinnedOutboundTransferReferencesLocked(this, previousState, nextState); } void IDomainTransport.EnqueuePublishedPayloadChunks(long sender, string requestedHash, string baseHash, long requestId) { EnqueuePublishedPayloadChunksLocked(this, sender, requestedHash, baseHash, requestId); } void IDomainTransport.ReceivePayloadChunk(long sender, string hash, long requestId, int transferKind, string baseHash, int chunkIndex, int chunkCount, int compressedSize, byte[] chunkBytes) { ReceivePayloadChunkLocked(this, sender, hash, requestId, transferKind, baseHash, chunkIndex, chunkCount, compressedSize, chunkBytes); } bool IDomainTransport.TryTrimPublishedCacheOnce() { return TryTrimTransportCacheOnceLocked(this); } void IDomainTransport.ClearPinnedCacheReferences() { ClearPinnedCacheReferencesLocked(this); } void IDomainTransport.ResetState() { ResetTransportState(this); } } private readonly struct PreparedPublishPayload { public string Signature { get; } public string PayloadHash { get; } public byte[] PayloadBytes { get; } public int EntryCount { get; } public PreparedPublishPayload(string signature, string payloadHash, byte[] payloadBytes, int entryCount) { Signature = signature ?? ""; PayloadHash = payloadHash ?? ""; PayloadBytes = payloadBytes ?? Array.Empty(); EntryCount = Math.Max(0, entryCount); } } private readonly struct OutboundTransferKey : IEquatable { public long Sender { get; } public string DomainKey { get; } public OutboundTransferKey(long sender, string domainKey) { Sender = sender; DomainKey = domainKey ?? ""; } public bool Equals(OutboundTransferKey other) { if (Sender == other.Sender) { return string.Equals(DomainKey, other.DomainKey, StringComparison.Ordinal); } return false; } public override bool Equals(object? obj) { if (obj is OutboundTransferKey other) { return Equals(other); } return false; } public override int GetHashCode() { return (Sender.GetHashCode() * 397) ^ StringComparer.Ordinal.GetHashCode(DomainKey); } } private sealed class DomainCodec { public EntryTransportSchema Schema { get; } public Func, string> SignatureBuilder { get; } public Func EntrySignatureBuilder { get; } public Func, byte[]> Serializer { get; } public Func> Deserializer { get; } public Func?, List> CloneEntries { get; } public DomainCodec(EntryTransportSchema schema) { Schema = schema ?? throw new ArgumentNullException("schema"); SignatureBuilder = Schema.ComputePayloadSignature; EntrySignatureBuilder = (TEntry entry) => Schema.ComputeEntrySignature(entry, includeRuleId: false, includeResolvedBiomeMask: true); Serializer = Schema.SerializeEntries; Deserializer = Schema.DeserializeEntries; CloneEntries = Schema.CloneEntries; } } private readonly struct EntrySignatureContext { public bool IncludeRuleId { get; } public bool IncludeResolvedBiomeMask { get; } public EntrySignatureContext(bool includeRuleId, bool includeResolvedBiomeMask) { IncludeRuleId = includeRuleId; IncludeResolvedBiomeMask = includeResolvedBiomeMask; } } private sealed class EntryFieldSpec { public Action? SignatureWriter { get; } public Action? PayloadWriter { get; } public Action? PayloadReader { get; } public Action? CopyValue { get; } public EntryFieldSpec(Action? signatureWriter, Action? payloadWriter, Action? payloadReader, Action? copyValue) { SignatureWriter = signatureWriter; PayloadWriter = payloadWriter; PayloadReader = payloadReader; CopyValue = copyValue; } } private sealed class EntryTransportSchema { private readonly EntryFieldSpec[] _fields; public int DtoVersion { get; } public Func CreateEntry { get; } public EntryTransportSchema(int dtoVersion, Func createEntry, params EntryFieldSpec[] fields) { DtoVersion = dtoVersion; CreateEntry = createEntry ?? throw new ArgumentNullException("createEntry"); _fields = fields ?? Array.Empty>(); } public string ComputePayloadSignature(IReadOnlyList entries) { PayloadSignatureBuilder payloadSignatureBuilder = new PayloadSignatureBuilder(); payloadSignatureBuilder.WriteInt(DtoVersion); payloadSignatureBuilder.WriteInt(entries.Count); EntrySignatureContext context = new EntrySignatureContext(includeRuleId: true, includeResolvedBiomeMask: true); foreach (TEntry entry in entries) { WriteSignatureFields(payloadSignatureBuilder, entry, context); } return payloadSignatureBuilder.ComputeHash(); } public string ComputePayloadSignature(IReadOnlyList entries, Func selector) { if (selector == null) { throw new ArgumentNullException("selector"); } PayloadSignatureBuilder payloadSignatureBuilder = new PayloadSignatureBuilder(); payloadSignatureBuilder.WriteInt(DtoVersion); payloadSignatureBuilder.WriteInt(entries.Count); EntrySignatureContext context = new EntrySignatureContext(includeRuleId: true, includeResolvedBiomeMask: true); foreach (TSource entry in entries) { WriteSignatureFields(payloadSignatureBuilder, selector(entry), context); } return payloadSignatureBuilder.ComputeHash(); } public string ComputeEntrySignature(TEntry entry, bool includeRuleId, bool includeResolvedBiomeMask) { PayloadSignatureBuilder payloadSignatureBuilder = new PayloadSignatureBuilder(); WriteSignatureFields(payloadSignatureBuilder, entry, new EntrySignatureContext(includeRuleId, includeResolvedBiomeMask)); return payloadSignatureBuilder.ComputeHash(); } public byte[] SerializeEntries(List entries) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown ZPackage val = new ZPackage(); val.Write(DtoVersion); val.Write(entries.Count); foreach (TEntry entry in entries) { WritePayloadFields(val, entry); } return val.GetArray(); } public List DeserializeEntries(byte[] payloadBytes) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown ZPackage val = new ZPackage(payloadBytes); int num = val.ReadInt(); if (num != DtoVersion) { throw new InvalidDataException($"Unsupported DTO version '{num}'."); } int num2 = val.ReadInt(); List list = new List(num2); for (int i = 0; i < num2; i++) { TEntry val2 = CreateEntry(); ReadPayloadFields(val, val2); list.Add(val2); } return list; } public List CloneEntries(List? entries) { if (entries == null || entries.Count == 0) { return new List(); } List list = new List(entries.Count); foreach (TEntry entry in entries) { list.Add(CloneEntry(entry)); } return list; } private TEntry CloneEntry(TEntry source) { TEntry val = CreateEntry(); EntryFieldSpec[] fields = _fields; for (int i = 0; i < fields.Length; i++) { fields[i].CopyValue?.Invoke(source, val); } return val; } private void WriteSignatureFields(PayloadSignatureBuilder builder, TEntry entry, EntrySignatureContext context) { EntryFieldSpec[] fields = _fields; for (int i = 0; i < fields.Length; i++) { fields[i].SignatureWriter?.Invoke(builder, entry, context); } } private void WritePayloadFields(ZPackage package, TEntry entry) { EntryFieldSpec[] fields = _fields; for (int i = 0; i < fields.Length; i++) { fields[i].PayloadWriter?.Invoke(package, entry); } } private void ReadPayloadFields(ZPackage package, TEntry entry) { EntryFieldSpec[] fields = _fields; for (int i = 0; i < fields.Length; i++) { fields[i].PayloadReader?.Invoke(package, entry); } } } private sealed class PendingInboundTransfer { public long ExpectedSender { get; set; } public long RequestId { get; set; } public string Hash { get; set; } = ""; public bool IsFullFallbackRequest { get; set; } public string RequestedBaseHash { get; set; } = ""; public float LastProgressAt { get; set; } public int TransferKind { get; set; } = -1; public string BaseHash { get; set; } = ""; public int ChunkSizeBytes { get; set; } public int ChunkCount { get; set; } public int ExpectedCompressedSize { get; set; } = -1; public byte[] CompressedBuffer { get; set; } = Array.Empty(); public bool[] ReceivedChunks { get; set; } = Array.Empty(); public int ReceivedChunkCount { get; set; } } private sealed class PendingReloadAction { public int RoleEpoch { get; set; } public string DomainKey { get; set; } = ""; public Action Action { get; set; } } private sealed class PendingPayloadProcessingJob { public int RoleEpoch { get; set; } public Action Action { get; set; } } private sealed class PendingMainThreadPayloadCommit { public int RoleEpoch { get; set; } public Action Action { get; set; } } private sealed class PayloadEntryIndex { public List OrderedKeys { get; } = new List(); public Dictionary EntriesByKey { get; } = new Dictionary(StringComparer.OrdinalIgnoreCase); public Dictionary EntrySignaturesByKey { get; } = new Dictionary(StringComparer.OrdinalIgnoreCase); } private sealed class PublishedPayloadHistoryEntry { public string Hash { get; set; } = ""; public byte[] PayloadBytes { get; set; } = Array.Empty(); public PayloadEntryIndex? PayloadIndex { get; set; } public int EstimatedBytes { get; set; } public LinkedListNode? LruNode { get; set; } } private sealed class TransferArtifact { public string CacheKey { get; set; } = ""; public int TransferKind { get; set; } public string BaseHash { get; set; } = ""; public string TargetHash { get; set; } = ""; public byte[] CompressedBytes { get; set; } = Array.Empty(); public int ChunkSizeBytes { get; set; } public int ChunkCount { get; set; } public int EstimatedBytes { get; set; } public LinkedListNode? LruNode { get; set; } } private sealed class OutboundChunkMessage { public long Sender { get; set; } public string DomainKey { get; set; } = ""; public string Hash { get; set; } = ""; public long RequestId { get; set; } public int TransferKind { get; set; } public string BaseHash { get; set; } = ""; public int ChunkIndex { get; set; } public int ChunkCount { get; set; } public int CompressedSize { get; set; } } private sealed class OutboundTransferState { public int RoleEpoch { get; set; } public string Hash { get; set; } = ""; public long RequestId { get; set; } public TransferArtifact Artifact { get; set; } public int NextChunkIndex { get; set; } public bool IsQueued { get; set; } public float LastRequestedAt { get; set; } } private sealed class PreparedOutboundChunk { public OutboundTransferKey Key { get; set; } public int RoleEpoch { get; set; } public long RequestId { get; set; } public OutboundChunkMessage Message { get; set; } public byte[] SourceBytes { get; set; } = Array.Empty(); public int ChunkOffset { get; set; } public int ChunkLength { get; set; } } private sealed class ValueCodec where TValue : class { public Action SignatureWriter { get; } public Action PayloadWriter { get; } public Func PayloadReader { get; } public Func CloneValue { get; } public ValueCodec(Action signatureWriter, Action payloadWriter, Func payloadReader, Func cloneValue) { SignatureWriter = signatureWriter ?? throw new ArgumentNullException("signatureWriter"); PayloadWriter = payloadWriter ?? throw new ArgumentNullException("payloadWriter"); PayloadReader = payloadReader ?? throw new ArgumentNullException("payloadReader"); CloneValue = cloneValue ?? throw new ArgumentNullException("cloneValue"); } } private const string PayloadRequestRpc = "DropNSpawn Payload Request"; private const string PayloadChunkRpc = "DropNSpawn Payload Chunk"; private const int DefaultChunkSizeBytes = 240000; private const int MaxConcurrentSmallClientRequests = 2; private const int MaxConcurrentLargeClientRequests = 1; private const int MaxPayloadProcessingWorkers = 3; private const int MaxArtifactPrewarmWorkers = 1; private const float DefaultMaxDeltaChangedEntryRatio = 0.5f; private const float DefaultMaxDeltaCompressedSizeRatio = 0.85f; private const float RequestRetrySeconds = 5f; private const int TotalPublishedCacheBudgetBytes = 67108864; private const int PublishedCacheTrimLowWatermarkPercent = 85; private const int DeltaDtoVersion = 1; private const int FullTransferKind = 0; private const int DeltaTransferKind = 1; private static readonly object Sync = new object(); private static readonly FieldInfo? ZPackageWriterField = typeof(ZPackage).GetField("m_writer", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly DomainTransport ObjectTransport = new DomainTransport(ObjectDropManager.TransportMetadata, ObjectCodec); private static readonly DomainTransport CharacterTransport = new DomainTransport(CharacterDropManager.TransportMetadata, CharacterCodec); private static readonly DomainTransport SpawnerTransport = new DomainTransport(SpawnerManager.TransportMetadata, SpawnerCodec); private static readonly DomainTransport LocationTransport = new DomainTransport(LocationManager.TransportMetadata, LocationCodec); private static readonly DomainTransport SpawnSystemTransport = new DomainTransport(SpawnSystemManager.TransportMetadata, SpawnSystemCodec); private static readonly Dictionary TransportsByDomainKey = new Dictionary(StringComparer.Ordinal) { [ObjectTransport.DomainKey] = ObjectTransport, [CharacterTransport.DomainKey] = CharacterTransport, [SpawnerTransport.DomainKey] = SpawnerTransport, [LocationTransport.DomainKey] = LocationTransport, [SpawnSystemTransport.DomainKey] = SpawnSystemTransport }; private static readonly IDomainTransport[] AllTransports = DomainRegistry.Transports.Select((DomainTransportMetadata metadata) => TransportsByDomainKey[metadata.DomainKey]).ToArray(); private static readonly IDomainTransport[] SmallLaneRequestPriorityTransports = (from transport in AllTransports where !transport.UsesLargeRequestLane orderby transport.ClientRequestPriority descending select transport).ToArray(); private static readonly IDomainTransport[] LargeLaneRequestPriorityTransports = (from transport in AllTransports where transport.UsesLargeRequestLane orderby transport.ClientRequestPriority descending select transport).ToArray(); private static MonoBehaviour? _host; private static ZRoutedRpc? _registeredRpc; private static readonly RingBufferQueue PendingOutboundTransferKeys = new RingBufferQueue(); private static readonly Dictionary ActiveOutboundTransfers = new Dictionary(); private static readonly RingBufferQueue PendingCriticalPayloadProcessingJobs = new RingBufferQueue(); private static readonly RingBufferQueue PendingDeltaArtifactPrewarmJobs = new RingBufferQueue(); private static readonly RingBufferQueue PendingCachePersistenceJobs = new RingBufferQueue(); private static readonly RingBufferQueue PendingMainThreadPayloadCommits = new RingBufferQueue(); private static readonly RingBufferQueue PendingReloadActions = new RingBufferQueue(); private static readonly HashSet PendingReloadDomainKeys = new HashSet(StringComparer.Ordinal); private static int _outboundBudgetFrame = int.MinValue; private static int _outboundBytesSentThisFrame; private static int _payloadProcessingWorkersRunning; private static int _networkRoleEpoch; private static DomainCodec? _objectCodec; private static DomainCodec? _characterCodec; private static DomainCodec? _spawnerCodec; private static DomainCodec? _locationCodec; private static DomainCodec? _spawnSystemCodec; private static readonly FieldRef RoutedRpcIdRef = AccessTools.FieldRefAccess("m_id"); private static ValueCodec _conditionsValueCodec; private static ValueCodec _characterDropValueCodec; private static ValueCodec _despawnRefundValueCodec; private static ValueCodec _despawnValueCodec; private static ValueCodec _bossTamedPressureValueCodec; private static ValueCodec _dropTableValueCodec; private static ValueCodec _damageableDropTableValueCodec; private static ValueCodec _pickableValueCodec; private static ValueCodec _pickableItemValueCodec; private static ValueCodec _fishValueCodec; private static ValueCodec _destructibleValueCodec; private static ValueCodec _spawnAreaValueCodec; private static ValueCodec _creatureSpawnerValueCodec; private static ValueCodec _offeringBowlValueCodec; private static ValueCodec _itemStandValueCodec; private static ValueCodec _vegvisirValueCodec; private static ValueCodec _runestoneValueCodec; private static ValueCodec _runestoneGlobalPinsValueCodec; private static ValueCodec _spawnSystemSpawnValueCodec; private static ValueCodec _spawnSystemConditionsValueCodec; private static ValueCodec _spawnSystemModifiersValueCodec; internal static int CurrentAuthorityEpoch => Volatile.Read(ref _networkRoleEpoch); private static DomainCodec ObjectCodec => _objectCodec ?? (_objectCodec = new DomainCodec(CreateObjectEntrySchema())); private static DomainCodec CharacterCodec => _characterCodec ?? (_characterCodec = new DomainCodec(CreateCharacterEntrySchema())); private static DomainCodec SpawnerCodec => _spawnerCodec ?? (_spawnerCodec = new DomainCodec(CreateSpawnerEntrySchema())); private static DomainCodec LocationCodec => _locationCodec ?? (_locationCodec = new DomainCodec(CreateLocationEntrySchema())); private static DomainCodec SpawnSystemCodec => _spawnSystemCodec ?? (_spawnSystemCodec = new DomainCodec(CreateSpawnSystemEntrySchema())); private static ValueCodec ConditionsValueCodec => _conditionsValueCodec ?? (_conditionsValueCodec = new ValueCodec(delegate(PayloadSignatureBuilder builder, ConditionsDefinition definition, EntrySignatureContext context) { WriteConditionsDefinition(builder, definition, context.IncludeResolvedBiomeMask); }, WriteConditionsDefinition, ReadConditionsDefinition, (ConditionsDefinition value) => ConfigurationEntryCloneSupport.CloneConditions(value))); private static ValueCodec CharacterDropValueCodec => _characterDropValueCodec ?? (_characterDropValueCodec = new ValueCodec(delegate(PayloadSignatureBuilder builder, CharacterDropDefinition definition, EntrySignatureContext _) { WriteCharacterDropDefinition(builder, definition); }, WriteCharacterDropDefinition, ReadCharacterDropDefinition, (CharacterDropDefinition value) => ConfigurationEntryCloneSupport.CloneCharacterDropDefinition(value))); private static ValueCodec DespawnRefundValueCodec => _despawnRefundValueCodec ?? (_despawnRefundValueCodec = new ValueCodec(delegate(PayloadSignatureBuilder builder, DespawnRefundEntryDefinition definition, EntrySignatureContext _) { WriteDespawnRefundEntryDefinition(builder, definition); }, WriteDespawnRefundEntryDefinition, ReadDespawnRefundEntryDefinition, ConfigurationEntryCloneSupport.CloneDespawnRefundEntryDefinition)); private static ValueCodec DespawnValueCodec => _despawnValueCodec ?? (_despawnValueCodec = new ValueCodec(delegate(PayloadSignatureBuilder builder, DespawnDefinition definition, EntrySignatureContext _) { WriteDespawnDefinition(builder, definition); }, WriteDespawnDefinition, ReadDespawnDefinition, (DespawnDefinition value) => ConfigurationEntryCloneSupport.CloneDespawnDefinition(value))); private static ValueCodec BossTamedPressureValueCodec => _bossTamedPressureValueCodec ?? (_bossTamedPressureValueCodec = new ValueCodec(delegate(PayloadSignatureBuilder builder, BossTamedPressureDefinition definition, EntrySignatureContext _) { WriteBossTamedPressureDefinition(builder, definition); }, WriteBossTamedPressureDefinition, ReadBossTamedPressureDefinition, (BossTamedPressureDefinition value) => ConfigurationEntryCloneSupport.CloneBossTamedPressureDefinition(value))); private static ValueCodec DropTableValueCodec => _dropTableValueCodec ?? (_dropTableValueCodec = new ValueCodec(delegate(PayloadSignatureBuilder builder, DropTableDefinition definition, EntrySignatureContext _) { WriteDropTableDefinition(builder, definition); }, WriteDropTableDefinition, ReadDropTableDefinition, (DropTableDefinition value) => ConfigurationEntryCloneSupport.CloneDropTableDefinition(value))); private static ValueCodec DamageableDropTableValueCodec => _damageableDropTableValueCodec ?? (_damageableDropTableValueCodec = new ValueCodec(delegate(PayloadSignatureBuilder builder, DamageableDropTableDefinition definition, EntrySignatureContext _) { WriteDamageableDropTableDefinition(builder, definition); }, WriteDamageableDropTableDefinition, ReadDamageableDropTableDefinition, (DamageableDropTableDefinition value) => ConfigurationEntryCloneSupport.CloneDamageableDropTableDefinition(value))); private static ValueCodec PickableValueCodec => _pickableValueCodec ?? (_pickableValueCodec = new ValueCodec(delegate(PayloadSignatureBuilder builder, PickableDefinition definition, EntrySignatureContext _) { WritePickableDefinition(builder, definition); }, WritePickableDefinition, ReadPickableDefinition, (PickableDefinition value) => ConfigurationEntryCloneSupport.ClonePickableDefinition(value))); private static ValueCodec PickableItemValueCodec => _pickableItemValueCodec ?? (_pickableItemValueCodec = new ValueCodec(delegate(PayloadSignatureBuilder builder, PickableItemDefinition definition, EntrySignatureContext _) { WritePickableItemDefinition(builder, definition); }, WritePickableItemDefinition, ReadPickableItemDefinition, (PickableItemDefinition value) => ConfigurationEntryCloneSupport.ClonePickableItemDefinition(value))); private static ValueCodec FishValueCodec => _fishValueCodec ?? (_fishValueCodec = new ValueCodec(delegate(PayloadSignatureBuilder builder, FishDefinition definition, EntrySignatureContext _) { WriteFishDefinition(builder, definition); }, WriteFishDefinition, ReadFishDefinition, (FishDefinition value) => ConfigurationEntryCloneSupport.CloneFishDefinition(value))); private static ValueCodec DestructibleValueCodec => _destructibleValueCodec ?? (_destructibleValueCodec = new ValueCodec(delegate(PayloadSignatureBuilder builder, DestructibleDefinition definition, EntrySignatureContext _) { WriteDestructibleDefinition(builder, definition); }, WriteDestructibleDefinition, ReadDestructibleDefinition, (DestructibleDefinition value) => ConfigurationEntryCloneSupport.CloneDestructibleDefinition(value))); private static ValueCodec SpawnAreaValueCodec => _spawnAreaValueCodec ?? (_spawnAreaValueCodec = new ValueCodec(delegate(PayloadSignatureBuilder builder, SpawnAreaDefinition definition, EntrySignatureContext _) { WriteSpawnerSyncSpawnAreaDefinition(builder, definition); }, WriteSpawnerSyncSpawnAreaDefinition, ReadSpawnerSyncSpawnAreaDefinition, (SpawnAreaDefinition value) => ConfigurationEntryCloneSupport.CloneSpawnAreaDefinition(value))); private static ValueCodec CreatureSpawnerValueCodec => _creatureSpawnerValueCodec ?? (_creatureSpawnerValueCodec = new ValueCodec(delegate(PayloadSignatureBuilder builder, CreatureSpawnerDefinition definition, EntrySignatureContext _) { WriteSpawnerSyncCreatureSpawnerDefinition(builder, definition); }, WriteSpawnerSyncCreatureSpawnerDefinition, ReadSpawnerSyncCreatureSpawnerDefinition, (CreatureSpawnerDefinition value) => ConfigurationEntryCloneSupport.CloneCreatureSpawnerDefinition(value))); private static ValueCodec OfferingBowlValueCodec => _offeringBowlValueCodec ?? (_offeringBowlValueCodec = new ValueCodec(delegate(PayloadSignatureBuilder builder, LocationOfferingBowlDefinition definition, EntrySignatureContext _) { WriteOfferingBowlDefinition(builder, definition); }, WriteOfferingBowlDefinition, ReadOfferingBowlDefinition, (LocationOfferingBowlDefinition value) => ConfigurationEntryCloneSupport.CloneLocationOfferingBowlDefinition(value))); private static ValueCodec ItemStandValueCodec => _itemStandValueCodec ?? (_itemStandValueCodec = new ValueCodec(delegate(PayloadSignatureBuilder builder, LocationItemStandDefinition definition, EntrySignatureContext _) { WriteItemStandDefinition(builder, definition); }, WriteItemStandDefinition, ReadItemStandDefinition, ConfigurationEntryCloneSupport.CloneLocationItemStandDefinition)); private static ValueCodec VegvisirValueCodec => _vegvisirValueCodec ?? (_vegvisirValueCodec = new ValueCodec(delegate(PayloadSignatureBuilder builder, LocationVegvisirDefinition definition, EntrySignatureContext _) { WriteVegvisirDefinition(builder, definition); }, WriteVegvisirDefinition, ReadVegvisirDefinition, ConfigurationEntryCloneSupport.CloneLocationVegvisirDefinition)); private static ValueCodec RunestoneValueCodec => _runestoneValueCodec ?? (_runestoneValueCodec = new ValueCodec(delegate(PayloadSignatureBuilder builder, LocationRunestoneDefinition definition, EntrySignatureContext _) { WriteRunestoneDefinition(builder, definition); }, WriteRunestoneDefinition, ReadRunestoneDefinition, ConfigurationEntryCloneSupport.CloneLocationRunestoneDefinition)); private static ValueCodec RunestoneGlobalPinsValueCodec => _runestoneGlobalPinsValueCodec ?? (_runestoneGlobalPinsValueCodec = new ValueCodec(delegate(PayloadSignatureBuilder builder, LocationRunestoneGlobalPinsDefinition definition, EntrySignatureContext _) { WriteRunestoneGlobalPinsDefinition(builder, definition); }, WriteRunestoneGlobalPinsDefinition, ReadRunestoneGlobalPinsDefinition, ConfigurationEntryCloneSupport.CloneLocationRunestoneGlobalPinsDefinition)); private static ValueCodec SpawnSystemSpawnValueCodec => _spawnSystemSpawnValueCodec ?? (_spawnSystemSpawnValueCodec = new ValueCodec(delegate(PayloadSignatureBuilder builder, SpawnSystemSpawnDefinition definition, EntrySignatureContext _) { WriteSpawnSystemSpawnDefinition(builder, definition); }, WriteSpawnSystemSpawnDefinition, ReadSpawnSystemSpawnDefinition, (SpawnSystemSpawnDefinition value) => ConfigurationEntryCloneSupport.CloneSpawnSystemSpawnDefinition(value))); private static ValueCodec SpawnSystemConditionsValueCodec => _spawnSystemConditionsValueCodec ?? (_spawnSystemConditionsValueCodec = new ValueCodec(delegate(PayloadSignatureBuilder builder, SpawnSystemConditionsDefinition definition, EntrySignatureContext context) { WriteSpawnSystemConditionsDefinition(builder, definition, context.IncludeResolvedBiomeMask); }, WriteSpawnSystemConditionsDefinition, ReadSpawnSystemConditionsDefinition, (SpawnSystemConditionsDefinition value) => ConfigurationEntryCloneSupport.CloneSpawnSystemConditionsDefinition(value))); private static ValueCodec SpawnSystemModifiersValueCodec => _spawnSystemModifiersValueCodec ?? (_spawnSystemModifiersValueCodec = new ValueCodec(delegate(PayloadSignatureBuilder builder, SpawnSystemModifiersDefinition definition, EntrySignatureContext _) { WriteSpawnSystemModifiersDefinition(builder, definition); }, WriteSpawnSystemModifiersDefinition, ReadSpawnSystemModifiersDefinition, (SpawnSystemModifiersDefinition value) => ConfigurationEntryCloneSupport.CloneSpawnSystemModifiersDefinition(value))); private static DomainTransportPolicy ResolveTransportPolicy(DomainTransportProfile profile) { return profile switch { DomainTransportProfile.SmallConfig => new DomainTransportPolicy(240000, 8388608, usesLargeRequestLane: false, supportsDeltaTransfers: true, enableArtifactPrewarm: false, 0.5f, 0.85f), DomainTransportProfile.MediumConfig => new DomainTransportPolicy(240000, 12582912, usesLargeRequestLane: false, supportsDeltaTransfers: true, enableArtifactPrewarm: false, 0.5f, 0.85f), DomainTransportProfile.LargeConfig => new DomainTransportPolicy(240000, 25165824, usesLargeRequestLane: true, supportsDeltaTransfers: true, enableArtifactPrewarm: false, 0.5f, 0.85f), DomainTransportProfile.LargeWithArtifacts => new DomainTransportPolicy(240000, 25165824, usesLargeRequestLane: true, supportsDeltaTransfers: true, enableArtifactPrewarm: true, 0.5f, 0.85f), _ => new DomainTransportPolicy(240000, 8388608, usesLargeRequestLane: false, supportsDeltaTransfers: true, enableArtifactPrewarm: false, 0.5f, 0.85f), }; } internal static void Initialize(MonoBehaviour host) { lock (Sync) { _host = host; EnsureRpcRegisteredLocked(); } } internal static void Shutdown() { lock (Sync) { _host = null; _registeredRpc = null; AdvanceRoleEpochAndResetWorkQueuesLocked(); _payloadProcessingWorkersRunning = 0; foreach (IDomainTransport value in TransportsByDomainKey.Values) { value.ResetState(); } } } internal static bool HasPendingWork() { lock (Sync) { return PendingMainThreadPayloadCommits.Count > 0 || PendingReloadActions.Count > 0 || PendingOutboundTransferKeys.Count > 0 || HasPendingClientRequestWorkLocked(); } } internal static bool ProcessPendingWork(float deadline) { PreparedOutboundChunk preparedChunk = null; Action action = null; int num = -1; bool result = false; lock (Sync) { EnsureRpcRegisteredLocked(); int frameCount = Time.frameCount; if (_outboundBudgetFrame != frameCount) { _outboundBudgetFrame = frameCount; _outboundBytesSentThisFrame = 0; } PendingReloadAction pendingReload; if (TryDequeueCurrentMainThreadPayloadCommitLocked(out action)) { num = _networkRoleEpoch; } else if (TryDequeueCurrentReloadActionLocked(out pendingReload)) { action = pendingReload.Action; num = pendingReload.RoleEpoch; } else if (TryStartNextWaitingPayloadRequestLocked()) { result = true; } else if (ZRoutedRpc.instance != null && Time.realtimeSinceStartup < deadline) { TryPrepareOutboundChunkForSendLocked(out preparedChunk); } } if (action != null) { lock (Sync) { if (num != _networkRoleEpoch) { return true; } } action(); return true; } if (preparedChunk != null) { bool flag; lock (Sync) { flag = preparedChunk.RoleEpoch == _networkRoleEpoch && DropNSpawnPlugin.IsSourceOfTruth; } bool flag2 = flag && SendOutboundChunk(preparedChunk); lock (Sync) { FinalizePreparedOutboundChunkLocked(preparedChunk, flag2); return flag2; } } return result; } internal static void HandleSourceOfTruthChanged(bool isSourceOfTruth) { lock (Sync) { EnsureRpcRegisteredLocked(); AdvanceRoleEpochAndResetWorkQueuesLocked(); foreach (IDomainTransport value in TransportsByDomainKey.Values) { value.ResetState(); } } } internal static bool IsPayloadCurrent(DomainDescriptor domain, string configurationSignature) { return IsPublishedPayloadCurrent(GetTransport(domain), configurationSignature); } internal static void PublishPayloadAsync(DomainDescriptor domain, List entries, string? knownSignature, Action applyManifest) { QueuePublishPayload(GetTransport(domain), entries, knownSignature, applyManifest); } internal static string PublishPayload(DomainDescriptor domain, List entries, string? knownSignature = null) { return PublishPayload(GetTransport(domain), entries, knownSignature); } internal static List CloneEntries(DomainDescriptor domain, List? entries) { return GetTransport(domain).Codec.CloneEntries(entries); } internal static bool TryGetEntries(DomainDescriptor domain, string manifestRaw, out List entries, out string payloadToken) { return TryGetEntries(GetTransport(domain), manifestRaw, out entries, out payloadToken); } internal static void HandleManifestChanged(DomainDescriptor domain, string manifestRaw) { HandleManifestChanged(GetTransport(domain), manifestRaw); } private static DomainTransport GetTransport(DomainDescriptor domain) { if (TransportsByDomainKey.TryGetValue(domain.DomainKey, out IDomainTransport value) && value is DomainTransport result) { return result; } throw new InvalidOperationException("No synchronized transport is registered for domain '" + domain.DomainKey + "'."); } private static void ResetTransportState(DomainTransport transport) { transport.LastPublishedSignature = ""; transport.LastPublishedManifest = ""; transport.PublishedPayloadBytes = null; transport.PublishedCompressedBytes = null; transport.PublishedPayloadIndex = null; transport.PublishedPayloadManifest = new PayloadManifest(); ClearPublishedPayloadHistoryLocked(transport); ClearPublishedTransferArtifactsLocked(transport); ClearPinnedCacheReferencesLocked(transport); transport.PendingArtifactBuildKeys.Clear(); transport.PublishVersion = 0; transport.PublishInFlight = false; transport.PendingPublishedSignature = ""; ResetClientState(transport); transport.Metadata.Hooks.OnTransportStateReset(); } private static void ResetClientState(DomainTransport transport) { transport.DesiredManifest = ""; transport.DesiredPayloadManifest = new PayloadManifest(); transport.InvalidDesiredManifest = ""; ClearBlockedManifestLocked(transport); transport.FullFallbackAttemptedHash = ""; transport.AvailableHash = ""; transport.AvailablePayloadBytes = null; transport.AvailableEntries = null; transport.AvailablePayloadIndex = null; transport.PendingTransfer = null; transport.NextRequestId = 0L; transport.RequestInFlight = false; transport.RequestStartedAt = 0f; transport.LastWaitingLogHash = ""; transport.ProcessingInFlight = false; transport.ProcessingHash = ""; transport.ProcessingVersion++; } private static bool IsPublishedPayloadCurrent(DomainTransport transport, string configurationSignature) { lock (Sync) { return IsPublishedPayloadCurrentLocked(transport, configurationSignature); } } private static bool IsPublishedPayloadCurrentLocked(DomainTransport transport, string configurationSignature) { if (!string.Equals(transport.LastPublishedSignature, configurationSignature, StringComparison.Ordinal) || transport.PublishedPayloadBytes == null || transport.PublishedCompressedBytes == null || transport.LastPublishedManifest.Length <= 0) { if (transport.PublishInFlight && configurationSignature.Length > 0) { return string.Equals(transport.PendingPublishedSignature, configurationSignature, StringComparison.Ordinal); } return false; } return true; } private static PreparedPublishPayload PreparePublishPayloadLocked(DomainTransport transport, List? entries, string? knownSignature = null) { List list = entries ?? new List(); byte[] array = transport.Serializer(list); string payloadHash = ComputeSha256(array); return new PreparedPublishPayload((!string.IsNullOrWhiteSpace(knownSignature)) ? knownSignature : transport.SignatureBuilder(list), payloadHash, array, list.Count); } private static bool TryReusePublishedManifestForSignatureLocked(DomainTransport transport, string? signature, out string manifest) { manifest = ""; if (string.IsNullOrWhiteSpace(signature)) { return false; } if (!string.Equals(transport.LastPublishedSignature, signature, StringComparison.Ordinal) || transport.PublishedPayloadBytes == null || transport.PublishedCompressedBytes == null || transport.LastPublishedManifest.Length == 0) { return false; } manifest = transport.LastPublishedManifest; return true; } private static bool IsPublishPendingForSignatureLocked(DomainTransport transport, string? signature) { if (transport.PublishInFlight && !string.IsNullOrWhiteSpace(signature)) { return string.Equals(transport.PendingPublishedSignature, signature, StringComparison.Ordinal); } return false; } private static bool TryReusePublishedManifestForHashLocked(DomainTransport transport, string payloadHash, string payloadSignature, out string manifest) { manifest = ""; if (!string.Equals(transport.PublishedPayloadManifest.Hash, payloadHash, StringComparison.Ordinal) || transport.PublishedPayloadBytes == null || transport.PublishedCompressedBytes == null || transport.LastPublishedManifest.Length == 0) { return false; } transport.LastPublishedSignature = payloadSignature; manifest = transport.LastPublishedManifest; return true; } private static bool TryGetAvailableEntriesLocked(DomainTransport transport, out List entries) { if (transport.AvailablePayloadBytes == null) { entries = new List(); return false; } try { if (transport.AvailableEntries != null) { entries = transport.Codec.CloneEntries(transport.AvailableEntries); return true; } List list = (transport.AvailableEntries = transport.Deserializer(transport.AvailablePayloadBytes) ?? new List()); if (!string.IsNullOrWhiteSpace(transport.AvailableHash)) { BuildPayloadIndex(transport, list, transport.AvailableHash, out PayloadEntryIndex payloadIndex); transport.AvailablePayloadIndex = payloadIndex; } entries = transport.Codec.CloneEntries(list); return true; } catch (Exception ex) { string availableHash = transport.AvailableHash; entries = new List(); string reason = "source=lazy_deserialize error=" + ex.Message; InvalidateMalformedAvailablePayloadLocked(transport, availableHash, reason, ex); return false; } } private static void QueuePublishPayload(DomainTransport transport, List entries, string? knownSignature, Action applyManifest) { DomainTransport transport2 = transport; Action applyManifest2 = applyManifest; bool flag = false; string manifest = ""; int publishVersion = 0; int roleEpoch = 0; PreparedPublishPayload preparedPayload = default(PreparedPublishPayload); lock (Sync) { EnsureRpcRegisteredLocked(); if (TryReusePublishedManifestForSignatureLocked(transport2, knownSignature, out manifest)) { flag = true; } else { if (IsPublishPendingForSignatureLocked(transport2, knownSignature)) { return; } try { preparedPayload = PreparePublishPayloadLocked(transport2, entries, knownSignature); } catch (Exception arg) { DropNSpawnPlugin.DropNSpawnLogger.LogError((object)$"Failed to capture synchronized {transport2.DisplayName} payload publish snapshot. {arg}"); return; } if (TryReusePublishedManifestForSignatureLocked(transport2, preparedPayload.Signature, out manifest)) { flag = true; } else { if (IsPublishPendingForSignatureLocked(transport2, preparedPayload.Signature)) { return; } if (TryReusePublishedManifestForHashLocked(transport2, preparedPayload.PayloadHash, preparedPayload.Signature, out manifest)) { flag = true; } else { publishVersion = ++transport2.PublishVersion; roleEpoch = _networkRoleEpoch; transport2.PublishInFlight = true; transport2.PendingPublishedSignature = preparedPayload.Signature; string previousHashSnapshot = transport2.PublishedPayloadManifest.Hash; byte[] previousPayloadBytesSnapshot = transport2.PublishedPayloadBytes; PayloadEntryIndex previousPayloadIndexSnapshot = transport2.PublishedPayloadIndex; QueueCriticalPayloadProcessingJobLocked(delegate { try { byte[] compressedPayload = CompressBytes(preparedPayload.PayloadBytes); PayloadEntryIndex preparedPublishedPayloadIndex = null; TransferArtifact primaryDeltaArtifact = null; if (previousHashSnapshot.Length > 0 && !string.Equals(previousHashSnapshot, preparedPayload.PayloadHash, StringComparison.Ordinal)) { TryBuildPrimaryDeltaArtifact(transport2, previousHashSnapshot, previousPayloadBytesSnapshot, previousPayloadIndexSnapshot, preparedPayload.PayloadHash, preparedPayload.PayloadBytes, null, compressedPayload, out preparedPublishedPayloadIndex, out primaryDeltaArtifact); } PayloadManifest manifest2 = new PayloadManifest { Hash = preparedPayload.PayloadHash, CompressedSize = compressedPayload.Length, ChunkCount = Math.Max(1, (int)Math.Ceiling((double)compressedPayload.Length / (double)transport2.ChunkSizeBytes)), EntryCount = preparedPayload.EntryCount }; QueueMainThreadPayloadCommitLocked(delegate { bool flag2 = false; string manifest3 = ""; lock (Sync) { if (roleEpoch != _networkRoleEpoch || publishVersion != transport2.PublishVersion) { return; } transport2.PublishInFlight = false; transport2.PendingPublishedSignature = ""; if (TryReusePublishedManifestForHashLocked(transport2, preparedPayload.PayloadHash, preparedPayload.Signature, out manifest3)) { flag2 = true; } else { string hash = transport2.PublishedPayloadManifest.Hash; RememberPublishedPayloadLocked(transport2, hash, transport2.PublishedPayloadBytes, transport2.PublishedPayloadIndex); transport2.LastPublishedSignature = preparedPayload.Signature; transport2.LastPublishedManifest = manifest2.Serialize(); transport2.PublishedPayloadBytes = preparedPayload.PayloadBytes; transport2.PublishedCompressedBytes = compressedPayload; transport2.PublishedPayloadIndex = preparedPublishedPayloadIndex; transport2.PublishedPayloadManifest = manifest2; ClearPublishedTransferArtifactsLocked(transport2); EnsureFullTransferArtifactLocked(transport2, preparedPayload.PayloadHash); bool flag3 = false; if (primaryDeltaArtifact != null && string.Equals(hash, previousHashSnapshot, StringComparison.Ordinal) && !transport2.PublishedTransferArtifacts.ContainsKey(primaryDeltaArtifact.CacheKey)) { StoreTransferArtifactLocked(transport2, primaryDeltaArtifact); flag3 = true; } TrimTransportCachesLocked(transport2); TrimAllPublishedCachesLocked(); if (hash.Length > 0 && !string.Equals(hash, preparedPayload.PayloadHash, StringComparison.Ordinal) && !flag3 && !string.Equals(hash, previousHashSnapshot, StringComparison.Ordinal)) { QueueTransferArtifactBuildIfNeededLocked(transport2, preparedPayload.PayloadHash, hash); } manifest3 = transport2.LastPublishedManifest; flag2 = true; } } if (flag2) { applyManifest2(manifest3); } }, roleEpoch); } catch (Exception ex2) { Exception ex3 = ex2; Exception ex = ex3; QueueMainThreadPayloadCommitLocked(delegate { lock (Sync) { if (roleEpoch != _networkRoleEpoch || publishVersion != transport2.PublishVersion) { return; } transport2.PublishInFlight = false; transport2.PendingPublishedSignature = ""; } DropNSpawnPlugin.DropNSpawnLogger.LogError((object)$"Failed to prepare synchronized {transport2.DisplayName} payload publish. {ex}"); }, roleEpoch); } }, roleEpoch); } } } } if (flag) { applyManifest2(manifest); } } private static string PublishPayload(DomainTransport transport, List entries, string? knownSignature = null) { lock (Sync) { EnsureRpcRegisteredLocked(); if (TryReusePublishedManifestForSignatureLocked(transport, knownSignature, out string manifest)) { return manifest; } PreparedPublishPayload preparedPublishPayload = PreparePublishPayloadLocked(transport, entries, knownSignature); if (TryReusePublishedManifestForSignatureLocked(transport, preparedPublishPayload.Signature, out string manifest2)) { return manifest2; } if (TryReusePublishedManifestForHashLocked(transport, preparedPublishPayload.PayloadHash, preparedPublishPayload.Signature, out string manifest3)) { return manifest3; } byte[] array = CompressBytes(preparedPublishPayload.PayloadBytes); PayloadEntryIndex resolvedTargetPayloadIndex = null; TransferArtifact artifact = null; PayloadManifest payloadManifest = new PayloadManifest { Hash = preparedPublishPayload.PayloadHash, CompressedSize = array.Length, ChunkCount = Math.Max(1, (int)Math.Ceiling((double)array.Length / (double)transport.ChunkSizeBytes)), EntryCount = preparedPublishPayload.EntryCount }; string hash = transport.PublishedPayloadManifest.Hash; if (hash.Length > 0 && !string.Equals(hash, preparedPublishPayload.PayloadHash, StringComparison.Ordinal)) { TryBuildPrimaryDeltaArtifact(transport, hash, transport.PublishedPayloadBytes, transport.PublishedPayloadIndex, preparedPublishPayload.PayloadHash, preparedPublishPayload.PayloadBytes, null, array, out resolvedTargetPayloadIndex, out artifact); } transport.LastPublishedSignature = preparedPublishPayload.Signature; transport.LastPublishedManifest = payloadManifest.Serialize(); RememberPublishedPayloadLocked(transport, hash, transport.PublishedPayloadBytes, transport.PublishedPayloadIndex); transport.PublishedPayloadBytes = preparedPublishPayload.PayloadBytes; transport.PublishedCompressedBytes = array; transport.PublishedPayloadIndex = resolvedTargetPayloadIndex; transport.PublishedPayloadManifest = payloadManifest; ClearPublishedTransferArtifactsLocked(transport); EnsureFullTransferArtifactLocked(transport, preparedPublishPayload.PayloadHash); if (artifact != null && !transport.PublishedTransferArtifacts.ContainsKey(artifact.CacheKey)) { StoreTransferArtifactLocked(transport, artifact); } TrimTransportCachesLocked(transport); TrimAllPublishedCachesLocked(); return transport.LastPublishedManifest; } } private static bool TryGetEntries(DomainTransport transport, string? manifestRaw, out List entries, out string payloadToken) { lock (Sync) { EnsureRpcRegisteredLocked(); if (!PayloadManifest.TryParse(manifestRaw, out PayloadManifest manifest)) { bool shouldLog; bool result = TryPreserveLastKnownGoodOnInvalidManifestLocked(transport, manifestRaw, out entries, out payloadToken, out shouldLog); if (shouldLog) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("Received invalid synchronized " + transport.DisplayName + " payload manifest '" + manifestRaw + "'. Keeping the last known good client payload state.")); } return result; } ClearInvalidManifestLocked(transport); transport.DesiredManifest = manifestRaw ?? ""; transport.DesiredPayloadManifest = manifest; RefreshBlockedManifestForDesiredHashLocked(transport, manifest.Hash); CancelProcessingIfHashMismatchLocked(transport, manifest.Hash); if (manifest.IsEmpty) { entries = new List(); payloadToken = ""; return false; } if (string.Equals(transport.AvailableHash, manifest.Hash, StringComparison.Ordinal) && transport.AvailablePayloadBytes != null && TryGetAvailableEntriesLocked(transport, out entries)) { payloadToken = manifest.Hash; return true; } if (IsManifestBlockedLocked(transport, manifest.Hash)) { entries = new List(); payloadToken = manifest.Hash; return false; } if (TryScheduleCachedPayloadLoadLocked(transport, manifest)) { entries = new List(); payloadToken = manifest.Hash; return false; } if (transport.ProcessingInFlight && string.Equals(transport.ProcessingHash, manifest.Hash, StringComparison.Ordinal)) { entries = new List(); payloadToken = manifest.Hash; return false; } if (EnsurePayloadRequestedLocked(transport, manifest)) { transport.LastWaitingLogHash = manifest.Hash; DropNSpawnPlugin.DropNSpawnLogger.LogDebug((object)("Requesting synchronized " + transport.DisplayName + " payload '" + manifest.Hash + "' from the server.")); } else if (!string.Equals(transport.LastWaitingLogHash, manifest.Hash, StringComparison.Ordinal)) { transport.LastWaitingLogHash = manifest.Hash; DropNSpawnPlugin.DropNSpawnLogger.LogDebug((object)("Waiting for synchronized " + transport.DisplayName + " payload '" + manifest.Hash + "' from the server.")); } entries = new List(); payloadToken = manifest.Hash; return false; } } private static string NormalizeBaseHash(string? baseHash) { if (!string.IsNullOrWhiteSpace(baseHash)) { return (baseHash ?? "").Trim(); } return ""; } private static string BuildTransferArtifactCacheKey(string targetHash, string? baseHash) { return targetHash + "|" + NormalizeBaseHash(baseHash); } private static void AdvanceRoleEpochAndResetWorkQueuesLocked() { _networkRoleEpoch++; PendingOutboundTransferKeys.Clear(); ActiveOutboundTransfers.Clear(); IDomainTransport[] allTransports = AllTransports; for (int i = 0; i < allTransports.Length; i++) { allTransports[i].ClearPinnedCacheReferences(); } PendingCriticalPayloadProcessingJobs.Clear(); PendingDeltaArtifactPrewarmJobs.Clear(); PendingCachePersistenceJobs.Clear(); PendingMainThreadPayloadCommits.Clear(); PendingReloadActions.Clear(); PendingReloadDomainKeys.Clear(); _outboundBudgetFrame = int.MinValue; _outboundBytesSentThisFrame = 0; } private static void NotifyTransportPayloadReadyIfNeeded(DomainTransport transport, string hash, int? entryCount, string successLogMessage) { transport.Metadata.Hooks.OnPayloadReady(hash, entryCount, successLogMessage, transport.DesiredPayloadManifest.Hash, transport.DesiredPayloadManifest.EntryCount); } private static bool TryReadCachedPayloadBytes(string cacheDirectoryName, string displayName, string hash, out byte[] payloadBytes, out byte[] compressedBytes) { string cachePath = GetCachePath(cacheDirectoryName, hash); payloadBytes = Array.Empty(); compressedBytes = Array.Empty(); if (!File.Exists(cachePath)) { return false; } compressedBytes = File.ReadAllBytes(cachePath); payloadBytes = DecompressBytes(compressedBytes); if (string.Equals(ComputeSha256(payloadBytes), hash, StringComparison.Ordinal)) { return true; } DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("Discarding stale cached " + displayName + " payload '" + hash + "' because the cached hash does not match.")); File.Delete(cachePath); payloadBytes = Array.Empty(); compressedBytes = Array.Empty(); return false; } private static string GetCachePath(string cacheDirectoryName, string hash) { return Path.Combine(Path.Combine(DropNSpawnPlugin.YamlConfigDirectoryPath, "cache"), hash + "." + cacheDirectoryName + ".bin"); } private static void WriteCacheFile(string cacheDirectoryName, string hash, byte[] compressedBytes) { WriteCacheFile(cacheDirectoryName, hash, compressedBytes, (compressedBytes != null) ? compressedBytes.Length : 0); } private static void WriteCacheFile(string cacheDirectoryName, string hash, byte[] compressedBytes, int compressedLength) { string cachePath = GetCachePath(cacheDirectoryName, hash); string directoryName = Path.GetDirectoryName(cachePath); if (!string.IsNullOrWhiteSpace(directoryName)) { Directory.CreateDirectory(directoryName); } int num = Math.Max(0, Math.Min(compressedLength, (compressedBytes != null) ? compressedBytes.Length : 0)); using FileStream fileStream = File.Create(cachePath); if (num > 0) { fileStream.Write(compressedBytes, 0, num); } } private static void DeleteCacheFileIfPresent(string cacheDirectoryName, string hash) { if (string.IsNullOrWhiteSpace(hash)) { return; } try { string cachePath = GetCachePath(cacheDirectoryName, hash); if (File.Exists(cachePath)) { File.Delete(cachePath); } } catch { } } private static string ComputeSha256(byte[] bytes) { using SHA256 sHA = SHA256.Create(); byte[] array = sHA.ComputeHash(bytes); StringBuilder stringBuilder = new StringBuilder(array.Length * 2); byte[] array2 = array; foreach (byte b in array2) { stringBuilder.Append(b.ToString("x2", CultureInfo.InvariantCulture)); } return stringBuilder.ToString(); } private static byte[] CompressBytes(byte[] input) { using MemoryStream memoryStream = new MemoryStream(); using (GZipStream gZipStream = new GZipStream(memoryStream, CompressionLevel.Fastest, leaveOpen: true)) { gZipStream.Write(input, 0, input.Length); } return memoryStream.ToArray(); } private static byte[] DecompressBytes(byte[] input) { return DecompressBytes(input, (input != null) ? input.Length : 0, 0); } private static byte[] DecompressBytes(byte[] input, int inputLength, int initialCapacityHint) { if (input == null || inputLength <= 0) { return Array.Empty(); } int count = Math.Max(0, Math.Min(inputLength, input.Length)); using MemoryStream stream = new MemoryStream(input, 0, count, writable: false, publiclyVisible: true); using GZipStream gZipStream = new GZipStream(stream, CompressionMode.Decompress); using MemoryStream memoryStream = ((initialCapacityHint > 0) ? new MemoryStream(initialCapacityHint) : new MemoryStream()); gZipStream.CopyTo(memoryStream); return memoryStream.ToArray(); } private static void WriteCharacterDropDefinition(PayloadSignatureBuilder builder, CharacterDropDefinition definition) { WriteList(builder, definition.Drops, WriteCharacterDropEntryDefinition); } private static void WriteCharacterDropEntryDefinition(PayloadSignatureBuilder builder, CharacterDropEntryDefinition definition) { builder.WriteString(definition.Item ?? ""); WriteOptional(builder, definition.Amount, WriteIntRangeDefinition); WriteNullableInt(builder, definition.AmountMin); WriteNullableInt(builder, definition.AmountMax); WriteNullableFloat(builder, definition.Chance); WriteNullableBool(builder, definition.DontScale); WriteNullableBool(builder, definition.LevelMultiplier); WriteNullableBool(builder, definition.OnePerPlayer); WriteNullableInt(builder, definition.AmountLimit); WriteNullableBool(builder, definition.DropInStack); } private static void WriteDespawnDefinition(PayloadSignatureBuilder builder, DespawnDefinition definition) { WriteNullableFloat(builder, definition.Range); WriteNullableFloat(builder, definition.Delay); WriteList(builder, definition.Refunds, WriteDespawnRefundEntryDefinition); } private static void WriteBossTamedPressureDefinition(PayloadSignatureBuilder builder, BossTamedPressureDefinition definition) { WriteStringList(builder, definition.BossPrefabs); WriteStringList(builder, definition.ExcludedBossPrefabs); WriteOptional(builder, definition.Targets, WriteBossTamedPressureTargetsDefinition); WriteOptional(builder, definition.Pressure, WriteBossTamedPressurePressureDefinition); WriteNullableString(builder, definition.Message); WriteNullableFloat(builder, definition.MessageInterval); } private static void WriteBossTamedPressureTargetsDefinition(PayloadSignatureBuilder builder, BossTamedPressureTargetsDefinition definition) { WriteNullableFloat(builder, definition.Range); WriteNullableFloat(builder, definition.ScanInterval); WriteNullableInt(builder, definition.MaxPerBoss); WriteStringList(builder, definition.ExcludedTamedPrefabs); WriteStringList(builder, definition.ExtraPressuredPrefabs); } private static void WriteBossTamedPressurePressureDefinition(PayloadSignatureBuilder builder, BossTamedPressurePressureDefinition definition) { WriteNullableFloat(builder, definition.DamageInterval); WriteNullableFloat(builder, definition.DamagePercentPerSecond); WriteNullableFloat(builder, definition.DamageMinBaseHealth); WriteNullableFloat(builder, definition.IncomingDamageMultiplier); WriteNullableFloat(builder, definition.OutgoingDamageMultiplier); } private static void WriteDespawnRefundEntryDefinition(PayloadSignatureBuilder builder, DespawnRefundEntryDefinition definition) { builder.WriteString(definition.Item ?? ""); WriteNullableInt(builder, definition.Amount); } private static void WriteDropTableDefinition(PayloadSignatureBuilder builder, DropTableDefinition definition) { WriteDropTablePayloadDefinition(builder, definition); } private static void WriteDamageableDropTableDefinition(PayloadSignatureBuilder builder, DamageableDropTableDefinition definition) { WriteNullableFloat(builder, definition.Health); WriteNullableInt(builder, definition.MinToolTier); WriteDropTablePayloadDefinition(builder, definition); } private static void WriteDropTablePayloadDefinition(PayloadSignatureBuilder builder, DropTablePayloadDefinition definition) { WriteOptional(builder, definition.Rolls, WriteIntRangeDefinition); WriteNullableInt(builder, definition.DropMin); WriteNullableInt(builder, definition.DropMax); WriteNullableFloat(builder, definition.DropChance); WriteNullableBool(builder, definition.OneOfEach); WriteList(builder, definition.Drops, WriteDropEntryDefinition); } private static void WriteDropEntryDefinition(PayloadSignatureBuilder builder, DropEntryDefinition definition) { builder.WriteString(definition.Item ?? ""); WriteOptional(builder, definition.Stack, WriteIntRangeDefinition); WriteNullableInt(builder, definition.StackMin); WriteNullableInt(builder, definition.StackMax); WriteNullableFloat(builder, definition.Weight); WriteNullableBool(builder, definition.DontScale); } private static void WriteSpawnerSyncSpawnAreaDefinition(PayloadSignatureBuilder builder, SpawnAreaDefinition definition) { WriteNullableFloat(builder, definition.LevelUpChance); WriteNullableFloat(builder, definition.SpawnInterval); WriteNullableFloat(builder, definition.TriggerDistance); WriteNullableBool(builder, definition.SetPatrolSpawnPoint); WriteNullableFloat(builder, definition.SpawnRadius); WriteNullableFloat(builder, definition.NearRadius); WriteNullableFloat(builder, definition.FarRadius); WriteNullableInt(builder, definition.MaxNear); WriteNullableInt(builder, definition.MaxTotal); WriteNullableInt(builder, definition.MaxTotalSpawns); WriteNullableBool(builder, definition.OnGroundOnly); WriteList(builder, definition.Creatures, WriteSpawnerSyncSpawnAreaCreatureDefinition); } private static void WriteSpawnerSyncSpawnAreaCreatureDefinition(PayloadSignatureBuilder builder, SpawnAreaSpawnDefinition definition) { builder.WriteString(definition.Creature ?? ""); WriteNullableFloat(builder, definition.Weight); WriteOptional(builder, definition.Level, WriteIntRangeDefinition); WriteNullableInt(builder, definition.MinLevel); WriteNullableInt(builder, definition.MaxLevel); WriteNullableString(builder, definition.Faction); WriteNullableString(builder, definition.Data); WriteStringDictionary(builder, definition.Fields); WriteStringList(builder, definition.Objects); } private static void WriteSpawnerSyncCreatureSpawnerDefinition(PayloadSignatureBuilder builder, CreatureSpawnerDefinition definition) { WriteNullableString(builder, definition.Creature); WriteOptional(builder, definition.TimeOfDay, WriteTimeOfDayDefinition); WriteNullableString(builder, definition.RequiredGlobalKey); WriteNullableString(builder, definition.BlockingGlobalKey); WriteOptional(builder, definition.Level, WriteIntRangeDefinition); WriteNullableInt(builder, definition.MinLevel); WriteNullableInt(builder, definition.MaxLevel); WriteNullableFloat(builder, definition.LevelUpChance); WriteNullableFloat(builder, definition.RespawnTimeMinutes); WriteNullableInt(builder, definition.SpawnCheckInterval); WriteNullableInt(builder, definition.SpawnGroupId); WriteNullableFloat(builder, definition.SpawnGroupRadius); WriteNullableFloat(builder, definition.SpawnerWeight); WriteNullableInt(builder, definition.MaxGroupSpawned); WriteNullableFloat(builder, definition.TriggerDistance); WriteNullableFloat(builder, definition.TriggerNoise); WriteNullableBool(builder, definition.RequireSpawnArea); WriteNullableBool(builder, definition.AllowInsidePlayerBase); WriteNullableBool(builder, definition.WakeUpAnimation); WriteNullableBool(builder, definition.SetPatrolSpawnPoint); WriteNullableString(builder, definition.Faction); WriteNullableString(builder, definition.Data); WriteStringDictionary(builder, definition.Fields); WriteStringList(builder, definition.Objects); } private static void WritePickableDefinition(PayloadSignatureBuilder builder, PickableDefinition definition) { WriteNullableString(builder, definition.OverrideName); WriteOptional(builder, definition.Drop, WritePickableDropDefinition); WriteOptional(builder, definition.ExtraDrops, WriteDropTablePayloadDefinition); } private static void WritePickableDropDefinition(PayloadSignatureBuilder builder, PickableDropDefinition definition) { builder.WriteString(definition.Item ?? ""); WriteNullableInt(builder, definition.Amount); WriteNullableInt(builder, definition.MinAmountScaled); WriteNullableBool(builder, definition.DontScale); } private static void WritePickableItemDefinition(PayloadSignatureBuilder builder, PickableItemDefinition definition) { WriteList(builder, definition.RandomDrops, WriteRandomPickableItemDefinition); WriteOptional(builder, definition.Drop, WritePickableItemDropDefinition); } private static void WriteFishDefinition(PayloadSignatureBuilder builder, FishDefinition definition) { WriteOptional(builder, definition.ExtraDrops, WriteDropTablePayloadDefinition); } private static void WriteDestructibleDefinition(PayloadSignatureBuilder builder, DestructibleDefinition definition) { WriteNullableFloat(builder, definition.Health); WriteNullableInt(builder, definition.MinToolTier); WriteNullableString(builder, definition.DestructibleType); WriteNullableString(builder, definition.SpawnWhenDestroyed); } private static void WritePickableItemDropDefinition(PayloadSignatureBuilder builder, PickableItemDropDefinition definition) { builder.WriteString(definition.Item ?? ""); WriteNullableInt(builder, definition.Stack); } private static void WriteRandomPickableItemDefinition(PayloadSignatureBuilder builder, RandomPickableItemDefinition definition) { builder.WriteString(definition.Item ?? ""); WriteOptional(builder, definition.Stack, WriteIntRangeDefinition); WriteNullableInt(builder, definition.StackMin); WriteNullableInt(builder, definition.StackMax); WriteNullableFloat(builder, definition.Weight); } private static void WriteOfferingBowlDefinition(PayloadSignatureBuilder builder, LocationOfferingBowlDefinition definition) { WriteNullableString(builder, definition.Name); WriteNullableString(builder, definition.UseItemText); WriteNullableString(builder, definition.UsedAltarText); WriteNullableString(builder, definition.CantOfferText); WriteNullableString(builder, definition.WrongOfferText); WriteNullableString(builder, definition.IncompleteOfferText); WriteNullableString(builder, definition.BossItem); WriteNullableInt(builder, definition.BossItems); WriteNullableString(builder, definition.BossPrefab); WriteNullableString(builder, definition.ItemPrefab); WriteNullableString(builder, definition.SetGlobalKey); WriteNullableBool(builder, definition.RenderSpawnAreaGizmos); WriteNullableBool(builder, definition.AlertOnSpawn); WriteNullableFloat(builder, definition.SpawnBossDelay); WriteOptional(builder, definition.SpawnBossDistance, WriteFloatRangeDefinition); WriteNullableFloat(builder, definition.SpawnBossMaxYDistance); WriteNullableInt(builder, definition.GetSolidHeightMargin); WriteNullableBool(builder, definition.EnableSolidHeightCheck); WriteNullableFloat(builder, definition.SpawnPointClearingRadius); WriteNullableFloat(builder, definition.SpawnYOffset); WriteNullableBool(builder, definition.UseItemStands); WriteNullableString(builder, definition.ItemStandPrefix); WriteNullableFloat(builder, definition.ItemStandMaxRange); WriteNullableFloat(builder, definition.RespawnMinutes); WriteNullableString(builder, definition.Data); WriteStringDictionary(builder, definition.Fields); WriteStringList(builder, definition.Objects); } private static void WriteItemStandDefinition(PayloadSignatureBuilder builder, LocationItemStandDefinition definition) { WriteNullableString(builder, definition.Path); WriteNullableString(builder, definition.Name); WriteNullableBool(builder, definition.CanBeRemoved); WriteNullableBool(builder, definition.AutoAttach); WriteNullableString(builder, definition.OrientationType); WriteStringList(builder, definition.SupportedTypes); WriteStringList(builder, definition.SupportedItems); WriteStringList(builder, definition.UnsupportedItems); WriteNullableFloat(builder, definition.PowerActivationDelay); WriteNullableString(builder, definition.GuardianPower); } private static void WriteVegvisirDefinition(PayloadSignatureBuilder builder, LocationVegvisirDefinition definition) { builder.WriteString(definition.Path ?? ""); WriteStringList(builder, definition.ExpectedLocations); WriteNullableString(builder, definition.Name); WriteNullableString(builder, definition.UseText); WriteNullableString(builder, definition.HoverName); WriteNullableString(builder, definition.SetsGlobalKey); WriteNullableString(builder, definition.SetsPlayerKey); WriteList(builder, definition.Locations, WriteVegvisirTargetDefinition); } private static void WriteVegvisirTargetDefinition(PayloadSignatureBuilder builder, LocationVegvisirTargetDefinition definition) { builder.WriteString(definition.LocationName ?? ""); WriteNullableString(builder, definition.PinName); WriteNullableString(builder, definition.PinType); WriteNullableBool(builder, definition.DiscoverAll); WriteNullableBool(builder, definition.ShowMap); WriteNullableFloat(builder, definition.Weight); } private static void WriteRunestoneDefinition(PayloadSignatureBuilder builder, LocationRunestoneDefinition definition) { builder.WriteString(definition.Path ?? ""); WriteNullableString(builder, definition.ExpectedLocationName); WriteNullableString(builder, definition.ExpectedLabel); WriteNullableString(builder, definition.ExpectedTopic); WriteNullableString(builder, definition.Name); WriteNullableString(builder, definition.Topic); WriteNullableString(builder, definition.Label); WriteNullableString(builder, definition.Text); WriteList(builder, definition.RandomTexts, WriteRunestoneTextDefinition); WriteNullableString(builder, definition.LocationName); WriteNullableString(builder, definition.PinName); WriteNullableString(builder, definition.PinType); WriteNullableBool(builder, definition.ShowMap); WriteNullableFloat(builder, definition.Chance); } private static void WriteRunestoneGlobalPinsDefinition(PayloadSignatureBuilder builder, LocationRunestoneGlobalPinsDefinition definition) { WriteList(builder, definition.TargetLocations, WriteRunestoneGlobalPinTargetDefinition); } private static void WriteRunestoneGlobalPinTargetDefinition(PayloadSignatureBuilder builder, LocationRunestoneGlobalPinTargetDefinition definition) { builder.WriteString(definition.LocationName ?? ""); WriteNullableFloat(builder, definition.Chance); WriteStringList(builder, definition.SourceBiomes); WriteNullableString(builder, definition.PinName); WriteNullableString(builder, definition.PinType); } private static void WriteRunestoneTextDefinition(PayloadSignatureBuilder builder, LocationRunestoneTextDefinition definition) { WriteNullableString(builder, definition.Topic); WriteNullableString(builder, definition.Label); WriteNullableString(builder, definition.Text); } private static void WriteConditionsDefinition(PayloadSignatureBuilder builder, ConditionsDefinition definition, bool includeResolvedBiomeMask) { WriteStringList(builder, definition.Biomes); if (includeResolvedBiomeMask) { WriteNullableInt(builder, GetResolvedBiomeMaskValue(definition.Biomes, definition.ResolvedBiomeMask)); } WriteStringList(builder, definition.Locations); WriteStringList(builder, definition.States); WriteStringList(builder, definition.Factions); WriteStringList(builder, definition.RequiredEnvironments); WriteStringList(builder, definition.RequiredGlobalKeys); WriteStringList(builder, definition.ForbiddenGlobalKeys); WriteOptional(builder, definition.Level, WriteIntRangeDefinition); WriteNullableInt(builder, definition.MinLevel); WriteNullableInt(builder, definition.MaxLevel); WriteOptional(builder, definition.Altitude, WriteFloatRangeDefinition); WriteNullableFloat(builder, definition.MinAltitude); WriteNullableFloat(builder, definition.MaxAltitude); WriteOptional(builder, definition.DistanceFromCenter, WriteFloatRangeDefinition); WriteNullableFloat(builder, definition.MinDistanceFromCenter); WriteNullableFloat(builder, definition.MaxDistanceFromCenter); WriteOptional(builder, definition.TimeOfDay, WriteTimeOfDayDefinition); WriteNullableBool(builder, definition.InDungeon); WriteNullableBool(builder, definition.InForest); WriteNullableBool(builder, definition.InsidePlayerBase); } private static void WriteIntRangeDefinition(PayloadSignatureBuilder builder, IntRangeDefinition definition) { WriteNullableInt(builder, definition.Min); WriteNullableInt(builder, definition.Max); } private static void WriteFloatRangeDefinition(PayloadSignatureBuilder builder, FloatRangeDefinition definition) { WriteNullableFloat(builder, definition.Min); WriteNullableFloat(builder, definition.Max); } private static void WriteTimeOfDayDefinition(PayloadSignatureBuilder builder, TimeOfDayDefinition definition) { WriteStringList(builder, definition.Values); } private static void WriteCharacterDropDefinition(ZPackage package, CharacterDropDefinition definition) { WriteList(package, definition.Drops, WriteCharacterDropEntryDefinition); } private static CharacterDropDefinition ReadCharacterDropDefinition(ZPackage package) { return new CharacterDropDefinition { Drops = ReadList(package, ReadCharacterDropEntryDefinition) }; } private static void WriteDespawnDefinition(ZPackage package, DespawnDefinition definition) { WriteNullableFloat(package, definition.Range); WriteNullableFloat(package, definition.Delay); WriteList(package, definition.Refunds, WriteDespawnRefundEntryDefinition); } private static DespawnDefinition ReadDespawnDefinition(ZPackage package) { return new DespawnDefinition { Range = ReadNullableFloat(package), Delay = ReadNullableFloat(package), Refunds = ReadList(package, ReadDespawnRefundEntryDefinition) }; } private static void WriteBossTamedPressureDefinition(ZPackage package, BossTamedPressureDefinition definition) { WriteStringList(package, definition.BossPrefabs); WriteStringList(package, definition.ExcludedBossPrefabs); WriteOptional(package, definition.Targets, WriteBossTamedPressureTargetsDefinition); WriteOptional(package, definition.Pressure, WriteBossTamedPressurePressureDefinition); WriteNullableString(package, definition.Message); WriteNullableFloat(package, definition.MessageInterval); } private static BossTamedPressureDefinition ReadBossTamedPressureDefinition(ZPackage package) { return new BossTamedPressureDefinition { BossPrefabs = ReadStringList(package), ExcludedBossPrefabs = ReadStringList(package), Targets = ReadOptional(package, ReadBossTamedPressureTargetsDefinition), Pressure = ReadOptional(package, ReadBossTamedPressurePressureDefinition), Message = ReadNullableString(package), MessageInterval = ReadNullableFloat(package) }; } private static void WriteBossTamedPressureTargetsDefinition(ZPackage package, BossTamedPressureTargetsDefinition definition) { WriteNullableFloat(package, definition.Range); WriteNullableFloat(package, definition.ScanInterval); WriteNullableInt(package, definition.MaxPerBoss); WriteStringList(package, definition.ExcludedTamedPrefabs); WriteStringList(package, definition.ExtraPressuredPrefabs); } private static BossTamedPressureTargetsDefinition ReadBossTamedPressureTargetsDefinition(ZPackage package) { return new BossTamedPressureTargetsDefinition { Range = ReadNullableFloat(package), ScanInterval = ReadNullableFloat(package), MaxPerBoss = ReadNullableInt(package), ExcludedTamedPrefabs = ReadStringList(package), ExtraPressuredPrefabs = ReadStringList(package) }; } private static void WriteBossTamedPressurePressureDefinition(ZPackage package, BossTamedPressurePressureDefinition definition) { WriteNullableFloat(package, definition.DamageInterval); WriteNullableFloat(package, definition.DamagePercentPerSecond); WriteNullableFloat(package, definition.DamageMinBaseHealth); WriteNullableFloat(package, definition.IncomingDamageMultiplier); WriteNullableFloat(package, definition.OutgoingDamageMultiplier); } private static BossTamedPressurePressureDefinition ReadBossTamedPressurePressureDefinition(ZPackage package) { return new BossTamedPressurePressureDefinition { DamageInterval = ReadNullableFloat(package), DamagePercentPerSecond = ReadNullableFloat(package), DamageMinBaseHealth = ReadNullableFloat(package), IncomingDamageMultiplier = ReadNullableFloat(package), OutgoingDamageMultiplier = ReadNullableFloat(package) }; } private static void WriteCharacterDropEntryDefinition(ZPackage package, CharacterDropEntryDefinition definition) { package.Write(definition.Item ?? ""); WriteOptional(package, definition.Amount, WriteIntRangeDefinition); WriteNullableInt(package, definition.AmountMin); WriteNullableInt(package, definition.AmountMax); WriteNullableFloat(package, definition.Chance); WriteNullableBool(package, definition.DontScale); WriteNullableBool(package, definition.LevelMultiplier); WriteNullableBool(package, definition.OnePerPlayer); WriteNullableInt(package, definition.AmountLimit); WriteNullableBool(package, definition.DropInStack); } private static void WriteDespawnRefundEntryDefinition(ZPackage package, DespawnRefundEntryDefinition definition) { package.Write(definition.Item ?? ""); WriteNullableInt(package, definition.Amount); } private static DespawnRefundEntryDefinition ReadDespawnRefundEntryDefinition(ZPackage package) { return new DespawnRefundEntryDefinition { Item = package.ReadString(), Amount = ReadNullableInt(package) }; } private static CharacterDropEntryDefinition ReadCharacterDropEntryDefinition(ZPackage package) { return new CharacterDropEntryDefinition { Item = package.ReadString(), Amount = ReadOptional(package, ReadIntRangeDefinition), AmountMin = ReadNullableInt(package), AmountMax = ReadNullableInt(package), Chance = ReadNullableFloat(package), DontScale = ReadNullableBool(package), LevelMultiplier = ReadNullableBool(package), OnePerPlayer = ReadNullableBool(package), AmountLimit = ReadNullableInt(package), DropInStack = ReadNullableBool(package) }; } private static void WriteDropTableDefinition(ZPackage package, DropTableDefinition definition) { WriteDropTablePayloadDefinition(package, definition); } private static DropTableDefinition ReadDropTableDefinition(ZPackage package) { DropTablePayloadDefinition dropTablePayloadDefinition = ReadDropTablePayloadDefinition(package); return new DropTableDefinition { Rolls = dropTablePayloadDefinition.Rolls, DropMin = dropTablePayloadDefinition.DropMin, DropMax = dropTablePayloadDefinition.DropMax, DropChance = dropTablePayloadDefinition.DropChance, OneOfEach = dropTablePayloadDefinition.OneOfEach, Drops = dropTablePayloadDefinition.Drops }; } private static void WriteDamageableDropTableDefinition(ZPackage package, DamageableDropTableDefinition definition) { WriteNullableFloat(package, definition.Health); WriteNullableInt(package, definition.MinToolTier); WriteDropTablePayloadDefinition(package, definition); } private static DamageableDropTableDefinition ReadDamageableDropTableDefinition(ZPackage package) { float? health = ReadNullableFloat(package); int? minToolTier = ReadNullableInt(package); DropTablePayloadDefinition dropTablePayloadDefinition = ReadDropTablePayloadDefinition(package); return new DamageableDropTableDefinition { Health = health, MinToolTier = minToolTier, Rolls = dropTablePayloadDefinition.Rolls, DropMin = dropTablePayloadDefinition.DropMin, DropMax = dropTablePayloadDefinition.DropMax, DropChance = dropTablePayloadDefinition.DropChance, OneOfEach = dropTablePayloadDefinition.OneOfEach, Drops = dropTablePayloadDefinition.Drops }; } private static void WriteDropTablePayloadDefinition(ZPackage package, DropTablePayloadDefinition definition) { WriteOptional(package, definition.Rolls, WriteIntRangeDefinition); WriteNullableInt(package, definition.DropMin); WriteNullableInt(package, definition.DropMax); WriteNullableFloat(package, definition.DropChance); WriteNullableBool(package, definition.OneOfEach); WriteList(package, definition.Drops, WriteDropEntryDefinition); } private static DropTablePayloadDefinition ReadDropTablePayloadDefinition(ZPackage package) { return new DropTablePayloadDefinition { Rolls = ReadOptional(package, ReadIntRangeDefinition), DropMin = ReadNullableInt(package), DropMax = ReadNullableInt(package), DropChance = ReadNullableFloat(package), OneOfEach = ReadNullableBool(package), Drops = ReadList(package, ReadDropEntryDefinition) }; } private static void WriteDropEntryDefinition(ZPackage package, DropEntryDefinition definition) { package.Write(definition.Item ?? ""); WriteOptional(package, definition.Stack, WriteIntRangeDefinition); WriteNullableInt(package, definition.StackMin); WriteNullableInt(package, definition.StackMax); WriteNullableFloat(package, definition.Weight); WriteNullableBool(package, definition.DontScale); } private static DropEntryDefinition ReadDropEntryDefinition(ZPackage package) { return new DropEntryDefinition { Item = package.ReadString(), Stack = ReadOptional(package, ReadIntRangeDefinition), StackMin = ReadNullableInt(package), StackMax = ReadNullableInt(package), Weight = ReadNullableFloat(package), DontScale = ReadNullableBool(package) }; } private static void WriteSpawnerSyncSpawnAreaDefinition(ZPackage package, SpawnAreaDefinition definition) { WriteNullableFloat(package, definition.LevelUpChance); WriteNullableFloat(package, definition.SpawnInterval); WriteNullableFloat(package, definition.TriggerDistance); WriteNullableBool(package, definition.SetPatrolSpawnPoint); WriteNullableFloat(package, definition.SpawnRadius); WriteNullableFloat(package, definition.NearRadius); WriteNullableFloat(package, definition.FarRadius); WriteNullableInt(package, definition.MaxNear); WriteNullableInt(package, definition.MaxTotal); WriteNullableInt(package, definition.MaxTotalSpawns); WriteNullableBool(package, definition.OnGroundOnly); WriteList(package, definition.Creatures, WriteSpawnerSyncSpawnAreaCreatureDefinition); } private static SpawnAreaDefinition ReadSpawnerSyncSpawnAreaDefinition(ZPackage package) { return new SpawnAreaDefinition { LevelUpChance = ReadNullableFloat(package), SpawnInterval = ReadNullableFloat(package), TriggerDistance = ReadNullableFloat(package), SetPatrolSpawnPoint = ReadNullableBool(package), SpawnRadius = ReadNullableFloat(package), NearRadius = ReadNullableFloat(package), FarRadius = ReadNullableFloat(package), MaxNear = ReadNullableInt(package), MaxTotal = ReadNullableInt(package), MaxTotalSpawns = ReadNullableInt(package), OnGroundOnly = ReadNullableBool(package), Creatures = ReadList(package, ReadSpawnerSyncSpawnAreaCreatureDefinition) }; } private static void WriteSpawnerSyncSpawnAreaCreatureDefinition(ZPackage package, SpawnAreaSpawnDefinition definition) { package.Write(definition.Creature ?? ""); WriteNullableFloat(package, definition.Weight); WriteOptional(package, definition.Level, WriteIntRangeDefinition); WriteNullableInt(package, definition.MinLevel); WriteNullableInt(package, definition.MaxLevel); WriteNullableString(package, definition.Faction); WriteNullableString(package, definition.Data); WriteStringDictionary(package, definition.Fields); WriteStringList(package, definition.Objects); } private static SpawnAreaSpawnDefinition ReadSpawnerSyncSpawnAreaCreatureDefinition(ZPackage package) { return new SpawnAreaSpawnDefinition { Creature = package.ReadString(), Weight = ReadNullableFloat(package), Level = ReadOptional(package, ReadIntRangeDefinition), MinLevel = ReadNullableInt(package), MaxLevel = ReadNullableInt(package), Faction = ReadNullableString(package), Data = ReadNullableString(package), Fields = ReadStringDictionary(package), Objects = ReadStringList(package) }; } private static void WriteSpawnerSyncCreatureSpawnerDefinition(ZPackage package, CreatureSpawnerDefinition definition) { WriteNullableString(package, definition.Creature); WriteOptional(package, definition.TimeOfDay, WriteTimeOfDayDefinition); WriteNullableString(package, definition.RequiredGlobalKey); WriteNullableString(package, definition.BlockingGlobalKey); WriteOptional(package, definition.Level, WriteIntRangeDefinition); WriteNullableInt(package, definition.MinLevel); WriteNullableInt(package, definition.MaxLevel); WriteNullableFloat(package, definition.LevelUpChance); WriteNullableFloat(package, definition.RespawnTimeMinutes); WriteNullableInt(package, definition.SpawnCheckInterval); WriteNullableInt(package, definition.SpawnGroupId); WriteNullableFloat(package, definition.SpawnGroupRadius); WriteNullableFloat(package, definition.SpawnerWeight); WriteNullableInt(package, definition.MaxGroupSpawned); WriteNullableFloat(package, definition.TriggerDistance); WriteNullableFloat(package, definition.TriggerNoise); WriteNullableBool(package, definition.RequireSpawnArea); WriteNullableBool(package, definition.AllowInsidePlayerBase); WriteNullableBool(package, definition.WakeUpAnimation); WriteNullableBool(package, definition.SetPatrolSpawnPoint); WriteNullableString(package, definition.Faction); WriteNullableString(package, definition.Data); WriteStringDictionary(package, definition.Fields); WriteStringList(package, definition.Objects); } private static CreatureSpawnerDefinition ReadSpawnerSyncCreatureSpawnerDefinition(ZPackage package) { return new CreatureSpawnerDefinition { Creature = ReadNullableString(package), TimeOfDay = ReadOptional(package, ReadTimeOfDayDefinition), RequiredGlobalKey = ReadNullableString(package), BlockingGlobalKey = ReadNullableString(package), Level = ReadOptional(package, ReadIntRangeDefinition), MinLevel = ReadNullableInt(package), MaxLevel = ReadNullableInt(package), LevelUpChance = ReadNullableFloat(package), RespawnTimeMinutes = ReadNullableFloat(package), SpawnCheckInterval = ReadNullableInt(package), SpawnGroupId = ReadNullableInt(package), SpawnGroupRadius = ReadNullableFloat(package), SpawnerWeight = ReadNullableFloat(package), MaxGroupSpawned = ReadNullableInt(package), TriggerDistance = ReadNullableFloat(package), TriggerNoise = ReadNullableFloat(package), RequireSpawnArea = ReadNullableBool(package), AllowInsidePlayerBase = ReadNullableBool(package), WakeUpAnimation = ReadNullableBool(package), SetPatrolSpawnPoint = ReadNullableBool(package), Faction = ReadNullableString(package), Data = ReadNullableString(package), Fields = ReadStringDictionary(package), Objects = ReadStringList(package) }; } private static void WritePickableDefinition(ZPackage package, PickableDefinition definition) { WriteNullableString(package, definition.OverrideName); WriteOptional(package, definition.Drop, WritePickableDropDefinition); WriteOptional(package, definition.ExtraDrops, WriteDropTablePayloadDefinition); } private static PickableDefinition ReadPickableDefinition(ZPackage package) { return new PickableDefinition { OverrideName = ReadNullableString(package), Drop = ReadOptional(package, ReadPickableDropDefinition), ExtraDrops = ReadOptional(package, ReadDropTablePayloadDefinition) }; } private static void WritePickableDropDefinition(ZPackage package, PickableDropDefinition definition) { package.Write(definition.Item ?? ""); WriteNullableInt(package, definition.Amount); WriteNullableInt(package, definition.MinAmountScaled); WriteNullableBool(package, definition.DontScale); } private static PickableDropDefinition ReadPickableDropDefinition(ZPackage package) { return new PickableDropDefinition { Item = package.ReadString(), Amount = ReadNullableInt(package), MinAmountScaled = ReadNullableInt(package), DontScale = ReadNullableBool(package) }; } private static void WritePickableItemDefinition(ZPackage package, PickableItemDefinition definition) { WriteList(package, definition.RandomDrops, WriteRandomPickableItemDefinition); WriteOptional(package, definition.Drop, WritePickableItemDropDefinition); } private static void WriteFishDefinition(ZPackage package, FishDefinition definition) { WriteOptional(package, definition.ExtraDrops, WriteDropTablePayloadDefinition); } private static FishDefinition ReadFishDefinition(ZPackage package) { return new FishDefinition { ExtraDrops = ReadOptional(package, ReadDropTablePayloadDefinition) }; } private static PickableItemDefinition ReadPickableItemDefinition(ZPackage package) { return new PickableItemDefinition { RandomDrops = ReadList(package, ReadRandomPickableItemDefinition), Drop = ReadOptional(package, ReadPickableItemDropDefinition) }; } private static void WriteDestructibleDefinition(ZPackage package, DestructibleDefinition definition) { WriteNullableFloat(package, definition.Health); WriteNullableInt(package, definition.MinToolTier); WriteNullableString(package, definition.DestructibleType); WriteNullableString(package, definition.SpawnWhenDestroyed); } private static DestructibleDefinition ReadDestructibleDefinition(ZPackage package) { return new DestructibleDefinition { Health = ReadNullableFloat(package), MinToolTier = ReadNullableInt(package), DestructibleType = ReadNullableString(package), SpawnWhenDestroyed = ReadNullableString(package) }; } private static void WritePickableItemDropDefinition(ZPackage package, PickableItemDropDefinition definition) { package.Write(definition.Item ?? ""); WriteNullableInt(package, definition.Stack); } private static PickableItemDropDefinition ReadPickableItemDropDefinition(ZPackage package) { return new PickableItemDropDefinition { Item = package.ReadString(), Stack = ReadNullableInt(package) }; } private static void WriteRandomPickableItemDefinition(ZPackage package, RandomPickableItemDefinition definition) { package.Write(definition.Item ?? ""); WriteOptional(package, definition.Stack, WriteIntRangeDefinition); WriteNullableInt(package, definition.StackMin); WriteNullableInt(package, definition.StackMax); WriteNullableFloat(package, definition.Weight); } private static RandomPickableItemDefinition ReadRandomPickableItemDefinition(ZPackage package) { return new RandomPickableItemDefinition { Item = package.ReadString(), Stack = ReadOptional(package, ReadIntRangeDefinition), StackMin = ReadNullableInt(package), StackMax = ReadNullableInt(package), Weight = ReadNullableFloat(package) }; } private static void WriteOfferingBowlDefinition(ZPackage package, LocationOfferingBowlDefinition definition) { WriteNullableString(package, definition.Name); WriteNullableString(package, definition.UseItemText); WriteNullableString(package, definition.UsedAltarText); WriteNullableString(package, definition.CantOfferText); WriteNullableString(package, definition.WrongOfferText); WriteNullableString(package, definition.IncompleteOfferText); WriteNullableString(package, definition.BossItem); WriteNullableInt(package, definition.BossItems); WriteNullableString(package, definition.BossPrefab); WriteNullableString(package, definition.ItemPrefab); WriteNullableString(package, definition.SetGlobalKey); WriteNullableBool(package, definition.RenderSpawnAreaGizmos); WriteNullableBool(package, definition.AlertOnSpawn); WriteNullableFloat(package, definition.SpawnBossDelay); WriteOptional(package, definition.SpawnBossDistance, WriteFloatRangeDefinition); WriteNullableFloat(package, definition.SpawnBossMaxYDistance); WriteNullableInt(package, definition.GetSolidHeightMargin); WriteNullableBool(package, definition.EnableSolidHeightCheck); WriteNullableFloat(package, definition.SpawnPointClearingRadius); WriteNullableFloat(package, definition.SpawnYOffset); WriteNullableBool(package, definition.UseItemStands); WriteNullableString(package, definition.ItemStandPrefix); WriteNullableFloat(package, definition.ItemStandMaxRange); WriteNullableFloat(package, definition.RespawnMinutes); WriteNullableString(package, definition.Data); WriteStringDictionary(package, definition.Fields); WriteStringList(package, definition.Objects); } private static LocationOfferingBowlDefinition ReadOfferingBowlDefinition(ZPackage package) { return new LocationOfferingBowlDefinition { Name = ReadNullableString(package), UseItemText = ReadNullableString(package), UsedAltarText = ReadNullableString(package), CantOfferText = ReadNullableString(package), WrongOfferText = ReadNullableString(package), IncompleteOfferText = ReadNullableString(package), BossItem = ReadNullableString(package), BossItems = ReadNullableInt(package), BossPrefab = ReadNullableString(package), ItemPrefab = ReadNullableString(package), SetGlobalKey = ReadNullableString(package), RenderSpawnAreaGizmos = ReadNullableBool(package), AlertOnSpawn = ReadNullableBool(package), SpawnBossDelay = ReadNullableFloat(package), SpawnBossDistance = ReadOptional(package, ReadFloatRangeDefinition), SpawnBossMaxYDistance = ReadNullableFloat(package), GetSolidHeightMargin = ReadNullableInt(package), EnableSolidHeightCheck = ReadNullableBool(package), SpawnPointClearingRadius = ReadNullableFloat(package), SpawnYOffset = ReadNullableFloat(package), UseItemStands = ReadNullableBool(package), ItemStandPrefix = ReadNullableString(package), ItemStandMaxRange = ReadNullableFloat(package), RespawnMinutes = ReadNullableFloat(package), Data = ReadNullableString(package), Fields = ReadStringDictionary(package), Objects = ReadStringList(package) }; } private static void WriteItemStandDefinition(ZPackage package, LocationItemStandDefinition definition) { WriteNullableString(package, definition.Path); WriteNullableString(package, definition.Name); WriteNullableBool(package, definition.CanBeRemoved); WriteNullableBool(package, definition.AutoAttach); WriteNullableString(package, definition.OrientationType); WriteStringList(package, definition.SupportedTypes); WriteStringList(package, definition.SupportedItems); WriteStringList(package, definition.UnsupportedItems); WriteNullableFloat(package, definition.PowerActivationDelay); WriteNullableString(package, definition.GuardianPower); } private static LocationItemStandDefinition ReadItemStandDefinition(ZPackage package) { return new LocationItemStandDefinition { Path = ReadNullableString(package), Name = ReadNullableString(package), CanBeRemoved = ReadNullableBool(package), AutoAttach = ReadNullableBool(package), OrientationType = ReadNullableString(package), SupportedTypes = ReadStringList(package), SupportedItems = ReadStringList(package), UnsupportedItems = ReadStringList(package), PowerActivationDelay = ReadNullableFloat(package), GuardianPower = ReadNullableString(package) }; } private static void WriteVegvisirDefinition(ZPackage package, LocationVegvisirDefinition definition) { package.Write(definition.Path ?? ""); WriteStringList(package, definition.ExpectedLocations); WriteNullableString(package, definition.Name); WriteNullableString(package, definition.UseText); WriteNullableString(package, definition.HoverName); WriteNullableString(package, definition.SetsGlobalKey); WriteNullableString(package, definition.SetsPlayerKey); WriteList(package, definition.Locations, WriteVegvisirTargetDefinition); } private static LocationVegvisirDefinition ReadVegvisirDefinition(ZPackage package) { return new LocationVegvisirDefinition { Path = package.ReadString(), ExpectedLocations = ReadStringList(package), Name = ReadNullableString(package), UseText = ReadNullableString(package), HoverName = ReadNullableString(package), SetsGlobalKey = ReadNullableString(package), SetsPlayerKey = ReadNullableString(package), Locations = ReadList(package, ReadVegvisirTargetDefinition) }; } private static void WriteVegvisirTargetDefinition(ZPackage package, LocationVegvisirTargetDefinition definition) { package.Write(definition.LocationName ?? ""); WriteNullableString(package, definition.PinName); WriteNullableString(package, definition.PinType); WriteNullableBool(package, definition.DiscoverAll); WriteNullableBool(package, definition.ShowMap); WriteNullableFloat(package, definition.Weight); } private static LocationVegvisirTargetDefinition ReadVegvisirTargetDefinition(ZPackage package) { return new LocationVegvisirTargetDefinition { LocationName = package.ReadString(), PinName = ReadNullableString(package), PinType = ReadNullableString(package), DiscoverAll = ReadNullableBool(package), ShowMap = ReadNullableBool(package), Weight = ReadNullableFloat(package) }; } private static void WriteRunestoneDefinition(ZPackage package, LocationRunestoneDefinition definition) { package.Write(definition.Path ?? ""); WriteNullableString(package, definition.ExpectedLocationName); WriteNullableString(package, definition.ExpectedLabel); WriteNullableString(package, definition.ExpectedTopic); WriteNullableString(package, definition.Name); WriteNullableString(package, definition.Topic); WriteNullableString(package, definition.Label); WriteNullableString(package, definition.Text); WriteList(package, definition.RandomTexts, WriteRunestoneTextDefinition); WriteNullableString(package, definition.LocationName); WriteNullableString(package, definition.PinName); WriteNullableString(package, definition.PinType); WriteNullableBool(package, definition.ShowMap); WriteNullableFloat(package, definition.Chance); } private static LocationRunestoneDefinition ReadRunestoneDefinition(ZPackage package) { return new LocationRunestoneDefinition { Path = package.ReadString(), ExpectedLocationName = ReadNullableString(package), ExpectedLabel = ReadNullableString(package), ExpectedTopic = ReadNullableString(package), Name = ReadNullableString(package), Topic = ReadNullableString(package), Label = ReadNullableString(package), Text = ReadNullableString(package), RandomTexts = ReadList(package, ReadRunestoneTextDefinition), LocationName = ReadNullableString(package), PinName = ReadNullableString(package), PinType = ReadNullableString(package), ShowMap = ReadNullableBool(package), Chance = ReadNullableFloat(package) }; } private static void WriteRunestoneGlobalPinsDefinition(ZPackage package, LocationRunestoneGlobalPinsDefinition definition) { WriteList(package, definition.TargetLocations, WriteRunestoneGlobalPinTargetDefinition); } private static LocationRunestoneGlobalPinsDefinition ReadRunestoneGlobalPinsDefinition(ZPackage package) { return new LocationRunestoneGlobalPinsDefinition { TargetLocations = ReadList(package, ReadRunestoneGlobalPinTargetDefinition) }; } private static void WriteRunestoneGlobalPinTargetDefinition(ZPackage package, LocationRunestoneGlobalPinTargetDefinition definition) { package.Write(definition.LocationName ?? ""); WriteNullableFloat(package, definition.Chance); WriteStringList(package, definition.SourceBiomes); WriteNullableString(package, definition.PinName); WriteNullableString(package, definition.PinType); } private static LocationRunestoneGlobalPinTargetDefinition ReadRunestoneGlobalPinTargetDefinition(ZPackage package) { return new LocationRunestoneGlobalPinTargetDefinition { LocationName = package.ReadString(), Chance = ReadNullableFloat(package), SourceBiomes = ReadStringList(package), PinName = ReadNullableString(package), PinType = ReadNullableString(package) }; } private static void WriteRunestoneTextDefinition(ZPackage package, LocationRunestoneTextDefinition definition) { WriteNullableString(package, definition.Topic); WriteNullableString(package, definition.Label); WriteNullableString(package, definition.Text); } private static LocationRunestoneTextDefinition ReadRunestoneTextDefinition(ZPackage package) { return new LocationRunestoneTextDefinition { Topic = ReadNullableString(package), Label = ReadNullableString(package), Text = ReadNullableString(package) }; } private static void WriteConditionsDefinition(ZPackage package, ConditionsDefinition definition) { WriteStringList(package, definition.Biomes); WriteNullableInt(package, GetResolvedBiomeMaskValue(definition.Biomes, definition.ResolvedBiomeMask)); WriteStringList(package, definition.Locations); WriteStringList(package, definition.States); WriteStringList(package, definition.Factions); WriteStringList(package, definition.RequiredEnvironments); WriteStringList(package, definition.RequiredGlobalKeys); WriteStringList(package, definition.ForbiddenGlobalKeys); WriteOptional(package, definition.Level, WriteIntRangeDefinition); WriteNullableInt(package, definition.MinLevel); WriteNullableInt(package, definition.MaxLevel); WriteOptional(package, definition.Altitude, WriteFloatRangeDefinition); WriteNullableFloat(package, definition.MinAltitude); WriteNullableFloat(package, definition.MaxAltitude); WriteOptional(package, definition.DistanceFromCenter, WriteFloatRangeDefinition); WriteNullableFloat(package, definition.MinDistanceFromCenter); WriteNullableFloat(package, definition.MaxDistanceFromCenter); WriteOptional(package, definition.TimeOfDay, WriteTimeOfDayDefinition); WriteNullableBool(package, definition.InDungeon); WriteNullableBool(package, definition.InForest); WriteNullableBool(package, definition.InsidePlayerBase); } private static ConditionsDefinition ReadConditionsDefinition(ZPackage package) { ConditionsDefinition obj = new ConditionsDefinition { Biomes = ReadStringList(package) }; int? num = ReadNullableInt(package); Biome? resolvedBiomeMask; if (num.HasValue) { int valueOrDefault = num.GetValueOrDefault(); resolvedBiomeMask = (Biome)valueOrDefault; } else { resolvedBiomeMask = null; } obj.ResolvedBiomeMask = resolvedBiomeMask; obj.Locations = ReadStringList(package); obj.States = ReadStringList(package); obj.Factions = ReadStringList(package); obj.RequiredEnvironments = ReadStringList(package); obj.RequiredGlobalKeys = ReadStringList(package); obj.ForbiddenGlobalKeys = ReadStringList(package); obj.Level = ReadOptional(package, ReadIntRangeDefinition); obj.MinLevel = ReadNullableInt(package); obj.MaxLevel = ReadNullableInt(package); obj.Altitude = ReadOptional(package, ReadFloatRangeDefinition); obj.MinAltitude = ReadNullableFloat(package); obj.MaxAltitude = ReadNullableFloat(package); obj.DistanceFromCenter = ReadOptional(package, ReadFloatRangeDefinition); obj.MinDistanceFromCenter = ReadNullableFloat(package); obj.MaxDistanceFromCenter = ReadNullableFloat(package); obj.TimeOfDay = ReadOptional(package, ReadTimeOfDayDefinition); obj.InDungeon = ReadNullableBool(package); obj.InForest = ReadNullableBool(package); obj.InsidePlayerBase = ReadNullableBool(package); return obj; } private static int? GetResolvedBiomeMaskValue(IEnumerable? configuredBiomes, Biome? resolvedBiomeMask) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected I4, but got Unknown //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected I4, but got Unknown if (resolvedBiomeMask.HasValue) { return (int)resolvedBiomeMask.Value; } Biome? val = BiomeResolutionSupport.ResolveBiomeMaskOrNull(configuredBiomes); if (val.HasValue) { Biome valueOrDefault = val.GetValueOrDefault(); return (int)valueOrDefault; } return null; } private static void WriteIntRangeDefinition(ZPackage package, IntRangeDefinition definition) { WriteNullableInt(package, definition.Min); WriteNullableInt(package, definition.Max); } private static IntRangeDefinition ReadIntRangeDefinition(ZPackage package) { return new IntRangeDefinition { Min = ReadNullableInt(package), Max = ReadNullableInt(package) }; } private static void WriteFloatRangeDefinition(ZPackage package, FloatRangeDefinition definition) { WriteNullableFloat(package, definition.Min); WriteNullableFloat(package, definition.Max); } private static FloatRangeDefinition ReadFloatRangeDefinition(ZPackage package) { return new FloatRangeDefinition { Min = ReadNullableFloat(package), Max = ReadNullableFloat(package) }; } private static void WriteTimeOfDayDefinition(ZPackage package, TimeOfDayDefinition definition) { WriteStringList(package, definition.Values); } private static TimeOfDayDefinition ReadTimeOfDayDefinition(ZPackage package) { return new TimeOfDayDefinition { Values = (ReadStringList(package) ?? new List()) }; } private static void WriteOptional(ZPackage package, T? value, Action writer) where T : class { bool flag = value != null; package.Write(flag); if (flag) { writer(package, value); } } private static T? ReadOptional(ZPackage package, Func reader) where T : class { if (!package.ReadBool()) { return null; } return reader(package); } private static void WriteOptional(PayloadSignatureBuilder builder, T? value, Action writer) where T : class { bool flag = value != null; builder.WriteBool(flag); if (flag) { writer(builder, value); } } private static void WriteList(ZPackage package, List? values, Action writer) { if (values == null) { package.Write(-1); return; } package.Write(values.Count); foreach (T value in values) { writer(package, value); } } private static void WriteList(PayloadSignatureBuilder builder, List? values, Action writer) { if (values == null) { builder.WriteInt(-1); return; } builder.WriteInt(values.Count); foreach (T value in values) { writer(builder, value); } } private static List? ReadList(ZPackage package, Func reader) { int num = package.ReadInt(); if (num < 0) { return null; } List list = new List(num); for (int i = 0; i < num; i++) { list.Add(reader(package)); } return list; } private static void WriteStringList(ZPackage package, List? values) { if (values == null) { package.Write(-1); return; } package.Write(values.Count); foreach (string value in values) { package.Write(value ?? ""); } } private static void WriteStringList(PayloadSignatureBuilder builder, List? values) { if (values == null) { builder.WriteInt(-1); return; } builder.WriteInt(values.Count); foreach (string value in values) { builder.WriteString(value ?? ""); } } private static List? ReadStringList(ZPackage package) { int num = package.ReadInt(); if (num < 0) { return null; } List list = new List(num); for (int i = 0; i < num; i++) { list.Add(package.ReadString()); } return list; } private static void WriteStringDictionary(ZPackage package, Dictionary? values) { if (values == null) { package.Write(-1); return; } List list = new List(values.Keys); list.Sort(StringComparer.Ordinal); package.Write(list.Count); foreach (string item in list) { string text = item ?? ""; package.Write(text); values.TryGetValue(text, out string value); WriteNullableString(package, value); } } private static void WriteStringDictionary(PayloadSignatureBuilder builder, Dictionary? values) { if (values == null) { builder.WriteInt(-1); return; } List list = new List(values.Keys); list.Sort(StringComparer.Ordinal); builder.WriteInt(list.Count); foreach (string item in list) { string text = item ?? ""; builder.WriteString(text); values.TryGetValue(text, out string value); WriteNullableString(builder, value); } } private static Dictionary? ReadStringDictionary(ZPackage package) { int num = package.ReadInt(); if (num < 0) { return null; } Dictionary dictionary = new Dictionary(num, StringComparer.OrdinalIgnoreCase); for (int i = 0; i < num; i++) { string key = package.ReadString(); string text = ReadNullableString(package); dictionary[key] = text ?? ""; } return dictionary; } private static void WriteNullableString(ZPackage package, string? value) { bool flag = value != null; package.Write(flag); if (flag) { package.Write(value); } } private static void WriteNullableString(PayloadSignatureBuilder builder, string? value) { bool flag = value != null; builder.WriteBool(flag); if (flag) { builder.WriteString(value); } } private static string? ReadNullableString(ZPackage package) { if (!package.ReadBool()) { return null; } return package.ReadString(); } private static void WriteNullableInt(ZPackage package, int? value) { package.Write(value.HasValue); if (value.HasValue) { package.Write(value.Value); } } private static void WriteNullableInt(PayloadSignatureBuilder builder, int? value) { builder.WriteBool(value.HasValue); if (value.HasValue) { builder.WriteInt(value.Value); } } private static int? ReadNullableInt(ZPackage package) { if (!package.ReadBool()) { return null; } return package.ReadInt(); } private static void WriteNullableFloat(ZPackage package, float? value) { package.Write(value.HasValue); if (value.HasValue) { package.Write(value.Value); } } private static void WriteNullableFloat(PayloadSignatureBuilder builder, float? value) { builder.WriteBool(value.HasValue); if (value.HasValue) { builder.WriteFloat(value.Value); } } private static float? ReadNullableFloat(ZPackage package) { if (!package.ReadBool()) { return null; } return package.ReadSingle(); } private static void WriteNullableBool(ZPackage package, bool? value) { package.Write(value.HasValue); if (value.HasValue) { package.Write(value.Value); } } private static void WriteNullableBool(PayloadSignatureBuilder builder, bool? value) { builder.WriteBool(value.HasValue); if (value.HasValue) { builder.WriteBool(value.Value); } } private static bool? ReadNullableBool(ZPackage package) { if (!package.ReadBool()) { return null; } return package.ReadBool(); } private static EntryFieldSpec StringField(Func getter, Action setter, Func? includeInSignature = null) { Func getter2 = getter; Action setter2 = setter; Func signatureFilter = includeInSignature ?? new Func(AlwaysIncludeInSignature); return new EntryFieldSpec(delegate(PayloadSignatureBuilder builder, TEntry entry, EntrySignatureContext context) { if (signatureFilter(context)) { builder.WriteString(getter2(entry) ?? ""); } }, delegate(ZPackage package, TEntry entry) { package.Write(getter2(entry) ?? ""); }, delegate(ZPackage package, TEntry entry) { setter2(entry, package.ReadString()); }, delegate(TEntry source, TEntry target) { setter2(target, getter2(source) ?? ""); }); } private static EntryFieldSpec BoolField(Func getter, Action setter, Func? includeInSignature = null) { Func getter2 = getter; Action setter2 = setter; Func signatureFilter = includeInSignature ?? new Func(AlwaysIncludeInSignature); return new EntryFieldSpec(delegate(PayloadSignatureBuilder builder, TEntry entry, EntrySignatureContext context) { if (signatureFilter(context)) { builder.WriteBool(getter2(entry)); } }, delegate(ZPackage package, TEntry entry) { package.Write(getter2(entry)); }, delegate(ZPackage package, TEntry entry) { setter2(entry, package.ReadBool()); }, delegate(TEntry source, TEntry target) { setter2(target, getter2(source)); }); } private static EntryFieldSpec NullableStringField(Func getter, Action setter, Func? includeInSignature = null) { Func getter2 = getter; Action setter2 = setter; Func signatureFilter = includeInSignature ?? new Func(AlwaysIncludeInSignature); return new EntryFieldSpec(delegate(PayloadSignatureBuilder builder, TEntry entry, EntrySignatureContext context) { if (signatureFilter(context)) { WriteNullableString(builder, getter2(entry)); } }, delegate(ZPackage package, TEntry entry) { WriteNullableString(package, getter2(entry)); }, delegate(ZPackage package, TEntry entry) { setter2(entry, ReadNullableString(package)); }, delegate(TEntry source, TEntry target) { setter2(target, getter2(source)); }); } private static EntryFieldSpec OptionalField(Func getter, Action setter, Action signatureWriter, Action payloadWriter, Func payloadReader, Func cloneValue, Func? includeInSignature = null) where TValue : class { Func getter2 = getter; Action signatureWriter2 = signatureWriter; Action payloadWriter2 = payloadWriter; Action setter2 = setter; Func payloadReader2 = payloadReader; Func cloneValue2 = cloneValue; Func signatureFilter = includeInSignature ?? new Func(AlwaysIncludeInSignature); return new EntryFieldSpec(delegate(PayloadSignatureBuilder builder, TEntry entry, EntrySignatureContext context) { if (signatureFilter(context)) { WriteOptional(builder, getter2(entry), delegate(PayloadSignatureBuilder fieldBuilder, TValue value) { signatureWriter2(fieldBuilder, value, context); }); } }, delegate(ZPackage package, TEntry entry) { WriteOptional(package, getter2(entry), payloadWriter2); }, delegate(ZPackage package, TEntry entry) { setter2(entry, ReadOptional(package, payloadReader2)); }, delegate(TEntry source, TEntry target) { setter2(target, cloneValue2(getter2(source))); }); } private static EntryFieldSpec OptionalField(Func getter, Action setter, ValueCodec codec, Func? includeInSignature = null) where TValue : class { Func getter2 = getter; ValueCodec codec2 = codec; Action setter2 = setter; Func signatureFilter = includeInSignature ?? new Func(AlwaysIncludeInSignature); return new EntryFieldSpec(delegate(PayloadSignatureBuilder builder, TEntry entry, EntrySignatureContext context) { if (signatureFilter(context)) { WriteOptional(builder, getter2(entry), delegate(PayloadSignatureBuilder fieldBuilder, TValue value) { codec2.SignatureWriter(fieldBuilder, value, context); }); } }, delegate(ZPackage package, TEntry entry) { WriteOptional(package, getter2(entry), codec2.PayloadWriter); }, delegate(ZPackage package, TEntry entry) { setter2(entry, ReadOptional(package, codec2.PayloadReader)); }, delegate(TEntry source, TEntry target) { TValue val = getter2(source); setter2(target, (val == null) ? null : codec2.CloneValue(val)); }); } private static EntryFieldSpec ListField(Func?> getter, Action?> setter, Action signatureWriter, Action payloadWriter, Func payloadReader, Func cloneValue, Func? includeInSignature = null) { Func?> getter2 = getter; Action signatureWriter2 = signatureWriter; Action payloadWriter2 = payloadWriter; Action?> setter2 = setter; Func payloadReader2 = payloadReader; Func cloneValue2 = cloneValue; Func signatureFilter = includeInSignature ?? new Func(AlwaysIncludeInSignature); return new EntryFieldSpec(delegate(PayloadSignatureBuilder builder, TEntry entry, EntrySignatureContext context) { if (signatureFilter(context)) { WriteList(builder, getter2(entry), delegate(PayloadSignatureBuilder fieldBuilder, TValue value) { signatureWriter2(fieldBuilder, value, context); }); } }, delegate(ZPackage package, TEntry entry) { WriteList(package, getter2(entry), payloadWriter2); }, delegate(ZPackage package, TEntry entry) { setter2(entry, ReadList(package, payloadReader2)); }, delegate(TEntry source, TEntry target) { setter2(target, CloneListValue(getter2(source), cloneValue2)); }); } private static EntryFieldSpec ListField(Func?> getter, Action?> setter, ValueCodec codec, Func? includeInSignature = null) where TValue : class { Func?> getter2 = getter; ValueCodec codec2 = codec; Action?> setter2 = setter; Func signatureFilter = includeInSignature ?? new Func(AlwaysIncludeInSignature); return new EntryFieldSpec(delegate(PayloadSignatureBuilder builder, TEntry entry, EntrySignatureContext context) { if (signatureFilter(context)) { WriteList(builder, getter2(entry), delegate(PayloadSignatureBuilder fieldBuilder, TValue value) { codec2.SignatureWriter(fieldBuilder, value, context); }); } }, delegate(ZPackage package, TEntry entry) { WriteList(package, getter2(entry), codec2.PayloadWriter); }, delegate(ZPackage package, TEntry entry) { setter2(entry, ReadList(package, codec2.PayloadReader)); }, delegate(TEntry source, TEntry target) { setter2(target, CloneListValue(getter2(source), codec2.CloneValue)); }); } private static EntryFieldSpec CopyOnlyField(Action copyValue) { return new EntryFieldSpec(null, null, null, copyValue); } private static bool AlwaysIncludeInSignature(EntrySignatureContext context) { return true; } private static List? CloneListValue(List? source, Func cloneValue) { if (source == null) { return null; } List list = new List(source.Count); foreach (TValue item in source) { list.Add(cloneValue(item)); } return list; } private static int GetInboundChunkOffset(int chunkSizeBytes, int chunkIndex) { return checked(chunkIndex * chunkSizeBytes); } private static bool TryGetInboundCompressedBufferCapacity(int chunkCount, int chunkIndex, int chunkLength, int compressedSize, int chunkSizeBytes, out int capacity, out string failureReason) { capacity = 0; failureReason = ""; if (compressedSize <= 0) { failureReason = $"compressed size {compressedSize} must be greater than 0."; return false; } if (chunkLength < 0 || chunkLength > chunkSizeBytes) { failureReason = $"chunk length {chunkLength} is outside the valid range 0-{chunkSizeBytes}."; return false; } int num = Math.Max(1, (int)Math.Ceiling((double)compressedSize / (double)chunkSizeBytes)); if (num != chunkCount) { failureReason = $"chunk count {chunkCount} did not match compressed size {compressedSize} descriptor chunk count {num}."; return false; } if (chunkIndex < chunkCount - 1 && chunkLength != chunkSizeBytes) { failureReason = $"non-terminal chunk {chunkIndex} had length {chunkLength} instead of {chunkSizeBytes}."; return false; } long num2 = (long)GetInboundChunkOffset(chunkSizeBytes, chunkIndex) + (long)chunkLength; long num3 = compressedSize; if (num3 < num2 || num3 > int.MaxValue) { failureReason = $"compressed buffer capacity {num3} is invalid for chunk {chunkIndex} length {chunkLength}."; return false; } capacity = (int)num3; return true; } private static bool TryInitializePendingInboundTransferBufferLocked(DomainTransport transport, PendingInboundTransfer pendingTransfer, string hash, int transferKind, string normalizedBaseHash, int chunkCount, int compressedSize, int chunkIndex, int chunkLength, out string failureReason) { failureReason = ""; pendingTransfer.TransferKind = transferKind; pendingTransfer.BaseHash = normalizedBaseHash; pendingTransfer.ChunkSizeBytes = transport.ChunkSizeBytes; pendingTransfer.ChunkCount = chunkCount; if (transferKind == 0 && string.Equals(transport.DesiredPayloadManifest.Hash, hash, StringComparison.Ordinal)) { PayloadManifest desiredPayloadManifest = transport.DesiredPayloadManifest; if (desiredPayloadManifest.ChunkCount > 0 && desiredPayloadManifest.ChunkCount != chunkCount) { failureReason = $"full transfer chunk count {chunkCount} did not match desired manifest chunk count {desiredPayloadManifest.ChunkCount}."; return false; } if (desiredPayloadManifest.CompressedSize > 0 && desiredPayloadManifest.CompressedSize != compressedSize) { failureReason = $"full transfer compressed size {compressedSize} did not match desired manifest compressed size {desiredPayloadManifest.CompressedSize}."; return false; } } if (!TryGetInboundCompressedBufferCapacity(chunkCount, chunkIndex, chunkLength, compressedSize, transport.ChunkSizeBytes, out var capacity, out failureReason)) { return false; } pendingTransfer.ExpectedCompressedSize = compressedSize; pendingTransfer.CompressedBuffer = new byte[capacity]; pendingTransfer.ReceivedChunks = new bool[chunkCount]; pendingTransfer.ReceivedChunkCount = 0; return true; } private static bool TryValidateInboundChunkBounds(PendingInboundTransfer pendingTransfer, int chunkIndex, int chunkLength, out string failureReason) { failureReason = ""; int num = Math.Max(1, pendingTransfer.ChunkSizeBytes); if (chunkLength < 0 || chunkLength > num) { failureReason = $"chunk length {chunkLength} is outside the valid range 0-{num}."; return false; } bool flag = chunkIndex == pendingTransfer.ChunkCount - 1; if (!flag && chunkLength != num) { failureReason = $"non-terminal chunk {chunkIndex} had length {chunkLength} instead of {num}."; return false; } int inboundChunkOffset = GetInboundChunkOffset(num, chunkIndex); if (inboundChunkOffset < 0 || inboundChunkOffset > pendingTransfer.CompressedBuffer.Length) { failureReason = $"chunk {chunkIndex} offset {inboundChunkOffset} exceeded compressed buffer length {pendingTransfer.CompressedBuffer.Length}."; return false; } int num2 = pendingTransfer.CompressedBuffer.Length - inboundChunkOffset; if (!flag) { if (chunkLength > num2) { failureReason = $"chunk {chunkIndex} length {chunkLength} exceeded remaining compressed buffer capacity {num2}."; return false; } return true; } int num3 = pendingTransfer.ExpectedCompressedSize - inboundChunkOffset; if (num3 <= 0 || num3 > num) { failureReason = $"last chunk {chunkIndex} expected length {num3} is invalid."; return false; } if (chunkLength != num3) { failureReason = $"last chunk {chunkIndex} length {chunkLength} did not match expected length {num3}."; return false; } return true; } private static bool BufferedChunkEquals(byte[] buffer, int offset, byte[] chunkBytes) { for (int i = 0; i < chunkBytes.Length; i++) { if (buffer[offset + i] != chunkBytes[i]) { return false; } } return true; } private static bool TryBufferInboundChunkBytes(PendingInboundTransfer pendingTransfer, int chunkIndex, byte[] chunkBytes, out bool isDuplicate, out string failureReason) { isDuplicate = false; if (!TryValidateInboundChunkBounds(pendingTransfer, chunkIndex, chunkBytes.Length, out failureReason)) { return false; } bool flag = chunkIndex == pendingTransfer.ChunkCount - 1; int inboundChunkOffset = GetInboundChunkOffset(Math.Max(1, pendingTransfer.ChunkSizeBytes), chunkIndex); if (pendingTransfer.ReceivedChunks[chunkIndex]) { int num = (flag ? (pendingTransfer.ExpectedCompressedSize - inboundChunkOffset) : pendingTransfer.ChunkSizeBytes); isDuplicate = true; if (num != chunkBytes.Length || !BufferedChunkEquals(pendingTransfer.CompressedBuffer, inboundChunkOffset, chunkBytes)) { failureReason = $"duplicate chunk {chunkIndex} differed from the already buffered data."; return false; } return true; } Buffer.BlockCopy(chunkBytes, 0, pendingTransfer.CompressedBuffer, inboundChunkOffset, chunkBytes.Length); pendingTransfer.ReceivedChunks[chunkIndex] = true; pendingTransfer.ReceivedChunkCount++; failureReason = ""; return true; } private static int GetInboundCompressedLength(PendingInboundTransfer pendingTransfer) { return Math.Max(0, pendingTransfer.ExpectedCompressedSize); } private static bool TryGetPublishedTransferArtifactLocked(DomainTransport transport, string targetHash, string? baseHash, out TransferArtifact? artifact) { artifact = null; string key = BuildTransferArtifactCacheKey(targetHash, baseHash); if (!transport.PublishedTransferArtifacts.TryGetValue(key, out artifact) || artifact == null) { return false; } LinkedListNode node = artifact.LruNode; TouchLruNodeLocked(transport.PublishedTransferArtifactLru, key, ref node); artifact.LruNode = node; return true; } private static void StoreTransferArtifactLocked(DomainTransport transport, TransferArtifact artifact) { if (artifact != null && artifact.CacheKey.Length != 0) { if (transport.PublishedTransferArtifacts.TryGetValue(artifact.CacheKey, out TransferArtifact value) && value != null) { RemoveTransferArtifactLocked(transport, value); } transport.PublishedTransferArtifacts[artifact.CacheKey] = artifact; AdjustPublishedTransferArtifactBytesLocked(transport, artifact.EstimatedBytes); LinkedListNode node = artifact.LruNode; TouchLruNodeLocked(transport.PublishedTransferArtifactLru, artifact.CacheKey, ref node); artifact.LruNode = node; } } private static TransferArtifact? EnsureFullTransferArtifactLocked(DomainTransport transport, string targetHash) { if (transport.PublishedCompressedBytes == null || transport.PublishedPayloadManifest.IsEmpty || !string.Equals(transport.PublishedPayloadManifest.Hash, targetHash, StringComparison.Ordinal)) { return null; } if (TryGetPublishedTransferArtifactLocked(transport, targetHash, "", out TransferArtifact artifact)) { return artifact; } TransferArtifact transferArtifact = new TransferArtifact { CacheKey = BuildTransferArtifactCacheKey(targetHash, ""), TransferKind = 0, BaseHash = "", TargetHash = targetHash, CompressedBytes = transport.PublishedCompressedBytes, ChunkSizeBytes = transport.ChunkSizeBytes, ChunkCount = Math.Max(1, (int)Math.Ceiling((double)transport.PublishedCompressedBytes.Length / (double)transport.ChunkSizeBytes)) }; transferArtifact.EstimatedBytes = EstimateTransferArtifactBytes(transferArtifact); StoreTransferArtifactLocked(transport, transferArtifact); return transferArtifact; } private static void QueueTransferArtifactBuildIfNeededLocked(DomainTransport transport, string targetHash, string? baseHash) { DomainTransport transport2 = transport; string targetHash2 = targetHash; if (!transport2.EnableArtifactPrewarm || !transport2.SupportsDeltaTransfers) { return; } string normalizedBaseHash = NormalizeBaseHash(baseHash); if (normalizedBaseHash.Length == 0 || transport2.PublishedCompressedBytes == null || transport2.PublishedPayloadManifest.IsEmpty || !string.Equals(transport2.PublishedPayloadManifest.Hash, targetHash2, StringComparison.Ordinal) || !transport2.PublishedPayloadHistory.TryGetValue(normalizedBaseHash, out PublishedPayloadHistoryEntry value) || value == null || value.PayloadBytes == null || value.PayloadBytes.Length == 0 || TryGetPublishedTransferArtifactLocked(transport2, targetHash2, normalizedBaseHash, out TransferArtifact _)) { return; } string cacheKey = BuildTransferArtifactCacheKey(targetHash2, normalizedBaseHash); if (!transport2.PendingArtifactBuildKeys.Add(cacheKey)) { return; } byte[] fullCompressedPayloadBytes = transport2.PublishedCompressedBytes; byte[] targetPayloadBytes = transport2.PublishedPayloadBytes ?? Array.Empty(); PayloadEntryIndex targetPayloadIndex = transport2.PublishedPayloadIndex; byte[] basePayloadBytes = value.PayloadBytes; PayloadEntryIndex basePayloadIndex = value.PayloadIndex; int roleEpoch = _networkRoleEpoch; LinkedListNode node = value.LruNode; TouchLruNodeLocked(transport2.PublishedPayloadHistoryLru, normalizedBaseHash, ref node); value.LruNode = node; QueueDeltaArtifactPrewarmJobLocked(delegate { try { PayloadEntryIndex resolvedTargetPayloadIndex; PayloadEntryIndex resolvedBasePayloadIndex; byte[] deltaPayloadBytes; if (!IsCurrentRoleEpoch(roleEpoch)) { QueueMainThreadPayloadCommitLocked(delegate { lock (Sync) { transport2.PendingArtifactBuildKeys.Remove(cacheKey); } }, roleEpoch); } else if (!TryEnsurePayloadIndex(transport2, targetHash2, targetPayloadBytes, targetPayloadIndex, out resolvedTargetPayloadIndex) || resolvedTargetPayloadIndex == null) { QueueMainThreadPayloadCommitLocked(delegate { lock (Sync) { transport2.PendingArtifactBuildKeys.Remove(cacheKey); } }, roleEpoch); } else if (!IsCurrentRoleEpoch(roleEpoch)) { QueueMainThreadPayloadCommitLocked(delegate { lock (Sync) { transport2.PendingArtifactBuildKeys.Remove(cacheKey); } }, roleEpoch); } else if (!TryEnsurePayloadIndex(transport2, normalizedBaseHash, basePayloadBytes, basePayloadIndex, out resolvedBasePayloadIndex) || resolvedBasePayloadIndex == null) { QueueMainThreadPayloadCommitLocked(delegate { lock (Sync) { transport2.PendingArtifactBuildKeys.Remove(cacheKey); } }, roleEpoch); } else if (!IsCurrentRoleEpoch(roleEpoch)) { QueueMainThreadPayloadCommitLocked(delegate { lock (Sync) { transport2.PendingArtifactBuildKeys.Remove(cacheKey); } }, roleEpoch); } else if (!TryBuildDeltaPayloadBytes(transport2, normalizedBaseHash, targetHash2, resolvedBasePayloadIndex, resolvedTargetPayloadIndex, out deltaPayloadBytes)) { QueueMainThreadPayloadCommitLocked(delegate { lock (Sync) { transport2.PendingArtifactBuildKeys.Remove(cacheKey); } }, roleEpoch); } else if (!IsCurrentRoleEpoch(roleEpoch)) { QueueMainThreadPayloadCommitLocked(delegate { lock (Sync) { transport2.PendingArtifactBuildKeys.Remove(cacheKey); } }, roleEpoch); } else { byte[] array = CompressBytes(deltaPayloadBytes); if (!IsCurrentRoleEpoch(roleEpoch)) { QueueMainThreadPayloadCommitLocked(delegate { lock (Sync) { transport2.PendingArtifactBuildKeys.Remove(cacheKey); } }, roleEpoch); } else if ((float)array.Length >= (float)fullCompressedPayloadBytes.Length * transport2.TransportPolicy.MaxDeltaCompressedSizeRatio) { QueueMainThreadPayloadCommitLocked(delegate { lock (Sync) { transport2.PendingArtifactBuildKeys.Remove(cacheKey); } }, roleEpoch); } else { TransferArtifact artifact2 = new TransferArtifact { CacheKey = cacheKey, TransferKind = 1, BaseHash = normalizedBaseHash, TargetHash = targetHash2, CompressedBytes = array, ChunkSizeBytes = transport2.ChunkSizeBytes, ChunkCount = Math.Max(1, (int)Math.Ceiling((double)array.Length / (double)transport2.ChunkSizeBytes)) }; artifact2.EstimatedBytes = EstimateTransferArtifactBytes(artifact2); QueueMainThreadPayloadCommitLocked(delegate { lock (Sync) { transport2.PendingArtifactBuildKeys.Remove(cacheKey); if (roleEpoch == _networkRoleEpoch && !transport2.PublishedPayloadManifest.IsEmpty && string.Equals(transport2.PublishedPayloadManifest.Hash, targetHash2, StringComparison.Ordinal) && !transport2.PublishedTransferArtifacts.ContainsKey(cacheKey)) { if (transport2.PublishedPayloadIndex == null) { transport2.PublishedPayloadIndex = resolvedTargetPayloadIndex; } RememberPublishedPayloadLocked(transport2, normalizedBaseHash, basePayloadBytes, resolvedBasePayloadIndex); StoreTransferArtifactLocked(transport2, artifact2); TrimTransportCachesLocked(transport2); TrimAllPublishedCachesLocked(); } } }, roleEpoch); } } } catch (Exception ex2) { Exception ex3 = ex2; Exception ex = ex3; QueueMainThreadPayloadCommitLocked(delegate { lock (Sync) { transport2.PendingArtifactBuildKeys.Remove(cacheKey); } DropNSpawnPlugin.DropNSpawnLogger.LogDebug((object)("Failed to prebuild synchronized " + transport2.DisplayName + " delta artifact '" + normalizedBaseHash + "->" + targetHash2 + "'. " + ex.Message)); }, roleEpoch); } }, roleEpoch); } private static long AllocateRequestIdLocked(DomainTransport transport) { long num = transport.NextRequestId + 1; if (num <= 0) { num = 1L; } transport.NextRequestId = num; return num; } private static long BeginPendingInboundTransferLocked(DomainTransport transport, string hash, string requestedBaseHash, bool isFullFallbackRequest, long expectedSender, out string resolvedBaseHash) { float realtimeSinceStartup = Time.realtimeSinceStartup; PendingInboundTransfer pendingTransfer = transport.PendingTransfer; if (pendingTransfer != null && string.Equals(pendingTransfer.Hash, hash, StringComparison.Ordinal) && pendingTransfer.IsFullFallbackRequest == isFullFallbackRequest) { pendingTransfer.ExpectedSender = expectedSender; if (pendingTransfer.RequestId <= 0) { pendingTransfer.RequestId = AllocateRequestIdLocked(transport); } if (pendingTransfer.RequestedBaseHash.Length == 0) { pendingTransfer.RequestedBaseHash = ((pendingTransfer.TransferKind >= 0) ? pendingTransfer.BaseHash : NormalizeBaseHash(requestedBaseHash)); } transport.RequestInFlight = true; transport.RequestStartedAt = realtimeSinceStartup; resolvedBaseHash = pendingTransfer.RequestedBaseHash; return pendingTransfer.RequestId; } long num = AllocateRequestIdLocked(transport); transport.PendingTransfer = new PendingInboundTransfer { ExpectedSender = expectedSender, RequestId = num, Hash = (hash ?? ""), IsFullFallbackRequest = isFullFallbackRequest, RequestedBaseHash = NormalizeBaseHash(requestedBaseHash) }; transport.RequestInFlight = true; transport.RequestStartedAt = realtimeSinceStartup; resolvedBaseHash = transport.PendingTransfer.RequestedBaseHash; return num; } private static void ClearPendingInboundTransferLocked(DomainTransport transport) { transport.PendingTransfer = null; transport.RequestInFlight = false; transport.RequestStartedAt = 0f; } private static bool MatchesCurrentPendingRequestLocked(DomainTransport transport, string hash) { if (transport.PendingTransfer != null) { return string.Equals(transport.PendingTransfer.Hash, hash, StringComparison.Ordinal); } return false; } private static float GetPendingRequestLastActivityAtLocked(DomainTransport transport) { float num = transport.RequestStartedAt; PendingInboundTransfer? pendingTransfer = transport.PendingTransfer; if (pendingTransfer != null && pendingTransfer.LastProgressAt > num) { num = transport.PendingTransfer.LastProgressAt; } return num; } private static bool HasPendingRequestTimedOutLocked(DomainTransport transport) { if (!transport.RequestInFlight) { return false; } float pendingRequestLastActivityAtLocked = GetPendingRequestLastActivityAtLocked(transport); if (pendingRequestLastActivityAtLocked > 0f) { return Time.realtimeSinceStartup - pendingRequestLastActivityAtLocked >= 5f; } return false; } private static void AbortPendingInboundTransferLocked(DomainTransport transport, string message, bool retryAsFull) { string hash = transport.DesiredPayloadManifest.Hash; ClearPendingInboundTransferLocked(transport); transport.LastWaitingLogHash = ""; DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)message); if (!string.IsNullOrWhiteSpace(hash)) { if (retryAsFull) { TryRequestFullFallbackOnceLocked(transport, hash, "source=delta_transfer_validation detail=" + message); } else { EnsurePayloadRequestedLocked(transport, transport.DesiredPayloadManifest); } } } private static bool TryRequestFullFallbackOnceLocked(DomainTransport transport, string hash, string reason) { if (string.IsNullOrWhiteSpace(hash)) { return false; } if (string.Equals(transport.FullFallbackAttemptedHash, hash, StringComparison.Ordinal)) { BlockManifestLocked(transport, hash, reason + " source=delta_full_fallback_exhausted fullFallbackAttempted=true"); return false; } transport.FullFallbackAttemptedHash = hash; return EnsurePayloadRequestedLocked(transport, transport.DesiredPayloadManifest, "", isFullFallbackRequest: true); } private static void CommitProcessedPayloadLocked(DomainTransport transport, int version, string hash, byte[] payloadBytes, List? entries, PayloadEntryIndex? payloadIndex, int? entryCount, string successLogMessage) { bool flag = false; lock (Sync) { if (!IsProcessingResultCurrentLocked(transport, version, hash) || !string.Equals(transport.DesiredPayloadManifest.Hash, hash, StringComparison.Ordinal)) { return; } transport.AvailableHash = hash; transport.AvailablePayloadBytes = payloadBytes; transport.AvailableEntries = entries; transport.AvailablePayloadIndex = payloadIndex; ClearBlockedManifestLocked(transport); ClearPendingInboundTransferLocked(transport); transport.LastWaitingLogHash = ""; transport.ProcessingInFlight = false; transport.ProcessingHash = ""; flag = true; QueueReloadActionLocked(transport); } if (flag) { NotifyTransportPayloadReadyIfNeeded(transport, hash, entryCount, successLogMessage); DropNSpawnPlugin.DropNSpawnLogger.LogDebug((object)successLogMessage); } } private static void QueueFetchedPayloadCacheWriteLocked(DomainTransport transport, string hash, byte[] payloadBytes, byte[]? compressedBytes, int compressedLength, bool requiresCompression, int roleEpoch) { byte[] payloadBytes2 = payloadBytes; DomainTransport transport2 = transport; string hash2 = hash; byte[] compressedBytes2 = compressedBytes; if (string.IsNullOrWhiteSpace(hash2)) { return; } QueueCachePersistenceJobLocked(delegate { try { if (IsCurrentRoleEpoch(roleEpoch)) { if (requiresCompression) { byte[] array = CompressBytes(payloadBytes2); if (array.Length != 0 && IsCurrentRoleEpoch(roleEpoch)) { WriteCacheFile(transport2.CacheDirectoryName, hash2, array); } } else { byte[] array2 = compressedBytes2 ?? Array.Empty(); if (array2.Length != 0 && compressedLength > 0 && IsCurrentRoleEpoch(roleEpoch)) { WriteCacheFile(transport2.CacheDirectoryName, hash2, array2, compressedLength); } } } } catch (Exception ex) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("Failed to persist synchronized " + transport2.DisplayName + " payload '" + hash2 + "' to cache. " + ex.Message)); } }, roleEpoch); } private static bool EnsurePayloadRequestedLocked(DomainTransport transport, PayloadManifest manifest, string? baseHashOverride = null, bool isFullFallbackRequest = false) { //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Expected O, but got Unknown if (manifest.IsEmpty || IsManifestBlockedLocked(transport, manifest.Hash) || (Object)(object)_host == (Object)null || ZRoutedRpc.instance == null) { return false; } if (transport.RequestInFlight && MatchesCurrentPendingRequestLocked(transport, manifest.Hash) && !HasPendingRequestTimedOutLocked(transport)) { return false; } if (!transport.RequestInFlight && !HasAvailableClientRequestSlotLocked(transport)) { return false; } if (!TryGetCurrentServerRoutedSender(out var sender)) { return false; } string requestedBaseHash = NormalizeBaseHash(baseHashOverride ?? ((transport.AvailablePayloadBytes != null && transport.AvailableHash.Length > 0 && !string.Equals(transport.AvailableHash, manifest.Hash, StringComparison.Ordinal)) ? transport.AvailableHash : "")); string resolvedBaseHash; long num = BeginPendingInboundTransferLocked(transport, manifest.Hash, requestedBaseHash, isFullFallbackRequest, sender, out resolvedBaseHash); ZPackage val = new ZPackage(); val.Write(transport.DomainKey); val.Write(manifest.Hash); val.Write(resolvedBaseHash); val.Write(num); ZRoutedRpc.instance.InvokeRoutedRPC(0L, "DropNSpawn Payload Request", new object[1] { val }); return true; } private static void EnqueuePublishedPayloadChunksLocked(DomainTransport transport, long sender, string requestedHash, string? baseHash, long requestId) { TransferArtifact orCreateTransferArtifactLocked = GetOrCreateTransferArtifactLocked(transport, requestedHash, baseHash); if (orCreateTransferArtifactLocked != null && orCreateTransferArtifactLocked.ChunkCount > 0) { UpsertOutboundTransferLocked(transport.DomainKey, sender, requestedHash, requestId, orCreateTransferArtifactLocked); } } private static TransferArtifact? GetOrCreateTransferArtifactLocked(DomainTransport transport, string requestedHash, string? baseHash) { if (transport.PublishedCompressedBytes == null || transport.PublishedPayloadManifest.IsEmpty || !string.Equals(transport.PublishedPayloadManifest.Hash, requestedHash, StringComparison.Ordinal)) { return null; } string text = (string.IsNullOrWhiteSpace(baseHash) ? "" : (baseHash ?? "").Trim()); if (TryGetPublishedTransferArtifactLocked(transport, requestedHash, text, out TransferArtifact artifact)) { return artifact; } TransferArtifact? result = EnsureFullTransferArtifactLocked(transport, requestedHash); if (text.Length > 0 && transport.EnableArtifactPrewarm) { QueueTransferArtifactBuildIfNeededLocked(transport, requestedHash, text); } TrimTransportCachesLocked(transport); TrimAllPublishedCachesLocked(); return result; } private static bool HasPendingClientRequestWorkLocked() { IDomainTransport[] allTransports = AllTransports; for (int i = 0; i < allTransports.Length; i++) { if (allTransports[i].HasWaitingRequest()) { return true; } } return false; } private static bool HasWaitingRequestLocked(DomainTransport transport) { if (transport.DesiredPayloadManifest.IsEmpty) { return false; } if (IsManifestBlockedLocked(transport, transport.DesiredPayloadManifest.Hash)) { return false; } if (string.Equals(transport.AvailableHash, transport.DesiredPayloadManifest.Hash, StringComparison.Ordinal) && transport.AvailablePayloadBytes != null) { return false; } if (transport.ProcessingInFlight && string.Equals(transport.ProcessingHash, transport.DesiredPayloadManifest.Hash, StringComparison.Ordinal)) { return false; } if (transport.RequestInFlight && MatchesCurrentPendingRequestLocked(transport, transport.DesiredPayloadManifest.Hash) && !HasPendingRequestTimedOutLocked(transport)) { return false; } return true; } private static int CountClientRequestsInFlightLocked(bool usesLargeRequestLane) { int num = 0; IDomainTransport[] allTransports = AllTransports; foreach (IDomainTransport domainTransport in allTransports) { num += domainTransport.CountClientRequestInFlight(usesLargeRequestLane); } return num; } private static int CountClientRequestInFlightLocked(DomainTransport transport) { if (!transport.RequestInFlight) { return 0; } if (HasPendingRequestTimedOutLocked(transport)) { return 0; } return 1; } private static int CountClientRequestInFlightLocked(DomainTransport transport, bool usesLargeRequestLane) { if (transport.UsesLargeRequestLane != usesLargeRequestLane) { return 0; } return CountClientRequestInFlightLocked(transport); } private static bool HasAvailableClientRequestSlotLocked(DomainTransport transport) { if (transport.UsesLargeRequestLane) { return CountClientRequestsInFlightLocked(usesLargeRequestLane: true) < 1; } return CountClientRequestsInFlightLocked(usesLargeRequestLane: false) < 2; } private static bool TryStartNextWaitingPayloadRequestLocked() { if ((Object)(object)_host == (Object)null || ZRoutedRpc.instance == null) { return false; } bool flag = CountClientRequestsInFlightLocked(usesLargeRequestLane: true) < 1; bool flag2 = CountClientRequestsInFlightLocked(usesLargeRequestLane: false) < 2; if (!flag && !flag2) { return false; } if (flag2 && TryStartNextWaitingPayloadRequestLocked(SmallLaneRequestPriorityTransports)) { return true; } if (flag) { return TryStartNextWaitingPayloadRequestLocked(LargeLaneRequestPriorityTransports); } return false; } private static bool TryStartNextWaitingPayloadRequestLocked(IEnumerable transports) { foreach (IDomainTransport transport in transports) { if (transport.TryStartDesiredPayloadRequest()) { return true; } } return false; } private static bool TryStartDesiredPayloadRequestLocked(DomainTransport transport) { if (!HasWaitingRequestLocked(transport)) { return false; } return EnsurePayloadRequestedLocked(transport, transport.DesiredPayloadManifest); } private static bool IsProcessingResultCurrentLocked(DomainTransport transport, int version, string hash) { if (transport.ProcessingVersion == version) { return string.Equals(transport.ProcessingHash, hash, StringComparison.Ordinal); } return false; } private static void ReceivePayloadChunkLocked(DomainTransport transport, long sender, string hash, long requestId, int transferKind, string baseHash, int chunkIndex, int chunkCount, int compressedSize, byte[] chunkBytes) { DomainTransport transport2 = transport; string hash2 = hash; PendingInboundTransfer pendingTransfer = transport2.PendingTransfer; if (string.IsNullOrWhiteSpace(hash2) || chunkCount <= 0 || compressedSize <= 0 || chunkIndex < 0 || chunkIndex >= chunkCount || pendingTransfer == null || (pendingTransfer.ExpectedSender != 0L && pendingTransfer.ExpectedSender != sender)) { return; } if (requestId != 0L) { if (pendingTransfer.RequestId != requestId) { return; } } else if (pendingTransfer.RequestId == 0L) { return; } if (!string.Equals(pendingTransfer.Hash, hash2, StringComparison.Ordinal)) { AbortPendingInboundTransferLocked(transport2, "Discarding synchronized " + transport2.DisplayName + " payload '" + hash2 + "' because the inbound request hash does not match the active request.", retryAsFull: true); return; } string text = NormalizeBaseHash(baseHash); if (pendingTransfer.TransferKind < 0) { if (!TryInitializePendingInboundTransferBufferLocked(transport2, pendingTransfer, hash2, transferKind, text, chunkCount, compressedSize, chunkIndex, (chunkBytes ?? Array.Empty()).Length, out string failureReason)) { AbortPendingInboundTransferLocked(transport2, "Discarding synchronized " + transport2.DisplayName + " payload '" + hash2 + "' because " + failureReason, retryAsFull: true); return; } } else if (pendingTransfer.TransferKind != transferKind || !string.Equals(pendingTransfer.BaseHash, text, StringComparison.Ordinal) || pendingTransfer.ChunkCount != chunkCount || pendingTransfer.ExpectedCompressedSize != compressedSize) { AbortPendingInboundTransferLocked(transport2, $"Discarding synchronized {transport2.DisplayName} payload '{hash2}' because chunk descriptor {transferKind}/{text}/{chunkCount}/{compressedSize} did not match the active transfer {pendingTransfer.TransferKind}/{pendingTransfer.BaseHash}/{pendingTransfer.ChunkCount}/{pendingTransfer.ExpectedCompressedSize}.", retryAsFull: true); return; } byte[] chunkBytes2 = chunkBytes ?? Array.Empty(); if (!TryBufferInboundChunkBytes(pendingTransfer, chunkIndex, chunkBytes2, out bool isDuplicate, out string failureReason2)) { AbortPendingInboundTransferLocked(transport2, "Discarding synchronized " + transport2.DisplayName + " payload '" + hash2 + "' because " + failureReason2, retryAsFull: true); return; } if (isDuplicate) { pendingTransfer.LastProgressAt = Time.realtimeSinceStartup; return; } pendingTransfer.LastProgressAt = Time.realtimeSinceStartup; if (pendingTransfer.ReceivedChunkCount < pendingTransfer.ChunkCount) { return; } int version = ++transport2.ProcessingVersion; transport2.ProcessingInFlight = true; transport2.ProcessingHash = hash2; int roleEpoch = _networkRoleEpoch; PayloadEntryIndex basePayloadIndexSnapshot = ((pendingTransfer.TransferKind == 1 && string.Equals(transport2.AvailableHash, pendingTransfer.BaseHash, StringComparison.Ordinal)) ? transport2.AvailablePayloadIndex : null); byte[] basePayloadBytesSnapshot = ((pendingTransfer.TransferKind == 1 && string.Equals(transport2.AvailableHash, pendingTransfer.BaseHash, StringComparison.Ordinal) && transport2.AvailablePayloadBytes != null) ? transport2.AvailablePayloadBytes : null); int num; if (pendingTransfer.TransferKind != 1) { byte[]? availablePayloadBytes = transport2.AvailablePayloadBytes; num = Math.Max(0, (availablePayloadBytes != null) ? availablePayloadBytes.Length : 0); } else { byte[] array = basePayloadBytesSnapshot; int val; if (array == null) { byte[]? availablePayloadBytes2 = transport2.AvailablePayloadBytes; val = ((availablePayloadBytes2 != null) ? availablePayloadBytes2.Length : 0); } else { val = array.Length; } num = Math.Max(0, val); } int transferDecompressionCapacityHint = num; byte[] compressedBuffer = pendingTransfer.CompressedBuffer; int compressedLength = GetInboundCompressedLength(pendingTransfer); ClearPendingInboundTransferLocked(transport2); transport2.LastWaitingLogHash = ""; QueueCriticalPayloadProcessingJobLocked(delegate { try { byte[] array2 = DecompressBytes(compressedBuffer, compressedLength, transferDecompressionCapacityHint); List entries = null; PayloadEntryIndex payloadIndex = null; byte[] payloadBytes; if (pendingTransfer.TransferKind == 1) { payloadBytes = ApplyDeltaPayloadBytes(transport2, pendingTransfer.BaseHash, hash2, array2, basePayloadIndexSnapshot, basePayloadBytesSnapshot, out List mergedEntries); entries = mergedEntries; } else { payloadBytes = array2; } if (!string.Equals(ComputeSha256(payloadBytes), hash2, StringComparison.Ordinal)) { throw new InvalidDataException("Discarding synchronized " + transport2.DisplayName + " payload '" + hash2 + "' because the fetched hash does not match."); } if (entries != null) { BuildPayloadIndex(transport2, entries, hash2, out payloadIndex); } QueueFetchedPayloadCacheWriteLocked(transport2, hash2, payloadBytes, compressedBuffer, compressedLength, pendingTransfer.TransferKind == 1, roleEpoch); string successLogMessage = ((pendingTransfer.TransferKind == 1) ? ("Fetched synchronized " + transport2.DisplayName + " delta payload '" + hash2 + "' from the server.") : ("Fetched synchronized " + transport2.DisplayName + " payload '" + hash2 + "' from the server.")); QueueMainThreadPayloadCommitLocked(delegate { CommitProcessedPayloadLocked(transport2, version, hash2, payloadBytes, entries, payloadIndex, entries?.Count, successLogMessage); }, roleEpoch); } catch (Exception ex2) { Exception ex3 = ex2; Exception ex = ex3; QueueMainThreadPayloadCommitLocked(delegate { lock (Sync) { if (IsProcessingResultCurrentLocked(transport2, version, hash2)) { transport2.ProcessingInFlight = false; transport2.ProcessingHash = ""; if (pendingTransfer.TransferKind == 1) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("Failed to apply synchronized " + transport2.DisplayName + " delta payload '" + hash2 + "'. Retrying as a full payload. " + ex.Message)); TryRequestFullFallbackOnceLocked(transport2, hash2, "source=delta_apply error=" + ex.Message); } else if (pendingTransfer.IsFullFallbackRequest) { BlockManifestLocked(transport2, hash2, "source=full_after_delta_fallback error=" + ex.Message + " fullFallbackAttempted=true"); } else { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("Failed to assemble synchronized " + transport2.DisplayName + " payload '" + hash2 + "'. Retrying. " + ex.Message)); EnsurePayloadRequestedLocked(transport2, transport2.DesiredPayloadManifest, ""); } } } }, roleEpoch); } }, roleEpoch); } private static void ClearAvailablePayloadLocked(DomainTransport transport, bool deleteCacheFile = false) { string availableHash = transport.AvailableHash; transport.AvailableHash = ""; transport.AvailablePayloadBytes = null; transport.AvailableEntries = null; transport.AvailablePayloadIndex = null; if (deleteCacheFile && !string.IsNullOrWhiteSpace(availableHash)) { DeleteCacheFileIfPresent(transport.CacheDirectoryName, availableHash); } } private static void InvalidateMalformedAvailablePayloadLocked(DomainTransport transport, string hash, string reason, Exception? ex = null) { ClearAvailablePayloadLocked(transport, deleteCacheFile: true); if (!string.IsNullOrWhiteSpace(hash) && string.Equals(transport.DesiredPayloadManifest.Hash, hash, StringComparison.Ordinal)) { BlockManifestLocked(transport, hash, reason); return; } string text = ((ex == null) ? "" : $" {ex}"); DropNSpawnPlugin.DropNSpawnLogger.LogError((object)("Failed to deserialize in-memory synchronized " + transport.DisplayName + " payload '" + hash + "'. Clearing the cached client payload state." + text)); } private static void ClearInvalidManifestLocked(DomainTransport transport) { transport.InvalidDesiredManifest = ""; } private static bool TryPreserveLastKnownGoodOnInvalidManifestLocked(DomainTransport transport, string? manifestRaw, out List entries, out string payloadToken, out bool shouldLog) { string text = manifestRaw ?? ""; shouldLog = !string.Equals(transport.InvalidDesiredManifest, text, StringComparison.Ordinal); transport.InvalidDesiredManifest = text; transport.DesiredManifest = text; transport.DesiredPayloadManifest = new PayloadManifest(); ClearBlockedManifestLocked(transport); ClearPendingInboundTransferLocked(transport); transport.LastWaitingLogHash = ""; transport.ProcessingInFlight = false; transport.ProcessingHash = ""; transport.ProcessingVersion++; if (TryGetAvailableEntriesLocked(transport, out entries)) { payloadToken = transport.AvailableHash; return true; } entries = new List(); payloadToken = transport.AvailableHash; return false; } private static void ClearBlockedManifestLocked(DomainTransport transport) { transport.BlockedManifestHash = ""; transport.BlockedManifestReason = ""; } private static void RefreshBlockedManifestForDesiredHashLocked(DomainTransport transport, string desiredHash) { if (string.IsNullOrWhiteSpace(desiredHash) || !string.Equals(transport.BlockedManifestHash, desiredHash, StringComparison.Ordinal)) { ClearBlockedManifestLocked(transport); } if (string.IsNullOrWhiteSpace(desiredHash) || !string.Equals(transport.FullFallbackAttemptedHash, desiredHash, StringComparison.Ordinal)) { transport.FullFallbackAttemptedHash = ""; } } private static bool IsManifestBlockedLocked(DomainTransport transport, string hash) { if (!string.IsNullOrWhiteSpace(hash)) { return string.Equals(transport.BlockedManifestHash, hash, StringComparison.Ordinal); } return false; } private static void BlockManifestLocked(DomainTransport transport, string hash, string reason) { transport.ProcessingInFlight = false; transport.ProcessingHash = ""; transport.ProcessingVersion++; ClearPendingInboundTransferLocked(transport); transport.RequestInFlight = false; transport.RequestStartedAt = 0f; transport.LastWaitingLogHash = hash ?? ""; transport.BlockedManifestHash = hash ?? ""; transport.BlockedManifestReason = reason ?? ""; DeleteCacheFileIfPresent(transport.CacheDirectoryName, hash ?? ""); DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("Synchronized " + transport.DisplayName + " payload '" + hash + "' is blocked until the server publishes a different manifest. desiredHash=" + ((transport.DesiredPayloadManifest.Hash.Length > 0) ? transport.DesiredPayloadManifest.Hash : "") + " reason=" + reason)); } private static void HandleManifestChanged(DomainTransport transport, string? manifestRaw) { lock (Sync) { EnsureRpcRegisteredLocked(); if (!PayloadManifest.TryParse(manifestRaw, out PayloadManifest manifest)) { List entries; string payloadToken; bool shouldLog; bool flag = TryPreserveLastKnownGoodOnInvalidManifestLocked(transport, manifestRaw, out entries, out payloadToken, out shouldLog); if (shouldLog) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("Received invalid synchronized " + transport.DisplayName + " payload manifest '" + manifestRaw + "'. Keeping the last known good client payload state.")); } if (flag) { QueueReloadActionLocked(transport); } return; } ClearInvalidManifestLocked(transport); transport.DesiredManifest = manifestRaw ?? ""; transport.DesiredPayloadManifest = manifest; RefreshBlockedManifestForDesiredHashLocked(transport, manifest.Hash); CancelProcessingIfHashMismatchLocked(transport, manifest.Hash); NotifyTransportManifestSeenLocked(transport, manifest); if (manifest.IsEmpty) { transport.AvailableHash = ""; transport.AvailablePayloadBytes = null; transport.AvailableEntries = null; transport.AvailablePayloadIndex = null; ClearPendingInboundTransferLocked(transport); transport.LastWaitingLogHash = ""; transport.ProcessingInFlight = false; transport.ProcessingHash = ""; transport.ProcessingVersion++; QueueReloadActionLocked(transport); } else if (string.Equals(transport.AvailableHash, manifest.Hash, StringComparison.Ordinal) && transport.AvailablePayloadBytes != null) { QueueReloadActionLocked(transport); } else if (!IsManifestBlockedLocked(transport, manifest.Hash) && !TryScheduleCachedPayloadLoadLocked(transport, manifest) && EnsurePayloadRequestedLocked(transport, manifest)) { transport.LastWaitingLogHash = manifest.Hash; DropNSpawnPlugin.DropNSpawnLogger.LogDebug((object)("Requesting synchronized " + transport.DisplayName + " payload '" + manifest.Hash + "' from the server.")); } } } private static void NotifyTransportManifestSeenLocked(DomainTransport transport, PayloadManifest manifest) { transport.Metadata.Hooks.OnManifestSeen(manifest.IsEmpty, manifest.Hash, manifest.CompressedSize, manifest.ChunkCount, manifest.EntryCount); } private static bool TryScheduleCachedPayloadLoadLocked(DomainTransport transport, PayloadManifest manifest) { DomainTransport transport2 = transport; PayloadManifest manifest2 = manifest; if (manifest2.IsEmpty) { return false; } if (IsManifestBlockedLocked(transport2, manifest2.Hash)) { return false; } if (transport2.ProcessingInFlight && string.Equals(transport2.ProcessingHash, manifest2.Hash, StringComparison.Ordinal)) { return true; } if (!File.Exists(GetCachePath(transport2.CacheDirectoryName, manifest2.Hash))) { return false; } int version = ++transport2.ProcessingVersion; transport2.ProcessingInFlight = true; transport2.ProcessingHash = manifest2.Hash; int roleEpoch = _networkRoleEpoch; QueueCriticalPayloadProcessingJobLocked(delegate { try { if (!TryReadCachedPayloadBytes(transport2.CacheDirectoryName, transport2.DisplayName, manifest2.Hash, out byte[] payloadBytes, out byte[] _)) { QueueMainThreadPayloadCommitLocked(delegate { lock (Sync) { if (IsProcessingResultCurrentLocked(transport2, version, manifest2.Hash)) { transport2.ProcessingInFlight = false; transport2.ProcessingHash = ""; if (EnsurePayloadRequestedLocked(transport2, transport2.DesiredPayloadManifest)) { transport2.LastWaitingLogHash = manifest2.Hash; DropNSpawnPlugin.DropNSpawnLogger.LogDebug((object)("Requesting synchronized " + transport2.DisplayName + " payload '" + manifest2.Hash + "' from the server.")); } } } }, roleEpoch); } else { QueueMainThreadPayloadCommitLocked(delegate { CommitProcessedPayloadLocked(transport2, version, manifest2.Hash, payloadBytes, null, null, null, "Loaded synchronized " + transport2.DisplayName + " payload '" + manifest2.Hash + "' from cache."); }, roleEpoch); } } catch (Exception ex2) { Exception ex3 = ex2; Exception ex = ex3; QueueMainThreadPayloadCommitLocked(delegate { lock (Sync) { if (IsProcessingResultCurrentLocked(transport2, version, manifest2.Hash)) { transport2.ProcessingInFlight = false; transport2.ProcessingHash = ""; DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("Failed to read cached " + transport2.DisplayName + " payload '" + manifest2.Hash + "'. " + ex.Message)); if (EnsurePayloadRequestedLocked(transport2, transport2.DesiredPayloadManifest)) { transport2.LastWaitingLogHash = manifest2.Hash; DropNSpawnPlugin.DropNSpawnLogger.LogDebug((object)("Requesting synchronized " + transport2.DisplayName + " payload '" + manifest2.Hash + "' from the server.")); } } } }, roleEpoch); } }, roleEpoch); return true; } private static void CancelProcessingIfHashMismatchLocked(DomainTransport transport, string desiredHash) { if (transport.ProcessingInFlight && !string.Equals(transport.ProcessingHash, desiredHash, StringComparison.Ordinal)) { transport.ProcessingInFlight = false; transport.ProcessingHash = ""; transport.ProcessingVersion++; } } private static void QueueCriticalPayloadProcessingJobLocked(Action job) { QueueCriticalPayloadProcessingJobLocked(job, _networkRoleEpoch); } private static void QueueCriticalPayloadProcessingJobLocked(Action job, int roleEpoch) { PendingCriticalPayloadProcessingJobs.Enqueue(new PendingPayloadProcessingJob { RoleEpoch = roleEpoch, Action = job }); EnsurePayloadProcessingWorkersLocked(); } private static void QueueDeltaArtifactPrewarmJobLocked(Action job) { QueueDeltaArtifactPrewarmJobLocked(job, _networkRoleEpoch); } private static void QueueDeltaArtifactPrewarmJobLocked(Action job, int roleEpoch) { PendingDeltaArtifactPrewarmJobs.Enqueue(new PendingPayloadProcessingJob { RoleEpoch = roleEpoch, Action = job }); EnsurePayloadProcessingWorkersLocked(); } private static void QueueCachePersistenceJobLocked(Action job) { QueueCachePersistenceJobLocked(job, _networkRoleEpoch); } private static void QueueCachePersistenceJobLocked(Action job, int roleEpoch) { PendingCachePersistenceJobs.Enqueue(new PendingPayloadProcessingJob { RoleEpoch = roleEpoch, Action = job }); EnsurePayloadProcessingWorkersLocked(); } private static void EnsurePayloadProcessingWorkersLocked() { int num = Math.Min(3, PendingCriticalPayloadProcessingJobs.Count + Math.Min(1, PendingDeltaArtifactPrewarmJobs.Count + PendingCachePersistenceJobs.Count)); while (_payloadProcessingWorkersRunning < num) { _payloadProcessingWorkersRunning++; ThreadPool.QueueUserWorkItem(delegate { ProcessPayloadProcessingJobsWorker(); }); } } private static void ProcessPayloadProcessingJobsWorker() { while (true) { Action action = null; lock (Sync) { PendingPayloadProcessingJob item = null; if (!PendingCriticalPayloadProcessingJobs.TryDequeue(out item) && !PendingDeltaArtifactPrewarmJobs.TryDequeue(out item) && !PendingCachePersistenceJobs.TryDequeue(out item)) { _payloadProcessingWorkersRunning = Math.Max(0, _payloadProcessingWorkersRunning - 1); break; } if (item != null && item.RoleEpoch == _networkRoleEpoch) { action = item.Action; } } if (action != null) { try { action(); } catch (Exception ex) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("Unhandled background payload processing failure. " + ex.Message)); } } } } private static bool IsCurrentRoleEpoch(int roleEpoch) { lock (Sync) { return roleEpoch == _networkRoleEpoch; } } private static void QueueMainThreadPayloadCommitLocked(Action action) { QueueMainThreadPayloadCommitLocked(action, _networkRoleEpoch); } private static void QueueMainThreadPayloadCommitLocked(Action action, int roleEpoch) { lock (Sync) { PendingMainThreadPayloadCommits.Enqueue(new PendingMainThreadPayloadCommit { RoleEpoch = roleEpoch, Action = action }); } } private static void QueueReloadActionLocked(DomainTransport transport) { string item = BuildPendingReloadDomainKey(transport.DomainKey, _networkRoleEpoch); if (PendingReloadDomainKeys.Add(item)) { PendingReloadActions.Enqueue(new PendingReloadAction { RoleEpoch = _networkRoleEpoch, DomainKey = transport.DomainKey, Action = transport.ReloadAction }); } } private static bool TryDequeueCurrentMainThreadPayloadCommitLocked(out Action? action) { action = null; PendingMainThreadPayloadCommit item; while (PendingMainThreadPayloadCommits.TryDequeue(out item)) { if (item != null && item.RoleEpoch == _networkRoleEpoch) { action = item.Action; return true; } } return false; } private static bool TryDequeueCurrentReloadActionLocked(out PendingReloadAction? pendingReload) { pendingReload = null; PendingReloadAction item; while (PendingReloadActions.TryDequeue(out item)) { if (item != null) { PendingReloadDomainKeys.Remove(BuildPendingReloadDomainKey(item.DomainKey, item.RoleEpoch)); if (item.RoleEpoch == _networkRoleEpoch) { pendingReload = item; return true; } } } return false; } private static string BuildPendingReloadDomainKey(string domainKey, int roleEpoch) { return roleEpoch.ToString(CultureInfo.InvariantCulture) + ":" + domainKey; } private static void RememberPublishedPayloadLocked(DomainTransport transport, string hash, byte[]? payloadBytes, PayloadEntryIndex? payloadIndex) { if (!string.IsNullOrWhiteSpace(hash) && payloadBytes != null && payloadBytes.Length != 0) { if (!transport.PublishedPayloadHistory.TryGetValue(hash, out PublishedPayloadHistoryEntry value)) { value = new PublishedPayloadHistoryEntry { Hash = hash }; transport.PublishedPayloadHistory[hash] = value; } int estimatedBytes = value.EstimatedBytes; value.PayloadBytes = payloadBytes; value.PayloadIndex = payloadIndex; value.EstimatedBytes = EstimatePublishedPayloadHistoryEntryBytes(hash, payloadBytes, payloadIndex); AdjustPublishedPayloadHistoryBytesLocked(transport, value.EstimatedBytes - estimatedBytes); LinkedListNode node = value.LruNode; TouchLruNodeLocked(transport.PublishedPayloadHistoryLru, hash, ref node); value.LruNode = node; } } private static int EstimatePublishedPayloadHistoryEntryBytes(string hash, byte[] payloadBytes, PayloadEntryIndex? payloadIndex) { return ClampByteEstimate(64L + (long)EstimateStringBytes(hash) + payloadBytes.Length + EstimatePayloadIndexBytes(payloadIndex)); } private static int EstimatePayloadIndexBytes(PayloadEntryIndex? payloadIndex) { if (payloadIndex == null) { return 0; } long num = 64L; num += (long)payloadIndex.OrderedKeys.Count * 24L; foreach (string orderedKey in payloadIndex.OrderedKeys) { num += EstimateStringBytes(orderedKey); } num += (long)payloadIndex.EntriesByKey.Count * 24L; foreach (KeyValuePair item in payloadIndex.EntrySignaturesByKey) { item.Deconstruct(out var key, out var value); string value2 = key; string value3 = value; num += 24L + (long)EstimateStringBytes(value2) + EstimateStringBytes(value3); } return ClampByteEstimate(num); } private static int EstimateTransferArtifactBytes(TransferArtifact artifact) { if (artifact == null) { return 0; } return ClampByteEstimate(64L + (long)EstimateStringBytes(artifact.BaseHash) + EstimateStringBytes(artifact.TargetHash) + artifact.CompressedBytes.Length); } private static int EstimateStringBytes(string? value) { return (value?.Length ?? 0) * 2; } private static int ClampByteEstimate(long estimatedBytes) { if (estimatedBytes > 0) { if (estimatedBytes < int.MaxValue) { return (int)estimatedBytes; } return int.MaxValue; } return 0; } private static int GetTrimTargetBytes(int budgetBytes) { if (budgetBytes <= 0) { return 0; } return Math.Max(0, budgetBytes * 85 / 100); } private static void TouchLruNodeLocked(LinkedList lru, string key, ref LinkedListNode? node) { if (key.Length != 0) { if (node == null || node.List != lru) { node = lru.AddLast(key); } else if (node.Next != null) { lru.Remove(node); lru.AddLast(node); } } } private static void RemoveLruNodeLocked(LinkedList lru, ref LinkedListNode? node) { if (node != null) { if (node.List == lru) { lru.Remove(node); } node = null; } } private static void AdjustPublishedPayloadHistoryBytesLocked(DomainTransport transport, int deltaBytes) { if (deltaBytes != 0) { transport.PublishedPayloadHistoryBytes = Math.Max(0, transport.PublishedPayloadHistoryBytes + deltaBytes); transport.PublishedCacheBytes = Math.Max(0, transport.PublishedCacheBytes + deltaBytes); } } private static void AdjustPublishedTransferArtifactBytesLocked(DomainTransport transport, int deltaBytes) { if (deltaBytes != 0) { transport.PublishedTransferArtifactBytes = Math.Max(0, transport.PublishedTransferArtifactBytes + deltaBytes); transport.PublishedCacheBytes = Math.Max(0, transport.PublishedCacheBytes + deltaBytes); } } private static void RemovePublishedPayloadHistoryEntryLocked(DomainTransport transport, PublishedPayloadHistoryEntry? entry) { if (entry != null) { transport.PublishedPayloadHistory.Remove(entry.Hash); LinkedListNode node = entry.LruNode; RemoveLruNodeLocked(transport.PublishedPayloadHistoryLru, ref node); entry.LruNode = node; AdjustPublishedPayloadHistoryBytesLocked(transport, -entry.EstimatedBytes); } } private static void RemoveTransferArtifactLocked(DomainTransport transport, TransferArtifact? artifact) { if (artifact != null) { transport.PublishedTransferArtifacts.Remove(artifact.CacheKey); LinkedListNode node = artifact.LruNode; RemoveLruNodeLocked(transport.PublishedTransferArtifactLru, ref node); artifact.LruNode = node; AdjustPublishedTransferArtifactBytesLocked(transport, -artifact.EstimatedBytes); } } private static void ClearPublishedPayloadHistoryLocked(DomainTransport transport) { transport.PublishedPayloadHistory.Clear(); transport.PublishedPayloadHistoryLru.Clear(); transport.PublishedCacheBytes = Math.Max(0, transport.PublishedCacheBytes - transport.PublishedPayloadHistoryBytes); transport.PublishedPayloadHistoryBytes = 0; } private static void ClearPublishedTransferArtifactsLocked(DomainTransport transport) { transport.PublishedTransferArtifacts.Clear(); transport.PublishedTransferArtifactLru.Clear(); transport.PublishedCacheBytes = Math.Max(0, transport.PublishedCacheBytes - transport.PublishedTransferArtifactBytes); transport.PublishedTransferArtifactBytes = 0; } private static void ClearPinnedCacheReferencesLocked(DomainTransport transport) { transport.PinnedPayloadHashRefCounts.Clear(); transport.PinnedArtifactKeyRefCounts.Clear(); } private static void IncrementRefCountLocked(Dictionary refCounts, string key) { if (!string.IsNullOrWhiteSpace(key)) { refCounts[key] = ((!refCounts.TryGetValue(key, out var value)) ? 1 : (value + 1)); } } private static void DecrementRefCountLocked(Dictionary refCounts, string key) { if (!string.IsNullOrWhiteSpace(key) && refCounts.TryGetValue(key, out var value)) { if (value <= 1) { refCounts.Remove(key); } else { refCounts[key] = value - 1; } } } private static bool IsPinnedLocked(Dictionary refCounts, string key) { if (key.Length > 0 && refCounts.TryGetValue(key, out var value)) { return value > 0; } return false; } private static bool TryTrimOneTransferArtifactLocked(DomainTransport transport) { int count = transport.PublishedTransferArtifacts.Count; LinkedListNode linkedListNode = transport.PublishedTransferArtifactLru.First; while (linkedListNode != null && count-- > 0) { LinkedListNode linkedListNode2 = linkedListNode; linkedListNode = linkedListNode.Next; string value = linkedListNode2.Value; if (!transport.PublishedTransferArtifacts.TryGetValue(value, out TransferArtifact value2) || value2 == null) { transport.PublishedTransferArtifactLru.Remove(linkedListNode2); continue; } if (IsPinnedLocked(transport.PinnedArtifactKeyRefCounts, value)) { transport.PublishedTransferArtifactLru.Remove(linkedListNode2); transport.PublishedTransferArtifactLru.AddLast(linkedListNode2); continue; } RemoveTransferArtifactLocked(transport, value2); return true; } return false; } private static bool TryTrimOnePayloadHistoryEntryLocked(DomainTransport transport) { int count = transport.PublishedPayloadHistory.Count; LinkedListNode linkedListNode = transport.PublishedPayloadHistoryLru.First; while (linkedListNode != null && count-- > 0) { LinkedListNode linkedListNode2 = linkedListNode; linkedListNode = linkedListNode.Next; string value = linkedListNode2.Value; if (!transport.PublishedPayloadHistory.TryGetValue(value, out PublishedPayloadHistoryEntry value2) || value2 == null) { transport.PublishedPayloadHistoryLru.Remove(linkedListNode2); continue; } if (IsPinnedLocked(transport.PinnedPayloadHashRefCounts, value)) { transport.PublishedPayloadHistoryLru.Remove(linkedListNode2); transport.PublishedPayloadHistoryLru.AddLast(linkedListNode2); continue; } RemovePublishedPayloadHistoryEntryLocked(transport, value2); return true; } return false; } private static void TrimTransportCachesLocked(DomainTransport transport) { int publishedCacheBudgetBytes = transport.PublishedCacheBudgetBytes; if (publishedCacheBudgetBytes > 0 && transport.PublishedCacheBytes > publishedCacheBudgetBytes) { int trimTargetBytes = GetTrimTargetBytes(publishedCacheBudgetBytes); int num = transport.PublishedPayloadHistory.Count + transport.PublishedTransferArtifacts.Count; while (transport.PublishedCacheBytes > trimTargetBytes && num-- > 0 && (TryTrimOneTransferArtifactLocked(transport) || TryTrimOnePayloadHistoryEntryLocked(transport))) { } } } private static int GetTotalPublishedCacheBytesLocked() { int num = 0; IDomainTransport[] allTransports = AllTransports; foreach (IDomainTransport domainTransport in allTransports) { num += domainTransport.PublishedCacheBytes; } return num; } private static bool TryTrimAnyTransportCacheOnceLocked() { foreach (IDomainTransport item in AllTransports.OrderByDescending((IDomainTransport transport) => transport.PublishedCacheBytes)) { if (item.PublishedCacheBytes > 0 && item.TryTrimPublishedCacheOnce()) { return true; } } return false; } private static bool TryTrimTransportCacheOnceLocked(DomainTransport transport) { if (!TryTrimOneTransferArtifactLocked(transport)) { return TryTrimOnePayloadHistoryEntryLocked(transport); } return true; } private static void TrimAllPublishedCachesLocked() { int totalPublishedCacheBytesLocked = GetTotalPublishedCacheBytesLocked(); if (totalPublishedCacheBytesLocked > 67108864) { int trimTargetBytes = GetTrimTargetBytes(67108864); int num = 0; IDomainTransport[] allTransports = AllTransports; foreach (IDomainTransport domainTransport in allTransports) { num += domainTransport.PublishedPayloadHistoryItemCount + domainTransport.PublishedTransferArtifactCount; } while (totalPublishedCacheBytesLocked > trimTargetBytes && num-- > 0 && TryTrimAnyTransportCacheOnceLocked()) { totalPublishedCacheBytesLocked = GetTotalPublishedCacheBytesLocked(); } } } private static bool BuildPayloadIndex(DomainTransport transport, List entries, string payloadHash, out PayloadEntryIndex? payloadIndex) { payloadIndex = new PayloadEntryIndex(); foreach (TEntry entry in entries) { string text = transport.KeySelector(entry); if (text.Length == 0) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("Skipping synchronized " + transport.DisplayName + " delta support for payload '" + payloadHash + "' because it contains an empty entry key.")); payloadIndex = null; return false; } if (payloadIndex.EntriesByKey.ContainsKey(text)) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("Skipping synchronized " + transport.DisplayName + " delta support for payload '" + payloadHash + "' because it contains duplicate key '" + text + "'.")); payloadIndex = null; return false; } payloadIndex.OrderedKeys.Add(text); payloadIndex.EntriesByKey[text] = entry; payloadIndex.EntrySignaturesByKey[text] = transport.EntrySignatureBuilder(entry); } return true; } private static bool TryEnsurePayloadIndex(DomainTransport transport, string payloadHash, byte[] payloadBytes, PayloadEntryIndex? existingIndex, out PayloadEntryIndex? payloadIndex) { if (existingIndex != null) { payloadIndex = existingIndex; return true; } List entries = transport.Deserializer(payloadBytes); return BuildPayloadIndex(transport, entries, payloadHash, out payloadIndex); } private static bool TryBuildDeltaPayloadBytes(DomainTransport transport, string baseHash, string targetHash, PayloadEntryIndex basePayloadIndex, PayloadEntryIndex targetPayloadIndex, out byte[] deltaPayloadBytes) { //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Expected O, but got Unknown List list = new List(targetPayloadIndex.OrderedKeys.Count); HashSet hashSet = new HashSet(StringComparer.OrdinalIgnoreCase); List list2 = new List(); foreach (string orderedKey in targetPayloadIndex.OrderedKeys) { if (!hashSet.Add(orderedKey)) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("Skipping synchronized " + transport.DisplayName + " delta " + baseHash + "->" + targetHash + " because payload '" + targetHash + "' contains duplicate key '" + orderedKey + "'.")); deltaPayloadBytes = Array.Empty(); return false; } list.Add(orderedKey); if (!basePayloadIndex.EntrySignaturesByKey.TryGetValue(orderedKey, out string value) || !targetPayloadIndex.EntrySignaturesByKey.TryGetValue(orderedKey, out string value2) || !string.Equals(value, value2, StringComparison.Ordinal)) { list2.Add(targetPayloadIndex.EntriesByKey[orderedKey]); } } List list3 = new List(); foreach (string orderedKey2 in basePayloadIndex.OrderedKeys) { if (!targetPayloadIndex.EntriesByKey.ContainsKey(orderedKey2)) { list3.Add(orderedKey2); } } int num = list3.Count + list2.Count; if (num == 0) { deltaPayloadBytes = Array.Empty(); return false; } if (targetPayloadIndex.OrderedKeys.Count > 0 && (double)num > Math.Ceiling((float)targetPayloadIndex.OrderedKeys.Count * transport.TransportPolicy.MaxDeltaChangedEntryRatio)) { deltaPayloadBytes = Array.Empty(); return false; } ZPackage val = new ZPackage(); val.Write(1); val.Write(baseHash); val.Write(targetHash); WriteStringList(val, list); WriteStringList(val, list3); val.Write((list2.Count == 0) ? Array.Empty() : transport.Serializer(list2)); deltaPayloadBytes = val.GetArray(); return true; } private static bool TryBuildPrimaryDeltaArtifact(DomainTransport transport, string baseHash, byte[]? basePayloadBytes, PayloadEntryIndex? basePayloadIndex, string targetHash, byte[] targetPayloadBytes, PayloadEntryIndex? targetPayloadIndex, byte[] fullCompressedPayloadBytes, out PayloadEntryIndex? resolvedTargetPayloadIndex, out TransferArtifact? artifact) { resolvedTargetPayloadIndex = targetPayloadIndex; artifact = null; if (!transport.SupportsDeltaTransfers) { return false; } string text = NormalizeBaseHash(baseHash); if (text.Length == 0 || string.IsNullOrWhiteSpace(targetHash) || string.Equals(text, targetHash, StringComparison.Ordinal) || basePayloadBytes == null || basePayloadBytes.Length == 0 || targetPayloadBytes.Length == 0 || fullCompressedPayloadBytes.Length == 0) { return false; } try { if (!TryEnsurePayloadIndex(transport, targetHash, targetPayloadBytes, targetPayloadIndex, out resolvedTargetPayloadIndex) || resolvedTargetPayloadIndex == null) { return false; } if (!TryEnsurePayloadIndex(transport, text, basePayloadBytes, basePayloadIndex, out PayloadEntryIndex payloadIndex) || payloadIndex == null) { return false; } if (!TryBuildDeltaPayloadBytes(transport, text, targetHash, payloadIndex, resolvedTargetPayloadIndex, out byte[] deltaPayloadBytes)) { return false; } byte[] array = CompressBytes(deltaPayloadBytes); if (array.Length == 0 || (float)array.Length >= (float)fullCompressedPayloadBytes.Length * transport.TransportPolicy.MaxDeltaCompressedSizeRatio) { return false; } artifact = new TransferArtifact { CacheKey = BuildTransferArtifactCacheKey(targetHash, text), TransferKind = 1, BaseHash = text, TargetHash = targetHash, CompressedBytes = array, ChunkSizeBytes = transport.ChunkSizeBytes, ChunkCount = Math.Max(1, (int)Math.Ceiling((double)array.Length / (double)transport.ChunkSizeBytes)) }; artifact.EstimatedBytes = EstimateTransferArtifactBytes(artifact); return true; } catch (Exception ex) { DropNSpawnPlugin.DropNSpawnLogger.LogDebug((object)("Failed to prebuild synchronized " + transport.DisplayName + " primary delta artifact '" + text + "->" + targetHash + "'. " + ex.Message)); return false; } } private static byte[] ApplyDeltaPayloadBytes(DomainTransport transport, string baseHash, string targetHash, byte[] deltaPayloadBytes, PayloadEntryIndex? basePayloadIndexSnapshot, byte[]? basePayloadBytesSnapshot, out List mergedEntries) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected O, but got Unknown mergedEntries = new List(); if (string.IsNullOrWhiteSpace(baseHash)) { throw new InvalidDataException("Missing base hash for synchronized " + transport.DisplayName + " delta payload '" + targetHash + "'."); } ZPackage val = new ZPackage(deltaPayloadBytes); int num = val.ReadInt(); if (num != 1) { throw new InvalidDataException($"Unsupported delta payload DTO version '{num}'."); } string text = val.ReadString(); string text2 = val.ReadString(); if (!string.Equals(baseHash, text, StringComparison.Ordinal) || !string.Equals(targetHash, text2, StringComparison.Ordinal)) { throw new InvalidDataException("Synchronized " + transport.DisplayName + " delta payload hash mismatch. Expected " + baseHash + "->" + targetHash + " but got " + text + "->" + text2 + "."); } List list = ReadStringList(val) ?? new List(); List list2 = ReadStringList(val) ?? new List(); byte[] array = val.ReadByteArray(); List list3 = ((array.Length == 0) ? new List() : transport.Deserializer(array)); Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); if (basePayloadIndexSnapshot != null) { foreach (KeyValuePair item in basePayloadIndexSnapshot.EntriesByKey) { dictionary[item.Key] = item.Value; } } else { byte[] payloadBytes = basePayloadBytesSnapshot ?? Array.Empty(); if (payloadBytes.Length == 0 && !TryReadCachedPayloadBytes(transport.CacheDirectoryName, transport.DisplayName, baseHash, out payloadBytes, out byte[] _)) { throw new InvalidDataException("Missing cached base payload '" + baseHash + "' required to apply synchronized " + transport.DisplayName + " delta '" + targetHash + "'."); } foreach (TEntry item2 in transport.Deserializer(payloadBytes)) { dictionary[transport.KeySelector(item2)] = item2; } } foreach (string item3 in list2) { dictionary.Remove(item3); } foreach (TEntry item4 in list3) { dictionary[transport.KeySelector(item4)] = item4; } mergedEntries = new List(list.Count); foreach (string item5 in list) { if (!dictionary.TryGetValue(item5, out var value)) { throw new InvalidDataException("Synchronized " + transport.DisplayName + " delta payload '" + targetHash + "' is missing ordered entry '" + item5 + "'."); } mergedEntries.Add(value); } return transport.Serializer(mergedEntries); } private static void EnsureRpcRegisteredLocked() { if (!((Object)(object)_host == (Object)null) && ZRoutedRpc.instance != null && _registeredRpc != ZRoutedRpc.instance) { ZRoutedRpc.instance.Register("DropNSpawn Payload Request", (Action)RPC_RequestPayload); ZRoutedRpc.instance.Register("DropNSpawn Payload Chunk", (Action)RPC_ReceivePayloadChunk); _registeredRpc = ZRoutedRpc.instance; } } private static bool IsOutboundTransferPeerReady(long sender) { if (sender == 0L) { return true; } ZNet instance = ZNet.instance; if (instance == null) { return false; } ZNetPeer peer = instance.GetPeer(sender); return ((peer != null) ? new bool?(peer.IsReady()) : null).GetValueOrDefault(); } private static bool IsOutboundTransferRequestEquivalent(OutboundTransferState state, string hash, long requestId, TransferArtifact artifact) { if (state != null && state.RequestId == requestId && string.Equals(state.Hash, hash, StringComparison.Ordinal) && state.Artifact != null && string.Equals(state.Artifact.TargetHash, artifact.TargetHash, StringComparison.Ordinal) && string.Equals(state.Artifact.BaseHash, artifact.BaseHash, StringComparison.Ordinal)) { return state.Artifact.TransferKind == artifact.TransferKind; } return false; } private static void EnqueueOutboundTransferKeyLocked(OutboundTransferKey key, OutboundTransferState state) { if (!state.IsQueued) { PendingOutboundTransferKeys.Enqueue(key); state.IsQueued = true; } } private static void UpdatePinnedOutboundTransferReferencesLocked(DomainTransport transport, OutboundTransferState? previousState, OutboundTransferState? nextState) { if (previousState != null) { DecrementRefCountLocked(transport.PinnedPayloadHashRefCounts, previousState.Hash); if (previousState.Artifact != null) { DecrementRefCountLocked(transport.PinnedPayloadHashRefCounts, previousState.Artifact.BaseHash); DecrementRefCountLocked(transport.PinnedArtifactKeyRefCounts, (previousState.Artifact.CacheKey.Length > 0) ? previousState.Artifact.CacheKey : BuildTransferArtifactCacheKey(previousState.Hash, previousState.Artifact.BaseHash)); } } if (nextState != null) { IncrementRefCountLocked(transport.PinnedPayloadHashRefCounts, nextState.Hash); if (nextState.Artifact != null) { IncrementRefCountLocked(transport.PinnedPayloadHashRefCounts, nextState.Artifact.BaseHash); IncrementRefCountLocked(transport.PinnedArtifactKeyRefCounts, (nextState.Artifact.CacheKey.Length > 0) ? nextState.Artifact.CacheKey : BuildTransferArtifactCacheKey(nextState.Hash, nextState.Artifact.BaseHash)); } } } private static void UpdatePinnedOutboundTransferReferencesForDomainLocked(string domainKey, OutboundTransferState? previousState, OutboundTransferState? nextState) { if (!string.IsNullOrWhiteSpace(domainKey) && TransportsByDomainKey.TryGetValue(domainKey, out IDomainTransport value)) { value.UpdatePinnedOutboundTransferReferences(previousState, nextState); } } private static void RemoveActiveOutboundTransferLocked(OutboundTransferKey key) { if (ActiveOutboundTransfers.TryGetValue(key, out OutboundTransferState value) && value != null) { UpdatePinnedOutboundTransferReferencesForDomainLocked(key.DomainKey, value, null); } ActiveOutboundTransfers.Remove(key); } private static void UpsertOutboundTransferLocked(string domainKey, long sender, string hash, long requestId, TransferArtifact artifact) { if (artifact == null) { return; } OutboundTransferKey key = new OutboundTransferKey(sender, domainKey); float realtimeSinceStartup = Time.realtimeSinceStartup; if (ActiveOutboundTransfers.TryGetValue(key, out OutboundTransferState value)) { if (value.RoleEpoch != _networkRoleEpoch || !IsOutboundTransferPeerReady(sender)) { RemoveActiveOutboundTransferLocked(key); } else { if (IsOutboundTransferRequestEquivalent(value, hash, requestId, artifact)) { value.LastRequestedAt = realtimeSinceStartup; EnqueueOutboundTransferKeyLocked(key, value); return; } if (requestId != 0L && value.RequestId != 0L && requestId < value.RequestId) { return; } } } OutboundTransferState outboundTransferState = new OutboundTransferState { RoleEpoch = _networkRoleEpoch, Hash = (hash ?? ""), RequestId = requestId, Artifact = artifact, NextChunkIndex = 0, IsQueued = (value?.IsQueued ?? false), LastRequestedAt = realtimeSinceStartup }; UpdatePinnedOutboundTransferReferencesForDomainLocked(domainKey, value, outboundTransferState); ActiveOutboundTransfers[key] = outboundTransferState; EnqueueOutboundTransferKeyLocked(key, outboundTransferState); } private static void RPC_RequestPayload(long sender, ZPackage package) { if (!DropNSpawnPlugin.IsSourceOfTruth) { return; } string text = package.ReadString(); string text2 = package.ReadString(); string baseHash = package.ReadString(); long requestId = ((package.GetPos() < package.Size()) ? package.ReadLong() : 0); if (string.IsNullOrWhiteSpace(text) || string.IsNullOrWhiteSpace(text2)) { return; } lock (Sync) { EnsureRpcRegisteredLocked(); if (TransportsByDomainKey.TryGetValue(text, out IDomainTransport value)) { value.EnqueuePublishedPayloadChunks(sender, text2, baseHash, requestId); } } } private static bool TryPrepareOutboundChunkForSendLocked(out PreparedOutboundChunk? preparedChunk) { preparedChunk = null; OutboundTransferKey item; while (PendingOutboundTransferKeys.TryDequeue(out item)) { if (!ActiveOutboundTransfers.TryGetValue(item, out OutboundTransferState value) || value == null) { continue; } value.IsQueued = false; if (value.RoleEpoch != _networkRoleEpoch || !IsOutboundTransferPeerReady(item.Sender)) { RemoveActiveOutboundTransferLocked(item); continue; } if (value.Artifact == null || value.NextChunkIndex < 0 || value.NextChunkIndex >= value.Artifact.ChunkCount) { RemoveActiveOutboundTransferLocked(item); continue; } int num = Math.Max(1, value.Artifact.ChunkSizeBytes); int num2 = value.NextChunkIndex * num; int num3 = value.Artifact.CompressedBytes.Length - num2; if (num3 <= 0) { RemoveActiveOutboundTransferLocked(item); continue; } int num4 = Math.Min(num, num3); if (_outboundBytesSentThisFrame + num4 > num * 2) { EnqueueOutboundTransferKeyLocked(item, value); return false; } preparedChunk = new PreparedOutboundChunk { Key = item, RoleEpoch = value.RoleEpoch, RequestId = value.RequestId, SourceBytes = value.Artifact.CompressedBytes, ChunkOffset = num2, ChunkLength = num4, Message = new OutboundChunkMessage { Sender = item.Sender, DomainKey = item.DomainKey, Hash = value.Hash, RequestId = value.RequestId, TransferKind = value.Artifact.TransferKind, BaseHash = value.Artifact.BaseHash, ChunkIndex = value.NextChunkIndex, ChunkCount = value.Artifact.ChunkCount, CompressedSize = value.Artifact.CompressedBytes.Length } }; return true; } return false; } private static void FinalizePreparedOutboundChunkLocked(PreparedOutboundChunk preparedChunk, bool sent) { if (preparedChunk == null || preparedChunk.RoleEpoch != _networkRoleEpoch || !DropNSpawnPlugin.IsSourceOfTruth || !ActiveOutboundTransfers.TryGetValue(preparedChunk.Key, out OutboundTransferState value) || value == null || value.RoleEpoch != _networkRoleEpoch || value.RequestId != preparedChunk.RequestId) { return; } if (!IsOutboundTransferPeerReady(preparedChunk.Key.Sender)) { RemoveActiveOutboundTransferLocked(preparedChunk.Key); return; } if (!sent) { EnqueueOutboundTransferKeyLocked(preparedChunk.Key, value); return; } _outboundBytesSentThisFrame += preparedChunk.ChunkLength; value.NextChunkIndex++; if (value.Artifact != null && value.NextChunkIndex < value.Artifact.ChunkCount) { EnqueueOutboundTransferKeyLocked(preparedChunk.Key, value); } else { RemoveActiveOutboundTransferLocked(preparedChunk.Key); } } private static bool SendOutboundChunk(PreparedOutboundChunk preparedChunk) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown if (ZRoutedRpc.instance == null) { return false; } OutboundChunkMessage message = preparedChunk.Message; ZPackage val = new ZPackage(); val.Write(message.DomainKey); val.Write(message.Hash); val.Write(message.TransferKind); val.Write(message.BaseHash); val.Write(message.ChunkIndex); val.Write(message.ChunkCount); val.Write(message.CompressedSize); WriteChunkBytes(val, preparedChunk.SourceBytes, preparedChunk.ChunkOffset, preparedChunk.ChunkLength); val.Write(message.RequestId); ZRoutedRpc.instance.InvokeRoutedRPC(message.Sender, "DropNSpawn Payload Chunk", new object[1] { val }); return true; } private static void WriteChunkBytes(ZPackage package, byte[] sourceBytes, int offset, int count) { if (count <= 0) { package.Write(Array.Empty()); } else if (ZPackageWriterField?.GetValue(package) is BinaryWriter binaryWriter) { package.Write(count); binaryWriter.Write(sourceBytes, offset, count); } else { byte[] array = new byte[count]; Buffer.BlockCopy(sourceBytes, offset, array, 0, count); package.Write(array); } } private static void RPC_ReceivePayloadChunk(long sender, ZPackage package) { if (DropNSpawnPlugin.IsSourceOfTruth || !IsServerRoutedSender(sender)) { return; } string key = package.ReadString(); string hash = package.ReadString(); int transferKind = package.ReadInt(); string baseHash = package.ReadString(); int chunkIndex = package.ReadInt(); int chunkCount = package.ReadInt(); int compressedSize = package.ReadInt(); byte[] chunkBytes = package.ReadByteArray(); long requestId = package.ReadLong(); lock (Sync) { EnsureRpcRegisteredLocked(); if (TransportsByDomainKey.TryGetValue(key, out IDomainTransport value)) { value.ReceivePayloadChunk(sender, hash, requestId, transferKind, baseHash, chunkIndex, chunkCount, compressedSize, chunkBytes); } } } private static bool TryGetCurrentServerRoutedSender(out long sender) { sender = 0L; if (ZRoutedRpc.instance == null || (Object)(object)ZNet.instance == (Object)null) { return false; } if (ZNet.instance.IsServer()) { sender = RoutedRpcIdRef.Invoke(ZRoutedRpc.instance); return sender != 0; } ZNetPeer serverPeer = ZNet.instance.GetServerPeer(); if (serverPeer == null) { return false; } sender = serverPeer.m_uid; return sender != 0; } private static bool IsServerRoutedSender(long sender) { if (TryGetCurrentServerRoutedSender(out var sender2)) { return sender2 == sender; } return false; } private static EntryTransportSchema CreateObjectEntrySchema() { return new EntryTransportSchema(ObjectDropManager.TransportMetadata.DtoVersion, () => new PrefabConfigurationEntry(), StringField((PrefabConfigurationEntry entry) => entry.RuleId, delegate(PrefabConfigurationEntry entry, string value) { entry.RuleId = value; }, (EntrySignatureContext context) => context.IncludeRuleId), StringField((PrefabConfigurationEntry entry) => entry.Prefab, delegate(PrefabConfigurationEntry entry, string value) { entry.Prefab = value; }), BoolField((PrefabConfigurationEntry entry) => entry.Enabled, delegate(PrefabConfigurationEntry entry, bool value) { entry.Enabled = value; }), OptionalField((PrefabConfigurationEntry entry) => entry.Conditions, delegate(PrefabConfigurationEntry entry, ConditionsDefinition? value) { entry.Conditions = value; }, ConditionsValueCodec), OptionalField((PrefabConfigurationEntry entry) => entry.DropOnDestroyed, delegate(PrefabConfigurationEntry entry, DropTableDefinition? value) { entry.DropOnDestroyed = value; }, DropTableValueCodec), OptionalField((PrefabConfigurationEntry entry) => entry.MineRock, delegate(PrefabConfigurationEntry entry, DamageableDropTableDefinition? value) { entry.MineRock = value; }, DamageableDropTableValueCodec), OptionalField((PrefabConfigurationEntry entry) => entry.MineRock5, delegate(PrefabConfigurationEntry entry, DamageableDropTableDefinition? value) { entry.MineRock5 = value; }, DamageableDropTableValueCodec), OptionalField((PrefabConfigurationEntry entry) => entry.TreeBase, delegate(PrefabConfigurationEntry entry, DamageableDropTableDefinition? value) { entry.TreeBase = value; }, DamageableDropTableValueCodec), OptionalField((PrefabConfigurationEntry entry) => entry.TreeLog, delegate(PrefabConfigurationEntry entry, DamageableDropTableDefinition? value) { entry.TreeLog = value; }, DamageableDropTableValueCodec), OptionalField((PrefabConfigurationEntry entry) => entry.Container, delegate(PrefabConfigurationEntry entry, DropTableDefinition? value) { entry.Container = value; }, DropTableValueCodec), OptionalField((PrefabConfigurationEntry entry) => entry.Pickable, delegate(PrefabConfigurationEntry entry, PickableDefinition? value) { entry.Pickable = value; }, PickableValueCodec), OptionalField((PrefabConfigurationEntry entry) => entry.PickableItem, delegate(PrefabConfigurationEntry entry, PickableItemDefinition? value) { entry.PickableItem = value; }, PickableItemValueCodec), OptionalField((PrefabConfigurationEntry entry) => entry.Fish, delegate(PrefabConfigurationEntry entry, FishDefinition? value) { entry.Fish = value; }, FishValueCodec), OptionalField((PrefabConfigurationEntry entry) => entry.Destructible, delegate(PrefabConfigurationEntry entry, DestructibleDefinition? value) { entry.Destructible = value; }, DestructibleValueCodec), CopyOnlyField(delegate(PrefabConfigurationEntry source, PrefabConfigurationEntry target) { target.SourcePath = source.SourcePath; }), CopyOnlyField(delegate(PrefabConfigurationEntry source, PrefabConfigurationEntry target) { target.SourceLine = source.SourceLine; }), CopyOnlyField(delegate(PrefabConfigurationEntry source, PrefabConfigurationEntry target) { target.SourceColumn = source.SourceColumn; })); } private static EntryTransportSchema CreateCharacterEntrySchema() { return new EntryTransportSchema(CharacterDropManager.TransportMetadata.DtoVersion, () => new CharacterDropPrefabEntry(), StringField((CharacterDropPrefabEntry entry) => entry.RuleId, delegate(CharacterDropPrefabEntry entry, string value) { entry.RuleId = value; }, (EntrySignatureContext context) => context.IncludeRuleId), StringField((CharacterDropPrefabEntry entry) => entry.Prefab, delegate(CharacterDropPrefabEntry entry, string value) { entry.Prefab = value; }), BoolField((CharacterDropPrefabEntry entry) => entry.Enabled, delegate(CharacterDropPrefabEntry entry, bool value) { entry.Enabled = value; }), OptionalField((CharacterDropPrefabEntry entry) => entry.Conditions, delegate(CharacterDropPrefabEntry entry, ConditionsDefinition? value) { entry.Conditions = value; }, ConditionsValueCodec), OptionalField((CharacterDropPrefabEntry entry) => entry.CharacterDrop, delegate(CharacterDropPrefabEntry entry, CharacterDropDefinition? value) { entry.CharacterDrop = value; }, CharacterDropValueCodec), OptionalField((CharacterDropPrefabEntry entry) => entry.Despawn, delegate(CharacterDropPrefabEntry entry, DespawnDefinition? value) { entry.Despawn = value; }, DespawnValueCodec), OptionalField((CharacterDropPrefabEntry entry) => entry.BossTamedPressure, delegate(CharacterDropPrefabEntry entry, BossTamedPressureDefinition? value) { entry.BossTamedPressure = value; }, BossTamedPressureValueCodec), CopyOnlyField(delegate(CharacterDropPrefabEntry source, CharacterDropPrefabEntry target) { target.SourcePath = source.SourcePath; }), CopyOnlyField(delegate(CharacterDropPrefabEntry source, CharacterDropPrefabEntry target) { target.SourceLine = source.SourceLine; }), CopyOnlyField(delegate(CharacterDropPrefabEntry source, CharacterDropPrefabEntry target) { target.SourceColumn = source.SourceColumn; })); } private static EntryTransportSchema CreateSpawnerEntrySchema() { return new EntryTransportSchema(SpawnerManager.TransportMetadata.DtoVersion, () => new SpawnerConfigurationEntry(), StringField((SpawnerConfigurationEntry entry) => entry.RuleId, delegate(SpawnerConfigurationEntry entry, string value) { entry.RuleId = value; }, (EntrySignatureContext context) => context.IncludeRuleId), StringField((SpawnerConfigurationEntry entry) => entry.Prefab, delegate(SpawnerConfigurationEntry entry, string value) { entry.Prefab = value; }), BoolField((SpawnerConfigurationEntry entry) => entry.Enabled, delegate(SpawnerConfigurationEntry entry, bool value) { entry.Enabled = value; }), NullableStringField((SpawnerConfigurationEntry entry) => entry.Location, delegate(SpawnerConfigurationEntry entry, string? value) { entry.Location = value; }), OptionalField((SpawnerConfigurationEntry entry) => entry.Conditions, delegate(SpawnerConfigurationEntry entry, ConditionsDefinition? value) { entry.Conditions = value; }, ConditionsValueCodec), OptionalField((SpawnerConfigurationEntry entry) => entry.SpawnArea, delegate(SpawnerConfigurationEntry entry, SpawnAreaDefinition? value) { entry.SpawnArea = value; }, SpawnAreaValueCodec), OptionalField((SpawnerConfigurationEntry entry) => entry.CreatureSpawner, delegate(SpawnerConfigurationEntry entry, CreatureSpawnerDefinition? value) { entry.CreatureSpawner = value; }, CreatureSpawnerValueCodec), CopyOnlyField(delegate(SpawnerConfigurationEntry source, SpawnerConfigurationEntry target) { target.SourcePath = source.SourcePath; }), CopyOnlyField(delegate(SpawnerConfigurationEntry source, SpawnerConfigurationEntry target) { target.SourceLine = source.SourceLine; }), CopyOnlyField(delegate(SpawnerConfigurationEntry source, SpawnerConfigurationEntry target) { target.SourceColumn = source.SourceColumn; })); } private static EntryTransportSchema CreateLocationEntrySchema() { return new EntryTransportSchema(LocationManager.TransportMetadata.DtoVersion, () => new LocationConfigurationEntry(), StringField((LocationConfigurationEntry entry) => entry.RuleId, delegate(LocationConfigurationEntry entry, string value) { entry.RuleId = value; }, (EntrySignatureContext context) => context.IncludeRuleId), StringField((LocationConfigurationEntry entry) => entry.Prefab, delegate(LocationConfigurationEntry entry, string value) { entry.Prefab = value; }), BoolField((LocationConfigurationEntry entry) => entry.Enabled, delegate(LocationConfigurationEntry entry, bool value) { entry.Enabled = value; }), OptionalField((LocationConfigurationEntry entry) => entry.Conditions, delegate(LocationConfigurationEntry entry, ConditionsDefinition? value) { entry.Conditions = value; }, ConditionsValueCodec), OptionalField((LocationConfigurationEntry entry) => entry.OfferingBowl, delegate(LocationConfigurationEntry entry, LocationOfferingBowlDefinition? value) { entry.OfferingBowl = value; }, OfferingBowlValueCodec), ListField((LocationConfigurationEntry entry) => entry.ItemStands, delegate(LocationConfigurationEntry entry, List? value) { entry.ItemStands = value; }, ItemStandValueCodec), ListField((LocationConfigurationEntry entry) => entry.Vegvisirs, delegate(LocationConfigurationEntry entry, List? value) { entry.Vegvisirs = value; }, VegvisirValueCodec), ListField((LocationConfigurationEntry entry) => entry.Runestones, delegate(LocationConfigurationEntry entry, List? value) { entry.Runestones = value; }, RunestoneValueCodec), OptionalField((LocationConfigurationEntry entry) => entry.RunestoneGlobalPins, delegate(LocationConfigurationEntry entry, LocationRunestoneGlobalPinsDefinition? value) { entry.RunestoneGlobalPins = value; }, RunestoneGlobalPinsValueCodec), CopyOnlyField(delegate(LocationConfigurationEntry source, LocationConfigurationEntry target) { target.SourcePath = source.SourcePath; }), CopyOnlyField(delegate(LocationConfigurationEntry source, LocationConfigurationEntry target) { target.SourceLine = source.SourceLine; }), CopyOnlyField(delegate(LocationConfigurationEntry source, LocationConfigurationEntry target) { target.SourceColumn = source.SourceColumn; })); } private static EntryTransportSchema CreateSpawnSystemEntrySchema() { return new EntryTransportSchema(SpawnSystemManager.TransportMetadata.DtoVersion, () => new CanonicalSpawnSystemEntry(), StringField((CanonicalSpawnSystemEntry entry) => entry.RuleId, delegate(CanonicalSpawnSystemEntry entry, string value) { entry.RuleId = value; }, (EntrySignatureContext context) => context.IncludeRuleId), StringField((CanonicalSpawnSystemEntry entry) => entry.Prefab, delegate(CanonicalSpawnSystemEntry entry, string value) { entry.Prefab = value; }), BoolField((CanonicalSpawnSystemEntry entry) => entry.Enabled, delegate(CanonicalSpawnSystemEntry entry, bool value) { entry.Enabled = value; }), OptionalField((CanonicalSpawnSystemEntry entry) => entry.Spawn, delegate(CanonicalSpawnSystemEntry entry, SpawnSystemSpawnDefinition? value) { entry.Spawn = value; }, SpawnSystemSpawnValueCodec), OptionalField((CanonicalSpawnSystemEntry entry) => entry.Conditions, delegate(CanonicalSpawnSystemEntry entry, SpawnSystemConditionsDefinition? value) { entry.Conditions = value; }, SpawnSystemConditionsValueCodec), OptionalField((CanonicalSpawnSystemEntry entry) => entry.Modifiers, delegate(CanonicalSpawnSystemEntry entry, SpawnSystemModifiersDefinition? value) { entry.Modifiers = value; }, SpawnSystemModifiersValueCodec), CopyOnlyField(delegate(CanonicalSpawnSystemEntry source, CanonicalSpawnSystemEntry target) { target.SourcePath = source.SourcePath; }), CopyOnlyField(delegate(CanonicalSpawnSystemEntry source, CanonicalSpawnSystemEntry target) { target.SourceLine = source.SourceLine; }), CopyOnlyField(delegate(CanonicalSpawnSystemEntry source, CanonicalSpawnSystemEntry target) { target.SourceColumn = source.SourceColumn; }), CopyOnlyField(delegate(CanonicalSpawnSystemEntry source, CanonicalSpawnSystemEntry target) { target.ReferenceOwnerName = source.ReferenceOwnerName; })); } private static byte[] SerializeObjectEntries(List entries) { return ObjectCodec.Schema.SerializeEntries(entries); } private static List DeserializeObjectEntries(byte[] payloadBytes) { return ObjectCodec.Schema.DeserializeEntries(payloadBytes); } private static byte[] SerializeCharacterEntries(List entries) { return CharacterCodec.Schema.SerializeEntries(entries); } private static List DeserializeCharacterEntries(byte[] payloadBytes) { return CharacterCodec.Schema.DeserializeEntries(payloadBytes); } private static byte[] SerializeSpawnerEntries(List entries) { return SpawnerCodec.Schema.SerializeEntries(entries); } private static List DeserializeSpawnerEntries(byte[] payloadBytes) { return SpawnerCodec.Schema.DeserializeEntries(payloadBytes); } private static byte[] SerializeLocationEntries(List entries) { return LocationCodec.Schema.SerializeEntries(entries); } private static List DeserializeLocationEntries(byte[] payloadBytes) { return LocationCodec.Schema.DeserializeEntries(payloadBytes); } private static byte[] SerializeSpawnSystemEntries(List entries) { return SpawnSystemCodec.Schema.SerializeEntries(entries); } private static List DeserializeSpawnSystemEntries(byte[] payloadBytes) { return SpawnSystemCodec.Schema.DeserializeEntries(payloadBytes); } private static void WriteSpawnSystemSpawnDefinition(ZPackage package, SpawnSystemSpawnDefinition definition) { WriteNullableString(package, definition.Name); WriteNullableBool(package, definition.HuntPlayer); WriteOptional(package, definition.Level, WriteIntRangeDefinition); WriteNullableFloat(package, definition.OverrideLevelUpChance); WriteNullableFloat(package, definition.LevelUpMinCenterDistance); WriteNullableFloat(package, definition.GroundOffset); WriteNullableFloat(package, definition.GroundOffsetRandom); WriteNullableFloat(package, definition.SpawnInterval); WriteNullableFloat(package, definition.SpawnChance); WriteOptional(package, definition.SpawnRadius, WriteFloatRangeDefinition); WriteOptional(package, definition.GroupSize, WriteIntRangeDefinition); WriteNullableFloat(package, definition.GroupRadius); } private static SpawnSystemSpawnDefinition ReadSpawnSystemSpawnDefinition(ZPackage package) { return new SpawnSystemSpawnDefinition { Name = ReadNullableString(package), HuntPlayer = ReadNullableBool(package), Level = ReadOptional(package, ReadIntRangeDefinition), OverrideLevelUpChance = ReadNullableFloat(package), LevelUpMinCenterDistance = ReadNullableFloat(package), GroundOffset = ReadNullableFloat(package), GroundOffsetRandom = ReadNullableFloat(package), SpawnInterval = ReadNullableFloat(package), SpawnChance = ReadNullableFloat(package), SpawnRadius = ReadOptional(package, ReadFloatRangeDefinition), GroupSize = ReadOptional(package, ReadIntRangeDefinition), GroupRadius = ReadNullableFloat(package) }; } private static void WriteSpawnSystemConditionsDefinition(ZPackage package, SpawnSystemConditionsDefinition definition) { WriteNullableFloat(package, definition.NoSpawnRadius); WriteNullableInt(package, definition.MaxSpawned); WriteOptional(package, definition.Tilt, WriteFloatRangeDefinition); WriteOptional(package, definition.Altitude, WriteFloatRangeDefinition); WriteOptional(package, definition.OceanDepth, WriteFloatRangeDefinition); WriteOptional(package, definition.DistanceFromCenter, WriteFloatRangeDefinition); WriteStringList(package, definition.Biomes); WriteNullableInt(package, GetResolvedBiomeMaskValue(definition.Biomes, definition.ResolvedBiomeMask)); WriteStringList(package, definition.BiomeAreas); WriteOptional(package, definition.TimeOfDay, WriteTimeOfDayDefinition); WriteStringList(package, definition.RequiredEnvironments); WriteNullableString(package, definition.RequiredGlobalKey); WriteNullableBool(package, definition.InLava); WriteNullableBool(package, definition.InForest); WriteNullableBool(package, definition.InsidePlayerBase); WriteNullableBool(package, definition.CanSpawnCloseToPlayer); } private static SpawnSystemConditionsDefinition ReadSpawnSystemConditionsDefinition(ZPackage package) { SpawnSystemConditionsDefinition obj = new SpawnSystemConditionsDefinition { NoSpawnRadius = ReadNullableFloat(package), MaxSpawned = ReadNullableInt(package), Tilt = ReadOptional(package, ReadFloatRangeDefinition), Altitude = ReadOptional(package, ReadFloatRangeDefinition), OceanDepth = ReadOptional(package, ReadFloatRangeDefinition), DistanceFromCenter = ReadOptional(package, ReadFloatRangeDefinition), Biomes = ReadStringList(package) }; int? num = ReadNullableInt(package); Biome? resolvedBiomeMask; if (num.HasValue) { int valueOrDefault = num.GetValueOrDefault(); resolvedBiomeMask = (Biome)valueOrDefault; } else { resolvedBiomeMask = null; } obj.ResolvedBiomeMask = resolvedBiomeMask; obj.BiomeAreas = ReadStringList(package); obj.TimeOfDay = ReadOptional(package, ReadTimeOfDayDefinition); obj.RequiredEnvironments = ReadStringList(package); obj.RequiredGlobalKey = ReadNullableString(package); obj.InLava = ReadNullableBool(package); obj.InForest = ReadNullableBool(package); obj.InsidePlayerBase = ReadNullableBool(package); obj.CanSpawnCloseToPlayer = ReadNullableBool(package); return obj; } private static void WriteSpawnSystemModifiersDefinition(ZPackage package, SpawnSystemModifiersDefinition definition) { WriteStringDictionary(package, definition.Fields); WriteStringList(package, definition.Objects); WriteNullableString(package, definition.Data); WriteNullableString(package, definition.Faction); } private static SpawnSystemModifiersDefinition ReadSpawnSystemModifiersDefinition(ZPackage package) { return new SpawnSystemModifiersDefinition { Fields = ReadStringDictionary(package), Objects = ReadStringList(package), Data = ReadNullableString(package), Faction = ReadNullableString(package) }; } private static string ComputeObjectPayloadSignature(List entries) { return ObjectCodec.Schema.ComputePayloadSignature(entries); } internal static string ComputeObjectConfigurationSignature(IEnumerable? entries) { return ComputeObjectPayloadSignature((entries ?? Enumerable.Empty()).ToList()); } internal static string ComputeObjectEntrySignature(PrefabConfigurationEntry entry) { return ObjectCodec.Schema.ComputeEntrySignature(entry, includeRuleId: false, includeResolvedBiomeMask: true); } internal static string ComputeObjectEntryIdentitySignature(PrefabConfigurationEntry entry) { return ObjectCodec.Schema.ComputeEntrySignature(entry, includeRuleId: false, includeResolvedBiomeMask: false); } internal static string ComputeObjectDropRowSignature(DropEntryDefinition definition) { PayloadSignatureBuilder payloadSignatureBuilder = new PayloadSignatureBuilder(); WriteDropEntryDefinition(payloadSignatureBuilder, definition); return payloadSignatureBuilder.ComputeHash(); } private static string ComputeCharacterPayloadSignature(List entries) { return CharacterCodec.Schema.ComputePayloadSignature(entries); } internal static string ComputeCharacterConfigurationSignature(IEnumerable? entries) { return ComputeCharacterPayloadSignature((entries ?? Enumerable.Empty()).ToList()); } internal static string ComputeCharacterEntrySignature(CharacterDropPrefabEntry entry) { return CharacterCodec.Schema.ComputeEntrySignature(entry, includeRuleId: false, includeResolvedBiomeMask: true); } internal static string ComputeCharacterEntryIdentitySignature(CharacterDropPrefabEntry entry) { return CharacterCodec.Schema.ComputeEntrySignature(entry, includeRuleId: false, includeResolvedBiomeMask: false); } internal static string ComputeCharacterDropRowSignature(CharacterDropEntryDefinition definition) { PayloadSignatureBuilder payloadSignatureBuilder = new PayloadSignatureBuilder(); WriteCharacterDropEntryDefinition(payloadSignatureBuilder, definition); return payloadSignatureBuilder.ComputeHash(); } private static string ComputeSpawnerPayloadSignature(List entries) { return SpawnerCodec.Schema.ComputePayloadSignature(entries); } internal static string ComputeSpawnerConfigurationSignature(IEnumerable? entries) { return ComputeSpawnerPayloadSignature((entries ?? Enumerable.Empty()).ToList()); } internal static string ComputeSpawnerEntrySignature(SpawnerConfigurationEntry entry) { return SpawnerCodec.Schema.ComputeEntrySignature(entry, includeRuleId: false, includeResolvedBiomeMask: true); } internal static string ComputeSpawnerEntryIdentitySignature(SpawnerConfigurationEntry entry) { return SpawnerCodec.Schema.ComputeEntrySignature(entry, includeRuleId: false, includeResolvedBiomeMask: false); } private static string ComputeLocationPayloadSignature(List entries) { return LocationCodec.Schema.ComputePayloadSignature(entries); } internal static string ComputeLocationConfigurationSignature(IEnumerable? entries) { return ComputeLocationPayloadSignature((entries ?? Enumerable.Empty()).ToList()); } internal static string ComputeLocationEntrySignature(LocationConfigurationEntry entry) { return LocationCodec.Schema.ComputeEntrySignature(entry, includeRuleId: false, includeResolvedBiomeMask: true); } internal static string ComputeLocationEntryIdentitySignature(LocationConfigurationEntry entry) { return LocationCodec.Schema.ComputeEntrySignature(entry, includeRuleId: false, includeResolvedBiomeMask: false); } private static string ComputeSpawnSystemPayloadSignature(IReadOnlyList entries) { return SpawnSystemCodec.Schema.ComputePayloadSignature(entries); } internal static string ComputeSpawnSystemProjectedConfigurationSignature(IReadOnlyList entries, Func selector) { return SpawnSystemCodec.Schema.ComputePayloadSignature(entries, selector); } internal static string ComputeSpawnSystemConfigurationSignature(IEnumerable? entries) { if (entries == null) { return ComputeSpawnSystemPayloadSignature(Array.Empty()); } if (entries is IReadOnlyList entries2) { return ComputeSpawnSystemPayloadSignature(entries2); } return ComputeSpawnSystemPayloadSignature(entries.ToList()); } internal static string ComputeSpawnSystemEntrySignature(CanonicalSpawnSystemEntry entry) { return SpawnSystemCodec.Schema.ComputeEntrySignature(entry, includeRuleId: false, includeResolvedBiomeMask: true); } internal static string ComputeSpawnSystemEntryIdentitySignature(CanonicalSpawnSystemEntry entry) { return SpawnSystemCodec.Schema.ComputeEntrySignature(entry, includeRuleId: false, includeResolvedBiomeMask: false); } private static void WriteSpawnSystemSpawnDefinition(PayloadSignatureBuilder builder, SpawnSystemSpawnDefinition definition) { WriteNullableString(builder, definition.Name); WriteNullableBool(builder, definition.HuntPlayer); WriteOptional(builder, definition.Level, WriteIntRangeDefinition); WriteNullableFloat(builder, definition.OverrideLevelUpChance); WriteNullableFloat(builder, definition.LevelUpMinCenterDistance); WriteNullableFloat(builder, definition.GroundOffset); WriteNullableFloat(builder, definition.GroundOffsetRandom); WriteNullableFloat(builder, definition.SpawnInterval); WriteNullableFloat(builder, definition.SpawnChance); WriteOptional(builder, definition.SpawnRadius, WriteFloatRangeDefinition); WriteOptional(builder, definition.GroupSize, WriteIntRangeDefinition); WriteNullableFloat(builder, definition.GroupRadius); } private static void WriteSpawnSystemConditionsDefinition(PayloadSignatureBuilder builder, SpawnSystemConditionsDefinition definition, bool includeResolvedBiomeMask) { WriteNullableFloat(builder, definition.NoSpawnRadius); WriteNullableInt(builder, definition.MaxSpawned); WriteOptional(builder, definition.Tilt, WriteFloatRangeDefinition); WriteOptional(builder, definition.Altitude, WriteFloatRangeDefinition); WriteOptional(builder, definition.OceanDepth, WriteFloatRangeDefinition); WriteOptional(builder, definition.DistanceFromCenter, WriteFloatRangeDefinition); WriteStringList(builder, definition.Biomes); if (includeResolvedBiomeMask) { WriteNullableInt(builder, GetResolvedBiomeMaskValue(definition.Biomes, definition.ResolvedBiomeMask)); } WriteStringList(builder, definition.BiomeAreas); WriteOptional(builder, definition.TimeOfDay, WriteTimeOfDayDefinition); WriteStringList(builder, definition.RequiredEnvironments); WriteNullableString(builder, definition.RequiredGlobalKey); WriteNullableBool(builder, definition.InLava); WriteNullableBool(builder, definition.InForest); WriteNullableBool(builder, definition.InsidePlayerBase); WriteNullableBool(builder, definition.CanSpawnCloseToPlayer); } private static void WriteSpawnSystemModifiersDefinition(PayloadSignatureBuilder builder, SpawnSystemModifiersDefinition definition) { WriteStringDictionary(builder, definition.Fields); WriteStringList(builder, definition.Objects); WriteNullableString(builder, definition.Data); WriteNullableString(builder, definition.Faction); } } internal sealed class OfferingBowlRuntimeState : MonoBehaviour { public float RespawnMinutes { get; set; } public long LocalLastUseTicks { get; set; } public ExpandWorldSpawnDataPayload? SpawnPayload { get; set; } } internal sealed class PrefabConfigurationEntry { [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 DropTableDefinition? DropOnDestroyed { get; set; } [YamlMember(Order = 5)] public DamageableDropTableDefinition? MineRock { get; set; } [YamlMember(Order = 6)] public DamageableDropTableDefinition? MineRock5 { get; set; } [YamlMember(Order = 7)] public DamageableDropTableDefinition? TreeBase { get; set; } [YamlMember(Order = 8)] public DamageableDropTableDefinition? TreeLog { get; set; } [YamlMember(Order = 9)] public DropTableDefinition? Container { get; set; } [YamlMember(Order = 10)] public PickableItemDefinition? PickableItem { get; set; } [YamlMember(Order = 11)] public PickableDefinition? Pickable { get; set; } [YamlMember(Order = 12)] public FishDefinition? Fish { get; set; } [YamlMember(Order = 13)] public DestructibleDefinition? Destructible { get; set; } [YamlIgnore] public string RuleId { get; set; } = ""; [YamlIgnore] public string? SourcePath { get; set; } [YamlIgnore] public int SourceLine { get; set; } [YamlIgnore] public int SourceColumn { get; set; } } internal sealed class PrefabReferenceEntry { [YamlMember(Order = 1)] public string Prefab { get; set; } = ""; [YamlMember(Order = 2)] public DropTableDefinition? DropOnDestroyed { get; set; } [YamlMember(Order = 3)] public DamageableDropTableDefinition? MineRock { get; set; } [YamlMember(Order = 4)] public DamageableDropTableDefinition? MineRock5 { get; set; } [YamlMember(Order = 5)] public DamageableDropTableDefinition? TreeBase { get; set; } [YamlMember(Order = 6)] public DamageableDropTableDefinition? TreeLog { get; set; } [YamlMember(Order = 7)] public DropTableDefinition? Container { get; set; } [YamlMember(Order = 8)] public PickableItemDefinition? PickableItem { get; set; } [YamlMember(Order = 9)] public PickableDefinition? Pickable { get; set; } [YamlMember(Order = 10)] public FishDefinition? Fish { get; set; } [YamlMember(Order = 11)] public DestructibleDefinition? Destructible { get; set; } } internal sealed class ObjectLocationReferenceEntry { [YamlMember(Order = 1)] public string Prefab { get; set; } = ""; [YamlMember(Order = 2)] public List Components { get; set; } = new List(); [YamlMember(Order = 3)] public List Locations { get; set; } = new List(); } internal class DropTablePayloadDefinition { [YamlMember(Order = 10)] public IntRangeDefinition? Rolls { get; set; } [YamlIgnore] public int? DropMin { get; set; } [YamlIgnore] public int? DropMax { get; set; } [YamlMember(Order = 11)] public float? DropChance { get; set; } [YamlMember(Order = 12)] public bool? OneOfEach { get; set; } [YamlMember(Order = 13)] public List? Drops { get; set; } } internal class DropTableDefinition : DropTablePayloadDefinition { } internal sealed class DamageableDropTableDefinition : DropTableDefinition { [YamlMember(Order = 1)] public float? Health { get; set; } [YamlMember(Order = 2)] public int? MinToolTier { get; set; } } internal sealed class DestructibleDefinition { [YamlMember(Order = 1)] public float? Health { get; set; } [YamlMember(Order = 2)] public int? MinToolTier { get; set; } [YamlMember(Order = 3)] public string? DestructibleType { get; set; } [YamlMember(Order = 4)] public string? SpawnWhenDestroyed { get; set; } } internal sealed class DropEntryDefinition { [YamlMember(Order = 1)] public string Item { get; set; } = ""; [YamlMember(Order = 2)] public IntRangeDefinition? Stack { get; set; } [YamlIgnore] public int? StackMin { get; set; } [YamlIgnore] public int? StackMax { get; set; } [YamlMember(Order = 3)] public float? Weight { get; set; } [YamlMember(Order = 4)] public bool? DontScale { get; set; } } internal sealed class PickableDefinition { [YamlMember(Order = 1)] public string? OverrideName { get; set; } [YamlMember(Order = 2)] public PickableDropDefinition? Drop { get; set; } [YamlMember(Order = 3)] public DropTablePayloadDefinition? ExtraDrops { get; set; } } internal sealed class PickableDropDefinition { [YamlMember(Order = 1)] public string Item { get; set; } = ""; [YamlMember(Order = 2)] public int? Amount { get; set; } [YamlMember(Order = 3)] public int? MinAmountScaled { get; set; } [YamlMember(Order = 4)] public bool? DontScale { get; set; } } internal sealed class PickableItemDefinition { [YamlMember(Order = 1)] public List? RandomDrops { get; set; } [YamlMember(Order = 2)] public PickableItemDropDefinition? Drop { get; set; } } internal sealed class PickableItemDropDefinition { [YamlMember(Order = 1)] public string Item { get; set; } = ""; [YamlMember(Order = 2)] public int? Stack { get; set; } } internal sealed class RandomPickableItemDefinition { [YamlMember(Order = 1)] public string Item { get; set; } = ""; [YamlMember(Order = 2)] public IntRangeDefinition? Stack { get; set; } [YamlIgnore] public int? StackMin { get; set; } [YamlIgnore] public int? StackMax { get; set; } [YamlMember(Order = 3)] public float? Weight { get; set; } } internal sealed class FishDefinition { [YamlMember(Order = 1)] public DropTablePayloadDefinition? ExtraDrops { get; set; } } internal static class ObjectDropManager { private readonly struct PendingObjectReconcileGroup { public string GroupKey { get; } public int Epoch { get; } public PendingObjectReconcileGroup(string groupKey, int epoch) { GroupKey = groupKey; Epoch = epoch; } } private readonly struct PendingObjectReconcileItem { public GameObject GameObject { get; } public int InstanceId { get; } public PendingObjectReconcileItem(GameObject gameObject, int instanceId) { GameObject = gameObject; InstanceId = instanceId; } } private sealed class PendingObjectReconcileGroupState { public RingBufferQueue Items { get; } = new RingBufferQueue(); public HashSet InstanceIds { get; } = new HashSet(); public bool ClearCreatorRestrictedContainerContents { get; set; } public LiveObjectComponentKind ComponentKinds { get; set; } public bool HighPriority { get; set; } public bool IsQueued { get; set; } } private sealed class GroupConditionalApplyPlan { public HashSet EligibleEntries { get; } = new HashSet(); public List MatchingEntries { get; } = new List(); public HashSet EligibleCompiledRules { get; } = new HashSet(); public List MatchingCompiledRules { get; } = new List(); } private sealed class GroupConditionalApplyPlanCacheEntry { public GroupConditionalApplyPlan Plan { get; set; } public LinkedListNode LruNode { get; set; } } private readonly struct StaticObjectMatchCacheEntry { public int Epoch { get; } public bool HasPotentialStaticMatch { get; } public StaticObjectMatchCacheEntry(int epoch, bool hasPotentialStaticMatch) { Epoch = epoch; HasPotentialStaticMatch = hasPotentialStaticMatch; } } [Flags] internal enum LiveObjectComponentKind { None = 0, DropOnDestroyed = 1, MineRock = 2, MineRock5 = 4, TreeBase = 8, TreeLog = 0x10, Container = 0x20, Pickable = 0x40, PickableItem = 0x80, Fish = 0x100, Destructible = 0x200, Piece = 0x400 } private sealed class PickableSnapshot { public GameObject? ItemPrefab { get; set; } public int Amount { get; set; } public int MinAmountScaled { get; set; } public bool DontScale { get; set; } public string OverrideName { get; set; } = ""; public DropTable ExtraDrops { get; set; } = new DropTable(); } private sealed class PickableItemRandomSnapshot { public GameObject? ItemPrefab { get; set; } public int StackMin { get; set; } public int StackMax { get; set; } } private sealed class PickableItemSnapshot { public GameObject? ItemPrefab { get; set; } public int Stack { get; set; } public List RandomItems { get; set; } = new List(); } private sealed class BuiltRandomPickableItems { public RandomItem[] Items { get; set; } = Array.Empty(); public float[] Weights { get; set; } = Array.Empty(); } private sealed class WeightedRandomPickableItemState { public float[] Weights { get; set; } = Array.Empty(); } private sealed class FishSnapshot { public DropTable ExtraDrops { get; set; } = new DropTable(); } private sealed class DestructibleSnapshot { public DestructibleType DestructibleType { get; set; } public GameObject? SpawnWhenDestroyed { get; set; } } private sealed class HealthSnapshot { public float? Destructible { get; set; } public float? MineRock { get; set; } public float? MineRock5 { get; set; } public float? TreeBase { get; set; } public float? TreeLog { get; set; } } private sealed class MinToolTierSnapshot { public int? Destructible { get; set; } public int? MineRock { get; set; } public int? MineRock5 { get; set; } public int? TreeBase { get; set; } public int? TreeLog { get; set; } } private sealed class PrefabSnapshot { public GameObject Prefab { get; set; } public HealthSnapshot? Health { get; set; } public MinToolTierSnapshot? MinToolTier { get; set; } public DropTable? DropOnDestroyed { get; set; } public DropTable? MineRock { get; set; } public DropTable? MineRock5 { get; set; } public DropTable? TreeBase { get; set; } public DropTable? TreeLog { get; set; } public DropTable? Container { get; set; } public PickableSnapshot? Pickable { get; set; } public PickableItemSnapshot? PickableItem { get; set; } public FishSnapshot? Fish { get; set; } public DestructibleSnapshot? Destructible { get; set; } } private sealed class SyncedObjectConfigurationState { public List Configuration { get; set; } = new List(); public Dictionary> ActiveEntriesByPrefab { get; } = new Dictionary>(StringComparer.OrdinalIgnoreCase); public Dictionary ConfiguredComponentKindsByPrefab { get; } = new Dictionary(StringComparer.OrdinalIgnoreCase); public Dictionary ReconcileComponentKindsByPrefab { get; } = new Dictionary(StringComparer.OrdinalIgnoreCase); public Dictionary> VneiEntriesByPrefab { get; } = new Dictionary>(StringComparer.OrdinalIgnoreCase); public Dictionary VneiEntrySignaturesByPrefab { get; set; } = new Dictionary(StringComparer.OrdinalIgnoreCase); public string ConfigurationSignature { get; set; } = ""; } private sealed class ParsedObjectConfigurationDocument { public List Configuration { get; } = new List(); public List Warnings { get; } = new List(); } private sealed class CompiledDropTableRow { public string Fingerprint { get; set; } = ""; public GameObject ItemPrefab { get; set; } public int StackMin { get; set; } public int StackMax { get; set; } public float Weight { get; set; } public bool DontScale { get; set; } } private sealed class CompiledDropTablePayload { public bool HasDropRangeOverride { get; set; } public int DropMin { get; set; } public int DropMax { get; set; } public bool HasDropChanceOverride { get; set; } public float DropChance { get; set; } public bool HasOneOfEachOverride { get; set; } public bool OneOfEach { get; set; } public List Drops { get; } = new List(); } private sealed class CompiledPickableDefinition { public bool HasItemPrefabOverride { get; set; } public GameObject? ItemPrefab { get; set; } public bool HasAmountOverride { get; set; } public int Amount { get; set; } public bool HasMinAmountScaledOverride { get; set; } public int MinAmountScaled { get; set; } public bool HasDontScaleOverride { get; set; } public bool DontScale { get; set; } public bool HasOverrideNameOverride { get; set; } public string OverrideName { get; set; } = ""; } private sealed class CompiledPickableItemRandomEntry { public ItemDrop ItemPrefab { get; set; } public int StackMin { get; set; } public int StackMax { get; set; } public float Weight { get; set; } } private sealed class CompiledPickableItemDefinition { public bool HasRandomOverride { get; set; } public RandomItem[] RandomItems { get; set; } = Array.Empty(); public float[] RandomWeights { get; set; } = Array.Empty(); public bool HasFixedDrop { get; set; } public bool HasFixedItemOverride { get; set; } public ItemDrop? FixedItemPrefab { get; set; } public bool HasFixedStackOverride { get; set; } public int FixedStack { get; set; } } private sealed class CompiledDamageableScalarDefinition { public bool HasHealthOverride { get; set; } public float Health { get; set; } public bool HasMinToolTierOverride { get; set; } public int MinToolTier { get; set; } } private sealed class CompiledDestructibleComponentDefinition { public bool HasHealthOverride { get; set; } public float Health { get; set; } public bool HasMinToolTierOverride { get; set; } public int MinToolTier { get; set; } public bool HasDestructibleTypeOverride { get; set; } public DestructibleType DestructibleType { get; set; } public bool HasSpawnWhenDestroyedOverride { get; set; } public GameObject? SpawnWhenDestroyed { get; set; } } private sealed class CompiledObjectDropRule { public PrefabConfigurationEntry Entry { get; set; } public bool HasConditions { get; set; } public CompiledDropTablePayload? DropOnDestroyed { get; set; } public CompiledDropTablePayload? MineRock { get; set; } public CompiledDropTablePayload? MineRock5 { get; set; } public CompiledDropTablePayload? TreeBase { get; set; } public CompiledDropTablePayload? TreeLog { get; set; } public CompiledDropTablePayload? Container { get; set; } public CompiledDropTablePayload? PickableExtraDrops { get; set; } public CompiledDropTablePayload? FishExtraDrops { get; set; } public CompiledPickableDefinition? Pickable { get; set; } public CompiledPickableItemDefinition? PickableItem { get; set; } public CompiledDestructibleComponentDefinition? Destructible { get; set; } public CompiledDamageableScalarDefinition? MineRockScalars { get; set; } public CompiledDamageableScalarDefinition? MineRock5Scalars { get; set; } public CompiledDamageableScalarDefinition? TreeBaseScalars { get; set; } public CompiledDamageableScalarDefinition? TreeLogScalars { get; set; } } private sealed class StaticCompiledDropTableTemplate { public DropTable Template { get; set; } public HashSet Fingerprints { get; } = new HashSet(StringComparer.Ordinal); } private sealed class CompiledObjectPrefabPlan { public List ActiveEntries { get; } = new List(); public List Rules { get; } = new List(); public Dictionary StaticDropTableTemplates { get; } = new Dictionary(); } private sealed class ObjectRuntimeDropConfigurationState { public static ObjectRuntimeDropConfigurationState Empty { get; } = new ObjectRuntimeDropConfigurationState(); public Dictionary PlansByPrefab { get; } = new Dictionary(StringComparer.OrdinalIgnoreCase); public Dictionary RulesByEntry { get; } = new Dictionary(); } private sealed class PendingSnapshotBuildState { public int BuildVersion { get; set; } public int GameDataSignature { get; set; } public int SnapshotSignature { get; set; } public string Source { get; set; } = ""; public List Prefabs { get; } = new List(); public List Snapshots { get; } = new List(); public Dictionary SnapshotsByPrefab { get; } = new Dictionary(StringComparer.OrdinalIgnoreCase); public int NextIndex { get; set; } } private sealed class LocationReferenceBucket { public SortedSet Components { get; } = new SortedSet(StringComparer.OrdinalIgnoreCase); public SortedSet Locations { get; } = new SortedSet(StringComparer.OrdinalIgnoreCase); public Dictionary ReferenceEntriesBySignature { get; } = new Dictionary(StringComparer.Ordinal); } private sealed class ObjectApplyOperations : IStandardBaselineDesiredStateOperations { public static ObjectApplyOperations Instance { get; } = new ObjectApplyOperations(); public string DomainKey => "object"; public BaselineDesiredStateCapabilities Capabilities => BaselineDesiredStateCapabilities.Validation | BaselineDesiredStateCapabilities.StaticBaseline | BaselineDesiredStateCapabilities.StaticApply | BaselineDesiredStateCapabilities.LiveApply | BaselineDesiredStateCapabilities.StaticRollback; public void Validate(ObjectDesiredState desiredState) { ValidateObjectDesiredState(desiredState); } public void RestoreStaticBaseline(ObjectDesiredState desiredState) { RestoreObjectStaticBaseline(desiredState); } public void ApplyDesiredStateToStaticBaseline(ObjectDesiredState desiredState) { ApplyObjectDesiredStateToStaticBaseline(desiredState); } public void PrepareLiveBaseline(ObjectDesiredState desiredState) { PrepareObjectLiveBaseline(desiredState); } public void ApplyDesiredStateToLive(ObjectDesiredState desiredState) { ApplyObjectDesiredStateToLive(desiredState); } public void Commit(ObjectDesiredState desiredState) { RecordAppliedState(desiredState.GameDataSignature, desiredState.DomainEnabled, desiredState.CurrentEntrySignatures); } public void HandleFailure(ObjectDesiredState desiredState, StandardApplyFailureContext failureContext) { if (failureContext.LiveStageFailed) { QueueReapplyActiveEntriesToLiveObjects(desiredState.LiveDirtyPrefabs); } } } private sealed class ObjectDesiredState { public StandardDomainApplyPlan ApplyPlan { get; set; } public int GameDataSignature { get; set; } public Dictionary CurrentEntrySignatures { get; set; } = EmptyEntrySignatures; public ObjectRuntimeDropConfigurationState RuntimeConfigurationState { get; set; } = ObjectRuntimeDropConfigurationState.Empty; public bool DomainEnabled { get; set; } public bool QueueLiveReconcile { get; set; } public HashSet? DirtyPrefabs { get; set; } public HashSet? LiveDirtyPrefabs { get; set; } public bool NeedsLiveReload { get; set; } } private sealed class ObjectConditionPlanCacheState { private readonly Dictionary _staticObjectMatchCache = new Dictionary(); private readonly Dictionary _groupConditionalApplyPlans = new Dictionary(StringComparer.Ordinal); private readonly LinkedList _groupConditionalApplyPlanLru = new LinkedList(); private readonly Dictionary _staticConditionContexts = new Dictionary(); public bool TryGetStaticObjectMatch(long cacheKey, int epoch, out bool hasPotentialStaticMatch) { if (_staticObjectMatchCache.TryGetValue(cacheKey, out var value) && value.Epoch == epoch) { hasPotentialStaticMatch = value.HasPotentialStaticMatch; return true; } hasPotentialStaticMatch = false; return false; } public void RecordStaticObjectMatch(long cacheKey, int epoch, bool hasPotentialStaticMatch) { _staticObjectMatchCache[cacheKey] = new StaticObjectMatchCacheEntry(epoch, hasPotentialStaticMatch); } public bool TryGetGroupConditionalApplyPlan(string cacheKey, out GroupConditionalApplyPlan? plan) { if (_groupConditionalApplyPlans.TryGetValue(cacheKey, out GroupConditionalApplyPlanCacheEntry value)) { TouchGroupConditionalApplyPlanCacheEntry(value); plan = value.Plan; return true; } plan = null; return false; } public void StoreGroupConditionalApplyPlan(string cacheKey, GroupConditionalApplyPlan plan) { if (_groupConditionalApplyPlans.TryGetValue(cacheKey, out GroupConditionalApplyPlanCacheEntry value)) { value.Plan = plan; TouchGroupConditionalApplyPlanCacheEntry(value); return; } LinkedListNode lruNode = _groupConditionalApplyPlanLru.AddLast(cacheKey); _groupConditionalApplyPlans[cacheKey] = new GroupConditionalApplyPlanCacheEntry { Plan = plan, LruNode = lruNode }; TrimGroupConditionalApplyPlanCacheIfNeeded(); } public void InvalidateStaticObjectMatchCacheForInstance(int instanceId) { for (int num = 1; num <= 1024; num <<= 1) { _staticObjectMatchCache.Remove(BuildStaticObjectMatchCacheKey(instanceId, (LiveObjectComponentKind)num)); } _staticConditionContexts.Remove(instanceId); } public bool TryGetStaticConditionContext(int instanceId, Vector3 position, out StaticConditionContextSnapshot snapshot) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) if (_staticConditionContexts.TryGetValue(instanceId, out snapshot) && snapshot.Position == position) { return true; } snapshot = null; return false; } public StaticConditionContextSnapshot StoreStaticConditionContext(int instanceId, StaticConditionContextSnapshot snapshot) { _staticConditionContexts[instanceId] = snapshot; return snapshot; } public void Clear() { _staticObjectMatchCache.Clear(); _groupConditionalApplyPlans.Clear(); _groupConditionalApplyPlanLru.Clear(); _staticConditionContexts.Clear(); } private void TouchGroupConditionalApplyPlanCacheEntry(GroupConditionalApplyPlanCacheEntry cacheEntry) { if (cacheEntry.LruNode.List != null && cacheEntry.LruNode != _groupConditionalApplyPlanLru.Last) { _groupConditionalApplyPlanLru.Remove(cacheEntry.LruNode); _groupConditionalApplyPlanLru.AddLast(cacheEntry.LruNode); } } private void TrimGroupConditionalApplyPlanCacheIfNeeded() { if (_groupConditionalApplyPlans.Count > 2048) { while (_groupConditionalApplyPlans.Count > 1536 && _groupConditionalApplyPlanLru.First != null) { LinkedListNode? first = _groupConditionalApplyPlanLru.First; _groupConditionalApplyPlanLru.RemoveFirst(); string value = first.Value; _groupConditionalApplyPlans.Remove(value); } } } } private sealed class StaticConditionContextSnapshot { public Vector3 Position { get; set; } public string ResolvedLocationName { get; set; } = ""; public Biome Biome { get; set; } public bool InDungeon { get; set; } } private readonly struct InvalidEntryWarningSuppressionScope : IDisposable { private readonly bool _active; public InvalidEntryWarningSuppressionScope(bool active) { _active = active; if (_active) { _invalidEntryWarningSuppressionDepth++; } } public void Dispose() { if (_active) { _invalidEntryWarningSuppressionDepth--; } } } private sealed class EventDropTableStateSet { private readonly Dictionary _states = new Dictionary(); public CachedEventDropTableState GetOrCreate(LiveObjectComponentKind componentKind) { if (_states.TryGetValue(componentKind, out CachedEventDropTableState value)) { return value; } CachedEventDropTableState cachedEventDropTableState = new CachedEventDropTableState(); _states[componentKind] = cachedEventDropTableState; return cachedEventDropTableState; } } private sealed class CachedEventDropTableState { public int Epoch { get; private set; } = -1; public string PrefabName { get; private set; } = ""; public bool IsInitialized { get; set; } public DropTable? SnapshotTable { get; private set; } public CompiledObjectDropRule[] RelevantRules { get; set; } = Array.Empty(); public bool HasCustomBlock { get; set; } public bool UsesTimeOfDay { get; set; } public bool UsesRequiredEnvironments { get; set; } public bool UsesInsidePlayerBase { get; set; } public string[] RequiredGlobalKeys { get; set; } = Array.Empty(); public string[] ForbiddenGlobalKeys { get; set; } = Array.Empty(); public int LastRuntimeSignature { get; set; } = int.MinValue; public bool HasCachedResolution { get; set; } public bool LastHasOverride { get; set; } public DropTable? LastResolvedDropTable { get; set; } public float LastInsidePlayerBaseSampleTime { get; set; } = float.NegativeInfinity; public bool IsInsidePlayerBase { get; set; } public void Reset(int epoch, string prefabName, DropTable? snapshotTable) { Epoch = epoch; PrefabName = prefabName ?? ""; SnapshotTable = snapshotTable; IsInitialized = false; RelevantRules = Array.Empty(); HasCustomBlock = false; UsesTimeOfDay = false; UsesRequiredEnvironments = false; UsesInsidePlayerBase = false; RequiredGlobalKeys = Array.Empty(); ForbiddenGlobalKeys = Array.Empty(); LastRuntimeSignature = int.MinValue; HasCachedResolution = false; LastHasOverride = false; LastResolvedDropTable = null; LastInsidePlayerBaseSampleTime = float.NegativeInfinity; IsInsidePlayerBase = false; } } private sealed class EventDropRuntimeContextSnapshot { public int Frame { get; set; } public int TimeOfDayPhaseMarker { get; set; } public string EnvironmentName { get; set; } = ""; public Dictionary GlobalKeyStates { get; } = new Dictionary(StringComparer.Ordinal); } private sealed class ObjectLazyRuntimeState { private readonly ConditionalWeakTable _pickableItemRandomStates = new ConditionalWeakTable(); private readonly ConditionalWeakTable _eventDropTableStates = new ConditionalWeakTable(); private EventDropRuntimeContextSnapshot? _eventDropRuntimeContextSnapshot; public bool HasRandomState(PickableItem pickableItem) { WeightedRandomPickableItemState value; return _pickableItemRandomStates.TryGetValue(pickableItem, out value); } public bool TryGetRandomState(PickableItem pickableItem, out WeightedRandomPickableItemState state) { return _pickableItemRandomStates.TryGetValue(pickableItem, out state); } public void SetRandomWeights(PickableItem pickableItem, float[] weights) { _pickableItemRandomStates.Remove(pickableItem); if (weights.Length != 0) { _pickableItemRandomStates.Add(pickableItem, new WeightedRandomPickableItemState { Weights = weights }); } } public void ClearRandomState(PickableItem pickableItem) { _pickableItemRandomStates.Remove(pickableItem); } public CachedEventDropTableState GetOrCreateEventDropTableState(GameObject gameObject, LiveObjectComponentKind componentKind) { return _eventDropTableStates.GetOrCreateValue(gameObject).GetOrCreate(componentKind); } public EventDropRuntimeContextSnapshot GetOrCreateEventDropRuntimeContextSnapshot() { int frameCount = Time.frameCount; if (_eventDropRuntimeContextSnapshot != null && _eventDropRuntimeContextSnapshot.Frame == frameCount) { return _eventDropRuntimeContextSnapshot; } EventDropRuntimeContextSnapshot obj = new EventDropRuntimeContextSnapshot { Frame = frameCount, TimeOfDayPhaseMarker = TimeOfDayFormatting.GetCurrentRuntimePhaseMarker() }; EnvMan instance = EnvMan.instance; obj.EnvironmentName = ((instance == null) ? null : instance.GetCurrentEnvironment()?.m_name) ?? ""; _eventDropRuntimeContextSnapshot = obj; return _eventDropRuntimeContextSnapshot; } } private sealed class ObjectLiveRegistryState { [CompilerGenerated] private sealed class d__8 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private GameObject <>2__current; private int <>l__initialThreadId; private HashSet prefabNames; public HashSet <>3__prefabNames; public ObjectLiveRegistryState <>4__this; private HashSet.Enumerator <>7__wrap1; private HashSet.Enumerator <>7__wrap2; GameObject IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__8(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(); } } <>7__wrap1 = default(HashSet.Enumerator); <>7__wrap2 = default(HashSet.Enumerator); <>1__state = -2; } private bool MoveNext() { try { int num = <>1__state; ObjectLiveRegistryState objectLiveRegistryState = <>4__this; if (num != 0) { if (num != 1) { return false; } <>1__state = -4; goto IL_00a9; } <>1__state = -1; <>7__wrap1 = prefabNames.GetEnumerator(); <>1__state = -3; goto IL_00c8; IL_00a9: while (<>7__wrap2.MoveNext()) { GameObject current = <>7__wrap2.Current; if ((Object)(object)current != (Object)null) { <>2__current = current; <>1__state = 1; return true; } } <>m__Finally2(); <>7__wrap2 = default(HashSet.Enumerator); goto IL_00c8; IL_00c8: string current2; HashSet value; do { if (<>7__wrap1.MoveNext()) { current2 = <>7__wrap1.Current; continue; } <>m__Finally1(); <>7__wrap1 = default(HashSet.Enumerator); return false; } while (!objectLiveRegistryState._liveObjectsByPrefab.TryGetValue(current2, out value)); <>7__wrap2 = value.GetEnumerator(); <>1__state = -4; goto IL_00a9; } 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)<>7__wrap1).Dispose(); } private void <>m__Finally2() { <>1__state = -3; ((IDisposable)<>7__wrap2).Dispose(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__8 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__8(0) { <>4__this = <>4__this }; } d__.prefabNames = <>3__prefabNames; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } private readonly Dictionary> _liveObjectsByPrefab = new Dictionary>(StringComparer.OrdinalIgnoreCase); private readonly Dictionary _liveObjectPrefabsByInstance = new Dictionary(); private readonly HashSet _bootstrappedTrackedPrefabs = new HashSet(StringComparer.OrdinalIgnoreCase); private int? _liveObjectRegistrySceneInstanceId; public bool HasSceneSession(int currentSceneInstanceId) { return _liveObjectRegistrySceneInstanceId == currentSceneInstanceId; } public void BeginSceneSession(int currentSceneInstanceId) { _liveObjectRegistrySceneInstanceId = currentSceneInstanceId; ClearTracked(); } public HashSet CollectUnbootstrappedTrackedPrefabs(IEnumerable prefabNames) { HashSet hashSet = new HashSet(StringComparer.OrdinalIgnoreCase); foreach (string prefabName in prefabNames) { if (!string.IsNullOrWhiteSpace(prefabName) && !_bootstrappedTrackedPrefabs.Contains(prefabName)) { hashSet.Add(prefabName); } } return hashSet; } public void MarkTrackedPrefabsBootstrapped(IEnumerable prefabNames) { foreach (string prefabName in prefabNames) { if (!string.IsNullOrWhiteSpace(prefabName)) { _bootstrappedTrackedPrefabs.Add(prefabName); } } } [IteratorStateMachine(typeof(d__8))] public IEnumerable EnumerateRegisteredLiveObjects(HashSet prefabNames) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__8(-2) { <>4__this = this, <>3__prefabNames = prefabNames }; } public bool TryGetTrackedPrefab(GameObject gameObject, out string prefabName) { return _liveObjectPrefabsByInstance.TryGetValue(gameObject, out prefabName); } public void Register(GameObject gameObject, string prefabName) { if (_liveObjectPrefabsByInstance.TryGetValue(gameObject, out string value)) { if (string.Equals(value, prefabName, StringComparison.OrdinalIgnoreCase)) { return; } Unregister(gameObject, value); } _liveObjectPrefabsByInstance[gameObject] = prefabName; if (!_liveObjectsByPrefab.TryGetValue(prefabName, out HashSet value2)) { value2 = new HashSet(); _liveObjectsByPrefab[prefabName] = value2; } value2.Add(gameObject); } public void Unregister(GameObject gameObject, string prefabName) { _liveObjectPrefabsByInstance.Remove(gameObject); if (_liveObjectsByPrefab.TryGetValue(prefabName, out HashSet value)) { value.Remove(gameObject); if (value.Count == 0) { _liveObjectsByPrefab.Remove(prefabName); } } } public void CollectDeadObjects(List> target) { target.Clear(); foreach (KeyValuePair item in _liveObjectPrefabsByInstance) { if ((Object)(object)item.Key == (Object)null) { target.Add(item); } } } public void ClearTracked() { _liveObjectsByPrefab.Clear(); _liveObjectPrefabsByInstance.Clear(); _bootstrappedTrackedPrefabs.Clear(); } } private sealed class ObjectPrefabProfileCatalogState { private readonly Dictionary _configuredComponentKindsByPrefab = new Dictionary(StringComparer.OrdinalIgnoreCase); private readonly Dictionary _reconcileComponentKindsByPrefab = new Dictionary(StringComparer.OrdinalIgnoreCase); private readonly Dictionary _lastAppliedConfiguredComponentKindsByPrefab = new Dictionary(StringComparer.OrdinalIgnoreCase); private readonly Dictionary _lastAppliedReconcileComponentKindsByPrefab = new Dictionary(StringComparer.OrdinalIgnoreCase); public void Clear() { ClearCurrentProfiles(); _lastAppliedConfiguredComponentKindsByPrefab.Clear(); _lastAppliedReconcileComponentKindsByPrefab.Clear(); } public void ClearCurrentProfiles() { _configuredComponentKindsByPrefab.Clear(); _reconcileComponentKindsByPrefab.Clear(); } public void RefreshConfiguredPrefabProfile(Dictionary> activeEntriesByPrefab, string prefabName) { ObjectDropManager.RefreshConfiguredPrefabProfile(activeEntriesByPrefab, _configuredComponentKindsByPrefab, prefabName); RefreshReconcilePrefabProfile(activeEntriesByPrefab, _reconcileComponentKindsByPrefab, prefabName); } public void ApplySyncedProfiles(Dictionary configuredComponentKindsByPrefab, Dictionary reconcileComponentKindsByPrefab) { ReplaceComponentKinds(_configuredComponentKindsByPrefab, configuredComponentKindsByPrefab); ReplaceComponentKinds(_reconcileComponentKindsByPrefab, reconcileComponentKindsByPrefab); } public bool TryGetReconcileKinds(string prefabName, out LiveObjectComponentKind reconcileKinds) { return _reconcileComponentKindsByPrefab.TryGetValue(prefabName, out reconcileKinds); } public bool RequiresLiveReconcile(string prefabName) { if (prefabName.Length == 0) { return false; } if (_reconcileComponentKindsByPrefab.TryGetValue(prefabName, out var value) && value != 0) { return true; } if (_lastAppliedReconcileComponentKindsByPrefab.TryGetValue(prefabName, out var value2)) { return value2 != LiveObjectComponentKind.None; } return false; } public bool RequiresLiveObjectTracking(string prefabName) { if (prefabName.Length == 0) { return false; } if (_configuredComponentKindsByPrefab.TryGetValue(prefabName, out var value) && value != 0) { return true; } if (_lastAppliedConfiguredComponentKindsByPrefab.TryGetValue(prefabName, out var value2)) { return value2 != LiveObjectComponentKind.None; } return false; } public bool RequiresLiveReconcile(string prefabName, LiveObjectComponentKind componentKind) { if (componentKind == LiveObjectComponentKind.Piece) { return RequiresLiveReconcile(prefabName); } if (_reconcileComponentKindsByPrefab.TryGetValue(prefabName, out var value)) { return (value & componentKind) != 0; } return false; } public HashSet FilterPrefabsRequiringLiveReconcile(IEnumerable? prefabNames) { HashSet hashSet = new HashSet(StringComparer.OrdinalIgnoreCase); if (prefabNames == null) { return hashSet; } foreach (string prefabName in prefabNames) { if (RequiresLiveReconcile(prefabName)) { hashSet.Add(prefabName); } } return hashSet; } public HashSet FilterPrefabsRequiringLiveTracking(IEnumerable? prefabNames) { HashSet hashSet = new HashSet(StringComparer.OrdinalIgnoreCase); if (prefabNames == null) { return hashSet; } foreach (string prefabName in prefabNames) { if (RequiresLiveObjectTracking(prefabName)) { hashSet.Add(prefabName); } } return hashSet; } public HashSet SnapshotPrefabsRequiringLiveTracking() { HashSet hashSet = new HashSet(StringComparer.OrdinalIgnoreCase); string key; LiveObjectComponentKind value; foreach (KeyValuePair item3 in _configuredComponentKindsByPrefab) { item3.Deconstruct(out key, out value); string item = key; if (value != 0) { hashSet.Add(item); } } foreach (KeyValuePair item4 in _lastAppliedConfiguredComponentKindsByPrefab) { item4.Deconstruct(out key, out value); string item2 = key; if (value != 0) { hashSet.Add(item2); } } return hashSet; } public void RecordCurrentConfiguredKindsAsLastApplied() { ReplaceComponentKinds(_lastAppliedConfiguredComponentKindsByPrefab, _configuredComponentKindsByPrefab); } public void RecordCurrentReconcileKindsAsLastApplied() { ReplaceComponentKinds(_lastAppliedReconcileComponentKindsByPrefab, _reconcileComponentKindsByPrefab); } public void ClearLastAppliedConfiguredKinds() { _lastAppliedConfiguredComponentKindsByPrefab.Clear(); } public void ClearLastAppliedReconcileKinds() { _lastAppliedReconcileComponentKindsByPrefab.Clear(); } } private sealed class ObjectReconcileQueueState { private readonly RingBufferQueue _pendingHighPriorityObjectReconcileGroups = new RingBufferQueue(); private readonly RingBufferQueue _pendingLowPriorityObjectReconcileGroups = new RingBufferQueue(); private readonly Dictionary _pendingObjectReconcileGroups = new Dictionary(StringComparer.Ordinal); private readonly Dictionary _pendingObjectReconcileClearFlags = new Dictionary(); public bool HasPendingWork() { if (_pendingHighPriorityObjectReconcileGroups.Count <= 0) { return _pendingLowPriorityObjectReconcileGroups.Count > 0; } return true; } public bool HasPendingGroups(bool highPriorityOnly) { if (_pendingHighPriorityObjectReconcileGroups.Count <= 0) { if (!highPriorityOnly) { return _pendingLowPriorityObjectReconcileGroups.Count > 0; } return false; } return true; } public bool TryGetGroupState(string groupKey, out PendingObjectReconcileGroupState groupState) { return _pendingObjectReconcileGroups.TryGetValue(groupKey, out groupState); } public void RemoveGroup(string groupKey) { _pendingObjectReconcileGroups.Remove(groupKey); } public IEnumerable> EnumerateGroups() { return _pendingObjectReconcileGroups; } public void EnqueueGroup(PendingObjectReconcileGroup queuedGroup, bool highPriority) { if (highPriority) { _pendingHighPriorityObjectReconcileGroups.Enqueue(queuedGroup); } else { _pendingLowPriorityObjectReconcileGroups.Enqueue(queuedGroup); } } public bool TryDequeueGroup(out PendingObjectReconcileGroup queuedGroup, bool highPriorityOnly = false) { if (_pendingHighPriorityObjectReconcileGroups.TryDequeue(out queuedGroup)) { return true; } if (highPriorityOnly) { return false; } return _pendingLowPriorityObjectReconcileGroups.TryDequeue(out queuedGroup); } public bool TryMergeOrAddClearFlag(int instanceId, bool clearCreatorRestrictedContainerContents) { if (_pendingObjectReconcileClearFlags.TryGetValue(instanceId, out var value)) { _pendingObjectReconcileClearFlags[instanceId] = value || clearCreatorRestrictedContainerContents; return true; } _pendingObjectReconcileClearFlags[instanceId] = clearCreatorRestrictedContainerContents; return false; } public bool TryTakeClearFlag(int instanceId, out bool clearCreatorRestrictedContainerContents) { if (_pendingObjectReconcileClearFlags.TryGetValue(instanceId, out clearCreatorRestrictedContainerContents)) { _pendingObjectReconcileClearFlags.Remove(instanceId); return true; } return false; } public void RemovePendingState(int instanceId) { _pendingObjectReconcileClearFlags.Remove(instanceId); } public PendingObjectReconcileGroupState GetOrCreateGroup(string groupKey, LiveObjectComponentKind configuredKinds, bool highPriority) { if (_pendingObjectReconcileGroups.TryGetValue(groupKey, out PendingObjectReconcileGroupState value)) { return value; } value = new PendingObjectReconcileGroupState { ComponentKinds = configuredKinds, HighPriority = highPriority }; _pendingObjectReconcileGroups[groupKey] = value; return value; } public void Clear() { _pendingHighPriorityObjectReconcileGroups.Clear(); _pendingLowPriorityObjectReconcileGroups.Clear(); _pendingObjectReconcileGroups.Clear(); _pendingObjectReconcileClearFlags.Clear(); } } [CompilerGenerated] private sealed class d__233 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private PrefabReferenceEntry <>2__current; private int <>l__initialThreadId; private HashSet existingPrefabs; public HashSet <>3__existingPrefabs; private IEnumerator> <>7__wrap1; PrefabReferenceEntry IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__233(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(); } } <>7__wrap1 = null; <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>7__wrap1 = BuildLocationReferenceBuckets().OrderBy, string>((KeyValuePair pair) => pair.Key, StringComparer.OrdinalIgnoreCase).GetEnumerator(); <>1__state = -3; break; case 1: <>1__state = -3; break; } while (<>7__wrap1.MoveNext()) { <>7__wrap1.Current.Deconstruct(out var key, out var value); string key2 = key; LocationReferenceBucket locationReferenceBucket = value; string text = ReferenceRefreshSupport.NormalizeKey(key2); if (text.Length != 0 && !existingPrefabs.Contains(text) && locationReferenceBucket.ReferenceEntriesBySignature.Count == 1) { PrefabReferenceEntry prefabReferenceEntry = locationReferenceBucket.ReferenceEntriesBySignature.Values.First(); existingPrefabs.Add(text); <>2__current = prefabReferenceEntry; <>1__state = 1; return true; } } <>m__Finally1(); <>7__wrap1 = 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 (<>7__wrap1 != null) { <>7__wrap1.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__233 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__233(0); } d__.existingPrefabs = <>3__existingPrefabs; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__235 : IEnumerable<(string LocationPrefab, GameObject RootPrefab)>, IEnumerable, IEnumerator<(string LocationPrefab, GameObject RootPrefab)>, IDisposable, IEnumerator { private int <>1__state; private (string LocationPrefab, GameObject RootPrefab) <>2__current; private int <>l__initialThreadId; private HashSet 5__2; private List.Enumerator <>7__wrap2; (string, GameObject) IEnumerator<(string, GameObject)>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__235(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(); } } 5__2 = null; <>7__wrap2 = default(List.Enumerator); <>1__state = -2; } private bool MoveNext() { //IL_00b4: Unknown result type (might be due to invalid IL or missing references) try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; if ((Object)(object)ZoneSystem.instance == (Object)null) { return false; } 5__2 = new HashSet(StringComparer.OrdinalIgnoreCase); <>7__wrap2 = ZoneSystem.instance.m_locations.GetEnumerator(); <>1__state = -3; break; case 1: <>1__state = -3; break; } while (<>7__wrap2.MoveNext()) { ZoneLocation current = <>7__wrap2.Current; if (!current.m_prefab.IsValid) { continue; } string text = (current.m_prefab.Name ?? "").Trim(); if (text.Length != 0 && 5__2.Add(text)) { current.m_prefab.Load(); GameObject asset = current.m_prefab.Asset; if (!((Object)(object)asset == (Object)null)) { <>2__current = (text, asset); <>1__state = 1; return true; } } } <>m__Finally1(); <>7__wrap2 = default(List.Enumerator); 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; ((IDisposable)<>7__wrap2).Dispose(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator<(string LocationPrefab, GameObject RootPrefab)> IEnumerable<(string, GameObject)>.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; return this; } return new d__235(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<(string, GameObject)>)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__219 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private string <>2__current; private int <>l__initialThreadId; private IEnumerator <>7__wrap1; string IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__219(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(); } } <>7__wrap1 = 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_006a; case 1: <>1__state = -1; goto IL_006a; case 2: <>1__state = -1; goto IL_0093; case 3: { <>1__state = -3; break; } IL_006a: if (File.Exists(PrimaryOverrideConfigurationPathYaml)) { <>2__current = PrimaryOverrideConfigurationPathYaml; <>1__state = 2; return true; } goto IL_0093; IL_0093: <>7__wrap1 = EnumerateSupplementalOverrideConfigurationPaths().GetEnumerator(); <>1__state = -3; break; } if (<>7__wrap1.MoveNext()) { string current = <>7__wrap1.Current; <>2__current = current; <>1__state = 3; return true; } <>m__Finally1(); <>7__wrap1 = 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 (<>7__wrap1 != null) { <>7__wrap1.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; return this; } return new d__219(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__224 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private GameObject <>2__current; private int <>l__initialThreadId; private HashSet 5__2; private List.Enumerator <>7__wrap2; GameObject IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__224(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { switch (<>1__state) { case -3: case 1: try { } finally { <>m__Finally1(); } break; case -4: case 2: try { } finally { <>m__Finally2(); } break; } 5__2 = null; <>7__wrap2 = default(List.Enumerator); <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; 5__2 = new HashSet(); if ((Object)(object)ZNetScene.instance == (Object)null) { return false; } <>7__wrap2 = ZNetScene.instance.m_prefabs.GetEnumerator(); <>1__state = -3; goto IL_00bd; case 1: <>1__state = -3; goto IL_00bd; case 2: { <>1__state = -4; break; } IL_00bd: while (<>7__wrap2.MoveNext()) { GameObject current = <>7__wrap2.Current; if ((Object)(object)current != (Object)null && !((Object)current).name.StartsWith("JVLmock_", StringComparison.OrdinalIgnoreCase) && 5__2.Add(((Object)current).GetInstanceID())) { <>2__current = current; <>1__state = 1; return true; } } <>m__Finally1(); <>7__wrap2 = default(List.Enumerator); <>7__wrap2 = ZNetScene.instance.m_nonNetViewPrefabs.GetEnumerator(); <>1__state = -4; break; } while (<>7__wrap2.MoveNext()) { GameObject current2 = <>7__wrap2.Current; if ((Object)(object)current2 != (Object)null && !((Object)current2).name.StartsWith("JVLmock_", StringComparison.OrdinalIgnoreCase) && 5__2.Add(((Object)current2).GetInstanceID())) { <>2__current = current2; <>1__state = 2; return true; } } <>m__Finally2(); <>7__wrap2 = default(List.Enumerator); 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; ((IDisposable)<>7__wrap2).Dispose(); } private void <>m__Finally2() { <>1__state = -1; ((IDisposable)<>7__wrap2).Dispose(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; return this; } return new d__224(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__225 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private GameObject <>2__current; private int <>l__initialThreadId; private IEnumerator <>7__wrap1; GameObject IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__225(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(); } } <>7__wrap1 = null; <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>7__wrap1 = EnumeratePrefabs().GetEnumerator(); <>1__state = -3; break; case 1: <>1__state = -3; break; } while (<>7__wrap1.MoveNext()) { GameObject current = <>7__wrap1.Current; if (HasReferenceRelevantComponents(current)) { <>2__current = current; <>1__state = 1; return true; } } <>m__Finally1(); <>7__wrap1 = 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 (<>7__wrap1 != null) { <>7__wrap1.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; return this; } return new d__225(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__238 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private string <>2__current; private int <>l__initialThreadId; private GameObject gameObject; public GameObject <>3__gameObject; string IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__238(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; if ((Object)(object)gameObject == (Object)null) { return false; } if ((Object)(object)gameObject.GetComponent() != (Object)null) { <>2__current = "dropOnDestroyed"; <>1__state = 1; return true; } goto IL_0080; case 1: <>1__state = -1; goto IL_0080; case 2: <>1__state = -1; goto IL_00ae; case 3: <>1__state = -1; goto IL_00dc; case 4: <>1__state = -1; goto IL_010a; case 5: <>1__state = -1; goto IL_0138; case 6: <>1__state = -1; goto IL_0166; case 7: <>1__state = -1; goto IL_0194; case 8: <>1__state = -1; goto IL_01c2; case 9: <>1__state = -1; goto IL_01f1; case 10: { <>1__state = -1; break; } IL_01f1: if ((Object)(object)gameObject.GetComponent() != (Object)null) { <>2__current = "destructible"; <>1__state = 10; return true; } break; IL_0138: if ((Object)(object)gameObject.GetComponent() != (Object)null) { <>2__current = "container"; <>1__state = 6; return true; } goto IL_0166; IL_01c2: if ((Object)(object)gameObject.GetComponent() != (Object)null) { <>2__current = "fish"; <>1__state = 9; return true; } goto IL_01f1; IL_0080: if ((Object)(object)gameObject.GetComponent() != (Object)null) { <>2__current = "mineRock"; <>1__state = 2; return true; } goto IL_00ae; IL_0166: if ((Object)(object)gameObject.GetComponent() != (Object)null) { <>2__current = "pickable"; <>1__state = 7; return true; } goto IL_0194; IL_00ae: if ((Object)(object)gameObject.GetComponent() != (Object)null) { <>2__current = "mineRock5"; <>1__state = 3; return true; } goto IL_00dc; IL_00dc: if ((Object)(object)gameObject.GetComponent() != (Object)null) { <>2__current = "treeBase"; <>1__state = 4; return true; } goto IL_010a; IL_0194: if ((Object)(object)gameObject.GetComponent() != (Object)null) { <>2__current = "pickableItem"; <>1__state = 8; return true; } goto IL_01c2; IL_010a: if ((Object)(object)gameObject.GetComponent() != (Object)null) { <>2__current = "treeLog"; <>1__state = 5; return true; } goto IL_0138; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__238 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__238(0); } d__.gameObject = <>3__gameObject; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } private const string ReferenceAutoUpdateStateKey = "object"; private const string LocationReferenceAutoUpdateStateKey = "object.locations"; internal static readonly DomainModuleDefinition Module = new DomainModuleDefinition("object", DropNSpawnPlugin.ReloadDomain.Object, "object_yaml", 100, ShouldReloadForPath, ReloadConfiguration, OnGameDataReady, HandleExpandWorldDataReady, 7, DomainTransportProfile.LargeConfig, "object", "object", 100, (PrefabConfigurationEntry entry) => entry.RuleId, ApplySyncedPayload, DomainWorkKinds.Runtime | DomainWorkKinds.SnapshotBuild | DomainWorkKinds.Reconcile, HasPendingSnapshotBuildWork, ProcessPendingSnapshotBuildStep, HasPendingReconcileWork, ProcessQueuedReconcileStep, MarkSyncedPayloadPending, EnterPendingSyncedPayloadState); 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 Snapshots = new List(); private static readonly Dictionary SnapshotsByPrefab = new Dictionary(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary> ActiveEntriesByPrefab = new Dictionary>(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary> VneiEntriesByPrefab = new Dictionary>(StringComparer.OrdinalIgnoreCase); private static readonly HashSet MissingComponentWarnings = new HashSet(StringComparer.OrdinalIgnoreCase); private static readonly HashSet InvalidEntryWarnings = new HashSet(StringComparer.OrdinalIgnoreCase); private static readonly int DestructibleLazyScalarSignatureKey = StringExtensionMethods.GetStableHashCode("DropNSpawn.destructible_scalar_signature"); private static readonly int MineRockLazyScalarSignatureKey = StringExtensionMethods.GetStableHashCode("DropNSpawn.minerock_scalar_signature"); private static readonly int MineRock5LazyScalarSignatureKey = StringExtensionMethods.GetStableHashCode("DropNSpawn.minerock5_scalar_signature"); private static readonly int TreeBaseLazyScalarSignatureKey = StringExtensionMethods.GetStableHashCode("DropNSpawn.treebase_scalar_signature"); private static readonly int TreeLogLazyScalarSignatureKey = StringExtensionMethods.GetStableHashCode("DropNSpawn.treelog_scalar_signature"); private static readonly MethodInfo? PickableItemSetupItemMethod = AccessTools.Method(typeof(PickableItem), "SetupItem", (Type[])null, (Type[])null); private static readonly FieldInfo? MineRock5HitAreasField = AccessTools.Field(typeof(MineRock5), "m_hitAreas"); private static readonly MethodInfo? MineRock5SaveHealthMethod = AccessTools.Method(typeof(MineRock5), "SaveHealth", (Type[])null, (Type[])null); private static readonly MethodInfo? MineRock5UpdateMeshMethod = AccessTools.Method(typeof(MineRock5), "UpdateMesh", (Type[])null, (Type[])null); private static readonly FieldInfo? MineRock5HitAreaHealthField = AccessTools.Field(typeof(MineRock5).GetNestedType("HitArea", BindingFlags.NonPublic), "m_health"); private static List _configuration = new List(); private static string _configurationSignature = ""; private static bool _initialized; private static int? _lastProcessedSnapshotSignature; private static int? _lastProcessedGameDataSignature; private static ObjectRuntimeDropConfigurationState _runtimeDropConfigurationState = ObjectRuntimeDropConfigurationState.Empty; private static string _runtimeDropConfigurationSignature = ""; private static int? _runtimeDropConfigurationGameDataSignature; private static int _cachedGameDataSignatureFrame = -1; private static int _cachedGameDataSignatureValue; private static int _cachedSnapshotSignatureFrame = -1; private static int _cachedSnapshotSignatureValue; private static bool _referenceArtifactsAutoRefreshConsumed; private static readonly Dictionary _lastAppliedEntrySignaturesByPrefab = new Dictionary(StringComparer.OrdinalIgnoreCase); private static string _lastAppliedConfigurationSignature = ""; private static int? _lastAppliedGameDataSignature; private static bool? _lastAppliedDomainEnabled; private static bool _lastAppliedSynchronizedPayloadReady; private static bool _synchronizedPayloadReady; private static int? _lastCommittedAuthorityEpoch; private static int _reconcileQueueEpoch; private static int _snapshotBuildVersion; private static PendingSnapshotBuildState? _pendingSnapshotBuild; private const string MockPrefabPrefix = "JVLmock_"; private const int GroupConditionalApplyPlanCacheLimit = 2048; private const int GroupConditionalApplyPlanCacheTrimTarget = 1536; private static readonly DomainConfigurationRuntime ConfigurationRuntime = new DomainConfigurationRuntime(new DomainLoadHooks(ParseLocalConfigurationDocuments, BuildSyncedConfigurationState, CommitSyncedConfigurationState, RejectLocalConfigurationPayload, (SyncedObjectConfigurationState state) => state.Configuration.Count, LogPartiallyAcceptedLocalConfigurationHook, LogLocalConfigurationLoaded, OnSourceOfTruthPayloadUnchanged, delegate { ConfigurationDomainHost.PublishSyncedPayload(DropNSpawnPlugin.IsSourceOfTruth, Descriptor, _configuration, _configurationSignature); }), new DomainSyncHooks(delegate(out List configuration, out string payloadToken) { return ConfigurationDomainHost.TryGetSyncedEntries(Descriptor, out configuration, out payloadToken); }, (string payloadToken) => ConfigurationDomainHost.ShouldSkipSyncedPayload(LoadState, payloadToken, Volatile.Read(ref _synchronizedPayloadReady)), BuildSyncedConfigurationState, CommitSyncedConfigurationState, (SyncedObjectConfigurationState state) => state.ActiveEntriesByPrefab.Count, "ServerSync:DropNSpawnObject", delegate { ConfigurationDomainHost.HandleWaitingForSyncedPayload(MarkSyncedPayloadPending, "Waiting for synchronized object override payload from the server."); }, LogSyncedObjectConfigurationLoaded, LogSyncedObjectConfigurationFailure)); private static readonly Dictionary EmptyEntrySignatures = new Dictionary(StringComparer.OrdinalIgnoreCase); private static readonly ObjectConditionPlanCacheState ConditionPlanCacheState = new ObjectConditionPlanCacheState(); private static int _invalidEntryWarningSuppressionDepth; private static readonly ObjectLazyRuntimeState LazyRuntimeState = new ObjectLazyRuntimeState(); private static readonly ObjectLiveRegistryState LiveRegistryState = new ObjectLiveRegistryState(); private static readonly ObjectPrefabProfileCatalogState PrefabProfileCatalogState = new ObjectPrefabProfileCatalogState(); private static readonly ObjectReconcileQueueState ReconcileQueueState = new ObjectReconcileQueueState(); internal static DomainDescriptor Descriptor => Module.DescriptorTyped; internal static DomainTransportMetadata TransportMetadata => Module.TransportMetadataTyped; private static DomainLoadState LoadState => ConfigurationRuntime.LoadState; private static string ReferenceConfigurationPath => Path.Combine(DropNSpawnPlugin.YamlConfigDirectoryPath, PluginSettingsFacade.GetYamlDomainFilePrefix("object") + ".reference.yml"); private static string LocationReferenceConfigurationPath => Path.Combine(DropNSpawnPlugin.YamlConfigDirectoryPath, PluginSettingsFacade.GetYamlDomainFilePrefix("object") + ".locations.reference.yml"); private static string PrimaryOverrideConfigurationPathYml => Path.Combine(DropNSpawnPlugin.YamlConfigDirectoryPath, PluginSettingsFacade.GetYamlDomainFilePrefix("object") + ".yml"); private static string PrimaryOverrideConfigurationPathYaml => Path.Combine(DropNSpawnPlugin.YamlConfigDirectoryPath, PluginSettingsFacade.GetYamlDomainFilePrefix("object") + ".yaml"); private static string FullScaffoldConfigurationPath => Path.Combine(DropNSpawnPlugin.YamlConfigDirectoryPath, PluginSettingsFacade.GetYamlDomainFilePrefix("object") + ".full.yml"); internal static string RulesWatcherPattern => DropNSpawnPlugin.YamlRulesWatcherPattern; private static void ApplyDesiredStateToPrefabs(ObjectDesiredState desiredState) { if (desiredState.DomainEnabled) { ApplyConfigurationToPrefabs(desiredState, desiredState.DirtyPrefabs); } } private static void ApplyDesiredStateToLiveObjects(ObjectDesiredState desiredState) { if (!desiredState.NeedsLiveReload) { return; } if (desiredState.ApplyPlan.SameGameData && desiredState.LiveDirtyPrefabs != null) { if (desiredState.LiveDirtyPrefabs.Count != 0) { if (desiredState.QueueLiveReconcile) { QueueReapplyActiveEntriesToLiveObjects(desiredState.LiveDirtyPrefabs); } else { ReapplyActiveEntriesToLiveObjects(desiredState, desiredState.DomainEnabled, desiredState.LiveDirtyPrefabs); } } } else if (desiredState.QueueLiveReconcile) { QueueReapplyActiveEntriesToLiveObjects(); } else { ReapplyActiveEntriesToLiveObjects(desiredState, desiredState.DomainEnabled); } } private static void ApplyConfigurationToPrefabs(ObjectDesiredState desiredState, HashSet? targetPrefabs = null) { IReadOnlyDictionary plansByPrefab = desiredState.RuntimeConfigurationState.PlansByPrefab; object obj; if (targetPrefabs == null) { obj = plansByPrefab.Keys; } else { obj = targetPrefabs; } foreach (string item in (IEnumerable)obj) { if (!plansByPrefab.TryGetValue(item, out var value)) { continue; } List activeEntries = value.ActiveEntries; if (!SnapshotsByPrefab.TryGetValue(item, out PrefabSnapshot value2)) { foreach (PrefabConfigurationEntry item2 in activeEntries) { WarnInvalidEntry("Object prefab '" + item + "' from " + DescribeEntrySource(item2) + " was not found in ZNetScene."); } continue; } foreach (PrefabConfigurationEntry item3 in activeEntries) { ApplyConfiguredComponents(value2.Prefab, value2, item3, updateRuntimeState: false, allowConditionalMatches: false); } ApplyEffectiveDropTableOverrides(value2.Prefab, value2, activeEntries, allowConditionalMatches: false); } } private static void ReapplyActiveEntriesToLiveObjects(ObjectDesiredState desiredState, bool domainEnabled, HashSet? dirtyPrefabs = null) { IReadOnlyDictionary plansByPrefab = desiredState.RuntimeConfigurationState.PlansByPrefab; foreach (GameObject item in (dirtyPrefabs == null) ? GetRegisteredLiveObjects() : GetRegisteredLiveObjects(dirtyPrefabs)) { string prefabName = GetPrefabName(item); if (!RequiresLiveReconcileForPrefab(prefabName)) { continue; } RegisterLiveObject(item, prefabName); if (SnapshotsByPrefab.TryGetValue(prefabName, out PrefabSnapshot value)) { RestoreConfiguredComponents(item, value, CreateRestoreMask(value), updateRuntimeState: true); if (domainEnabled && plansByPrefab.TryGetValue(prefabName, out var value2)) { ReconcileConfiguredInstance(item, value, value2.ActiveEntries, clearCreatorRestrictedContainerContents: false); } } } } private static void QueueReapplyActiveEntriesToLiveObjects(HashSet? dirtyPrefabs = null) { foreach (GameObject item in (dirtyPrefabs == null) ? GetRegisteredLiveObjects() : GetRegisteredLiveObjects(dirtyPrefabs)) { string prefabName = GetPrefabName(item); if (prefabName.Length != 0 && RequiresLiveReconcileForPrefab(prefabName)) { RegisterLiveObject(item, prefabName); if (SnapshotsByPrefab.ContainsKey(prefabName)) { QueueTrackedObjectInstanceReconcileLocked(item, prefabName, clearCreatorRestrictedContainerContents: false); } } } } internal static bool ShouldReloadForPath(string? path) { if (PluginSettingsFacade.IsEligibleOverrideConfigurationPath(path)) { return IsOverrideConfigurationFileName(Path.GetFileName(path ?? "")); } return false; } internal static void Initialize() { lock (Sync) { if (!_initialized) { LoadConfiguration(); _initialized = true; } } } internal static void ReloadConfiguration() { lock (Sync) { LoadConfiguration(); ApplyIfReady(queueLiveReconcile: true); PromoteQueuedReconcileGroupsLocked(LiveObjectComponentKind.TreeBase | LiveObjectComponentKind.TreeLog); DrainQueuedHighPriorityReconcilesLocked(); } } internal static void MarkSyncedPayloadPending() { lock (Sync) { ConfigurationRuntime.MarkSyncedPayloadPending(DropNSpawnPlugin.IsSourceOfTruth, delegate { Volatile.Write(ref _synchronizedPayloadReady, value: false); }); } } internal static void EnterPendingSyncedPayloadState() { lock (Sync) { Dictionary previousVneiEntrySignatures = BuildVneiEntrySignaturesByPrefab(); HashSet previouslyAppliedPrefabs = BuildLastAppliedPrefabs(); ConfigurationRuntime.EnterPendingSyncedPayloadState(DropNSpawnPlugin.IsSourceOfTruth, ResetLoadedConfigurationState, delegate { _configurationSignature = ""; _lastAppliedSynchronizedPayloadReady = false; RestoreSnapshots(previouslyAppliedPrefabs); RestoreTrackedLiveObjects(previouslyAppliedPrefabs); RefreshVneiCompatibility(previousVneiEntrySignatures); }); } } private static bool CanUseCurrentRuntimeState() { if (!DropNSpawnPlugin.IsSourceOfTruth && !Volatile.Read(ref _synchronizedPayloadReady)) { return _lastCommittedAuthorityEpoch == NetworkPayloadSyncSupport.CurrentAuthorityEpoch; } return true; } private static HashSet BuildLastAppliedPrefabs() { HashSet hashSet = new HashSet(StringComparer.OrdinalIgnoreCase); if (!_lastAppliedDomainEnabled.GetValueOrDefault()) { return hashSet; } foreach (string key in _lastAppliedEntrySignaturesByPrefab.Keys) { hashSet.Add(key); } return hashSet; } internal static bool HandleExpandWorldDataReady() { lock (Sync) { if (!DropNSpawnPlugin.IsSourceOfTruth) { return false; } string text = NetworkPayloadSyncSupport.ComputeObjectConfigurationSignature(_configuration); if (string.Equals(text, _configurationSignature, StringComparison.Ordinal)) { return false; } _configurationSignature = text; ConfigurationDomainHost.PublishSyncedPayload(DropNSpawnPlugin.IsSourceOfTruth, Descriptor, _configuration, _configurationSignature); ApplyIfReady(queueLiveReconcile: true); return true; } } internal static void ApplySyncedPayload() { lock (Sync) { Dictionary previousVneiEntrySignatures = BuildVneiEntrySignaturesByPrefab(); ConfigurationRuntime.ApplySyncedPayload(delegate { RefreshVneiCompatibility(previousVneiEntrySignatures); ApplyIfReady(queueLiveReconcile: true); }); } } internal static void OnGameDataReady(string source) { lock (Sync) { if (!_initialized) { Initialize(); } if (!IsGameDataReady()) { return; } int num = ComputeGameDataSignature(); int num2 = ComputeSnapshotSignature(); if (_lastProcessedGameDataSignature != num) { if (_lastProcessedSnapshotSignature != num2 || Snapshots.Count == 0) { ScheduleSnapshotBuildLocked(source, num, num2); } else { CompleteGameDataReadyLocked(source, num, num2); } } } } internal static bool HasPendingSnapshotBuildWork() { lock (Sync) { return _pendingSnapshotBuild != null; } } internal static bool ProcessPendingSnapshotBuildStep(float deadline) { GameObject val = null; PendingSnapshotBuildState pendingSnapshotBuild; lock (Sync) { pendingSnapshotBuild = _pendingSnapshotBuild; if (pendingSnapshotBuild == null) { return false; } if (pendingSnapshotBuild.NextIndex >= pendingSnapshotBuild.Prefabs.Count) { CompletePendingSnapshotBuildLocked(pendingSnapshotBuild); return true; } val = pendingSnapshotBuild.Prefabs[pendingSnapshotBuild.NextIndex]; pendingSnapshotBuild.NextIndex++; } PrefabSnapshot prefabSnapshot = (((Object)(object)val != (Object)null) ? CaptureSnapshot(val) : null); lock (Sync) { if (_pendingSnapshotBuild == null || pendingSnapshotBuild == null || _pendingSnapshotBuild != pendingSnapshotBuild) { return true; } if (prefabSnapshot != null) { pendingSnapshotBuild.Snapshots.Add(prefabSnapshot); if (!pendingSnapshotBuild.SnapshotsByPrefab.ContainsKey(((Object)prefabSnapshot.Prefab).name)) { pendingSnapshotBuild.SnapshotsByPrefab.Add(((Object)prefabSnapshot.Prefab).name, prefabSnapshot); } } if (pendingSnapshotBuild.NextIndex >= pendingSnapshotBuild.Prefabs.Count && Time.realtimeSinceStartup <= deadline) { CompletePendingSnapshotBuildLocked(pendingSnapshotBuild); } } return true; } internal static bool TryWriteFullScaffoldConfigurationFile(out string path, out string error) { lock (Sync) { path = FullScaffoldConfigurationPath; error = ""; if (!IsGameDataReady() && Snapshots.Count == 0) { error = "Object game data is not ready yet."; return false; } CaptureSnapshotsIfNeeded(); Directory.CreateDirectory(DropNSpawnPlugin.YamlConfigDirectoryPath); File.WriteAllText(path, BuildFullScaffoldConfigurationTemplate()); DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)("Wrote object full scaffold configuration to " + path + ".")); return true; } } internal static void RefreshReferenceConfigurationFile() { lock (Sync) { if (IsGameDataReady()) { CaptureSnapshotsIfNeeded(); string content = BuildReferenceConfigurationTemplate(); string content2 = BuildLocationReferenceConfigurationTemplate(); WriteReferenceConfigurationFile(content, "Updated object reference configurations at " + ReferenceConfigurationPath + " and " + LocationReferenceConfigurationPath + "."); WriteLocationReferenceConfigurationFile(content2); ReferenceRefreshSupport.RecordAutoUpdateState("object", ReferenceConfigurationPath, ComputeReferenceSourceSignature(), null, "2026-03-26-full-rewrite-v1"); } } } private static bool IsGameDataReady() { if ((Object)(object)ZNetScene.instance != (Object)null) { return (Object)(object)ObjectDB.instance != (Object)null; } return false; } private static void EnsureReferenceArtifactsUpToDate() { if (!IsGameDataReady()) { return; } string sourceSignature = ComputeReferenceSourceSignature(); bool num = File.Exists(ReferenceConfigurationPath); bool flag = File.Exists(LocationReferenceConfigurationPath); bool flag2 = PluginSettingsFacade.ShouldAutoCreateMissingReferenceFiles(); bool flag3 = !num && flag2; bool flag4 = !flag && flag2; if (flag3 || flag4) { CaptureSnapshotsIfNeeded(); if (flag3) { WriteReferenceConfigurationFile(BuildReferenceConfigurationTemplate(), "Created object reference configuration at " + ReferenceConfigurationPath + "."); ReferenceRefreshSupport.RecordAutoUpdateState("object", ReferenceConfigurationPath, sourceSignature, null, "2026-03-26-full-rewrite-v1"); } if (flag4) { WriteLocationReferenceConfigurationFile(BuildLocationReferenceConfigurationTemplate()); DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)("Created object location reference configuration at " + LocationReferenceConfigurationPath + ".")); ReferenceRefreshSupport.RecordAutoUpdateState("object.locations", LocationReferenceConfigurationPath, sourceSignature, null, "2026-03-26-full-rewrite-v1"); } } else { if (!PluginSettingsFacade.ShouldAutoUpdateReferenceFiles()) { return; } bool flag5 = !ReferenceRefreshSupport.ShouldSkipAutoUpdate("object", ReferenceConfigurationPath, sourceSignature, "2026-03-26-full-rewrite-v1"); bool flag6 = !ReferenceRefreshSupport.ShouldSkipAutoUpdate("object.locations", LocationReferenceConfigurationPath, sourceSignature, "2026-03-26-full-rewrite-v1"); if (flag5 || flag6) { CaptureSnapshotsIfNeeded(); if (flag5) { WriteReferenceConfigurationFile(BuildReferenceConfigurationTemplate(), "Updated object reference configuration at " + ReferenceConfigurationPath + "."); ReferenceRefreshSupport.RecordAutoUpdateState("object", ReferenceConfigurationPath, sourceSignature, null, "2026-03-26-full-rewrite-v1"); } if (flag6) { WriteLocationReferenceConfigurationFile(BuildLocationReferenceConfigurationTemplate()); DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)("Updated object location reference configuration at " + LocationReferenceConfigurationPath + ".")); ReferenceRefreshSupport.RecordAutoUpdateState("object.locations", LocationReferenceConfigurationPath, sourceSignature, null, "2026-03-26-full-rewrite-v1"); } } } } private static bool EnsurePrimaryOverrideConfigurationFileExists() { if (File.Exists(PrimaryOverrideConfigurationPathYml) || File.Exists(PrimaryOverrideConfigurationPathYaml) || EnumerateSupplementalOverrideConfigurationPaths().Any()) { return false; } if (!IsGameDataReady() || Snapshots.Count == 0) { return false; } Directory.CreateDirectory(DropNSpawnPlugin.YamlConfigDirectoryPath); File.WriteAllText(PrimaryOverrideConfigurationPathYml, BuildPrimaryOverrideConfigurationTemplate()); DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)("Created object override configuration at " + PrimaryOverrideConfigurationPathYml + ".")); return true; } private static void LoadConfiguration() { Dictionary previousVneiEntrySignatures = BuildVneiEntrySignaturesByPrefab(); if (DropNSpawnPlugin.IsSourceOfTruth) { if (ConfigurationRuntime.ReloadSourceOfTruth(EnumerateOverrideConfigurationPaths().ToList()) == DomainReloadOutcome.Loaded) { RefreshVneiCompatibility(previousVneiEntrySignatures); } } else if (ConfigurationRuntime.ReloadSynced() == DomainReloadOutcome.Loaded) { RefreshVneiCompatibility(previousVneiEntrySignatures); } } private static void RefreshVneiCompatibility(Dictionary previousVneiEntrySignatures) { RefreshVneiCompatibility(previousVneiEntrySignatures, BuildVneiEntrySignaturesByPrefab()); } private static void RefreshVneiCompatibility(Dictionary previousVneiEntrySignatures, Dictionary currentVneiEntrySignatures) { VneiCompatibility.RefreshObjectPrefabs(BuildDirtyPrefabs(previousVneiEntrySignatures, currentVneiEntrySignatures)); } private static void ScheduleSnapshotBuildLocked(string source, int gameDataSignature, int snapshotSignature) { if (_pendingSnapshotBuild == null || _pendingSnapshotBuild.GameDataSignature != gameDataSignature || _pendingSnapshotBuild.SnapshotSignature != snapshotSignature) { PendingSnapshotBuildState pendingSnapshotBuildState = new PendingSnapshotBuildState(); pendingSnapshotBuildState.BuildVersion = ++_snapshotBuildVersion; pendingSnapshotBuildState.GameDataSignature = gameDataSignature; pendingSnapshotBuildState.SnapshotSignature = snapshotSignature; pendingSnapshotBuildState.Source = source; pendingSnapshotBuildState.Prefabs.AddRange(EnumerateRelevantPrefabs()); _pendingSnapshotBuild = pendingSnapshotBuildState; } } private static void CompletePendingSnapshotBuildLocked(PendingSnapshotBuildState buildState) { if (_pendingSnapshotBuild == null || _pendingSnapshotBuild != buildState) { return; } Snapshots.Clear(); Snapshots.AddRange(buildState.Snapshots); SnapshotsByPrefab.Clear(); foreach (var (key, value) in buildState.SnapshotsByPrefab) { SnapshotsByPrefab[key] = value; } _pendingSnapshotBuild = null; CompleteGameDataReadyLocked(buildState.Source, buildState.GameDataSignature, buildState.SnapshotSignature); } private static void CompleteGameDataReadyLocked(string source, int gameDataSignature, int snapshotSignature) { EnsureLiveObjectRegistrySessionLocked(); ClearQueuedReconcileState(); if (DropNSpawnPlugin.IsSourceOfTruth) { if (!_referenceArtifactsAutoRefreshConsumed) { EnsureReferenceArtifactsUpToDate(); _referenceArtifactsAutoRefreshConsumed = true; } if (EnsurePrimaryOverrideConfigurationFileExists()) { LoadConfiguration(); } } else { _referenceArtifactsAutoRefreshConsumed = true; } ApplyIfReady(queueLiveReconcile: true); _lastProcessedSnapshotSignature = snapshotSignature; _lastProcessedGameDataSignature = gameDataSignature; DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)("DropNSpawn processed after " + source + ".")); } private static void ResetLoadedConfigurationState() { ClearQueuedReconcileState(); ActiveEntriesByPrefab.Clear(); PrefabProfileCatalogState.ClearCurrentProfiles(); VneiEntriesByPrefab.Clear(); MissingComponentWarnings.Clear(); InvalidEntryWarnings.Clear(); _runtimeDropConfigurationState = ObjectRuntimeDropConfigurationState.Empty; _runtimeDropConfigurationSignature = ""; _runtimeDropConfigurationGameDataSignature = null; _configuration = new List(); Volatile.Write(ref _synchronizedPayloadReady, value: false); } private static List CloneAndNormalizeConfigurationEntries(List? configuration, string sourceName) { List list = NetworkPayloadSyncSupport.CloneEntries(Descriptor, configuration); foreach (PrefabConfigurationEntry item in list) { NormalizeEntry(item); item.SourcePath = (string.IsNullOrWhiteSpace(item.SourcePath) ? sourceName : item.SourcePath); } return list; } private static List PrepareLocalConfigurationEntries(List? configuration, string sourceName, List warnings) { List list = CloneAndNormalizeConfigurationEntries(configuration, sourceName); List list2 = new List(); foreach (PrefabConfigurationEntry item in list) { if (TryAcceptLocalConfigurationEntry(item, warnings)) { list2.Add(item); } } return list2; } private static bool TryAcceptLocalConfigurationEntry(PrefabConfigurationEntry entry, List warnings) { if (!entry.Enabled) { return true; } string text = CreateConfigurationContext(entry); if (string.IsNullOrWhiteSpace(entry.Prefab)) { warnings.Add("Entry '" + text + "' is missing required prefab."); return false; } if (!TryResolveConfiguredObjectPrefab(entry.Prefab, out var hasSupportedObjectComponents)) { warnings.Add("Entry '" + text + "' references unknown object prefab '" + entry.Prefab + "'."); return false; } if (!hasSupportedObjectComponents) { warnings.Add("Entry '" + text + "' references '" + entry.Prefab + "', but it is not a supported object prefab."); return false; } return true; } private static bool TryResolveConfiguredObjectPrefab(string prefabName, out bool hasSupportedObjectComponents) { hasSupportedObjectComponents = true; if ((Object)(object)ZNetScene.instance == (Object)null || string.IsNullOrWhiteSpace(prefabName)) { return true; } GameObject prefab = ZNetScene.instance.GetPrefab(prefabName.Trim()); if ((Object)(object)prefab == (Object)null) { hasSupportedObjectComponents = false; return false; } hasSupportedObjectComponents = HasRelevantLiveObjectComponents(prefab); return true; } private static SyncedObjectConfigurationState BuildSyncedConfigurationState(List configuration, string sourceName) { using (BeginInvalidEntryWarningSuppressionForSyncedClientBuild(sourceName)) { SyncedObjectConfigurationState syncedObjectConfigurationState = new SyncedObjectConfigurationState(); foreach (PrefabConfigurationEntry item in CloneAndNormalizeConfigurationEntries(configuration, sourceName)) { if (!string.IsNullOrWhiteSpace(item.Prefab)) { RemoveEffectiveConfigurationEntry(syncedObjectConfigurationState.Configuration, syncedObjectConfigurationState.ActiveEntriesByPrefab, item.Prefab, item.RuleId); if (item.Enabled) { syncedObjectConfigurationState.Configuration.Add(item); GetOrCreateActiveEntries(syncedObjectConfigurationState.ActiveEntriesByPrefab, item.Prefab).Add(item); } } } RefreshConfiguredPrefabProfiles(syncedObjectConfigurationState.ActiveEntriesByPrefab, syncedObjectConfigurationState.ConfiguredComponentKindsByPrefab, syncedObjectConfigurationState.ReconcileComponentKindsByPrefab); RebuildVneiDisplayEntries(syncedObjectConfigurationState.Configuration, syncedObjectConfigurationState.VneiEntriesByPrefab); syncedObjectConfigurationState.VneiEntrySignaturesByPrefab = BuildVneiEntrySignaturesByPrefab(syncedObjectConfigurationState.VneiEntriesByPrefab); syncedObjectConfigurationState.ConfigurationSignature = NetworkPayloadSyncSupport.ComputeObjectConfigurationSignature(syncedObjectConfigurationState.Configuration); return syncedObjectConfigurationState; } } private static void CommitSyncedConfigurationState(SyncedObjectConfigurationState state, string payloadToken) { ResetLoadedConfigurationState(); _configuration = state.Configuration; string key; List value; foreach (KeyValuePair> item in state.ActiveEntriesByPrefab) { item.Deconstruct(out key, out value); string key2 = key; List value2 = value; ActiveEntriesByPrefab[key2] = value2; } PrefabProfileCatalogState.ApplySyncedProfiles(state.ConfiguredComponentKindsByPrefab, state.ReconcileComponentKindsByPrefab); foreach (KeyValuePair> item2 in state.VneiEntriesByPrefab) { item2.Deconstruct(out key, out value); string key3 = key; List value3 = value; VneiEntriesByPrefab[key3] = value3; } _configurationSignature = state.ConfigurationSignature; LoadState.LastLoadedPayload = payloadToken; LoadState.LastRejectedPayload = ""; LoadState.PendingStrictPayload = ""; LoadState.LastRejectedValidationKey = ""; Volatile.Write(ref _synchronizedPayloadReady, value: true); _lastCommittedAuthorityEpoch = (DropNSpawnPlugin.IsSourceOfTruth ? null : new int?(NetworkPayloadSyncSupport.CurrentAuthorityEpoch)); } private static LocalLoadResult ParseLocalConfigurationDocuments(List documents) { List list = new List(); List list2 = new List(); List list3 = new List(); int num = 0; int num2 = 0; foreach (ConfigurationLoadSupport.LocalYamlDocument document in documents) { if (document.ReadError != null) { list2.Add("Failed to read " + document.Path + ". " + document.ReadError); continue; } try { ParsedObjectConfigurationDocument parsedObjectConfigurationDocument = ParseConfiguration(document.Yaml ?? "", document.Path); list3.AddRange(parsedObjectConfigurationDocument.Warnings); num += parsedObjectConfigurationDocument.Configuration.Count; List collection = PrepareLocalConfigurationEntries(parsedObjectConfigurationDocument.Configuration, document.Path, list3); list.AddRange(collection); num2++; } catch (Exception ex) { list2.Add($"Failed to parse {document.Path}{FormatYamlExceptionLocation(ex)}. Object override YAML must start with a root list like '- prefab: ...'. {ex}"); } } return new LocalLoadResult { Entries = list, Errors = list2, Warnings = list3, ParsedEntryCount = num, LoadedFileCount = num2 }; } private static void RejectLocalConfigurationPayload(string payload, IEnumerable errors) { if (string.Equals(LoadState.LastRejectedPayload, payload, StringComparison.Ordinal)) { return; } LoadState.LastRejectedPayload = payload; LoadState.PendingStrictPayload = ""; LoadState.LastRejectedValidationKey = ""; DropNSpawnPlugin.DropNSpawnLogger.LogError((object)"Rejected object reload. Keeping the previous authoritative object configuration."); foreach (string item in errors.Where((string message) => !string.IsNullOrWhiteSpace(message)).Distinct(StringComparer.OrdinalIgnoreCase)) { DropNSpawnPlugin.DropNSpawnLogger.LogError((object)item); } } private static bool RemoveEffectiveConfigurationEntry(string prefabName, string ruleId) { bool result = RemoveEffectiveConfigurationEntry(_configuration, ActiveEntriesByPrefab, prefabName, ruleId); RefreshConfiguredPrefabProfile(prefabName); return result; } private static bool RemoveEffectiveConfigurationEntry(List configuration, Dictionary> activeEntriesByPrefab, string prefabName, string ruleId) { bool result = false; for (int num = configuration.Count - 1; num >= 0; num--) { PrefabConfigurationEntry prefabConfigurationEntry = configuration[num]; if (string.Equals(prefabConfigurationEntry.Prefab, prefabName, StringComparison.OrdinalIgnoreCase) && string.Equals(prefabConfigurationEntry.RuleId, ruleId, StringComparison.Ordinal)) { configuration.RemoveAt(num); result = true; } } if (activeEntriesByPrefab.TryGetValue(prefabName, out List 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); } } return result; } private static ParsedObjectConfigurationDocument ParseConfiguration(string yaml, string? sourcePath) { ParsedObjectConfigurationDocument parsedObjectConfigurationDocument = new ParsedObjectConfigurationDocument(); if (string.IsNullOrWhiteSpace(yaml)) { return parsedObjectConfigurationDocument; } checked { using StringReader input = new StringReader(yaml); YamlStream yamlStream = new YamlStream(); yamlStream.Load(input); if (yamlStream.Documents.Count == 0) { return parsedObjectConfigurationDocument; } YamlSequenceNode obj = yamlStream.Documents[0].RootNode as YamlSequenceNode; if (obj == null) { Mark start = yamlStream.Documents[0].RootNode.Start; Mark end = yamlStream.Documents[0].RootNode.End; throw new YamlException(in start, in end, "Object override YAML root must be a sequence."); } foreach (YamlNode child in obj.Children) { if (!(child is YamlMappingNode yamlMappingNode)) { parsedObjectConfigurationDocument.Warnings.Add("Skipped object YAML node at " + FormatYamlNodeLocation(sourcePath, child.Start) + ". Expected a list item object like '- prefab: wood' but found " + DescribeYamlNode(child) + "."); continue; } try { string input2 = SerializeYamlNode(yamlMappingNode); PrefabConfigurationEntry prefabConfigurationEntry = Deserializer.Deserialize(input2) ?? new PrefabConfigurationEntry(); prefabConfigurationEntry.SourceLine = (int)yamlMappingNode.Start.Line; prefabConfigurationEntry.SourceColumn = (int)yamlMappingNode.Start.Column; parsedObjectConfigurationDocument.Configuration.Add(prefabConfigurationEntry); } catch (Exception ex) { parsedObjectConfigurationDocument.Warnings.Add("Skipped invalid object entry at " + FormatYamlNodeLocation(sourcePath, yamlMappingNode.Start) + ". " + FormatEntryParseFailure(ex)); } } return parsedObjectConfigurationDocument; } } private static string SerializeYamlNode(YamlNode node) { YamlStream yamlStream = new YamlStream(new YamlDocument(node)); using StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture); yamlStream.Save(stringWriter, assignAnchors: false); return stringWriter.ToString(); } private static string DescribeYamlNode(YamlNode node) { if (node is YamlScalarNode yamlScalarNode) { string text = yamlScalarNode.Value ?? ""; if (text.Length != 0) { return "scalar '" + text + "'"; } return "an empty scalar"; } if (node is YamlSequenceNode) { return "a nested sequence"; } if (node is YamlMappingNode) { return "a mapping"; } return "an unknown YAML node"; } private static string FormatYamlNodeLocation(string? sourcePath, Mark mark) { string text = (string.IsNullOrWhiteSpace(sourcePath) ? "inline YAML" : Path.GetFileName(sourcePath)); if (mark.Line > 0) { text = text + ":" + mark.Line.ToString(CultureInfo.InvariantCulture); } return text; } private static string FormatEntryParseFailure(Exception ex) { if (ex is YamlException ex2) { return ex2.Message; } return ex.Message; } private static void NormalizeEntry(PrefabConfigurationEntry entry) { entry.Prefab = (entry.Prefab ?? "").Trim(); NormalizeObjectConditions(entry.Conditions, entry.Prefab + ".conditions"); NormalizeDropTable(entry.DropOnDestroyed); NormalizeDropTable(entry.MineRock); NormalizeDropTable(entry.MineRock5); NormalizeDropTable(entry.TreeBase); NormalizeDropTable(entry.TreeLog); NormalizeDropTable(entry.Container); NormalizeDropTablePayload(entry.Pickable?.ExtraDrops); NormalizeDropTablePayload(entry.Fish?.ExtraDrops); NormalizeRandomPickableItems(entry.PickableItem?.RandomDrops); entry.RuleId = NormalizeOptionalRuleId(entry.RuleId) ?? BuildRuleId(entry); } private static void NormalizeObjectConditions(ConditionsDefinition? conditions, string context) { if (conditions != null) { IntRangeDefinition? level = conditions.Level; if ((level != null && level.HasValues()) || conditions.MinLevel.HasValue || conditions.MaxLevel.HasValue) { WarnInvalidEntry("Entry '" + context + "' uses conditions.level, but level filters are only valid for character-drop conditions. The key was ignored."); conditions.Level = null; conditions.MinLevel = null; conditions.MaxLevel = null; } List? states = conditions.States; if (states != null && states.Count > 0) { WarnInvalidEntry("Entry '" + context + "' uses conditions.states, but state filters are only valid for character-drop conditions. The key was ignored."); conditions.States = null; } List? factions = conditions.Factions; if (factions != null && factions.Count > 0) { WarnInvalidEntry("Entry '" + context + "' uses conditions.factions, but faction filters are only valid for character-drop conditions. The key was ignored."); conditions.Factions = null; } } } private static string BuildRuleId(PrefabConfigurationEntry entry) { PrefabConfigurationEntry entry2 = new PrefabConfigurationEntry { Prefab = entry.Prefab, Enabled = true, Conditions = entry.Conditions, DropOnDestroyed = entry.DropOnDestroyed, MineRock = entry.MineRock, MineRock5 = entry.MineRock5, TreeBase = entry.TreeBase, TreeLog = entry.TreeLog, Container = entry.Container, Destructible = entry.Destructible, Pickable = entry.Pickable, PickableItem = entry.PickableItem, Fish = entry.Fish }; return entry.Prefab + ":" + NetworkPayloadSyncSupport.ComputeObjectEntryIdentitySignature(entry2); } private static string? NormalizeOptionalRuleId(string? ruleId) { if (ruleId == null) { return null; } string text = ruleId.Trim(); if (text.Length != 0) { return text; } return null; } private static List GetOrCreateActiveEntries(string prefabName) { return GetOrCreateActiveEntries(ActiveEntriesByPrefab, prefabName); } private static List GetOrCreateActiveEntries(Dictionary> activeEntriesByPrefab, string prefabName) { if (!activeEntriesByPrefab.TryGetValue(prefabName, out List value)) { value = (activeEntriesByPrefab[prefabName] = new List()); } return value; } private static bool CanUseLazyDamageableScalarFastPath(PrefabConfigurationEntry entry, LiveObjectComponentKind componentKind) { if (componentKind != LiveObjectComponentKind.MineRock && componentKind != LiveObjectComponentKind.MineRock5 && componentKind != LiveObjectComponentKind.TreeBase && componentKind != LiveObjectComponentKind.TreeLog) { return false; } return !DropConditionEvaluator.HasDynamicConditions(entry.Conditions); } private static bool ContainerNeedsLiveMutation(PrefabConfigurationEntry entry) { return false; } private static PrefabConfigurationEntry? CreateVneiDisplayBaseEntry(PrefabConfigurationEntry? entry) { if (entry == null || !entry.Enabled || string.IsNullOrWhiteSpace(entry.Prefab)) { return null; } DropTableDefinition dropTableDefinition = CreateClientProjectionDropTableDefinition(entry.DropOnDestroyed); DamageableDropTableDefinition damageableDropTableDefinition = CreateClientProjectionDamageableDropTableDefinition(entry.MineRock); DamageableDropTableDefinition damageableDropTableDefinition2 = CreateClientProjectionDamageableDropTableDefinition(entry.MineRock5); DamageableDropTableDefinition damageableDropTableDefinition3 = CreateClientProjectionDamageableDropTableDefinition(entry.TreeBase); DamageableDropTableDefinition damageableDropTableDefinition4 = CreateClientProjectionDamageableDropTableDefinition(entry.TreeLog); DropTableDefinition dropTableDefinition2 = CreateClientProjectionDropTableDefinition(entry.Container); PickableDefinition pickableDefinition = CreateClientProjectionPickableDefinition(entry.Pickable); PickableItemDefinition pickableItemDefinition = CreateClientProjectionPickableItemDefinition(entry.PickableItem); FishDefinition fishDefinition = CreateClientProjectionFishDefinition(entry.Fish); DestructibleDefinition destructibleDefinition = CreateClientProjectionDestructibleDefinition(entry.Destructible); if (dropTableDefinition == null && damageableDropTableDefinition == null && damageableDropTableDefinition2 == null && damageableDropTableDefinition3 == null && damageableDropTableDefinition4 == null && dropTableDefinition2 == null && pickableDefinition == null && pickableItemDefinition == null && fishDefinition == null && destructibleDefinition == null) { return null; } return new PrefabConfigurationEntry { RuleId = entry.RuleId, Prefab = entry.Prefab, Enabled = true, Conditions = entry.Conditions, DropOnDestroyed = dropTableDefinition, MineRock = damageableDropTableDefinition, MineRock5 = damageableDropTableDefinition2, TreeBase = damageableDropTableDefinition3, TreeLog = damageableDropTableDefinition4, Container = dropTableDefinition2, Pickable = pickableDefinition, PickableItem = pickableItemDefinition, Fish = fishDefinition, Destructible = destructibleDefinition }; } private static DropTableDefinition? CreateClientProjectionDropTableDefinition(DropTableDefinition? definition) { if (!HasDropTableOverride(definition)) { return null; } return new DropTableDefinition { Rolls = CloneIntRange(definition.Rolls), DropMin = definition.DropMin, DropMax = definition.DropMax, DropChance = definition.DropChance, OneOfEach = definition.OneOfEach, Drops = CloneDropEntries(definition.Drops) }; } private static DamageableDropTableDefinition? CreateClientProjectionDamageableDropTableDefinition(DamageableDropTableDefinition? definition) { if (!HasDamageableOverride(definition)) { return null; } return new DamageableDropTableDefinition { Health = definition.Health, MinToolTier = definition.MinToolTier, Rolls = CloneIntRange(definition.Rolls), DropMin = definition.DropMin, DropMax = definition.DropMax, DropChance = definition.DropChance, OneOfEach = definition.OneOfEach, Drops = CloneDropEntries(definition.Drops) }; } private static PickableDefinition? CreateClientProjectionPickableDefinition(PickableDefinition? definition) { if (!HasClientProjectedPickableOverride(definition)) { return null; } return new PickableDefinition { OverrideName = definition.OverrideName, Drop = ((definition.Drop == null) ? null : new PickableDropDefinition { Item = definition.Drop.Item, Amount = definition.Drop.Amount, MinAmountScaled = definition.Drop.MinAmountScaled, DontScale = definition.Drop.DontScale }), ExtraDrops = CreateClientProjectionDropTablePayloadDefinition(definition.ExtraDrops) }; } private static PickableItemDefinition? CreateClientProjectionPickableItemDefinition(PickableItemDefinition? definition) { if (!HasPickableItemOverride(definition)) { return null; } return new PickableItemDefinition { RandomDrops = CloneRandomPickableItems(definition.RandomDrops), Drop = ((definition.Drop == null) ? null : new PickableItemDropDefinition { Item = definition.Drop.Item, Stack = definition.Drop.Stack }) }; } private static FishDefinition? CreateClientProjectionFishDefinition(FishDefinition? definition) { if (!HasFishOverride(definition)) { return null; } return new FishDefinition { ExtraDrops = CreateClientProjectionDropTablePayloadDefinition(definition.ExtraDrops) }; } private static DestructibleDefinition? CreateClientProjectionDestructibleDefinition(DestructibleDefinition? definition) { if (!HasDestructibleOverride(definition)) { return null; } return new DestructibleDefinition { Health = definition.Health, MinToolTier = definition.MinToolTier, DestructibleType = definition.DestructibleType, SpawnWhenDestroyed = definition.SpawnWhenDestroyed }; } private static DropTablePayloadDefinition? CreateClientProjectionDropTablePayloadDefinition(DropTablePayloadDefinition? definition) { if (!HasDropTableOverride(definition)) { return null; } return new DropTablePayloadDefinition { Rolls = CloneIntRange(definition.Rolls), DropMin = definition.DropMin, DropMax = definition.DropMax, DropChance = definition.DropChance, OneOfEach = definition.OneOfEach, Drops = CloneDropEntries(definition.Drops) }; } private static List? CloneDropEntries(List? definitions) { return definitions?.Select((DropEntryDefinition definition) => new DropEntryDefinition { Item = definition.Item, Stack = CloneIntRange(definition.Stack), StackMin = definition.StackMin, StackMax = definition.StackMax, Weight = definition.Weight, DontScale = definition.DontScale }).ToList(); } private static List? CloneRandomPickableItems(List? definitions) { return definitions?.Select((RandomPickableItemDefinition definition) => new RandomPickableItemDefinition { Item = definition.Item, Stack = CloneIntRange(definition.Stack), StackMin = definition.StackMin, StackMax = definition.StackMax, Weight = definition.Weight }).ToList(); } private static IntRangeDefinition? CloneIntRange(IntRangeDefinition? range) { if (range != null) { return new IntRangeDefinition { Min = range.Min, Max = range.Max }; } return null; } private static void RebuildVneiDisplayEntries(IEnumerable entries) { RebuildVneiDisplayEntries(entries, VneiEntriesByPrefab); } private static void RebuildVneiDisplayEntries(IEnumerable entries, Dictionary> vneiEntriesByPrefab) { vneiEntriesByPrefab.Clear(); foreach (PrefabConfigurationEntry item in entries ?? Enumerable.Empty()) { PrefabConfigurationEntry prefabConfigurationEntry = CreateVneiProjectionEntry(item); if (prefabConfigurationEntry != null) { if (!vneiEntriesByPrefab.TryGetValue(prefabConfigurationEntry.Prefab, out List value)) { value = new List(); vneiEntriesByPrefab[prefabConfigurationEntry.Prefab] = value; } value.Add(prefabConfigurationEntry); } } } private static PrefabConfigurationEntry? CreateVneiProjectionEntry(PrefabConfigurationEntry? entry) { if (entry == null || !entry.Enabled || string.IsNullOrWhiteSpace(entry.Prefab)) { return null; } PrefabConfigurationEntry prefabConfigurationEntry = CreateVneiDisplayBaseEntry(entry); if (prefabConfigurationEntry == null) { if (!HasDropTableOverride(entry.DropOnDestroyed) && !HasDamageableOverride(entry.MineRock) && !HasDamageableOverride(entry.MineRock5) && !HasDamageableOverride(entry.TreeBase) && !HasDamageableOverride(entry.TreeLog) && !HasDropTableOverride(entry.Container) && !HasFishOverride(entry.Fish) && !HasDestructibleOverride(entry.Destructible)) { return null; } prefabConfigurationEntry = new PrefabConfigurationEntry { RuleId = entry.RuleId, Prefab = entry.Prefab, Enabled = true, Conditions = entry.Conditions }; } prefabConfigurationEntry.PickableItem = null; return prefabConfigurationEntry; } private static Dictionary BuildVneiEntrySignaturesByPrefab() { return BuildVneiEntrySignaturesByPrefab(VneiEntriesByPrefab); } private static Dictionary BuildVneiEntrySignaturesByPrefab(Dictionary> vneiEntriesByPrefab) { return DomainEntrySignatureSupport.BuildSignaturesByKey(vneiEntriesByPrefab, (List entries) => NetworkPayloadSyncSupport.ComputeObjectConfigurationSignature(entries.OrderBy((PrefabConfigurationEntry entry) => entry.RuleId, StringComparer.Ordinal).ToList())); } private static List? GetVneiEntries(string prefabName) { if (VneiEntriesByPrefab.TryGetValue(prefabName ?? "", out List value)) { return value; } if (!ActiveEntriesByPrefab.TryGetValue(prefabName ?? "", out List value2)) { return null; } return value2; } private static bool HasDropTableOverride(DropTablePayloadDefinition? definition) { if (definition != null) { IntRangeDefinition? rolls = definition.Rolls; if ((rolls == null || !rolls.HasValues()) && !definition.DropMin.HasValue && !definition.DropMax.HasValue && !definition.DropChance.HasValue && !definition.OneOfEach.HasValue) { return definition.Drops != null; } return true; } return false; } private static bool HasDamageableHealthOverride(DamageableDropTableDefinition? definition) { return definition?.Health.HasValue ?? false; } private static bool HasDamageableMinToolTierOverride(DamageableDropTableDefinition? definition) { return definition?.MinToolTier.HasValue ?? false; } private static bool HasDamageableOverride(DamageableDropTableDefinition? definition) { if (!HasDropTableOverride(definition) && !HasDamageableHealthOverride(definition)) { return HasDamageableMinToolTierOverride(definition); } return true; } private static bool HasDestructibleHealthOverride(DestructibleDefinition? definition) { return definition?.Health.HasValue ?? false; } private static bool HasDestructibleMinToolTierOverride(DestructibleDefinition? definition) { return definition?.MinToolTier.HasValue ?? false; } private static bool HasDestructibleTypeOverride(DestructibleDefinition? definition) { return !string.IsNullOrWhiteSpace(definition?.DestructibleType); } private static bool HasDestructibleSpawnWhenDestroyedOverride(DestructibleDefinition? definition) { return !string.IsNullOrWhiteSpace(definition?.SpawnWhenDestroyed); } private static bool HasDestructibleComponentStateOverride(DestructibleDefinition? definition) { if (definition != null) { if (string.IsNullOrWhiteSpace(definition.DestructibleType)) { return !string.IsNullOrWhiteSpace(definition.SpawnWhenDestroyed); } return true; } return false; } private static bool HasDestructibleOverride(DestructibleDefinition? definition) { if (!HasDestructibleHealthOverride(definition) && !HasDestructibleMinToolTierOverride(definition)) { return HasDestructibleComponentStateOverride(definition); } return true; } private static void NormalizeDropTable(DropTableDefinition? definition) { if (definition != null) { NormalizeDropTablePayload(definition); } } private static void NormalizeDropTablePayload(DropTablePayloadDefinition? definition) { if (definition == null) { return; } IntRangeDefinition? rolls = definition.Rolls; if (rolls != null && rolls.HasValues()) { definition.DropMin = RangeFormatting.GetMin(definition.Rolls, definition.DropMin); definition.DropMax = RangeFormatting.GetMax(definition.Rolls, definition.DropMin, definition.DropMax); } if (definition.Drops == null) { return; } foreach (DropEntryDefinition drop in definition.Drops) { IntRangeDefinition? stack = drop.Stack; if (stack != null && stack.HasValues()) { drop.StackMin = RangeFormatting.GetMin(drop.Stack, drop.StackMin); drop.StackMax = RangeFormatting.GetMax(drop.Stack, drop.StackMin, drop.StackMax); } } } private static void NormalizeRandomPickableItems(List? items) { if (items == null) { return; } foreach (RandomPickableItemDefinition item in items) { IntRangeDefinition? stack = item.Stack; if (stack != null && stack.HasValues()) { item.StackMin = RangeFormatting.GetMin(item.Stack, item.StackMin); item.StackMax = RangeFormatting.GetMax(item.Stack, item.StackMin, item.StackMax); } } } private static bool HasPickableOverride(PickableDefinition? definition) { if (definition != null) { if (!HasPickableDropOverride(definition.Drop) && definition.OverrideName == null) { return HasDropTableOverride(definition.ExtraDrops); } return true; } return false; } private static bool HasClientVisiblePickableOverride(PickableDefinition? definition) { if (definition != null) { if (!HasPickableDropOverride(definition.Drop)) { return definition.OverrideName != null; } return true; } return false; } private static bool HasClientProjectedPickableOverride(PickableDefinition? definition) { if (definition != null) { if (!HasPickableDropOverride(definition.Drop) && definition.OverrideName == null) { return HasDropTableOverride(definition.ExtraDrops); } return true; } return false; } private static bool HasPickableDropOverride(PickableDropDefinition? definition) { if (definition != null) { if (string.IsNullOrWhiteSpace(definition.Item) && !definition.Amount.HasValue && !definition.MinAmountScaled.HasValue) { return definition.DontScale.HasValue; } return true; } return false; } private static bool HasPickableItemDropOverride(PickableItemDropDefinition? definition) { if (definition != null) { if (string.IsNullOrWhiteSpace(definition.Item)) { return definition.Stack.HasValue; } return true; } return false; } private static bool HasPickableItemOverride(PickableItemDefinition? definition) { if (definition != null) { if (!HasPickableItemDropOverride(definition.Drop)) { return definition.RandomDrops != null; } return true; } return false; } private static bool HasFishOverride(FishDefinition? definition) { if (definition != null) { return HasDropTableOverride(definition.ExtraDrops); } return false; } private static bool IsEventOnlyDropTableFastPathKind(LiveObjectComponentKind componentKind) { if (componentKind != LiveObjectComponentKind.DropOnDestroyed && componentKind != LiveObjectComponentKind.MineRock && componentKind != LiveObjectComponentKind.MineRock5 && componentKind != LiveObjectComponentKind.TreeBase && componentKind != LiveObjectComponentKind.TreeLog) { return componentKind == LiveObjectComponentKind.Container; } return true; } private static bool UsesLiveDropTableReconcile(LiveObjectComponentKind componentKind) { return !IsEventOnlyDropTableFastPathKind(componentKind); } private static bool RequiresLiveReconcile(DropTableDefinition? definition, LiveObjectComponentKind componentKind) { if (definition != null) { return !IsEventOnlyDropTableFastPathKind(componentKind); } return false; } private static bool RequiresLiveReconcile(DamageableDropTableDefinition? definition, LiveObjectComponentKind componentKind) { if (definition != null) { if (!HasDamageableHealthOverride(definition) && !HasDamageableMinToolTierOverride(definition)) { if (!IsEventOnlyDropTableFastPathKind(componentKind)) { return HasDropTableOverride(definition); } return false; } return true; } return false; } private static bool RequiresLiveReconcile(PrefabConfigurationEntry entry, DestructibleDefinition? definition) { if (definition == null) { return false; } if (HasDestructibleHealthOverride(definition) || HasDestructibleMinToolTierOverride(definition) || HasDestructibleTypeOverride(definition)) { return !CanUseLazyDestructibleScalarFastPath(entry); } return false; } private static bool CanUseLazyDestructibleScalarFastPath(PrefabConfigurationEntry entry) { return !DropConditionEvaluator.HasDynamicConditions(entry.Conditions); } private static bool ShouldReconcileLocally(GameObject gameObject) { return PluginSettingsFacade.IsObjectDomainEnabled(); } private static bool TryGetConditionalContext(GameObject gameObject, out string prefabName, out PrefabSnapshot snapshot, out List entries) { snapshot = null; entries = null; if (!CanUseCurrentRuntimeState()) { prefabName = ""; return false; } prefabName = GetPrefabName(gameObject); if (!ActiveEntriesByPrefab.TryGetValue(prefabName, out entries) || entries.Count == 0 || !SnapshotsByPrefab.TryGetValue(prefabName, out snapshot)) { return false; } if (!ShouldApplyToInstance(gameObject)) { return false; } return true; } private static bool TryGetConditionalDropContext(GameObject gameObject, out string prefabName, out PrefabSnapshot snapshot, out List compiledRules) { compiledRules = null; if (!TryGetConditionalContext(gameObject, out prefabName, out snapshot, out List _)) { return false; } EnsureRuntimeDropConfigurationState(); if (_runtimeDropConfigurationState.PlansByPrefab.TryGetValue(prefabName, out CompiledObjectPrefabPlan value) && (compiledRules = value.Rules) != null) { return compiledRules.Count > 0; } return false; } private static bool TryGetCompiledObjectDropRule(PrefabConfigurationEntry entry, out CompiledObjectDropRule? compiledRule) { EnsureRuntimeDropConfigurationState(); return _runtimeDropConfigurationState.RulesByEntry.TryGetValue(entry, out compiledRule); } private static bool TryGetStaticDropTableTemplate(string prefabName, LiveObjectComponentKind componentKind, out StaticCompiledDropTableTemplate? template) { template = null; EnsureRuntimeDropConfigurationState(); if (_runtimeDropConfigurationState.PlansByPrefab.TryGetValue(prefabName, out CompiledObjectPrefabPlan value)) { return value.StaticDropTableTemplates.TryGetValue(componentKind, out template); } return false; } private static bool TryGetOverrideDropTable(GameObject gameObject, Func payloadSelector, Func snapshotSelector, LiveObjectComponentKind componentKind, string contextSuffix, out DropTable? overrideTable) { return TryGetCachedEventDropTable(gameObject, payloadSelector, snapshotSelector, componentKind, out overrideTable); } internal static DropTable? OverrideConditionalDropOnDestroyed(DropOnDestroyed dropOnDestroyed) { lock (Sync) { if (!TryGetOverrideDropTable(((Component)dropOnDestroyed).gameObject, (CompiledObjectDropRule rule) => rule.DropOnDestroyed, (PrefabSnapshot snapshot) => snapshot.DropOnDestroyed, LiveObjectComponentKind.DropOnDestroyed, "DropOnDestroyed", out DropTable overrideTable)) { return null; } DropTable dropWhenDestroyed = dropOnDestroyed.m_dropWhenDestroyed; dropOnDestroyed.m_dropWhenDestroyed = overrideTable; return dropWhenDestroyed; } } internal static DropTable? OverrideConditionalMineRockDrops(MineRock mineRock) { lock (Sync) { if (!TryGetOverrideDropTable(((Component)mineRock).gameObject, (CompiledObjectDropRule rule) => rule.MineRock, (PrefabSnapshot snapshot) => snapshot.MineRock, LiveObjectComponentKind.MineRock, "MineRock", out DropTable overrideTable)) { return null; } DropTable dropItems = mineRock.m_dropItems; mineRock.m_dropItems = overrideTable; return dropItems; } } internal static DropTable? OverrideConditionalMineRock5Drops(MineRock5 mineRock5) { lock (Sync) { if (!TryGetOverrideDropTable(((Component)mineRock5).gameObject, (CompiledObjectDropRule rule) => rule.MineRock5, (PrefabSnapshot snapshot) => snapshot.MineRock5, LiveObjectComponentKind.MineRock5, "MineRock5", out DropTable overrideTable)) { return null; } DropTable dropItems = mineRock5.m_dropItems; mineRock5.m_dropItems = overrideTable; return dropItems; } } internal static DropTable? OverrideContainerDrops(Container container) { lock (Sync) { if (!TryGetEffectiveContainerDropTable(((Component)container).gameObject, out DropTable overrideTable)) { return null; } DropTable defaultItems = container.m_defaultItems; container.m_defaultItems = overrideTable; return defaultItems; } } private static bool TryGetEffectiveContainerDropTable(GameObject gameObject, out DropTable? overrideTable) { return TryGetCachedEventDropTable(gameObject, (CompiledObjectDropRule rule) => rule.Container, (PrefabSnapshot snapshot) => snapshot.Container, LiveObjectComponentKind.Container, out overrideTable); } internal static DropTable? OverrideConditionalTreeBaseDrops(TreeBase treeBase) { lock (Sync) { if (!TryGetOverrideDropTable(((Component)treeBase).gameObject, (CompiledObjectDropRule rule) => rule.TreeBase, (PrefabSnapshot snapshot) => snapshot.TreeBase, LiveObjectComponentKind.TreeBase, "TreeBase", out DropTable overrideTable)) { return null; } DropTable dropWhenDestroyed = treeBase.m_dropWhenDestroyed; treeBase.m_dropWhenDestroyed = overrideTable; return dropWhenDestroyed; } } internal static DropTable? OverrideConditionalTreeLogDrops(TreeLog treeLog) { lock (Sync) { if (!TryGetOverrideDropTable(((Component)treeLog).gameObject, (CompiledObjectDropRule rule) => rule.TreeLog, (PrefabSnapshot snapshot) => snapshot.TreeLog, LiveObjectComponentKind.TreeLog, "TreeLog", out DropTable overrideTable)) { return null; } DropTable dropWhenDestroyed = treeLog.m_dropWhenDestroyed; treeLog.m_dropWhenDestroyed = overrideTable; return dropWhenDestroyed; } } internal static GameObject? OverrideConditionalDestructibleSpawnWhenDestroyed(Destructible destructible) { lock (Sync) { if (!TryGetConditionalDropContext(((Component)destructible).gameObject, out string _, out PrefabSnapshot _, out List compiledRules)) { return null; } GameObject spawnWhenDestroyed = null; bool flag = false; foreach (CompiledObjectDropRule item in compiledRules) { CompiledDestructibleComponentDefinition? destructible2 = item.Destructible; if (destructible2 != null && destructible2.HasSpawnWhenDestroyedOverride && EntryMatches(((Component)destructible).gameObject, item.Entry, allowConditionalMatches: true)) { flag = true; spawnWhenDestroyed = item.Destructible.SpawnWhenDestroyed; } } if (!flag) { return null; } GameObject spawnWhenDestroyed2 = destructible.m_spawnWhenDestroyed; destructible.m_spawnWhenDestroyed = spawnWhenDestroyed; return spawnWhenDestroyed2; } } private static bool TryResolveLazyDamageableScalars(GameObject gameObject, LiveObjectComponentKind componentKind, out CompiledDamageableScalarDefinition resolvedScalars, out int signature) { resolvedScalars = null; signature = 0; if (!TryGetConditionalDropContext(gameObject, out string _, out PrefabSnapshot _, out List compiledRules)) { return false; } CompiledDamageableScalarDefinition compiledDamageableScalarDefinition = new CompiledDamageableScalarDefinition(); foreach (CompiledObjectDropRule item in compiledRules) { if (!CanUseLazyDamageableScalarFastPath(item.Entry, componentKind) || !EntryMatches(gameObject, item.Entry, allowConditionalMatches: true)) { continue; } CompiledDamageableScalarDefinition damageableScalarDefinition = GetDamageableScalarDefinition(item, componentKind); if (damageableScalarDefinition != null) { if (damageableScalarDefinition.HasHealthOverride) { compiledDamageableScalarDefinition.HasHealthOverride = true; compiledDamageableScalarDefinition.Health = damageableScalarDefinition.Health; } if (damageableScalarDefinition.HasMinToolTierOverride) { compiledDamageableScalarDefinition.HasMinToolTierOverride = true; compiledDamageableScalarDefinition.MinToolTier = damageableScalarDefinition.MinToolTier; } } } if (!compiledDamageableScalarDefinition.HasHealthOverride && !compiledDamageableScalarDefinition.HasMinToolTierOverride) { return false; } resolvedScalars = compiledDamageableScalarDefinition; signature = ComputeLazyDamageableScalarSignature(compiledDamageableScalarDefinition); return true; } private static bool TryResolveLazyDestructibleScalars(GameObject gameObject, out CompiledDestructibleComponentDefinition resolvedDefinition, out int signature) { resolvedDefinition = null; signature = 0; if (!TryGetConditionalDropContext(gameObject, out string _, out PrefabSnapshot _, out List compiledRules)) { return false; } CompiledDestructibleComponentDefinition compiledDestructibleComponentDefinition = new CompiledDestructibleComponentDefinition(); foreach (CompiledObjectDropRule item in compiledRules) { if (item.Destructible != null && CanUseLazyDestructibleScalarFastPath(item.Entry) && EntryMatches(gameObject, item.Entry, allowConditionalMatches: true)) { if (item.Destructible.HasHealthOverride) { compiledDestructibleComponentDefinition.HasHealthOverride = true; compiledDestructibleComponentDefinition.Health = item.Destructible.Health; } if (item.Destructible.HasMinToolTierOverride) { compiledDestructibleComponentDefinition.HasMinToolTierOverride = true; compiledDestructibleComponentDefinition.MinToolTier = item.Destructible.MinToolTier; } } } if (!compiledDestructibleComponentDefinition.HasHealthOverride && !compiledDestructibleComponentDefinition.HasMinToolTierOverride) { return false; } resolvedDefinition = compiledDestructibleComponentDefinition; signature = ComputeLazyDestructibleScalarSignature(compiledDestructibleComponentDefinition); return true; } private static bool TryResolveLazyDestructibleType(GameObject gameObject, out DestructibleType resolvedType) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Expected I4, but got Unknown //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) resolvedType = (DestructibleType)1; if (!TryGetConditionalContext(gameObject, out string prefabName, out PrefabSnapshot snapshot, out List _) || snapshot.Destructible == null) { return false; } EnsureRuntimeDropConfigurationState(); List rules; if (!_runtimeDropConfigurationState.PlansByPrefab.TryGetValue(prefabName, out CompiledObjectPrefabPlan value) || (rules = value.Rules) == null || rules.Count == 0) { return false; } bool flag = false; DestructibleType destructibleType = snapshot.Destructible.DestructibleType; foreach (CompiledObjectDropRule item in rules) { CompiledDestructibleComponentDefinition? destructible = item.Destructible; if (destructible != null && destructible.HasDestructibleTypeOverride) { if (!CanUseLazyDestructibleScalarFastPath(item.Entry)) { return false; } flag = true; if (EntryMatches(gameObject, item.Entry, allowConditionalMatches: true)) { destructibleType = item.Destructible.DestructibleType; } } } if (!flag) { return false; } resolvedType = (DestructibleType)(int)destructibleType; return true; } private static CompiledDamageableScalarDefinition? GetDamageableScalarDefinition(CompiledObjectDropRule compiledRule, LiveObjectComponentKind componentKind) { return componentKind switch { LiveObjectComponentKind.MineRock => compiledRule.MineRockScalars, LiveObjectComponentKind.MineRock5 => compiledRule.MineRock5Scalars, LiveObjectComponentKind.TreeBase => compiledRule.TreeBaseScalars, LiveObjectComponentKind.TreeLog => compiledRule.TreeLogScalars, _ => null, }; } private static int ComputeLazyDamageableScalarSignature(CompiledDamageableScalarDefinition scalars) { return (((17 * 31 + (scalars.HasHealthOverride ? 1 : 0)) * 31 + (scalars.HasHealthOverride ? BitConverter.SingleToInt32Bits(scalars.Health) : 0)) * 31 + (scalars.HasMinToolTierOverride ? 1 : 0)) * 31 + (scalars.HasMinToolTierOverride ? scalars.MinToolTier : 0); } private static int ComputeLazyDestructibleScalarSignature(CompiledDestructibleComponentDefinition definition) { return (((17 * 31 + (definition.HasHealthOverride ? 1 : 0)) * 31 + (definition.HasHealthOverride ? BitConverter.SingleToInt32Bits(definition.Health) : 0)) * 31 + (definition.HasMinToolTierOverride ? 1 : 0)) * 31 + (definition.HasMinToolTierOverride ? definition.MinToolTier : 0); } private static void ApplyLazyTreeBaseScalars(TreeBase treeBase, CompiledDamageableScalarDefinition scalars, int signature) { ZNetView component = ((Component)treeBase).GetComponent(); ZDO val = ((component != null) ? component.GetZDO() : null); bool flag = ((val != null) ? val.GetInt(TreeBaseLazyScalarSignatureKey, int.MinValue) : int.MinValue) == signature; bool num = !scalars.HasHealthOverride || Mathf.Approximately(treeBase.m_health, scalars.Health); bool flag2 = !scalars.HasMinToolTierOverride || treeBase.m_minToolTier == scalars.MinToolTier; if (num && flag2 && (flag || (Object)(object)component == (Object)null || val == null || !component.IsOwner())) { return; } if (scalars.HasHealthOverride) { treeBase.m_health = scalars.Health; } if (scalars.HasMinToolTierOverride) { treeBase.m_minToolTier = scalars.MinToolTier; } if (!((Object)(object)component == (Object)null || val == null || !component.IsOwner() || flag)) { if (scalars.HasHealthOverride) { val.Set(ZDOVars.s_health, Mathf.Max(scalars.Health, 0.01f)); } val.Set(TreeBaseLazyScalarSignatureKey, signature, false); } } private static void ApplyLazyTreeLogScalars(TreeLog treeLog, CompiledDamageableScalarDefinition scalars, int signature) { ZNetView component = ((Component)treeLog).GetComponent(); ZDO val = ((component != null) ? component.GetZDO() : null); bool flag = ((val != null) ? val.GetInt(TreeLogLazyScalarSignatureKey, int.MinValue) : int.MinValue) == signature; bool num = !scalars.HasHealthOverride || Mathf.Approximately(treeLog.m_health, scalars.Health); bool flag2 = !scalars.HasMinToolTierOverride || treeLog.m_minToolTier == scalars.MinToolTier; if (num && flag2 && (flag || (Object)(object)component == (Object)null || val == null || !component.IsOwner())) { return; } if (scalars.HasHealthOverride) { treeLog.m_health = scalars.Health; } if (scalars.HasMinToolTierOverride) { treeLog.m_minToolTier = scalars.MinToolTier; } if (!((Object)(object)component == (Object)null || val == null || !component.IsOwner() || flag)) { if (scalars.HasHealthOverride) { val.Set(ZDOVars.s_health, GetScaledMineHealth(Mathf.Max(scalars.Health, 0.01f))); } val.Set(TreeLogLazyScalarSignatureKey, signature, false); } } private static void ApplyLazyMineRockScalars(MineRock mineRock, CompiledDamageableScalarDefinition scalars, int signature) { ZNetView component = ((Component)mineRock).GetComponent(); ZDO val = ((component != null) ? component.GetZDO() : null); bool flag = ((val != null) ? val.GetInt(MineRockLazyScalarSignatureKey, int.MinValue) : int.MinValue) == signature; bool num = !scalars.HasHealthOverride || Mathf.Approximately(mineRock.m_health, scalars.Health); bool flag2 = !scalars.HasMinToolTierOverride || mineRock.m_minToolTier == scalars.MinToolTier; if (num && flag2 && (flag || (Object)(object)component == (Object)null || val == null || !component.IsOwner())) { return; } if (scalars.HasHealthOverride) { mineRock.m_health = scalars.Health; } if (scalars.HasMinToolTierOverride) { mineRock.m_minToolTier = scalars.MinToolTier; } if (!((Object)(object)component == (Object)null || val == null || !component.IsOwner() || flag)) { if (scalars.HasHealthOverride) { SetMineRockAreaHealthAbsolute(mineRock, GetScaledMineHealth(Mathf.Max(scalars.Health, 0.01f))); } val.Set(MineRockLazyScalarSignatureKey, signature, false); } } private static void ApplyLazyMineRock5Scalars(MineRock5 mineRock5, CompiledDamageableScalarDefinition scalars, int signature) { ZNetView component = ((Component)mineRock5).GetComponent(); ZDO val = ((component != null) ? component.GetZDO() : null); bool flag = ((val != null) ? val.GetInt(MineRock5LazyScalarSignatureKey, int.MinValue) : int.MinValue) == signature; bool num = !scalars.HasHealthOverride || Mathf.Approximately(mineRock5.m_health, scalars.Health); bool flag2 = !scalars.HasMinToolTierOverride || mineRock5.m_minToolTier == scalars.MinToolTier; if (num && flag2 && (flag || (Object)(object)component == (Object)null || val == null || !component.IsOwner())) { return; } if (scalars.HasHealthOverride) { mineRock5.m_health = scalars.Health; } if (scalars.HasMinToolTierOverride) { mineRock5.m_minToolTier = scalars.MinToolTier; } if (!((Object)(object)component == (Object)null || val == null || !component.IsOwner() || flag)) { if (scalars.HasHealthOverride) { SetMineRock5AreaHealthAbsolute(mineRock5, GetScaledMineHealth(Mathf.Max(scalars.Health, 0.01f))); } val.Set(MineRock5LazyScalarSignatureKey, signature, false); } } private static void ApplyLazyDestructibleScalars(Destructible destructible, CompiledDestructibleComponentDefinition definition, int signature) { ZNetView component = ((Component)destructible).GetComponent(); ZDO val = ((component != null) ? component.GetZDO() : null); bool flag = ((val != null) ? val.GetInt(DestructibleLazyScalarSignatureKey, int.MinValue) : int.MinValue) == signature; bool num = !definition.HasHealthOverride || Mathf.Approximately(destructible.m_health, definition.Health); bool flag2 = !definition.HasMinToolTierOverride || destructible.m_minToolTier == definition.MinToolTier; if (num && flag2 && (flag || (Object)(object)component == (Object)null || val == null || !component.IsOwner())) { return; } if (definition.HasHealthOverride) { destructible.m_health = definition.Health; } if (definition.HasMinToolTierOverride) { destructible.m_minToolTier = definition.MinToolTier; } if (!((Object)(object)component == (Object)null || val == null || !component.IsOwner() || flag)) { if (definition.HasHealthOverride) { val.Set(ZDOVars.s_health, GetScaledMineHealth(Mathf.Max(definition.Health, 0.01f))); } val.Set(DestructibleLazyScalarSignatureKey, signature, false); } } [IteratorStateMachine(typeof(d__219))] private static IEnumerable EnumerateOverrideConfigurationPaths() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__219(-2); } private static IEnumerable EnumerateSupplementalOverrideConfigurationPaths() { return DomainConfigurationFileSupport.EnumerateSupplementalOverrideConfigurationPaths("object", IsOverrideConfigurationFileName); } private static bool IsOverrideConfigurationFileName(string fileName) { if (string.IsNullOrWhiteSpace(fileName)) { return false; } if (!fileName.Equals(PluginSettingsFacade.GetYamlDomainFilePrefix("object") + ".yml", StringComparison.OrdinalIgnoreCase) && !fileName.Equals(PluginSettingsFacade.GetYamlDomainFilePrefix("object") + ".yaml", StringComparison.OrdinalIgnoreCase)) { if (fileName.StartsWith(PluginSettingsFacade.GetYamlDomainSupplementalPrefix("object"), StringComparison.OrdinalIgnoreCase)) { if (!fileName.EndsWith(".yml", StringComparison.OrdinalIgnoreCase)) { return fileName.EndsWith(".yaml", StringComparison.OrdinalIgnoreCase); } return true; } return false; } return true; } private static void CaptureSnapshotsIfNeeded() { if (Snapshots.Count > 0) { return; } foreach (GameObject item in EnumerateRelevantPrefabs()) { PrefabSnapshot prefabSnapshot = CaptureSnapshot(item); if (prefabSnapshot != null) { Snapshots.Add(prefabSnapshot); if (!SnapshotsByPrefab.ContainsKey(((Object)prefabSnapshot.Prefab).name)) { SnapshotsByPrefab.Add(((Object)prefabSnapshot.Prefab).name, prefabSnapshot); } } } DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)$"Captured {Snapshots.Count} relevant prefab snapshot(s)."); } private static void RefreshSnapshots() { Snapshots.Clear(); SnapshotsByPrefab.Clear(); CaptureSnapshotsIfNeeded(); } [IteratorStateMachine(typeof(d__224))] private static IEnumerable EnumeratePrefabs() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__224(-2); } [IteratorStateMachine(typeof(d__225))] private static IEnumerable EnumerateRelevantPrefabs() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__225(-2); } private static int ComputeGameDataSignature() { int frameCount = Time.frameCount; if (_cachedGameDataSignatureFrame == frameCount) { return _cachedGameDataSignatureValue; } int num = ComputeGameDataSignatureCore(); _cachedGameDataSignatureFrame = frameCount; _cachedGameDataSignatureValue = num; return num; } private static int ComputeGameDataSignatureCore() { if (!IsGameDataReady() || (Object)(object)ZNetScene.instance == (Object)null || (Object)(object)ObjectDB.instance == (Object)null) { return 0; } return HashGameObjectCollection(HashGameObjectCollection((17 * 31 + ((Object)ZNetScene.instance).GetInstanceID()) * 31 + ((Object)ObjectDB.instance).GetInstanceID(), EnumerateRelevantPrefabs()), ObjectDB.instance.m_items); } private static int ComputeSnapshotSignature() { int frameCount = Time.frameCount; if (_cachedSnapshotSignatureFrame == frameCount) { return _cachedSnapshotSignatureValue; } int num = ComputeSnapshotSignatureCore(); _cachedSnapshotSignatureFrame = frameCount; _cachedSnapshotSignatureValue = num; return num; } private static int ComputeSnapshotSignatureCore() { if (!IsGameDataReady() || (Object)(object)ZNetScene.instance == (Object)null || (Object)(object)ObjectDB.instance == (Object)null) { return 0; } return HashNamedGameObjectCollection(HashNamedGameObjectCollection(17, EnumerateRelevantPrefabs()), ObjectDB.instance.m_items); } private static string ComputeReferenceSourceSignature() { return ReferenceRefreshSupport.ComputeStableHashForKeys(from prefab in EnumerateRelevantPrefabs() select ((Object)prefab).name); } private static int HashGameObjectCollection(int hash, IEnumerable prefabs) { foreach (GameObject prefab in prefabs) { hash = hash * 31 + (((Object)(object)prefab != (Object)null) ? ((Object)prefab).GetInstanceID() : 0); } return hash; } private static int HashNamedGameObjectCollection(int hash, IEnumerable prefabs) { List list = (from prefab in prefabs where (Object)(object)prefab != (Object)null select ((Object)prefab).name).OrderBy((string name) => name, StringComparer.Ordinal).ToList(); hash = hash * 31 + list.Count; foreach (string item in list) { hash = hash * 31 + item.GetHashCode(); } return hash; } [IteratorStateMachine(typeof(d__233))] private static IEnumerable BuildSupplementalLocationReferenceEntries(HashSet existingPrefabs) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__233(-2) { <>3__existingPrefabs = existingPrefabs }; } private static Dictionary BuildLocationReferenceBuckets() { Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); foreach (var item2 in EnumerateLocationRootPrefabs()) { string item = item2.LocationPrefab; Transform[] componentsInChildren = item2.RootPrefab.GetComponentsInChildren(true); foreach (Transform val in componentsInChildren) { GameObject val2 = (((Object)(object)val != (Object)null) ? ((Component)val).gameObject : null); if ((Object)(object)val2 == (Object)null) { continue; } PrefabReferenceEntry prefabReferenceEntry = CaptureLocationReferenceEntry(val2); if (prefabReferenceEntry == null) { continue; } if (!dictionary.TryGetValue(prefabReferenceEntry.Prefab, out var value)) { value = new LocationReferenceBucket(); dictionary[prefabReferenceEntry.Prefab] = value; } value.Locations.Add(item); foreach (string locationReferenceComponent in GetLocationReferenceComponents(val2)) { value.Components.Add(locationReferenceComponent); } string key = Serializer.Serialize(prefabReferenceEntry).TrimEnd('\r', '\n'); value.ReferenceEntriesBySignature.TryAdd(key, prefabReferenceEntry); } } return dictionary; } [IteratorStateMachine(typeof(d__235))] private static IEnumerable<(string LocationPrefab, GameObject RootPrefab)> EnumerateLocationRootPrefabs() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__235(-2); } private static PrefabSnapshot? CaptureSnapshot(GameObject prefab) { //IL_0255: Unknown result type (might be due to invalid IL or missing references) DropOnDestroyed component = prefab.GetComponent(); MineRock component2 = prefab.GetComponent(); MineRock5 component3 = prefab.GetComponent(); TreeBase component4 = prefab.GetComponent(); TreeLog component5 = prefab.GetComponent(); Container component6 = prefab.GetComponent(); Pickable component7 = prefab.GetComponent(); PickableItem component8 = prefab.GetComponent(); Fish component9 = prefab.GetComponent(); Destructible component10 = prefab.GetComponent(); if ((Object)(object)component == (Object)null && (Object)(object)component2 == (Object)null && (Object)(object)component3 == (Object)null && (Object)(object)component4 == (Object)null && (Object)(object)component5 == (Object)null && (Object)(object)component6 == (Object)null && (Object)(object)component7 == (Object)null && (Object)(object)component8 == (Object)null && (Object)(object)component9 == (Object)null && (Object)(object)component10 == (Object)null) { return null; } return new PrefabSnapshot { Prefab = prefab, Health = CreateHealthSnapshot(component10, component2, component3, component4, component5), MinToolTier = CreateMinToolTierSnapshot(component10, component2, component3, component4, component5), DropOnDestroyed = (((Object)(object)component != (Object)null) ? CloneDropTable(component.m_dropWhenDestroyed) : null), MineRock = (((Object)(object)component2 != (Object)null) ? CloneDropTable(component2.m_dropItems) : null), MineRock5 = (((Object)(object)component3 != (Object)null) ? CloneDropTable(component3.m_dropItems) : null), TreeBase = (((Object)(object)component4 != (Object)null) ? CloneDropTable(component4.m_dropWhenDestroyed) : null), TreeLog = (((Object)(object)component5 != (Object)null) ? CloneDropTable(component5.m_dropWhenDestroyed) : null), Container = (((Object)(object)component6 != (Object)null) ? CloneDropTable(component6.m_defaultItems) : null), Pickable = (((Object)(object)component7 != (Object)null) ? new PickableSnapshot { ItemPrefab = component7.m_itemPrefab, Amount = component7.m_amount, MinAmountScaled = component7.m_minAmountScaled, DontScale = component7.m_dontScale, OverrideName = component7.m_overrideName, ExtraDrops = CloneDropTable(component7.m_extraDrops) } : null), PickableItem = (((Object)(object)component8 != (Object)null) ? CapturePickableItemSnapshot(component8) : null), Fish = (((Object)(object)component9 != (Object)null) ? new FishSnapshot { ExtraDrops = CloneDropTable(component9.m_extraDrops) } : null), Destructible = (((Object)(object)component10 != (Object)null) ? new DestructibleSnapshot { DestructibleType = component10.m_destructibleType, SpawnWhenDestroyed = component10.m_spawnWhenDestroyed } : null) }; } private static PrefabReferenceEntry? CaptureLocationReferenceEntry(GameObject gameObject) { if ((Object)(object)gameObject == (Object)null) { return null; } PrefabSnapshot prefabSnapshot = CaptureSnapshot(gameObject); if (prefabSnapshot == null) { return null; } string prefabName = GetPrefabName(gameObject); if (string.IsNullOrWhiteSpace(prefabName)) { return null; } prefabSnapshot.Prefab = gameObject; PrefabConfigurationEntry prefabConfigurationEntry = BuildConfigurationEntry(prefabSnapshot); prefabConfigurationEntry.Prefab = prefabName; return new PrefabReferenceEntry { Prefab = prefabConfigurationEntry.Prefab, DropOnDestroyed = prefabConfigurationEntry.DropOnDestroyed, MineRock = prefabConfigurationEntry.MineRock, MineRock5 = prefabConfigurationEntry.MineRock5, TreeBase = prefabConfigurationEntry.TreeBase, TreeLog = prefabConfigurationEntry.TreeLog, Container = prefabConfigurationEntry.Container, Destructible = prefabConfigurationEntry.Destructible, Pickable = prefabConfigurationEntry.Pickable, PickableItem = prefabConfigurationEntry.PickableItem, Fish = prefabConfigurationEntry.Fish }; } [IteratorStateMachine(typeof(d__238))] private static IEnumerable GetLocationReferenceComponents(GameObject gameObject) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__238(-2) { <>3__gameObject = gameObject }; } private static bool HasReferenceRelevantComponents(GameObject prefab) { return HasRelevantLiveObjectComponents(prefab); } private static HealthSnapshot? CreateHealthSnapshot(Destructible? destructible, MineRock? mineRock, MineRock5? mineRock5, TreeBase? treeBase, TreeLog? treeLog) { if ((Object)(object)destructible == (Object)null && (Object)(object)mineRock == (Object)null && (Object)(object)mineRock5 == (Object)null && (Object)(object)treeBase == (Object)null && (Object)(object)treeLog == (Object)null) { return null; } return new HealthSnapshot { Destructible = destructible?.m_health, MineRock = mineRock?.m_health, MineRock5 = mineRock5?.m_health, TreeBase = treeBase?.m_health, TreeLog = treeLog?.m_health }; } private static MinToolTierSnapshot? CreateMinToolTierSnapshot(Destructible? destructible, MineRock? mineRock, MineRock5? mineRock5, TreeBase? treeBase, TreeLog? treeLog) { if ((Object)(object)destructible == (Object)null && (Object)(object)mineRock == (Object)null && (Object)(object)mineRock5 == (Object)null && (Object)(object)treeBase == (Object)null && (Object)(object)treeLog == (Object)null) { return null; } return new MinToolTierSnapshot { Destructible = destructible?.m_minToolTier, MineRock = mineRock?.m_minToolTier, MineRock5 = mineRock5?.m_minToolTier, TreeBase = treeBase?.m_minToolTier, TreeLog = treeLog?.m_minToolTier }; } private static PickableItemSnapshot CapturePickableItemSnapshot(PickableItem pickableItem) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) PickableItemSnapshot pickableItemSnapshot = new PickableItemSnapshot { ItemPrefab = (Object.op_Implicit((Object)(object)pickableItem.m_itemPrefab) ? ((Component)pickableItem.m_itemPrefab).gameObject : null), Stack = pickableItem.m_stack }; RandomItem[] randomItemPrefabs = pickableItem.m_randomItemPrefabs; foreach (RandomItem val in randomItemPrefabs) { pickableItemSnapshot.RandomItems.Add(new PickableItemRandomSnapshot { ItemPrefab = (Object.op_Implicit((Object)(object)val.m_itemPrefab) ? ((Component)val.m_itemPrefab).gameObject : null), StackMin = val.m_stackMin, StackMax = val.m_stackMax }); } return pickableItemSnapshot; } private static void ApplyIfReady(bool queueLiveReconcile = false) { if (IsGameDataReady() && Snapshots.Count != 0 && (DropNSpawnPlugin.IsSourceOfTruth || Volatile.Read(ref _synchronizedPayloadReady))) { int num = ComputeGameDataSignature(); bool flag = PluginSettingsFacade.IsObjectDomainEnabled(); Dictionary currentEntrySignatures = BuildActiveEntrySignaturesByPrefab(); if (!StandardDomainApplySupport.IsAlreadyApplied(_lastAppliedGameDataSignature, num, _lastAppliedDomainEnabled, flag, _lastAppliedConfigurationSignature, _configurationSignature) || _lastAppliedSynchronizedPayloadReady != Volatile.Read(ref _synchronizedPayloadReady)) { RunApplyCoordinator(num, flag, currentEntrySignatures, queueLiveReconcile); } } } private static void EnsureRuntimeDropConfigurationState() { if (IsGameDataReady()) { int num = ComputeGameDataSignature(); if (_runtimeDropConfigurationGameDataSignature != num || !string.Equals(_runtimeDropConfigurationSignature, _configurationSignature, StringComparison.Ordinal)) { _runtimeDropConfigurationState = BuildRuntimeDropConfigurationState(); _runtimeDropConfigurationGameDataSignature = num; _runtimeDropConfigurationSignature = _configurationSignature; } } } private static ObjectRuntimeDropConfigurationState BuildRuntimeDropConfigurationState() { ObjectRuntimeDropConfigurationState objectRuntimeDropConfigurationState = new ObjectRuntimeDropConfigurationState(); foreach (KeyValuePair> item in ActiveEntriesByPrefab) { item.Deconstruct(out var key, out var value); string text = key; List list = value; CompiledObjectPrefabPlan compiledObjectPrefabPlan = new CompiledObjectPrefabPlan(); compiledObjectPrefabPlan.ActiveEntries.AddRange(list); foreach (PrefabConfigurationEntry item2 in list) { CompiledObjectDropRule compiledObjectDropRule = CompileObjectDropRule(item2); if (compiledObjectDropRule != null) { compiledObjectPrefabPlan.Rules.Add(compiledObjectDropRule); objectRuntimeDropConfigurationState.RulesByEntry[item2] = compiledObjectDropRule; } } if (compiledObjectPrefabPlan.ActiveEntries.Count > 0) { BuildStaticDropTableTemplatesForPrefab(text, compiledObjectPrefabPlan); objectRuntimeDropConfigurationState.PlansByPrefab[text] = compiledObjectPrefabPlan; } } return objectRuntimeDropConfigurationState; } private static void BuildStaticDropTableTemplatesForPrefab(string prefabName, CompiledObjectPrefabPlan plan) { if (!SnapshotsByPrefab.TryGetValue(prefabName, out PrefabSnapshot value)) { return; } Dictionary dictionary = new Dictionary(); TryAddStaticDropTableTemplate(dictionary, plan.Rules, value.DropOnDestroyed, LiveObjectComponentKind.DropOnDestroyed, (CompiledObjectDropRule rule) => rule.DropOnDestroyed); TryAddStaticDropTableTemplate(dictionary, plan.Rules, value.MineRock, LiveObjectComponentKind.MineRock, (CompiledObjectDropRule rule) => rule.MineRock); TryAddStaticDropTableTemplate(dictionary, plan.Rules, value.MineRock5, LiveObjectComponentKind.MineRock5, (CompiledObjectDropRule rule) => rule.MineRock5); TryAddStaticDropTableTemplate(dictionary, plan.Rules, value.TreeBase, LiveObjectComponentKind.TreeBase, (CompiledObjectDropRule rule) => rule.TreeBase); TryAddStaticDropTableTemplate(dictionary, plan.Rules, value.TreeLog, LiveObjectComponentKind.TreeLog, (CompiledObjectDropRule rule) => rule.TreeLog); TryAddStaticDropTableTemplate(dictionary, plan.Rules, value.Container, LiveObjectComponentKind.Container, (CompiledObjectDropRule rule) => rule.Container); TryAddStaticDropTableTemplate(dictionary, plan.Rules, value.Pickable?.ExtraDrops, LiveObjectComponentKind.Pickable, (CompiledObjectDropRule rule) => rule.PickableExtraDrops); TryAddStaticDropTableTemplate(dictionary, plan.Rules, value.Fish?.ExtraDrops, LiveObjectComponentKind.Fish, (CompiledObjectDropRule rule) => rule.FishExtraDrops); if (dictionary.Count <= 0) { return; } foreach (var (key, value2) in dictionary) { plan.StaticDropTableTemplates[key] = value2; } } private static void TryAddStaticDropTableTemplate(Dictionary templates, IEnumerable compiledRules, DropTable? snapshotTable, LiveObjectComponentKind componentKind, Func payloadSelector) { List list = new List(); foreach (CompiledObjectDropRule item in compiledRules ?? Enumerable.Empty()) { CompiledDropTablePayload compiledDropTablePayload = payloadSelector(item); if (compiledDropTablePayload != null && !item.HasConditions) { list.Add(compiledDropTablePayload); } } if (list.Count != 0) { templates[componentKind] = BuildStaticDropTableTemplate(snapshotTable, list); } } private static StaticCompiledDropTableTemplate BuildStaticDropTableTemplate(DropTable? snapshotTable, IEnumerable payloads) { StaticCompiledDropTableTemplate staticCompiledDropTableTemplate = new StaticCompiledDropTableTemplate { Template = ((snapshotTable != null) ? CloneDropTable(snapshotTable) : CreateDefaultDropTable()) }; staticCompiledDropTableTemplate.Template.m_drops = new List(); foreach (CompiledDropTablePayload item in payloads ?? Enumerable.Empty()) { ApplyDropTableScalarOverrides(staticCompiledDropTableTemplate.Template, item); AppendDropTableRows(staticCompiledDropTableTemplate.Template.m_drops, item.Drops, staticCompiledDropTableTemplate.Fingerprints); } return staticCompiledDropTableTemplate; } private static CompiledObjectDropRule? CompileObjectDropRule(PrefabConfigurationEntry entry) { CompiledObjectDropRule compiledObjectDropRule = new CompiledObjectDropRule { Entry = entry, HasConditions = DropConditionEvaluator.HasConditions(entry.Conditions), DropOnDestroyed = CompileDropTablePayload(entry, entry.DropOnDestroyed, "DropOnDestroyed"), MineRock = CompileDropTablePayload(entry, entry.MineRock, "MineRock"), MineRock5 = CompileDropTablePayload(entry, entry.MineRock5, "MineRock5"), TreeBase = CompileDropTablePayload(entry, entry.TreeBase, "TreeBase"), TreeLog = CompileDropTablePayload(entry, entry.TreeLog, "TreeLog"), Container = CompileDropTablePayload(entry, entry.Container, "Container"), PickableExtraDrops = CompileDropTablePayload(entry, entry.Pickable?.ExtraDrops, "Pickable/ExtraDrops"), FishExtraDrops = CompileDropTablePayload(entry, entry.Fish?.ExtraDrops, "Fish/ExtraDrops"), Pickable = CompilePickableDefinition(entry), PickableItem = CompilePickableItemDefinition(entry), Destructible = CompileDestructibleComponentDefinition(entry), MineRockScalars = CompileDamageableScalarDefinition(entry, entry.MineRock, "MineRock"), MineRock5Scalars = CompileDamageableScalarDefinition(entry, entry.MineRock5, "MineRock5"), TreeBaseScalars = CompileDamageableScalarDefinition(entry, entry.TreeBase, "TreeBase"), TreeLogScalars = CompileDamageableScalarDefinition(entry, entry.TreeLog, "TreeLog") }; if (compiledObjectDropRule.DropOnDestroyed == null && compiledObjectDropRule.MineRock == null && compiledObjectDropRule.MineRock5 == null && compiledObjectDropRule.TreeBase == null && compiledObjectDropRule.TreeLog == null && compiledObjectDropRule.Container == null && compiledObjectDropRule.PickableExtraDrops == null && compiledObjectDropRule.FishExtraDrops == null && compiledObjectDropRule.Pickable == null && compiledObjectDropRule.PickableItem == null && compiledObjectDropRule.Destructible == null) { return null; } return compiledObjectDropRule; } private static CompiledDamageableScalarDefinition? CompileDamageableScalarDefinition(PrefabConfigurationEntry entry, DamageableDropTableDefinition? definition, string componentName) { if (!HasDamageableOverride(definition)) { return null; } string text = BuildCompiledObjectDropContext(entry, componentName); CompiledDamageableScalarDefinition compiledDamageableScalarDefinition = new CompiledDamageableScalarDefinition(); if (HasDamageableHealthOverride(definition) && TryGetConfiguredHealth(definition.Health.Value, text + "/Health", out var normalizedHealth)) { compiledDamageableScalarDefinition.HasHealthOverride = true; compiledDamageableScalarDefinition.Health = normalizedHealth; } if (HasDamageableMinToolTierOverride(definition) && TryGetConfiguredMinToolTier(definition.MinToolTier.Value, text + "/minToolTier", out var normalizedMinToolTier)) { compiledDamageableScalarDefinition.HasMinToolTierOverride = true; compiledDamageableScalarDefinition.MinToolTier = normalizedMinToolTier; } if (!compiledDamageableScalarDefinition.HasHealthOverride && !compiledDamageableScalarDefinition.HasMinToolTierOverride) { return null; } return compiledDamageableScalarDefinition; } private static CompiledDestructibleComponentDefinition? CompileDestructibleComponentDefinition(PrefabConfigurationEntry entry) { //IL_00c0: Unknown result type (might be due to invalid IL or missing references) if (!HasDestructibleOverride(entry.Destructible)) { return null; } DestructibleDefinition destructible = entry.Destructible; string text = BuildCompiledObjectDropContext(entry, "Destructible"); CompiledDestructibleComponentDefinition compiledDestructibleComponentDefinition = new CompiledDestructibleComponentDefinition(); if (HasDestructibleHealthOverride(destructible) && TryGetConfiguredHealth(destructible.Health.Value, text + "/Health", out var normalizedHealth)) { compiledDestructibleComponentDefinition.HasHealthOverride = true; compiledDestructibleComponentDefinition.Health = normalizedHealth; } if (HasDestructibleMinToolTierOverride(destructible) && TryGetConfiguredMinToolTier(destructible.MinToolTier.Value, text + "/minToolTier", out var normalizedMinToolTier)) { compiledDestructibleComponentDefinition.HasMinToolTierOverride = true; compiledDestructibleComponentDefinition.MinToolTier = normalizedMinToolTier; } if (!string.IsNullOrWhiteSpace(destructible.DestructibleType)) { if (Enum.TryParse(destructible.DestructibleType, ignoreCase: true, out DestructibleType result)) { compiledDestructibleComponentDefinition.HasDestructibleTypeOverride = true; compiledDestructibleComponentDefinition.DestructibleType = result; } else { WarnInvalidEntry("Entry '" + text + "' has invalid destructibleType '" + destructible.DestructibleType + "'."); } } if (!string.IsNullOrWhiteSpace(destructible.SpawnWhenDestroyed)) { GameObject val = ResolveSpawnPrefab(destructible.SpawnWhenDestroyed, text); if ((Object)(object)val != (Object)null) { compiledDestructibleComponentDefinition.HasSpawnWhenDestroyedOverride = true; compiledDestructibleComponentDefinition.SpawnWhenDestroyed = val; } } if (!compiledDestructibleComponentDefinition.HasHealthOverride && !compiledDestructibleComponentDefinition.HasMinToolTierOverride && !compiledDestructibleComponentDefinition.HasDestructibleTypeOverride && !compiledDestructibleComponentDefinition.HasSpawnWhenDestroyedOverride) { return null; } return compiledDestructibleComponentDefinition; } private static CompiledPickableDefinition? CompilePickableDefinition(PrefabConfigurationEntry entry) { if (!HasPickableOverride(entry.Pickable)) { return null; } PickableDefinition pickable = entry.Pickable; CompiledPickableDefinition compiledPickableDefinition = new CompiledPickableDefinition(); if (HasPickableDropOverride(pickable.Drop)) { if (!string.IsNullOrWhiteSpace(pickable.Drop.Item)) { GameObject val = ResolveItemPrefab(pickable.Drop.Item, BuildCompiledObjectDropContext(entry, "Pickable")); if ((Object)(object)val != (Object)null) { compiledPickableDefinition.HasItemPrefabOverride = true; compiledPickableDefinition.ItemPrefab = val; } } if (pickable.Drop.Amount.HasValue) { compiledPickableDefinition.HasAmountOverride = true; compiledPickableDefinition.Amount = Math.Max(1, pickable.Drop.Amount.Value); } if (pickable.Drop.MinAmountScaled.HasValue) { compiledPickableDefinition.HasMinAmountScaledOverride = true; compiledPickableDefinition.MinAmountScaled = Math.Max(1, pickable.Drop.MinAmountScaled.Value); } if (pickable.Drop.DontScale.HasValue) { compiledPickableDefinition.HasDontScaleOverride = true; compiledPickableDefinition.DontScale = pickable.Drop.DontScale.Value; } } if (pickable.OverrideName != null) { compiledPickableDefinition.HasOverrideNameOverride = true; compiledPickableDefinition.OverrideName = pickable.OverrideName; } return compiledPickableDefinition; } private static CompiledPickableItemDefinition? CompilePickableItemDefinition(PrefabConfigurationEntry entry) { if (!HasPickableItemOverride(entry.PickableItem)) { return null; } PickableItemDefinition pickableItem = entry.PickableItem; CompiledPickableItemDefinition compiledPickableItemDefinition = new CompiledPickableItemDefinition(); bool hasRandomOverride = pickableItem.RandomDrops != null; List list = pickableItem.RandomDrops ?? new List(); bool num = list.Count > 0; bool flag = HasPickableItemDropOverride(pickableItem.Drop); string text = BuildCompiledObjectDropContext(entry, "PickableItem"); if (num && flag) { WarnInvalidEntry("Entry '" + text + "' defines both drop and randomDrops. randomDrops take precedence."); } compiledPickableItemDefinition.HasRandomOverride = hasRandomOverride; if (num) { BuiltRandomPickableItems builtRandomPickableItems = BuildRandomItems(list, text); compiledPickableItemDefinition.RandomItems = builtRandomPickableItems.Items; compiledPickableItemDefinition.RandomWeights = builtRandomPickableItems.Weights; } compiledPickableItemDefinition.HasFixedDrop = flag; if (flag) { if (!string.IsNullOrWhiteSpace(pickableItem.Drop?.Item)) { GameObject val = ResolveItemPrefab(pickableItem.Drop.Item, text); if ((Object)(object)val != (Object)null) { compiledPickableItemDefinition.HasFixedItemOverride = true; compiledPickableItemDefinition.FixedItemPrefab = val.GetComponent(); } } PickableItemDropDefinition? drop = pickableItem.Drop; if (drop != null && drop.Stack.HasValue) { compiledPickableItemDefinition.HasFixedStackOverride = true; compiledPickableItemDefinition.FixedStack = Math.Max(1, pickableItem.Drop.Stack.Value); } } return compiledPickableItemDefinition; } private static CompiledDropTablePayload? CompileDropTablePayload(PrefabConfigurationEntry entry, DropTablePayloadDefinition? definition, string componentName) { if (!HasDropTableOverride(definition)) { return null; } CompiledDropTablePayload compiledDropTablePayload = new CompiledDropTablePayload(); if (definition.DropMin.HasValue || definition.DropMax.HasValue) { compiledDropTablePayload.HasDropRangeOverride = true; compiledDropTablePayload.DropMin = Math.Max(0, definition.DropMin.GetValueOrDefault(1)); compiledDropTablePayload.DropMax = Math.Max(compiledDropTablePayload.DropMin, definition.DropMax ?? definition.DropMin.GetValueOrDefault(1)); } if (definition.DropChance.HasValue) { compiledDropTablePayload.HasDropChanceOverride = true; compiledDropTablePayload.DropChance = Mathf.Clamp01(definition.DropChance.Value); } if (definition.OneOfEach.HasValue) { compiledDropTablePayload.HasOneOfEachOverride = true; compiledDropTablePayload.OneOfEach = definition.OneOfEach.Value; } string context = BuildCompiledObjectDropContext(entry, componentName); IEnumerable drops = definition.Drops; foreach (DropEntryDefinition item in drops ?? Enumerable.Empty()) { if (TryCompileDropTableRow(item, context, out CompiledDropTableRow compiledRow)) { compiledDropTablePayload.Drops.Add(compiledRow); } } return compiledDropTablePayload; } private static bool TryCompileDropTableRow(DropEntryDefinition drop, string context, out CompiledDropTableRow compiledRow) { compiledRow = null; string text = (drop.Item ?? "").Trim(); if (text.Length == 0) { WarnInvalidEntry("Entry '" + context + "' contains a drop without an item name."); return false; } GameObject val = ResolveItemPrefab(text, context); if ((Object)(object)val == (Object)null) { return false; } compiledRow = new CompiledDropTableRow { Fingerprint = BuildDropRowFingerprint(drop), ItemPrefab = val, StackMin = Math.Max(1, drop.StackMin.GetValueOrDefault(1)), StackMax = Math.Max(Math.Max(1, drop.StackMin.GetValueOrDefault(1)), drop.StackMax ?? drop.StackMin.GetValueOrDefault(1)), Weight = Mathf.Max(0f, drop.Weight.GetValueOrDefault(1f)), DontScale = drop.DontScale.GetValueOrDefault() }; return true; } private static void ValidateConfiguredPrefabs() { foreach (var (text2, list2) in ActiveEntriesByPrefab) { if (SnapshotsByPrefab.ContainsKey(text2)) { continue; } foreach (PrefabConfigurationEntry item in list2) { WarnInvalidEntry("Object prefab '" + text2 + "' from " + DescribeEntrySource(item) + " was not found in ZNetScene."); } } } private static void RecordAppliedState(int gameDataSignature, bool domainEnabled, Dictionary currentEntrySignatures) { _lastAppliedGameDataSignature = gameDataSignature; _lastAppliedDomainEnabled = domainEnabled; _lastAppliedConfigurationSignature = _configurationSignature; _lastAppliedSynchronizedPayloadReady = Volatile.Read(ref _synchronizedPayloadReady); ReplaceEntrySignatures(_lastAppliedEntrySignaturesByPrefab, currentEntrySignatures); if (domainEnabled) { PrefabProfileCatalogState.RecordCurrentConfiguredKindsAsLastApplied(); PrefabProfileCatalogState.RecordCurrentReconcileKindsAsLastApplied(); } else { PrefabProfileCatalogState.ClearLastAppliedConfiguredKinds(); PrefabProfileCatalogState.ClearLastAppliedReconcileKinds(); } } private static void RestoreSnapshots(HashSet? targetPrefabs = null) { if (targetPrefabs == null) { foreach (PrefabSnapshot snapshot in Snapshots) { RestoreConfiguredComponents(snapshot.Prefab, snapshot, CreateRestoreMask(snapshot), updateRuntimeState: false); } return; } foreach (string targetPrefab in targetPrefabs) { if (SnapshotsByPrefab.TryGetValue(targetPrefab, out PrefabSnapshot value)) { RestoreConfiguredComponents(value.Prefab, value, CreateRestoreMask(value), updateRuntimeState: false); } } } private static void RestoreTrackedLiveObjects(HashSet prefabs) { if (prefabs.Count == 0 || !IsGameDataReady()) { return; } foreach (GameObject registeredLiveObject in GetRegisteredLiveObjects(prefabs)) { if (!((Object)(object)registeredLiveObject == (Object)null)) { string prefabName = GetPrefabName(registeredLiveObject); if (SnapshotsByPrefab.TryGetValue(prefabName, out PrefabSnapshot value)) { RestoreConfiguredComponents(registeredLiveObject, value, CreateRestoreMask(value), updateRuntimeState: true); } } } } private static PrefabConfigurationEntry CreateRestoreMask(PrefabSnapshot snapshot) { return new PrefabConfigurationEntry { Prefab = ((Object)snapshot.Prefab).name, Destructible = CreateRestoreDestructibleMask(snapshot), DropOnDestroyed = ((snapshot.DropOnDestroyed != null) ? CreateRestoreDropTableMask() : null), MineRock = CreateRestoreDamageableDropTableMask(snapshot.MineRock, snapshot.Health?.MineRock, snapshot.MinToolTier?.MineRock), MineRock5 = CreateRestoreDamageableDropTableMask(snapshot.MineRock5, snapshot.Health?.MineRock5, snapshot.MinToolTier?.MineRock5), TreeBase = CreateRestoreDamageableDropTableMask(snapshot.TreeBase, snapshot.Health?.TreeBase, snapshot.MinToolTier?.TreeBase), TreeLog = CreateRestoreDamageableDropTableMask(snapshot.TreeLog, snapshot.Health?.TreeLog, snapshot.MinToolTier?.TreeLog), Container = ((snapshot.Container != null) ? CreateRestoreDropTableMask() : null), Pickable = ((snapshot.Pickable != null) ? new PickableDefinition { OverrideName = "" } : null), PickableItem = ((snapshot.PickableItem != null) ? new PickableItemDefinition { RandomDrops = new List() } : null), Fish = ((snapshot.Fish != null) ? new FishDefinition { ExtraDrops = CreateRestoreDropTableMask() } : null) }; } private static DropTableDefinition CreateRestoreDropTableMask() { return new DropTableDefinition { Drops = new List() }; } private static DamageableDropTableDefinition? CreateRestoreDamageableDropTableMask(DropTable? dropTable, float? health, int? minToolTier) { if (dropTable == null && !health.HasValue && !minToolTier.HasValue) { return null; } return new DamageableDropTableDefinition { Drops = ((dropTable != null) ? new List() : null), Health = (health.HasValue ? new float?(0f) : null), MinToolTier = (minToolTier.HasValue ? new int?(0) : null) }; } private static DestructibleDefinition? CreateRestoreDestructibleMask(PrefabSnapshot snapshot) { //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) bool flag = snapshot.Health?.Destructible.HasValue ?? false; bool flag2 = snapshot.MinToolTier?.Destructible.HasValue ?? false; bool flag3 = snapshot.Destructible != null; if (!flag && !flag2 && !flag3) { return null; } DestructibleDefinition obj = new DestructibleDefinition { Health = (flag ? new float?(0f) : null), MinToolTier = (flag2 ? new int?(0) : null) }; object destructibleType; if (!flag3) { destructibleType = null; } else { DestructibleType destructibleType2 = snapshot.Destructible.DestructibleType; destructibleType = ((object)(DestructibleType)(ref destructibleType2)).ToString(); } obj.DestructibleType = (string?)destructibleType; obj.SpawnWhenDestroyed = (flag3 ? "restore" : null); return obj; } private static Dictionary BuildActiveEntrySignaturesByPrefab() { return DomainEntrySignatureSupport.BuildSignaturesByKey(ActiveEntriesByPrefab, NetworkPayloadSyncSupport.ComputeObjectConfigurationSignature); } private static HashSet BuildDirtyPrefabs(Dictionary previous, Dictionary current) { return DomainDictionaryDiffSupport.BuildDirtyKeys(previous, current); } private static void ReplaceEntrySignatures(Dictionary target, Dictionary source) { DomainDictionaryDiffSupport.ReplaceEntries(target, source); } private static void ApplyEffectiveDropTableOverrides(GameObject gameObject, PrefabSnapshot snapshot, IEnumerable entries, bool allowConditionalMatches, GroupConditionalApplyPlan? groupPlan = null, bool includeEventOnlyKinds = true) { EnsureRuntimeDropConfigurationState(); List rules; if (_runtimeDropConfigurationState.PlansByPrefab.TryGetValue(((Object)snapshot.Prefab).name, out CompiledObjectPrefabPlan value) && (rules = value.Rules) != null && rules.Count != 0) { DropOnDestroyed val = default(DropOnDestroyed); if ((includeEventOnlyKinds || (UsesLiveDropTableReconcile(LiveObjectComponentKind.DropOnDestroyed) && RequiresLiveReconcileForPrefab(((Object)snapshot.Prefab).name, LiveObjectComponentKind.DropOnDestroyed))) && gameObject.TryGetComponent(ref val) && TryBuildEffectiveDropTable(gameObject, ((Object)snapshot.Prefab).name, rules, (CompiledObjectDropRule rule) => rule.DropOnDestroyed, snapshot.DropOnDestroyed, LiveObjectComponentKind.DropOnDestroyed, allowConditionalMatches, groupPlan, out DropTable effectiveTable)) { val.m_dropWhenDestroyed = effectiveTable; } MineRock val2 = default(MineRock); if ((includeEventOnlyKinds || (UsesLiveDropTableReconcile(LiveObjectComponentKind.MineRock) && RequiresLiveReconcileForPrefab(((Object)snapshot.Prefab).name, LiveObjectComponentKind.MineRock))) && gameObject.TryGetComponent(ref val2) && TryBuildEffectiveDropTable(gameObject, ((Object)snapshot.Prefab).name, rules, (CompiledObjectDropRule rule) => rule.MineRock, snapshot.MineRock, LiveObjectComponentKind.MineRock, allowConditionalMatches, groupPlan, out DropTable effectiveTable2)) { val2.m_dropItems = effectiveTable2; } MineRock5 val3 = default(MineRock5); if ((includeEventOnlyKinds || (UsesLiveDropTableReconcile(LiveObjectComponentKind.MineRock5) && RequiresLiveReconcileForPrefab(((Object)snapshot.Prefab).name, LiveObjectComponentKind.MineRock5))) && gameObject.TryGetComponent(ref val3) && TryBuildEffectiveDropTable(gameObject, ((Object)snapshot.Prefab).name, rules, (CompiledObjectDropRule rule) => rule.MineRock5, snapshot.MineRock5, LiveObjectComponentKind.MineRock5, allowConditionalMatches, groupPlan, out DropTable effectiveTable3)) { val3.m_dropItems = effectiveTable3; } Container val4 = default(Container); if ((includeEventOnlyKinds || (UsesLiveDropTableReconcile(LiveObjectComponentKind.Container) && RequiresLiveReconcileForPrefab(((Object)snapshot.Prefab).name, LiveObjectComponentKind.Container))) && gameObject.TryGetComponent(ref val4) && TryBuildEffectiveDropTable(gameObject, ((Object)snapshot.Prefab).name, rules, (CompiledObjectDropRule rule) => rule.Container, snapshot.Container, LiveObjectComponentKind.Container, allowConditionalMatches, groupPlan, out DropTable effectiveTable4)) { val4.m_defaultItems = effectiveTable4; } TreeBase val5 = default(TreeBase); if ((includeEventOnlyKinds || (UsesLiveDropTableReconcile(LiveObjectComponentKind.TreeBase) && RequiresLiveReconcileForPrefab(((Object)snapshot.Prefab).name, LiveObjectComponentKind.TreeBase))) && gameObject.TryGetComponent(ref val5) && TryBuildEffectiveDropTable(gameObject, ((Object)snapshot.Prefab).name, rules, (CompiledObjectDropRule rule) => rule.TreeBase, snapshot.TreeBase, LiveObjectComponentKind.TreeBase, allowConditionalMatches, groupPlan, out DropTable effectiveTable5)) { val5.m_dropWhenDestroyed = effectiveTable5; } TreeLog val6 = default(TreeLog); if ((includeEventOnlyKinds || (UsesLiveDropTableReconcile(LiveObjectComponentKind.TreeLog) && RequiresLiveReconcileForPrefab(((Object)snapshot.Prefab).name, LiveObjectComponentKind.TreeLog))) && gameObject.TryGetComponent(ref val6) && TryBuildEffectiveDropTable(gameObject, ((Object)snapshot.Prefab).name, rules, (CompiledObjectDropRule rule) => rule.TreeLog, snapshot.TreeLog, LiveObjectComponentKind.TreeLog, allowConditionalMatches, groupPlan, out DropTable effectiveTable6)) { val6.m_dropWhenDestroyed = effectiveTable6; } Pickable val7 = default(Pickable); if ((includeEventOnlyKinds || RequiresLiveReconcileForPrefab(((Object)snapshot.Prefab).name, LiveObjectComponentKind.Pickable)) && gameObject.TryGetComponent(ref val7) && TryBuildEffectiveDropTable(gameObject, ((Object)snapshot.Prefab).name, rules, (CompiledObjectDropRule rule) => rule.PickableExtraDrops, snapshot.Pickable?.ExtraDrops, LiveObjectComponentKind.Pickable, allowConditionalMatches, groupPlan, out DropTable effectiveTable7)) { val7.m_extraDrops = effectiveTable7; } Fish val8 = default(Fish); if ((includeEventOnlyKinds || RequiresLiveReconcileForPrefab(((Object)snapshot.Prefab).name, LiveObjectComponentKind.Fish)) && gameObject.TryGetComponent(ref val8) && TryBuildEffectiveDropTable(gameObject, ((Object)snapshot.Prefab).name, rules, (CompiledObjectDropRule rule) => rule.FishExtraDrops, snapshot.Fish?.ExtraDrops, LiveObjectComponentKind.Fish, allowConditionalMatches, groupPlan, out DropTable effectiveTable8)) { val8.m_extraDrops = effectiveTable8; } } } private static bool TryBuildEffectiveDropTable(GameObject gameObject, string prefabName, IEnumerable rules, Func payloadSelector, DropTable? snapshotTable, LiveObjectComponentKind componentKind, bool allowConditionalMatches, GroupConditionalApplyPlan? groupPlan, out DropTable? effectiveTable) { effectiveTable = null; StaticCompiledDropTableTemplate template = null; if (prefabName.Length > 0) { TryGetStaticDropTableTemplate(prefabName, componentKind, out template); } List list = new List(); bool flag = false; if (groupPlan != null) { foreach (CompiledObjectDropRule matchingCompiledRule in groupPlan.MatchingCompiledRules) { CompiledDropTablePayload compiledDropTablePayload = payloadSelector(matchingCompiledRule); if (compiledDropTablePayload != null) { flag = true; if (template == null || matchingCompiledRule.HasConditions) { list.Add(compiledDropTablePayload); } } } } foreach (CompiledObjectDropRule item in rules ?? Enumerable.Empty()) { CompiledDropTablePayload compiledDropTablePayload2 = payloadSelector(item); if (compiledDropTablePayload2 != null) { flag = true; if ((groupPlan == null || !groupPlan.EligibleCompiledRules.Contains(item)) && (template == null || item.HasConditions) && EntryMatches(gameObject, item.Entry, allowConditionalMatches)) { list.Add(compiledDropTablePayload2); } } } if (!flag) { return false; } if (template != null) { effectiveTable = BuildEffectiveDropTable(template, list); return true; } effectiveTable = BuildEffectiveDropTable(snapshotTable, list); return true; } private static bool EntryMatches(GameObject gameObject, PrefabConfigurationEntry entry, bool allowConditionalMatches) { if (!DropConditionEvaluator.HasConditions(entry.Conditions)) { return true; } if (allowConditionalMatches) { return DropConditionEvaluator.AreSatisfied(gameObject, entry.Conditions); } return false; } private static bool ShouldApplyToInstance(GameObject gameObject) { Piece component = gameObject.GetComponent(); if ((Object)(object)component == (Object)null) { return true; } return component.GetCreator() == 0; } private static void ClearContainerContentsIfNeeded(GameObject gameObject, PrefabConfigurationEntry entry) { Container val = default(Container); if (ContainerNeedsLiveMutation(entry) && HasDropTableOverride(entry.Container) && gameObject.TryGetComponent(ref val) && EntryMatches(gameObject, entry, allowConditionalMatches: true) && val.IsOwner()) { Inventory inventory = val.GetInventory(); if (inventory.NrOfItems() != 0) { inventory.RemoveAll(); } } } private static void RestoreConfiguredComponents(GameObject gameObject, PrefabSnapshot snapshot, PrefabConfigurationEntry entry, bool updateRuntimeState) { RestoreResourceComponents(gameObject, snapshot, entry, updateRuntimeState); RestoreInteractiveComponents(gameObject, snapshot, entry, updateRuntimeState); } private static void ApplyConfiguredComponents(GameObject gameObject, PrefabSnapshot snapshot, PrefabConfigurationEntry entry, bool updateRuntimeState, bool allowConditionalMatches) { if (EntryMatches(gameObject, entry, allowConditionalMatches)) { string contextRoot = ((Object)snapshot.Prefab).name + "@" + ((Object)gameObject).name; TryGetCompiledObjectDropRule(entry, out CompiledObjectDropRule compiledRule); ApplyResourceComponents(gameObject, entry, compiledRule, contextRoot, updateRuntimeState); ApplyInteractiveComponents(gameObject, entry, compiledRule, contextRoot, updateRuntimeState); } } private static bool TryGetConfiguredHealth(float configuredHealth, string context, out float normalizedHealth) { if (float.IsNaN(configuredHealth) || float.IsInfinity(configuredHealth) || configuredHealth <= 0f) { WarnInvalidEntry($"Entry '{context}' has invalid health '{configuredHealth}'. Health must be greater than 0."); normalizedHealth = 0f; return false; } normalizedHealth = configuredHealth; return true; } private static bool TryGetConfiguredMinToolTier(int configuredMinToolTier, string context, out int normalizedMinToolTier) { if (configuredMinToolTier < 0) { WarnInvalidEntry($"Entry '{context}' has invalid minToolTier '{configuredMinToolTier}'. minToolTier must be 0 or greater."); normalizedMinToolTier = 0; return false; } normalizedMinToolTier = configuredMinToolTier; return true; } private static void ApplyDestructibleHealth(Destructible destructible, float configuredBaseHealth, bool updateRuntimeState) { float health = destructible.m_health; if (!Mathf.Approximately(health, configuredBaseHealth)) { destructible.m_health = configuredBaseHealth; if (updateRuntimeState) { AdjustSharedHealthZdo(((Component)destructible).gameObject, GetScaledMineHealth(health), GetScaledMineHealth(configuredBaseHealth)); } } } private static void ApplyDestructibleMinToolTier(Destructible destructible, int configuredMinToolTier) { if (destructible.m_minToolTier != configuredMinToolTier) { destructible.m_minToolTier = configuredMinToolTier; } } private static void ApplyDestructibleType(Destructible destructible, DestructibleType configuredType) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) if (destructible.m_destructibleType != configuredType) { destructible.m_destructibleType = configuredType; } } private static void ApplyMineRockHealth(MineRock mineRock, float configuredBaseHealth, bool updateRuntimeState) { float health = mineRock.m_health; mineRock.m_health = configuredBaseHealth; if (updateRuntimeState) { AdjustMineRockAreaHealth(mineRock, GetScaledMineHealth(health), GetScaledMineHealth(configuredBaseHealth)); } } private static void ApplyMineRock5Health(MineRock5 mineRock5, float configuredBaseHealth, bool updateRuntimeState) { float health = mineRock5.m_health; mineRock5.m_health = configuredBaseHealth; if (updateRuntimeState) { AdjustMineRock5AreaHealth(mineRock5, GetScaledMineHealth(health), GetScaledMineHealth(configuredBaseHealth)); } } private static void ApplyTreeBaseHealth(TreeBase treeBase, float configuredBaseHealth, bool updateRuntimeState) { float health = treeBase.m_health; treeBase.m_health = configuredBaseHealth; if (updateRuntimeState) { AdjustSharedHealthZdo(((Component)treeBase).gameObject, Mathf.Max(health, 0.01f), Mathf.Max(configuredBaseHealth, 0.01f)); } } private static void ApplyTreeLogHealth(TreeLog treeLog, float configuredBaseHealth, bool updateRuntimeState) { float health = treeLog.m_health; treeLog.m_health = configuredBaseHealth; if (updateRuntimeState) { AdjustSharedHealthZdo(((Component)treeLog).gameObject, GetScaledMineHealth(health), GetScaledMineHealth(configuredBaseHealth)); } } private static float GetScaledMineHealth(float baseHealth) { if ((Object)(object)Game.instance == (Object)null) { return baseHealth; } return baseHealth + (float)Game.m_worldLevel * Game.instance.m_worldLevelMineHPMultiplier * baseHealth; } private static void AdjustSharedHealthZdo(GameObject gameObject, float oldMaxHealth, float newMaxHealth) { ZNetView component = gameObject.GetComponent(); ZDO val = ((component != null) ? component.GetZDO() : null); if (!((Object)(object)component == (Object)null) && val != null && component.IsOwner()) { float num = RemapHealth(val.GetFloat(ZDOVars.s_health, oldMaxHealth), oldMaxHealth, newMaxHealth); val.Set(ZDOVars.s_health, num); } } private static void AdjustMineRockAreaHealth(MineRock mineRock, float oldMaxHealth, float newMaxHealth) { ZNetView component = ((Component)mineRock).GetComponent(); ZDO val = ((component != null) ? component.GetZDO() : null); if (!((Object)(object)component == (Object)null) && val != null && component.IsOwner()) { int mineRockAreaCount = GetMineRockAreaCount(mineRock); for (int i = 0; i < mineRockAreaCount; i++) { string text = $"Health{i}"; float @float = val.GetFloat(text, oldMaxHealth); val.Set(text, RemapHealth(@float, oldMaxHealth, newMaxHealth)); } } } private static void SetMineRockAreaHealthAbsolute(MineRock mineRock, float configuredAreaHealth) { ZNetView component = ((Component)mineRock).GetComponent(); ZDO val = ((component != null) ? component.GetZDO() : null); if (!((Object)(object)component == (Object)null) && val != null && component.IsOwner()) { int mineRockAreaCount = GetMineRockAreaCount(mineRock); for (int i = 0; i < mineRockAreaCount; i++) { val.Set($"Health{i}", configuredAreaHealth); } } } private static int GetMineRockAreaCount(MineRock mineRock) { return (((Object)(object)mineRock.m_areaRoot != (Object)null) ? mineRock.m_areaRoot.GetComponentsInChildren() : ((Component)mineRock).gameObject.GetComponentsInChildren()).Length; } private static void AdjustMineRock5AreaHealth(MineRock5 mineRock5, float oldMaxHealth, float newMaxHealth) { if (MineRock5HitAreasField == null || MineRock5HitAreaHealthField == null) { return; } ZNetView component = ((Component)mineRock5).GetComponent(); ZDO val = ((component != null) ? component.GetZDO() : null); if ((Object)(object)component == (Object)null || val == null || !component.IsOwner() || !(MineRock5HitAreasField.GetValue(mineRock5) is IList list)) { return; } foreach (object item in list) { if (item != null) { float currentHealth = ((MineRock5HitAreaHealthField.GetValue(item) is float num) ? num : oldMaxHealth); MineRock5HitAreaHealthField.SetValue(item, RemapHealth(currentHealth, oldMaxHealth, newMaxHealth)); } } MineRock5SaveHealthMethod?.Invoke(mineRock5, null); MineRock5UpdateMeshMethod?.Invoke(mineRock5, null); } private static void SetMineRock5AreaHealthAbsolute(MineRock5 mineRock5, float configuredAreaHealth) { if (MineRock5HitAreasField == null || MineRock5HitAreaHealthField == null) { return; } ZNetView component = ((Component)mineRock5).GetComponent(); ZDO val = ((component != null) ? component.GetZDO() : null); if ((Object)(object)component == (Object)null || val == null || !component.IsOwner() || !(MineRock5HitAreasField.GetValue(mineRock5) is IList list)) { return; } foreach (object item in list) { if (item != null) { MineRock5HitAreaHealthField.SetValue(item, configuredAreaHealth); } } MineRock5SaveHealthMethod?.Invoke(mineRock5, null); MineRock5UpdateMeshMethod?.Invoke(mineRock5, null); } private static float RemapHealth(float currentHealth, float oldMaxHealth, float newMaxHealth) { if (newMaxHealth <= 0f || currentHealth <= 0f) { return 0f; } if (oldMaxHealth <= 0f) { return newMaxHealth; } return Mathf.Clamp01(currentHealth / oldMaxHealth) * newMaxHealth; } private static void ApplyPickableDefinition(Pickable pickable, PickableDefinition definition, string context, bool updateRuntimeState) { if (HasPickableDropOverride(definition.Drop)) { if (!string.IsNullOrWhiteSpace(definition.Drop.Item)) { GameObject val = ResolveItemPrefab(definition.Drop.Item, context); if ((Object)(object)val != (Object)null && (Object)(object)pickable.m_itemPrefab != (Object)(object)val) { pickable.m_itemPrefab = val; } } if (definition.Drop.Amount.HasValue && pickable.m_amount != Math.Max(1, definition.Drop.Amount.Value)) { pickable.m_amount = Math.Max(1, definition.Drop.Amount.Value); } if (definition.Drop.MinAmountScaled.HasValue && pickable.m_minAmountScaled != Math.Max(1, definition.Drop.MinAmountScaled.Value)) { pickable.m_minAmountScaled = Math.Max(1, definition.Drop.MinAmountScaled.Value); } if (definition.Drop.DontScale.HasValue && pickable.m_dontScale != definition.Drop.DontScale.Value) { pickable.m_dontScale = definition.Drop.DontScale.Value; } } if (definition.OverrideName != null && pickable.m_overrideName != definition.OverrideName) { pickable.m_overrideName = definition.OverrideName; } } private static void ApplyPickableDefinition(Pickable pickable, CompiledPickableDefinition definition, bool updateRuntimeState) { if (definition.HasItemPrefabOverride && (Object)(object)pickable.m_itemPrefab != (Object)(object)definition.ItemPrefab) { pickable.m_itemPrefab = definition.ItemPrefab; } if (definition.HasAmountOverride && pickable.m_amount != definition.Amount) { pickable.m_amount = definition.Amount; } if (definition.HasMinAmountScaledOverride && pickable.m_minAmountScaled != definition.MinAmountScaled) { pickable.m_minAmountScaled = definition.MinAmountScaled; } if (definition.HasDontScaleOverride && pickable.m_dontScale != definition.DontScale) { pickable.m_dontScale = definition.DontScale; } if (definition.HasOverrideNameOverride && pickable.m_overrideName != definition.OverrideName) { pickable.m_overrideName = definition.OverrideName; } } private static void ApplyPickableItemDefinition(PickableItem pickableItem, PickableItemDefinition definition, string context, bool updateRuntimeState) { PickableItem pickableItem2 = pickableItem; bool flag = false; bool forceRandomRefresh = false; bool flag2 = definition.RandomDrops != null; if (definition.RandomDrops == null) { List list2 = (definition.RandomDrops = new List()); } bool flag3 = definition.RandomDrops.Count > 0; bool flag4 = HasPickableItemDropOverride(definition.Drop); if (flag3 && flag4) { WarnInvalidEntry("Entry '" + context + "' defines both drop and randomDrops. randomDrops take precedence."); } if (flag3) { BuiltRandomPickableItems builtRandomPickableItems = BuildRandomItems(definition.RandomDrops, context); if (!PickableItemRandomItemsEqual(pickableItem2.m_randomItemPrefabs, builtRandomPickableItems.Items)) { pickableItem2.m_randomItemPrefabs = builtRandomPickableItems.Items; flag = true; forceRandomRefresh = true; } if (!PickableItemRandomWeightsEqual(pickableItem2, builtRandomPickableItems.Weights)) { SetPickableItemRandomWeights(pickableItem2, builtRandomPickableItems.Weights); flag = true; forceRandomRefresh = true; } if ((Object)(object)pickableItem2.m_itemPrefab != (Object)null && !builtRandomPickableItems.Items.Any((RandomItem randomItem) => (Object)(object)randomItem.m_itemPrefab == (Object)(object)pickableItem2.m_itemPrefab)) { pickableItem2.m_itemPrefab = null; flag = true; forceRandomRefresh = true; } if (builtRandomPickableItems.Items.Length == 0) { if ((Object)(object)pickableItem2.m_itemPrefab != (Object)null) { pickableItem2.m_itemPrefab = null; flag = true; } if (pickableItem2.m_stack != 1) { pickableItem2.m_stack = 1; flag = true; } } } else { if (LazyRuntimeState.HasRandomState(pickableItem2) && !PickableItemRandomWeightsEqual(pickableItem2, Array.Empty())) { ClearPickableItemRandomWeights(pickableItem2); flag = true; } if (flag2 && pickableItem2.m_randomItemPrefabs.Length != 0) { pickableItem2.m_randomItemPrefabs = Array.Empty(); flag = true; } if (flag4) { if (!string.IsNullOrWhiteSpace(definition.Drop?.Item)) { GameObject val = ResolveItemPrefab(definition.Drop.Item, context); if ((Object)(object)val != (Object)null) { ItemDrop component = val.GetComponent(); if ((Object)(object)pickableItem2.m_itemPrefab != (Object)(object)component) { pickableItem2.m_itemPrefab = component; flag = true; } } } PickableItemDropDefinition? drop = definition.Drop; if (drop != null && drop.Stack.HasValue && pickableItem2.m_stack != Math.Max(1, definition.Drop.Stack.Value)) { pickableItem2.m_stack = Math.Max(1, definition.Drop.Stack.Value); flag = true; } } } if (updateRuntimeState && flag) { bool useRandomItems = flag3 && pickableItem2.m_randomItemPrefabs.Length != 0; UpdatePickableItemRuntimeState(pickableItem2, useRandomItems, forceRandomRefresh); } } private static void ApplyPickableItemDefinition(PickableItem pickableItem, CompiledPickableItemDefinition definition, bool updateRuntimeState) { PickableItem pickableItem2 = pickableItem; bool flag = false; bool forceRandomRefresh = false; bool flag2 = definition.RandomItems.Length != 0; if (flag2) { if (!PickableItemRandomItemsEqual(pickableItem2.m_randomItemPrefabs, definition.RandomItems)) { RandomItem[] array = (RandomItem[])(object)new RandomItem[definition.RandomItems.Length]; Array.Copy(definition.RandomItems, array, definition.RandomItems.Length); pickableItem2.m_randomItemPrefabs = array; flag = true; forceRandomRefresh = true; } if (!PickableItemRandomWeightsEqual(pickableItem2, definition.RandomWeights)) { SetPickableItemRandomWeights(pickableItem2, definition.RandomWeights); flag = true; forceRandomRefresh = true; } if ((Object)(object)pickableItem2.m_itemPrefab != (Object)null && !definition.RandomItems.Any((RandomItem randomItem) => (Object)(object)randomItem.m_itemPrefab == (Object)(object)pickableItem2.m_itemPrefab)) { pickableItem2.m_itemPrefab = null; flag = true; forceRandomRefresh = true; } if (definition.RandomItems.Length == 0) { if ((Object)(object)pickableItem2.m_itemPrefab != (Object)null) { pickableItem2.m_itemPrefab = null; flag = true; } if (pickableItem2.m_stack != 1) { pickableItem2.m_stack = 1; flag = true; } } } else { if (LazyRuntimeState.HasRandomState(pickableItem2) && !PickableItemRandomWeightsEqual(pickableItem2, Array.Empty())) { ClearPickableItemRandomWeights(pickableItem2); flag = true; } if (definition.HasRandomOverride && pickableItem2.m_randomItemPrefabs.Length != 0) { pickableItem2.m_randomItemPrefabs = Array.Empty(); flag = true; } if (definition.HasFixedDrop) { if (definition.HasFixedItemOverride && (Object)(object)pickableItem2.m_itemPrefab != (Object)(object)definition.FixedItemPrefab) { pickableItem2.m_itemPrefab = definition.FixedItemPrefab; flag = true; } if (definition.HasFixedStackOverride && pickableItem2.m_stack != definition.FixedStack) { pickableItem2.m_stack = definition.FixedStack; flag = true; } } } if (updateRuntimeState && flag) { UpdatePickableItemRuntimeState(pickableItem2, flag2 && pickableItem2.m_randomItemPrefabs.Length != 0, forceRandomRefresh); } } private static void ApplyDestructibleDefinition(Destructible destructible, DestructibleDefinition definition, string context, bool includeSpawnWhenDestroyed) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) if (!string.IsNullOrWhiteSpace(definition.DestructibleType)) { if (Enum.TryParse(definition.DestructibleType, ignoreCase: true, out DestructibleType result)) { ApplyDestructibleType(destructible, result); } else { WarnInvalidEntry("Entry '" + context + "' has invalid destructibleType '" + definition.DestructibleType + "'."); } } if (includeSpawnWhenDestroyed && !string.IsNullOrWhiteSpace(definition.SpawnWhenDestroyed)) { destructible.m_spawnWhenDestroyed = ResolveSpawnPrefab(definition.SpawnWhenDestroyed, context); } } private static GameObject? ResolveSpawnPrefab(string prefabName, string context) { string text = (prefabName ?? "").Trim(); if (text.Length == 0) { return null; } ZNetScene instance = ZNetScene.instance; object obj = ((instance != null) ? instance.GetPrefab(text) : null); if (obj == null) { ObjectDB instance2 = ObjectDB.instance; obj = ((instance2 != null) ? instance2.GetItemPrefab(text) : null); } GameObject val = (GameObject)obj; if ((Object)(object)val == (Object)null) { WarnInvalidEntry("Entry '" + context + "' references unknown spawn prefab '" + text + "'."); } return val; } private static DropTable BuildDropTable(DropTablePayloadDefinition definition, string context) { DropTable obj = CreateDefaultDropTable(); ApplyDropTableScalarOverrides(obj, definition, resetToDefaultsWhenUnset: true); AppendDropTableRows(obj.m_drops, definition.Drops, context); return obj; } private static DropTable BuildEffectiveDropTable(DropTable? snapshotTable, IEnumerable matchingPayloads, string context) { List list = (matchingPayloads ?? Enumerable.Empty()).Where(HasDropTableOverride).ToList(); if (list.Count == 0) { if (snapshotTable == null) { return CreateDefaultDropTable(); } return CloneDropTable(snapshotTable); } DropTable val = ((snapshotTable != null) ? CloneDropTable(snapshotTable) : CreateDefaultDropTable()); val.m_drops = new List(); HashSet seenFingerprints = new HashSet(StringComparer.Ordinal); foreach (DropTablePayloadDefinition item in list) { ApplyDropTableScalarOverrides(val, item, resetToDefaultsWhenUnset: false); AppendDropTableRows(val.m_drops, item.Drops, context, seenFingerprints); } return val; } private static DropTable BuildEffectiveDropTable(DropTable? snapshotTable, IEnumerable matchingPayloads) { List list = (matchingPayloads ?? Enumerable.Empty()).ToList(); if (list.Count == 0) { if (snapshotTable == null) { return CreateDefaultDropTable(); } return CloneDropTable(snapshotTable); } DropTable val = ((snapshotTable != null) ? CloneDropTable(snapshotTable) : CreateDefaultDropTable()); val.m_drops = new List(); HashSet seenFingerprints = new HashSet(StringComparer.Ordinal); foreach (CompiledDropTablePayload item in list) { ApplyDropTableScalarOverrides(val, item); AppendDropTableRows(val.m_drops, item.Drops, seenFingerprints); } return val; } private static DropTable BuildEffectiveDropTable(StaticCompiledDropTableTemplate template, IEnumerable matchingPayloads) { List list = (matchingPayloads ?? Enumerable.Empty()).ToList(); if (list.Count == 0) { return CloneDropTable(template.Template); } DropTable val = CloneDropTable(template.Template); HashSet seenFingerprints = new HashSet(template.Fingerprints, StringComparer.Ordinal); foreach (CompiledDropTablePayload item in list) { ApplyDropTableScalarOverrides(val, item); AppendDropTableRows(val.m_drops, item.Drops, seenFingerprints); } return val; } private static DropTable CreateDefaultDropTable() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown return new DropTable { m_dropMin = 1, m_dropMax = 1, m_dropChance = 1f, m_oneOfEach = false, m_drops = new List() }; } private static void ApplyDropTableScalarOverrides(DropTable dropTable, DropTablePayloadDefinition definition, bool resetToDefaultsWhenUnset) { if (definition.DropMin.HasValue || definition.DropMax.HasValue) { int num = Math.Max(0, definition.DropMin.GetValueOrDefault(1)); int dropMax = Math.Max(num, definition.DropMax ?? definition.DropMin.GetValueOrDefault(1)); dropTable.m_dropMin = num; dropTable.m_dropMax = dropMax; } else if (resetToDefaultsWhenUnset) { dropTable.m_dropMin = 1; dropTable.m_dropMax = 1; } if (definition.DropChance.HasValue) { dropTable.m_dropChance = Mathf.Clamp01(definition.DropChance.Value); } else if (resetToDefaultsWhenUnset) { dropTable.m_dropChance = 1f; } if (definition.OneOfEach.HasValue) { dropTable.m_oneOfEach = definition.OneOfEach.Value; } else if (resetToDefaultsWhenUnset) { dropTable.m_oneOfEach = false; } } private static void ApplyDropTableScalarOverrides(DropTable dropTable, CompiledDropTablePayload definition) { if (definition.HasDropRangeOverride) { dropTable.m_dropMin = definition.DropMin; dropTable.m_dropMax = definition.DropMax; } if (definition.HasDropChanceOverride) { dropTable.m_dropChance = definition.DropChance; } if (definition.HasOneOfEachOverride) { dropTable.m_oneOfEach = definition.OneOfEach; } } private static void AppendDropTableRows(List target, IEnumerable? definitions, string context, HashSet? seenFingerprints = null) { //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) foreach (DropEntryDefinition item2 in definitions ?? Enumerable.Empty()) { string text = (item2.Item ?? "").Trim(); if (text.Length == 0) { WarnInvalidEntry("Entry '" + context + "' contains a drop without an item name."); continue; } GameObject val = ResolveItemPrefab(text, context); if (!((Object)(object)val == (Object)null)) { string item = BuildDropRowFingerprint(item2); if (seenFingerprints == null || seenFingerprints.Add(item)) { target.Add(new DropData { m_item = val, m_stackMin = Math.Max(1, item2.StackMin.GetValueOrDefault(1)), m_stackMax = Math.Max(Math.Max(1, item2.StackMin.GetValueOrDefault(1)), item2.StackMax ?? item2.StackMin.GetValueOrDefault(1)), m_weight = Mathf.Max(0f, item2.Weight.GetValueOrDefault(1f)), m_dontScale = item2.DontScale.GetValueOrDefault() }); } } } } private static void AppendDropTableRows(List target, IEnumerable definitions, HashSet? seenFingerprints = null) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) foreach (CompiledDropTableRow item in definitions ?? Enumerable.Empty()) { if (seenFingerprints == null || seenFingerprints.Add(item.Fingerprint)) { target.Add(new DropData { m_item = item.ItemPrefab, m_stackMin = item.StackMin, m_stackMax = item.StackMax, m_weight = item.Weight, m_dontScale = item.DontScale }); } } } private static string BuildDropRowFingerprint(DropEntryDefinition definition) { return NetworkPayloadSyncSupport.ComputeObjectDropRowSignature(new DropEntryDefinition { Item = (definition.Item ?? "").Trim(), StackMin = Math.Max(1, definition.StackMin.GetValueOrDefault(1)), StackMax = Math.Max(Math.Max(1, definition.StackMin.GetValueOrDefault(1)), definition.StackMax ?? definition.StackMin.GetValueOrDefault(1)), Weight = Mathf.Max(0f, definition.Weight.GetValueOrDefault(1f)), DontScale = definition.DontScale.GetValueOrDefault() }); } private static GameObject? ResolveItemPrefab(string itemName, string context) { string text = (itemName ?? "").Trim(); if (text.Length == 0) { WarnInvalidEntry("Entry '" + context + "' references an empty item prefab name."); return null; } ObjectDB instance = ObjectDB.instance; object obj = ((instance != null) ? instance.GetItemPrefab(text) : null); if (obj == null) { ZNetScene instance2 = ZNetScene.instance; obj = ((instance2 != null) ? instance2.GetPrefab(text) : null); } GameObject val = (GameObject)obj; if ((Object)(object)val == (Object)null) { WarnInvalidEntry("Entry '" + context + "' references unknown item prefab '" + text + "'."); return null; } ItemDrop val2 = default(ItemDrop); if (!val.TryGetComponent(ref val2)) { WarnInvalidEntry("Entry '" + context + "' references '" + text + "', but it is not an item prefab."); return null; } return val; } private static DropTable CloneDropTable(DropTable source) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected O, but got Unknown //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) DropTable val = new DropTable { m_dropMin = source.m_dropMin, m_dropMax = source.m_dropMax, m_dropChance = source.m_dropChance, m_oneOfEach = source.m_oneOfEach, m_drops = new List(source.m_drops.Count) }; foreach (DropData drop in source.m_drops) { val.m_drops.Add(new DropData { m_item = drop.m_item, m_stackMin = drop.m_stackMin, m_stackMax = drop.m_stackMax, m_weight = drop.m_weight, m_dontScale = drop.m_dontScale }); } return val; } private static string FormatYamlBool(bool value) { if (!value) { return "false"; } return "true"; } private static string FormatYamlFloat(float value) { return value.ToString("0.###", CultureInfo.InvariantCulture); } private static string FormatYamlString(string value) { if (value.Length == 0) { return "''"; } if (!char.IsWhiteSpace(value[0]) && !char.IsWhiteSpace(value[value.Length - 1]) && value.IndexOfAny(new char[17] { ':', '#', '{', '}', '[', ']', ',', '\'', '"', '&', '*', '!', '|', '>', '%', '@', '`' }) < 0 && value[0] != '-' && value[0] != '?' && !string.Equals(value, "null", StringComparison.OrdinalIgnoreCase) && !string.Equals(value, "true", StringComparison.OrdinalIgnoreCase) && !string.Equals(value, "false", StringComparison.OrdinalIgnoreCase)) { return value; } return "'" + value.Replace("'", "''") + "'"; } private static PrefabConfigurationEntry BuildConfigurationEntry(PrefabSnapshot snapshot) { return new PrefabConfigurationEntry { Prefab = ((Object)snapshot.Prefab).name, Enabled = true, Destructible = ConvertDestructible(snapshot), DropOnDestroyed = ((snapshot.DropOnDestroyed != null) ? ConvertDropTable(snapshot.DropOnDestroyed) : null), MineRock = ((snapshot.MineRock != null) ? ConvertDamageableDropTable(snapshot.MineRock, snapshot.Health?.MineRock, snapshot.MinToolTier?.MineRock) : null), MineRock5 = ((snapshot.MineRock5 != null) ? ConvertDamageableDropTable(snapshot.MineRock5, snapshot.Health?.MineRock5, snapshot.MinToolTier?.MineRock5) : null), TreeBase = ((snapshot.TreeBase != null) ? ConvertDamageableDropTable(snapshot.TreeBase, snapshot.Health?.TreeBase, snapshot.MinToolTier?.TreeBase) : null), TreeLog = ((snapshot.TreeLog != null) ? ConvertDamageableDropTable(snapshot.TreeLog, snapshot.Health?.TreeLog, snapshot.MinToolTier?.TreeLog) : null), Container = ((snapshot.Container != null) ? ConvertDropTable(snapshot.Container) : null), Pickable = ((snapshot.Pickable != null) ? ConvertPickable(snapshot.Pickable) : null), PickableItem = ((snapshot.PickableItem != null) ? ConvertPickableItem(snapshot.PickableItem) : null), Fish = ((snapshot.Fish != null) ? ConvertFish(snapshot.Fish) : null) }; } private static int CompareObjectEntriesForOutput(PrefabConfigurationEntry? left, PrefabConfigurationEntry? right) { if (left == right) { return 0; } if (left == null) { return 1; } if (right == null) { return -1; } int num = GetPrimaryObjectComponentRank(left).CompareTo(GetPrimaryObjectComponentRank(right)); if (num != 0) { return num; } int num2 = GetObjectComponentSignatureMask(left).CompareTo(GetObjectComponentSignatureMask(right)); if (num2 != 0) { return num2; } return string.Compare(left.Prefab, right.Prefab, StringComparison.OrdinalIgnoreCase); } private static int GetPrimaryObjectComponentRank(PrefabConfigurationEntry entry) { if (entry.Container != null) { return 0; } if (entry.Pickable != null) { return 1; } if (entry.PickableItem != null) { return 2; } if (entry.Fish != null) { return 3; } if (entry.MineRock != null) { return 4; } if (entry.MineRock5 != null) { return 5; } if (entry.TreeBase != null) { return 6; } if (entry.TreeLog != null) { return 7; } if (entry.DropOnDestroyed != null) { return 8; } if (entry.Destructible != null) { return 9; } return 10; } private static int GetObjectComponentSignatureMask(PrefabConfigurationEntry entry) { int num = 0; if (entry.Container != null) { num |= 1; } if (entry.Pickable != null) { num |= 2; } if (entry.PickableItem != null) { num |= 4; } if (entry.Fish != null) { num |= 8; } if (entry.MineRock != null) { num |= 0x10; } if (entry.MineRock5 != null) { num |= 0x20; } if (entry.TreeBase != null) { num |= 0x40; } if (entry.TreeLog != null) { num |= 0x80; } if (entry.DropOnDestroyed != null) { num |= 0x100; } if (entry.Destructible != null) { num |= 0x200; } return num; } private static DestructibleDefinition? ConvertDestructible(PrefabSnapshot snapshot) { //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Invalid comparison between Unknown and I4 //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) bool flag = snapshot.Health?.Destructible.HasValue ?? false; bool flag2 = snapshot.MinToolTier?.Destructible.HasValue ?? false; if (!flag && !flag2 && snapshot.Destructible == null) { return null; } DestructibleDefinition obj = new DestructibleDefinition { Health = (flag ? snapshot.Health.Destructible : null), MinToolTier = (flag2 ? snapshot.MinToolTier.Destructible : null) }; object destructibleType; if (snapshot.Destructible == null || (int)snapshot.Destructible.DestructibleType == 1) { destructibleType = null; } else { DestructibleType destructibleType2 = snapshot.Destructible.DestructibleType; destructibleType = ((object)(DestructibleType)(ref destructibleType2)).ToString(); } obj.DestructibleType = (string?)destructibleType; obj.SpawnWhenDestroyed = NormalizeReferencePrefabName(snapshot.Destructible?.SpawnWhenDestroyed); return obj; } private static DropTableDefinition ConvertDropTable(DropTable dropTable) { int num = Math.Max(0, dropTable.m_dropMin); int actualMax = Math.Max(num, dropTable.m_dropMax); List list = (from drop in dropTable.m_drops select new { Name = NormalizeReferencePrefabName(drop.m_item), Drop = drop } into entry where !string.IsNullOrWhiteSpace(entry.Name) select new DropEntryDefinition { Item = entry.Name, Stack = RangeFormatting.FromReference(entry.Drop.m_stackMin, entry.Drop.m_stackMax, 1, 1), Weight = (IsReferenceDefault(entry.Drop.m_weight, 1f) ? null : new float?(entry.Drop.m_weight)), DontScale = (entry.Drop.m_dontScale ? new bool?(true) : null) }).ToList(); return new DropTableDefinition { Rolls = RangeFormatting.FromReference(num, actualMax, 1, 1), DropChance = (IsReferenceDefault(dropTable.m_dropChance, 1f) ? null : new float?(dropTable.m_dropChance)), OneOfEach = (dropTable.m_oneOfEach ? new bool?(true) : null), Drops = ((list.Count > 0) ? list : null) }; } private static DamageableDropTableDefinition ConvertDamageableDropTable(DropTable dropTable, float? health, int? minToolTier) { DropTableDefinition dropTableDefinition = ConvertDropTable(dropTable); return new DamageableDropTableDefinition { Health = health, MinToolTier = minToolTier, Rolls = dropTableDefinition.Rolls, DropChance = dropTableDefinition.DropChance, OneOfEach = dropTableDefinition.OneOfEach, Drops = dropTableDefinition.Drops }; } private static PickableDefinition ConvertPickable(PickableSnapshot snapshot) { DropTableDefinition dropTableDefinition = ConvertDropTable(snapshot.ExtraDrops); string text = NormalizeReferencePrefabName(snapshot.ItemPrefab); PickableDropDefinition drop = null; if (!string.IsNullOrWhiteSpace(text) || snapshot.Amount != 1 || snapshot.MinAmountScaled != 0 || snapshot.DontScale) { drop = new PickableDropDefinition { Item = (text ?? ""), Amount = ((snapshot.Amount == 1) ? null : new int?(snapshot.Amount)), MinAmountScaled = ((snapshot.MinAmountScaled == 0) ? null : new int?(snapshot.MinAmountScaled)), DontScale = (snapshot.DontScale ? new bool?(true) : null) }; } return new PickableDefinition { OverrideName = (string.IsNullOrWhiteSpace(snapshot.OverrideName) ? null : snapshot.OverrideName), Drop = drop, ExtraDrops = (HasReferenceDropTableContent(dropTableDefinition) ? dropTableDefinition : null) }; } private static PickableItemDefinition ConvertPickableItem(PickableItemSnapshot snapshot) { List list = (from item in snapshot.RandomItems select new { Name = NormalizeReferencePrefabName(item.ItemPrefab), Item = item } into entry where !string.IsNullOrWhiteSpace(entry.Name) select new RandomPickableItemDefinition { Item = entry.Name, Stack = RangeFormatting.FromReference(entry.Item.StackMin, entry.Item.StackMax, 1, 1) }).ToList(); string text = NormalizeReferencePrefabName(snapshot.ItemPrefab); return new PickableItemDefinition { RandomDrops = ((list.Count > 0) ? list : null), Drop = ((list.Count == 0 && (!string.IsNullOrWhiteSpace(text) || snapshot.Stack != 1)) ? new PickableItemDropDefinition { Item = (text ?? ""), Stack = ((snapshot.Stack == 1) ? null : new int?(snapshot.Stack)) } : null) }; } private static FishDefinition ConvertFish(FishSnapshot snapshot) { DropTableDefinition dropTableDefinition = ConvertDropTable(snapshot.ExtraDrops); return new FishDefinition { ExtraDrops = (HasReferenceDropTableContent(dropTableDefinition) ? dropTableDefinition : null) }; } private static bool HasReferenceDropTableContent(DropTablePayloadDefinition? definition) { if (definition != null) { IntRangeDefinition? rolls = definition.Rolls; if ((rolls == null || !rolls.HasValues()) && !definition.DropMin.HasValue && !definition.DropMax.HasValue && !definition.DropChance.HasValue && !definition.OneOfEach.HasValue) { if (definition.Drops != null) { return definition.Drops.Count > 0; } return false; } return true; } return false; } private static IntRangeDefinition? GetRollsRange(DropTablePayloadDefinition definition) { return definition.Rolls ?? RangeFormatting.From(definition.DropMin, definition.DropMax ?? definition.DropMin); } private static IntRangeDefinition? GetStackRange(DropEntryDefinition definition) { return definition.Stack ?? RangeFormatting.From(definition.StackMin, definition.StackMax ?? definition.StackMin); } private static IntRangeDefinition? GetStackRange(RandomPickableItemDefinition definition) { return definition.Stack ?? RangeFormatting.From(definition.StackMin, definition.StackMax ?? definition.StackMin); } private static bool IsReferenceDefault(float value, float defaultValue) { return Math.Abs(value - defaultValue) < 0.0001f; } private static string? NormalizeReferencePrefabName(GameObject? prefab) { if (!((Object)(object)prefab == (Object)null)) { return NormalizeReferencePrefabName(((Object)prefab).name); } return null; } private static string? NormalizeReferencePrefabName(string? prefabName) { if (string.IsNullOrWhiteSpace(prefabName)) { return null; } if (!prefabName.StartsWith("JVLmock_", StringComparison.OrdinalIgnoreCase)) { return prefabName; } string text = prefabName.Substring("JVLmock_".Length); if (string.IsNullOrWhiteSpace(text)) { return null; } ZNetScene instance = ZNetScene.instance; if (!((Object)(object)((instance != null) ? instance.GetPrefab(text) : null) != (Object)null)) { ObjectDB instance2 = ObjectDB.instance; if (!((Object)(object)((instance2 != null) ? instance2.GetItemPrefab(text) : null) != (Object)null)) { return null; } } return text; } private static string GetPrefabName(GameObject gameObject) { if ((Object)(object)gameObject == (Object)null) { return ""; } ZNetView component = gameObject.GetComponent(); 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 ((Object)prefab).name; } } string prefabName = Utils.GetPrefabName(gameObject); if (!string.IsNullOrWhiteSpace(prefabName)) { return prefabName; } string name = ((Object)gameObject).name; if (name.EndsWith("(Clone)", StringComparison.Ordinal)) { string text = name; int length = "(Clone)".Length; return text.Substring(0, text.Length - length).TrimEnd(); } return name; } private static void RunApplyCoordinator(int gameDataSignature, bool domainEnabled, Dictionary currentEntrySignatures, bool queueLiveReconcile) { ObjectDesiredState objectDesiredState = BuildObjectDesiredState(gameDataSignature, domainEnabled, currentEntrySignatures, queueLiveReconcile); _ = StandardBaselineDesiredStateCoordinator.Run(objectDesiredState.ApplyPlan, objectDesiredState, ObjectApplyOperations.Instance).Success; } private static ObjectDesiredState BuildObjectDesiredState(int gameDataSignature, bool domainEnabled, Dictionary currentEntrySignatures, bool queueLiveReconcile) { StandardDomainApplyPlan applyPlan = StandardDomainApplySupport.BuildPlan(_lastAppliedGameDataSignature, gameDataSignature, _lastAppliedDomainEnabled, domainEnabled, _lastAppliedEntrySignaturesByPrefab, currentEntrySignatures, EmptyEntrySignatures, canUseTargetedLiveReload: true); HashSet dirtyKeys = applyPlan.DirtyKeys; HashSet liveDirtyPrefabs = ((dirtyKeys != null) ? FilterPrefabsRequiringLiveReconcile(dirtyKeys) : null); EnsureRuntimeDropConfigurationState(); return new ObjectDesiredState { GameDataSignature = gameDataSignature, ApplyPlan = applyPlan, CurrentEntrySignatures = currentEntrySignatures, RuntimeConfigurationState = _runtimeDropConfigurationState, DomainEnabled = domainEnabled, QueueLiveReconcile = queueLiveReconcile, DirtyPrefabs = dirtyKeys, LiveDirtyPrefabs = liveDirtyPrefabs, NeedsLiveReload = ((applyPlan.PreviousDomainEnabled && FilterPrefabsRequiringLiveReconcile(_lastAppliedEntrySignaturesByPrefab.Keys).Count > 0) || (domainEnabled && FilterPrefabsRequiringLiveReconcile(currentEntrySignatures.Keys).Count > 0)) }; } private static void RestoreObjectStaticBaseline(ObjectDesiredState desiredState) { RestoreSnapshots(desiredState.DirtyPrefabs); } private static void ValidateObjectDesiredState(ObjectDesiredState desiredState) { ValidateConfiguredPrefabs(); } private static void ApplyObjectDesiredStateToStaticBaseline(ObjectDesiredState desiredState) { ApplyDesiredStateToPrefabs(desiredState); } private static void PrepareObjectLiveBaseline(ObjectDesiredState desiredState) { } private static void ApplyObjectDesiredStateToLive(ObjectDesiredState desiredState) { ApplyDesiredStateToLiveObjects(desiredState); } private static bool HasPotentialStaticMatchForComponent(GameObject gameObject, string prefabName, LiveObjectComponentKind sourceKind) { long cacheKey = BuildStaticObjectMatchCacheKey(((Object)gameObject).GetInstanceID(), sourceKind); if (ConditionPlanCacheState.TryGetStaticObjectMatch(cacheKey, _reconcileQueueEpoch, out var hasPotentialStaticMatch)) { return hasPotentialStaticMatch; } hasPotentialStaticMatch = false; if (ActiveEntriesByPrefab.TryGetValue(prefabName, out List value)) { foreach (PrefabConfigurationEntry item in value) { if (DoesEntryAffectComponentKind(item, sourceKind) && (!DropConditionEvaluator.HasStaticConditions(item.Conditions) || DropConditionEvaluator.AreStaticConditionsSatisfied(gameObject, item.Conditions))) { hasPotentialStaticMatch = true; break; } } } ConditionPlanCacheState.RecordStaticObjectMatch(cacheKey, _reconcileQueueEpoch, hasPotentialStaticMatch); return hasPotentialStaticMatch; } private static bool DoesEntryAffectComponentKind(PrefabConfigurationEntry entry, LiveObjectComponentKind sourceKind) { if (sourceKind == LiveObjectComponentKind.Piece) { return true; } return (GetReconcileComponentKinds(entry) & sourceKind) != 0; } private static long BuildStaticObjectMatchCacheKey(int instanceId, LiveObjectComponentKind sourceKind) { return ((long)instanceId << 32) ^ (uint)sourceKind; } private static bool CanUseGroupConditionalApplyPlan(ConditionsDefinition? conditions) { if (!DropConditionEvaluator.HasConditions(conditions)) { return true; } if (conditions != null && !DropConditionEvaluator.HasDynamicConditions(conditions) && !conditions.InForest.HasValue) { FloatRangeDefinition? distanceFromCenter = conditions.DistanceFromCenter; if ((distanceFromCenter == null || !distanceFromCenter.HasValues()) && !conditions.MinDistanceFromCenter.HasValue && !conditions.MaxDistanceFromCenter.HasValue) { FloatRangeDefinition? altitude = conditions.Altitude; if ((altitude == null || !altitude.HasValues()) && !conditions.MinAltitude.HasValue) { return !conditions.MaxAltitude.HasValue; } } } return false; } private static bool TryGetGroupConditionalApplyPlan(GameObject gameObject, PrefabSnapshot snapshot, IReadOnlyCollection entries, out GroupConditionalApplyPlan? plan) { plan = null; if (entries.Count == 0) { return false; } bool flag = false; bool flag2 = false; bool flag3 = false; bool flag4 = false; foreach (PrefabConfigurationEntry entry in entries) { if (CanUseGroupConditionalApplyPlan(entry.Conditions)) { flag = true; ConditionsDefinition conditions = entry.Conditions; flag2 |= conditions != null && conditions.Locations?.Count > 0; flag3 |= (conditions != null && conditions.ResolvedBiomeMask.HasValue) || (conditions != null && conditions.Biomes?.Count > 0); flag4 |= conditions?.InDungeon.HasValue ?? false; } } if (!flag) { return false; } string groupKey = BuildObjectReconcileGroupKey(gameObject, ((Object)snapshot.Prefab).name); StaticConditionContextSnapshot orBuildStaticConditionContextSnapshot = GetOrBuildStaticConditionContextSnapshot(gameObject, flag2, flag3, flag4); string resolvedLocationName = (flag2 ? orBuildStaticConditionContextSnapshot.ResolvedLocationName : null); string cacheKey = BuildGroupConditionalApplyPlanCacheKey(groupKey, flag2, flag3, flag4, orBuildStaticConditionContextSnapshot); if (ConditionPlanCacheState.TryGetGroupConditionalApplyPlan(cacheKey, out GroupConditionalApplyPlan plan2)) { plan = plan2; return true; } EnsureRuntimeDropConfigurationState(); _runtimeDropConfigurationState.PlansByPrefab.TryGetValue(((Object)snapshot.Prefab).name, out CompiledObjectPrefabPlan value); List list = value?.Rules; GroupConditionalApplyPlan groupConditionalApplyPlan = new GroupConditionalApplyPlan(); foreach (PrefabConfigurationEntry entry2 in entries) { if (CanUseGroupConditionalApplyPlan(entry2.Conditions)) { groupConditionalApplyPlan.EligibleEntries.Add(entry2); if (!DropConditionEvaluator.HasConditions(entry2.Conditions) || DropConditionEvaluator.AreStaticConditionsSatisfied(gameObject, entry2.Conditions, resolvedLocationName)) { groupConditionalApplyPlan.MatchingEntries.Add(entry2); } } } if (list != null) { HashSet hashSet = new HashSet(groupConditionalApplyPlan.MatchingEntries); foreach (CompiledObjectDropRule item in list) { if (groupConditionalApplyPlan.EligibleEntries.Contains(item.Entry)) { groupConditionalApplyPlan.EligibleCompiledRules.Add(item); if (hashSet.Contains(item.Entry)) { groupConditionalApplyPlan.MatchingCompiledRules.Add(item); } } } } ConditionPlanCacheState.StoreGroupConditionalApplyPlan(cacheKey, groupConditionalApplyPlan); plan = groupConditionalApplyPlan; return true; } private static StaticConditionContextSnapshot GetOrBuildStaticConditionContextSnapshot(GameObject gameObject, bool usesLocation, bool usesBiome, bool usesInDungeon) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) int instanceID = ((Object)gameObject).GetInstanceID(); Vector3 position = gameObject.transform.position; if (ConditionPlanCacheState.TryGetStaticConditionContext(instanceID, position, out StaticConditionContextSnapshot snapshot)) { return snapshot; } snapshot = new StaticConditionContextSnapshot { Position = position }; if (usesLocation) { snapshot.ResolvedLocationName = DropConditionEvaluator.GetResolvedLocationNameForConditions(gameObject) ?? ""; } if (usesBiome) { StaticConditionContextSnapshot staticConditionContextSnapshot = snapshot; WorldGenerator instance = WorldGenerator.instance; staticConditionContextSnapshot.Biome = ((instance != null) ? instance.GetBiome(position) : Heightmap.FindBiome(position)); } if (usesInDungeon) { snapshot.InDungeon = Character.InInterior(position); } return ConditionPlanCacheState.StoreStaticConditionContext(instanceID, snapshot); } private static string BuildGroupConditionalApplyPlanCacheKey(string groupKey, bool usesLocation, bool usesBiome, bool usesInDungeon, StaticConditionContextSnapshot conditionContext) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected I4, but got Unknown StringBuilder stringBuilder = new StringBuilder(groupKey.Length + 64); stringBuilder.Append(groupKey); if (usesLocation) { stringBuilder.Append("|loc:"); stringBuilder.Append(conditionContext.ResolvedLocationName); } if (usesBiome) { stringBuilder.Append("|bio:"); stringBuilder.Append((int)conditionContext.Biome); } if (usesInDungeon) { stringBuilder.Append("|dgn:"); stringBuilder.Append(conditionContext.InDungeon ? '1' : '0'); } return stringBuilder.ToString(); } private static void RemovePendingObjectConditionPlanState(int instanceId) { ConditionPlanCacheState.InvalidateStaticObjectMatchCacheForInstance(instanceId); } private static void ClearLiveObjectConditionCaches() { ConditionPlanCacheState.Clear(); } private static void WarnMissingComponent(string key, string componentName) { if (MissingComponentWarnings.Add(key)) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("Prefab configuration references " + componentName + ", but the component was not found on '" + key + "'.")); } } private static void WarnInvalidEntry(string message) { if (_invalidEntryWarningSuppressionDepth <= 0 && !ShouldSuppressServerSourcedInvalidEntryWarning(message) && InvalidEntryWarnings.Add(message)) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)message); } } private static InvalidEntryWarningSuppressionScope BeginInvalidEntryWarningSuppressionForSyncedClientBuild(string sourceName) { if (DropNSpawnPlugin.IsSourceOfTruth || !sourceName.StartsWith("ServerSync:", StringComparison.Ordinal)) { return default(InvalidEntryWarningSuppressionScope); } return new InvalidEntryWarningSuppressionScope(active: true); } private static bool ShouldSuppressServerSourcedInvalidEntryWarning(string message) { if (!DropNSpawnPlugin.IsSourceOfTruth) { return message.IndexOf("ServerSync:", StringComparison.Ordinal) >= 0; } return false; } private static void LogPartiallyAcceptedLocalConfiguration(int parsedEntryCount, int acceptedEntryCount, List warnings) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)$"Loaded {acceptedEntryCount} object override entries from {parsedEntryCount} parsed entries. Invalid entries were skipped."); foreach (string item in warnings.Where((string message) => !string.IsNullOrWhiteSpace(message)).Distinct(StringComparer.OrdinalIgnoreCase)) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)item); } } private static void LogPartiallyAcceptedLocalConfigurationHook(int parsedEntryCount, int acceptedEntryCount, IEnumerable warnings) { LogPartiallyAcceptedLocalConfiguration(parsedEntryCount, acceptedEntryCount, warnings.ToList()); } private static void LogLocalConfigurationLoaded(int acceptedEntryCount, int loadedFileCount) { DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)$"Loaded {acceptedEntryCount} object override entries from {loadedFileCount} override file(s)."); } private static void OnSourceOfTruthPayloadUnchanged() { if (!NetworkPayloadSyncSupport.IsPayloadCurrent(Descriptor, _configurationSignature)) { ConfigurationDomainHost.PublishSyncedPayload(DropNSpawnPlugin.IsSourceOfTruth, Descriptor, _configuration, _configurationSignature); } } private static void LogSyncedObjectConfigurationLoaded(string payloadToken, int acceptedEntryCount) { DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)$"Loaded {acceptedEntryCount} synchronized object configuration(s) from the server."); } private static void LogSyncedObjectConfigurationFailure(string payloadToken, Exception ex) { DropNSpawnPlugin.DropNSpawnLogger.LogError((object)$"Failed to deserialize synchronized object payload DTO. {ex}"); } private static string CreateConfigurationContext(PrefabConfigurationEntry entry) { return (string.IsNullOrWhiteSpace(entry.Prefab) ? "" : entry.Prefab) + " @ " + DescribeEntrySource(entry); } private static string DescribeEntrySource(PrefabConfigurationEntry entry) { string text = DescribeEntrySource(entry.SourcePath); if (entry.SourceLine <= 0) { return text; } return text + ":" + entry.SourceLine.ToString(CultureInfo.InvariantCulture); } private static string DescribeEntrySource(string? sourcePath) { if (!string.IsNullOrWhiteSpace(sourcePath)) { return sourcePath; } return "unknown source"; } private static string FormatYamlExceptionLocation(Exception ex) { if (!(ex is YamlException ex2) || ex2.Start.Line <= 0) { return ""; } return ":" + ex2.Start.Line.ToString(CultureInfo.InvariantCulture); } private static string BuildCompiledObjectDropContext(PrefabConfigurationEntry entry, string componentName) { string text = (string.IsNullOrWhiteSpace(entry.Prefab) ? "" : entry.Prefab); string text2 = (string.IsNullOrWhiteSpace(entry.RuleId) ? "" : entry.RuleId); return text + "/" + componentName + "/" + text2 + "@" + DescribeEntrySource(entry); } private static void RestoreInteractiveComponents(GameObject gameObject, PrefabSnapshot snapshot, PrefabConfigurationEntry entry, bool updateRuntimeState) { Container val = default(Container); if (UsesLiveDropTableReconcile(LiveObjectComponentKind.Container) && HasDropTableOverride(entry.Container) && gameObject.TryGetComponent(ref val) && snapshot.Container != null) { val.m_defaultItems = CloneDropTable(snapshot.Container); } Pickable val2 = default(Pickable); if (HasPickableOverride(entry.Pickable) && gameObject.TryGetComponent(ref val2) && snapshot.Pickable != null) { val2.m_itemPrefab = snapshot.Pickable.ItemPrefab; val2.m_amount = snapshot.Pickable.Amount; val2.m_minAmountScaled = snapshot.Pickable.MinAmountScaled; val2.m_dontScale = snapshot.Pickable.DontScale; val2.m_overrideName = snapshot.Pickable.OverrideName; val2.m_extraDrops = CloneDropTable(snapshot.Pickable.ExtraDrops); } PickableItem pickableItem = default(PickableItem); if (HasPickableItemOverride(entry.PickableItem) && gameObject.TryGetComponent(ref pickableItem) && snapshot.PickableItem != null) { RestorePickableItem(pickableItem, snapshot.PickableItem, updateRuntimeState); } Fish val3 = default(Fish); if (HasFishOverride(entry.Fish) && gameObject.TryGetComponent(ref val3) && snapshot.Fish != null) { val3.m_extraDrops = CloneDropTable(snapshot.Fish.ExtraDrops); } } private static void ApplyInteractiveComponents(GameObject gameObject, PrefabConfigurationEntry entry, CompiledObjectDropRule? compiledRule, string contextRoot, bool updateRuntimeState) { Container val = default(Container); if (HasDropTableOverride(entry.Container) && !gameObject.TryGetComponent(ref val)) { WarnMissingComponent(contextRoot + "/Container", "Container"); } if (HasPickableOverride(entry.Pickable)) { Pickable pickable = default(Pickable); if (!gameObject.TryGetComponent(ref pickable)) { WarnMissingComponent(contextRoot + "/Pickable", "Pickable"); } else if (compiledRule?.Pickable != null) { ApplyPickableDefinition(pickable, compiledRule.Pickable, updateRuntimeState); } else { ApplyPickableDefinition(pickable, entry.Pickable, contextRoot + "/Pickable", updateRuntimeState); } } if (HasPickableItemOverride(entry.PickableItem)) { PickableItem pickableItem = default(PickableItem); if (!gameObject.TryGetComponent(ref pickableItem)) { WarnMissingComponent(contextRoot + "/PickableItem", "PickableItem"); } else if (compiledRule?.PickableItem != null) { ApplyPickableItemDefinition(pickableItem, compiledRule.PickableItem, updateRuntimeState); } else { ApplyPickableItemDefinition(pickableItem, entry.PickableItem, contextRoot + "/PickableItem", updateRuntimeState); } } } internal static void ApplyLazyMineRockScalarsIfNeeded(MineRock mineRock) { lock (Sync) { if (TryResolveLazyDamageableScalars(((Component)mineRock).gameObject, LiveObjectComponentKind.MineRock, out CompiledDamageableScalarDefinition resolvedScalars, out int signature)) { ApplyLazyMineRockScalars(mineRock, resolvedScalars, signature); } } } internal static void ApplyLazyDestructibleScalarsIfNeeded(Destructible destructible) { lock (Sync) { if (TryResolveLazyDestructibleScalars(((Component)destructible).gameObject, out CompiledDestructibleComponentDefinition resolvedDefinition, out int signature)) { ApplyLazyDestructibleScalars(destructible, resolvedDefinition, signature); } } } internal static void ApplyLazyDestructibleTypeIfNeeded(Destructible destructible) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) lock (Sync) { if (TryResolveLazyDestructibleType(((Component)destructible).gameObject, out var resolvedType)) { ApplyDestructibleType(destructible, resolvedType); } } } internal static void ApplyLazyMineRock5ScalarsIfNeeded(MineRock5 mineRock5) { lock (Sync) { if (TryResolveLazyDamageableScalars(((Component)mineRock5).gameObject, LiveObjectComponentKind.MineRock5, out CompiledDamageableScalarDefinition resolvedScalars, out int signature)) { ApplyLazyMineRock5Scalars(mineRock5, resolvedScalars, signature); } } } internal static void ApplyLazyTreeBaseScalarsIfNeeded(TreeBase treeBase) { lock (Sync) { if (TryResolveLazyDamageableScalars(((Component)treeBase).gameObject, LiveObjectComponentKind.TreeBase, out CompiledDamageableScalarDefinition resolvedScalars, out int signature)) { ApplyLazyTreeBaseScalars(treeBase, resolvedScalars, signature); } } } internal static void ApplyLazyTreeLogScalarsIfNeeded(TreeLog treeLog) { lock (Sync) { if (TryResolveLazyDamageableScalars(((Component)treeLog).gameObject, LiveObjectComponentKind.TreeLog, out CompiledDamageableScalarDefinition resolvedScalars, out int signature)) { ApplyLazyTreeLogScalars(treeLog, resolvedScalars, signature); } } } private static bool TryGetCachedEventDropTable(GameObject gameObject, Func payloadSelector, Func snapshotSelector, LiveObjectComponentKind componentKind, out DropTable? overrideTable) { overrideTable = null; if (!TryGetConditionalContext(gameObject, out string prefabName, out PrefabSnapshot snapshot, out List entries)) { return false; } EnsureRuntimeDropConfigurationState(); if (!_runtimeDropConfigurationState.PlansByPrefab.TryGetValue(prefabName, out CompiledObjectPrefabPlan value) || value.Rules.Count == 0) { return false; } CachedEventDropTableState orCreateEventDropTableState = LazyRuntimeState.GetOrCreateEventDropTableState(gameObject, componentKind); DropTable snapshotTable = snapshotSelector(snapshot); if (orCreateEventDropTableState.Epoch != _reconcileQueueEpoch || !string.Equals(orCreateEventDropTableState.PrefabName, prefabName, StringComparison.Ordinal)) { orCreateEventDropTableState.Reset(_reconcileQueueEpoch, prefabName, snapshotTable); } if (!orCreateEventDropTableState.IsInitialized) { InitializeCachedEventDropTableState(orCreateEventDropTableState, value.Rules, payloadSelector); } if (!orCreateEventDropTableState.HasCustomBlock) { return false; } int num = ComputeCachedEventDropTableRuntimeSignature(gameObject, orCreateEventDropTableState); if (orCreateEventDropTableState.HasCachedResolution && orCreateEventDropTableState.LastRuntimeSignature == num) { overrideTable = orCreateEventDropTableState.LastResolvedDropTable; return orCreateEventDropTableState.LastHasOverride; } GroupConditionalApplyPlan plan = null; TryGetGroupConditionalApplyPlan(gameObject, snapshot, entries, out plan); bool flag = TryBuildEffectiveDropTable(gameObject, prefabName, orCreateEventDropTableState.RelevantRules, payloadSelector, orCreateEventDropTableState.SnapshotTable, componentKind, allowConditionalMatches: true, plan, out overrideTable); orCreateEventDropTableState.LastRuntimeSignature = num; orCreateEventDropTableState.HasCachedResolution = true; orCreateEventDropTableState.LastHasOverride = flag; orCreateEventDropTableState.LastResolvedDropTable = overrideTable; return flag; } private static void InitializeCachedEventDropTableState(CachedEventDropTableState cacheState, IEnumerable compiledRules, Func payloadSelector) { List list = new List(); HashSet destination = null; HashSet destination2 = null; foreach (CompiledObjectDropRule compiledRule in compiledRules) { if (payloadSelector(compiledRule) != null) { cacheState.HasCustomBlock = true; list.Add(compiledRule); ConditionsDefinition conditions = compiledRule.Entry.Conditions; if (DropConditionEvaluator.HasDynamicConditions(conditions)) { cacheState.UsesTimeOfDay |= conditions?.TimeOfDay != null; cacheState.UsesRequiredEnvironments |= HasConfiguredConditionValues(conditions?.RequiredEnvironments); cacheState.UsesInsidePlayerBase |= conditions?.InsidePlayerBase.HasValue ?? false; AddNormalizedConditionValues(conditions?.RequiredGlobalKeys, ref destination); AddNormalizedConditionValues(conditions?.ForbiddenGlobalKeys, ref destination2); } } } cacheState.RelevantRules = list.ToArray(); cacheState.RequiredGlobalKeys = destination?.ToArray() ?? Array.Empty(); cacheState.ForbiddenGlobalKeys = destination2?.ToArray() ?? Array.Empty(); cacheState.IsInitialized = true; } private static bool HasConfiguredConditionValues(IEnumerable? values) { if (values == null) { return false; } foreach (string value in values) { if (!string.IsNullOrWhiteSpace(value)) { return true; } } return false; } private static void AddNormalizedConditionValues(IEnumerable? values, ref HashSet? destination) { if (values == null) { return; } foreach (string value in values) { string text = (value ?? "").Trim(); if (text.Length != 0) { if (destination == null) { destination = new HashSet(StringComparer.Ordinal); } destination.Add(text); } } } private static int ComputeCachedEventDropTableRuntimeSignature(GameObject gameObject, CachedEventDropTableState cacheState) { if (!cacheState.UsesTimeOfDay && !cacheState.UsesRequiredEnvironments && !cacheState.UsesInsidePlayerBase && cacheState.RequiredGlobalKeys.Length == 0 && cacheState.ForbiddenGlobalKeys.Length == 0) { return 0; } EventDropRuntimeContextSnapshot orCreateEventDropRuntimeContextSnapshot = LazyRuntimeState.GetOrCreateEventDropRuntimeContextSnapshot(); int num = 17; if (cacheState.UsesTimeOfDay) { num = CombineCachedEventDropRuntimeSignature(num, orCreateEventDropRuntimeContextSnapshot.TimeOfDayPhaseMarker); } if (cacheState.UsesRequiredEnvironments) { num = CombineCachedEventDropRuntimeSignature(num, orCreateEventDropRuntimeContextSnapshot.EnvironmentName); } if (cacheState.UsesInsidePlayerBase) { num = CombineCachedEventDropRuntimeSignature(num, GetCachedEventInsidePlayerBaseState(gameObject, cacheState)); } string[] requiredGlobalKeys = cacheState.RequiredGlobalKeys; foreach (string text in requiredGlobalKeys) { num = CombineCachedEventDropRuntimeSignature(num, text); num = CombineCachedEventDropRuntimeSignature(num, GetCachedEventGlobalKeyState(orCreateEventDropRuntimeContextSnapshot, text)); } requiredGlobalKeys = cacheState.ForbiddenGlobalKeys; foreach (string text2 in requiredGlobalKeys) { num = CombineCachedEventDropRuntimeSignature(num, text2); num = CombineCachedEventDropRuntimeSignature(num, GetCachedEventGlobalKeyState(orCreateEventDropRuntimeContextSnapshot, text2)); } return num; } private static bool GetCachedEventInsidePlayerBaseState(GameObject gameObject, CachedEventDropTableState cacheState) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) float realtimeSinceStartup = Time.realtimeSinceStartup; if (realtimeSinceStartup - cacheState.LastInsidePlayerBaseSampleTime >= 0.5f) { cacheState.IsInsidePlayerBase = (Object)(object)EffectArea.IsPointInsideArea(gameObject.transform.position, (Type)4, 0f) != (Object)null; cacheState.LastInsidePlayerBaseSampleTime = realtimeSinceStartup; } return cacheState.IsInsidePlayerBase; } private static bool GetCachedEventGlobalKeyState(EventDropRuntimeContextSnapshot runtimeContext, string key) { if (runtimeContext.GlobalKeyStates.TryGetValue(key, out var value)) { return value; } value = (Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetGlobalKey(key); runtimeContext.GlobalKeyStates[key] = value; return value; } private static int CombineCachedEventDropRuntimeSignature(int current, bool value) { return current * 31 + (value ? 1 : 0); } private static int CombineCachedEventDropRuntimeSignature(int current, int value) { return current * 31 + value; } private static int CombineCachedEventDropRuntimeSignature(int current, string value) { return current * 31 + (value?.GetHashCode() ?? 0); } private static bool PickableItemRandomItemsEqual(IReadOnlyList currentItems, IReadOnlyList desiredItems) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) if (currentItems.Count != desiredItems.Count) { return false; } for (int i = 0; i < currentItems.Count; i++) { RandomItem val = currentItems[i]; RandomItem val2 = desiredItems[i]; if ((Object)(object)val.m_itemPrefab != (Object)(object)val2.m_itemPrefab || val.m_stackMin != val2.m_stackMin || val.m_stackMax != val2.m_stackMax) { return false; } } return true; } private static bool PickableItemRandomWeightsEqual(PickableItem pickableItem, IReadOnlyList desiredWeights) { if (!LazyRuntimeState.TryGetRandomState(pickableItem, out WeightedRandomPickableItemState state)) { return desiredWeights.Count == 0; } if (state.Weights.Length != desiredWeights.Count) { return false; } for (int i = 0; i < state.Weights.Length; i++) { if (!Mathf.Approximately(state.Weights[i], desiredWeights[i])) { return false; } } return true; } private static BuiltRandomPickableItems BuildRandomItems(List definitions, string context) { //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) List list = new List(); List list2 = new List(); foreach (RandomPickableItemDefinition definition in definitions) { if (string.IsNullOrWhiteSpace(definition.Item)) { WarnInvalidEntry("Entry '" + context + "' contains a randomDrops item without an item name."); continue; } float valueOrDefault = definition.Weight.GetValueOrDefault(1f); if (float.IsNaN(valueOrDefault) || float.IsInfinity(valueOrDefault) || valueOrDefault <= 0f) { WarnInvalidEntry($"Entry '{context}' contains a randomDrops item for '{definition.Item}' with invalid weight '{valueOrDefault}'. Weight must be greater than 0."); continue; } GameObject val = ResolveItemPrefab(definition.Item, context); if (!((Object)(object)val == (Object)null)) { list.Add(new RandomItem { m_itemPrefab = val.GetComponent(), m_stackMin = Math.Max(1, definition.StackMin.GetValueOrDefault(1)), m_stackMax = Math.Max(Math.Max(1, definition.StackMin.GetValueOrDefault(1)), definition.StackMax ?? definition.StackMin.GetValueOrDefault(1)) }); list2.Add(valueOrDefault); } } return new BuiltRandomPickableItems { Items = list.ToArray(), Weights = list2.ToArray() }; } private static void RestorePickableItem(PickableItem pickableItem, PickableItemSnapshot snapshot, bool updateRuntimeState) { ClearPickableItemRandomWeights(pickableItem); pickableItem.m_itemPrefab = (Object.op_Implicit((Object)(object)snapshot.ItemPrefab) ? snapshot.ItemPrefab.GetComponent() : null); pickableItem.m_stack = snapshot.Stack; pickableItem.m_randomItemPrefabs = snapshot.RandomItems.Select(delegate(PickableItemRandomSnapshot item) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) RandomItem result = default(RandomItem); result.m_itemPrefab = (Object.op_Implicit((Object)(object)item.ItemPrefab) ? item.ItemPrefab.GetComponent() : null); result.m_stackMin = item.StackMin; result.m_stackMax = item.StackMax; return result; }).ToArray(); if (updateRuntimeState) { UpdatePickableItemRuntimeState(pickableItem, pickableItem.m_randomItemPrefabs.Length != 0 && (Object)(object)pickableItem.m_itemPrefab == (Object)null, forceRandomRefresh: false); } } private static void SetPickableItemRandomWeights(PickableItem pickableItem, IReadOnlyList weights) { LazyRuntimeState.SetRandomWeights(pickableItem, weights.ToArray()); } private static void ClearPickableItemRandomWeights(PickableItem pickableItem) { LazyRuntimeState.ClearRandomState(pickableItem); } private static RandomItem SelectRandomPickableItem(PickableItem pickableItem) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) RandomItem[] randomItemPrefabs = pickableItem.m_randomItemPrefabs; if (randomItemPrefabs.Length == 0) { return default(RandomItem); } if (!LazyRuntimeState.TryGetRandomState(pickableItem, out WeightedRandomPickableItemState state) || state.Weights.Length != randomItemPrefabs.Length) { return randomItemPrefabs[Random.Range(0, randomItemPrefabs.Length)]; } float num = 0f; for (int i = 0; i < state.Weights.Length; i++) { num += Math.Max(0f, state.Weights[i]); } if (num <= 0f) { return randomItemPrefabs[Random.Range(0, randomItemPrefabs.Length)]; } float num2 = Random.Range(0f, num); float num3 = 0f; int num4 = 0; for (int j = 0; j < state.Weights.Length; j++) { float num5 = Math.Max(0f, state.Weights[j]); if (!(num5 <= 0f)) { num4 = j; num3 += num5; if (num2 <= num3) { return randomItemPrefabs[j]; } } } return randomItemPrefabs[num4]; } private static void UpdatePickableItemRuntimeState(PickableItem pickableItem, bool useRandomItems, bool forceRandomRefresh) { //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) ZNetView component = ((Component)pickableItem).GetComponent(); ZDO val = ((component != null) ? component.GetZDO() : null); if (useRandomItems && pickableItem.m_randomItemPrefabs.Length != 0) { bool flag = val != null && (Object)(object)component != (Object)null; bool flag2 = (Object)(object)component != (Object)null && component.IsOwner(); bool flag3 = val != null && val.GetInt(ZDOVars.s_itemPrefab, 0) != 0; if (forceRandomRefresh && val != null && flag2) { val.Set(ZDOVars.s_itemPrefab, 0, false); val.Set(ZDOVars.s_itemStack, 0, false); flag3 = false; } if (flag3) { int @int = val.GetInt(ZDOVars.s_itemPrefab, 0); ObjectDB instance = ObjectDB.instance; GameObject val2 = ((instance != null) ? instance.GetItemPrefab(@int) : null); ItemDrop val3 = (Object.op_Implicit((Object)(object)val2) ? val2.GetComponent() : null); if ((Object)(object)val3 != (Object)null) { pickableItem.m_itemPrefab = val3; pickableItem.m_stack = Math.Max(1, val.GetInt(ZDOVars.s_itemStack, Math.Max(1, pickableItem.m_stack))); } else { flag3 = false; } } if (!flag3 && flag && !flag2) { pickableItem.m_itemPrefab = null; pickableItem.m_stack = 1; RefreshPickableItemVisual(pickableItem); return; } if (!flag3) { RandomItem val4 = SelectRandomPickableItem(pickableItem); pickableItem.m_itemPrefab = val4.m_itemPrefab; if ((Object)(object)pickableItem.m_itemPrefab != (Object)null) { pickableItem.m_stack = ScalePickableItemStack(val4); ObjectDB instance2 = ObjectDB.instance; if (val != null && (Object)(object)component != (Object)null && component.IsOwner() && (Object)(object)instance2 != (Object)null) { int prefabHash = instance2.GetPrefabHash(((Component)pickableItem.m_itemPrefab).gameObject); val.Set(ZDOVars.s_itemPrefab, prefabHash, false); val.Set(ZDOVars.s_itemStack, Math.Max(1, pickableItem.m_stack), false); } } } } else if (val != null && (Object)(object)component != (Object)null && component.IsOwner()) { if ((Object)(object)pickableItem.m_itemPrefab != (Object)null) { ObjectDB instance3 = ObjectDB.instance; if ((Object)(object)instance3 == (Object)null) { RefreshPickableItemVisual(pickableItem); return; } int prefabHash2 = instance3.GetPrefabHash(((Component)pickableItem.m_itemPrefab).gameObject); val.Set(ZDOVars.s_itemPrefab, prefabHash2, false); val.Set(ZDOVars.s_itemStack, Math.Max(1, pickableItem.m_stack), false); } else { val.Set(ZDOVars.s_itemPrefab, 0, false); val.Set(ZDOVars.s_itemStack, 0, false); } } RefreshPickableItemVisual(pickableItem); } private static int ScalePickableItemStack(RandomItem randomItem) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) int num = Math.Max(1, randomItem.m_stackMin); int num2 = Math.Max(num, randomItem.m_stackMax); if ((Object)(object)randomItem.m_itemPrefab == (Object)null) { return num; } if ((Object)(object)Game.instance != (Object)null) { return Game.instance.ScaleDrops(randomItem.m_itemPrefab.m_itemData, num, num2 + 1); } return Random.Range(num, num2 + 1); } private static void RefreshPickableItemVisual(PickableItem pickableItem) { if (!(PickableItemSetupItemMethod == null)) { PickableItemSetupItemMethod.Invoke(pickableItem, new object[1] { false }); PickableItemSetupItemMethod.Invoke(pickableItem, new object[1] { true }); } } internal static void TrackObjectInstance(GameObject? gameObject) { lock (Sync) { TryTrackLiveObjectInstanceLocked(gameObject, out string _); } } internal static void UntrackObjectInstance(GameObject? gameObject) { lock (Sync) { UntrackLiveObjectInstanceLocked(gameObject); } } private static IEnumerable GetRegisteredLiveObjects() { EnsureLiveObjectRegistrySessionLocked(); HashSet hashSet = SnapshotPrefabsRequiringLiveTracking(); BootstrapLiveObjectRegistryIfNeededLocked(hashSet); CleanupRegisteredLiveObjects(); return LiveRegistryState.EnumerateRegisteredLiveObjects(hashSet); } private static IEnumerable GetRegisteredLiveObjects(HashSet dirtyPrefabs) { EnsureLiveObjectRegistrySessionLocked(); HashSet hashSet = FilterPrefabsRequiringLiveTracking(dirtyPrefabs); BootstrapLiveObjectRegistryIfNeededLocked(hashSet); CleanupRegisteredLiveObjects(); return LiveRegistryState.EnumerateRegisteredLiveObjects(hashSet); } private static void EnsureLiveObjectRegistrySessionLocked() { int currentSceneInstanceId = (((Object)(object)ZNetScene.instance != (Object)null) ? ((Object)ZNetScene.instance).GetInstanceID() : 0); if (!LiveRegistryState.HasSceneSession(currentSceneInstanceId)) { LiveRegistryState.BeginSceneSession(currentSceneInstanceId); ClearLiveObjectConditionCaches(); } } private static void BootstrapLiveObjectRegistryIfNeededLocked(HashSet targetPrefabs) { if (targetPrefabs == null || targetPrefabs.Count == 0) { return; } HashSet missingPrefabs = LiveRegistryState.CollectUnbootstrappedTrackedPrefabs(targetPrefabs); if (missingPrefabs.Count == 0) { return; } VisitActiveLoadedSceneGameObjects(delegate(GameObject gameObject) { if (HasRelevantLiveObjectComponents(gameObject)) { string prefabName = GetPrefabName(gameObject); if (prefabName.Length != 0 && missingPrefabs.Contains(prefabName)) { RegisterLiveObject(gameObject, prefabName); } } }); LiveRegistryState.MarkTrackedPrefabsBootstrapped(missingPrefabs); } private static bool TryTrackLiveObjectInstanceLocked(GameObject? gameObject, out string prefabName) { EnsureLiveObjectRegistrySessionLocked(); prefabName = ""; if ((Object)(object)gameObject == (Object)null) { return false; } if (LiveRegistryState.TryGetTrackedPrefab(gameObject, out string prefabName2) && !string.IsNullOrWhiteSpace(prefabName2)) { prefabName = prefabName2; return true; } prefabName = GetPrefabName(gameObject); if (prefabName.Length == 0) { return false; } if (!RequiresLiveTrackingForPrefab(prefabName)) { return true; } RegisterLiveObject(gameObject, prefabName); return true; } private static void UntrackLiveObjectInstanceLocked(GameObject? gameObject) { if (!((Object)(object)gameObject == (Object)null)) { int instanceID = ((Object)gameObject).GetInstanceID(); RemovePendingObjectReconcileState(instanceID); RemovePendingObjectConditionPlanState(instanceID); if (LiveRegistryState.TryGetTrackedPrefab(gameObject, out string prefabName) && !string.IsNullOrWhiteSpace(prefabName)) { UnregisterLiveObject(gameObject, prefabName); } } } private static void RegisterLiveObject(GameObject gameObject, string prefabName) { if (!((Object)(object)gameObject == (Object)null) && prefabName.Length != 0 && RequiresLiveTrackingForPrefab(prefabName)) { LiveRegistryState.Register(gameObject, prefabName); } } private static void CleanupRegisteredLiveObjects() { List> list = new List>(); LiveRegistryState.CollectDeadObjects(list); if (list.Count == 0) { return; } foreach (var (gameObject, prefabName) in list) { UnregisterLiveObject(gameObject, prefabName); } } private static void UnregisterLiveObject(GameObject gameObject, string prefabName) { LiveRegistryState.Unregister(gameObject, prefabName); } private static bool HasRelevantLiveObjectComponents(GameObject gameObject) { if ((Object)(object)gameObject == (Object)null) { return false; } DropOnDestroyed val = default(DropOnDestroyed); if (gameObject.TryGetComponent(ref val)) { return true; } MineRock val2 = default(MineRock); if (gameObject.TryGetComponent(ref val2)) { return true; } MineRock5 val3 = default(MineRock5); if (gameObject.TryGetComponent(ref val3)) { return true; } TreeBase val4 = default(TreeBase); if (gameObject.TryGetComponent(ref val4)) { return true; } TreeLog val5 = default(TreeLog); if (gameObject.TryGetComponent(ref val5)) { return true; } Container val6 = default(Container); if (gameObject.TryGetComponent(ref val6)) { return true; } Pickable val7 = default(Pickable); if (gameObject.TryGetComponent(ref val7)) { return true; } PickableItem val8 = default(PickableItem); if (gameObject.TryGetComponent(ref val8)) { return true; } Fish val9 = default(Fish); if (gameObject.TryGetComponent(ref val9)) { return true; } Destructible val10 = default(Destructible); return gameObject.TryGetComponent(ref val10); } private static void VisitActiveLoadedSceneGameObjects(Action visitor) { SceneTraversalSupport.VisitActiveLoadedSceneGameObjects(visitor); } internal static void ReconcilePieceInstance(Piece piece, bool clearCreatorRestrictedContainerContents) { ReconcileObjectInstance(((Component)piece).gameObject, clearCreatorRestrictedContainerContents); } internal static void ReconcileObjectInstance(GameObject gameObject, bool clearCreatorRestrictedContainerContents) { lock (Sync) { ReconcileObjectInstanceCore(gameObject, clearCreatorRestrictedContainerContents); } } private static void ReconcileObjectInstanceCore(GameObject? gameObject, bool clearCreatorRestrictedContainerContents) { if (!TryTrackLiveObjectInstanceLocked(gameObject, out string prefabName) || !ShouldReconcileLocally(gameObject)) { return; } List value; bool flag = ActiveEntriesByPrefab.TryGetValue(prefabName, out value) && value.Count > 0; if (IsGameDataReady() && !DropNSpawnPlugin.IsGameDataRefreshDeferred(DropNSpawnPlugin.ReloadDomain.Object) && SnapshotsByPrefab.TryGetValue(prefabName, out PrefabSnapshot value2) && RequiresLiveReconcileForPrefab(prefabName)) { RestoreConfiguredComponents(gameObject, value2, CreateRestoreMask(value2), updateRuntimeState: true); if (PluginSettingsFacade.IsObjectDomainEnabled() && flag) { ReconcileConfiguredInstance(gameObject, value2, value, clearCreatorRestrictedContainerContents); } } } private static void ReconcileConfiguredInstance(GameObject gameObject, PrefabSnapshot snapshot, IEnumerable entries, bool clearCreatorRestrictedContainerContents) { List list = (entries as List) ?? entries.ToList(); TryGetGroupConditionalApplyPlan(gameObject, snapshot, list, out GroupConditionalApplyPlan plan); if (!ShouldApplyToInstance(gameObject)) { if (!clearCreatorRestrictedContainerContents) { return; } { foreach (PrefabConfigurationEntry item in list) { ClearContainerContentsIfNeeded(gameObject, item); } return; } } if (plan != null) { foreach (PrefabConfigurationEntry matchingEntry in plan.MatchingEntries) { ApplyConfiguredComponents(gameObject, snapshot, matchingEntry, updateRuntimeState: true, allowConditionalMatches: true); } } foreach (PrefabConfigurationEntry item2 in list) { if (plan == null || !plan.EligibleEntries.Contains(item2)) { ApplyConfiguredComponents(gameObject, snapshot, item2, updateRuntimeState: true, allowConditionalMatches: true); } } ApplyEffectiveDropTableOverrides(gameObject, snapshot, list, allowConditionalMatches: true, plan, includeEventOnlyKinds: false); } private static void RefreshConfiguredPrefabProfile(string prefabName) { PrefabProfileCatalogState.RefreshConfiguredPrefabProfile(ActiveEntriesByPrefab, prefabName); } private static void RefreshConfiguredPrefabProfiles(Dictionary> activeEntriesByPrefab, Dictionary configuredComponentKindsByPrefab, Dictionary reconcileComponentKindsByPrefab) { configuredComponentKindsByPrefab.Clear(); reconcileComponentKindsByPrefab.Clear(); foreach (string key in activeEntriesByPrefab.Keys) { RefreshConfiguredPrefabProfile(activeEntriesByPrefab, configuredComponentKindsByPrefab, key); RefreshReconcilePrefabProfile(activeEntriesByPrefab, reconcileComponentKindsByPrefab, key); } } private static void RefreshConfiguredPrefabProfile(Dictionary> activeEntriesByPrefab, Dictionary configuredComponentKindsByPrefab, string prefabName) { if (!activeEntriesByPrefab.TryGetValue(prefabName, out List value) || value.Count == 0) { configuredComponentKindsByPrefab.Remove(prefabName); return; } LiveObjectComponentKind liveObjectComponentKind = LiveObjectComponentKind.None; foreach (PrefabConfigurationEntry item in value) { liveObjectComponentKind |= GetConfiguredComponentKinds(item); } if (liveObjectComponentKind == LiveObjectComponentKind.None) { configuredComponentKindsByPrefab.Remove(prefabName); } else { configuredComponentKindsByPrefab[prefabName] = liveObjectComponentKind; } } private static void RefreshReconcilePrefabProfile(Dictionary> activeEntriesByPrefab, Dictionary reconcileComponentKindsByPrefab, string prefabName) { if (!activeEntriesByPrefab.TryGetValue(prefabName, out List value) || value.Count == 0) { reconcileComponentKindsByPrefab.Remove(prefabName); return; } LiveObjectComponentKind liveObjectComponentKind = LiveObjectComponentKind.None; foreach (PrefabConfigurationEntry item in value) { liveObjectComponentKind |= GetReconcileComponentKinds(item); } if (liveObjectComponentKind == LiveObjectComponentKind.None) { reconcileComponentKindsByPrefab.Remove(prefabName); } else { reconcileComponentKindsByPrefab[prefabName] = liveObjectComponentKind; } } private static LiveObjectComponentKind GetConfiguredComponentKinds(PrefabConfigurationEntry entry) { LiveObjectComponentKind liveObjectComponentKind = LiveObjectComponentKind.None; if (entry.DropOnDestroyed != null) { liveObjectComponentKind |= LiveObjectComponentKind.DropOnDestroyed; } if (entry.MineRock != null) { liveObjectComponentKind |= LiveObjectComponentKind.MineRock; } if (entry.MineRock5 != null) { liveObjectComponentKind |= LiveObjectComponentKind.MineRock5; } if (entry.TreeBase != null) { liveObjectComponentKind |= LiveObjectComponentKind.TreeBase; } if (entry.TreeLog != null) { liveObjectComponentKind |= LiveObjectComponentKind.TreeLog; } if (entry.Container != null) { liveObjectComponentKind |= LiveObjectComponentKind.Container; } if (entry.Pickable != null) { liveObjectComponentKind |= LiveObjectComponentKind.Pickable; } if (entry.PickableItem != null) { liveObjectComponentKind |= LiveObjectComponentKind.PickableItem; } if (entry.Fish != null) { liveObjectComponentKind |= LiveObjectComponentKind.Fish; } if (RequiresLiveReconcile(entry, entry.Destructible)) { liveObjectComponentKind |= LiveObjectComponentKind.Destructible; } return liveObjectComponentKind; } private static LiveObjectComponentKind GetReconcileComponentKinds(PrefabConfigurationEntry entry) { LiveObjectComponentKind liveObjectComponentKind = LiveObjectComponentKind.None; if (RequiresLiveReconcile(entry.DropOnDestroyed, LiveObjectComponentKind.DropOnDestroyed)) { liveObjectComponentKind |= LiveObjectComponentKind.DropOnDestroyed; } if (RequiresLiveReconcile(entry.MineRock, LiveObjectComponentKind.MineRock) && !CanUseLazyDamageableScalarFastPath(entry, LiveObjectComponentKind.MineRock)) { liveObjectComponentKind |= LiveObjectComponentKind.MineRock; } if (RequiresLiveReconcile(entry.MineRock5, LiveObjectComponentKind.MineRock5) && !CanUseLazyDamageableScalarFastPath(entry, LiveObjectComponentKind.MineRock5)) { liveObjectComponentKind |= LiveObjectComponentKind.MineRock5; } if (RequiresLiveReconcile(entry.TreeBase, LiveObjectComponentKind.TreeBase) && !CanUseLazyDamageableScalarFastPath(entry, LiveObjectComponentKind.TreeBase)) { liveObjectComponentKind |= LiveObjectComponentKind.TreeBase; } if (RequiresLiveReconcile(entry.TreeLog, LiveObjectComponentKind.TreeLog) && !CanUseLazyDamageableScalarFastPath(entry, LiveObjectComponentKind.TreeLog)) { liveObjectComponentKind |= LiveObjectComponentKind.TreeLog; } if (ContainerNeedsLiveMutation(entry)) { liveObjectComponentKind |= LiveObjectComponentKind.Container; } if (entry.Pickable != null) { liveObjectComponentKind |= LiveObjectComponentKind.Pickable; } if (entry.PickableItem != null) { liveObjectComponentKind |= LiveObjectComponentKind.PickableItem; } if (entry.Fish != null) { liveObjectComponentKind |= LiveObjectComponentKind.Fish; } if (RequiresLiveReconcile(entry, entry.Destructible)) { liveObjectComponentKind |= LiveObjectComponentKind.Destructible; } return liveObjectComponentKind; } private static bool RequiresLiveReconcileForPrefab(string prefabName) { return PrefabProfileCatalogState.RequiresLiveReconcile(prefabName); } private static bool RequiresLiveTrackingForPrefab(string prefabName) { return PrefabProfileCatalogState.RequiresLiveObjectTracking(prefabName); } private static bool RequiresLiveReconcileForPrefab(string prefabName, LiveObjectComponentKind componentKind) { return PrefabProfileCatalogState.RequiresLiveReconcile(prefabName, componentKind); } private static HashSet FilterPrefabsRequiringLiveReconcile(IEnumerable? prefabNames) { return PrefabProfileCatalogState.FilterPrefabsRequiringLiveReconcile(prefabNames); } private static HashSet FilterPrefabsRequiringLiveTracking(IEnumerable? prefabNames) { return PrefabProfileCatalogState.FilterPrefabsRequiringLiveTracking(prefabNames); } private static HashSet SnapshotPrefabsRequiringLiveTracking() { return PrefabProfileCatalogState.SnapshotPrefabsRequiringLiveTracking(); } private static void ReplaceComponentKinds(Dictionary target, Dictionary source) { target.Clear(); foreach (var (key, liveObjectComponentKind2) in source) { if (liveObjectComponentKind2 != 0) { target[key] = liveObjectComponentKind2; } } } internal static void QueueObjectInstanceReconcile(GameObject? gameObject, bool clearCreatorRestrictedContainerContents, LiveObjectComponentKind sourceKind) { lock (Sync) { if (!((Object)(object)gameObject == (Object)null) && ShouldReconcileLocally(gameObject)) { string prefabName = GetPrefabName(gameObject); if (prefabName.Length != 0 && ShouldQueueAwakeReconcileForPrefab(prefabName, sourceKind) && HasPotentialStaticMatchForComponent(gameObject, prefabName, sourceKind) && TryTrackLiveObjectInstanceLocked(gameObject, out prefabName)) { QueueTrackedObjectInstanceReconcileLocked(gameObject, prefabName, clearCreatorRestrictedContainerContents); } } } } internal static bool HasPendingReconcileWork() { lock (Sync) { return ReconcileQueueState.HasPendingWork(); } } internal static bool ProcessQueuedReconcileStep(float deadline) { lock (Sync) { return TryProcessNextQueuedReconcileItemLocked(deadline, highPriorityOnly: false); } } private static void DrainQueuedHighPriorityReconcilesLocked() { while (TryProcessNextQueuedReconcileItemLocked(float.MaxValue, highPriorityOnly: true)) { } } private static bool TryProcessNextQueuedReconcileItemLocked(float deadline, bool highPriorityOnly) { while (ReconcileQueueState.HasPendingGroups(highPriorityOnly)) { if (!highPriorityOnly && Time.realtimeSinceStartup >= deadline) { return false; } if (!IsGameDataReady() || DropNSpawnPlugin.IsGameDataRefreshDeferred(DropNSpawnPlugin.ReloadDomain.Object)) { return false; } if (!TryDequeuePendingObjectReconcileGroup(out var queuedGroup, highPriorityOnly) || !ReconcileQueueState.TryGetGroupState(queuedGroup.GroupKey, out PendingObjectReconcileGroupState groupState)) { continue; } groupState.IsQueued = false; if (queuedGroup.Epoch != _reconcileQueueEpoch) { continue; } while (groupState.Items.Count > 0) { if (!groupState.Items.TryDequeue(out var item)) { continue; } groupState.InstanceIds.Remove(item.InstanceId); bool clearCreatorRestrictedContainerContents; if ((Object)(object)item.GameObject == (Object)null) { ReconcileQueueState.RemovePendingState(item.InstanceId); } else if (ReconcileQueueState.TryTakeClearFlag(item.InstanceId, out clearCreatorRestrictedContainerContents)) { ReconcileObjectInstanceCore(item.GameObject, clearCreatorRestrictedContainerContents); if (groupState.Items.Count > 0) { EnqueueObjectReconcileGroup(queuedGroup.GroupKey, groupState); } else { ReconcileQueueState.RemoveGroup(queuedGroup.GroupKey); } return true; } } ReconcileQueueState.RemoveGroup(queuedGroup.GroupKey); } return false; } private static bool ShouldQueueAwakeReconcileForPrefab(string prefabName, LiveObjectComponentKind sourceKind) { if (prefabName.Length == 0) { return false; } if (sourceKind == LiveObjectComponentKind.Piece) { return RequiresLiveReconcileForPrefab(prefabName); } if (PrefabProfileCatalogState.TryGetReconcileKinds(prefabName, out var reconcileKinds)) { return (reconcileKinds & sourceKind) != 0; } return false; } private static string BuildObjectReconcileGroupKey(GameObject gameObject, string prefabName) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) Transform root = gameObject.transform.root; if ((Object)(object)root != (Object)null && (Object)(object)((Component)root).gameObject != (Object)null && (Object)(object)((Component)root).gameObject != (Object)(object)gameObject) { return $"root:{((Object)((Component)root).gameObject).GetInstanceID()}:{prefabName}"; } Vector2i zone = ZoneSystem.GetZone(gameObject.transform.position); return $"zone:{zone.x}:{zone.y}:{prefabName}"; } private static bool IsHighPriorityPrefab(string prefabName) { if (!PrefabProfileCatalogState.TryGetReconcileKinds(prefabName, out var reconcileKinds)) { return false; } LiveObjectComponentKind liveObjectComponentKind = LiveObjectComponentKind.Pickable | LiveObjectComponentKind.PickableItem | LiveObjectComponentKind.Fish; return (reconcileKinds & liveObjectComponentKind) != 0; } private static void PromoteQueuedReconcileGroupsLocked(LiveObjectComponentKind componentKinds) { foreach (var (groupKey, pendingObjectReconcileGroupState2) in ReconcileQueueState.EnumerateGroups()) { if (pendingObjectReconcileGroupState2.IsQueued && !pendingObjectReconcileGroupState2.HighPriority && (pendingObjectReconcileGroupState2.ComponentKinds & componentKinds) != 0) { pendingObjectReconcileGroupState2.HighPriority = true; ReconcileQueueState.EnqueueGroup(new PendingObjectReconcileGroup(groupKey, _reconcileQueueEpoch), highPriority: true); } } } private static void EnqueueObjectReconcileGroup(string groupKey, PendingObjectReconcileGroupState groupState) { if (!groupState.IsQueued) { groupState.IsQueued = true; PendingObjectReconcileGroup queuedGroup = new PendingObjectReconcileGroup(groupKey, _reconcileQueueEpoch); ReconcileQueueState.EnqueueGroup(queuedGroup, groupState.HighPriority); } } private static bool TryDequeuePendingObjectReconcileGroup(out PendingObjectReconcileGroup queuedGroup, bool highPriorityOnly = false) { return ReconcileQueueState.TryDequeueGroup(out queuedGroup, highPriorityOnly); } private static void QueueTrackedObjectInstanceReconcileLocked(GameObject gameObject, string prefabName, bool clearCreatorRestrictedContainerContents) { int instanceID = ((Object)gameObject).GetInstanceID(); if (!ReconcileQueueState.TryMergeOrAddClearFlag(instanceID, clearCreatorRestrictedContainerContents)) { string groupKey = BuildObjectReconcileGroupKey(gameObject, prefabName); PrefabProfileCatalogState.TryGetReconcileKinds(prefabName, out var reconcileKinds); PendingObjectReconcileGroupState orCreateGroup = ReconcileQueueState.GetOrCreateGroup(groupKey, reconcileKinds, IsHighPriorityPrefab(prefabName)); orCreateGroup.ClearCreatorRestrictedContainerContents |= clearCreatorRestrictedContainerContents; if (orCreateGroup.InstanceIds.Add(instanceID)) { orCreateGroup.Items.Enqueue(new PendingObjectReconcileItem(gameObject, instanceID)); EnqueueObjectReconcileGroup(groupKey, orCreateGroup); } } } private static void RemovePendingObjectReconcileState(int instanceId) { ReconcileQueueState.RemovePendingState(instanceId); } private static void ClearQueuedReconcileState() { _reconcileQueueEpoch++; ReconcileQueueState.Clear(); ClearLiveObjectConditionCaches(); } private static List> BuildConfigurationTemplate() { Dictionary locationBuckets = BuildLocationReferenceBuckets(); List> list = PrefabOutputSections.BuildSections(Snapshots.Select(BuildConfigurationEntry), (PrefabConfigurationEntry entry) => entry.Prefab, (PrefabConfigurationEntry entry) => ResolveObjectOwnerName(entry.Prefab, locationBuckets)); foreach (PrefabOwnerSection item in list) { item.Entries.Sort(CompareObjectEntriesForOutput); } return list; } private static List BuildReferenceEntries() { List list = (from entry in BuildConfigurationTemplate().SelectMany((PrefabOwnerSection section) => section.Entries) select new PrefabReferenceEntry { Prefab = entry.Prefab, DropOnDestroyed = entry.DropOnDestroyed, MineRock = entry.MineRock, MineRock5 = entry.MineRock5, TreeBase = entry.TreeBase, TreeLog = entry.TreeLog, Container = entry.Container, Destructible = entry.Destructible, Pickable = entry.Pickable, PickableItem = entry.PickableItem, Fish = entry.Fish }).ToList(); foreach (PrefabReferenceEntry item in BuildSupplementalLocationReferenceEntries(ReferenceRefreshSupport.ToNormalizedKeySet(list.Select((PrefabReferenceEntry entry) => entry.Prefab)))) { list.Add(item); } return list; } private static string BuildReferenceConfigurationTemplate() { return SerializeReferenceEntries(BuildReferenceEntries()); } private static string SerializeReferenceEntries(IEnumerable entries) { Dictionary locationBuckets = BuildLocationReferenceBuckets(); List> list = PrefabOutputSections.BuildSections(entries, (PrefabReferenceEntry entry) => entry.Prefab, (PrefabReferenceEntry entry) => ResolveObjectOwnerName(entry.Prefab, locationBuckets)); foreach (PrefabOwnerSection item in list) { item.Entries.Sort((PrefabReferenceEntry left, PrefabReferenceEntry right) => StringComparer.OrdinalIgnoreCase.Compare(left.Prefab, right.Prefab)); } return PrefabOutputSections.SerializeReferenceSections(list, Serializer); } private static void WriteReferenceConfigurationFile(string content, string logMessage) { Directory.CreateDirectory(DropNSpawnPlugin.YamlConfigDirectoryPath); GeneratedFileWriter.WriteAllTextIfChanged(ReferenceConfigurationPath, content); DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)logMessage); } private static string BuildLocationReferenceConfigurationTemplate() { return SerializeLocationReferenceEntries(BuildLocationReferenceEntries()); } private static List BuildLocationReferenceEntries() { return (from pair in BuildLocationReferenceBuckets().OrderBy, string>((KeyValuePair pair) => pair.Key, StringComparer.OrdinalIgnoreCase) select new ObjectLocationReferenceEntry { Prefab = pair.Key, Components = pair.Value.Components.ToList(), Locations = pair.Value.Locations.ToList() }).ToList(); } private static string SerializeLocationReferenceEntries(IEnumerable entries) { Dictionary locationBuckets = BuildLocationReferenceBuckets(); List> list = PrefabOutputSections.BuildSections(entries, (ObjectLocationReferenceEntry entry) => entry.Prefab, (ObjectLocationReferenceEntry entry) => ResolveObjectOwnerName(entry.Prefab, locationBuckets)); foreach (PrefabOwnerSection item in list) { item.Entries.Sort((ObjectLocationReferenceEntry left, ObjectLocationReferenceEntry right) => StringComparer.OrdinalIgnoreCase.Compare(left.Prefab, right.Prefab)); } return PrefabOutputSections.SerializeReferenceSections(list, Serializer); } private static string ResolveObjectOwnerName(string prefabName, Dictionary locationBuckets) { PrefabOwnerResolver.OwnerSnapshot snapshot = PrefabOwnerResolver.GetSnapshot(); string text = (prefabName ?? "").Trim(); if (text.Length > 0 && locationBuckets.TryGetValue(text, out LocationReferenceBucket value)) { List list = (from ownerName in value.Locations.Select(snapshot.GetOwnerName) where !string.Equals(ownerName, "Unknown / Untracked", StringComparison.OrdinalIgnoreCase) select ownerName).Distinct(StringComparer.OrdinalIgnoreCase).ToList(); if (list.Count == 1) { return list[0]; } if (list.Count > 1) { return "Unknown / Untracked"; } } return snapshot.GetOwnerName(text); } private static void WriteLocationReferenceConfigurationFile(string content) { Directory.CreateDirectory(DropNSpawnPlugin.YamlConfigDirectoryPath); GeneratedFileWriter.WriteAllTextIfChanged(LocationReferenceConfigurationPath, content); } private static void RestoreResourceComponents(GameObject gameObject, PrefabSnapshot snapshot, PrefabConfigurationEntry entry, bool updateRuntimeState) { //IL_00de: Unknown result type (might be due to invalid IL or missing references) Destructible val = default(Destructible); if (HasDestructibleOverride(entry.Destructible) && gameObject.TryGetComponent(ref val) && snapshot.Destructible != null) { if (HasDestructibleHealthOverride(entry.Destructible)) { float? num = snapshot.Health?.Destructible; if (num.HasValue) { float valueOrDefault = num.GetValueOrDefault(); ApplyDestructibleHealth(val, valueOrDefault, updateRuntimeState); } } if (HasDestructibleMinToolTierOverride(entry.Destructible)) { int? num2 = snapshot.MinToolTier?.Destructible; if (num2.HasValue) { int valueOrDefault2 = num2.GetValueOrDefault(); ApplyDestructibleMinToolTier(val, valueOrDefault2); } } if (HasDestructibleComponentStateOverride(entry.Destructible)) { if (!string.IsNullOrWhiteSpace(entry.Destructible?.DestructibleType)) { ApplyDestructibleType(val, snapshot.Destructible.DestructibleType); } if (!updateRuntimeState && HasDestructibleSpawnWhenDestroyedOverride(entry.Destructible)) { val.m_spawnWhenDestroyed = snapshot.Destructible.SpawnWhenDestroyed; } } } DropOnDestroyed val2 = default(DropOnDestroyed); if (UsesLiveDropTableReconcile(LiveObjectComponentKind.DropOnDestroyed) && HasDropTableOverride(entry.DropOnDestroyed) && gameObject.TryGetComponent(ref val2) && snapshot.DropOnDestroyed != null) { val2.m_dropWhenDestroyed = CloneDropTable(snapshot.DropOnDestroyed); } MineRock val3 = default(MineRock); if (HasDamageableOverride(entry.MineRock) && gameObject.TryGetComponent(ref val3)) { if (UsesLiveDropTableReconcile(LiveObjectComponentKind.MineRock) && HasDropTableOverride(entry.MineRock) && snapshot.MineRock != null) { val3.m_dropItems = CloneDropTable(snapshot.MineRock); } if (HasDamageableHealthOverride(entry.MineRock)) { float? num = snapshot.Health?.MineRock; if (num.HasValue) { float valueOrDefault3 = num.GetValueOrDefault(); ApplyMineRockHealth(val3, valueOrDefault3, updateRuntimeState); } } if (HasDamageableMinToolTierOverride(entry.MineRock)) { int? num2 = snapshot.MinToolTier?.MineRock; if (num2.HasValue) { int valueOrDefault4 = num2.GetValueOrDefault(); val3.m_minToolTier = valueOrDefault4; } } } MineRock5 val4 = default(MineRock5); if (HasDamageableOverride(entry.MineRock5) && gameObject.TryGetComponent(ref val4)) { if (UsesLiveDropTableReconcile(LiveObjectComponentKind.MineRock5) && HasDropTableOverride(entry.MineRock5) && snapshot.MineRock5 != null) { val4.m_dropItems = CloneDropTable(snapshot.MineRock5); } if (HasDamageableHealthOverride(entry.MineRock5)) { float? num = snapshot.Health?.MineRock5; if (num.HasValue) { float valueOrDefault5 = num.GetValueOrDefault(); ApplyMineRock5Health(val4, valueOrDefault5, updateRuntimeState); } } if (HasDamageableMinToolTierOverride(entry.MineRock5)) { int? num2 = snapshot.MinToolTier?.MineRock5; if (num2.HasValue) { int valueOrDefault6 = num2.GetValueOrDefault(); val4.m_minToolTier = valueOrDefault6; } } } TreeBase val5 = default(TreeBase); if (HasDamageableOverride(entry.TreeBase) && gameObject.TryGetComponent(ref val5)) { if (UsesLiveDropTableReconcile(LiveObjectComponentKind.TreeBase) && HasDropTableOverride(entry.TreeBase) && snapshot.TreeBase != null) { val5.m_dropWhenDestroyed = CloneDropTable(snapshot.TreeBase); } if (HasDamageableHealthOverride(entry.TreeBase)) { float? num = snapshot.Health?.TreeBase; if (num.HasValue) { float valueOrDefault7 = num.GetValueOrDefault(); ApplyTreeBaseHealth(val5, valueOrDefault7, updateRuntimeState); } } if (HasDamageableMinToolTierOverride(entry.TreeBase)) { int? num2 = snapshot.MinToolTier?.TreeBase; if (num2.HasValue) { int valueOrDefault8 = num2.GetValueOrDefault(); val5.m_minToolTier = valueOrDefault8; } } } TreeLog val6 = default(TreeLog); if (!HasDamageableOverride(entry.TreeLog) || !gameObject.TryGetComponent(ref val6)) { return; } if (UsesLiveDropTableReconcile(LiveObjectComponentKind.TreeLog) && HasDropTableOverride(entry.TreeLog) && snapshot.TreeLog != null) { val6.m_dropWhenDestroyed = CloneDropTable(snapshot.TreeLog); } if (HasDamageableHealthOverride(entry.TreeLog)) { float? num = snapshot.Health?.TreeLog; if (num.HasValue) { float valueOrDefault9 = num.GetValueOrDefault(); ApplyTreeLogHealth(val6, valueOrDefault9, updateRuntimeState); } } if (HasDamageableMinToolTierOverride(entry.TreeLog)) { int? num2 = snapshot.MinToolTier?.TreeLog; if (num2.HasValue) { int valueOrDefault10 = num2.GetValueOrDefault(); val6.m_minToolTier = valueOrDefault10; } } } private static void ApplyResourceComponents(GameObject gameObject, PrefabConfigurationEntry entry, CompiledObjectDropRule? compiledRule, string contextRoot, bool updateRuntimeState) { //IL_0150: Unknown result type (might be due to invalid IL or missing references) if (HasDestructibleOverride(entry.Destructible)) { Destructible val = default(Destructible); if (!gameObject.TryGetComponent(ref val)) { WarnMissingComponent(contextRoot + "/Destructible", "Destructible"); } else { float normalizedHealth; if (compiledRule != null && (compiledRule.Destructible?.HasHealthOverride).GetValueOrDefault()) { ApplyDestructibleHealth(val, compiledRule.Destructible.Health, updateRuntimeState); } else if (HasDestructibleHealthOverride(entry.Destructible) && TryGetConfiguredHealth(entry.Destructible.Health.Value, contextRoot + "/Destructible/Health", out normalizedHealth)) { ApplyDestructibleHealth(val, normalizedHealth, updateRuntimeState); } int normalizedMinToolTier; if (compiledRule != null && (compiledRule.Destructible?.HasMinToolTierOverride).GetValueOrDefault()) { ApplyDestructibleMinToolTier(val, compiledRule.Destructible.MinToolTier); } else if (HasDestructibleMinToolTierOverride(entry.Destructible) && TryGetConfiguredMinToolTier(entry.Destructible.MinToolTier.Value, contextRoot + "/Destructible/minToolTier", out normalizedMinToolTier)) { ApplyDestructibleMinToolTier(val, normalizedMinToolTier); } if (compiledRule?.Destructible != null) { if (compiledRule.Destructible.HasDestructibleTypeOverride) { ApplyDestructibleType(val, compiledRule.Destructible.DestructibleType); } if (!updateRuntimeState && compiledRule.Destructible.HasSpawnWhenDestroyedOverride) { val.m_spawnWhenDestroyed = compiledRule.Destructible.SpawnWhenDestroyed; } } else if (HasDestructibleComponentStateOverride(entry.Destructible)) { ApplyDestructibleDefinition(val, entry.Destructible, contextRoot + "/Destructible", !updateRuntimeState); } } } DropOnDestroyed val2 = default(DropOnDestroyed); if (HasDropTableOverride(entry.DropOnDestroyed) && !gameObject.TryGetComponent(ref val2)) { WarnMissingComponent(contextRoot + "/DropOnDestroyed", "DropOnDestroyed"); } if (HasDamageableOverride(entry.MineRock)) { MineRock val3 = default(MineRock); if (!gameObject.TryGetComponent(ref val3)) { WarnMissingComponent(contextRoot + "/MineRock", "MineRock"); } else { float normalizedHealth2; if (compiledRule != null && (compiledRule.MineRockScalars?.HasHealthOverride).GetValueOrDefault()) { ApplyMineRockHealth(val3, compiledRule.MineRockScalars.Health, updateRuntimeState); } else if (HasDamageableHealthOverride(entry.MineRock) && TryGetConfiguredHealth(entry.MineRock.Health.Value, contextRoot + "/MineRock/Health", out normalizedHealth2)) { ApplyMineRockHealth(val3, normalizedHealth2, updateRuntimeState); } int normalizedMinToolTier2; if (compiledRule != null && (compiledRule.MineRockScalars?.HasMinToolTierOverride).GetValueOrDefault()) { val3.m_minToolTier = compiledRule.MineRockScalars.MinToolTier; } else if (HasDamageableMinToolTierOverride(entry.MineRock) && TryGetConfiguredMinToolTier(entry.MineRock.MinToolTier.Value, contextRoot + "/MineRock/minToolTier", out normalizedMinToolTier2)) { val3.m_minToolTier = normalizedMinToolTier2; } } } if (HasDamageableOverride(entry.MineRock5)) { MineRock5 val4 = default(MineRock5); if (!gameObject.TryGetComponent(ref val4)) { WarnMissingComponent(contextRoot + "/MineRock5", "MineRock5"); } else { float normalizedHealth3; if (compiledRule != null && (compiledRule.MineRock5Scalars?.HasHealthOverride).GetValueOrDefault()) { ApplyMineRock5Health(val4, compiledRule.MineRock5Scalars.Health, updateRuntimeState); } else if (HasDamageableHealthOverride(entry.MineRock5) && TryGetConfiguredHealth(entry.MineRock5.Health.Value, contextRoot + "/MineRock5/Health", out normalizedHealth3)) { ApplyMineRock5Health(val4, normalizedHealth3, updateRuntimeState); } int normalizedMinToolTier3; if (compiledRule != null && (compiledRule.MineRock5Scalars?.HasMinToolTierOverride).GetValueOrDefault()) { val4.m_minToolTier = compiledRule.MineRock5Scalars.MinToolTier; } else if (HasDamageableMinToolTierOverride(entry.MineRock5) && TryGetConfiguredMinToolTier(entry.MineRock5.MinToolTier.Value, contextRoot + "/MineRock5/minToolTier", out normalizedMinToolTier3)) { val4.m_minToolTier = normalizedMinToolTier3; } } } if (HasDamageableOverride(entry.TreeBase)) { TreeBase val5 = default(TreeBase); if (!gameObject.TryGetComponent(ref val5)) { WarnMissingComponent(contextRoot + "/TreeBase", "TreeBase"); } else { float normalizedHealth4; if (compiledRule != null && (compiledRule.TreeBaseScalars?.HasHealthOverride).GetValueOrDefault()) { ApplyTreeBaseHealth(val5, compiledRule.TreeBaseScalars.Health, updateRuntimeState); } else if (HasDamageableHealthOverride(entry.TreeBase) && TryGetConfiguredHealth(entry.TreeBase.Health.Value, contextRoot + "/TreeBase/Health", out normalizedHealth4)) { ApplyTreeBaseHealth(val5, normalizedHealth4, updateRuntimeState); } int normalizedMinToolTier4; if (compiledRule != null && (compiledRule.TreeBaseScalars?.HasMinToolTierOverride).GetValueOrDefault()) { val5.m_minToolTier = compiledRule.TreeBaseScalars.MinToolTier; } else if (HasDamageableMinToolTierOverride(entry.TreeBase) && TryGetConfiguredMinToolTier(entry.TreeBase.MinToolTier.Value, contextRoot + "/TreeBase/minToolTier", out normalizedMinToolTier4)) { val5.m_minToolTier = normalizedMinToolTier4; } } } if (!HasDamageableOverride(entry.TreeLog)) { return; } TreeLog val6 = default(TreeLog); if (!gameObject.TryGetComponent(ref val6)) { WarnMissingComponent(contextRoot + "/TreeLog", "TreeLog"); return; } float normalizedHealth5; if (compiledRule != null && (compiledRule.TreeLogScalars?.HasHealthOverride).GetValueOrDefault()) { ApplyTreeLogHealth(val6, compiledRule.TreeLogScalars.Health, updateRuntimeState); } else if (HasDamageableHealthOverride(entry.TreeLog) && TryGetConfiguredHealth(entry.TreeLog.Health.Value, contextRoot + "/TreeLog/Health", out normalizedHealth5)) { ApplyTreeLogHealth(val6, normalizedHealth5, updateRuntimeState); } int normalizedMinToolTier5; if (compiledRule != null && (compiledRule.TreeLogScalars?.HasMinToolTierOverride).GetValueOrDefault()) { val6.m_minToolTier = compiledRule.TreeLogScalars.MinToolTier; } else if (HasDamageableMinToolTierOverride(entry.TreeLog) && TryGetConfiguredMinToolTier(entry.TreeLog.MinToolTier.Value, contextRoot + "/TreeLog/minToolTier", out normalizedMinToolTier5)) { val6.m_minToolTier = normalizedMinToolTier5; } } private static string BuildFullScaffoldConfigurationTemplate() { StringBuilder stringBuilder = new StringBuilder(); bool flag = false; foreach (PrefabOwnerSection item in BuildConfigurationTemplate()) { foreach (PrefabConfigurationEntry entry in item.Entries) { if (flag) { AppendScaffoldBlankLine(stringBuilder); } AppendScaffoldObjectEntry(stringBuilder, entry); flag = true; } } if (!flag) { return "[]" + Environment.NewLine; } return stringBuilder.ToString(); } private static void AppendScaffoldObjectEntry(StringBuilder builder, PrefabConfigurationEntry entry) { AppendScaffoldListEntryLine(builder, 0, "prefab", entry.Prefab); AppendScaffoldLine(builder, 1, "enabled: " + FormatYamlBool(entry.Enabled)); AppendScaffoldConditionsBlock(builder, 1); if (entry.DropOnDestroyed != null) { AppendScaffoldDropTableBlock(builder, 1, "dropOnDestroyed", entry.DropOnDestroyed); } if (entry.MineRock != null) { AppendScaffoldDamageableDropTableBlock(builder, 1, "mineRock", entry.MineRock); } if (entry.MineRock5 != null) { AppendScaffoldDamageableDropTableBlock(builder, 1, "mineRock5", entry.MineRock5); } if (entry.TreeBase != null) { AppendScaffoldDamageableDropTableBlock(builder, 1, "treeBase", entry.TreeBase); } if (entry.TreeLog != null) { AppendScaffoldDamageableDropTableBlock(builder, 1, "treeLog", entry.TreeLog); } if (entry.Container != null) { AppendScaffoldDropTableBlock(builder, 1, "container", entry.Container); } if (entry.PickableItem != null) { AppendScaffoldPickableItemBlock(builder, entry.PickableItem); } if (entry.Pickable != null) { AppendScaffoldPickableBlock(builder, entry.Pickable); } if (entry.Fish != null) { AppendScaffoldFishBlock(builder, entry.Fish); } if (entry.Destructible != null) { AppendScaffoldDestructibleBlock(builder, entry.Destructible); } } private static void AppendScaffoldDamageableDropTableBlock(StringBuilder builder, int indent, string blockName, DamageableDropTableDefinition definition) { AppendScaffoldLine(builder, indent, blockName + ":"); AppendScaffoldLine(builder, indent + 1, "health: " + FormatYamlFloat(definition.Health.GetValueOrDefault(1f))); AppendScaffoldLine(builder, indent + 1, $"minToolTier: {definition.MinToolTier.GetValueOrDefault()}"); AppendScaffoldDropTableValueLines(builder, indent + 1, definition); } private static void AppendScaffoldDropTableBlock(StringBuilder builder, int indent, string blockName, DropTableDefinition definition) { AppendScaffoldLine(builder, indent, blockName + ":"); AppendScaffoldDropTableValueLines(builder, indent + 1, definition); } private static void AppendScaffoldDropTablePayloadBlock(StringBuilder builder, int indent, string blockName, DropTablePayloadDefinition definition) { AppendScaffoldLine(builder, indent, blockName + ":"); AppendScaffoldDropTableValueLines(builder, indent + 1, definition); } private static void AppendScaffoldDropTableValueLines(StringBuilder builder, int indent, DropTablePayloadDefinition definition) { AppendScaffoldLine(builder, indent, "rolls: " + RangeFormatting.FormatInlineObject(GetRollsRange(definition) ?? RangeFormatting.From(1, 1))); AppendScaffoldLine(builder, indent, "dropChance: " + FormatYamlFloat(definition.DropChance.GetValueOrDefault(1f))); AppendScaffoldLine(builder, indent, "oneOfEach: " + FormatYamlBool(definition.OneOfEach.GetValueOrDefault())); if (definition.Drops != null && definition.Drops.Count > 0) { AppendScaffoldLine(builder, indent, "drops:"); { foreach (DropEntryDefinition drop in definition.Drops) { AppendScaffoldDropEntry(builder, indent + 1, drop); } return; } } AppendScaffoldLine(builder, indent, "drops: []"); } private static void AppendScaffoldDropEntry(StringBuilder builder, int indent, DropEntryDefinition definition) { AppendScaffoldListEntryLine(builder, indent, "item", definition.Item); AppendScaffoldLine(builder, indent + 1, "stack: " + RangeFormatting.FormatInlineObject(GetStackRange(definition) ?? RangeFormatting.From(1, 1))); AppendScaffoldLine(builder, indent + 1, "weight: " + FormatYamlFloat(definition.Weight.GetValueOrDefault(1f))); AppendScaffoldLine(builder, indent + 1, "dontScale: " + FormatYamlBool(definition.DontScale.GetValueOrDefault())); } private static void AppendScaffoldDestructibleBlock(StringBuilder builder, DestructibleDefinition definition) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) AppendScaffoldLine(builder, 1, "destructible:"); AppendScaffoldLine(builder, 2, "health: " + FormatYamlFloat(definition.Health.GetValueOrDefault(1f))); AppendScaffoldLine(builder, 2, $"minToolTier: {definition.MinToolTier.GetValueOrDefault()}"); string? text = definition.DestructibleType; if (text == null) { DestructibleType val = (DestructibleType)1; text = ((object)(DestructibleType)(ref val)).ToString(); } AppendScaffoldLine(builder, 2, "destructibleType: " + FormatYamlString(text)); AppendScaffoldStringLine(builder, 2, "spawnWhenDestroyed", definition.SpawnWhenDestroyed); } private static void AppendScaffoldPickableBlock(StringBuilder builder, PickableDefinition definition) { AppendScaffoldLine(builder, 1, "pickable:"); AppendScaffoldStringLine(builder, 2, "overrideName", definition.OverrideName); AppendScaffoldLine(builder, 2, "drop:"); AppendScaffoldStringLine(builder, 3, "item", definition.Drop?.Item); AppendScaffoldLine(builder, 3, $"amount: {(definition.Drop?.Amount).GetValueOrDefault(1)}"); AppendScaffoldLine(builder, 3, $"minAmountScaled: {(definition.Drop?.MinAmountScaled).GetValueOrDefault()} # Minimum final amount after Game.ScaleDrops; ignored when dontScale is true."); AppendScaffoldLine(builder, 3, "dontScale: " + FormatYamlBool((definition.Drop?.DontScale).GetValueOrDefault())); AppendScaffoldDropTablePayloadBlock(builder, 2, "extraDrops", definition.ExtraDrops ?? new DropTablePayloadDefinition()); } private static void AppendScaffoldPickableItemBlock(StringBuilder builder, PickableItemDefinition definition) { AppendScaffoldLine(builder, 1, "pickableItem:"); if (definition.RandomDrops != null && definition.RandomDrops.Count > 0) { AppendScaffoldLine(builder, 2, "randomDrops:"); foreach (RandomPickableItemDefinition randomDrop in definition.RandomDrops) { AppendScaffoldListEntryLine(builder, 3, "item", randomDrop.Item); AppendScaffoldLine(builder, 4, "stack: " + RangeFormatting.FormatInlineObject(GetStackRange(randomDrop) ?? RangeFormatting.From(1, 1))); if (randomDrop.Weight.HasValue) { AppendScaffoldLine(builder, 4, "weight: " + FormatYamlFloat(randomDrop.Weight.Value)); } } } else { AppendScaffoldLine(builder, 2, "randomDrops: []"); } if (definition.Drop != null) { AppendScaffoldLine(builder, 2, "drop:"); AppendScaffoldStringLine(builder, 3, "item", definition.Drop.Item); AppendScaffoldLine(builder, 3, $"stack: {definition.Drop.Stack.GetValueOrDefault(1)}"); } else { AppendScaffoldLine(builder, 2, "drop:"); AppendScaffoldLine(builder, 3, "item: null"); AppendScaffoldLine(builder, 3, "stack: 1"); } } private static void AppendScaffoldFishBlock(StringBuilder builder, FishDefinition definition) { AppendScaffoldLine(builder, 1, "fish:"); AppendScaffoldDropTablePayloadBlock(builder, 2, "extraDrops", definition.ExtraDrops ?? new DropTablePayloadDefinition()); } private static void AppendScaffoldLine(StringBuilder builder, int indent, string text) { builder.Append(' ', indent * 2); builder.AppendLine(text); } private static void AppendScaffoldBlankLine(StringBuilder builder) { builder.AppendLine(); } private static void AppendScaffoldConditionsBlock(StringBuilder builder, int indent) { AppendScaffoldLine(builder, indent, "conditions:"); AppendScaffoldLine(builder, indent + 1, "altitude: null"); AppendScaffoldLine(builder, indent + 1, "distanceFromCenter: null"); AppendScaffoldLine(builder, indent + 1, "biomes: []"); AppendScaffoldLine(builder, indent + 1, "locations: []"); AppendScaffoldLine(builder, indent + 1, "timeOfDay: null"); AppendScaffoldLine(builder, indent + 1, "requiredEnvironments: []"); AppendScaffoldLine(builder, indent + 1, "requiredGlobalKeys: []"); AppendScaffoldLine(builder, indent + 1, "forbiddenGlobalKeys: []"); AppendScaffoldLine(builder, indent + 1, "inForest: null"); AppendScaffoldLine(builder, indent + 1, "inDungeon: null"); AppendScaffoldLine(builder, indent + 1, "insidePlayerBase: null"); } private static void AppendScaffoldStringLine(StringBuilder builder, int indent, string key, string? value) { if (value == null) { AppendScaffoldLine(builder, indent, key + ": null"); } else { AppendScaffoldLine(builder, indent, key + ": " + FormatYamlString(value)); } } private static void AppendScaffoldListEntryLine(StringBuilder builder, int indent, string key, string? value) { if (value == null) { AppendScaffoldLine(builder, indent, "- " + key + ": null"); } else { AppendScaffoldLine(builder, indent, "- " + key + ": " + FormatYamlString(value)); } } private static string BuildPrimaryOverrideConfigurationTemplate() { StringBuilder stringBuilder = new StringBuilder(); CommentedYamlTemplateSupport.AppendTemplateComment(stringBuilder, "Any file named " + PluginSettingsFacade.GetYamlDomainSupplementalPrefix("object") + "*.yml or " + PluginSettingsFacade.GetYamlDomainSupplementalPrefix("object") + "*.yaml is also loaded # ex) " + PluginSettingsFacade.GetYamlDomainFilePrefix("object") + "_rand1.yml, " + PluginSettingsFacade.GetYamlDomainFilePrefix("object") + "_rand2.yaml"); CommentedYamlTemplateSupport.AppendTemplateComment(stringBuilder, "Use " + PluginSettingsFacade.GetYamlDomainFilePrefix("object") + ".reference.yml to look up real prefab names and reference values, " + PluginSettingsFacade.GetYamlDomainFilePrefix("object") + ".locations.reference.yml to see which location roots include a given object prefab, and run `dns:full object` for exhaustive field examples"); CommentedYamlTemplateSupport.AppendTemplateComment(stringBuilder, "Matching drop-table component blocks merge together. If any block matches, vanilla rows for that component are replaced by the union of matching custom rows."); CommentedYamlTemplateSupport.AppendTemplateComment(stringBuilder, "A conditionless custom entry becomes the custom default for every populated component in that entry."); CommentedYamlTemplateSupport.AppendTemplateComment(stringBuilder, "Piece-based prefabs are world-only. Player-built instances are not overridden."); CommentedYamlTemplateSupport.AppendTemplateBlankLine(stringBuilder); CommentedYamlTemplateSupport.AppendTemplateComment(stringBuilder, "dropOnDestroyed"); CommentedYamlTemplateSupport.AppendTemplateBlankLine(stringBuilder); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 0, "- prefab: goblin_totempole"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 1, "enabled: true"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 1, "conditions: # If these conditions fail, this entry is ignored # Vanilla rows are used only when no custom drop-table entry for that component matches"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "altitude: null # ex) -1000~1000 # Range in world-height meters"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "distanceFromCenter: null # ex) 0~10000 # Range in meters from the world center"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "biomes: [] # ex) [BlackForest, Mistlands] # Allowed biomes # EWD custom biome names also work when EWD is installed"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "locations: [] # ex) [Hildir_camp] # Allowed location prefab names"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "timeOfDay: null # ex) [night] # [day, afternoon, night] # day contains afternoon"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "requiredEnvironments: [] # ex) [Rain] # Allowed environment names"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "requiredGlobalKeys: [] # ex) [defeated_gdking] # Required global keys"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "forbiddenGlobalKeys: [] # ex) [nomap] # Forbidden global keys"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "inForest: null # ex) true = forest only # false = outside forest only # null or no field allows both"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "inDungeon: null # ex) true = dungeon only # false = overworld only # null or no field allows both"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "insidePlayerBase: null # ex) true = near player base only # false = away from player base only # null or no field allows both"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 1, "dropOnDestroyed:"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "rolls: 1~1 # ex) 1~3 # Range of successful rolls from this table"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "dropChance: 1 # Chance from 0 to 1 that this table rolls at all"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "oneOfEach: false # True lets each entry roll at most once per table roll"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "drops: # Set drops: [] to disable a drop table"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "- item: null # ex) Wood # Required item prefab name"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 3, "stack: 1~1 # ex) 1~2 # Range of stack size"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 3, "weight: 1 # Relative weight versus other entries in the same table"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 3, "dontScale: false # True skips the game's built-in drop scaling for this entry"); CommentedYamlTemplateSupport.AppendTemplateBlankLine(stringBuilder); CommentedYamlTemplateSupport.AppendTemplateComment(stringBuilder, "mineRock, mineRock5, treeBase, and treeLog"); CommentedYamlTemplateSupport.AppendTemplateBlankLine(stringBuilder); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 0, "- prefab: MineRock_Copper"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 1, "enabled: true"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 1, "conditions: {}"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 1, "mineRock:"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "health: null # ex) 1000"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "minToolTier: 0 # ex) tier 0 AxeStone/PickaxeAntler, tier 1 AxeFlint/PickaxeBronze, tier 2 AxeBronze/PickaxeIron, tier 3 PickaxeBlackMetal, tier 4 AxeBlackMetal/AxeJotunBane, tier 5 BatteringRam, tier 6 AxeBerzerkr"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "rolls: 1~1"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "dropChance: 1"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "oneOfEach: false"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "drops:"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "- item: null # ex) Stone"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 3, "stack: 1~1 # ex) 1~3 # Range of stack size"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 3, "weight: 1"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 3, "dontScale: false"); CommentedYamlTemplateSupport.AppendTemplateBlankLine(stringBuilder); CommentedYamlTemplateSupport.AppendTemplateComment(stringBuilder, "container"); CommentedYamlTemplateSupport.AppendTemplateBlankLine(stringBuilder); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 0, "- prefab: TreasureChest_meadows"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 1, "enabled: true"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 1, "conditions: {}"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 1, "container:"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "rolls: 1~1"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "dropChance: 1"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "oneOfEach: false"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "drops:"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "- item: null # ex) Coins # Required item prefab name"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 3, "stack: 1~1 # ex) 10~20 # Range of stack size"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 3, "weight: 1"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 3, "dontScale: false"); CommentedYamlTemplateSupport.AppendTemplateBlankLine(stringBuilder); CommentedYamlTemplateSupport.AppendTemplateComment(stringBuilder, "pickableItem # Use either randomDrops or drop # If both are set, randomDrops takes precedence"); CommentedYamlTemplateSupport.AppendTemplateBlankLine(stringBuilder); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 0, "- prefab: Pickable_DolmenTreasure"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 1, "enabled: true"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 1, "conditions: {}"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 1, "pickableItem:"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "randomDrops:"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "- item: null # ex) Coins"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 3, "stack: 1~1 # ex) 1~3 # Range of stack size"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 3, "weight: 1"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "drop:"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 3, "item: null # ex) Coins"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 3, "stack: 1"); CommentedYamlTemplateSupport.AppendTemplateBlankLine(stringBuilder); CommentedYamlTemplateSupport.AppendTemplateComment(stringBuilder, "pickable"); CommentedYamlTemplateSupport.AppendTemplateBlankLine(stringBuilder); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 0, "- prefab: BlueberryBush"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 1, "enabled: true"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 1, "conditions: {}"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 1, "pickable:"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "overrideName: null # Optional display name override"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "drop:"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 3, "item: null # ex) Blueberries"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 3, "amount: 1"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 3, "minAmountScaled: 0 # Minimum final amount after Game.ScaleDrops # ignored when dontScale is true"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 3, "dontScale: false"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "extraDrops:"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 3, "rolls: 1~1"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 3, "dropChance: 1"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 3, "oneOfEach: false"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 3, "drops:"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 3, "- item: null # ex) Wood"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 4, "stack: 1~1 # ex) 1~3 # Range of stack size"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 4, "weight: 1"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 4, "dontScale: false"); CommentedYamlTemplateSupport.AppendTemplateBlankLine(stringBuilder); CommentedYamlTemplateSupport.AppendTemplateComment(stringBuilder, "fish"); CommentedYamlTemplateSupport.AppendTemplateBlankLine(stringBuilder); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 0, "- prefab: Fish2"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 1, "enabled: true"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 1, "conditions: {}"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 1, "fish:"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "extraDrops:"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 3, "rolls: 1~1"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 3, "dropChance: 1"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 3, "oneOfEach: false"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 3, "drops:"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 3, "- item: null # ex) Amber"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 4, "stack: 1~1 # ex) 1~3 # Range of stack size"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 4, "weight: 1"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 4, "dontScale: false"); CommentedYamlTemplateSupport.AppendTemplateBlankLine(stringBuilder); CommentedYamlTemplateSupport.AppendTemplateComment(stringBuilder, "destructible"); CommentedYamlTemplateSupport.AppendTemplateBlankLine(stringBuilder); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 0, "- prefab: CloudberryBush"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 1, "enabled: true"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 1, "conditions: {}"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 1, "destructible:"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "health: null # ex) 80"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "minToolTier: 0"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "destructibleType: Default # Values: None, Default, Tree, Character, Everything"); CommentedYamlTemplateSupport.AppendTemplateLine(stringBuilder, 2, "spawnWhenDestroyed: null # ex) Cloudberry # Optional direct spawn prefab"); CommentedYamlTemplateSupport.AppendTemplateBlankLine(stringBuilder); return stringBuilder.ToString(); } private static void AppendObjectTemplateEntry(StringBuilder builder, PrefabConfigurationEntry entry) { CommentedYamlTemplateSupport.AppendTemplateComment(builder, "----- " + entry.Prefab + " -----"); CommentedYamlTemplateSupport.AppendTemplateLine(builder, 0, "- prefab: " + entry.Prefab); CommentedYamlTemplateSupport.AppendTemplateLine(builder, 1, "enabled: " + FormatYamlBool(entry.Enabled)); AppendOptionalSharedConditions(builder, 1); if (entry.DropOnDestroyed != null) { AppendDropTableTemplateBlock(builder, 1, "dropOnDestroyed", entry.DropOnDestroyed); } if (entry.MineRock != null) { AppendDamageableDropTableTemplateBlock(builder, 1, "mineRock", entry.MineRock); } if (entry.MineRock5 != null) { AppendDamageableDropTableTemplateBlock(builder, 1, "mineRock5", entry.MineRock5); } if (entry.TreeBase != null) { AppendDamageableDropTableTemplateBlock(builder, 1, "treeBase", entry.TreeBase); } if (entry.TreeLog != null) { AppendDamageableDropTableTemplateBlock(builder, 1, "treeLog", entry.TreeLog); } if (entry.Container != null) { AppendDropTableTemplateBlock(builder, 1, "container", entry.Container); } if (entry.PickableItem != null) { AppendPickableItemTemplateBlock(builder, entry.PickableItem); } if (entry.Pickable != null) { AppendPickableTemplateBlock(builder, entry.Pickable); } if (entry.Fish != null) { AppendFishTemplateBlock(builder, entry.Fish); } if (entry.Destructible != null) { AppendDestructibleTemplateBlock(builder, entry.Destructible); } CommentedYamlTemplateSupport.AppendTemplateBlankLine(builder); } private static void AppendDamageableDropTableTemplateBlock(StringBuilder builder, int indent, string blockName, DamageableDropTableDefinition definition) { CommentedYamlTemplateSupport.AppendTemplateLine(builder, indent, blockName + ":"); CommentedYamlTemplateSupport.AppendTemplateLine(builder, indent + 1, "health: " + FormatYamlFloat(definition.Health.GetValueOrDefault(1f))); CommentedYamlTemplateSupport.AppendTemplateLine(builder, indent + 1, $"minToolTier: {definition.MinToolTier.GetValueOrDefault()}"); AppendDropTableValueLines(builder, indent + 1, definition); } private static void AppendDropTableTemplateBlock(StringBuilder builder, int indent, string blockName, DropTableDefinition definition) { CommentedYamlTemplateSupport.AppendTemplateLine(builder, indent, blockName + ":"); AppendDropTableValueLines(builder, indent + 1, definition); } private static void AppendDropTableValueLines(StringBuilder builder, int indent, DropTablePayloadDefinition definition) { CommentedYamlTemplateSupport.AppendTemplateLine(builder, indent, "rolls: " + RangeFormatting.FormatShorthand(GetRollsRange(definition) ?? RangeFormatting.From(1, 1))); CommentedYamlTemplateSupport.AppendTemplateLine(builder, indent, "dropChance: " + FormatYamlFloat(definition.DropChance.GetValueOrDefault(1f))); CommentedYamlTemplateSupport.AppendTemplateLine(builder, indent, "oneOfEach: " + FormatYamlBool(definition.OneOfEach.GetValueOrDefault())); CommentedYamlTemplateSupport.AppendTemplateLine(builder, indent, "drops:"); if (definition.Drops != null && definition.Drops.Count > 0) { foreach (DropEntryDefinition drop in definition.Drops) { AppendDropEntryTemplate(builder, indent, drop); } return; } AppendOptionalDropEntryTemplate(builder, indent); } private static void AppendDropEntryTemplate(StringBuilder builder, int indent, DropEntryDefinition definition) { CommentedYamlTemplateSupport.AppendTemplateLine(builder, indent, "- item: " + definition.Item); CommentedYamlTemplateSupport.AppendTemplateLine(builder, indent + 1, "stack: " + RangeFormatting.FormatShorthand(GetStackRange(definition) ?? RangeFormatting.From(1, 1))); CommentedYamlTemplateSupport.AppendTemplateLine(builder, indent + 1, "weight: " + FormatYamlFloat(definition.Weight.GetValueOrDefault(1f))); CommentedYamlTemplateSupport.AppendTemplateLine(builder, indent + 1, "dontScale: " + FormatYamlBool(definition.DontScale.GetValueOrDefault())); } private static void AppendOptionalDropEntryTemplate(StringBuilder builder, int indent) { CommentedYamlTemplateSupport.AppendTemplateNestedLine(builder, indent, "- item: Wood"); CommentedYamlTemplateSupport.AppendTemplateNestedLine(builder, indent + 1, "stack: 1~3"); CommentedYamlTemplateSupport.AppendTemplateNestedLine(builder, indent + 1, "weight: 1"); CommentedYamlTemplateSupport.AppendTemplateNestedLine(builder, indent + 1, "dontScale: false"); } private static void AppendDestructibleTemplateBlock(StringBuilder builder, DestructibleDefinition definition) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) CommentedYamlTemplateSupport.AppendTemplateLine(builder, 1, "destructible:"); CommentedYamlTemplateSupport.AppendTemplateLine(builder, 2, "health: " + FormatYamlFloat(definition.Health.GetValueOrDefault(1f))); CommentedYamlTemplateSupport.AppendTemplateLine(builder, 2, $"minToolTier: {definition.MinToolTier.GetValueOrDefault()}"); string? text = definition.DestructibleType; if (text == null) { DestructibleType val = (DestructibleType)1; text = ((object)(DestructibleType)(ref val)).ToString(); } CommentedYamlTemplateSupport.AppendTemplateLine(builder, 2, "destructibleType: " + text); if (!string.IsNullOrWhiteSpace(definition.SpawnWhenDestroyed)) { CommentedYamlTemplateSupport.AppendTemplateLine(builder, 2, "spawnWhenDestroyed: " + definition.SpawnWhenDestroyed); } else { CommentedYamlTemplateSupport.AppendTemplateNestedLine(builder, 2, "spawnWhenDestroyed: Cloudberry"); } } private static void AppendPickableTemplateBlock(StringBuilder builder, PickableDefinition definition) { CommentedYamlTemplateSupport.AppendTemplateLine(builder, 1, "pickable:"); if (!string.IsNullOrWhiteSpace(definition.OverrideName)) { CommentedYamlTemplateSupport.AppendTemplateLine(builder, 2, "overrideName: " + definition.OverrideName); } else { CommentedYamlTemplateSupport.AppendTemplateNestedLine(builder, 2, "overrideName: Custom display name"); } CommentedYamlTemplateSupport.AppendTemplateLine(builder, 2, "drop:"); CommentedYamlTemplateSupport.AppendTemplateLine(builder, 3, "item: " + (definition.Drop?.Item ?? "Blueberries")); CommentedYamlTemplateSupport.AppendTemplateLine(builder, 3, $"amount: {definition.Drop?.Amount.GetValueOrDefault(1) ?? 1}"); CommentedYamlTemplateSupport.AppendTemplateLine(builder, 3, $"minAmountScaled: {definition.Drop?.MinAmountScaled.GetValueOrDefault() ?? 0} # Minimum final amount after Game.ScaleDrops; ignored when dontScale is true."); CommentedYamlTemplateSupport.AppendTemplateLine(builder, 3, "dontScale: " + FormatYamlBool((definition.Drop?.DontScale).GetValueOrDefault())); CommentedYamlTemplateSupport.AppendTemplateNestedLine(builder, 2, "extraDrops:"); CommentedYamlTemplateSupport.AppendTemplateNestedLine(builder, 3, "rolls: 1~3"); CommentedYamlTemplateSupport.AppendTemplateNestedLine(builder, 3, "dropChance: 1"); CommentedYamlTemplateSupport.AppendTemplateNestedLine(builder, 3, "oneOfEach: false"); CommentedYamlTemplateSupport.AppendTemplateNestedLine(builder, 3, "drops:"); AppendOptionalDropEntryTemplate(builder, 3); } private static void AppendPickableItemTemplateBlock(StringBuilder builder, PickableItemDefinition definition) { CommentedYamlTemplateSupport.AppendTemplateLine(builder, 1, "pickableItem:"); CommentedYamlTemplateSupport.AppendTemplateLine(builder, 2, "randomDrops:"); if (definition.RandomDrops != null && definition.RandomDrops.Count > 0) { foreach (RandomPickableItemDefinition randomDrop in definition.RandomDrops) { CommentedYamlTemplateSupport.AppendTemplateLine(builder, 2, "- item: " + randomDrop.Item); CommentedYamlTemplateSupport.AppendTemplateLine(builder, 3, "stack: " + RangeFormatting.FormatShorthand(GetStackRange(randomDrop) ?? RangeFormatting.From(1, 1))); if (randomDrop.Weight.HasValue) { CommentedYamlTemplateSupport.AppendTemplateLine(builder, 3, "weight: " + FormatYamlFloat(randomDrop.Weight.Value)); } } } else { CommentedYamlTemplateSupport.AppendTemplateNestedLine(builder, 2, "- item: Coins"); CommentedYamlTemplateSupport.AppendTemplateNestedLine(builder, 3, "stack: 1~3"); CommentedYamlTemplateSupport.AppendTemplateNestedLine(builder, 3, "weight: 1"); } CommentedYamlTemplateSupport.AppendTemplateLine(builder, 2, "drop:"); CommentedYamlTemplateSupport.AppendTemplateLine(builder, 3, "item: " + (definition.Drop?.Item ?? "Coins")); CommentedYamlTemplateSupport.AppendTemplateLine(builder, 3, $"stack: {(definition.Drop?.Stack).GetValueOrDefault(1)}"); } private static void AppendFishTemplateBlock(StringBuilder builder, FishDefinition definition) { CommentedYamlTemplateSupport.AppendTemplateLine(builder, 1, "fish:"); CommentedYamlTemplateSupport.AppendTemplateNestedLine(builder, 2, "extraDrops:"); CommentedYamlTemplateSupport.AppendTemplateNestedLine(builder, 3, "rolls: 1~3"); CommentedYamlTemplateSupport.AppendTemplateNestedLine(builder, 3, "dropChance: 1"); CommentedYamlTemplateSupport.AppendTemplateNestedLine(builder, 3, "oneOfEach: false"); CommentedYamlTemplateSupport.AppendTemplateNestedLine(builder, 3, "drops:"); AppendOptionalDropEntryTemplate(builder, 3); } private static void AppendOptionalSharedConditions(StringBuilder builder, int indent, bool nested = false) { AppendConditionTemplateLine(builder, indent, "conditions:", nested); AppendConditionTemplateLine(builder, indent + 1, "altitude: -1000~1000", nested); AppendConditionTemplateLine(builder, indent + 1, "distanceFromCenter: 0~10000", nested); AppendConditionTemplateLine(builder, indent + 1, "biomes: [BlackForest, Mistlands]", nested); AppendConditionTemplateLine(builder, indent + 1, "locations: [Hildir_camp]", nested); AppendConditionTemplateLine(builder, indent + 1, "timeOfDay: [night]", nested); AppendConditionTemplateLine(builder, indent + 1, "requiredEnvironments: [Rain]", nested); AppendConditionTemplateLine(builder, indent + 1, "requiredGlobalKeys: [defeated_gdking]", nested); AppendConditionTemplateLine(builder, indent + 1, "forbiddenGlobalKeys: [nomap]", nested); AppendConditionTemplateLine(builder, indent + 1, "inForest: true", nested); AppendConditionTemplateLine(builder, indent + 1, "inDungeon: false", nested); AppendConditionTemplateLine(builder, indent + 1, "insidePlayerBase: false", nested); } private static void AppendConditionTemplateLine(StringBuilder builder, int indent, string text, bool nested) { CommentedYamlTemplateSupport.AppendTemplateNestedLine(builder, indent, text); } internal static bool HasVneiRelevantContainerOverride(string prefabName) { lock (Sync) { return HasRelevantVneiOverride(prefabName, (PrefabConfigurationEntry entry) => HasDropTableOverride(entry.Container)); } } internal static bool HasVneiRelevantDropOnDestroyedOverride(string prefabName) { lock (Sync) { return HasRelevantVneiOverride(prefabName, (PrefabConfigurationEntry entry) => HasDropTableOverride(entry.DropOnDestroyed)); } } internal static bool HasVneiRelevantMineRockOverride(string prefabName) { lock (Sync) { return HasRelevantVneiOverride(prefabName, (PrefabConfigurationEntry entry) => HasDropTableOverride(entry.MineRock)); } } internal static bool HasVneiRelevantMineRock5Override(string prefabName) { lock (Sync) { return HasRelevantVneiOverride(prefabName, (PrefabConfigurationEntry entry) => HasDropTableOverride(entry.MineRock5)); } } internal static bool HasVneiRelevantPickableOverride(string prefabName) { lock (Sync) { return HasRelevantVneiOverride(prefabName, (PrefabConfigurationEntry entry) => entry.Pickable != null && (HasPickableDropOverride(entry.Pickable.Drop) || HasDropTableOverride(entry.Pickable.ExtraDrops))); } } internal static bool HasVneiRelevantFishOverride(string prefabName) { lock (Sync) { return HasRelevantVneiOverride(prefabName, (PrefabConfigurationEntry entry) => HasDropTableOverride(entry.Fish?.ExtraDrops)); } } internal static bool HasVneiRelevantDestructibleOverride(string prefabName) { lock (Sync) { return HasRelevantVneiOverride(prefabName, (PrefabConfigurationEntry entry) => !string.IsNullOrWhiteSpace(entry.Destructible?.SpawnWhenDestroyed)); } } internal static bool HasVneiRelevantTreeBaseOverride(string prefabName) { lock (Sync) { return HasRelevantVneiOverride(prefabName, (PrefabConfigurationEntry entry) => HasDropTableOverride(entry.TreeBase) || HasDropTableOverride(entry.TreeLog) || HasDropTableOverride(entry.DropOnDestroyed)); } } internal static bool TryGetVneiDisplayForDropTable(GameObject prefab, DropTable dropTable, out List results) { lock (Sync) { results = new List(); if ((Object)(object)prefab == (Object)null || dropTable == null) { return false; } Container val = default(Container); if (prefab.TryGetComponent(ref val) && val.m_defaultItems == dropTable) { return TryGetVneiDisplayForContainer(prefab, out results); } DropOnDestroyed val2 = default(DropOnDestroyed); if (prefab.TryGetComponent(ref val2) && val2.m_dropWhenDestroyed == dropTable) { return TryGetVneiDropTableDisplay(prefab, (PrefabSnapshot snapshot) => snapshot.DropOnDestroyed, (PrefabConfigurationEntry entry) => entry.DropOnDestroyed, (DropTableDefinition payload) => payload, "dropOnDestroyed", 1, out results); } MineRock val3 = default(MineRock); if (prefab.TryGetComponent(ref val3) && val3.m_dropItems == dropTable) { return TryGetVneiDropTableDisplay(prefab, (PrefabSnapshot snapshot) => snapshot.MineRock, (PrefabConfigurationEntry entry) => entry.MineRock, (DamageableDropTableDefinition payload) => payload, "mineRock", 1, out results); } MineRock5 val4 = default(MineRock5); if (prefab.TryGetComponent(ref val4) && val4.m_dropItems == dropTable) { return TryGetVneiDropTableDisplay(prefab, (PrefabSnapshot snapshot) => snapshot.MineRock5, (PrefabConfigurationEntry entry) => entry.MineRock5, (DamageableDropTableDefinition payload) => payload, "mineRock5", 1, out results); } Fish val5 = default(Fish); if (prefab.TryGetComponent(ref val5) && val5.m_extraDrops == dropTable) { return TryGetVneiDisplayForFish(val5, out results); } return false; } } internal static bool TryGetVneiDisplayForContainer(GameObject prefab, out List results) { lock (Sync) { return TryGetVneiDropTableDisplay(prefab, (PrefabSnapshot snapshot) => snapshot.Container, (PrefabConfigurationEntry entry) => entry.Container, (DropTableDefinition payload) => payload, "container", 1, out results); } } internal static bool TryGetVneiDisplayForPickable(GameObject prefab, Pickable pickable, out List results) { lock (Sync) { results = new List(); if ((Object)(object)prefab == (Object)null || (Object)(object)pickable == (Object)null) { return false; } string prefabName = GetPrefabName(prefab); List vneiEntries = GetVneiEntries(prefabName); SnapshotsByPrefab.TryGetValue(prefabName, out PrefabSnapshot value); PickableSnapshot pickableSnapshot = value?.Pickable; bool flag = vneiEntries?.Any((PrefabConfigurationEntry entry) => entry.Pickable != null) ?? false; if (!flag && pickableSnapshot == null) { return false; } GameObject val = pickableSnapshot?.ItemPrefab; int num = Math.Max(1, pickableSnapshot?.Amount ?? 1); bool flag2 = false; HashSet seen = new HashSet(StringComparer.Ordinal); IEnumerable enumerable = vneiEntries; foreach (PrefabConfigurationEntry item in enumerable ?? Enumerable.Empty()) { PickableDefinition pickable2 = item.Pickable; if (pickable2 != null && !DropConditionEvaluator.HasConditions(item.Conditions) && HasPickableDropOverride(pickable2.Drop)) { GameObject val2 = ResolveItemPrefab(pickable2.Drop.Item, prefabName + "/pickable.drop"); if (!((Object)(object)val2 == (Object)null)) { flag2 = true; val = val2; num = Math.Max(1, pickable2.Drop.Amount.GetValueOrDefault(1)); } } } if ((Object)(object)val != (Object)null && (!flag2 || (Object)(object)val != (Object)null)) { AddUniqueVneiRow(results, seen, new VneiRecipeResult(((Object)val).name, 1, 1, 1f, num, num, 1f)); } enumerable = vneiEntries; foreach (PrefabConfigurationEntry item2 in enumerable ?? Enumerable.Empty()) { PickableDefinition pickable3 = item2.Pickable; if (pickable3 != null && DropConditionEvaluator.HasConditions(item2.Conditions) && HasPickableDropOverride(pickable3.Drop)) { GameObject val3 = ResolveItemPrefab(pickable3.Drop.Item, prefabName + "/pickable.drop"); if (!((Object)(object)val3 == (Object)null)) { int num2 = Math.Max(1, pickable3.Drop.Amount.GetValueOrDefault(1)); AddUniqueVneiRow(results, seen, new VneiRecipeResult(((Object)val3).name, 1, 1, 1f, num2, num2, 1f)); } } } if (TryGetVneiPickableExtraResults(prefab, value, vneiEntries, out List results2)) { foreach (VneiRecipeResult item3 in results2) { AddUniqueVneiRow(results, seen, item3); } } return flag || pickableSnapshot != null; } } internal static bool TryGetVneiDisplayForFish(Fish fish, out List results) { lock (Sync) { results = new List(); if ((Object)(object)fish == (Object)null || (Object)(object)((Component)fish).gameObject == (Object)null) { return false; } return TryGetVneiDropTableDisplay(((Component)fish).gameObject, (PrefabSnapshot snapshot) => snapshot.Fish?.ExtraDrops, (PrefabConfigurationEntry entry) => entry.Fish, (FishDefinition definition) => definition.ExtraDrops, "fish.extraDrops", 1, out results); } } internal static bool TryGetVneiDisplayForDestructible(Destructible destructible, out List results) { lock (Sync) { results = new List(); if ((Object)(object)destructible == (Object)null) { return false; } string prefabName = GetPrefabName(((Component)destructible).gameObject); List? vneiEntries = GetVneiEntries(prefabName); SnapshotsByPrefab.TryGetValue(prefabName, out PrefabSnapshot value); GameObject val = value?.Destructible?.SpawnWhenDestroyed; bool flag = false; bool flag2 = false; HashSet seen = new HashSet(StringComparer.Ordinal); IEnumerable enumerable = vneiEntries; foreach (PrefabConfigurationEntry item in enumerable ?? Enumerable.Empty()) { DestructibleDefinition destructible2 = item.Destructible; if (destructible2 == null) { continue; } string text = (destructible2.SpawnWhenDestroyed ?? "").Trim(); if (text.Length == 0) { continue; } flag = true; GameObject val2 = ResolvePrefab(text); if (!((Object)(object)val2 == (Object)null)) { if (DropConditionEvaluator.HasConditions(item.Conditions)) { AddUniqueVneiRow(results, seen, new VneiRecipeResult(((Object)val2).name, 1, 1, 1f, 1, 1, 1f)); continue; } flag2 = true; val = val2; } } if ((Object)(object)val != (Object)null) { AddUniqueVneiRow(results, seen, new VneiRecipeResult(((Object)val).name, 1, 1, 1f, 1, 1, 1f)); } else if (!flag2 && (Object)(object)value?.Destructible?.SpawnWhenDestroyed != (Object)null) { AddUniqueVneiRow(results, seen, new VneiRecipeResult(((Object)value.Destructible.SpawnWhenDestroyed).name, 1, 1, 1f, 1, 1, 1f)); } return flag || (Object)(object)value?.Destructible?.SpawnWhenDestroyed != (Object)null; } } internal static bool TryGetVneiDisplayForTreeBase(TreeBase treeBase, out List results) { lock (Sync) { results = new List(); if ((Object)(object)treeBase == (Object)null) { return false; } bool flag = false; HashSet seen = new HashSet(StringComparer.Ordinal); if (TryGetVneiDropTableDisplay(((Component)treeBase).gameObject, (PrefabSnapshot snapshot) => snapshot.TreeBase, (PrefabConfigurationEntry entry) => entry.TreeBase, (DamageableDropTableDefinition payload) => payload, "treeBase", 1, out List results2)) { flag = true; foreach (VneiRecipeResult item in results2) { AddUniqueVneiRow(results, seen, item); } } if ((Object)(object)treeBase.m_stubPrefab != (Object)null && TryGetVneiDropTableDisplay(treeBase.m_stubPrefab, (PrefabSnapshot snapshot) => snapshot.DropOnDestroyed, (PrefabConfigurationEntry entry) => entry.DropOnDestroyed, (DropTableDefinition payload) => payload, "treeBase.stub", 1, out List results3)) { flag = true; foreach (VneiRecipeResult item2 in results3) { AddUniqueVneiRow(results, seen, item2); } } return flag | AppendTreeLogVneiResults(treeBase.m_logPrefab, 1, 0, results, seen); } } private static bool AppendTreeLogVneiResults(GameObject? logPrefab, int treeCount, int depth, List results, HashSet seen) { TreeLog val = default(TreeLog); if ((Object)(object)logPrefab == (Object)null || depth > 50 || !logPrefab.TryGetComponent(ref val)) { return false; } bool flag = false; if (val.m_subLogPoints != null && val.m_subLogPoints.Length != 0) { flag |= AppendTreeLogVneiResults(val.m_subLogPrefab, Math.Max(1, val.m_subLogPoints.Length), depth + 1, results, seen); } if (TryGetVneiDropTableDisplay(logPrefab, (PrefabSnapshot snapshot) => snapshot.TreeLog, (PrefabConfigurationEntry entry) => entry.TreeLog, (DamageableDropTableDefinition payload) => payload, "treeLog", Math.Max(1, treeCount), out List results2)) { flag = true; foreach (VneiRecipeResult item in results2) { AddUniqueVneiRow(results, seen, item); } } return flag; } private static bool TryGetVneiPickableExtraResults(GameObject prefab, PrefabSnapshot? snapshot, List? entries, out List results) { PrefabSnapshot snapshot2 = snapshot; return TryGetVneiDropTableDisplay(prefab, (PrefabSnapshot _) => snapshot2?.Pickable?.ExtraDrops, (PrefabConfigurationEntry entry) => entry.Pickable, (PickableDefinition definition) => definition.ExtraDrops, "pickable.extraDrops", 1, out results); } private static bool TryGetVneiDropTableDisplay(GameObject prefab, Func snapshotSelector, Func blockSelector, Func payloadSelector, string contextSuffix, int groupMultiplier, out List results) where TBlock : class { results = new List(); if ((Object)(object)prefab == (Object)null) { return false; } string prefabName = GetPrefabName(prefab); List? vneiEntries = GetVneiEntries(prefabName); SnapshotsByPrefab.TryGetValue(prefabName, out PrefabSnapshot value); DropTable val = ((value != null) ? snapshotSelector(value) : null); bool flag = false; List list = new List(); List list2 = new List(); IEnumerable enumerable = vneiEntries; foreach (PrefabConfigurationEntry item in enumerable ?? Enumerable.Empty()) { TBlock val2 = blockSelector(item); if (val2 == null) { continue; } DropTablePayloadDefinition dropTablePayloadDefinition = payloadSelector(val2); if (HasDropTableOverride(dropTablePayloadDefinition)) { flag = true; if (DropConditionEvaluator.HasConditions(item.Conditions)) { list2.Add(dropTablePayloadDefinition); } else { list.Add(dropTablePayloadDefinition); } } } if (!flag && val == null) { return false; } DropTable val3 = ((list.Count > 0) ? BuildEffectiveDropTable(val, list, prefabName + "/" + contextSuffix) : ((val != null) ? CloneDropTable(val) : CreateDefaultDropTable())); List list3 = val3.m_drops.Select(CloneDropData).ToList(); HashSet seenFingerprints = new HashSet(list3.Select(BuildDropRowFingerprint), StringComparer.Ordinal); foreach (DropTablePayloadDefinition item2 in list2) { AppendDropTableRows(list3, item2.Drops, prefabName + "/" + contextSuffix, seenFingerprints); } results = BuildVneiResultsFromDropTable(val3, list3, groupMultiplier); if (!flag) { return val != null; } return true; } private static List BuildVneiResultsFromDropTable(DropTable table, List rows, int groupMultiplier) { //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) List list = new List(); if (table == null || rows == null || rows.Count == 0) { return list; } float num = rows.Sum((DropData row) => Mathf.Max(0f, row.m_weight)); int num2 = Math.Max(0, table.m_dropMin * Math.Max(1, groupMultiplier)); int groupMax = Math.Max(num2, table.m_dropMax * Math.Max(1, groupMultiplier)); float groupChance = Mathf.Clamp01(table.m_dropChance); foreach (DropData row in rows) { if (!((Object)(object)row.m_item == (Object)null)) { float chance = ((num <= 0f) ? 1f : Mathf.Clamp01(Mathf.Max(0f, row.m_weight) / num)); int num3 = Math.Max(1, row.m_stackMin); int max = Math.Max(num3, row.m_stackMax); list.Add(new VneiRecipeResult(((Object)row.m_item).name, num2, groupMax, groupChance, num3, max, chance)); } } return list; } private static DropData CloneDropData(DropData row) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) DropData result = default(DropData); result.m_item = row.m_item; result.m_stackMin = row.m_stackMin; result.m_stackMax = row.m_stackMax; result.m_weight = row.m_weight; result.m_dontScale = row.m_dontScale; return result; } private static string BuildDropRowFingerprint(DropData row) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) return BuildDropRowFingerprint(new DropEntryDefinition { Item = (((Object)(object)row.m_item != (Object)null) ? ((Object)row.m_item).name : ""), StackMin = row.m_stackMin, StackMax = row.m_stackMax, Weight = row.m_weight, DontScale = row.m_dontScale }); } private static void AddUniqueVneiRow(List results, HashSet seen, VneiRecipeResult row) { string item = string.Join("\n", row.PrefabName ?? "", row.GroupMin, row.GroupMax, row.GroupChance.ToString("R"), row.Min, row.Max, row.Chance.ToString("R")); if (seen.Add(item)) { results.Add(row); } } private static GameObject? ResolvePrefab(string prefabName) { string text = (prefabName ?? "").Trim(); if (text.Length == 0) { return null; } ZNetScene instance = ZNetScene.instance; object obj = ((instance != null) ? instance.GetPrefab(text) : null); if (obj == null) { ObjectDB instance2 = ObjectDB.instance; if (instance2 == null) { return null; } obj = instance2.GetItemPrefab(text); } return (GameObject?)obj; } private static bool HasRelevantVneiOverride(string prefabName, Func predicate) { return GetVneiEntries(prefabName ?? "")?.Any(predicate) ?? false; } } internal static class PrefabProvenanceRegistry { internal sealed class MappingSnapshot { internal Dictionary Owners { get; } internal string Signature { get; } internal MappingSnapshot(Dictionary owners, string signature) { Owners = owners ?? new Dictionary(StringComparer.OrdinalIgnoreCase); Signature = signature ?? ""; } } private enum ProviderKind { JotunnZoneManager, LocationManagerTemplate, CreatureManagerTemplate, JotunnCreatureManager, JotunnPrefabManager } private sealed class ProviderHandle { public ProviderKind Kind { get; set; } public Assembly Assembly { get; set; } public string AssemblyName { get; set; } = ""; public string OwnerName { get; set; } = ""; public Type? ManagerType { get; set; } public PropertyInfo? ManagerInstanceProperty { get; set; } public FieldInfo? ManagerCreaturesField { get; set; } public PropertyInfo? ManagerCreaturesProperty { get; set; } public FieldInfo? RegisteredCreaturesField { get; set; } public FieldInfo? RegisteredLocationsField { get; set; } public PropertyInfo? PrefabsProperty { get; set; } public FieldInfo? PrefabsField { get; set; } public PropertyInfo? LocationsProperty { get; set; } public FieldInfo? LocationsField { get; set; } } private readonly struct OwnerMapping { internal string OwnerName { get; } internal int Priority { get; } internal OwnerMapping(string ownerName, int priority) { OwnerName = ownerName; Priority = priority; } } private sealed class InternalMappingSnapshot { public Dictionary Owners { get; set; } = new Dictionary(StringComparer.OrdinalIgnoreCase); public string Signature { get; set; } = ""; } [StructLayout(LayoutKind.Auto)] [CompilerGenerated] private struct <>c__DisplayClass47_0 { public HashSet seen; } [CompilerGenerated] private sealed class d__27 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private ProviderHandle <>2__current; private int <>l__initialThreadId; private IEnumerable assemblies; public IEnumerable <>3__assemblies; private IEnumerator <>7__wrap1; ProviderHandle IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__27(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(); } } <>7__wrap1 = null; <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>7__wrap1 = assemblies.GetEnumerator(); <>1__state = -3; break; case 1: <>1__state = -3; break; } while (<>7__wrap1.MoveNext()) { Assembly current = <>7__wrap1.Current; Type type = SafeGetType(current, "CreatureManager.Creature"); if (!(type == null)) { FieldInfo fieldInfo = TryGetTypeField(type, "registeredCreatures"); if (!(fieldInfo == null)) { <>2__current = new ProviderHandle { Kind = ProviderKind.CreatureManagerTemplate, Assembly = current, AssemblyName = (current.GetName().Name ?? current.FullName ?? "Unknown / Untracked"), OwnerName = ResolveAssemblyOwnerName(current), RegisteredCreaturesField = fieldInfo }; <>1__state = 1; return true; } } } <>m__Finally1(); <>7__wrap1 = 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 (<>7__wrap1 != null) { <>7__wrap1.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__27 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__27(0); } d__.assemblies = <>3__assemblies; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__28 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private ProviderHandle <>2__current; private int <>l__initialThreadId; private IEnumerable assemblies; public IEnumerable <>3__assemblies; private IEnumerator <>7__wrap1; ProviderHandle IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__28(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(); } } <>7__wrap1 = null; <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>7__wrap1 = assemblies.GetEnumerator(); <>1__state = -3; break; case 1: <>1__state = -3; break; } while (<>7__wrap1.MoveNext()) { Assembly current = <>7__wrap1.Current; Type type = SafeGetType(current, "LocationManager.Location"); if (!(type == null)) { FieldInfo fieldInfo = TryGetTypeField(type, "registeredLocations"); if (!(fieldInfo == null)) { <>2__current = new ProviderHandle { Kind = ProviderKind.LocationManagerTemplate, Assembly = current, AssemblyName = (current.GetName().Name ?? current.FullName ?? "Unknown / Untracked"), OwnerName = ResolveAssemblyOwnerName(current), RegisteredLocationsField = fieldInfo }; <>1__state = 1; return true; } } } <>m__Finally1(); <>7__wrap1 = 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 (<>7__wrap1 != null) { <>7__wrap1.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__28 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__28(0); } d__.assemblies = <>3__assemblies; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__47 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private string <>2__current; private int <>l__initialThreadId; private string normalizedPrefabName; public string <>3__normalizedPrefabName; private HashSet.Enumerator <>7__wrap1; string IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__47(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(); } } <>7__wrap1 = default(HashSet.Enumerator); <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: { <>1__state = -1; <>c__DisplayClass47_0 <>c__DisplayClass47_ = default(<>c__DisplayClass47_0); <>c__DisplayClass47_.seen = new HashSet(StringComparer.OrdinalIgnoreCase); g__YieldIfNew|47_0(normalizedPrefabName, ref <>c__DisplayClass47_); string text = TrimCloneSuffix(normalizedPrefabName); g__YieldIfNew|47_0(text, ref <>c__DisplayClass47_); int num = text.IndexOf(':'); if (num > 0) { g__YieldIfNew|47_0(text.Substring(0, num), ref <>c__DisplayClass47_); } <>7__wrap1 = <>c__DisplayClass47_.seen.GetEnumerator(); <>1__state = -3; break; } case 1: <>1__state = -3; break; } if (<>7__wrap1.MoveNext()) { string current = <>7__wrap1.Current; <>2__current = current; <>1__state = 1; return true; } <>m__Finally1(); <>7__wrap1 = default(HashSet.Enumerator); 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; ((IDisposable)<>7__wrap1).Dispose(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__47 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__47(0); } d__.normalizedPrefabName = <>3__normalizedPrefabName; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } private static readonly object Sync = new object(); private static string _providerAssemblySignature = ""; private static List _providerCache = new List(); private static string _mappingSignature = ""; private static Dictionary _owners = new Dictionary(StringComparer.OrdinalIgnoreCase); private static MappingSnapshot _snapshot = new MappingSnapshot(new Dictionary(StringComparer.OrdinalIgnoreCase), ""); private static bool _mappingsDirty = true; private static bool _allowCacheLoad = true; internal static bool TryGetOwnerName(string? prefabName, out string ownerName) { ownerName = ""; string text = (prefabName ?? "").Trim(); if (text.Length == 0) { return false; } EnsureMappingsLoaded(); foreach (string item in EnumerateLookupCandidates(text)) { if (_owners.TryGetValue(item, out var value) && !string.IsNullOrWhiteSpace(value.OwnerName)) { ownerName = value.OwnerName; return true; } } return false; } internal static string GetOwnerNameOrFallback(string? prefabName) { return PrefabOwnerResolver.GetOwnerName(prefabName); } internal static void Invalidate() { lock (Sync) { _mappingSignature = ""; _owners = new Dictionary(StringComparer.OrdinalIgnoreCase); _snapshot = new MappingSnapshot(new Dictionary(StringComparer.OrdinalIgnoreCase), ""); _mappingsDirty = true; _allowCacheLoad = false; } } internal static MappingSnapshot GetSnapshot() { EnsureMappingsLoaded(); return _snapshot; } private static void EnsureMappingsLoaded() { if (!_mappingsDirty && _snapshot.Signature.Length > 0) { return; } lock (Sync) { if (!_mappingsDirty && _snapshot.Signature.Length > 0) { return; } Assembly[] array = (from assembly in AppDomain.CurrentDomain.GetAssemblies() where !assembly.IsDynamic select assembly).ToArray(); string text = ReferenceRefreshSupport.ComputeStableHashForKeys(array.Select((Assembly assembly) => assembly.FullName ?? assembly.GetName().Name ?? "")); if (_allowCacheLoad && TryLoadMappingsSnapshotFromCache(text, out InternalMappingSnapshot snapshot)) { _providerAssemblySignature = text; _owners = snapshot.Owners; _mappingSignature = snapshot.Signature; _snapshot = new MappingSnapshot(_owners.ToDictionary, string, string>((KeyValuePair pair) => pair.Key, (KeyValuePair pair) => pair.Value.OwnerName, StringComparer.OrdinalIgnoreCase), _mappingSignature); _mappingsDirty = false; return; } InternalMappingSnapshot internalMappingSnapshot = BuildMappingsSnapshot(GetProviders(array, text)); if (!string.Equals(internalMappingSnapshot.Signature, _mappingSignature, StringComparison.Ordinal)) { _owners = internalMappingSnapshot.Owners; _mappingSignature = internalMappingSnapshot.Signature; _snapshot = new MappingSnapshot(_owners.ToDictionary, string, string>((KeyValuePair pair) => pair.Key, (KeyValuePair pair) => pair.Value.OwnerName, StringComparer.OrdinalIgnoreCase), _mappingSignature); } SaveMappingsSnapshotToCache(text, internalMappingSnapshot); _mappingsDirty = false; _allowCacheLoad = true; } } private static string GetCachePath() { string text = Path.Combine(DropNSpawnPlugin.YamlConfigDirectoryPath, "cache"); Directory.CreateDirectory(text); return Path.Combine(text, ".prefab-owner-provenance-cache.txt"); } private static bool TryLoadMappingsSnapshotFromCache(string assemblySignature, out InternalMappingSnapshot snapshot) { snapshot = new InternalMappingSnapshot(); string cachePath = GetCachePath(); if (!File.Exists(cachePath)) { return false; } try { string[] array = File.ReadAllLines(cachePath); if (array.Length < 3 || !string.Equals(array[0], "v1", StringComparison.Ordinal)) { return false; } if (!string.Equals(array[1], assemblySignature, StringComparison.Ordinal)) { return false; } Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); for (int i = 3; i < array.Length; i++) { string text = array[i]; if (string.IsNullOrWhiteSpace(text)) { continue; } string[] array2 = text.Split('\t'); if (array2.Length >= 3) { string text2 = DecodeCacheField(array2[0]); string text3 = DecodeCacheField(array2[1]); if (int.TryParse(array2[2], out var result) && !string.IsNullOrWhiteSpace(text2) && !string.IsNullOrWhiteSpace(text3)) { dictionary[text2] = new OwnerMapping(text3, result); } } } snapshot = new InternalMappingSnapshot { Owners = dictionary, Signature = (array[2] ?? "") }; return snapshot.Signature.Length > 0; } catch { return false; } } private static void SaveMappingsSnapshotToCache(string assemblySignature, InternalMappingSnapshot snapshot) { if (string.IsNullOrWhiteSpace(assemblySignature) || string.IsNullOrWhiteSpace(snapshot.Signature)) { return; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("v1"); stringBuilder.AppendLine(assemblySignature); stringBuilder.AppendLine(snapshot.Signature); foreach (var (value, ownerMapping2) in snapshot.Owners.OrderBy, string>((KeyValuePair pair) => pair.Key, StringComparer.OrdinalIgnoreCase)) { stringBuilder.Append(EncodeCacheField(value)).Append('\t').Append(EncodeCacheField(ownerMapping2.OwnerName)) .Append('\t') .Append(ownerMapping2.Priority) .AppendLine(); } GeneratedFileWriter.WriteAllTextIfChanged(GetCachePath(), stringBuilder.ToString()); } private static string EncodeCacheField(string? value) { return Convert.ToBase64String(Encoding.UTF8.GetBytes(value ?? "")); } private static string DecodeCacheField(string? value) { if (string.IsNullOrWhiteSpace(value)) { return ""; } try { return Encoding.UTF8.GetString(Convert.FromBase64String(value)); } catch { return ""; } } private static List GetProviders(Assembly[] assemblies, string assemblySignature) { if (string.Equals(_providerAssemblySignature, assemblySignature, StringComparison.Ordinal)) { return _providerCache; } List list = new List(); ProviderHandle providerHandle = TryCreateJotunnZoneProvider(assemblies); if (providerHandle != null) { list.Add(providerHandle); } ProviderHandle providerHandle2 = TryCreateJotunnPrefabProvider(assemblies); if (providerHandle2 != null) { list.Add(providerHandle2); } ProviderHandle providerHandle3 = TryCreateJotunnCreatureProvider(assemblies); if (providerHandle3 != null) { list.Add(providerHandle3); } list.AddRange(CreateCreatureManagerTemplateProviders(assemblies)); list.AddRange(CreateLocationManagerTemplateProviders(assemblies)); list = list.OrderBy((ProviderHandle provider) => provider.Kind).ThenBy((ProviderHandle provider) => provider.OwnerName, StringComparer.OrdinalIgnoreCase).ThenBy((ProviderHandle provider) => provider.AssemblyName, StringComparer.OrdinalIgnoreCase) .ToList(); _providerAssemblySignature = assemblySignature; _providerCache = list; return _providerCache; } private static ProviderHandle? TryCreateJotunnZoneProvider(IEnumerable assemblies) { foreach (Assembly assembly in assemblies) { Type type = SafeGetType(assembly, "Jotunn.Managers.ZoneManager"); if (!(type == null)) { PropertyInfo propertyInfo = TryGetTypeProperty(type, "Instance"); PropertyInfo propertyInfo2 = TryGetTypeProperty(type, "Locations"); FieldInfo fieldInfo = TryGetTypeField(type, "Locations"); if (!(propertyInfo == null) && (!(propertyInfo2 == null) || !(fieldInfo == null))) { return new ProviderHandle { Kind = ProviderKind.JotunnZoneManager, Assembly = assembly, AssemblyName = (assembly.GetName().Name ?? assembly.FullName ?? "Jotunn"), OwnerName = ResolveAssemblyOwnerName(assembly), ManagerType = type, ManagerInstanceProperty = propertyInfo, LocationsProperty = propertyInfo2, LocationsField = fieldInfo }; } } } return null; } private static ProviderHandle? TryCreateJotunnPrefabProvider(IEnumerable assemblies) { foreach (Assembly assembly in assemblies) { Type type = SafeGetType(assembly, "Jotunn.Managers.PrefabManager"); if (!(type == null)) { PropertyInfo propertyInfo = TryGetTypeProperty(type, "Instance"); PropertyInfo propertyInfo2 = TryGetTypeProperty(type, "Prefabs"); FieldInfo fieldInfo = TryGetTypeField(type, "Prefabs"); if (!(propertyInfo == null) && (!(propertyInfo2 == null) || !(fieldInfo == null))) { return new ProviderHandle { Kind = ProviderKind.JotunnPrefabManager, Assembly = assembly, AssemblyName = (assembly.GetName().Name ?? assembly.FullName ?? "Jotunn"), OwnerName = ResolveAssemblyOwnerName(assembly), ManagerType = type, ManagerInstanceProperty = propertyInfo, PrefabsProperty = propertyInfo2, PrefabsField = fieldInfo }; } } } return null; } private static ProviderHandle? TryCreateJotunnCreatureProvider(IEnumerable assemblies) { foreach (Assembly assembly in assemblies) { Type type = SafeGetType(assembly, "Jotunn.Managers.CreatureManager"); if (!(type == null)) { PropertyInfo propertyInfo = TryGetTypeProperty(type, "Instance"); FieldInfo fieldInfo = TryGetTypeField(type, "Creatures"); PropertyInfo propertyInfo2 = TryGetTypeProperty(type, "Creatures"); if (!(propertyInfo == null) && (!(fieldInfo == null) || !(propertyInfo2 == null))) { return new ProviderHandle { Kind = ProviderKind.JotunnCreatureManager, Assembly = assembly, AssemblyName = (assembly.GetName().Name ?? assembly.FullName ?? "Jotunn"), OwnerName = ResolveAssemblyOwnerName(assembly), ManagerType = type, ManagerInstanceProperty = propertyInfo, ManagerCreaturesField = fieldInfo, ManagerCreaturesProperty = propertyInfo2 }; } } } return null; } [IteratorStateMachine(typeof(d__27))] private static IEnumerable CreateCreatureManagerTemplateProviders(IEnumerable assemblies) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__27(-2) { <>3__assemblies = assemblies }; } [IteratorStateMachine(typeof(d__28))] private static IEnumerable CreateLocationManagerTemplateProviders(IEnumerable assemblies) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__28(-2) { <>3__assemblies = assemblies }; } private static InternalMappingSnapshot BuildMappingsSnapshot(IEnumerable providers) { Dictionary owners = new Dictionary(StringComparer.OrdinalIgnoreCase); List list = new List(); foreach (ProviderHandle provider in providers) { switch (provider.Kind) { case ProviderKind.JotunnZoneManager: CollectJotunnLocationMappings(provider, owners, list); break; case ProviderKind.LocationManagerTemplate: CollectLocationManagerTemplateMappings(provider, owners, list); break; case ProviderKind.JotunnPrefabManager: CollectJotunnPrefabMappings(provider, owners, list); break; case ProviderKind.JotunnCreatureManager: CollectJotunnCreatureMappings(provider, owners, list); break; case ProviderKind.CreatureManagerTemplate: CollectCreatureManagerTemplateMappings(provider, owners, list); break; } } return new InternalMappingSnapshot { Owners = owners, Signature = ReferenceRefreshSupport.ComputeStableHashForKeys(list) }; } private static void CollectJotunnLocationMappings(ProviderHandle provider, Dictionary owners, List tokens) { object obj = provider.ManagerInstanceProperty?.GetValue(null, null); if (obj == null) { return; } object obj2 = provider.LocationsField?.GetValue(obj) ?? provider.LocationsProperty?.GetValue(obj, null); IEnumerable source; if (!(obj2 is IDictionary dictionary)) { source = GetEnumerable(obj2); } else { IEnumerable values = dictionary.Values; source = values; } foreach (object item in (from object entry in source where entry != null select (entry)).OrderBy((object entry) => GetPrefabNameFromHolder(entry) ?? "", StringComparer.OrdinalIgnoreCase)) { string prefabNameFromHolder = GetPrefabNameFromHolder(item); string text = ResolveOwnerNameFromSourceModHolder(item, provider.OwnerName); if (!string.IsNullOrWhiteSpace(prefabNameFromHolder) && !string.IsNullOrWhiteSpace(text)) { TryAddOwnerMapping(owners, prefabNameFromHolder, text, 0); tokens.Add("jl:" + prefabNameFromHolder + ":" + text); } } } private static void CollectJotunnPrefabMappings(ProviderHandle provider, Dictionary owners, List tokens) { object obj = provider.ManagerInstanceProperty?.GetValue(null, null); if (obj == null) { return; } object obj2 = provider.PrefabsField?.GetValue(obj) ?? provider.PrefabsProperty?.GetValue(obj, null); IEnumerable source; if (!(obj2 is IDictionary dictionary)) { source = GetEnumerable(obj2); } else { IEnumerable values = dictionary.Values; source = values; } foreach (object item in (from object entry in source where entry != null select (entry)).OrderBy((object entry) => GetPrefabNameFromHolder(entry) ?? "", StringComparer.OrdinalIgnoreCase)) { string prefabNameFromHolder = GetPrefabNameFromHolder(item); string text = ResolveOwnerNameFromSourceModHolder(item, provider.OwnerName); if (!string.IsNullOrWhiteSpace(prefabNameFromHolder) && !string.IsNullOrWhiteSpace(text)) { TryAddOwnerMapping(owners, prefabNameFromHolder, text, 2); tokens.Add("jp:" + prefabNameFromHolder + ":" + text); } } } private static void CollectJotunnCreatureMappings(ProviderHandle provider, Dictionary owners, List tokens) { object obj = provider.ManagerInstanceProperty?.GetValue(null, null); if (obj == null) { return; } foreach (object item in (from object entry in GetEnumerable(provider.ManagerCreaturesField?.GetValue(obj) ?? provider.ManagerCreaturesProperty?.GetValue(obj, null)) where entry != null select (entry)).OrderBy((object entry) => GetPrefabNameFromHolder(entry) ?? "", StringComparer.OrdinalIgnoreCase)) { string prefabNameFromHolder = GetPrefabNameFromHolder(item); string text = ResolveOwnerNameFromSourceModHolder(item, provider.OwnerName); if (!string.IsNullOrWhiteSpace(prefabNameFromHolder) && !string.IsNullOrWhiteSpace(text)) { TryAddOwnerMapping(owners, prefabNameFromHolder, text, 0); tokens.Add("jc:" + prefabNameFromHolder + ":" + text); } } } private static void CollectCreatureManagerTemplateMappings(ProviderHandle provider, Dictionary owners, List tokens) { foreach (object item in (from object entry in GetEnumerable(provider.RegisteredCreaturesField?.GetValue(null)) where entry != null select entry).OrderBy((object entry) => GetPrefabNameFromHolder(entry) ?? "", StringComparer.OrdinalIgnoreCase)) { string prefabNameFromHolder = GetPrefabNameFromHolder(item); if (!string.IsNullOrWhiteSpace(prefabNameFromHolder) && !string.IsNullOrWhiteSpace(provider.OwnerName)) { TryAddOwnerMapping(owners, prefabNameFromHolder, provider.OwnerName, 1); tokens.Add("cm:" + provider.OwnerName + ":" + prefabNameFromHolder); } } } private static void CollectLocationManagerTemplateMappings(ProviderHandle provider, Dictionary owners, List tokens) { foreach (object item in (from object entry in GetEnumerable(provider.RegisteredLocationsField?.GetValue(null)) where entry != null select entry).OrderBy((object entry) => GetPrefabNameFromHolder(entry) ?? "", StringComparer.OrdinalIgnoreCase)) { string prefabNameFromHolder = GetPrefabNameFromHolder(item); if (!string.IsNullOrWhiteSpace(prefabNameFromHolder) && !string.IsNullOrWhiteSpace(provider.OwnerName)) { TryAddOwnerMapping(owners, prefabNameFromHolder, provider.OwnerName, 1); tokens.Add("lm:" + provider.OwnerName + ":" + prefabNameFromHolder); } } } private static void TryAddOwnerMapping(Dictionary owners, string prefabName, string ownerName, int priority) { string text = (prefabName ?? "").Trim(); string text2 = (ownerName ?? "").Trim(); if (text.Length != 0 && text2.Length != 0 && (!owners.TryGetValue(text, out var value) || value.Priority > priority)) { owners[text] = new OwnerMapping(text2, priority); } } private static string? GetPrefabNameFromHolder(object? holder) { if (holder == null) { return null; } if (TryGetRawMemberValue(holder, "Prefab", out object value)) { GameObject val = (GameObject)((value is GameObject) ? value : null); if (val != null) { string text = (((Object)val).name ?? "").Trim(); if (text.Length > 0) { return text; } return GetPrefabNameFromLocationHolder(holder); } } return GetPrefabNameFromLocationHolder(holder); } private static string? GetPrefabNameFromLocationHolder(object holder) { if (TryGetLocationComponentHolderPrefabName(holder, "Location", out string prefabName) || TryGetLocationComponentHolderPrefabName(holder, "location", out prefabName)) { return prefabName; } if (TryGetRawMemberValue(holder, "ZoneLocation", out object value) && value != null && TryGetRawMemberValue(value, "m_prefabName", out object value2)) { string text = (value2?.ToString() ?? "").Trim(); if (text.Length > 0) { return text; } } return null; } private static bool TryGetLocationComponentHolderPrefabName(object holder, string memberName, out string? prefabName) { prefabName = null; if (!TryGetRawMemberValue(holder, memberName, out object value) || value == null) { return false; } GameObject val = (GameObject)((value is GameObject) ? value : null); if (val != null) { string text = (((Object)val).name ?? "").Trim(); if (text.Length == 0) { return false; } prefabName = text; return true; } Location val2 = (Location)((value is Location) ? value : null); if (val2 != null) { string text2 = (((Object)val2).name ?? "").Trim(); if (text2.Length == 0) { return false; } prefabName = text2; return true; } return false; } private static string ResolveOwnerNameFromSourceModHolder(object holder, string fallbackOwnerName) { if (TryGetRawMemberValue(holder, "SourceMod", out object value) && value != null && TryResolvePluginOwnerName(value, out string ownerName)) { return ownerName; } return fallbackOwnerName; } private static string ResolveAssemblyOwnerName(Assembly assembly) { foreach (PluginInfo value in Chainloader.PluginInfos.Values) { if ((object)((object)value.Instance)?.GetType().Assembly == assembly) { string text = (value.Metadata.Name ?? "").Trim(); if (text.Length > 0) { return text; } string text2 = (value.Metadata.GUID ?? "").Trim(); if (text2.Length > 0) { return text2; } } } string text3 = assembly.GetName().Name ?? assembly.FullName ?? ""; if (!string.IsNullOrWhiteSpace(text3)) { return text3; } return "Unknown / Untracked"; } private static bool TryResolvePluginOwnerName(object sourceMod, out string ownerName) { ownerName = ""; if (TryGetRawMemberValue(sourceMod, "GUID", out object value)) { string text = (value?.ToString() ?? "").Trim(); if (text.Length > 0 && Chainloader.PluginInfos.TryGetValue(text, out var value2)) { string text2 = (value2.Metadata.Name ?? "").Trim(); ownerName = ((text2.Length > 0) ? text2 : text); return true; } if (text.Length > 0) { ownerName = text; return true; } } if (TryGetRawMemberValue(sourceMod, "Name", out object value3)) { string text3 = (value3?.ToString() ?? "").Trim(); if (text3.Length > 0) { ownerName = text3; return true; } } return false; } private static IEnumerable GetEnumerable(object? value) { return (value as IEnumerable) ?? Array.Empty(); } private static bool TryGetRawMemberValue(object instance, string memberName, out object? value) { value = null; Type type = instance.GetType(); while (type != null) { PropertyInfo property = type.GetProperty(memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null) { try { value = property.GetValue(instance, null); return true; } catch { return false; } } FieldInfo field = type.GetField(memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { try { value = field.GetValue(instance); return true; } catch { return false; } } type = type.BaseType; } return false; } private static Type? SafeGetType(Assembly assembly, string fullTypeName) { try { return assembly.GetType(fullTypeName, throwOnError: false, ignoreCase: false); } catch { return null; } } private static PropertyInfo? TryGetTypeProperty(Type? type, string memberName) { string memberName2 = memberName; if (type == null || string.IsNullOrWhiteSpace(memberName2)) { return null; } Type type2 = type; while (type2 != null) { PropertyInfo propertyInfo = type2.GetProperty(memberName2, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) ?? type2.GetProperties(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((PropertyInfo candidate) => string.Equals(candidate.Name, memberName2, StringComparison.OrdinalIgnoreCase)); if (propertyInfo != null) { return propertyInfo; } type2 = type2.BaseType; } return null; } private static FieldInfo? TryGetTypeField(Type? type, string memberName) { string memberName2 = memberName; if (type == null || string.IsNullOrWhiteSpace(memberName2)) { return null; } Type type2 = type; while (type2 != null) { FieldInfo fieldInfo = type2.GetField(memberName2, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) ?? type2.GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((FieldInfo candidate) => string.Equals(candidate.Name, memberName2, StringComparison.OrdinalIgnoreCase)); if (fieldInfo != null) { return fieldInfo; } type2 = type2.BaseType; } return null; } [IteratorStateMachine(typeof(d__47))] private static IEnumerable EnumerateLookupCandidates(string normalizedPrefabName) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__47(-2) { <>3__normalizedPrefabName = normalizedPrefabName }; } private static string TrimCloneSuffix(string prefabName) { if (!prefabName.EndsWith("(Clone)", StringComparison.Ordinal)) { return prefabName; } int length = "(Clone)".Length; return prefabName.Substring(0, prefabName.Length - length).TrimEnd(); } [CompilerGenerated] internal static void g__YieldIfNew|47_0(string candidate, ref <>c__DisplayClass47_0 P_1) { if (!string.IsNullOrWhiteSpace(candidate)) { P_1.seen.Add(candidate.Trim()); } } } internal sealed class PrefabOwnerSection { internal string OwnerName { get; } internal List Entries { get; } internal PrefabOwnerSection(string ownerName, List entries) { OwnerName = (string.IsNullOrWhiteSpace(ownerName) ? "Unknown / Untracked" : ownerName.Trim()); Entries = entries ?? new List(); } } internal static class PrefabOutputSections { private sealed class GroupedEntry { public T Entry { get; set; } public string PrefabName { get; set; } = ""; public string OwnerName { get; set; } = "Unknown / Untracked"; } internal static List> BuildSections(IEnumerable entries, Func getPrefabName) { Func getPrefabName2 = getPrefabName; PrefabOwnerResolver.OwnerSnapshot snapshot = PrefabOwnerResolver.GetSnapshot(); return BuildSections(entries, getPrefabName2, (T entry) => snapshot.GetOwnerName(getPrefabName2(entry))); } internal static List> BuildSections(IEnumerable entries, Func getPrefabName, Func getOwnerName) { Func getPrefabName2 = getPrefabName; Func getOwnerName2 = getOwnerName; return (from @group in (from entry in entries.Select(delegate(T entry) { string prefabName = (getPrefabName2(entry) ?? "").Trim(); string text = (getOwnerName2(entry) ?? "").Trim(); return new GroupedEntry { Entry = entry, PrefabName = prefabName, OwnerName = ((text.Length > 0) ? text : "Unknown / Untracked") }; }) orderby GetOwnerSortBucket(entry.OwnerName) select entry).ThenBy, string>((GroupedEntry entry) => entry.OwnerName, StringComparer.OrdinalIgnoreCase).ThenBy, string>((GroupedEntry entry) => entry.PrefabName, StringComparer.OrdinalIgnoreCase).GroupBy, string>((GroupedEntry entry) => entry.OwnerName, StringComparer.OrdinalIgnoreCase) select new PrefabOwnerSection(@group.First().OwnerName, @group.Select((GroupedEntry entry) => entry.Entry).ToList())).ToList(); } internal static string SerializeReferenceSections(IEnumerable> sections, ISerializer serializer) { StringBuilder stringBuilder = new StringBuilder(); bool flag = false; foreach (PrefabOwnerSection section in sections) { if (section.Entries.Count == 0) { continue; } if (flag) { stringBuilder.AppendLine(); } AppendSectionHeaderComment(stringBuilder, section.OwnerName); foreach (T entry in section.Entries) { string value = CollapseScalarBlockListsToInlineLists(serializer.Serialize(new T[1] { entry }).TrimEnd('\r', '\n')); stringBuilder.AppendLine(value); } flag = true; } if (!flag) { return "[]" + Environment.NewLine; } return stringBuilder.ToString(); } internal static void AppendSectionHeaderComment(StringBuilder builder, string ownerName) { builder.Append("# ===== "); builder.Append(string.IsNullOrWhiteSpace(ownerName) ? "Unknown / Untracked" : ownerName.Trim()); builder.AppendLine(" ====="); } private static string CollapseScalarBlockListsToInlineLists(string yaml) { if (string.IsNullOrWhiteSpace(yaml) || yaml.IndexOf("- ", StringComparison.Ordinal) < 0) { return yaml; } string[] array = yaml.Replace("\r\n", "\n").Split('\n'); StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < array.Length; i++) { if (TryCollapseScalarBlockList(array, ref i, out string collapsedLine)) { stringBuilder.AppendLine(collapsedLine); } else { stringBuilder.AppendLine(array[i]); } } return stringBuilder.ToString().TrimEnd('\r', '\n'); } private static bool TryCollapseScalarBlockList(string[] lines, ref int index, out string collapsedLine) { collapsedLine = ""; string text = lines[index]; if (string.IsNullOrWhiteSpace(text)) { return false; } int firstNonWhitespaceIndex = GetFirstNonWhitespaceIndex(text); if (firstNonWhitespaceIndex < 0) { return false; } string text2 = text; int num = firstNonWhitespaceIndex; if (text2.Substring(num, text2.Length - num).StartsWith("-", StringComparison.Ordinal)) { return false; } int num2 = text.LastIndexOf(':'); if (num2 < 0 || num2 != text.Length - 1) { return false; } string text3 = text.Substring(0, firstNonWhitespaceIndex) + "- "; List list = new List(); int i; for (i = index + 1; i < lines.Length && lines[i].StartsWith(text3, StringComparison.Ordinal); i++) { text2 = lines[i]; num = text3.Length; string text4 = text2.Substring(num, text2.Length - num); if (!IsSimpleScalarYamlListItem(text4)) { return false; } if (i + 1 < lines.Length) { string text5 = lines[i + 1]; if (GetFirstNonWhitespaceIndex(text5) > firstNonWhitespaceIndex && !text5.StartsWith(text3, StringComparison.Ordinal)) { return false; } } list.Add(text4); } if (list.Count == 0) { return false; } collapsedLine = text + " [" + string.Join(", ", list) + "]"; index = i - 1; return true; } private static bool IsSimpleScalarYamlListItem(string itemValue) { if (string.IsNullOrWhiteSpace(itemValue)) { return false; } string text = itemValue.Trim(); if (text.EndsWith(":", StringComparison.Ordinal) || text.Contains(": ", StringComparison.Ordinal)) { return false; } return true; } private static int GetFirstNonWhitespaceIndex(string line) { for (int i = 0; i < line.Length; i++) { if (!char.IsWhiteSpace(line[i])) { return i; } } return -1; } private static int GetOwnerSortBucket(string ownerName) { if (string.Equals(ownerName, "Valheim", StringComparison.OrdinalIgnoreCase)) { return 0; } if (string.Equals(ownerName, "Unknown / Untracked", StringComparison.OrdinalIgnoreCase)) { return 2; } return 1; } } internal static class PrefabOwnerResolver { internal sealed class OwnerSnapshot { [StructLayout(LayoutKind.Auto)] [CompilerGenerated] private struct <>c__DisplayClass6_0 { public HashSet seen; } [CompilerGenerated] private sealed class d__6 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private string <>2__current; private int <>l__initialThreadId; private string normalizedPrefabName; public string <>3__normalizedPrefabName; private HashSet.Enumerator <>7__wrap1; string IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__6(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(); } } <>7__wrap1 = default(HashSet.Enumerator); <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: { <>1__state = -1; <>c__DisplayClass6_0 <>c__DisplayClass6_ = default(<>c__DisplayClass6_0); <>c__DisplayClass6_.seen = new HashSet(StringComparer.OrdinalIgnoreCase); g__AddIfNew|6_0(normalizedPrefabName, ref <>c__DisplayClass6_); string text = TrimCloneSuffix(normalizedPrefabName); g__AddIfNew|6_0(text, ref <>c__DisplayClass6_); int num = text.IndexOf(':'); if (num > 0) { g__AddIfNew|6_0(text.Substring(0, num), ref <>c__DisplayClass6_); } <>7__wrap1 = <>c__DisplayClass6_.seen.GetEnumerator(); <>1__state = -3; break; } case 1: <>1__state = -3; break; } if (<>7__wrap1.MoveNext()) { string current = <>7__wrap1.Current; <>2__current = current; <>1__state = 1; return true; } <>m__Finally1(); <>7__wrap1 = default(HashSet.Enumerator); 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; ((IDisposable)<>7__wrap1).Dispose(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__6 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__6(0); } d__.normalizedPrefabName = <>3__normalizedPrefabName; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } private readonly Dictionary _owners; internal string Signature { get; } internal OwnerSnapshot(Dictionary owners, string signature) { _owners = owners ?? new Dictionary(StringComparer.OrdinalIgnoreCase); Signature = signature ?? ""; } internal string GetOwnerName(string? prefabName) { string text = (prefabName ?? "").Trim(); if (text.Length == 0) { return "Unknown / Untracked"; } foreach (string item in EnumerateLookupCandidates(text)) { if (_owners.TryGetValue(item, out string value) && !string.IsNullOrWhiteSpace(value)) { return value; } } foreach (string item2 in EnumerateLookupCandidates(text)) { if (VanillaPrefabCatalog.IsAvailable && VanillaPrefabCatalog.IsVanilla(item2)) { return "Valheim"; } } foreach (string item3 in EnumerateLookupCandidates(text)) { if (PrefabOwnerCatalog.IsLikelyRuntimeVanillaPrefab(item3)) { return "Valheim"; } } return "Unknown / Untracked"; } [IteratorStateMachine(typeof(d__6))] private static IEnumerable EnumerateLookupCandidates(string normalizedPrefabName) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__6(-2) { <>3__normalizedPrefabName = normalizedPrefabName }; } private static string TrimCloneSuffix(string prefabName) { if (!prefabName.EndsWith("(Clone)", StringComparison.Ordinal)) { return prefabName; } int length = "(Clone)".Length; return prefabName.Substring(0, prefabName.Length - length).TrimEnd(); } [CompilerGenerated] internal static void g__AddIfNew|6_0(string candidate, ref <>c__DisplayClass6_0 P_1) { if (!string.IsNullOrWhiteSpace(candidate)) { P_1.seen.Add(candidate.Trim()); } } } private static readonly object Sync = new object(); private static string _snapshotSignature = ""; private static OwnerSnapshot _snapshot = new OwnerSnapshot(new Dictionary(StringComparer.OrdinalIgnoreCase), ""); internal static void Invalidate() { lock (Sync) { _snapshotSignature = ""; _snapshot = new OwnerSnapshot(new Dictionary(StringComparer.OrdinalIgnoreCase), ""); } PrefabProvenanceRegistry.Invalidate(); } internal static string GetOwnerName(string? prefabName) { return GetSnapshot().GetOwnerName(prefabName); } internal static OwnerSnapshot GetSnapshot() { PrefabProvenanceRegistry.MappingSnapshot snapshot = PrefabProvenanceRegistry.GetSnapshot(); PrefabOwnerCatalog.MappingSnapshot snapshot2 = PrefabOwnerCatalog.GetSnapshot(); string text = "provenance:" + snapshot.Signature + "|bundles:" + snapshot2.Signature; if (string.Equals(text, _snapshotSignature, StringComparison.Ordinal)) { return _snapshot; } lock (Sync) { if (string.Equals(text, _snapshotSignature, StringComparison.Ordinal)) { return _snapshot; } Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); string key; string value; foreach (KeyValuePair owner in snapshot2.Owners) { owner.Deconstruct(out key, out value); string text2 = key; string value2 = value; if (!string.IsNullOrWhiteSpace(text2) && !string.IsNullOrWhiteSpace(value2)) { dictionary[text2] = value2; } } foreach (KeyValuePair owner2 in snapshot.Owners) { owner2.Deconstruct(out value, out key); string text3 = value; string value3 = key; if (!string.IsNullOrWhiteSpace(text3) && !string.IsNullOrWhiteSpace(value3)) { dictionary[text3] = value3; } } _snapshot = new OwnerSnapshot(dictionary, text); _snapshotSignature = text; return _snapshot; } } } internal static class PrefabOwnerCatalog { internal sealed class MappingSnapshot { internal Dictionary Owners { get; } internal string Signature { get; } internal MappingSnapshot(Dictionary owners, string signature) { Owners = owners ?? new Dictionary(StringComparer.OrdinalIgnoreCase); Signature = signature ?? ""; } } private sealed class PluginResources { public string OwnerName { get; set; } = ""; public string[] ResourceNames { get; set; } = Array.Empty(); } [StructLayout(LayoutKind.Auto)] [CompilerGenerated] private struct <>c__DisplayClass38_0 { public HashSet seen; } [CompilerGenerated] private sealed class d__38 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private string <>2__current; private int <>l__initialThreadId; private string normalizedPrefabName; public string <>3__normalizedPrefabName; private HashSet.Enumerator <>7__wrap1; string IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__38(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(); } } <>7__wrap1 = default(HashSet.Enumerator); <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: { <>1__state = -1; <>c__DisplayClass38_0 <>c__DisplayClass38_ = default(<>c__DisplayClass38_0); <>c__DisplayClass38_.seen = new HashSet(StringComparer.OrdinalIgnoreCase); g__YieldIfNew|38_0(normalizedPrefabName, ref <>c__DisplayClass38_); string text = TrimCloneSuffix(normalizedPrefabName); g__YieldIfNew|38_0(text, ref <>c__DisplayClass38_); int num = text.IndexOf(':'); if (num > 0) { g__YieldIfNew|38_0(text.Substring(0, num), ref <>c__DisplayClass38_); } <>7__wrap1 = <>c__DisplayClass38_.seen.GetEnumerator(); <>1__state = -3; break; } case 1: <>1__state = -3; break; } if (<>7__wrap1.MoveNext()) { string current = <>7__wrap1.Current; <>2__current = current; <>1__state = 1; return true; } <>m__Finally1(); <>7__wrap1 = default(HashSet.Enumerator); 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; ((IDisposable)<>7__wrap1).Dispose(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__38 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__38(0); } d__.normalizedPrefabName = <>3__normalizedPrefabName; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } internal const string VanillaOwnerName = "Valheim"; internal const string UnknownOwnerName = "Unknown / Untracked"; private static readonly object Sync = new object(); private static readonly Dictionary PrefabOwners = new Dictionary(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary BundleOwners = new Dictionary(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary> PrefabsByBundle = new Dictionary>(StringComparer.OrdinalIgnoreCase); private static readonly HashSet KnownBundleNames = new HashSet(StringComparer.OrdinalIgnoreCase); private static string _loadedBundleSignature = ""; private static string _loadedPluginResourcesSignature = ""; private static MappingSnapshot _snapshot = new MappingSnapshot(new Dictionary(StringComparer.OrdinalIgnoreCase), ""); private static string _pluginResourcesSignature = ""; private static List _pluginResourcesCache = new List(); private static bool _mappingsDirty = true; internal static string GetOwnerName(string? prefabName) { string text = (prefabName ?? "").Trim(); if (text.Length == 0) { return "Unknown / Untracked"; } foreach (string item in EnumerateLookupCandidates(text)) { if (VanillaPrefabCatalog.IsAvailable && VanillaPrefabCatalog.IsVanilla(item)) { return "Valheim"; } } return PrefabOwnerResolver.GetOwnerName(text); } internal static string GetCurrentBundleSignature() { return BuildBundleSignature(); } internal static string GetCurrentPluginResourcesSignature() { return BuildPluginResourcesSignature(); } internal static MappingSnapshot GetSnapshot() { EnsureMappingsLoaded(); return _snapshot; } internal static void Invalidate() { lock (Sync) { _mappingsDirty = true; } } private static void EnsureMappingsLoaded() { string text = BuildBundleSignature(); string text2 = BuildPluginResourcesSignature(); if (!_mappingsDirty && string.Equals(text, _loadedBundleSignature, StringComparison.Ordinal) && string.Equals(text2, _loadedPluginResourcesSignature, StringComparison.Ordinal)) { return; } lock (Sync) { if (!_mappingsDirty && string.Equals(text, _loadedBundleSignature, StringComparison.Ordinal) && string.Equals(text2, _loadedPluginResourcesSignature, StringComparison.Ordinal)) { return; } if (TryLoadMappingsFromCache(text, text2)) { _mappingsDirty = false; return; } Dictionary loadedBundlesByName = GetLoadedBundlesByName(); HashSet currentBundleNames = new HashSet(loadedBundlesByName.Keys, StringComparer.OrdinalIgnoreCase); if (TryIncrementallyExtendMappings(loadedBundlesByName, currentBundleNames, text, text2)) { _mappingsDirty = false; return; } RebuildMappings(loadedBundlesByName, text, text2); _mappingsDirty = false; } } private static void RebuildMappings(Dictionary loadedBundles, string bundleSignature, string pluginResourcesSignature) { PrefabOwners.Clear(); PrefabsByBundle.Clear(); KnownBundleNames.Clear(); Dictionary dictionary = BuildPrefabToBundleMapping(loadedBundles.Values); Dictionary dictionary2 = BuildBundleToOwnerMapping(dictionary.Values.Distinct(StringComparer.OrdinalIgnoreCase)); foreach (var (text3, key) in dictionary) { if (dictionary2.TryGetValue(key, out var value)) { PrefabOwners[text3] = value; } if (!PrefabsByBundle.TryGetValue(key, out HashSet value2)) { value2 = new HashSet(StringComparer.OrdinalIgnoreCase); PrefabsByBundle[key] = value2; } value2.Add(text3); } foreach (string key2 in loadedBundles.Keys) { KnownBundleNames.Add(key2); } _loadedBundleSignature = bundleSignature; _loadedPluginResourcesSignature = pluginResourcesSignature; RefreshSnapshot(); SaveMappingsToCache(); DropNSpawnPlugin.DropNSpawnLogger.LogDebug((object)$"Tracked {PrefabOwners.Count} prefab owner mapping(s) across {dictionary2.Count} mod asset bundle(s)."); } private static Dictionary GetLoadedBundlesByName() { Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); foreach (AssetBundle allLoadedAssetBundle in AssetBundle.GetAllLoadedAssetBundles()) { string text = ((Object)allLoadedAssetBundle).name ?? ""; if (text.Length != 0) { dictionary[text] = allLoadedAssetBundle; } } return dictionary; } private static Dictionary BuildPrefabToBundleMapping(IEnumerable bundles) { Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); foreach (AssetBundle bundle in bundles) { string text = ((Object)bundle).name ?? ""; if (text.Length == 0) { continue; } string[] allAssetNames = bundle.GetAllAssetNames(); foreach (string text2 in allAssetNames) { if (text2.EndsWith(".prefab", StringComparison.OrdinalIgnoreCase)) { string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(text2); if (!string.IsNullOrWhiteSpace(fileNameWithoutExtension)) { dictionary[fileNameWithoutExtension] = text; } } } } return dictionary; } private static bool TryIncrementallyExtendMappings(Dictionary loadedBundles, HashSet currentBundleNames, string bundleSignature, string pluginResourcesSignature) { if (!string.Equals(_loadedPluginResourcesSignature, pluginResourcesSignature, StringComparison.Ordinal) || KnownBundleNames.Count == 0 || currentBundleNames.Count < KnownBundleNames.Count || KnownBundleNames.Except(currentBundleNames, StringComparer.OrdinalIgnoreCase).Any()) { return false; } List list = currentBundleNames.Except(KnownBundleNames, StringComparer.OrdinalIgnoreCase).OrderBy((string name) => name, StringComparer.OrdinalIgnoreCase).ToList(); if (list.Count == 0) { _loadedBundleSignature = bundleSignature; _loadedPluginResourcesSignature = pluginResourcesSignature; RefreshSnapshot(); return true; } Dictionary dictionary = BuildBundleToOwnerMapping(list); foreach (string item in list) { if (!loadedBundles.TryGetValue(item, out AssetBundle value)) { continue; } KnownBundleNames.Add(item); if (!PrefabsByBundle.TryGetValue(item, out HashSet value2)) { value2 = new HashSet(StringComparer.OrdinalIgnoreCase); PrefabsByBundle[item] = value2; } string value3; string value4 = (dictionary.TryGetValue(item, out value3) ? value3 : ""); string[] allAssetNames = value.GetAllAssetNames(); foreach (string text in allAssetNames) { if (!text.EndsWith(".prefab", StringComparison.OrdinalIgnoreCase)) { continue; } string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(text); if (!string.IsNullOrWhiteSpace(fileNameWithoutExtension)) { value2.Add(fileNameWithoutExtension); if (!string.IsNullOrWhiteSpace(value4)) { PrefabOwners[fileNameWithoutExtension] = value4; } } } } _loadedBundleSignature = bundleSignature; _loadedPluginResourcesSignature = pluginResourcesSignature; RefreshSnapshot(); SaveMappingsToCache(); return true; } private static Dictionary BuildBundleToOwnerMapping(IEnumerable bundleNames) { Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); List pluginResources = GetPluginResources(); foreach (string item in bundleNames.Distinct(StringComparer.OrdinalIgnoreCase)) { if (item.Length == 0) { continue; } if (BundleOwners.TryGetValue(item, out string value)) { if (!string.IsNullOrWhiteSpace(value)) { dictionary[item] = value; } continue; } string text = ResolveOwnerName(item, pluginResources); BundleOwners[item] = text ?? ""; if (!string.IsNullOrWhiteSpace(text)) { dictionary[item] = text; } } return dictionary; } private static List GetPluginResources() { string text = BuildPluginResourcesSignature(); if (string.Equals(text, _pluginResourcesSignature, StringComparison.Ordinal)) { return _pluginResourcesCache; } List pluginResourcesCache = (from pluginInfo in Chainloader.PluginInfos.Values select new PluginResources { OwnerName = GetPluginDisplayName(pluginInfo), ResourceNames = GetManifestResourceNames(pluginInfo) } into plugin where plugin.OwnerName.Length > 0 select plugin).ToList(); _pluginResourcesSignature = text; _pluginResourcesCache = pluginResourcesCache; BundleOwners.Clear(); return _pluginResourcesCache; } private static void RefreshSnapshot() { _snapshot = new MappingSnapshot(new Dictionary(PrefabOwners, StringComparer.OrdinalIgnoreCase), ReferenceRefreshSupport.ComputeStableHashForKeys(new string[2] { "bundles:" + _loadedBundleSignature, "plugins:" + _loadedPluginResourcesSignature })); } private static string GetCachePath() { string text = Path.Combine(DropNSpawnPlugin.YamlConfigDirectoryPath, "cache"); Directory.CreateDirectory(text); return Path.Combine(text, ".prefab-owner-bundle-cache.txt"); } private static bool TryLoadMappingsFromCache(string bundleSignature, string pluginResourcesSignature) { string cachePath = GetCachePath(); if (!File.Exists(cachePath)) { return false; } try { string[] array = File.ReadAllLines(cachePath); if (array.Length < 4 || !string.Equals(array[0], "v1", StringComparison.Ordinal)) { return false; } if (!string.Equals(array[1], bundleSignature, StringComparison.Ordinal) || !string.Equals(array[2], pluginResourcesSignature, StringComparison.Ordinal)) { return false; } PrefabOwners.Clear(); PrefabsByBundle.Clear(); KnownBundleNames.Clear(); BundleOwners.Clear(); for (int i = 4; i < array.Length; i++) { string text = array[i]; if (string.IsNullOrWhiteSpace(text)) { continue; } string[] array2 = text.Split('\t'); if (array2.Length < 3) { continue; } string text2 = DecodeCacheField(array2[0]); string value = DecodeCacheField(array2[1]); string text3 = DecodeCacheField(array2[2]); if (!string.IsNullOrWhiteSpace(text2) && !string.IsNullOrWhiteSpace(text3)) { PrefabOwners[text2] = value; KnownBundleNames.Add(text3); if (!PrefabsByBundle.TryGetValue(text3, out HashSet value2)) { value2 = new HashSet(StringComparer.OrdinalIgnoreCase); PrefabsByBundle[text3] = value2; } value2.Add(text2); if (!string.IsNullOrWhiteSpace(value)) { BundleOwners[text3] = value; } } } _loadedBundleSignature = bundleSignature; _loadedPluginResourcesSignature = pluginResourcesSignature; _snapshot = new MappingSnapshot(new Dictionary(PrefabOwners, StringComparer.OrdinalIgnoreCase), array[3] ?? ""); return _snapshot.Signature.Length > 0; } catch { return false; } } private static void SaveMappingsToCache() { if (string.IsNullOrWhiteSpace(_loadedBundleSignature) || string.IsNullOrWhiteSpace(_loadedPluginResourcesSignature) || string.IsNullOrWhiteSpace(_snapshot.Signature)) { return; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("v1"); stringBuilder.AppendLine(_loadedBundleSignature); stringBuilder.AppendLine(_loadedPluginResourcesSignature); stringBuilder.AppendLine(_snapshot.Signature); foreach (var (value, source) in PrefabsByBundle.OrderBy>, string>((KeyValuePair> pair) => pair.Key, StringComparer.OrdinalIgnoreCase)) { foreach (string item in source.OrderBy((string prefabName) => prefabName, StringComparer.OrdinalIgnoreCase)) { PrefabOwners.TryGetValue(item, out string value2); stringBuilder.Append(EncodeCacheField(item)).Append('\t').Append(EncodeCacheField(value2 ?? "")) .Append('\t') .Append(EncodeCacheField(value)) .AppendLine(); } } GeneratedFileWriter.WriteAllTextIfChanged(GetCachePath(), stringBuilder.ToString()); } private static string EncodeCacheField(string? value) { return Convert.ToBase64String(Encoding.UTF8.GetBytes(value ?? "")); } private static string DecodeCacheField(string? value) { if (string.IsNullOrWhiteSpace(value)) { return ""; } try { return Encoding.UTF8.GetString(Convert.FromBase64String(value)); } catch { return ""; } } private static string? ResolveOwnerName(string bundleName, List plugins) { string bundleName2 = bundleName; return plugins.FirstOrDefault((PluginResources candidate) => candidate.ResourceNames.Any((string resourceName) => resourceName.EndsWith(bundleName2, StringComparison.OrdinalIgnoreCase)))?.OwnerName; } private static string GetPluginDisplayName(PluginInfo pluginInfo) { string text = pluginInfo.Metadata.Name?.Trim() ?? ""; if (text.Length > 0) { return text; } string text2 = pluginInfo.Metadata.GUID?.Trim() ?? ""; if (text2.Length <= 0) { return "Unknown / Untracked"; } return text2; } private static string[] GetManifestResourceNames(PluginInfo pluginInfo) { try { return ((object)pluginInfo.Instance)?.GetType().Assembly.GetManifestResourceNames() ?? Array.Empty(); } catch { return Array.Empty(); } } private static string BuildPluginResourcesSignature() { return string.Join("|", Chainloader.PluginInfos.Values.Select(delegate(PluginInfo pluginInfo) { string text = pluginInfo.Metadata.GUID ?? ""; string text2 = pluginInfo.Metadata.Name ?? ""; string text3 = ((object)pluginInfo.Instance)?.GetType().Assembly.FullName ?? ""; return text + ":" + text2 + ":" + text3; }).OrderBy((string signature) => signature, StringComparer.OrdinalIgnoreCase)); } private static string BuildBundleSignature() { return string.Join("|", (from assetBundle in AssetBundle.GetAllLoadedAssetBundles() select ((Object)assetBundle).name ?? "").OrderBy((string name) => name, StringComparer.OrdinalIgnoreCase)); } [IteratorStateMachine(typeof(d__38))] private static IEnumerable EnumerateLookupCandidates(string normalizedPrefabName) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__38(-2) { <>3__normalizedPrefabName = normalizedPrefabName }; } private static string TrimCloneSuffix(string prefabName) { if (!prefabName.EndsWith("(Clone)", StringComparison.Ordinal)) { return prefabName; } int length = "(Clone)".Length; return prefabName.Substring(0, prefabName.Length - length).TrimEnd(); } internal static bool IsLikelyRuntimeVanillaPrefab(string prefabName) { if (string.IsNullOrWhiteSpace(prefabName)) { return false; } ObjectDB instance = ObjectDB.instance; if ((Object)(object)((instance != null) ? instance.GetItemPrefab(prefabName) : null) != (Object)null) { return true; } ZNetScene instance2 = ZNetScene.instance; if ((Object)(object)((instance2 != null) ? instance2.GetPrefab(prefabName) : null) != (Object)null) { return true; } if ((Object)(object)ZoneSystem.instance == (Object)null) { return false; } foreach (ZoneLocation location in ZoneSystem.instance.m_locations) { if (string.Equals((location?.m_prefabName ?? location?.m_prefab.Name ?? "").Trim(), prefabName, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } [CompilerGenerated] internal static void g__YieldIfNew|38_0(string candidate, ref <>c__DisplayClass38_0 P_1) { if (!string.IsNullOrWhiteSpace(candidate)) { P_1.seen.Add(candidate.Trim()); } } } internal sealed class PluginBootstrapCoordinator { private readonly DropNSpawnPlugin _host; internal PluginBootstrapCoordinator(DropNSpawnPlugin host) { _host = host; } internal void Run() { PluginManifestCoordinator.Initialize(DropNSpawnPlugin.ConfigSync); bool saveOnConfigSet = ((BaseUnityPlugin)_host).Config.SaveOnConfigSet; ((BaseUnityPlugin)_host).Config.SaveOnConfigSet = false; try { BindConfigurationEntries(); InitializeCoordinators(); AttachReloadAndManifestHandlers(); InitializeRuntimeSystems(); ApplyPatchesAndWatchers(); ((BaseUnityPlugin)_host).Config.Save(); } finally { if (saveOnConfigSet) { ((BaseUnityPlugin)_host).Config.SaveOnConfigSet = saveOnConfigSet; } } } private void BindConfigurationEntries() { //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Expected O, but got Unknown //IL_02be: Unknown result type (might be due to invalid IL or missing references) //IL_02d2: Unknown result type (might be due to invalid IL or missing references) //IL_02e6: Expected O, but got Unknown PluginBoundSettings.ServerConfigLocked = _host.BindConfigEntry("1 - General", "Lock Configuration", DropNSpawnPlugin.Toggle.On, "If on, the configuration is locked and can be changed by server admins only.", synchronizedSetting: true, 800); PluginBoundSettings.EnableCharacterOverrides = _host.BindConfigEntry("1 - General", "Enable Character Overrides", DropNSpawnPlugin.Toggle.On, "If off, DropNSpawn character YAML files stay on disk but CharacterDrop runtime overrides are not applied and existing character changes are restored to vanilla. Turn this off with Enable Object when using Drop That!. Turn this off when using Spawner Tweaks creature overrides.", synchronizedSetting: true, 700); PluginBoundSettings.EnableObjectOverrides = _host.BindConfigEntry("1 - General", "Enable Object Overrides", DropNSpawnPlugin.Toggle.On, "If off, DropNSpawn object YAML files stay on disk but object runtime overrides are not applied and existing object changes are restored to vanilla. Turn this off with Enable Character when using Drop That!. Turn this off when using Spawner Tweaks features for Chests or Pickables.", synchronizedSetting: true, 600); PluginBoundSettings.EnableSpawnerOverrides = _host.BindConfigEntry("1 - General", "Enable Spawner Overrides", DropNSpawnPlugin.Toggle.On, "If off, DropNSpawn SpawnArea and CreatureSpawner runtime overrides are not applied and existing spawner changes are restored to vanilla. Turn this off with Enable SpawnSystem when using Spawn That!. Turn this off when using Spawner Tweaks Spawn points or Spawners features.", synchronizedSetting: true, 500); SpawnerGlobalConfig.Bind(_host); PluginBoundSettings.EnableLocationOverrides = _host.BindConfigEntry("1 - General", "Enable Location Overrides", DropNSpawnPlugin.Toggle.On, "If off, DropNSpawn location runtime overrides for OfferingBowl, ItemStand, and Vegvisir are not applied and existing location changes are restored to vanilla. Turn this off when using Spawner Tweaks Boss altars or Item stands features.", synchronizedSetting: true, 400); PluginBoundSettings.EnableSpawnSystemOverrides = _host.BindConfigEntry("1 - General", "Enable SpawnSystem Overrides", DropNSpawnPlugin.Toggle.On, "If off, DropNSpawn world SpawnSystem runtime overrides and extended global key handling are not applied and existing SpawnSystem changes are restored to vanilla. Turn this off for Expand World Spawns. Turn this off with Enable Spawner when using Spawn That! world spawning.", synchronizedSetting: true, 300); PluginBoundSettings.AfternoonStartFraction = _host.BindConfigEntry("1 - General", "Afternoon Start Fraction", 0.5f, new ConfigDescription("Affects only timeOfDay: [afternoon]. Uses the raw day fraction before Valheim's internal day/night rescale. Valheim day starts at 0.15 and night starts at 0.85. Allowed range is 0.2 to 0.8.", (AcceptableValueBase)(object)new AcceptableValueRange(0.2f, 0.8f), Array.Empty()), synchronizedSetting: true, 200); PluginBoundSettings.ShowLocationProxyOfferingBowlHoverInfo = _host.BindConfigEntry("2 - Boss", "Show LocationProxy Offering Bowl Hover Info", DropNSpawnPlugin.Toggle.On, "If on, looking at an OfferingBowl shows simplified offering info with the spawned boss/item and required offering item. Matching altar ItemStands also show their required supported item names."); PluginBoundSettings.PerPlayerBossStones = _host.BindConfigEntry("2 - Boss", "Per Player Boss Stones", DropNSpawnPlugin.Toggle.On, "Each player sees their own version of reality. Any player standing in the Start Temple when a trophy is sacrificed will have the trophy hung in their reality as well. Any player not standing in the Start Temple when a trophy is sacrificed will not see the trophy in their reality."); PluginBoundSettings.RemoteForsakenPowerSelection = _host.BindConfigEntry("2 - Boss", "Remote Forsaken Power Selection", DropNSpawnPlugin.Toggle.On, "If on, players can rotate through Forsaken Powers they have unlocked through per-player boss stones without returning to the Start Temple."); BossRulesConfig.Bind(_host); DespawnRulesConfig.Bind(_host); CharacterDropGlobalConfig.Bind(_host); LocationRunestoneGlobalPinsConfig.Bind(_host); PluginBoundSettings.ReferenceUpdateMode = _host.BindConfigEntry("4 - Client", "Reference Update Mode", DropNSpawnPlugin.ReferenceUpdateMode.AutoUpdate, "AutoUpdate automatically creates missing reference YAML files and updates existing ones, except DNS_spawner.locations.reference.yml, which is only auto-created when missing and never auto-updated afterwards. DNS_spawnsystem.reference.yml is always manual-export-only. ManualUpdate automatically creates missing reference YAML files but updates existing ones only when you run dns:reference, while DNS_spawnsystem.reference.yml still remains manual-export-only.", synchronizedSetting: false); PluginBoundSettings.EnableOfferingBowlDiagnostics = _host.BindConfigEntry("4 - Client", "Enable OfferingBowl Diagnostics", DropNSpawnPlugin.Toggle.Off, "If on, emits targeted diagnostics for OfferingBowl startup and loose altar override application, including the resolved location prefab, parent ZNetView, and how many OfferingBowl components share that ZNetView. Leave off during normal play.", synchronizedSetting: false); PluginBoundSettings.EnableBossStoneDiagnostics = _host.BindConfigEntry("4 - Client", "Enable BossStone Diagnostics", DropNSpawnPlugin.Toggle.Off, "If on, emits targeted diagnostics for per-player boss stone routed RPC flows, especially reset request/apply/ack handling. Leave off during normal play.", synchronizedSetting: false); PluginBoundSettings.EnableDespawnDiagnostics = _host.BindConfigEntry("4 - Client", "Enable Despawn Diagnostics", DropNSpawnPlugin.Toggle.Off, "If on, emits targeted diagnostics for configured despawn tracking, nearby-player counting, countdown start/cancel, unload persistence, and final despawn execution. Enable this when reproducing dedicated-server despawn problems.", synchronizedSetting: false); PluginBoundSettings.RotateForsakenPowerShortcut = _host.BindConfigEntry("4 - Client", "Rotate Forsaken Power Shortcut", new KeyboardShortcut((KeyCode)103, Array.Empty()), new ConfigDescription("Shortcut used to rotate through unlocked Forsaken Powers when Remote Forsaken Power Selection is enabled. This setting is client-side only.", (AcceptableValueBase)(object)new DropNSpawnPlugin.AcceptableShortcuts(), Array.Empty()), synchronizedSetting: false); PluginBoundSettings.EnableSpawnSystemDiagnostics = _host.BindConfigEntry("4 - Client", "Enable SpawnSystem Diagnostics", DropNSpawnPlugin.Toggle.Off, "If on, emits detailed client-side spawnsystem diagnostic logs such as build stamps, apply-skip reasons, queued/compiled build stages, and awake retrigger traces. Leave off during normal play.", synchronizedSetting: false); } private void InitializeCoordinators() { _host.RuntimeWorkCoordinator = new PluginRuntimeWorkCoordinator(_host); _host.ReloadCoordinator = new PluginReloadCoordinator(_host, PluginBoundSettings.EnableObjectOverrides, PluginBoundSettings.EnableCharacterOverrides, PluginBoundSettings.EnableSpawnerOverrides, PluginBoundSettings.EnableLocationOverrides, PluginBoundSettings.EnableSpawnSystemOverrides); } private void AttachReloadAndManifestHandlers() { DropNSpawnPlugin.ConfigSync.AddLockingConfigEntry(PluginBoundSettings.ServerConfigLocked); DropNSpawnPlugin.ConfigSync.SourceOfTruthChanged += _host.ReloadCoordinator.HandleSourceOfTruthChanged; PluginBoundSettings.EnableObjectOverrides.SettingChanged += _host.ReloadCoordinator.HandleDomainToggleSettingChanged; PluginBoundSettings.EnableCharacterOverrides.SettingChanged += _host.ReloadCoordinator.HandleDomainToggleSettingChanged; PluginBoundSettings.EnableSpawnerOverrides.SettingChanged += _host.ReloadCoordinator.HandleDomainToggleSettingChanged; PluginBoundSettings.EnableLocationOverrides.SettingChanged += _host.ReloadCoordinator.HandleDomainToggleSettingChanged; PluginBoundSettings.EnableSpawnSystemOverrides.SettingChanged += _host.ReloadCoordinator.HandleDomainToggleSettingChanged; PluginManifestCoordinator.AttachRuntimeDomainHandlers(); } private void InitializeRuntimeSystems() { Directory.CreateDirectory(DropNSpawnPlugin.YamlConfigDirectoryPath); NetworkPayloadSyncSupport.Initialize((MonoBehaviour)(object)_host); ExampleContentWriter.EnsureDefaultExampleFiles(); ObjectDropManager.Initialize(); CharacterDropManager.Initialize(); SpawnerManager.Initialize(); LocationManager.Initialize(); SpawnSystemManager.Initialize(); BossStonePerPlayerRuntime.Initialize(); DropNSpawnConsoleCommands.Register(); if (PluginSettingsFacade.IsSpawnSystemDiagnosticsEnabled()) { DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)("Booting DropNSpawn build=" + DropNSpawnPlugin.RuntimeBuildStamp)); } } private void ApplyPatchesAndWatchers() { Assembly executingAssembly = Assembly.GetExecutingAssembly(); _host.HarmonyInstance.PatchAll(executingAssembly); VneiCompatibility.Initialize(_host.HarmonyInstance); _host.ReloadCoordinator.InitializeWatchers(); } } [BepInPlugin("sighsorry.DropNSpawn", "DropNSpawn", "1.2.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class DropNSpawnPlugin : BaseUnityPlugin { [Flags] internal enum ReloadDomain { None = 0, Object = 1, Character = 2, Spawner = 4, Location = 8, SpawnSystem = 0x10, All = 0x1F } internal readonly struct DomainToggleState { internal Toggle Object { get; } internal Toggle Character { get; } internal Toggle Spawner { get; } internal Toggle Location { get; } internal Toggle SpawnSystem { get; } internal DomainToggleState(Toggle @object, Toggle character, Toggle spawner, Toggle location, Toggle spawnSystem) { Object = @object; Character = character; Spawner = spawner; Location = location; SpawnSystem = spawnSystem; } } public enum Toggle { On = 1, Off = 0 } public enum ReferenceUpdateMode { AutoUpdate, ManualUpdate } private class ConfigurationManagerAttributes { [UsedImplicitly] public int? Order; [UsedImplicitly] public bool? Browsable; [UsedImplicitly] public string? Category; [UsedImplicitly] public Action? CustomDrawer; } internal class AcceptableShortcuts : AcceptableValueBase { public AcceptableShortcuts() : base(typeof(KeyboardShortcut)) { } public override object Clamp(object value) { return value; } public override bool IsValid(object value) { return true; } public override string ToDescriptionString() { return "# Acceptable values: " + string.Join(", ", UnityInput.Current.SupportedKeyCodes); } } internal const string ModName = "DropNSpawn"; internal const string YamlFilePrefix = "DNS"; internal const string ModVersion = "1.2.1"; internal const string Author = "sighsorry"; private const string ModGUID = "sighsorry.DropNSpawn"; internal static readonly string RuntimeBuildStamp = BuildRuntimeBuildStamp(); private static string ConfigFileName = "sighsorry.DropNSpawn.cfg"; private static string ConfigFileFullPath = Paths.ConfigPath + Path.DirectorySeparatorChar + ConfigFileName; internal static string ConnectionError = ""; private readonly Harmony _harmony = new Harmony("sighsorry.DropNSpawn"); public static readonly ManualLogSource DropNSpawnLogger = Logger.CreateLogSource("DropNSpawn"); private static ConfigSync? _configSync; private PluginReloadCoordinator? _reloadCoordinator; private PluginRuntimeWorkCoordinator? _runtimeWorkCoordinator; internal static string YamlConfigDirectoryPath => Path.Combine(Paths.ConfigPath, "DropNSpawn"); internal static string YamlRulesWatcherPattern => "DNS_*.*"; internal static string CurrentConfigFileName => ConfigFileName; internal static string CurrentConfigFileFullPath => ConfigFileFullPath; internal static DropNSpawnPlugin? Instance { get; private set; } internal static ConfigSync ConfigSync => _configSync ?? throw new InvalidOperationException("ServerSync has not been initialized yet."); internal static bool IsSourceOfTruth => ConfigSync.IsSourceOfTruth; internal Harmony HarmonyInstance => _harmony; internal PluginReloadCoordinator? ReloadCoordinator { get { return _reloadCoordinator; } set { _reloadCoordinator = value; } } internal PluginRuntimeWorkCoordinator? RuntimeWorkCoordinator { get { return _runtimeWorkCoordinator; } set { _runtimeWorkCoordinator = value; } } public void Awake() { EnsureServerSyncInitialized(); Instance = this; new PluginBootstrapCoordinator(this).Run(); } private void Update() { BossStonePerPlayerRuntime.EnsureRpcRegistered(); BossStonePerPlayerRuntime.ProcessPendingResetRequests(); BossTamedPressureRuntime.ExecuteServerTick(); DespawnRulesManager.ExecuteServerTick(); _runtimeWorkCoordinator?.ProcessUpdateFrame(); } private static string BuildRuntimeBuildStamp() { try { string text = typeof(DropNSpawnPlugin).Assembly.ManifestModule.ModuleVersionId.ToString("N"); return "1.2.1+" + text.Substring(0, 8); } catch { return "1.2.1"; } } private void OnDestroy() { if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } SaveWithRespectToConfigSet(); if (_configSync != null && _reloadCoordinator != null) { _configSync.SourceOfTruthChanged -= _reloadCoordinator.HandleSourceOfTruthChanged; } if (_reloadCoordinator != null) { ConfigEntry? enableObjectOverrides = PluginBoundSettings.EnableObjectOverrides; if (enableObjectOverrides != null) { enableObjectOverrides.SettingChanged -= _reloadCoordinator.HandleDomainToggleSettingChanged; } ConfigEntry? enableCharacterOverrides = PluginBoundSettings.EnableCharacterOverrides; if (enableCharacterOverrides != null) { enableCharacterOverrides.SettingChanged -= _reloadCoordinator.HandleDomainToggleSettingChanged; } ConfigEntry? enableSpawnerOverrides = PluginBoundSettings.EnableSpawnerOverrides; if (enableSpawnerOverrides != null) { enableSpawnerOverrides.SettingChanged -= _reloadCoordinator.HandleDomainToggleSettingChanged; } ConfigEntry? enableLocationOverrides = PluginBoundSettings.EnableLocationOverrides; if (enableLocationOverrides != null) { enableLocationOverrides.SettingChanged -= _reloadCoordinator.HandleDomainToggleSettingChanged; } ConfigEntry? enableSpawnSystemOverrides = PluginBoundSettings.EnableSpawnSystemOverrides; if (enableSpawnSystemOverrides != null) { enableSpawnSystemOverrides.SettingChanged -= _reloadCoordinator.HandleDomainToggleSettingChanged; } } PluginManifestCoordinator.DetachRuntimeDomainHandlers(); _runtimeWorkCoordinator?.Dispose(); _runtimeWorkCoordinator = null; _reloadCoordinator?.Dispose(); _reloadCoordinator = null; PluginBoundSettings.Clear(); NetworkPayloadSyncSupport.Shutdown(); BossStonePerPlayerRuntime.Shutdown(); } private static void EnsureServerSyncInitialized() { if (_configSync == null) { _configSync = new ConfigSync("sighsorry.DropNSpawn") { DisplayName = "DropNSpawn", CurrentVersion = "1.2.1", MinimumRequiredVersion = "1.2.1" }; } } internal static string GetSyncedManifestValue(DomainDescriptor domain) { return PluginManifestCoordinator.GetSyncedManifestValue(domain); } internal void SaveWithRespectToConfigSet(bool reload = false, bool save = true) { bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet; ((BaseUnityPlugin)this).Config.SaveOnConfigSet = false; try { if (reload) { ((BaseUnityPlugin)this).Config.Reload(); } if (save) { ((BaseUnityPlugin)this).Config.Save(); } } finally { ((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet; } } internal static bool IsRuntimeServer() { if ((Object)(object)ZNet.instance != (Object)null) { return ZNet.instance.IsServer(); } return false; } internal static void QueueGameDataRefresh(ReloadDomain domains, string source) { Instance?._runtimeWorkCoordinator?.QueueGameDataRefresh(domains, source); } internal static bool IsGameDataRefreshDeferred(ReloadDomain domain) { DropNSpawnPlugin? instance = Instance; if (instance == null) { return false; } return (instance._runtimeWorkCoordinator?.IsGameDataRefreshDeferred(domain)).GetValueOrDefault(); } internal static bool TryGetSyncedEntries(DomainDescriptor domain, out List entries, out string payloadToken) { return PluginManifestCoordinator.TryGetSyncedEntries(domain, out entries, out payloadToken); } internal static void PublishSyncedPayload(DomainDescriptor domain, List entries, string? knownSignature) { PluginManifestCoordinator.PublishSyncedPayload(domain, entries, knownSignature); } internal ConfigEntry BindConfigEntry(string group, string name, T value, ConfigDescription description, bool synchronizedSetting = true, int? configManagerOrder = null) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown ConfigDescription val = new ConfigDescription(description.Description + (synchronizedSetting ? " [Synced with Server]" : " [Not Synced with Server]"), description.AcceptableValues, BuildConfigDescriptionTags(description.Tags, configManagerOrder)); ConfigEntry val2 = ((BaseUnityPlugin)this).Config.Bind(group, name, value, val); ConfigSync.AddConfigEntry(val2).SynchronizedConfig = synchronizedSetting; return val2; } private ConfigEntry config(string group, string name, T value, ConfigDescription description, bool synchronizedSetting = true) { return BindConfigEntry(group, name, value, description, synchronizedSetting); } internal ConfigEntry BindConfigEntry(string group, string name, T value, string description, bool synchronizedSetting = true, int? configManagerOrder = null) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown return BindConfigEntry(group, name, value, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty()), synchronizedSetting, configManagerOrder); } private ConfigEntry config(string group, string name, T value, string description, bool synchronizedSetting = true) { return BindConfigEntry(group, name, value, description, synchronizedSetting); } private static object[] BuildConfigDescriptionTags(object[]? existingTags, int? configManagerOrder) { if (!configManagerOrder.HasValue) { return existingTags ?? Array.Empty(); } return (existingTags ?? Array.Empty()).Concat(new object[1] { new ConfigurationManagerAttributes { Order = configManagerOrder.Value } }).ToArray(); } } public static class KeyboardExtensions { [SpecialName] public sealed class $8D1D3E80A18AA9715780B6CB7003B2F1 { [SpecialName] public static class $895AB635D4D087636CF1C26BA650BA11 { } [ExtensionMarker("$895AB635D4D087636CF1C26BA650BA11")] public bool IsKeyDown() { throw new NotSupportedException(); } [ExtensionMarker("$895AB635D4D087636CF1C26BA650BA11")] public bool IsKeyHeld() { throw new NotSupportedException(); } } public static bool IsKeyDown(this KeyboardShortcut shortcut) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) if ((int)((KeyboardShortcut)(ref shortcut)).MainKey != 0 && Input.GetKeyDown(((KeyboardShortcut)(ref shortcut)).MainKey)) { return ((KeyboardShortcut)(ref shortcut)).Modifiers.All((Func)Input.GetKey); } return false; } public static bool IsKeyHeld(this KeyboardShortcut shortcut) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) if ((int)((KeyboardShortcut)(ref shortcut)).MainKey != 0 && Input.GetKey(((KeyboardShortcut)(ref shortcut)).MainKey)) { return ((KeyboardShortcut)(ref shortcut)).Modifiers.All((Func)Input.GetKey); } return false; } } public static class ToggleExtentions { [SpecialName] public sealed class $A5DFA62E049B860EDABA9962FA410667 { [SpecialName] public static class $B6EBA18AB32C5C8A4BB623283A60F3A3 { } [ExtensionMarker("$B6EBA18AB32C5C8A4BB623283A60F3A3")] public bool IsOn() { throw new NotSupportedException(); } [ExtensionMarker("$B6EBA18AB32C5C8A4BB623283A60F3A3")] public bool IsOff() { throw new NotSupportedException(); } } public static bool IsOn(this DropNSpawnPlugin.Toggle value) { return value == DropNSpawnPlugin.Toggle.On; } public static bool IsOff(this DropNSpawnPlugin.Toggle value) { return value == DropNSpawnPlugin.Toggle.Off; } } internal static class PluginManifestCoordinator { private static readonly Dictionary> SyncedManifests = new Dictionary>(); private static readonly Dictionary SyncedManifestChangedHandlers = new Dictionary(); internal static void Initialize(ConfigSync configSync) { SyncedManifests.Clear(); SyncedManifestChangedHandlers.Clear(); DomainDescriptor[] runtimeDomains = DomainRegistry.RuntimeDomains; foreach (DomainDescriptor domainDescriptor in runtimeDomains) { SyncedManifests[domainDescriptor.ReloadDomain] = new CustomSyncedValue(configSync, domainDescriptor.ManifestSettingKey, "", domainDescriptor.ManifestPriority); DomainDescriptor capturedDomain = domainDescriptor; SyncedManifestChangedHandlers[domainDescriptor.ReloadDomain] = delegate { HandleSyncedManifestChanged(capturedDomain); }; } } internal static void AttachRuntimeDomainHandlers() { DomainDescriptor[] runtimeDomains = DomainRegistry.RuntimeDomains; foreach (DomainDescriptor domain in runtimeDomains) { GetSyncedManifestEntry(domain).ValueChanged += GetSyncedManifestChangedHandler(domain); } } internal static void DetachRuntimeDomainHandlers() { DomainDescriptor[] runtimeDomains = DomainRegistry.RuntimeDomains; foreach (DomainDescriptor domainDescriptor in runtimeDomains) { if (SyncedManifests.TryGetValue(domainDescriptor.ReloadDomain, out CustomSyncedValue value) && SyncedManifestChangedHandlers.TryGetValue(domainDescriptor.ReloadDomain, out Action value2)) { value.ValueChanged -= value2; } } } internal static string GetSyncedManifestValue(DomainDescriptor domain) { return GetSyncedManifestEntry(domain).Value ?? ""; } internal static bool TryGetSyncedEntries(DomainDescriptor domain, out List entries, out string payloadToken) { return NetworkPayloadSyncSupport.TryGetEntries(domain, GetSyncedManifestValue(domain), out entries, out payloadToken); } internal static void PublishSyncedPayload(DomainDescriptor domain, List entries, string? knownSignature) { DomainDescriptor domain2 = domain; NetworkPayloadSyncSupport.PublishPayloadAsync(domain2, entries, knownSignature, delegate(string manifest) { AssignServerManifestValue(GetSyncedManifestEntry(domain2), manifest, broadcastToConnectedClients: true); }); } internal static void EnterClientAuthorityCutover() { DomainDescriptor[] runtimeDomains = DomainRegistry.RuntimeDomains; for (int i = 0; i < runtimeDomains.Length; i++) { runtimeDomains[i].OnClientAuthorityCutover?.Invoke(); } } internal static void ReplayCurrentSyncedManifestStates() { if (!DropNSpawnPlugin.IsSourceOfTruth) { DomainDescriptor[] runtimeDomains = DomainRegistry.RuntimeDomains; for (int i = 0; i < runtimeDomains.Length; i++) { HandleSyncedManifestChanged(runtimeDomains[i]); } } } private static CustomSyncedValue GetSyncedManifestEntry(DomainDescriptor domain) { if (SyncedManifests.TryGetValue(domain.ReloadDomain, out CustomSyncedValue value)) { return value; } throw new InvalidOperationException("ServerSync " + domain.DomainKey + " payload has not been initialized yet."); } private static Action GetSyncedManifestChangedHandler(DomainDescriptor domain) { if (SyncedManifestChangedHandlers.TryGetValue(domain.ReloadDomain, out Action value)) { return value; } throw new InvalidOperationException("ServerSync " + domain.DomainKey + " manifest handler has not been initialized yet."); } private static void HandleSyncedManifestChanged(DomainDescriptor domain) { if (!DropNSpawnPlugin.IsSourceOfTruth) { domain.BeforeClientManifestChanged?.Invoke(); domain.HandleManifestChanged(GetSyncedManifestValue(domain)); } } private static void AssignServerManifestValue(CustomSyncedValue syncedValue, string manifest, bool broadcastToConnectedClients) { if (manifest == null) { manifest = ""; } if (string.Equals(syncedValue.Value ?? "", manifest, StringComparison.Ordinal)) { return; } if (broadcastToConnectedClients || !DropNSpawnPlugin.IsSourceOfTruth) { syncedValue.AssignLocalValue(manifest); return; } bool processingServerUpdate = ConfigSync.ProcessingServerUpdate; ConfigSync.ProcessingServerUpdate = true; try { syncedValue.AssignLocalValue(manifest); } finally { ConfigSync.ProcessingServerUpdate = processingServerUpdate; } } } internal sealed class PluginReloadCoordinator { [CompilerGenerated] private sealed class d__33 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public PluginReloadCoordinator <>4__this; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__33(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { int num = <>1__state; PluginReloadCoordinator pluginReloadCoordinator = <>4__this; float lastQueuedConfigReloadTime; if (num != 0) { if (num != 1) { return false; } <>1__state = -1; lock (pluginReloadCoordinator._reloadDebounceLock) { lastQueuedConfigReloadTime = pluginReloadCoordinator._lastQueuedConfigReloadTime; } goto IL_0087; } <>1__state = -1; goto IL_001e; IL_001e: lock (pluginReloadCoordinator._reloadDebounceLock) { lastQueuedConfigReloadTime = pluginReloadCoordinator._lastQueuedConfigReloadTime; } goto IL_0087; IL_0087: if (Time.realtimeSinceStartup - lastQueuedConfigReloadTime < 0.5f) { <>2__current = null; <>1__state = 1; return true; } bool configReloadPending; lock (pluginReloadCoordinator._reloadDebounceLock) { configReloadPending = pluginReloadCoordinator._configReloadPending; pluginReloadCoordinator._configReloadPending = false; } if (configReloadPending) { pluginReloadCoordinator.ExecuteQueuedConfigReload(); } lock (pluginReloadCoordinator._reloadDebounceLock) { if (!pluginReloadCoordinator._configReloadPending) { pluginReloadCoordinator._configReloadCoroutine = null; goto IL_0104; } } goto IL_001e; IL_0104: return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class d__34 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public PluginReloadCoordinator <>4__this; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__34(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { int num = <>1__state; PluginReloadCoordinator pluginReloadCoordinator = <>4__this; float lastQueuedRuleReloadTime; if (num != 0) { if (num != 1) { return false; } <>1__state = -1; lock (pluginReloadCoordinator._reloadDebounceLock) { lastQueuedRuleReloadTime = pluginReloadCoordinator._lastQueuedRuleReloadTime; } goto IL_0087; } <>1__state = -1; goto IL_001e; IL_001e: lock (pluginReloadCoordinator._reloadDebounceLock) { lastQueuedRuleReloadTime = pluginReloadCoordinator._lastQueuedRuleReloadTime; } goto IL_0087; IL_0087: if (Time.realtimeSinceStartup - lastQueuedRuleReloadTime < 0.5f) { <>2__current = null; <>1__state = 1; return true; } DropNSpawnPlugin.ReloadDomain pendingRuleReloadDomains; lock (pluginReloadCoordinator._reloadDebounceLock) { pendingRuleReloadDomains = pluginReloadCoordinator._pendingRuleReloadDomains; pluginReloadCoordinator._pendingRuleReloadDomains = DropNSpawnPlugin.ReloadDomain.None; } if (pendingRuleReloadDomains != 0) { pluginReloadCoordinator.ExecuteQueuedRuleReload(pendingRuleReloadDomains); } lock (pluginReloadCoordinator._reloadDebounceLock) { if (pluginReloadCoordinator._pendingRuleReloadDomains == DropNSpawnPlugin.ReloadDomain.None) { pluginReloadCoordinator._rulesReloadCoroutine = null; goto IL_0105; } } goto IL_001e; IL_0105: return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private const float FileReloadDebounceSeconds = 0.5f; private readonly DropNSpawnPlugin _host; private readonly ConfigEntry _enableObjectOverrides; private readonly ConfigEntry _enableCharacterOverrides; private readonly ConfigEntry _enableSpawnerOverrides; private readonly ConfigEntry _enableLocationOverrides; private readonly ConfigEntry _enableSpawnSystemOverrides; private readonly object _reloadLock = new object(); private readonly object _reloadDebounceLock = new object(); private FileSystemWatcher? _configWatcher; private FileSystemWatcher? _rulesWatcher; private Coroutine? _configReloadCoroutine; private Coroutine? _rulesReloadCoroutine; private DropNSpawnPlugin.ReloadDomain _pendingRuleReloadDomains; private bool _configReloadPending; private float _lastQueuedConfigReloadTime; private float _lastQueuedRuleReloadTime; internal bool IsConfigEntryReloadSuppressed { get; private set; } internal PluginReloadCoordinator(DropNSpawnPlugin host, ConfigEntry enableObjectOverrides, ConfigEntry enableCharacterOverrides, ConfigEntry enableSpawnerOverrides, ConfigEntry enableLocationOverrides, ConfigEntry enableSpawnSystemOverrides) { _host = host; _enableObjectOverrides = enableObjectOverrides; _enableCharacterOverrides = enableCharacterOverrides; _enableSpawnerOverrides = enableSpawnerOverrides; _enableLocationOverrides = enableLocationOverrides; _enableSpawnSystemOverrides = enableSpawnSystemOverrides; } internal void HandleSourceOfTruthChanged(bool isSourceOfTruth) { DropNSpawnPlugin.DropNSpawnLogger.LogDebug((object)$"Config source of truth changed. Local is owner: {isSourceOfTruth}."); NetworkPayloadSyncSupport.HandleSourceOfTruthChanged(isSourceOfTruth); if (!isSourceOfTruth) { PluginManifestCoordinator.EnterClientAuthorityCutover(); PluginManifestCoordinator.ReplayCurrentSyncedManifestStates(); } UpdateRulesWatcherState(DropNSpawnPlugin.IsSourceOfTruth); ReloadDomains(DropNSpawnPlugin.ReloadDomain.All); } internal void HandleDomainToggleSettingChanged(object? sender, EventArgs e) { if (!IsConfigEntryReloadSuppressed) { ReloadDomains(GetReloadDomainForToggleSetting(sender)); } } internal void InitializeWatchers() { SetupConfigWatcher(); SetupRulesWatcher(); } internal void Dispose() { _configWatcher?.Dispose(); _rulesWatcher?.Dispose(); if (_configReloadCoroutine != null) { ((MonoBehaviour)_host).StopCoroutine(_configReloadCoroutine); _configReloadCoroutine = null; } if (_rulesReloadCoroutine != null) { ((MonoBehaviour)_host).StopCoroutine(_rulesReloadCoroutine); _rulesReloadCoroutine = null; } } internal void UpdateRulesWatcherState(bool isSourceOfTruth) { if (_rulesWatcher != null) { _rulesWatcher.EnableRaisingEvents = isSourceOfTruth; } } private void SetupConfigWatcher() { _configWatcher = new FileSystemWatcher(Paths.ConfigPath, DropNSpawnPlugin.CurrentConfigFileName); _configWatcher.Changed += OnConfigFileChanged; _configWatcher.Created += OnConfigFileChanged; _configWatcher.Renamed += OnConfigFileChanged; _configWatcher.IncludeSubdirectories = true; _configWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject; _configWatcher.EnableRaisingEvents = true; } private void SetupRulesWatcher() { Directory.CreateDirectory(DropNSpawnPlugin.YamlConfigDirectoryPath); _rulesWatcher = new FileSystemWatcher(DropNSpawnPlugin.YamlConfigDirectoryPath, ObjectDropManager.RulesWatcherPattern); _rulesWatcher.Changed += OnRuleFileChanged; _rulesWatcher.Created += OnRuleFileChanged; _rulesWatcher.Deleted += OnRuleFileChanged; _rulesWatcher.Renamed += OnRuleFileChanged; _rulesWatcher.IncludeSubdirectories = true; _rulesWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject; UpdateRulesWatcherState(DropNSpawnPlugin.IsSourceOfTruth); } private void OnConfigFileChanged(object sender, FileSystemEventArgs e) { QueueConfigReload(); } private void OnRuleFileChanged(object sender, FileSystemEventArgs e) { if (!DropNSpawnPlugin.IsSourceOfTruth) { return; } DropNSpawnPlugin.ReloadDomain reloadDomain = DropNSpawnPlugin.ReloadDomain.None; DomainDescriptor[] runtimeDomains = DomainRegistry.RuntimeDomains; foreach (DomainDescriptor domainDescriptor in runtimeDomains) { bool flag = domainDescriptor.ShouldReloadForPath(e.FullPath); if (!flag && e is RenamedEventArgs renamedEventArgs) { flag = domainDescriptor.ShouldReloadForPath(renamedEventArgs.OldFullPath); } if (flag) { reloadDomain |= domainDescriptor.ReloadDomain; } } if (reloadDomain != 0) { QueueRuleReload(reloadDomain); } } private void QueueConfigReload() { lock (_reloadDebounceLock) { _configReloadPending = true; _lastQueuedConfigReloadTime = Time.realtimeSinceStartup; if (_configReloadCoroutine == null) { _configReloadCoroutine = ((MonoBehaviour)_host).StartCoroutine(ProcessQueuedConfigReload()); } } } private void QueueRuleReload(DropNSpawnPlugin.ReloadDomain domains) { if (domains == DropNSpawnPlugin.ReloadDomain.None) { return; } lock (_reloadDebounceLock) { _pendingRuleReloadDomains |= domains; _lastQueuedRuleReloadTime = Time.realtimeSinceStartup; if (_rulesReloadCoroutine == null) { _rulesReloadCoroutine = ((MonoBehaviour)_host).StartCoroutine(ProcessQueuedRuleReload()); } } } [IteratorStateMachine(typeof(d__33))] private IEnumerator ProcessQueuedConfigReload() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__33(0) { <>4__this = this }; } [IteratorStateMachine(typeof(d__34))] private IEnumerator ProcessQueuedRuleReload() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__34(0) { <>4__this = this }; } private void ExecuteQueuedConfigReload() { lock (_reloadLock) { if (!File.Exists(DropNSpawnPlugin.CurrentConfigFileFullPath)) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)"Config file does not exist. Skipping reload."); return; } try { DropNSpawnPlugin.DropNSpawnLogger.LogDebug((object)"Reloading configuration..."); DropNSpawnPlugin.DomainToggleState previous = CaptureDomainToggleState(); IsConfigEntryReloadSuppressed = true; _host.SaveWithRespectToConfigSet(reload: true, save: false); ReloadDomains(GetChangedDomainToggles(previous, CaptureDomainToggleState())); DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)"Configuration reload complete."); } catch (Exception ex) { DropNSpawnPlugin.DropNSpawnLogger.LogError((object)("Error reloading configuration: " + ex.Message)); } finally { IsConfigEntryReloadSuppressed = false; } } } private void ExecuteQueuedRuleReload(DropNSpawnPlugin.ReloadDomain domains) { if (domains == DropNSpawnPlugin.ReloadDomain.None || !DropNSpawnPlugin.IsSourceOfTruth) { return; } lock (_reloadLock) { try { DropNSpawnPlugin.DropNSpawnLogger.LogDebug((object)"Reloading override YAML configuration..."); ReloadDomains(domains); DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)"Override YAML configuration reload complete."); } catch (Exception ex) { DropNSpawnPlugin.DropNSpawnLogger.LogError((object)("Error reloading override YAML configuration: " + ex.Message)); } } } private DropNSpawnPlugin.DomainToggleState CaptureDomainToggleState() { return new DropNSpawnPlugin.DomainToggleState(_enableObjectOverrides.Value, _enableCharacterOverrides.Value, _enableSpawnerOverrides.Value, _enableLocationOverrides.Value, _enableSpawnSystemOverrides.Value); } private DropNSpawnPlugin.ReloadDomain GetReloadDomainForToggleSetting(object? sender) { DropNSpawnPlugin.ReloadDomain reloadDomain = DropNSpawnPlugin.ReloadDomain.None; if (sender == _enableObjectOverrides) { reloadDomain |= DropNSpawnPlugin.ReloadDomain.Object; } if (sender == _enableCharacterOverrides) { reloadDomain |= DropNSpawnPlugin.ReloadDomain.Character; } if (sender == _enableSpawnerOverrides) { reloadDomain |= DropNSpawnPlugin.ReloadDomain.Spawner; } if (sender == _enableLocationOverrides) { reloadDomain |= DropNSpawnPlugin.ReloadDomain.Location; } if (sender == _enableSpawnSystemOverrides) { reloadDomain |= DropNSpawnPlugin.ReloadDomain.SpawnSystem; } return reloadDomain; } private static DropNSpawnPlugin.ReloadDomain GetChangedDomainToggles(DropNSpawnPlugin.DomainToggleState previous, DropNSpawnPlugin.DomainToggleState current) { DropNSpawnPlugin.ReloadDomain reloadDomain = DropNSpawnPlugin.ReloadDomain.None; if (previous.Object != current.Object) { reloadDomain |= DropNSpawnPlugin.ReloadDomain.Object; } if (previous.Character != current.Character) { reloadDomain |= DropNSpawnPlugin.ReloadDomain.Character; } if (previous.Spawner != current.Spawner) { reloadDomain |= DropNSpawnPlugin.ReloadDomain.Spawner; } if (previous.Location != current.Location) { reloadDomain |= DropNSpawnPlugin.ReloadDomain.Location; } if (previous.SpawnSystem != current.SpawnSystem) { reloadDomain |= DropNSpawnPlugin.ReloadDomain.SpawnSystem; } return reloadDomain; } private static void ReloadDomains(DropNSpawnPlugin.ReloadDomain domains) { DomainDescriptor[] runtimeDomains = DomainRegistry.RuntimeDomains; foreach (DomainDescriptor domainDescriptor in runtimeDomains) { if ((domains & domainDescriptor.ReloadDomain) != 0) { domainDescriptor.Reload(); } } } } internal sealed class PluginRuntimeWorkCoordinator { [CompilerGenerated] private sealed class d__27 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public string initialSource; public PluginRuntimeWorkCoordinator <>4__this; private string 5__2; private DropNSpawnPlugin.ReloadDomain 5__3; private DomainDescriptor[] <>7__wrap3; private int <>7__wrap4; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__27(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { 5__2 = null; <>7__wrap3 = null; <>1__state = -2; } private bool MoveNext() { int num = <>1__state; PluginRuntimeWorkCoordinator pluginRuntimeWorkCoordinator = <>4__this; float lastQueuedGameDataRefreshTime; switch (num) { default: return false; case 0: <>1__state = -1; 5__2 = initialSource; goto IL_0035; case 1: <>1__state = -1; lock (pluginRuntimeWorkCoordinator._gameDataRefreshLock) { lastQueuedGameDataRefreshTime = pluginRuntimeWorkCoordinator._lastQueuedGameDataRefreshTime; } goto IL_0098; case 2: { <>1__state = -1; goto IL_01b0; } IL_0035: lock (pluginRuntimeWorkCoordinator._gameDataRefreshLock) { lastQueuedGameDataRefreshTime = pluginRuntimeWorkCoordinator._lastQueuedGameDataRefreshTime; } goto IL_0098; IL_0098: if (Time.realtimeSinceStartup - lastQueuedGameDataRefreshTime < 0.1f) { <>2__current = null; <>1__state = 1; return true; } lock (pluginRuntimeWorkCoordinator._gameDataRefreshLock) { 5__3 = pluginRuntimeWorkCoordinator._pendingGameDataRefreshDomains; pluginRuntimeWorkCoordinator._pendingGameDataRefreshDomains = DropNSpawnPlugin.ReloadDomain.None; } if (5__3 == DropNSpawnPlugin.ReloadDomain.None) { lock (pluginRuntimeWorkCoordinator._gameDataRefreshLock) { pluginRuntimeWorkCoordinator._gameDataRefreshCoroutine = null; } return false; } DropNSpawnPlugin.DropNSpawnLogger.LogDebug((object)$"Processing queued game-data refresh after {5__2} for domains: {5__3}."); PrefabOwnerResolver.Invalidate(); <>7__wrap3 = DomainRegistry.RuntimeDomains; <>7__wrap4 = 0; goto IL_01be; IL_01b0: <>7__wrap4++; goto IL_01be; IL_01be: if (<>7__wrap4 < <>7__wrap3.Length) { DomainDescriptor domainDescriptor = <>7__wrap3[<>7__wrap4]; if ((5__3 & domainDescriptor.ReloadDomain) != 0) { domainDescriptor.OnGameDataReady(5__2); pluginRuntimeWorkCoordinator.MarkGameDataRefreshDomainProcessed(domainDescriptor.ReloadDomain); if (pluginRuntimeWorkCoordinator.ShouldYieldBetweenQueuedGameDataRefreshDomains(5__3, domainDescriptor.ReloadDomain)) { <>2__current = null; <>1__state = 2; return true; } } goto IL_01b0; } <>7__wrap3 = null; 5__2 = "queued game-data refresh"; goto IL_0035; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private const float GameDataRefreshDebounceSeconds = 0.1f; private const float ReconcileQueueFrameBudgetSeconds = 0.002f; private const int WorkLaneCount = 3; private readonly DropNSpawnPlugin _host; private readonly object _gameDataRefreshLock = new object(); private Coroutine? _gameDataRefreshCoroutine; private DropNSpawnPlugin.ReloadDomain _deferredGameDataRefreshDomains; private DropNSpawnPlugin.ReloadDomain _pendingGameDataRefreshDomains; private float _lastQueuedGameDataRefreshTime; private int _reconcileRoundRobinCursor; private int _snapshotBuildRoundRobinCursor; private int _workLaneRoundRobinCursor; private bool _hasObservedExpandWorldDataReadyState; private bool _lastObservedExpandWorldDataReadyState = true; internal PluginRuntimeWorkCoordinator(DropNSpawnPlugin host) { _host = host; } internal void Dispose() { if (_gameDataRefreshCoroutine != null) { ((MonoBehaviour)_host).StopCoroutine(_gameDataRefreshCoroutine); _gameDataRefreshCoroutine = null; } } internal void ProcessUpdateFrame() { ObserveExpandWorldDataReadyTransition(); if (NetworkPayloadSyncSupport.HasPendingWork() || HasPendingSnapshotBuildWork() || HasPendingReconcileWork()) { float num = Time.realtimeSinceStartup + 0.002f; int num2 = 0; while (Time.realtimeSinceStartup < num && num2 < 5) { num2 = ((!ProcessNextPendingWorkLane(num)) ? (num2 + 1) : 0); } } } internal void QueueGameDataRefresh(DropNSpawnPlugin.ReloadDomain domains, string source) { if (domains == DropNSpawnPlugin.ReloadDomain.None) { return; } lock (_gameDataRefreshLock) { _pendingGameDataRefreshDomains |= domains; _deferredGameDataRefreshDomains |= domains; _lastQueuedGameDataRefreshTime = Time.realtimeSinceStartup; if (_gameDataRefreshCoroutine == null) { _gameDataRefreshCoroutine = ((MonoBehaviour)_host).StartCoroutine(ProcessQueuedGameDataRefresh(source)); } } } internal bool IsGameDataRefreshDeferred(DropNSpawnPlugin.ReloadDomain domain) { if (domain == DropNSpawnPlugin.ReloadDomain.None) { return false; } lock (_gameDataRefreshLock) { return (_deferredGameDataRefreshDomains & domain) != 0; } } private void ObserveExpandWorldDataReadyTransition() { if (!BiomeResolutionSupport.IsExpandWorldDataPresent()) { return; } bool flag = BiomeResolutionSupport.IsExpandWorldDataReadyOrUnavailable(); bool flag2 = false; if (!_hasObservedExpandWorldDataReadyState) { _hasObservedExpandWorldDataReadyState = true; _lastObservedExpandWorldDataReadyState = flag; flag2 = flag; } else if (flag && !_lastObservedExpandWorldDataReadyState) { _lastObservedExpandWorldDataReadyState = true; flag2 = true; } else { _lastObservedExpandWorldDataReadyState = flag; } if (flag2 && DropNSpawnPlugin.IsSourceOfTruth) { bool flag3 = false; DomainDescriptor[] runtimeDomains = DomainRegistry.RuntimeDomains; foreach (DomainDescriptor domainDescriptor in runtimeDomains) { flag3 |= domainDescriptor.HandleExpandWorldDataReady(); } if (flag3) { DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)"ExpandWorldData biome sync became ready; replayed synchronized biome-mask publish for object, character, spawner, location, and spawnsystem domains."); } } } private bool ProcessNextPendingWorkLane(float deadline) { for (int i = 0; i < 3; i++) { int num = (_workLaneRoundRobinCursor + i) % 3; if (HasPendingWork(num)) { _workLaneRoundRobinCursor = (num + 1) % 3; if (ProcessPendingWork(num, deadline)) { return true; } } } return false; } private bool ProcessNextPendingSnapshotBuildStep(float deadline) { for (int i = 0; i < DomainRegistry.SnapshotBuildDomains.Length; i++) { int num = (_snapshotBuildRoundRobinCursor + i) % DomainRegistry.SnapshotBuildDomains.Length; DomainDescriptor domainDescriptor = DomainRegistry.SnapshotBuildDomains[num]; if (domainDescriptor.HasPendingSnapshotBuildWork != null && domainDescriptor.ProcessPendingSnapshotBuildStep != null && domainDescriptor.HasPendingSnapshotBuildWork()) { _snapshotBuildRoundRobinCursor = (num + 1) % DomainRegistry.SnapshotBuildDomains.Length; return domainDescriptor.ProcessPendingSnapshotBuildStep(deadline); } } return false; } private bool HasPendingWork(int lane) { return lane switch { 0 => NetworkPayloadSyncSupport.HasPendingWork(), 1 => HasPendingSnapshotBuildWork(), _ => HasPendingReconcileWork(), }; } private bool ProcessPendingWork(int lane, float deadline) { return lane switch { 0 => NetworkPayloadSyncSupport.ProcessPendingWork(deadline), 1 => ProcessNextPendingSnapshotBuildStep(deadline), _ => ProcessNextQueuedReconcileStep(deadline), }; } private bool ProcessNextQueuedReconcileStep(float deadline) { for (int i = 0; i < DomainRegistry.ReconcileDomains.Length; i++) { int num = (_reconcileRoundRobinCursor + i) % DomainRegistry.ReconcileDomains.Length; DomainDescriptor domainDescriptor = DomainRegistry.ReconcileDomains[num]; if (domainDescriptor.HasPendingReconcileWork != null && domainDescriptor.ProcessPendingReconcileStep != null && domainDescriptor.HasPendingReconcileWork()) { _reconcileRoundRobinCursor = (num + 1) % DomainRegistry.ReconcileDomains.Length; return domainDescriptor.ProcessPendingReconcileStep(deadline); } } return false; } private bool HasPendingReconcileWork() { DomainDescriptor[] reconcileDomains = DomainRegistry.ReconcileDomains; foreach (DomainDescriptor domainDescriptor in reconcileDomains) { if (domainDescriptor.HasPendingReconcileWork != null && domainDescriptor.ProcessPendingReconcileStep != null && domainDescriptor.HasPendingReconcileWork()) { return true; } } return false; } private bool HasPendingSnapshotBuildWork() { DomainDescriptor[] snapshotBuildDomains = DomainRegistry.SnapshotBuildDomains; foreach (DomainDescriptor domainDescriptor in snapshotBuildDomains) { if (domainDescriptor.HasPendingSnapshotBuildWork != null && domainDescriptor.ProcessPendingSnapshotBuildStep != null && domainDescriptor.HasPendingSnapshotBuildWork()) { return true; } } return false; } [IteratorStateMachine(typeof(d__27))] private IEnumerator ProcessQueuedGameDataRefresh(string initialSource) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__27(0) { <>4__this = this, initialSource = initialSource }; } private bool ShouldYieldBetweenQueuedGameDataRefreshDomains(DropNSpawnPlugin.ReloadDomain domains, DropNSpawnPlugin.ReloadDomain processedDomain) { if ((domains & ~processedDomain) != 0) { return true; } lock (_gameDataRefreshLock) { return _pendingGameDataRefreshDomains != DropNSpawnPlugin.ReloadDomain.None; } } private void MarkGameDataRefreshDomainProcessed(DropNSpawnPlugin.ReloadDomain domain) { lock (_gameDataRefreshLock) { if ((_pendingGameDataRefreshDomains & domain) == 0) { _deferredGameDataRefreshDomains &= ~domain; } } } } internal static class PluginBoundSettings { internal static ConfigEntry? ServerConfigLocked { get; set; } internal static ConfigEntry? EnableObjectOverrides { get; set; } internal static ConfigEntry? EnableCharacterOverrides { get; set; } internal static ConfigEntry? EnableSpawnerOverrides { get; set; } internal static ConfigEntry? EnableLocationOverrides { get; set; } internal static ConfigEntry? EnableSpawnSystemOverrides { get; set; } internal static ConfigEntry? AfternoonStartFraction { get; set; } internal static ConfigEntry? ShowLocationProxyOfferingBowlHoverInfo { get; set; } internal static ConfigEntry? EnableBossTamedPressure { get; set; } internal static ConfigEntry? PerPlayerBossStones { get; set; } internal static ConfigEntry? RemoteForsakenPowerSelection { get; set; } internal static ConfigEntry? ReferenceUpdateMode { get; set; } internal static ConfigEntry? EnableOfferingBowlDiagnostics { get; set; } internal static ConfigEntry? EnableBossStoneDiagnostics { get; set; } internal static ConfigEntry? EnableDespawnDiagnostics { get; set; } internal static ConfigEntry? EnableSpawnSystemDiagnostics { get; set; } internal static ConfigEntry? RotateForsakenPowerShortcut { get; set; } internal static void Clear() { ServerConfigLocked = null; EnableObjectOverrides = null; EnableCharacterOverrides = null; EnableSpawnerOverrides = null; EnableLocationOverrides = null; EnableSpawnSystemOverrides = null; AfternoonStartFraction = null; ShowLocationProxyOfferingBowlHoverInfo = null; EnableBossTamedPressure = null; PerPlayerBossStones = null; RemoteForsakenPowerSelection = null; ReferenceUpdateMode = null; EnableOfferingBowlDiagnostics = null; EnableBossStoneDiagnostics = null; EnableDespawnDiagnostics = null; EnableSpawnSystemDiagnostics = null; RotateForsakenPowerShortcut = null; } } internal static class PluginSettingsFacade { [CompilerGenerated] private sealed class <>c__DisplayClass29_0 { public Func isOverrideFileName; internal bool b__0(string path) { if (IsEligibleOverrideConfigurationPath(path)) { return isOverrideFileName(Path.GetFileName(path)); } return false; } } [CompilerGenerated] private sealed class d__29 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private string <>2__current; private int <>l__initialThreadId; private Func isOverrideFileName; public Func <>3__isOverrideFileName; private string searchPattern; public string <>3__searchPattern; private IEnumerator <>7__wrap1; string IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__29(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(); } } <>7__wrap1 = null; <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: { <>1__state = -1; <>c__DisplayClass29_0 CS$<>8__locals0 = new <>c__DisplayClass29_0 { isOverrideFileName = isOverrideFileName }; if (!Directory.Exists(DropNSpawnPlugin.YamlConfigDirectoryPath)) { return false; } IEnumerable enumerable = (from path in Directory.EnumerateFiles(DropNSpawnPlugin.YamlConfigDirectoryPath, searchPattern, SearchOption.AllDirectories) where IsEligibleOverrideConfigurationPath(path) && CS$<>8__locals0.isOverrideFileName(Path.GetFileName(path)) select path).OrderBy((string path) => path, StringComparer.OrdinalIgnoreCase); <>7__wrap1 = enumerable.GetEnumerator(); <>1__state = -3; break; } case 1: <>1__state = -3; break; } if (<>7__wrap1.MoveNext()) { string current = <>7__wrap1.Current; <>2__current = current; <>1__state = 1; return true; } <>m__Finally1(); <>7__wrap1 = 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 (<>7__wrap1 != null) { <>7__wrap1.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__29 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__29(0); } d__.searchPattern = <>3__searchPattern; d__.isOverrideFileName = <>3__isOverrideFileName; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } internal static bool ShouldShowLocationProxyOfferingBowlHoverInfo() { ConfigEntry? showLocationProxyOfferingBowlHoverInfo = PluginBoundSettings.ShowLocationProxyOfferingBowlHoverInfo; if (showLocationProxyOfferingBowlHoverInfo == null) { return true; } return showLocationProxyOfferingBowlHoverInfo.Value != DropNSpawnPlugin.Toggle.Off; } internal static bool IsPerPlayerBossStonesEnabled() { ConfigEntry? perPlayerBossStones = PluginBoundSettings.PerPlayerBossStones; if (perPlayerBossStones == null) { return true; } return perPlayerBossStones.Value != DropNSpawnPlugin.Toggle.Off; } internal static bool IsRemoteForsakenPowerSelectionEnabled() { ConfigEntry? remoteForsakenPowerSelection = PluginBoundSettings.RemoteForsakenPowerSelection; if (remoteForsakenPowerSelection == null) { return true; } return remoteForsakenPowerSelection.Value != DropNSpawnPlugin.Toggle.Off; } internal static bool IsBossTamedPressureEnabled() { ConfigEntry? enableBossTamedPressure = PluginBoundSettings.EnableBossTamedPressure; if (enableBossTamedPressure == null) { return true; } return enableBossTamedPressure.Value != DropNSpawnPlugin.Toggle.Off; } internal static bool ShouldAutoUpdateReferenceFiles() { ConfigEntry? referenceUpdateMode = PluginBoundSettings.ReferenceUpdateMode; if (referenceUpdateMode == null) { return true; } return referenceUpdateMode.Value != DropNSpawnPlugin.ReferenceUpdateMode.ManualUpdate; } internal static bool ShouldAutoCreateMissingReferenceFiles() { return true; } internal static bool IsObjectDomainEnabled() { ConfigEntry? enableObjectOverrides = PluginBoundSettings.EnableObjectOverrides; if (enableObjectOverrides == null) { return true; } return enableObjectOverrides.Value != DropNSpawnPlugin.Toggle.Off; } internal static bool IsCharacterDomainEnabled() { ConfigEntry? enableCharacterOverrides = PluginBoundSettings.EnableCharacterOverrides; if (enableCharacterOverrides == null) { return true; } return enableCharacterOverrides.Value != DropNSpawnPlugin.Toggle.Off; } internal static bool IsSpawnerDomainEnabled() { ConfigEntry? enableSpawnerOverrides = PluginBoundSettings.EnableSpawnerOverrides; if (enableSpawnerOverrides == null) { return true; } return enableSpawnerOverrides.Value != DropNSpawnPlugin.Toggle.Off; } internal static bool IsLocationDomainEnabled() { ConfigEntry? enableLocationOverrides = PluginBoundSettings.EnableLocationOverrides; if (enableLocationOverrides == null) { return true; } return enableLocationOverrides.Value != DropNSpawnPlugin.Toggle.Off; } internal static bool IsSpawnSystemDomainEnabled() { ConfigEntry? enableSpawnSystemOverrides = PluginBoundSettings.EnableSpawnSystemOverrides; if (enableSpawnSystemOverrides == null) { return true; } return enableSpawnSystemOverrides.Value != DropNSpawnPlugin.Toggle.Off; } internal static bool IsRunestoneGlobalPinsEnabled() { return LocationRunestoneGlobalPinsConfig.IsEnabled(); } internal static float GetAfternoonStartFraction() { return PluginBoundSettings.AfternoonStartFraction?.Value ?? 0.5f; } internal static KeyboardShortcut GetRotateForsakenPowerShortcut() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) return (KeyboardShortcut)(((??)PluginBoundSettings.RotateForsakenPowerShortcut?.Value) ?? default(KeyboardShortcut)); } internal static bool IsGlobalCharacterDropInStackEnabled() { return CharacterDropGlobalConfig.IsGlobalDropInStackEnabled(); } internal static float GetSameBossDuplicateBlockRadius() { return BossRulesConfig.GetSameBossDuplicateBlockRadius(); } internal static int GetDefaultSpawnAreaMaxTotalSpawns() { return SpawnerGlobalConfig.GetDefaultSpawnAreaMaxTotalSpawns(); } internal static float GetDefaultDespawnRange() { return DespawnRulesConfig.GetDefaultDespawnRange(); } internal static float GetDefaultDespawnDelaySeconds() { return DespawnRulesConfig.GetDefaultDespawnDelaySeconds(); } internal static float GetCharacterDropOnePerPlayerNearbyRange() { return CharacterDropGlobalConfig.GetOnePerPlayerNearbyRange(); } internal static bool IsCharacterDropOnePerPlayerNearbyRangeLivingPlayersOnly() { return CharacterDropGlobalConfig.IsOnePerPlayerNearbyRangeLivingPlayersOnly(); } internal static bool IsCharacterDropInStackBlacklisted(string? prefabName) { return CharacterDropGlobalConfig.IsDropInStackBlacklisted(prefabName); } internal static bool IsEligibleOverrideConfigurationPath(string? path) { if (string.IsNullOrWhiteSpace(path)) { return false; } string fullPath = Path.GetFullPath(path); string value = EnsureTrailingSeparator(Path.GetFullPath(DropNSpawnPlugin.YamlConfigDirectoryPath)); return fullPath.StartsWith(value, StringComparison.OrdinalIgnoreCase); } internal static string GetYamlDomainFilePrefix(string domain) { return "DNS_" + domain; } internal static bool IsSpawnSystemDiagnosticsEnabled() { ConfigEntry? enableSpawnSystemDiagnostics = PluginBoundSettings.EnableSpawnSystemDiagnostics; if (enableSpawnSystemDiagnostics == null) { return false; } return enableSpawnSystemDiagnostics.Value == DropNSpawnPlugin.Toggle.On; } internal static bool IsOfferingBowlDiagnosticsEnabled() { ConfigEntry? enableOfferingBowlDiagnostics = PluginBoundSettings.EnableOfferingBowlDiagnostics; if (enableOfferingBowlDiagnostics == null) { return false; } return enableOfferingBowlDiagnostics.Value == DropNSpawnPlugin.Toggle.On; } internal static bool IsBossStoneDiagnosticsEnabled() { ConfigEntry? enableBossStoneDiagnostics = PluginBoundSettings.EnableBossStoneDiagnostics; if (enableBossStoneDiagnostics == null) { return false; } return enableBossStoneDiagnostics.Value == DropNSpawnPlugin.Toggle.On; } internal static bool IsDespawnDiagnosticsEnabled() { ConfigEntry? enableDespawnDiagnostics = PluginBoundSettings.EnableDespawnDiagnostics; if (enableDespawnDiagnostics == null) { return false; } return enableDespawnDiagnostics.Value == DropNSpawnPlugin.Toggle.On; } internal static string GetYamlDomainSupplementalPrefix(string domain) { return GetYamlDomainFilePrefix(domain) + "_"; } [IteratorStateMachine(typeof(d__29))] internal static IEnumerable EnumerateSupplementalOverrideConfigurationPaths(string searchPattern, Func isOverrideFileName) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__29(-2) { <>3__searchPattern = searchPattern, <>3__isOverrideFileName = isOverrideFileName }; } private static string EnsureTrailingSeparator(string path) { if (path.EndsWith(Path.DirectorySeparatorChar) || path.EndsWith(Path.AltDirectorySeparatorChar)) { return path; } return path + Path.DirectorySeparatorChar; } } internal static class BossRulesManager { private static readonly Dictionary> TrackedBossesByPrefab = new Dictionary>(StringComparer.OrdinalIgnoreCase); internal static bool ShouldBlockConfiguredSameBossSpawn(GameObject? targetPrefab, Vector3 sourcePosition) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return ShouldBlockSameBossSpawn(targetPrefab, sourcePosition, PluginSettingsFacade.GetSameBossDuplicateBlockRadius()); } internal static bool ShouldBlockSameBossSpawn(GameObject? targetPrefab, Vector3 sourcePosition, float radius) { //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) if (radius <= 0f || !TryGetBossPrefabName(targetPrefab, out string prefabName)) { return false; } if (!TrackedBossesByPrefab.TryGetValue(prefabName, out HashSet value) || value.Count == 0) { return false; } float rangeSquared = radius * radius; value.RemoveWhere((Character character) => !IsTrackableBossCharacter(character)); if (value.Count == 0) { TrackedBossesByPrefab.Remove(prefabName); return false; } foreach (Character item in value) { if (IsWithinRangeXZ(item.GetCenterPoint(), sourcePosition, rangeSquared)) { return true; } } return false; } internal static void TrackBossCharacter(Character? character) { if (TryGetTrackableBossPrefabName(character, out string prefabName)) { if (!TrackedBossesByPrefab.TryGetValue(prefabName, out HashSet value)) { value = new HashSet(); TrackedBossesByPrefab[prefabName] = value; } value.Add(character); } } internal static void UntrackBossCharacter(Character? character) { if ((Object)(object)character == (Object)null) { return; } if (TryGetTrackableBossPrefabName(character, out string prefabName) && TrackedBossesByPrefab.TryGetValue(prefabName, out HashSet value)) { value.Remove(character); if (value.Count == 0) { TrackedBossesByPrefab.Remove(prefabName); } } else { RemoveBossCharacterByScan(character); } } internal static void ClearRuntimeState() { TrackedBossesByPrefab.Clear(); } private static void RemoveBossCharacterByScan(Character character) { string text = null; foreach (var (text3, hashSet2) in TrackedBossesByPrefab) { if (hashSet2.Remove(character)) { text = ((hashSet2.Count == 0) ? text3 : null); break; } } if (text != null) { TrackedBossesByPrefab.Remove(text); } } private static bool TryGetTrackableBossPrefabName(Character? character, out string prefabName) { prefabName = ""; if (IsTrackableBossCharacter(character)) { return TryGetBossPrefabName(((Component)character).gameObject, out prefabName); } return false; } private static bool IsTrackableBossCharacter(Character? character) { if ((Object)(object)character != (Object)null && (Object)(object)((Component)character).gameObject != (Object)null && !character.IsDead()) { return character.IsBoss(); } return false; } private static bool IsWithinRangeXZ(Vector3 source, Vector3 target, float rangeSquared) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) Vector3 val = source - target; val.y = 0f; return ((Vector3)(ref val)).sqrMagnitude < rangeSquared; } private static bool TryGetBossPrefabName(GameObject? prefab, out string prefabName) { prefabName = GetPrefabName(prefab); Character val = default(Character); if ((Object)(object)prefab != (Object)null && prefabName.Length > 0 && prefab.TryGetComponent(ref val)) { return val.IsBoss(); } return false; } private static string GetPrefabName(GameObject? gameObject) { if ((Object)(object)gameObject == (Object)null) { return ""; } ZNetView component = gameObject.GetComponent(); 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 ((Object)prefab).name; } } string prefabName = Utils.GetPrefabName(gameObject); if (!string.IsNullOrWhiteSpace(prefabName)) { return prefabName; } string text = ((Object)gameObject).name ?? ""; if (text.EndsWith("(Clone)", StringComparison.Ordinal)) { string text2 = text; int length = "(Clone)".Length; return text2.Substring(0, text2.Length - length).TrimEnd(); } return text; } } internal sealed class DespawnRefundDrop { internal GameObject Prefab { get; } internal int Amount { get; } internal DespawnRefundDrop(GameObject prefab, int amount) { Prefab = prefab; Amount = amount; } } internal static class DespawnRulesManager { private enum DespawnObservationSource { BootstrapScan, CreatedZdo, LoadedCharacter } private enum DespawnProducerSkipSource { CreatedZdo, LoadedCharacter, DetachPersist } private enum CreatedZdoObservationDecision { Eligible, Ineligible, Unknown } private enum ObservationApplicationResult { Applied, Dropped, Deferred } private readonly struct PendingDespawnObservation { internal ZDOID ZdoId { get; } internal int PrefabHashHint { get; } internal string PrefabNameHint { get; } internal DespawnObservationSource Source { get; } internal float NextAttemptAt { get; } internal float ExpireAt { get; } internal int RetryCount { get; } internal PendingDespawnObservation(ZDOID zdoId, int prefabHashHint, string prefabNameHint, DespawnObservationSource source, float nextAttemptAt = 0f, float expireAt = 0f, int retryCount = 0) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) ZdoId = zdoId; PrefabHashHint = prefabHashHint; PrefabNameHint = prefabNameHint ?? ""; Source = source; NextAttemptAt = nextAttemptAt; ExpireAt = expireAt; RetryCount = retryCount; } } private readonly struct PendingDespawnDetachPersist { internal ZDOID ZdoId { get; } internal Vector3 ProbePoint { get; } internal int PrefabHashHint { get; } internal string PrefabNameHint { get; } internal PendingDespawnDetachPersist(ZDOID zdoId, Vector3 probePoint, int prefabHashHint, string prefabNameHint) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) ZdoId = zdoId; ProbePoint = probePoint; PrefabHashHint = prefabHashHint; PrefabNameHint = prefabNameHint ?? ""; } } private sealed class TrackedDespawnState { internal readonly List Refunds = new List(); internal string DisplayName { get; set; } = "Target"; internal string PrefabName { get; set; } = ""; internal float? RangeOverride { get; set; } internal float? DelayOverride { get; set; } internal double NoPlayerSince { get; set; } = -1.0; internal int LastAnnouncedRemainingSeconds { get; set; } = -1; internal long LastInterestedPlayerId { get; set; } internal long CountdownRecipientPlayerId { get; set; } internal long ScheduledCheckAtBucket { get; set; } = long.MinValue; internal void UpdateFromCharacter(Character character, float? rangeOverride, float? delayOverride, IReadOnlyCollection refunds) { DisplayName = GetDisplayName(character); PrefabName = Utils.GetPrefabName(((Component)character).gameObject); RangeOverride = rangeOverride; DelayOverride = delayOverride; Refunds.Clear(); if (refunds != null) { Refunds.AddRange(refunds); } } internal void UpdateFromZdoPrefab(string prefabName, float? rangeOverride, float? delayOverride, IReadOnlyCollection refunds) { DisplayName = (string.IsNullOrWhiteSpace(prefabName) ? "Target" : prefabName); PrefabName = prefabName ?? ""; RangeOverride = rangeOverride; DelayOverride = delayOverride; Refunds.Clear(); if (refunds != null) { Refunds.AddRange(refunds); } } internal void ResetCountdown() { NoPlayerSince = -1.0; LastAnnouncedRemainingSeconds = -1; CountdownRecipientPlayerId = 0L; } internal float GetEffectiveRange() { return Mathf.Clamp(RangeOverride ?? PluginSettingsFacade.GetDefaultDespawnRange(), 0f, 128f); } internal float GetEffectiveDelaySeconds() { return Mathf.Clamp(DelayOverride ?? PluginSettingsFacade.GetDefaultDespawnDelaySeconds(), 0f, 300f); } } private const float CreatedZdoObservationRetryIntervalSeconds = 0.25f; private const float CreatedZdoObservationRetryTimeoutSeconds = 1f; private const float DespawnCountdownCheckIntervalSeconds = 0.5f; private const float DespawnIdleCheckIntervalSeconds = 1f; private const float DespawnTrackingRefreshIntervalSeconds = 1f; private const float DespawnIneligibleProducerSummaryIntervalSeconds = 5f; private const int DespawnFinalCountdownSeconds = 5; private const int DespawnReminderIntervalSeconds = 5; private static readonly Dictionary TrackedDespawnTargets = new Dictionary(); private static readonly SortedDictionary> ScheduledDespawnChecks = new SortedDictionary>(); private static readonly Dictionary PendingDespawnObservations = new Dictionary(); private static readonly Dictionary PendingDespawnDetachPersists = new Dictionary(); private static readonly List PendingDespawnRemovals = new List(); private static readonly List PendingDespawnObservationRemovals = new List(); private static readonly List PendingDespawnObservationUpdates = new List(); private static readonly List PendingDespawnDetachPersistRemovals = new List(); private static readonly List BootstrapScanBuffer = new List(); private static float _nextDespawnTrackingRefreshAt; private static float _nextIneligibleProducerSummaryAt; private static bool _loggedServerTickActivation; private static bool _pendingBootstrapScan = true; private static int _createdZdoProducerQueuedCount; private static int _createdZdoProducerDeferredCount; private static int _createdZdoProducerDeferredExpiredCount; private static int _skippedCreatedZdoProducerCount; private static int _skippedLoadedCharacterProducerCount; private static int _skippedDetachPersistProducerCount; private static int _loadedCharacterProducerAttemptCount; private static int _loadedCharacterProducerQueuedCount; private static int _loadedCharacterProducerMissingCharacterCount; private static int _loadedCharacterProducerDeadCharacterCount; private static int _loadedCharacterProducerMissingNviewCount; private static int _loadedCharacterProducerInvalidNviewCount; private static int _loadedCharacterProducerMissingZdoCount; private static int _loadedCharacterProducerDeadZdoCount; private static int _loadedCharacterProducerMissingPrefabNameCount; internal static void ExecuteServerTick() { if (!DropNSpawnPlugin.IsRuntimeServer()) { return; } if (!PluginSettingsFacade.IsCharacterDomainEnabled()) { if (TrackedDespawnTargets.Count > 0) { TrackedDespawnTargets.Clear(); PendingDespawnRemovals.Clear(); } if (ScheduledDespawnChecks.Count > 0) { ScheduledDespawnChecks.Clear(); } if (PendingDespawnObservations.Count > 0) { PendingDespawnObservations.Clear(); PendingDespawnObservationRemovals.Clear(); } if (PendingDespawnObservationUpdates.Count > 0) { PendingDespawnObservationUpdates.Clear(); } if (PendingDespawnDetachPersists.Count > 0) { PendingDespawnDetachPersists.Clear(); PendingDespawnDetachPersistRemovals.Clear(); } _nextDespawnTrackingRefreshAt = 0f; ResetSkippedIneligibleProducerDiagnostics(); _loggedServerTickActivation = false; _pendingBootstrapScan = true; return; } if (!_loggedServerTickActivation) { LogDiagnostics($"Despawn server tick active. players={Player.GetAllPlayers().Count} characterDomainEnabled={PluginSettingsFacade.IsCharacterDomainEnabled()} trackedCharacters={TrackedDespawnTargets.Count}."); _loggedServerTickActivation = true; } ProcessSkippedIneligibleProducerDiagnostics(Time.time); ApplyPendingDespawnObservations(); float time = Time.time; if (_nextDespawnTrackingRefreshAt <= time) { PruneTrackedDespawnTargetsAgainstCurrentConfig(); if (_pendingBootstrapScan && RunPendingBootstrapScan()) { _pendingBootstrapScan = false; ApplyPendingDespawnObservations(); } _nextDespawnTrackingRefreshAt = time + 1f; } double currentDespawnClockSeconds = GetCurrentDespawnClockSeconds(); ApplyPendingDespawnDetaches(currentDespawnClockSeconds); if (TrackedDespawnTargets.Count == 0) { if (ScheduledDespawnChecks.Count > 0) { ScheduledDespawnChecks.Clear(); } } else if (ScheduledDespawnChecks.Count != 0) { ProcessScheduledDespawnChecks(currentDespawnClockSeconds); } } private static void ProcessScheduledDespawnChecks(double nowSeconds) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0090: 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_0099: Unknown result type (might be due to invalid IL or missing references) if (ScheduledDespawnChecks.Count == 0) { return; } long nowBucket = QuantizeScheduledCheck(nowSeconds); PendingDespawnRemovals.Clear(); long bucket; List dueTargets; while (TryDequeueDueScheduledCheck(nowBucket, out bucket, out dueTargets)) { foreach (ZDOID item in dueTargets) { if (TrackedDespawnTargets.TryGetValue(item, out TrackedDespawnState value) && value.ScheduledCheckAtBucket == bucket) { value.ScheduledCheckAtBucket = long.MinValue; ZDOMan instance = ZDOMan.instance; ZDO val = ((instance != null) ? instance.GetZDO(item) : null); if (val == null || IsDeadZdo(item)) { PendingDespawnRemovals.Add(item); } else { ProcessTrackedDespawnTarget(item, val, value, nowSeconds); } } } } FlushPendingDespawnRemovals(); } private static bool TryDequeueDueScheduledCheck(long nowBucket, out long bucket, out List dueTargets) { if (ScheduledDespawnChecks.Count == 0) { bucket = long.MinValue; dueTargets = null; return false; } using IEnumerator>> enumerator = (object)ScheduledDespawnChecks.GetEnumerator(); if (!enumerator.MoveNext()) { bucket = long.MinValue; dueTargets = null; return false; } KeyValuePair> current = enumerator.Current; if (current.Key > nowBucket) { bucket = long.MinValue; dueTargets = null; return false; } bucket = current.Key; dueTargets = current.Value; ScheduledDespawnChecks.Remove(current.Key); return true; } internal static void MarkBootstrapScanDirty(string reason) { _pendingBootstrapScan = true; if (!string.IsNullOrWhiteSpace(reason)) { LogDiagnostics("Marked despawn bootstrap scan dirty. reason=" + reason + "."); } } private static bool RunPendingBootstrapScan() { if (ZDOMan.instance == null) { return false; } IReadOnlyList despawnBootstrapPrefabOrder = CharacterDropManager.GetDespawnBootstrapPrefabOrder(); if (despawnBootstrapPrefabOrder.Count == 0) { return true; } LogDiagnostics($"Running despawn bootstrap scan for {despawnBootstrapPrefabOrder.Count} prefab(s)."); foreach (string item in despawnBootstrapPrefabOrder) { QueueBootstrapScanDespawnObservations(item); } return true; } internal static void QueueCreatedDespawnTarget(int prefabHashHint, ZDO? zdo) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) if (DropNSpawnPlugin.IsRuntimeServer() && PluginSettingsFacade.IsCharacterDomainEnabled() && zdo != null && !((ZDOID)(ref zdo.m_uid)).IsNone()) { int num; int authoritativePrefabHash = (num = zdo.GetPrefab()); if (num == 0) { num = prefabHashHint; } if (GetCreatedZdoObservationDecision(authoritativePrefabHash, prefabHashHint) == CreatedZdoObservationDecision.Ineligible) { RecordSkippedIneligibleProducer(DespawnProducerSkipSource.CreatedZdo); return; } EnqueueDespawnObservation(new PendingDespawnObservation(zdo.m_uid, num, "", DespawnObservationSource.CreatedZdo)); _createdZdoProducerQueuedCount++; } } private static void ApplyPendingDespawnObservations() { //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) if (PendingDespawnObservations.Count == 0 || (Object)(object)ZNetScene.instance == (Object)null || (Object)(object)ObjectDB.instance == (Object)null || ZDOMan.instance == null) { return; } float time = Time.time; PendingDespawnObservationRemovals.Clear(); PendingDespawnObservationUpdates.Clear(); foreach (PendingDespawnObservation value in PendingDespawnObservations.Values) { if (value.NextAttemptAt > time) { continue; } ZDO zDO = ZDOMan.instance.GetZDO(value.ZdoId); if (zDO == null || IsDeadZdo(value.ZdoId)) { PendingDespawnObservationRemovals.Add(value.ZdoId); continue; } PendingDespawnObservation updatedObservation; ObservationApplicationResult observationApplicationResult = ApplyQueuedObservation(value, zDO, time, out updatedObservation); switch (observationApplicationResult) { case ObservationApplicationResult.Applied: case ObservationApplicationResult.Dropped: PendingDespawnObservationRemovals.Add(value.ZdoId); break; case ObservationApplicationResult.Deferred: PendingDespawnObservationUpdates.Add(updatedObservation); break; default: throw new ArgumentOutOfRangeException("applyResult", observationApplicationResult, null); } } foreach (PendingDespawnObservation pendingDespawnObservationUpdate in PendingDespawnObservationUpdates) { PendingDespawnObservations[pendingDespawnObservationUpdate.ZdoId] = pendingDespawnObservationUpdate; } foreach (ZDOID pendingDespawnObservationRemoval in PendingDespawnObservationRemovals) { PendingDespawnObservations.Remove(pendingDespawnObservationRemoval); } PendingDespawnObservationRemovals.Clear(); PendingDespawnObservationUpdates.Clear(); } private static void ApplyPendingDespawnDetaches(double nowSeconds) { //IL_0059: 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_0069: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) if (PendingDespawnDetachPersists.Count == 0 || (Object)(object)ZNetScene.instance == (Object)null || (Object)(object)ObjectDB.instance == (Object)null || ZDOMan.instance == null) { return; } PendingDespawnDetachPersistRemovals.Clear(); foreach (PendingDespawnDetachPersist value in PendingDespawnDetachPersists.Values) { ZDO zDO = ZDOMan.instance.GetZDO(value.ZdoId); if (zDO == null || IsDeadZdo(value.ZdoId)) { PendingDespawnDetachPersistRemovals.Add(value.ZdoId); continue; } PendingDespawnDetachPersistRemovals.Add(value.ZdoId); ApplyDetachPersist(value, zDO, nowSeconds); } foreach (ZDOID pendingDespawnDetachPersistRemoval in PendingDespawnDetachPersistRemovals) { PendingDespawnDetachPersists.Remove(pendingDespawnDetachPersistRemoval); } PendingDespawnDetachPersistRemovals.Clear(); } internal static void TryPersistDespawnCountdownBeforeResetZdo(ZNetView? nview) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) Character val = default(Character); if (!DropNSpawnPlugin.IsRuntimeServer() || !PluginSettingsFacade.IsCharacterDomainEnabled() || (Object)(object)nview == (Object)null || !nview.IsValid() || !((Component)nview).TryGetComponent(ref val) || val.GetHealth() <= 0f) { return; } ZDO zDO = nview.GetZDO(); if (zDO != null) { if (!ShouldQueueDespawnObservation(zDO.GetPrefab(), Utils.GetPrefabName(((Component)val).gameObject))) { RecordSkippedIneligibleProducer(DespawnProducerSkipSource.DetachPersist); } else { PendingDespawnDetachPersists[zDO.m_uid] = new PendingDespawnDetachPersist(zDO.m_uid, val.GetCenterPoint(), zDO.GetPrefab(), Utils.GetPrefabName(((Component)val).gameObject)); } } } internal static void TryTrackLoadedDespawnTarget(Character? character) { //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) if (!DropNSpawnPlugin.IsRuntimeServer() || !PluginSettingsFacade.IsCharacterDomainEnabled()) { return; } _loadedCharacterProducerAttemptCount++; if ((Object)(object)character == (Object)null || (Object)(object)((Component)character).gameObject == (Object)null) { _loadedCharacterProducerMissingCharacterCount++; return; } if (character.IsDead()) { _loadedCharacterProducerDeadCharacterCount++; return; } ZNetView component = ((Component)character).GetComponent(); string prefabName = Utils.GetPrefabName(((Component)character).gameObject); if ((Object)(object)component == (Object)null) { _loadedCharacterProducerMissingNviewCount++; return; } if (!component.IsValid()) { _loadedCharacterProducerInvalidNviewCount++; return; } ZDO zDO = component.GetZDO(); if (zDO == null) { _loadedCharacterProducerMissingZdoCount++; return; } if (IsDeadZdo(zDO.m_uid)) { _loadedCharacterProducerDeadZdoCount++; return; } if (string.IsNullOrWhiteSpace(prefabName)) { _loadedCharacterProducerMissingPrefabNameCount++; return; } if (!ShouldQueueDespawnObservation(zDO.GetPrefab(), prefabName)) { RecordSkippedIneligibleProducer(DespawnProducerSkipSource.LoadedCharacter); return; } EnqueueDespawnObservation(new PendingDespawnObservation(zDO.m_uid, zDO.GetPrefab(), prefabName, DespawnObservationSource.LoadedCharacter)); _loadedCharacterProducerQueuedCount++; LogDiagnostics($"Queued loaded character observation for despawn tracking zdo={zDO.m_uid} prefab={prefabName} prefabHash={zDO.GetPrefab()}."); } private static void ProcessTrackedDespawnTarget(ZDOID zdoId, ZDO zdo, TrackedDespawnState state, double nowSeconds) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_02e4: Unknown result type (might be due to invalid IL or missing references) //IL_0298: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_021b: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_0249: Unknown result type (might be due to invalid IL or missing references) Character val = TryGetLoadedTrackedCharacter(zdo); if ((Object)(object)val != (Object)null && val.GetHealth() <= 0f) { LogDiagnostics($"Dropping tracked despawn target zdo={zdoId} because loaded character is already dead."); PendingDespawnRemovals.Add(zdoId); return; } float effectiveRange = state.GetEffectiveRange(); float effectiveDelaySeconds = state.GetEffectiveDelaySeconds(); if (effectiveRange <= 0f) { state.ResetCountdown(); ScheduleTrackedDespawnCheck(zdoId, state, nowSeconds + GetIdleCheckIntervalSeconds()); return; } Vector3 val2 = (((Object)(object)val != (Object)null) ? val.GetCenterPoint() : zdo.GetPosition()); if (SceneProximityQueries.TryFindAnyLivingPlayerInRangeXZ(val2, effectiveRange, out var playerId)) { if (playerId != 0L) { state.LastInterestedPlayerId = playerId; } if (state.NoPlayerSince >= 0.0) { long num = playerId; if (SceneProximityQueries.TryFindNearestLivingPlayerInRangeXZ(val2, effectiveRange, out var playerId2)) { num = playerId2; } SendDespawnMessage(num, BuildDespawnCanceledMessage(state.DisplayName)); LogDiagnostics($"Canceled despawn countdown zdo={zdoId} name={state.DisplayName} recipient={num} position={FormatPosition(val2)}."); } state.ResetCountdown(); ScheduleTrackedDespawnCheck(zdoId, state, nowSeconds + GetIdleCheckIntervalSeconds()); return; } if (state.NoPlayerSince < 0.0) { StartDespawnCountdown(state, nowSeconds, effectiveDelaySeconds); LogDiagnostics($"Started despawn countdown zdo={zdoId} name={state.DisplayName} delay={effectiveDelaySeconds:0.##} loaded={(Object)(object)val != (Object)null} position={FormatPosition(val2)}."); } double num2 = nowSeconds - state.NoPlayerSince; if (num2 >= (double)effectiveDelaySeconds) { LogDiagnostics($"Expiring despawn countdown zdo={zdoId} name={state.DisplayName} elapsed={num2:0.##} delay={effectiveDelaySeconds:0.##} loaded={(Object)(object)val != (Object)null} refunds={state.Refunds.Count} position={FormatPosition(val2)}."); if (!CharacterDropManager.TryExecuteConfiguredDespawnRefunds(val2, state.Refunds) && PluginSettingsFacade.IsDespawnDiagnosticsEnabled()) { LogDiagnostics($"Configured despawn refund execution failed zdo={zdoId} name={state.DisplayName} position={val2.x:F1},{val2.y:F1},{val2.z:F1} refunds={state.Refunds.Count}."); } DespawnCleanupSupport.ApplyBeforeDestroy(zdo); zdo.SetOwner(ZDOMan.instance.m_sessionID); ZDOMan.instance.DestroyZDO(zdo); PendingDespawnRemovals.Add(zdoId); } else { int remainingSeconds = GetRemainingSeconds(effectiveDelaySeconds, num2); if (state.CountdownRecipientPlayerId != 0L && remainingSeconds != state.LastAnnouncedRemainingSeconds && ShouldAnnounceDespawnRemaining(remainingSeconds)) { SendDespawnMessage(state.CountdownRecipientPlayerId, BuildDespawnReminderMessage(state.DisplayName, remainingSeconds)); state.LastAnnouncedRemainingSeconds = remainingSeconds; } ScheduleTrackedDespawnCheck(zdoId, state, nowSeconds + GetCountdownCheckIntervalSeconds()); } } private static void PruneTrackedDespawnTargetsAgainstCurrentConfig() { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) if (TrackedDespawnTargets.Count == 0) { return; } foreach (var (val2, trackedDespawnState2) in TrackedDespawnTargets) { if (!string.IsNullOrWhiteSpace(trackedDespawnState2.PrefabName) && !CharacterDropManager.TryResolveDespawnTrackingRule(trackedDespawnState2.PrefabName, out float? _, out float? _, out IReadOnlyCollection _)) { PendingDespawnRemovals.Add(val2); LogDiagnostics($"Stopped tracking despawn target because prefab '{trackedDespawnState2.PrefabName}' is no longer eligible under current despawn config zdo={val2}."); } } FlushPendingDespawnRemovals(); } private static void QueueBootstrapScanDespawnObservations(string prefabName) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrWhiteSpace(prefabName) || ZDOMan.instance == null) { return; } BootstrapScanBuffer.Clear(); int num = 0; while (!ZDOMan.instance.GetAllZDOsWithPrefabIterative(prefabName, BootstrapScanBuffer, ref num)) { } foreach (ZDO item in BootstrapScanBuffer) { if (item != null && !((ZDOID)(ref item.m_uid)).IsNone()) { EnqueueDespawnObservation(new PendingDespawnObservation(item.m_uid, item.GetPrefab(), prefabName, DespawnObservationSource.BootstrapScan)); } } } private static void EnqueueDespawnObservation(PendingDespawnObservation observation) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) ZDOID zdoId = observation.ZdoId; if (!((ZDOID)(ref zdoId)).IsNone()) { if (!PendingDespawnObservations.TryGetValue(observation.ZdoId, out var value)) { PendingDespawnObservations[observation.ZdoId] = observation; } else { PendingDespawnObservations[observation.ZdoId] = MergeDespawnObservation(value, observation); } } } private static PendingDespawnObservation MergeDespawnObservation(PendingDespawnObservation current, PendingDespawnObservation incoming) { //IL_00c7: Unknown result type (might be due to invalid IL or missing references) PendingDespawnObservation pendingDespawnObservation = ((GetObservationPriority(incoming.Source) >= GetObservationPriority(current.Source)) ? incoming : current); int prefabHashHint = ((incoming.PrefabHashHint != 0) ? incoming.PrefabHashHint : current.PrefabHashHint); string prefabNameHint = ((!string.IsNullOrWhiteSpace(incoming.PrefabNameHint)) ? incoming.PrefabNameHint : current.PrefabNameHint); float nextAttemptAt = ((pendingDespawnObservation.Source == DespawnObservationSource.CreatedZdo) ? Mathf.Max(current.NextAttemptAt, incoming.NextAttemptAt) : 0f); float expireAt = ((pendingDespawnObservation.Source == DespawnObservationSource.CreatedZdo) ? Mathf.Max(current.ExpireAt, incoming.ExpireAt) : 0f); int retryCount = ((pendingDespawnObservation.Source == DespawnObservationSource.CreatedZdo) ? Math.Max(current.RetryCount, incoming.RetryCount) : 0); return new PendingDespawnObservation(pendingDespawnObservation.ZdoId, prefabHashHint, prefabNameHint, pendingDespawnObservation.Source, nextAttemptAt, expireAt, retryCount); } private static int GetObservationPriority(DespawnObservationSource source) { return source switch { DespawnObservationSource.LoadedCharacter => 3, DespawnObservationSource.CreatedZdo => 2, _ => 1, }; } private static string DescribeObservationSource(DespawnObservationSource source) { return source switch { DespawnObservationSource.LoadedCharacter => "loaded character", DespawnObservationSource.CreatedZdo => "created ZDO", _ => "bootstrap scan", }; } private static ObservationApplicationResult ApplyQueuedObservation(PendingDespawnObservation observation, ZDO zdo, float nowRealtime, out PendingDespawnObservation updatedObservation) { updatedObservation = observation; if (ApplyObservation(observation, zdo) != null) { return ObservationApplicationResult.Applied; } if (TryDeferCreatedZdoObservation(observation, zdo, nowRealtime, out updatedObservation)) { return ObservationApplicationResult.Deferred; } return ObservationApplicationResult.Dropped; } private static TrackedDespawnState? ApplyObservation(PendingDespawnObservation observation, ZDO zdo) { return ApplyObservation(zdo, observation.PrefabHashHint, observation.PrefabNameHint, DescribeObservationSource(observation.Source)); } private static TrackedDespawnState? ApplyObservation(ZDO zdo, int prefabHashHint, string prefabNameHint, string source) { if (!TryResolveObservationConfig(zdo, prefabHashHint, prefabNameHint, out string prefabName, out float? rangeOverride, out float? delayOverride, out IReadOnlyCollection refunds)) { return null; } return ApplyObservationResolved(prefabName, zdo, rangeOverride, delayOverride, refunds, source); } private static bool TryResolveObservationConfig(ZDO zdo, int prefabHashHint, string prefabNameHint, out string prefabName, out float? rangeOverride, out float? delayOverride, out IReadOnlyCollection refunds) { prefabName = (string.IsNullOrWhiteSpace(prefabNameHint) ? "" : prefabNameHint); rangeOverride = null; delayOverride = null; refunds = (IReadOnlyCollection)(object)Array.Empty(); int num = zdo.GetPrefab(); if (num == 0) { num = prefabHashHint; } if (num != 0 && CharacterDropManager.TryResolveDespawnTrackingRule(num, out string prefabName2, out rangeOverride, out delayOverride, out refunds)) { prefabName = ((!string.IsNullOrWhiteSpace(prefabName2)) ? prefabName2 : prefabName); return !string.IsNullOrWhiteSpace(prefabName); } if (!string.IsNullOrWhiteSpace(prefabName) && CharacterDropManager.TryResolveDespawnTrackingRule(prefabName, out rangeOverride, out delayOverride, out refunds)) { return true; } return false; } private static TrackedDespawnState ApplyObservationResolved(string prefabName, ZDO zdo, float? rangeOverride, float? delayOverride, IReadOnlyCollection refunds, string source) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) bool num = TrackedDespawnTargets.ContainsKey(zdo.m_uid); TrackedDespawnState orCreateTrackedDespawnState = GetOrCreateTrackedDespawnState(zdo.m_uid); Character val = TryGetLoadedTrackedCharacter(zdo); if ((Object)(object)val != (Object)null) { orCreateTrackedDespawnState.UpdateFromCharacter(val, rangeOverride, delayOverride, refunds); PrimeTrackedDespawnInterestIfNeeded(orCreateTrackedDespawnState, val.GetCenterPoint()); } else { orCreateTrackedDespawnState.UpdateFromZdoPrefab(prefabName, rangeOverride, delayOverride, refunds); PrimeTrackedDespawnInterestIfNeeded(orCreateTrackedDespawnState, zdo.GetPosition()); } if (!num) { LogDiagnostics($"Tracking despawn target from {source} zdo={zdo.m_uid} name={orCreateTrackedDespawnState.DisplayName} prefab={prefabName} loaded={(Object)(object)val != (Object)null} refunds={orCreateTrackedDespawnState.Refunds.Count} position={FormatPosition(zdo.GetPosition())}."); } ScheduleTrackedDespawnCheck(zdo.m_uid, orCreateTrackedDespawnState, GetCurrentDespawnClockSeconds()); return orCreateTrackedDespawnState; } private static void ApplyDetachPersist(PendingDespawnDetachPersist persist, ZDO zdo, double nowSeconds) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) TrackedDespawnState trackedDespawnState = ApplyObservation(new PendingDespawnObservation(persist.ZdoId, persist.PrefabHashHint, persist.PrefabNameHint, DespawnObservationSource.LoadedCharacter), zdo); if (trackedDespawnState == null) { return; } float effectiveRange = trackedDespawnState.GetEffectiveRange(); if (!(effectiveRange <= 0f)) { if (SceneProximityQueries.TryFindAnyLivingPlayerInRangeXZ(persist.ProbePoint, effectiveRange, out var playerId)) { trackedDespawnState.LastInterestedPlayerId = playerId; } else if (!(trackedDespawnState.NoPlayerSince >= 0.0)) { float effectiveDelaySeconds = trackedDespawnState.GetEffectiveDelaySeconds(); StartDespawnCountdown(trackedDespawnState, nowSeconds, effectiveDelaySeconds); ScheduleTrackedDespawnCheck(persist.ZdoId, trackedDespawnState, nowSeconds); LogDiagnostics($"Started despawn countdown from ResetZDO path zdo={persist.ZdoId} name={trackedDespawnState.DisplayName} range={effectiveRange:0.##} delay={effectiveDelaySeconds:0.##} position={FormatPosition(persist.ProbePoint)}."); } } } private static void StartDespawnCountdown(TrackedDespawnState state, double nowSeconds, float despawnDelaySeconds) { state.NoPlayerSince = nowSeconds; state.CountdownRecipientPlayerId = GetCountdownRecipientPlayerId(state); state.LastAnnouncedRemainingSeconds = GetRemainingSeconds(despawnDelaySeconds, 0.0); if (state.CountdownRecipientPlayerId == 0L) { LogDiagnostics($"Started despawn countdown without message recipients name={state.DisplayName} prefab={state.PrefabName} delay={despawnDelaySeconds:0.##}."); } if (despawnDelaySeconds > 0f && state.CountdownRecipientPlayerId != 0L) { SendDespawnMessage(state.CountdownRecipientPlayerId, BuildDespawnStartMessage(state.DisplayName, state.LastAnnouncedRemainingSeconds)); } } private static void PrimeTrackedDespawnInterestIfNeeded(TrackedDespawnState state, Vector3 point) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) if (!(state.NoPlayerSince >= 0.0) && state.LastInterestedPlayerId == 0L) { float effectiveRange = state.GetEffectiveRange(); if (!(effectiveRange <= 0f) && SceneProximityQueries.TryFindAnyLivingPlayerInRangeXZ(point, effectiveRange, out var playerId)) { state.LastInterestedPlayerId = playerId; LogDiagnostics($"Primed despawn message recipient name={state.DisplayName} recipient={playerId} position={FormatPosition(point)}."); } } } private static long GetCountdownRecipientPlayerId(TrackedDespawnState state) { long lastInterestedPlayerId = state.LastInterestedPlayerId; if (!IsDespawnMessageRecipientAvailable(lastInterestedPlayerId)) { return 0L; } return lastInterestedPlayerId; } private static void FlushPendingDespawnRemovals() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) if (PendingDespawnRemovals.Count == 0) { return; } foreach (ZDOID pendingDespawnRemoval in PendingDespawnRemovals) { if (TrackedDespawnTargets.TryGetValue(pendingDespawnRemoval, out TrackedDespawnState value)) { value.ScheduledCheckAtBucket = long.MinValue; } TrackedDespawnTargets.Remove(pendingDespawnRemoval); } PendingDespawnRemovals.Clear(); } private static TrackedDespawnState GetOrCreateTrackedDespawnState(ZDOID zdoId) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) if (!TrackedDespawnTargets.TryGetValue(zdoId, out TrackedDespawnState value)) { value = new TrackedDespawnState(); TrackedDespawnTargets[zdoId] = value; } return value; } private static Character? TryGetLoadedTrackedCharacter(ZDO zdo) { if ((Object)(object)ZNetScene.instance == (Object)null || !ZNetScene.instance.m_instances.TryGetValue(zdo, out var value) || (Object)(object)value == (Object)null || (Object)(object)((Component)value).gameObject == (Object)null) { return null; } return ((Component)value).GetComponent(); } private static bool IsDeadZdo(ZDOID zdoId) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) if (ZDOMan.instance != null) { return ZDOMan.instance.m_deadZDOs.ContainsKey(zdoId); } return false; } private static int GetRemainingSeconds(float despawnDelaySeconds, double elapsedSeconds) { float num = Mathf.Max(0f, despawnDelaySeconds - (float)elapsedSeconds); return Mathf.Max(0, Mathf.CeilToInt(num)); } private static void ScheduleTrackedDespawnCheck(ZDOID zdoId, TrackedDespawnState state, double scheduledTime) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) long key = (state.ScheduledCheckAtBucket = QuantizeScheduledCheck(scheduledTime)); if (!ScheduledDespawnChecks.TryGetValue(key, out List value)) { value = new List(); ScheduledDespawnChecks[key] = value; } value.Add(zdoId); } private static CreatedZdoObservationDecision GetCreatedZdoObservationDecision(int authoritativePrefabHash, int prefabHashHint) { if (!CharacterDropManager.IsDespawnTrackingRuleLookupReady()) { return CreatedZdoObservationDecision.Eligible; } if (authoritativePrefabHash != 0) { if (!CharacterDropManager.IsEligibleDespawnTrackingPrefabHash(authoritativePrefabHash)) { return CreatedZdoObservationDecision.Ineligible; } return CreatedZdoObservationDecision.Eligible; } if (prefabHashHint != 0 && CharacterDropManager.IsEligibleDespawnTrackingPrefabHash(prefabHashHint)) { return CreatedZdoObservationDecision.Eligible; } return CreatedZdoObservationDecision.Unknown; } private static bool ShouldQueueDespawnObservation(int prefabHashHint, string prefabNameHint) { if (!CharacterDropManager.IsDespawnTrackingRuleLookupReady()) { return true; } if (prefabHashHint != 0 && CharacterDropManager.IsEligibleDespawnTrackingPrefabHash(prefabHashHint)) { return true; } if (!string.IsNullOrWhiteSpace(prefabNameHint)) { return CharacterDropManager.IsEligibleDespawnTrackingPrefabName(prefabNameHint); } return false; } private static bool TryDeferCreatedZdoObservation(PendingDespawnObservation observation, ZDO zdo, float nowRealtime, out PendingDespawnObservation deferredObservation) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) deferredObservation = observation; if (observation.Source != DespawnObservationSource.CreatedZdo || zdo.GetPrefab() != 0) { return false; } float num = ((observation.ExpireAt > 0f) ? observation.ExpireAt : (nowRealtime + 1f)); if (nowRealtime >= num) { _createdZdoProducerDeferredExpiredCount++; return false; } deferredObservation = new PendingDespawnObservation(observation.ZdoId, observation.PrefabHashHint, observation.PrefabNameHint, observation.Source, nowRealtime + 0.25f, num, observation.RetryCount + 1); if (observation.RetryCount == 0) { _createdZdoProducerDeferredCount++; } return true; } private static void RecordSkippedIneligibleProducer(DespawnProducerSkipSource source) { switch (source) { case DespawnProducerSkipSource.CreatedZdo: _skippedCreatedZdoProducerCount++; break; case DespawnProducerSkipSource.LoadedCharacter: _skippedLoadedCharacterProducerCount++; break; case DespawnProducerSkipSource.DetachPersist: _skippedDetachPersistProducerCount++; break; default: throw new ArgumentOutOfRangeException("source", source, null); } } private static void ProcessSkippedIneligibleProducerDiagnostics(float nowRealtime) { if (!PluginSettingsFacade.IsDespawnDiagnosticsEnabled()) { ResetSkippedIneligibleProducerDiagnostics(); _nextIneligibleProducerSummaryAt = nowRealtime + 5f; } else if (_nextIneligibleProducerSummaryAt <= 0f) { _nextIneligibleProducerSummaryAt = nowRealtime + 5f; } else { if (_nextIneligibleProducerSummaryAt > nowRealtime) { return; } _nextIneligibleProducerSummaryAt = nowRealtime + 5f; int num = _skippedCreatedZdoProducerCount + _skippedLoadedCharacterProducerCount + _skippedDetachPersistProducerCount; bool flag = _createdZdoProducerQueuedCount > 0 || _createdZdoProducerDeferredCount > 0 || _createdZdoProducerDeferredExpiredCount > 0; if (num > 0 || flag || _loadedCharacterProducerAttemptCount > 0) { if (flag) { LogDiagnostics($"Created-ZDO despawn producer over the last {5f:0.#}s: queued={_createdZdoProducerQueuedCount} deferred={_createdZdoProducerDeferredCount} expired={_createdZdoProducerDeferredExpiredCount} ineligible={_skippedCreatedZdoProducerCount}."); } if (num > 0) { LogDiagnostics($"Skipped ineligible despawn producer candidates over the last {5f:0.#}s: createdZdo={_skippedCreatedZdoProducerCount} loadedCharacter={_skippedLoadedCharacterProducerCount} resetZdo={_skippedDetachPersistProducerCount}."); } if (_loadedCharacterProducerAttemptCount > 0) { LogDiagnostics($"Loaded-character despawn producer over the last {5f:0.#}s: attempts={_loadedCharacterProducerAttemptCount} queued={_loadedCharacterProducerQueuedCount} missingCharacter={_loadedCharacterProducerMissingCharacterCount} deadCharacter={_loadedCharacterProducerDeadCharacterCount} nviewMissing={_loadedCharacterProducerMissingNviewCount} nviewInvalid={_loadedCharacterProducerInvalidNviewCount} zdoMissing={_loadedCharacterProducerMissingZdoCount} deadZdo={_loadedCharacterProducerDeadZdoCount} prefabMissing={_loadedCharacterProducerMissingPrefabNameCount} ineligible={_skippedLoadedCharacterProducerCount}."); } ResetSkippedIneligibleProducerDiagnostics(); } } } private static void ResetSkippedIneligibleProducerDiagnostics() { _nextIneligibleProducerSummaryAt = 0f; _createdZdoProducerQueuedCount = 0; _createdZdoProducerDeferredCount = 0; _createdZdoProducerDeferredExpiredCount = 0; _skippedCreatedZdoProducerCount = 0; _skippedLoadedCharacterProducerCount = 0; _skippedDetachPersistProducerCount = 0; _loadedCharacterProducerAttemptCount = 0; _loadedCharacterProducerQueuedCount = 0; _loadedCharacterProducerMissingCharacterCount = 0; _loadedCharacterProducerDeadCharacterCount = 0; _loadedCharacterProducerMissingNviewCount = 0; _loadedCharacterProducerInvalidNviewCount = 0; _loadedCharacterProducerMissingZdoCount = 0; _loadedCharacterProducerDeadZdoCount = 0; _loadedCharacterProducerMissingPrefabNameCount = 0; } private static long QuantizeScheduledCheck(double scheduledTime) { return Math.Max(0L, (long)Math.Ceiling(scheduledTime * 1000.0)); } private static double GetIdleCheckIntervalSeconds() { return 1.0; } private static double GetCountdownCheckIntervalSeconds() { return 0.5; } private static double GetCurrentDespawnClockSeconds() { ZNet instance = ZNet.instance; if (instance == null) { return Time.time; } return instance.GetTimeSeconds(); } private static bool ShouldAnnounceDespawnRemaining(int remainingSeconds) { if (remainingSeconds <= 0) { return false; } if (remainingSeconds <= 5) { return true; } return remainingSeconds % 5 == 0; } private static void SendDespawnMessage(long playerId, string message) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) if (playerId == 0L || string.IsNullOrWhiteSpace(message)) { return; } if (DropNSpawnPlugin.IsRuntimeServer()) { if (!TrySendServerDespawnMessage(playerId, message)) { Player player = Player.GetPlayer(playerId); if ((Object)(object)player == (Object)null) { LogDiagnostics($"Message skipped because server recipient could not be resolved. recipientId={playerId} message='{message}'."); return; } LogDiagnostics($"Message server fallback delivered locally. recipientId={playerId} name='{player.GetPlayerName()}' characterId={((Character)player).GetZDOID()} message='{message}'."); ((Character)player).Message((MessageType)1, message, 0, (Sprite)null); } return; } Player player2 = Player.GetPlayer(playerId); if ((Object)(object)player2 == (Object)null) { LogDiagnostics($"Message skipped because recipient player could not be resolved. playerId={playerId} message='{message}'."); } else if ((Object)(object)((Component)player2).gameObject == (Object)null || ((Character)player2).IsDead()) { LogDiagnostics($"Message skipped because recipient player is unavailable. playerId={playerId} name='{player2.GetPlayerName()}' dead={((Character)player2).IsDead()} message='{message}'."); } else { LogDiagnostics($"Message delivered locally. playerId={playerId} name='{player2.GetPlayerName()}' characterId={((Character)player2).GetZDOID()} message='{message}'."); ((Character)player2).Message((MessageType)1, message, 0, (Sprite)null); } } private static bool IsDespawnMessageRecipientAvailable(long recipientId) { if (recipientId == 0L) { return false; } if (DropNSpawnPlugin.IsRuntimeServer()) { if (IsValidMessageTargetPeerId(recipientId)) { return true; } Player player = Player.GetPlayer(recipientId); long targetPeerId; string resolutionSource; if ((Object)(object)player != (Object)null) { return TryResolveMessageTargetPeerId(player, out targetPeerId, out resolutionSource); } return false; } Player player2 = Player.GetPlayer(recipientId); if ((Object)(object)player2 != (Object)null && (Object)(object)((Component)player2).gameObject != (Object)null) { return !((Character)player2).IsDead(); } return false; } private static bool TrySendServerDespawnMessage(long recipientId, string message) { //IL_0136: Unknown result type (might be due to invalid IL or missing references) if (ZRoutedRpc.instance == null) { return false; } if (IsValidMessageTargetPeerId(recipientId)) { string text = ResolveRecipientName(recipientId); int num; if (recipientId != ZNet.GetUID()) { ZNet instance = ZNet.instance; if (instance == null) { num = 0; } else { ZNetPeer peer = instance.GetPeer(recipientId); num = (((peer != null) ? new bool?(peer.IsReady()) : null).GetValueOrDefault() ? 1 : 0); } } else { num = 1; } bool flag = (byte)num != 0; LogDiagnostics($"Sending ShowMessage RPC. recipientId={recipientId} name='{text}' peerReady={flag} via=recipientId message='{message}'."); ZRoutedRpc.instance.InvokeRoutedRPC(recipientId, "ShowMessage", new object[2] { 1, message }); return true; } Player player = Player.GetPlayer(recipientId); if ((Object)(object)player != (Object)null && TryResolveMessageTargetPeerId(player, out long targetPeerId, out string resolutionSource)) { int num2; if (targetPeerId != ZNet.GetUID()) { ZNet instance2 = ZNet.instance; if (instance2 == null) { num2 = 0; } else { ZNetPeer peer2 = instance2.GetPeer(targetPeerId); num2 = (((peer2 != null) ? new bool?(peer2.IsReady()) : null).GetValueOrDefault() ? 1 : 0); } } else { num2 = 1; } bool flag2 = (byte)num2 != 0; LogDiagnostics($"Sending ShowMessage RPC. recipientId={recipientId} name='{player.GetPlayerName()}' characterId={((Character)player).GetZDOID()} targetPeerId={targetPeerId} peerReady={flag2} via={resolutionSource} message='{message}'."); ZRoutedRpc.instance.InvokeRoutedRPC(targetPeerId, "ShowMessage", new object[2] { 1, message }); return true; } return false; } private static bool TryResolveMessageTargetPeerId(Player player, out long targetPeerId, out string resolutionSource) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) targetPeerId = 0L; resolutionSource = "none"; if ((Object)(object)player == (Object)null) { return false; } ZDOID zDOID = ((Character)player).GetZDOID(); long userID = ((ZDOID)(ref zDOID)).UserID; if (IsValidMessageTargetPeerId(userID)) { targetPeerId = userID; resolutionSource = "characterZdoUserId"; return true; } ZNet instance = ZNet.instance; List list = ((instance != null) ? instance.GetPeers() : null); if (list != null) { foreach (ZNetPeer item in list) { if (item != null && item.IsReady() && item.m_characterID == zDOID) { targetPeerId = item.m_uid; resolutionSource = "peerCharacterId"; return true; } } } string playerName = player.GetPlayerName(); if (!string.IsNullOrWhiteSpace(playerName)) { ZNet instance2 = ZNet.instance; ZNetPeer val = ((instance2 != null) ? instance2.GetPeerByPlayerName(playerName) : null); if (val != null && val.IsReady()) { targetPeerId = val.m_uid; resolutionSource = "playerName"; return true; } } return false; } private static bool IsValidMessageTargetPeerId(long peerId) { if (peerId == 0L) { return false; } if (peerId == ZNet.GetUID()) { return true; } ZNet instance = ZNet.instance; if (instance == null) { return false; } ZNetPeer peer = instance.GetPeer(peerId); return ((peer != null) ? new bool?(peer.IsReady()) : null).GetValueOrDefault(); } private static string ResolveRecipientName(long recipientId) { if (recipientId == ZNet.GetUID()) { if (!((Object)(object)Player.m_localPlayer != (Object)null)) { return "local"; } return Player.m_localPlayer.GetPlayerName(); } ZNet instance = ZNet.instance; ZNetPeer val = ((instance != null) ? instance.GetPeer(recipientId) : null); if (val != null && !string.IsNullOrWhiteSpace(val.m_playerName)) { return val.m_playerName; } return recipientId.ToString(); } private static string BuildDespawnStartMessage(string displayName, int remainingSeconds) { return $"{displayName} will despawn in {remainingSeconds}s unless someone returns."; } private static string BuildDespawnReminderMessage(string displayName, int remainingSeconds) { return $"{displayName} will despawn in {remainingSeconds}s."; } private static string BuildDespawnCanceledMessage(string displayName) { return displayName + " despawn canceled."; } private static string GetDisplayName(Character? character) { if ((Object)(object)character == (Object)null) { return "Target"; } string hoverName = character.GetHoverName(); if (!string.IsNullOrWhiteSpace(hoverName)) { return hoverName; } if (!string.IsNullOrWhiteSpace(character.m_name)) { if (Localization.instance == null) { return character.m_name; } return Localization.instance.Localize(character.m_name); } if (!((Object)(object)((Component)character).gameObject != (Object)null) || string.IsNullOrWhiteSpace(((Object)((Component)character).gameObject).name)) { return "Target"; } return ((Object)((Component)character).gameObject).name; } internal static bool IsManagedDespawnMessage(string? message) { if (string.IsNullOrWhiteSpace(message)) { return false; } if (!message.Contains(" will despawn in ", StringComparison.OrdinalIgnoreCase)) { return message.Contains(" despawn canceled.", StringComparison.OrdinalIgnoreCase); } return true; } internal static void LogDiagnostics(string message) { if (PluginSettingsFacade.IsDespawnDiagnosticsEnabled()) { DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)("[Despawn] " + message)); } } private static string FormatPosition(Vector3 position) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) return $"{position.x:0.##},{position.y:0.##},{position.z:0.##}"; } } internal static class DespawnCleanupSupport { internal static void ApplyBeforeDestroy(ZDO zdo) { TryClearActiveBossCountForDespawnedZdo(zdo); } private static void TryClearActiveBossCountForDespawnedZdo(ZDO zdo) { if (!((Object)(object)ZoneSystem.instance == (Object)null) && zdo.GetBool("bosscount", false)) { float num = default(float); ZoneSystem.instance.GetGlobalKey((GlobalKeys)38, ref num); ZoneSystem.instance.SetGlobalKey((GlobalKeys)38, Mathf.Max(0f, num - 1f)); zdo.Set("bosscount", false); } } } internal abstract class DomainTransportHooks { private sealed class NoOpDomainTransportHooks : DomainTransportHooks { } internal static DomainTransportHooks NoOp { get; } = new NoOpDomainTransportHooks(); internal virtual void OnTransportStateReset() { } internal virtual void OnManifestSeen(bool isEmpty, string manifestHash, int compressedSize, int chunkCount, int? entryCount) { } internal virtual void OnPayloadReady(string hash, int? entryCount, string successLogMessage, string desiredManifestHash, int? desiredEntryCount) { } } internal static class BossRulesConfig { private const float SameBossDuplicateBlockRadius = 64f; private static ConfigEntry _enableSameBossDuplicateBlock; internal static void Bind(DropNSpawnPlugin plugin) { PluginBoundSettings.EnableBossTamedPressure = plugin.BindConfigEntry("2 - Boss", "Enable Boss Tamed Pressure", DropNSpawnPlugin.Toggle.Off, "If on, character.yml bossTamedPressure entries can apply periodic damage and combat damage multipliers to tamed MonsterAI creatures near configured boss prefabs. If off, configured bossTamedPressure YAML stays on disk but no pressure scan, damage, or multiplier flags are applied.", synchronizedSetting: true, 200); _enableSameBossDuplicateBlock = plugin.BindConfigEntry("2 - Boss", "Enable Same Boss Duplicate Block", DropNSpawnPlugin.Toggle.On, $"If on, OfferingBowl and CreatureSpawner both block new spawns when the same boss prefab already exists within {64f:0} horizontal XZ meters of the altar or spawner. Applies only when the target prefab is marked as a boss.", synchronizedSetting: true, 100); } internal static float GetSameBossDuplicateBlockRadius() { ConfigEntry enableSameBossDuplicateBlock = _enableSameBossDuplicateBlock; if (enableSameBossDuplicateBlock == null || enableSameBossDuplicateBlock.Value != 0) { return 64f; } return 0f; } } internal static class DespawnRulesConfig { private static ConfigEntry _defaultDespawnRange; private static ConfigEntry _defaultDespawnDelaySeconds; internal static void Bind(DropNSpawnPlugin plugin) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Expected O, but got Unknown _defaultDespawnRange = plugin.BindConfigEntry("3 - Character", "Default Despawn Range", 64f, new ConfigDescription("Default horizontal XZ range used by character.yml despawn rules when an entry omits despawn.range. Also applies automatically to boss prefabs auto-detected from the server prefab catalog when no explicit character.yml despawn rule exists. If 0, despawn countdowns are disabled unless a prefab entry overrides range.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 128f), Array.Empty())); _defaultDespawnDelaySeconds = plugin.BindConfigEntry("3 - Character", "Default Despawn Delay Seconds", 60f, new ConfigDescription("Default delay used by character.yml despawn rules when an entry omits despawn.delay. Applies only to prefabs with a despawn block.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 300f), Array.Empty())); } internal static float GetDefaultDespawnRange() { return Mathf.Clamp(_defaultDespawnRange?.Value ?? 0f, 0f, 128f); } internal static float GetDefaultDespawnDelaySeconds() { return Mathf.Clamp(_defaultDespawnDelaySeconds?.Value ?? 0f, 0f, 300f); } } internal static class CharacterDropGlobalConfig { private static readonly object DropInStackBlacklistLock = new object(); private static string _dropInStackBlacklistRaw = ""; private static HashSet _dropInStackBlacklist = new HashSet(StringComparer.OrdinalIgnoreCase); private static ConfigEntry _globalDropInStack = null; private static ConfigEntry _dropInStackBlacklistEntry = null; private static ConfigEntry _onePerPlayerNearbyRange = null; private static ConfigEntry _onePerPlayerNearbyRangeLivingPlayersOnly = null; internal static void Bind(DropNSpawnPlugin plugin) { //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Expected O, but got Unknown _globalDropInStack = plugin.BindConfigEntry("3 - Character", "Global Drop In Stack", DropNSpawnPlugin.Toggle.Off, "If on, all character loot drops in stacks whenever possible, including vanilla drops that are not overridden in YAML. Items listed in the Drop In Stack Blacklist always stay as separate drops. Non-stackable items and single-quantity drops are unchanged. Turning this off only disables the global default; per-entry YAML dropInStack still works unless the item is blacklisted."); _dropInStackBlacklistEntry = plugin.BindConfigEntry("3 - Character", "Drop In Stack Blacklist", "", "Comma, semicolon, or newline separated item prefab names that should never use character loot drop-in-stack. Applies to both vanilla character drops and YAML-driven character drops when they pass through CharacterDrop. This blacklist has higher priority than the global default and higher priority than per-entry YAML dropInStack. Example: Coins,TrophyDeer"); _onePerPlayerNearbyRange = plugin.BindConfigEntry("3 - Character", "One Per Player Nearby Range", 32f, new ConfigDescription("If 0, disables the nearby-player override and uses vanilla server-wide online player count for character-drop onePerPlayer. If greater than 0, counts only players within this many horizontal XZ meters of the dropping character.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); _onePerPlayerNearbyRangeLivingPlayersOnly = plugin.BindConfigEntry("3 - Character", "One Per Player Nearby Range Living Players Only", DropNSpawnPlugin.Toggle.Off, "If on, the One Per Player Nearby Range override counts only living players and excludes dead players waiting to respawn. If off, it counts all nearby players, matching the broader vanilla-style nearby-presence behavior."); } internal static bool IsGlobalDropInStackEnabled() { ConfigEntry globalDropInStack = _globalDropInStack; if (globalDropInStack == null) { return false; } return globalDropInStack.Value == DropNSpawnPlugin.Toggle.On; } internal static float GetOnePerPlayerNearbyRange() { return Mathf.Max(0f, _onePerPlayerNearbyRange?.Value ?? 100f); } internal static bool IsOnePerPlayerNearbyRangeLivingPlayersOnly() { ConfigEntry onePerPlayerNearbyRangeLivingPlayersOnly = _onePerPlayerNearbyRangeLivingPlayersOnly; if (onePerPlayerNearbyRangeLivingPlayersOnly == null) { return false; } return onePerPlayerNearbyRangeLivingPlayersOnly.Value == DropNSpawnPlugin.Toggle.On; } internal static bool IsDropInStackBlacklisted(string? prefabName) { if (prefabName == null) { return false; } string text = prefabName.Trim(); if (text.Length == 0) { return false; } lock (DropInStackBlacklistLock) { EnsureDropInStackBlacklistCache(); return _dropInStackBlacklist.Contains(text); } } private static void EnsureDropInStackBlacklistCache() { string text = _dropInStackBlacklistEntry?.Value ?? ""; if (!string.Equals(_dropInStackBlacklistRaw, text, StringComparison.Ordinal)) { _dropInStackBlacklistRaw = text; _dropInStackBlacklist = (from value in text.Split(new char[4] { ',', ';', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries) select value.Trim() into value where value.Length > 0 select value).ToHashSet(StringComparer.OrdinalIgnoreCase); } } } internal static class SpawnerGlobalConfig { internal const int MinSpawnAreaMaxTotalSpawns = 0; internal const int MaxSpawnAreaMaxTotalSpawns = 1000; private static ConfigEntry _defaultSpawnAreaMaxTotalSpawns; internal static void Bind(DropNSpawnPlugin plugin) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Expected O, but got Unknown _defaultSpawnAreaMaxTotalSpawns = plugin.BindConfigEntry("1 - General", "Default SpawnArea Max Total Spawns", 0, new ConfigDescription($"Default successful-spawn limit for every SpawnArea. 0 disables this option and leaves SpawnAreas unlimited. Values from 1 to {1000} make each SpawnArea destroy itself after that many successful spawns. Override per YAML entry with spawnArea.maxTotalSpawns.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 1000), Array.Empty()), synchronizedSetting: true, 450); } internal static int GetDefaultSpawnAreaMaxTotalSpawns() { return ClampSpawnAreaMaxTotalSpawns(_defaultSpawnAreaMaxTotalSpawns?.Value ?? 0); } internal static int ClampSpawnAreaMaxTotalSpawns(int value) { return Math.Max(0, Math.Min(1000, value)); } } internal static class EspSpawnSystemCompatibility { private readonly struct PendingRefresh { public SpawnSystem System { get; } public int SystemId { get; } public int Epoch { get; } public int ReadyFrame { get; } public PendingRefresh(SpawnSystem system, int systemId, int epoch, int readyFrame) { System = system; SystemId = systemId; Epoch = epoch; ReadyFrame = readyFrame; } } private const int RefreshFrameDelay = 1; private static readonly RingBufferQueue PendingRefreshes = new RingBufferQueue(); private static readonly HashSet PendingRefreshIds = new HashSet(); private static bool _typesResolved; private static Type? _spawnSystemTextType; private static MethodInfo? _drawSpawnSystemsMethod; private static bool _loggedRefreshFailure; internal static bool HasPendingRefreshes() { return PendingRefreshes.Count > 0; } internal static void ClearPendingRefreshes() { PendingRefreshes.Clear(); PendingRefreshIds.Clear(); } internal static void RemovePendingRefresh(int systemId) { PendingRefreshIds.Remove(systemId); } internal static void RequestRefresh(SpawnSystem? system, int epoch) { if (!((Object)(object)system == (Object)null) && !ShouldSkipRefresh()) { int instanceID = ((Object)system).GetInstanceID(); if (PendingRefreshIds.Add(instanceID)) { PendingRefreshes.Enqueue(new PendingRefresh(system, instanceID, epoch, Time.frameCount + 1)); } } } internal static bool TryProcessPendingRefresh(float deadline, int expectedEpoch) { while (PendingRefreshes.Count > 0) { if (Time.realtimeSinceStartup >= deadline) { return false; } if (DropNSpawnPlugin.IsGameDataRefreshDeferred(DropNSpawnPlugin.ReloadDomain.SpawnSystem)) { return false; } if (!PendingRefreshes.TryPeek(out var item)) { continue; } if (item.ReadyFrame > Time.frameCount) { return false; } if (PendingRefreshes.TryDequeue(out item)) { PendingRefreshIds.Remove(item.SystemId); if (item.Epoch == expectedEpoch && !((Object)(object)item.System == (Object)null)) { RefreshMarkers(item.System); return true; } } } return false; } private static void RefreshMarkers(SpawnSystem system) { if (ShouldSkipRefresh() || !TryResolveHooks(out Type spawnSystemTextType, out MethodInfo drawSpawnSystemsMethod)) { return; } try { HashSet hashSet = new HashSet(); Component[] componentsInChildren = ((Component)system).GetComponentsInChildren(spawnSystemTextType, true); foreach (Component val in componentsInChildren) { if ((Object)(object)val != (Object)null && (Object)(object)val.gameObject != (Object)null) { hashSet.Add(val.gameObject); } } foreach (GameObject item in hashSet) { item.SetActive(false); Object.Destroy((Object)(object)item); } drawSpawnSystemsMethod.Invoke(null, new object[1] { system }); } catch (Exception arg) { if (!_loggedRefreshFailure) { _loggedRefreshFailure = true; DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)$"Failed to refresh ESP SpawnSystem markers after authoritative replace. {arg}"); } } } private static bool ShouldSkipRefresh() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 if ((int)SystemInfo.graphicsDeviceType == 4) { return true; } if ((Object)(object)ZNet.instance != (Object)null) { return ZNet.instance.IsDedicated(); } return false; } private static bool TryResolveHooks(out Type? spawnSystemTextType, out MethodInfo? drawSpawnSystemsMethod) { if (!_typesResolved) { _spawnSystemTextType = SafeTypeLookup.FindLoadedType("ESP.SpawnSystemText", "ESP"); Type type = SafeTypeLookup.FindLoadedType("ESP.SpawnSystem_Awake", "ESP"); _drawSpawnSystemsMethod = ((type != null) ? AccessTools.Method(type, "DrawSpawnSystems", (Type[])null, (Type[])null) : null); _typesResolved = true; } spawnSystemTextType = _spawnSystemTextType; drawSpawnSystemsMethod = _drawSpawnSystemsMethod; if (spawnSystemTextType != null) { return drawSpawnSystemsMethod != null; } return false; } } internal static class SceneProximityQueries { internal static int CountPlayersInRangeXZ(Vector3 point, float range, bool livingPlayersOnly) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) if (range <= 0f) { return 0; } if (DropNSpawnPlugin.IsRuntimeServer()) { return CountServerPlayersInRangeXZ(point, range * range, livingPlayersOnly); } int num = 0; float rangeSquared = range * range; foreach (Player allPlayer in Player.GetAllPlayers()) { if (IsPlayerInRangeXZ(allPlayer, point, rangeSquared, livingPlayersOnly)) { num++; } } return num; } internal static int CountLivingPlayersInRangeXZ(Vector3 point, float range) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return CountPlayersInRangeXZ(point, range, livingPlayersOnly: true); } internal static bool AnyLivingPlayerInRangeXZ(Vector3 point, float range) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) long playerId; return TryFindAnyLivingPlayerInRangeXZ(point, range, out playerId); } internal static bool TryFindAnyLivingPlayerInRangeXZ(Vector3 point, float range, out long playerId) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) playerId = 0L; if (range <= 0f) { return false; } float rangeSquared = range * range; if (DropNSpawnPlugin.IsRuntimeServer()) { return TryFindAnyServerPlayerInRangeXZ(point, rangeSquared, out playerId); } foreach (Player allPlayer in Player.GetAllPlayers()) { if (!((Object)(object)allPlayer == (Object)null) && !((Object)(object)((Component)allPlayer).gameObject == (Object)null) && !((Character)allPlayer).IsDead()) { long playerID = allPlayer.GetPlayerID(); if (playerID != 0L && IsWithinRangeXZ(((Component)allPlayer).transform.position, point, rangeSquared)) { playerId = playerID; return true; } } } return false; } internal static bool TryFindNearestLivingPlayerInRangeXZ(Vector3 point, float range, out long playerId) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) playerId = 0L; if (range <= 0f) { return false; } float num = range * range; if (DropNSpawnPlugin.IsRuntimeServer()) { return TryFindNearestServerPlayerInRangeXZ(point, num, out playerId); } float num2 = float.MaxValue; foreach (Player allPlayer in Player.GetAllPlayers()) { if ((Object)(object)allPlayer == (Object)null || (Object)(object)((Component)allPlayer).gameObject == (Object)null || ((Character)allPlayer).IsDead()) { continue; } long playerID = allPlayer.GetPlayerID(); if (playerID != 0L) { Vector3 val = ((Component)allPlayer).transform.position - point; val.y = 0f; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (!(sqrMagnitude >= num) && !(sqrMagnitude >= num2)) { num2 = sqrMagnitude; playerId = playerID; } } } return playerId != 0; } internal static void CollectLivingPlayerIdsInRangeXZ(Vector3 point, float range, HashSet playerIds) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) playerIds.Clear(); if (range <= 0f) { return; } if (DropNSpawnPlugin.IsRuntimeServer()) { CollectServerPlayerIdsInRangeXZ(point, range * range, playerIds); return; } float rangeSquared = range * range; foreach (Player allPlayer in Player.GetAllPlayers()) { if (!((Object)(object)allPlayer == (Object)null) && !((Object)(object)((Component)allPlayer).gameObject == (Object)null) && !((Character)allPlayer).IsDead()) { long playerID = allPlayer.GetPlayerID(); if (playerID != 0L && IsWithinRangeXZ(((Component)allPlayer).transform.position, point, rangeSquared)) { playerIds.Add(playerID); } } } } private static int CountServerPlayersInRangeXZ(Vector3 point, float rangeSquared, bool livingPlayersOnly) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) int num = 0; if (IsLocalServerPlayerInRangeXZ(point, rangeSquared, livingPlayersOnly)) { num++; } ZNet instance = ZNet.instance; List list = ((instance != null) ? instance.GetPeers() : null); if (list == null) { return num; } foreach (ZNetPeer item in list) { if (IsServerPeerInRangeXZ(item, point, rangeSquared, livingPlayersOnly)) { num++; } } return num; } private static void CollectServerPlayerIdsInRangeXZ(Vector3 point, float rangeSquared, HashSet playerIds) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) long uID = ZNet.GetUID(); if (uID != 0L && IsLocalServerPlayerInRangeXZ(point, rangeSquared, livingPlayersOnly: true)) { playerIds.Add(uID); } ZNet instance = ZNet.instance; List list = ((instance != null) ? instance.GetPeers() : null); if (list == null) { return; } foreach (ZNetPeer item in list) { if (item != null && item.m_uid != 0L && IsServerPeerInRangeXZ(item, point, rangeSquared, livingPlayersOnly: true)) { playerIds.Add(item.m_uid); } } } private static bool TryFindAnyServerPlayerInRangeXZ(Vector3 point, float rangeSquared, out long playerId) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) playerId = 0L; long uID = ZNet.GetUID(); if (uID != 0L && IsLocalServerPlayerInRangeXZ(point, rangeSquared, livingPlayersOnly: true)) { playerId = uID; return true; } ZNet instance = ZNet.instance; List list = ((instance != null) ? instance.GetPeers() : null); if (list == null) { return false; } foreach (ZNetPeer item in list) { if (item != null && item.m_uid != 0L && IsServerPeerInRangeXZ(item, point, rangeSquared, livingPlayersOnly: true)) { playerId = item.m_uid; return true; } } return false; } private static bool TryFindNearestServerPlayerInRangeXZ(Vector3 point, float rangeSquared, out long playerId) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) playerId = 0L; float num = float.MaxValue; Player localPlayer = Player.m_localPlayer; long uID = ZNet.GetUID(); if (uID != 0L && (Object)(object)localPlayer != (Object)null && (Object)(object)((Component)localPlayer).gameObject != (Object)null && !((Character)localPlayer).IsDead()) { Vector3 val = ((Component)localPlayer).transform.position - point; val.y = 0f; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (sqrMagnitude < rangeSquared) { num = sqrMagnitude; playerId = uID; } } ZNet instance = ZNet.instance; List list = ((instance != null) ? instance.GetPeers() : null); if (list == null) { return playerId != 0; } foreach (ZNetPeer item in list) { if (item != null && item.m_uid != 0L && IsServerPeerInRangeXZ(item, point, rangeSquared, livingPlayersOnly: true)) { Vector3 val2 = item.GetRefPos() - point; val2.y = 0f; float sqrMagnitude2 = ((Vector3)(ref val2)).sqrMagnitude; if (!(sqrMagnitude2 >= num)) { num = sqrMagnitude2; playerId = item.m_uid; } } } return playerId != 0; } private static bool IsPlayerInRangeXZ(Player? player, Vector3 point, float rangeSquared, bool livingPlayersOnly) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player != (Object)null && (Object)(object)((Component)player).gameObject != (Object)null && (!livingPlayersOnly || !((Character)player).IsDead())) { return IsWithinRangeXZ(((Component)player).transform.position, point, rangeSquared); } return false; } private static bool IsLocalServerPlayerInRangeXZ(Vector3 point, float rangeSquared, bool livingPlayersOnly) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null && (Object)(object)((Component)localPlayer).gameObject != (Object)null && (!livingPlayersOnly || !((Character)localPlayer).IsDead())) { return IsWithinRangeXZ(((Component)localPlayer).transform.position, point, rangeSquared); } return false; } private static bool IsServerPeerInRangeXZ(ZNetPeer? peer, Vector3 point, float rangeSquared, bool livingPlayersOnly) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) if (peer == null || !peer.IsReady() || !IsWithinRangeXZ(peer.GetRefPos(), point, rangeSquared)) { return false; } if (!livingPlayersOnly) { return true; } if (TryGetLoadedPeerPlayer(peer, out Player player)) { if ((Object)(object)player != (Object)null) { return !((Character)player).IsDead(); } return false; } return true; } private static bool TryGetLoadedPeerPlayer(ZNetPeer peer, out Player? player) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) player = null; if (peer == null || ((ZDOID)(ref peer.m_characterID)).IsNone() || (Object)(object)ZNetScene.instance == (Object)null) { return false; } GameObject val = ZNetScene.instance.FindInstance(peer.m_characterID); if ((Object)(object)val != (Object)null) { return val.TryGetComponent(ref player); } return false; } private static bool IsWithinRangeXZ(Vector3 source, Vector3 target, float rangeSquared) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) Vector3 val = source - target; val.y = 0f; return ((Vector3)(ref val)).sqrMagnitude < rangeSquared; } private static string GetPrefabName(GameObject? gameObject) { if ((Object)(object)gameObject == (Object)null) { return ""; } ZNetView component = gameObject.GetComponent(); 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 ((Object)prefab).name; } } string prefabName = Utils.GetPrefabName(gameObject); if (!string.IsNullOrWhiteSpace(prefabName)) { return prefabName; } string text = ((Object)gameObject).name ?? ""; if (text.EndsWith("(Clone)", StringComparison.Ordinal)) { string text2 = text; int length = "(Clone)".Length; return text2.Substring(0, text2.Length - length).TrimEnd(); } return text; } } internal sealed class SpawnSystemTransportHooks : DomainTransportHooks { private string _lastLoggedManifestHash = ""; private string _lastLoggedPayloadReadyHash = ""; internal static SpawnSystemTransportHooks Instance { get; } = new SpawnSystemTransportHooks(); internal override void OnTransportStateReset() { _lastLoggedManifestHash = ""; _lastLoggedPayloadReadyHash = ""; } internal override void OnManifestSeen(bool isEmpty, string manifestHash, int compressedSize, int chunkCount, int? entryCount) { string text = (isEmpty ? "" : (manifestHash ?? "")); if (!string.Equals(_lastLoggedManifestHash, text, StringComparison.Ordinal)) { _lastLoggedManifestHash = text; if (isEmpty) { DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)"Spawnsystem sync stage=manifest_seen hash="); return; } string text2 = (entryCount.HasValue ? entryCount.Value.ToString(CultureInfo.InvariantCulture) : "unknown"); DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)("Spawnsystem sync stage=manifest_seen hash=" + manifestHash + " compressedBytes=" + compressedSize.ToString(CultureInfo.InvariantCulture) + " chunks=" + chunkCount.ToString(CultureInfo.InvariantCulture) + " entries=" + text2)); } } internal override void OnPayloadReady(string hash, int? entryCount, string successLogMessage, string desiredManifestHash, int? desiredEntryCount) { if (!string.IsNullOrWhiteSpace(hash) && !string.Equals(_lastLoggedPayloadReadyHash, hash, StringComparison.Ordinal)) { _lastLoggedPayloadReadyHash = hash; string text = ((successLogMessage.IndexOf("cache", StringComparison.OrdinalIgnoreCase) >= 0) ? "cache" : "network"); if (!entryCount.HasValue && string.Equals(desiredManifestHash, hash, StringComparison.Ordinal)) { entryCount = desiredEntryCount; } string text2 = (entryCount.HasValue ? entryCount.Value.ToString(CultureInfo.InvariantCulture) : "unknown"); DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)("Spawnsystem sync stage=payload_ready hash=" + hash + " source=" + text + " entries=" + text2)); } } } internal static class BossStonePerPlayerRuntime { private sealed class PendingBossStoneResetRequest { public long RequestId { get; set; } public long RequesterPeerId { get; set; } public string TargetPlayerName { get; set; } = ""; public float CreatedAt { get; set; } public float NextRetryAt { get; set; } } private const string StartTemplePrefabName = "StartTemple"; private const string DeepNorthBossStonesPrefabName = "DeepNorth_BossStones_TW"; private const string PlayerKeyPrefix = "dns_bossstone_"; private const string BossStoneSacrificeRequestRpc = "DropNSpawn BossStone Sacrifice Request"; private const string BossStoneResetRequestRpc = "DropNSpawn BossStone Reset Request"; private const string BossStoneResetApplyRpc = "DropNSpawn BossStone Reset Apply"; private const string BossStoneResetAckRpc = "DropNSpawn BossStone Reset Ack"; private const string BossStoneResetStatusRpc = "DropNSpawn BossStone Reset Status"; private const float BossStoneResetRetryIntervalSeconds = 0.5f; private const float BossStoneResetRequestTimeoutSeconds = 10f; private static readonly HashSet PerPlayerBossStoneLocationPrefabs = new HashSet(StringComparer.OrdinalIgnoreCase) { "StartTemple", "DeepNorth_BossStones_TW" }; private static readonly FieldRef ItemStandNviewRef = AccessTools.FieldRefAccess("m_nview"); private static readonly FieldRef RoutedRpcIdRef = AccessTools.FieldRefAccess("m_id"); private static readonly MethodInfo? ItemStandGetOrientationMethod = AccessTools.Method(typeof(ItemStand), "GetOrientation", (Type[])null, (Type[])null); private static readonly MethodInfo? ItemStandSetVisualItemMethod = AccessTools.Method(typeof(ItemStand), "SetVisualItem", new Type[4] { typeof(string), typeof(int), typeof(int), typeof(int) }, (Type[])null); private static ZRoutedRpc? _registeredRpcInstance; private static readonly Dictionary PendingBossStoneResetRequests = new Dictionary(); private static long _nextBossStoneSacrificeRequestId = 1L; private static long _nextBossStoneResetRequestId = 1L; internal static void Initialize() { EnsureRpcRegistered(); } private static void LogDiagnostic(string message) { DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)("[BossStone] " + message)); } internal static void EnsureRpcRegistered() { ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != null && instance != _registeredRpcInstance) { if (_registeredRpcInstance != null) { Shutdown(); } instance.Register("DropNSpawn BossStone Sacrifice Request", (Action)OnBossStoneSacrificeRequestRpc); instance.Register("DropNSpawn BossStone Reset Request", (Action)OnBossStoneResetRequestRpc); instance.Register("DropNSpawn BossStone Reset Apply", (Action)OnBossStoneResetApplyRpc); instance.Register("DropNSpawn BossStone Reset Ack", (Action)OnBossStoneResetAckRpc); instance.Register("DropNSpawn BossStone Reset Status", (Action)OnBossStoneResetStatusRpc); _registeredRpcInstance = instance; if (PluginSettingsFacade.IsBossStoneDiagnosticsEnabled()) { LogDiagnostic("Registered boss stone routed RPC handlers."); } } } internal static void Shutdown() { _registeredRpcInstance = null; PendingBossStoneResetRequests.Clear(); } internal static bool ShouldHandle(ItemStand? itemStand) { if (PluginSettingsFacade.IsPerPlayerBossStonesEnabled() && TryGetBossStone(itemStand, out BossStone bossStone)) { return IsPerPlayerBossStone(bossStone); } return false; } internal static bool TryRequestReset(string exactPlayerName, out string message) { if (!TryResolveKnownPlayerName(exactPlayerName, out string resolvedPlayerName)) { string text = (exactPlayerName ?? "").Trim(); message = ((text.Length == 0) ? "Syntax: dns:bossstone reset " : ("Player '" + text + "' not found. Use exact player name.")); if (PluginSettingsFacade.IsBossStoneDiagnosticsEnabled()) { LogDiagnostic("Reset request rejected before send. input='" + text + "' reason='player_not_found'."); } return false; } EnsureRpcRegistered(); if (ZRoutedRpc.instance == null) { message = "Boss stone reset is unavailable because routed RPC is not ready."; if (PluginSettingsFacade.IsBossStoneDiagnosticsEnabled()) { LogDiagnostic("Reset request rejected before send. target='" + resolvedPlayerName + "' reason='rpc_not_ready'."); } return false; } ZRoutedRpc.instance.InvokeRoutedRPC("DropNSpawn BossStone Reset Request", new object[1] { resolvedPlayerName }); message = "Queued boss stone reset request for '" + resolvedPlayerName + "'. Awaiting server result."; if (PluginSettingsFacade.IsBossStoneDiagnosticsEnabled()) { LogDiagnostic("Reset request sent. target='" + resolvedPlayerName + "'."); } return true; } internal static void ProcessPendingResetRequests() { if (ZRoutedRpc.instance == null || (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || PendingBossStoneResetRequests.Count == 0) { return; } float realtimeSinceStartup = Time.realtimeSinceStartup; long[] array = PendingBossStoneResetRequests.Keys.ToArray(); foreach (long num in array) { if (!PendingBossStoneResetRequests.TryGetValue(num, out PendingBossStoneResetRequest value) || value == null || realtimeSinceStartup < value.NextRetryAt) { continue; } if (realtimeSinceStartup - value.CreatedAt >= 10f) { if (PluginSettingsFacade.IsBossStoneDiagnosticsEnabled()) { LogDiagnostic($"Reset request timed out. requestId={num} target='{value.TargetPlayerName}'."); } CompletePendingBossStoneResetRequest(num, success: false, $"Boss stone reset failed for '{value.TargetPlayerName}': target did not acknowledge within {10f:0.#}s."); continue; } if (TryGetHostedLocalPlayerName(out string hostedLocalPlayerName) && string.Equals(value.TargetPlayerName, hostedLocalPlayerName, StringComparison.Ordinal)) { if (PluginSettingsFacade.IsBossStoneDiagnosticsEnabled()) { LogDiagnostic($"Reset apply routed locally for hosted player. requestId={num} target='{value.TargetPlayerName}'."); } ZRoutedRpc.instance.InvokeRoutedRPC("DropNSpawn BossStone Reset Apply", new object[1] { value.RequestId }); value.NextRetryAt = realtimeSinceStartup + 0.5f; continue; } ZNetPeer peerByPlayerName = ZNet.instance.GetPeerByPlayerName(value.TargetPlayerName); if (peerByPlayerName == null || !peerByPlayerName.IsReady()) { if (PluginSettingsFacade.IsBossStoneDiagnosticsEnabled()) { LogDiagnostic($"Reset request waiting for ready peer. requestId={num} target='{value.TargetPlayerName}' peerFound={peerByPlayerName != null} peerReady={peerByPlayerName != null && peerByPlayerName.IsReady()}."); } value.NextRetryAt = realtimeSinceStartup + 0.5f; } else { if (PluginSettingsFacade.IsBossStoneDiagnosticsEnabled()) { LogDiagnostic($"Reset apply sent. requestId={num} target='{value.TargetPlayerName}' peerId={peerByPlayerName.m_uid}."); } ZRoutedRpc.instance.InvokeRoutedRPC(peerByPlayerName.m_uid, "DropNSpawn BossStone Reset Apply", new object[1] { value.RequestId }); value.NextRetryAt = realtimeSinceStartup + 0.5f; } } } internal static bool TryInspectCurrentTarget(out string[] lines, out string error) { error = ""; Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { lines = Array.Empty(); error = "Local player is not ready."; return false; } GameObject hoverObject = ((Humanoid)localPlayer).GetHoverObject(); if ((Object)(object)hoverObject == (Object)null) { lines = Array.Empty(); error = "No hover target."; return false; } ItemStand itemStand = hoverObject.GetComponent() ?? hoverObject.GetComponentInParent(); if (!TryGetBossStone(itemStand, out BossStone bossStone) || (Object)(object)bossStone == (Object)null) { lines = Array.Empty(); error = "Current hover target is not a boss stone item stand."; return false; } Location bossStoneLocation = GetBossStoneLocation(bossStone); string text = (((Object)(object)bossStoneLocation != (Object)null) ? Utils.GetPrefabName(((Object)((Component)bossStoneLocation).gameObject).name) : ""); string playerKey = GetPlayerKey(bossStone); string[] obj = new string[6] { "BossStone: yes", $"PerPlayerEligible: {IsPerPlayerBossStone(bossStone)}", "Location: " + text, null, null, null }; ItemStand itemStand2 = bossStone.m_itemStand; object obj2; if (itemStand2 == null) { obj2 = null; } else { StatusEffect guardianPower = itemStand2.m_guardianPower; obj2 = ((guardianPower != null) ? ((Object)guardianPower).name : null); } if (obj2 == null) { obj2 = ""; } obj[3] = "GuardianPower: " + (string?)obj2; obj[4] = "PlayerKey: " + playerKey; obj[5] = $"ActiveForLocalPlayer: {LocalPlayerHasStoneActive(itemStand)}"; lines = obj; return true; } internal static bool TryHandleUseItem(ItemStand itemStand, Humanoid user, ItemData item, out bool result) { result = false; if (ShouldHandle(itemStand) && !((Object)(object)Player.m_localPlayer == (Object)null)) { Player val = (Player)(object)((user is Player) ? user : null); if (val != null && !((Object)(object)val != (Object)(object)Player.m_localPlayer)) { if (PluginSettingsFacade.IsBossStoneDiagnosticsEnabled()) { string[] obj = new string[6] { "Sacrifice use-item intercepted. player='", val.GetPlayerName(), "' item='", null, null, null }; object obj2; if (item == null) { obj2 = null; } else { GameObject dropPrefab = item.m_dropPrefab; obj2 = ((dropPrefab != null) ? ((Object)dropPrefab).name : null); } if (obj2 == null) { obj2 = item?.m_shared?.m_name ?? ""; } obj[3] = (string)obj2; obj[4] = "' "; StatusEffect guardianPower = itemStand.m_guardianPower; obj[5] = string.Format("bossStone='{0}' canAccept={1}.", ((guardianPower != null) ? ((Object)guardianPower).name : null) ?? "", item != null && CanAcceptConfiguredSacrifice(itemStand, item)); LogDiagnostic(string.Concat(obj)); } if (item == null || !CanAcceptConfiguredSacrifice(itemStand, item) || !((Humanoid)val).GetInventory().ContainsItem(item)) { if (PluginSettingsFacade.IsBossStoneDiagnosticsEnabled()) { LogDiagnostic($"Sacrifice use-item rejected locally. player='{val.GetPlayerName()}' itemPresent={item != null} " + $"canAccept={item != null && CanAcceptConfiguredSacrifice(itemStand, item)} inventoryContains={item != null && ((Humanoid)val).GetInventory().ContainsItem(item)}."); } ((Character)val).Message((MessageType)2, "$piece_itemstand_cantattach", 0, (Sprite)null); result = true; return true; } if (!TryGetBossStone(itemStand, out BossStone bossStone) || (Object)(object)bossStone == (Object)null) { if (PluginSettingsFacade.IsBossStoneDiagnosticsEnabled()) { LogDiagnostic("Sacrifice use-item fell through because boss stone resolution failed after local validation. player='" + val.GetPlayerName() + "'."); } return false; } long num = _nextBossStoneSacrificeRequestId++; if (PluginSettingsFacade.IsBossStoneDiagnosticsEnabled()) { string text = $"Sacrifice applying locally before broadcast. requestId={num} player='{val.GetPlayerName()}' "; GameObject dropPrefab2 = item.m_dropPrefab; LogDiagnostic(text + "item='" + (((dropPrefab2 != null) ? ((Object)dropPrefab2).name : null) ?? item.m_shared?.m_name ?? "") + "'."); } if (!TryApplyLocalBossStoneSacrifice(val, bossStone, item, num)) { result = true; return true; } if (!TryBroadcastSacrifice(bossStone, num) && PluginSettingsFacade.IsBossStoneDiagnosticsEnabled()) { LogDiagnostic($"Sacrifice broadcast skipped after local apply. requestId={num} player='{val.GetPlayerName()}'."); } result = true; return true; } } return false; } internal static bool TryOverrideHaveAttachment(ItemStand itemStand, out bool result) { result = false; if (!ShouldHandle(itemStand)) { return false; } result = LocalPlayerHasStoneActive(itemStand); return true; } internal static bool TryOverrideUpdateVisual(ItemStand itemStand) { if (!ShouldHandle(itemStand)) { return false; } object obj; if (!LocalPlayerHasStoneActive(itemStand)) { obj = ""; } else { List supportedItems = itemStand.m_supportedItems; if (supportedItems == null) { obj = null; } else { ItemDrop? obj2 = supportedItems.FirstOrDefault(); obj = ((obj2 != null) ? ((Object)obj2).name : null); } if (obj == null) { obj = ""; } } string itemName = (string)obj; int orientation = GetOrientation(itemStand); SetVisualItem(itemStand, itemName, 0, 1, orientation); return true; } internal static int ClearBossStonePlayerKeys(Player player) { if ((Object)(object)player == (Object)null) { return 0; } List list = (from key in player.GetUniqueKeys() where key?.StartsWith("dns_bossstone_", StringComparison.Ordinal) ?? false select key).ToList(); foreach (string item in list) { ((Humanoid)player).RemoveUniqueKey(item); } if (list.Count > 0 && (Object)(object)player == (Object)(object)Player.m_localPlayer) { ForsakenPowerSelectionRuntime.InvalidateGuardianPowerCache(); } return list.Count; } internal static bool LocalPlayerHasStoneActive(ItemStand? itemStand) { if (!TryGetBossStone(itemStand, out BossStone bossStone) || (Object)(object)bossStone == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null) { return false; } return ((Humanoid)Player.m_localPlayer).HaveUniqueKey(GetPlayerKey(bossStone)); } internal static bool HasUnlockedGuardianPower(Player? player, string guardianPowerName) { if ((Object)(object)player == (Object)null || string.IsNullOrWhiteSpace(guardianPowerName)) { return false; } return ((Humanoid)player).HaveUniqueKey("dns_bossstone_" + guardianPowerName.Trim()); } internal static List GetUnlockedGuardianPowerNames(Player? player) { if ((Object)(object)player == (Object)null) { return new List(); } return (from key in player.GetUniqueKeys() where key?.StartsWith("dns_bossstone_", StringComparison.Ordinal) ?? false select key.Substring("dns_bossstone_".Length) into key where key.Length > 0 select key).Distinct(StringComparer.Ordinal).ToList(); } private static bool CanAcceptConfiguredSacrifice(ItemStand itemStand, ItemData item) { if ((Object)(object)itemStand == (Object)null || item == null) { return false; } if (!itemStand.CanAttach(item)) { return false; } List supportedItems = itemStand.m_supportedItems; if (supportedItems == null || supportedItems.Count == 0) { return true; } string text = item.m_shared?.m_name ?? ""; GameObject dropPrefab = item.m_dropPrefab; string text2 = ((dropPrefab != null) ? ((Object)dropPrefab).name : null) ?? ""; foreach (ItemDrop item2 in supportedItems) { if (!((Object)(object)item2 == (Object)null)) { string b = item2.m_itemData?.m_shared?.m_name ?? ""; string b2 = (((Object)(object)((Component)item2).gameObject != (Object)null) ? ((Object)((Component)item2).gameObject).name : ((Object)item2).name); if ((text.Length > 0 && string.Equals(text, b, StringComparison.OrdinalIgnoreCase)) || (text2.Length > 0 && string.Equals(text2, b2, StringComparison.OrdinalIgnoreCase))) { return true; } } } return false; } private static bool CanAcceptConfiguredSacrifice(ItemStand itemStand, string itemPrefabName) { if ((Object)(object)itemStand == (Object)null || string.IsNullOrWhiteSpace(itemPrefabName)) { return false; } List supportedItems = itemStand.m_supportedItems; if (supportedItems == null || supportedItems.Count == 0) { return false; } string a = itemPrefabName.Trim(); foreach (ItemDrop item in supportedItems) { if (!((Object)(object)item == (Object)null)) { string b = (((Object)(object)((Component)item).gameObject != (Object)null) ? ((Object)((Component)item).gameObject).name : ((Object)item).name); if (string.Equals(a, b, StringComparison.OrdinalIgnoreCase)) { return true; } } } return false; } private static bool TryApplyLocalBossStoneSacrifice(Player localPlayer, BossStone bossStone, ItemData item, long requestId) { if (!TryConsumeLocalBossStoneSacrifice(localPlayer, item)) { ((Character)localPlayer).Message((MessageType)2, "$piece_itemstand_cantattach", 0, (Sprite)null); return false; } string playerKey = GetPlayerKey(bossStone); if (!((Humanoid)localPlayer).HaveUniqueKey(playerKey)) { ((Humanoid)localPlayer).AddUniqueKey(playerKey); ForsakenPowerSelectionRuntime.InvalidateGuardianPowerCache(); } RefreshAllBossStoneVisuals(); if (PluginSettingsFacade.IsBossStoneDiagnosticsEnabled()) { LogDiagnostic($"Sacrifice applied locally. requestId={requestId} player='{localPlayer.GetPlayerName()}' key='{playerKey}'."); } return true; } private static bool TryResolveKnownPlayerName(string playerName, out string resolvedPlayerName) { //IL_0073: Unknown result type (might be due to invalid IL or missing references) resolvedPlayerName = ""; string text = (playerName ?? "").Trim(); if (text.Length == 0) { return false; } if ((Object)(object)Player.m_localPlayer != (Object)null && string.Equals(Player.m_localPlayer.GetPlayerName(), text, StringComparison.OrdinalIgnoreCase)) { resolvedPlayerName = Player.m_localPlayer.GetPlayerName(); return true; } ZNet instance = ZNet.instance; foreach (PlayerInfo item in ((instance != null) ? instance.GetPlayerList() : null) ?? new List()) { string text2 = (item.m_name ?? "").Trim(); if (string.Equals(text2, text, StringComparison.OrdinalIgnoreCase)) { resolvedPlayerName = text2; return true; } } return false; } private static bool TryGetBossStone(ItemStand? itemStand, out BossStone? bossStone) { bossStone = null; if ((Object)(object)itemStand == (Object)null || (Object)(object)itemStand.m_guardianPower == (Object)null) { return false; } bossStone = ((Component)itemStand).GetComponentInParent(); return (Object)(object)bossStone != (Object)null; } private static Location? GetBossStoneLocation(BossStone? bossStone) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)bossStone == (Object)null)) { return Location.GetLocation(((Component)bossStone).transform.position, true); } return null; } private static bool IsPerPlayerBossStone(BossStone? bossStone) { Location bossStoneLocation = GetBossStoneLocation(bossStone); if ((Object)(object)bossStoneLocation != (Object)null) { return PerPlayerBossStoneLocationPrefabs.Contains(Utils.GetPrefabName(((Object)((Component)bossStoneLocation).gameObject).name)); } return false; } private static string GetPlayerKey(BossStone bossStone) { string guardianPowerName; string text = (TryResolveBossStoneGuardianPowerName(bossStone, out guardianPowerName) ? guardianPowerName : Utils.GetPrefabName(((Object)((Component)bossStone).gameObject).name)); return "dns_bossstone_" + text; } private static bool TryResolveBossStoneGuardianPowerName(BossStone? bossStone, out string guardianPowerName) { object obj; if (bossStone == null) { obj = null; } else { ItemStand itemStand = bossStone.m_itemStand; if (itemStand == null) { obj = null; } else { StatusEffect guardianPower = itemStand.m_guardianPower; obj = ((guardianPower == null) ? null : ((Object)guardianPower).name?.Trim()); } } if (obj == null) { obj = ""; } guardianPowerName = (string)obj; if (guardianPowerName.Length > 0) { return true; } string text = (((Object)(object)((bossStone != null) ? ((Component)bossStone).gameObject : null) != (Object)null) ? Utils.GetPrefabName(((Object)((Component)bossStone).gameObject).name).Trim() : ""); if (text.Length == 0) { return false; } if (text.StartsWith("GP_", StringComparison.Ordinal)) { guardianPowerName = text; return true; } if (text.StartsWith("BossStone_", StringComparison.OrdinalIgnoreCase) && text.Length > "BossStone_".Length) { guardianPowerName = "GP_" + text.Substring("BossStone_".Length); return true; } return false; } private static bool IsLocalPlayerInsideTemple(BossStone bossStone) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; Location bossStoneLocation = GetBossStoneLocation(bossStone); if ((Object)(object)localPlayer != (Object)null && (Object)(object)bossStoneLocation != (Object)null) { return bossStoneLocation.IsInside(((Component)localPlayer).transform.position, 0f, false); } return false; } private static bool TryBroadcastSacrifice(BossStone bossStone, long requestId) { //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) EnsureRpcRegistered(); ZNetView itemStandZNetView = GetItemStandZNetView(bossStone.m_itemStand); if (ZRoutedRpc.instance == null) { if (PluginSettingsFacade.IsBossStoneDiagnosticsEnabled()) { ItemStand itemStand = bossStone.m_itemStand; object obj; if (itemStand == null) { obj = null; } else { StatusEffect guardianPower = itemStand.m_guardianPower; obj = ((guardianPower != null) ? ((Object)guardianPower).name : null); } if (obj == null) { obj = ""; } LogDiagnostic("Sacrifice broadcast aborted. bossStone='" + (string?)obj + "' " + $"routedRpcReady={ZRoutedRpc.instance != null}."); } return false; } if (PluginSettingsFacade.IsBossStoneDiagnosticsEnabled()) { object[] obj2 = new object[4] { requestId, (object)(ZDOID)(((??)((itemStandZNetView == null) ? null : itemStandZNetView.GetZDO()?.m_uid)) ?? ZDOID.None), ((itemStandZNetView != null) ? ((Object)itemStandZNetView).name : null) ?? "", null }; ItemStand itemStand2 = bossStone.m_itemStand; object obj3; if (itemStand2 == null) { obj3 = null; } else { StatusEffect guardianPower2 = itemStand2.m_guardianPower; obj3 = ((guardianPower2 != null) ? ((Object)guardianPower2).name : null); } if (obj3 == null) { obj3 = ""; } obj2[3] = obj3; LogDiagnostic(string.Format("Sacrifice request broadcast. requestId={0} itemStandId={1} requestView='{2}' bossStone='{3}'.", obj2)); } ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "DropNSpawn BossStone Sacrifice Request", new object[3] { requestId, GetPlayerKey(bossStone), ((Component)bossStone).transform.position }); return true; } private static ZNetView? GetItemStandZNetView(ItemStand? itemStand) { if ((Object)(object)itemStand == (Object)null) { return null; } object obj; if (!((Object)(object)itemStand.m_netViewOverride != (Object)null)) { obj = ItemStandNviewRef.Invoke(itemStand); if (obj == null) { return ((Component)itemStand).GetComponent(); } } else { obj = itemStand.m_netViewOverride; } return (ZNetView?)obj; } private static void OnBossStoneSacrificeRequestRpc(long sender, long requestId, string playerKey, Vector3 bossStonePosition) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) string normalizedPlayerKey; bool flag = TryNormalizePlayerKey(playerKey, out normalizedPlayerKey); Player localPlayer = Player.m_localPlayer; Location location = Location.GetLocation(bossStonePosition, true); bool flag2 = (Object)(object)localPlayer != (Object)null && (Object)(object)location != (Object)null && location.IsInside(((Component)localPlayer).transform.position, 0f, false); bool flag3 = IsLocalRoutedSender(sender); if (PluginSettingsFacade.IsBossStoneDiagnosticsEnabled()) { LogDiagnostic($"Sacrifice broadcast received. requestId={requestId} sender={sender} senderIsLocal={flag3} validKey={flag} " + string.Format("location='{0}' localPlayer='{1}' insideLocation={2}.", ((Object)(object)location != (Object)null) ? Utils.GetPrefabName(((Object)((Component)location).gameObject).name) : "", ((localPlayer != null) ? localPlayer.GetPlayerName() : null) ?? "", flag2)); } if (flag && !((Object)(object)localPlayer == (Object)null) && !((Object)(object)location == (Object)null) && flag2) { if (!((Humanoid)localPlayer).HaveUniqueKey(normalizedPlayerKey)) { ((Humanoid)localPlayer).AddUniqueKey(normalizedPlayerKey); ForsakenPowerSelectionRuntime.InvalidateGuardianPowerCache(); } RefreshAllBossStoneVisuals(); } } private static void OnBossStoneResetRequestRpc(long sender, string exactPlayerName) { if (ZRoutedRpc.instance == null || (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return; } if (!TryResolveKnownPlayerName(exactPlayerName, out string resolvedPlayerName)) { if (PluginSettingsFacade.IsBossStoneDiagnosticsEnabled()) { LogDiagnostic(string.Format("Reset request received by server but target not found. sender={0} input='{1}'.", sender, (exactPlayerName ?? "").Trim())); } SendBossStoneResetStatus(sender, "Boss stone reset failed: player '" + exactPlayerName?.Trim() + "' was not found."); return; } long num = _nextBossStoneResetRequestId++; PendingBossStoneResetRequests[num] = new PendingBossStoneResetRequest { RequestId = num, RequesterPeerId = sender, TargetPlayerName = resolvedPlayerName, CreatedAt = Time.realtimeSinceStartup, NextRetryAt = Time.realtimeSinceStartup }; if (PluginSettingsFacade.IsBossStoneDiagnosticsEnabled()) { LogDiagnostic($"Reset request accepted by server. requestId={num} sender={sender} target='{resolvedPlayerName}'."); } ProcessPendingResetRequests(); } private static void OnBossStoneResetApplyRpc(long sender, long requestId) { bool flag = IsServerRoutedSender(sender); Player localPlayer = Player.m_localPlayer; if (PluginSettingsFacade.IsBossStoneDiagnosticsEnabled()) { LogDiagnostic(string.Format("Reset apply received. requestId={0} sender={1} serverValid={2} localPlayerReady={3} localPlayer='{4}'.", requestId, sender, flag, (Object)(object)localPlayer != (Object)null, ((localPlayer != null) ? localPlayer.GetPlayerName() : null) ?? "")); } if (flag && !((Object)(object)localPlayer == (Object)null)) { int num = ClearBossStonePlayerKeys(localPlayer); RefreshAllBossStoneVisuals(); Console instance = Console.instance; if (instance != null) { instance.Print($"Removed {num} boss stone keys from '{localPlayer.GetPlayerName()}'."); } if (PluginSettingsFacade.IsBossStoneDiagnosticsEnabled()) { LogDiagnostic($"Reset apply completed locally. requestId={requestId} removedCount={num} player='{localPlayer.GetPlayerName()}'."); } ZRoutedRpc instance2 = ZRoutedRpc.instance; if (instance2 != null) { instance2.InvokeRoutedRPC("DropNSpawn BossStone Reset Ack", new object[2] { requestId, num }); } } } private static void OnBossStoneResetAckRpc(long sender, long requestId, int removedCount) { if (ZRoutedRpc.instance == null || (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || !PendingBossStoneResetRequests.TryGetValue(requestId, out PendingBossStoneResetRequest value) || value == null) { if (PluginSettingsFacade.IsBossStoneDiagnosticsEnabled()) { LogDiagnostic($"Reset ack ignored. sender={sender} requestId={requestId} pendingFound={PendingBossStoneResetRequests.ContainsKey(requestId)}."); } return; } if (PluginSettingsFacade.IsBossStoneDiagnosticsEnabled()) { LogDiagnostic($"Reset ack received by server. sender={sender} requestId={requestId} removedCount={removedCount} target='{value.TargetPlayerName}'."); } CompletePendingBossStoneResetRequest(requestId, success: true, $"Boss stone reset completed for '{value.TargetPlayerName}': removed {removedCount} key(s)."); } private static void OnBossStoneResetStatusRpc(long sender, string message) { bool flag = IsServerRoutedSender(sender); if (PluginSettingsFacade.IsBossStoneDiagnosticsEnabled()) { LogDiagnostic($"Reset status received. sender={sender} serverValid={flag} message='{message}'."); } if (flag) { Console instance = Console.instance; if (instance != null) { instance.Print(message); } } } private static bool TryGetHostedLocalPlayerName(out string hostedLocalPlayerName) { hostedLocalPlayerName = ""; if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || (Object)(object)Player.m_localPlayer == (Object)null) { return false; } hostedLocalPlayerName = Player.m_localPlayer.GetPlayerName()?.Trim() ?? ""; return hostedLocalPlayerName.Length > 0; } private static bool TryGetHostedLocalPlayerPeerId(out long hostedLocalPeerId) { hostedLocalPeerId = 0L; if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || (Object)(object)Player.m_localPlayer == (Object)null || ZRoutedRpc.instance == null) { return false; } hostedLocalPeerId = RoutedRpcIdRef.Invoke(ZRoutedRpc.instance); return hostedLocalPeerId != 0; } private static bool IsLocalRoutedSender(long sender) { if (ZRoutedRpc.instance != null) { return RoutedRpcIdRef.Invoke(ZRoutedRpc.instance) == sender; } return false; } private static bool TryNormalizePlayerKey(string playerKey, out string normalizedPlayerKey) { normalizedPlayerKey = (playerKey ?? "").Trim(); if (normalizedPlayerKey.StartsWith("dns_bossstone_", StringComparison.Ordinal)) { return normalizedPlayerKey.Length > "dns_bossstone_".Length; } return false; } private static bool TryConsumeLocalBossStoneSacrifice(Player localPlayer, ItemData item) { if ((Object)(object)localPlayer == (Object)null || item == null) { if (PluginSettingsFacade.IsBossStoneDiagnosticsEnabled()) { LogDiagnostic("Sacrifice consume could not remove item because local player or item was not ready."); } return false; } bool flag = false; GameObject dropPrefab = item.m_dropPrefab; string text = ((dropPrefab != null) ? ((Object)dropPrefab).name : null) ?? ""; string text2 = item.m_shared?.m_name ?? text; if (((Humanoid)localPlayer).GetInventory().ContainsItem(item)) { ((Humanoid)localPlayer).UnequipItem(item, false); flag = ((Humanoid)localPlayer).GetInventory().RemoveOneItem(item); if (flag) { ((Character)localPlayer).ShowRemovedMessage(item, 1); } } else if (text2.Length > 0 && ((Humanoid)localPlayer).GetInventory().CountItems(text2, -1, true) > 0) { ((Humanoid)localPlayer).GetInventory().RemoveItem(text2, 1, -1, true); flag = true; } if (PluginSettingsFacade.IsBossStoneDiagnosticsEnabled()) { LogDiagnostic($"Sacrifice consume finalized local inventory. player='{localPlayer.GetPlayerName()}' item='{text2}' prefab='{text}' removed={flag}."); } return flag; } private static void CompletePendingBossStoneResetRequest(long requestId, bool success, string message) { if (PendingBossStoneResetRequests.TryGetValue(requestId, out PendingBossStoneResetRequest value) && value != null) { PendingBossStoneResetRequests.Remove(requestId); if (PluginSettingsFacade.IsBossStoneDiagnosticsEnabled()) { LogDiagnostic($"Reset request completed on server. requestId={requestId} success={success} requester={value.RequesterPeerId} target='{value.TargetPlayerName}' message='{message}'."); } SendBossStoneResetStatus(value.RequesterPeerId, message); } } private static void SendBossStoneResetStatus(long requesterPeerId, string message) { if (ZRoutedRpc.instance == null) { if (PluginSettingsFacade.IsBossStoneDiagnosticsEnabled()) { LogDiagnostic($"Reset status printed locally because routed RPC is unavailable. requester={requesterPeerId} message='{message}'."); } Console instance = Console.instance; if (instance != null) { instance.Print(message); } } else if (requesterPeerId == 0L) { if (PluginSettingsFacade.IsBossStoneDiagnosticsEnabled()) { LogDiagnostic("Reset status printed locally for local requester. message='" + message + "'."); } Console instance2 = Console.instance; if (instance2 != null) { instance2.Print(message); } } else { if (PluginSettingsFacade.IsBossStoneDiagnosticsEnabled()) { LogDiagnostic($"Reset status sent to requester. requester={requesterPeerId} message='{message}'."); } ZRoutedRpc.instance.InvokeRoutedRPC(requesterPeerId, "DropNSpawn BossStone Reset Status", new object[1] { message }); } } private static bool IsServerRoutedSender(long sender) { if (ZRoutedRpc.instance == null || (Object)(object)ZNet.instance == (Object)null) { return false; } if (ZNet.instance.IsServer()) { return RoutedRpcIdRef.Invoke(ZRoutedRpc.instance) == sender; } ZNetPeer serverPeer = ZNet.instance.GetServerPeer(); if (serverPeer != null) { return serverPeer.m_uid == sender; } return false; } private static int GetOrientation(ItemStand itemStand) { object obj = ItemStandGetOrientationMethod?.Invoke(itemStand, null); if (obj is int) { return (int)obj; } return 0; } private static void SetVisualItem(ItemStand itemStand, string itemName, int variant, int quality, int orientation) { ItemStandSetVisualItemMethod?.Invoke(itemStand, new object[4] { itemName, variant, quality, orientation }); } private static void RefreshAllBossStoneVisuals() { if ((Object)(object)ZNetScene.instance == (Object)null) { return; } BossStone[] array = Object.FindObjectsByType((FindObjectsSortMode)0); foreach (BossStone val in array) { if ((Object)(object)val != (Object)null && IsPerPlayerBossStone(val)) { TryOverrideUpdateVisual(val.m_itemStand); } } } } internal static class ForsakenPowerSelectionRuntime { private const float GuardianPowerHintBaseOffsetDown = 8f; private const float GuardianPowerHintFixedExtraOffsetDown = 8f; private static readonly Dictionary GuardianPowerOrder = new Dictionary(StringComparer.OrdinalIgnoreCase) { { "GP_Eikthyr", 0 }, { "GP_TheElder", 1 }, { "GP_Bonemass", 2 }, { "GP_Moder", 3 }, { "GP_Yagluth", 4 }, { "GP_Queen", 5 }, { "GP_Ashlands", 6 }, { "GP_Fader", 6 }, { "GP_DeepNorth", 7 }, { "SE_Boss_Brutalis", 8 }, { "SE_Boss_Gorr", 9 }, { "SE_Boss_StormHerald", 10 }, { "SE_Boss_Sythrak", 11 } }; private static TMP_Text? _guardianPowerHintText; private static int _guardianPowerHintHudInstanceId; private static readonly List CachedUnlockedGuardianPowers = new List(); private static int _cachedUnlockedGuardianPowersPlayerInstanceId; private static bool _unlockedGuardianPowersDirty = true; private static KeyboardShortcut _cachedHintShortcut; private static string _cachedHintText = ""; internal static void InvalidateGuardianPowerCache() { _unlockedGuardianPowersDirty = true; } internal static void TryRotateSelection(Player? player) { if (!CanRotateSelection(player)) { return; } List cachedUnlockedGuardianPowers = GetCachedUnlockedGuardianPowers(player); if (cachedUnlockedGuardianPowers.Count == 0) { ((Character)player).Message((MessageType)1, "No unlocked Forsaken Powers available.", 0, (Sprite)null); return; } string currentPower = player.GetGuardianPowerName() ?? ""; if (cachedUnlockedGuardianPowers.Count != 1 || !string.Equals(cachedUnlockedGuardianPowers[0], currentPower, StringComparison.OrdinalIgnoreCase)) { int num = cachedUnlockedGuardianPowers.FindIndex((string powerName) => string.Equals(powerName, currentPower, StringComparison.OrdinalIgnoreCase)); int index = ((num >= 0) ? ((num + 1) % cachedUnlockedGuardianPowers.Count) : 0); string text = cachedUnlockedGuardianPowers[index]; player.SetGuardianPower(text); ((Character)player).Message((MessageType)1, "Forsaken Power: " + GetDisplayName(text), 0, (Sprite)null); } } internal static void UpdateHudHint(Hud? hud, Player? player) { if (!((Object)(object)hud == (Object)null)) { TMP_Text val = EnsureGuardianPowerHint(hud); bool flag = ShouldShowHudHint(hud, player); ((Component)val).gameObject.SetActive(flag); if (flag) { ApplyGuardianPowerHintLayout(hud, val); val.text = GetCachedHintText(); } } } private static bool CanRotateSelection(Player? player) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) if (!PluginSettingsFacade.IsRemoteForsakenPowerSelectionEnabled() || (Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer || !PluginSettingsFacade.GetRotateForsakenPowerShortcut().IsKeyDown()) { return false; } if (((Character)player).IsDead() || ((Character)player).InCutscene() || ((Character)player).IsTeleporting()) { return false; } if (((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus()) || Console.IsVisible() || TextInput.IsVisible() || StoreGui.IsVisible() || InventoryGui.IsVisible() || Menu.IsVisible() || ((Object)(object)TextViewer.instance != (Object)null && TextViewer.instance.IsVisible()) || Minimap.IsOpen() || Minimap.InTextInput() || GameCamera.InFreeFly() || PlayerCustomizaton.IsBarberGuiVisible() || UnifiedPopup.IsVisible() || Hud.InRadial() || Hud.IsPieceSelectionVisible()) { return false; } return true; } private static List BuildUnlockedGuardianPowers(Player player) { List unlockedGuardianPowerNames = BossStonePerPlayerRuntime.GetUnlockedGuardianPowerNames(player); unlockedGuardianPowerNames.RemoveAll(delegate(string powerName) { if (powerName.Length != 0) { ObjectDB instance = ObjectDB.instance; return (Object)(object)((instance != null) ? instance.GetStatusEffect(StringExtensionMethods.GetStableHashCode(powerName)) : null) == (Object)null; } return true; }); unlockedGuardianPowerNames.Sort(CompareGuardianPowerNames); return unlockedGuardianPowerNames; } private static List GetCachedUnlockedGuardianPowers(Player player) { int instanceID = ((Object)player).GetInstanceID(); if (_unlockedGuardianPowersDirty || _cachedUnlockedGuardianPowersPlayerInstanceId != instanceID) { CachedUnlockedGuardianPowers.Clear(); CachedUnlockedGuardianPowers.AddRange(BuildUnlockedGuardianPowers(player)); _cachedUnlockedGuardianPowersPlayerInstanceId = instanceID; _unlockedGuardianPowersDirty = false; } return CachedUnlockedGuardianPowers; } private static int CompareGuardianPowerNames(string left, string right) { int guardianPowerOrder = GetGuardianPowerOrder(left); int guardianPowerOrder2 = GetGuardianPowerOrder(right); int num = guardianPowerOrder.CompareTo(guardianPowerOrder2); if (num != 0) { return num; } return string.Compare(left, right, StringComparison.OrdinalIgnoreCase); } private static int GetGuardianPowerOrder(string guardianPowerName) { if (!GuardianPowerOrder.TryGetValue(guardianPowerName ?? "", out var value)) { return int.MaxValue; } return value; } private static string GetDisplayName(string guardianPowerName) { ObjectDB instance = ObjectDB.instance; string text = ((instance == null) ? null : instance.GetStatusEffect(StringExtensionMethods.GetStableHashCode(guardianPowerName))?.m_name) ?? guardianPowerName; if (Localization.instance == null) { return text; } return Localization.instance.Localize(text); } private static bool ShouldShowHudHint(Hud hud, Player? player) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) KeyboardShortcut rotateForsakenPowerShortcut = PluginSettingsFacade.GetRotateForsakenPowerShortcut(); if (!PluginSettingsFacade.IsRemoteForsakenPowerSelectionEnabled() || (Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer || (int)((KeyboardShortcut)(ref rotateForsakenPowerShortcut)).MainKey == 0 || (Object)(object)hud.m_gpRoot == (Object)null || !((Component)hud.m_gpRoot).gameObject.activeSelf) { return false; } return GetCachedUnlockedGuardianPowers(player).Count > 0; } private static TMP_Text EnsureGuardianPowerHint(Hud hud) { if ((Object)(object)_guardianPowerHintText != (Object)null && _guardianPowerHintHudInstanceId == ((Object)hud).GetInstanceID() && (Object)(object)((Component)_guardianPowerHintText).gameObject != (Object)null) { return _guardianPowerHintText; } TMP_Text val = (((Object)(object)hud.m_gpCooldown != (Object)null) ? hud.m_gpCooldown : hud.m_gpName); _guardianPowerHintText = Object.Instantiate(val, (Transform)(object)hud.m_gpRoot); ((Object)_guardianPowerHintText).name = "DNS_ForsakenRotateHint"; _guardianPowerHintText.text = ""; _guardianPowerHintText.textWrappingMode = (TextWrappingModes)0; _guardianPowerHintText.fontSize = Mathf.Max(12f, val.fontSize - 2f); _guardianPowerHintText.alignment = (TextAlignmentOptions)514; ((Transform)_guardianPowerHintText.rectTransform).SetParent((Transform)(object)hud.m_gpRoot, false); _guardianPowerHintHudInstanceId = ((Object)hud).GetInstanceID(); return _guardianPowerHintText; } private static void ApplyGuardianPowerHintLayout(Hud hud, TMP_Text hintText) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) RectTransform rectTransform = hintText.rectTransform; RectTransform rectTransform2 = ((Graphic)hud.m_gpIcon).rectTransform; rectTransform.anchorMin = rectTransform2.anchorMin; rectTransform.anchorMax = rectTransform2.anchorMax; rectTransform.pivot = new Vector2(0.5f, 1f); float x = rectTransform2.anchoredPosition.x; float y = rectTransform2.anchoredPosition.y; Rect rect = rectTransform2.rect; rectTransform.anchoredPosition = new Vector2(x, y - ((Rect)(ref rect)).height * 0.5f - 8f - 8f); rect = rectTransform2.rect; rectTransform.sizeDelta = new Vector2(Mathf.Max(((Rect)(ref rect)).width + 72f, 128f), rectTransform.sizeDelta.y); } private static string GetCachedHintText() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) KeyboardShortcut rotateForsakenPowerShortcut = PluginSettingsFacade.GetRotateForsakenPowerShortcut(); if (_cachedHintText.Length == 0 || !((object)(KeyboardShortcut)(ref _cachedHintShortcut)).Equals((object?)rotateForsakenPowerShortcut)) { _cachedHintShortcut = rotateForsakenPowerShortcut; _cachedHintText = "[" + GetShortcutLabel(rotateForsakenPowerShortcut) + "] Rotate"; } return _cachedHintText; } private static string GetShortcutLabel(KeyboardShortcut shortcut) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) List list = ((KeyboardShortcut)(ref shortcut)).Modifiers.Select(GetKeyLabel).ToList(); if ((int)((KeyboardShortcut)(ref shortcut)).MainKey != 0) { list.Add(GetKeyLabel(((KeyboardShortcut)(ref shortcut)).MainKey)); } return string.Join("+", list.Where((string label) => label.Length > 0)); } private static string GetKeyLabel(KeyCode keyCode) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected I4, but got Unknown //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Expected I4, but got Unknown return (keyCode - 48) switch { 0 => "0", 1 => "1", 2 => "2", 3 => "3", 4 => "4", 5 => "5", 6 => "6", 7 => "7", 8 => "8", 9 => "9", _ => (keyCode - 303) switch { 3 => "Ctrl", 2 => "Ctrl", 1 => "Shift", 0 => "Shift", 5 => "Alt", 4 => "Alt", _ => ((object)(KeyCode)(ref keyCode)).ToString(), }, }; } } internal sealed class IntRangeDefinition : IYamlConvertible { public int? Min { get; set; } public int? Max { get; set; } internal bool HasValues() { if (!Min.HasValue) { return Max.HasValue; } return true; } void IYamlConvertible.Read(IParser parser, Type expectedType, ObjectDeserializer nestedObjectDeserializer) { if (parser.TryConsume(out var @event)) { (Min, Max) = RangeFormatting.ParseIntRange(@event.Value); return; } parser.Consume(); MappingEnd event2; while (!parser.Accept(out event2)) { string text = (parser.Consume().Value ?? "").Trim(); string text2 = text.ToLowerInvariant(); if (!(text2 == "min")) { if (!(text2 == "max")) { throw new YamlException("Unsupported range key '" + text + "'. Only 'min' and 'max' are supported."); } Max = RangeFormatting.ParseNullableInt(parser.Consume().Value); } else { Min = RangeFormatting.ParseNullableInt(parser.Consume().Value); } } parser.Consume(); } void IYamlConvertible.Write(IEmitter emitter, ObjectSerializer nestedObjectSerializer) { emitter.Emit(new YamlDotNet.Core.Events.Scalar(RangeFormatting.FormatShorthand(this))); } } internal sealed class FloatRangeDefinition : IYamlConvertible { public float? Min { get; set; } public float? Max { get; set; } internal bool HasValues() { if (!Min.HasValue) { return Max.HasValue; } return true; } void IYamlConvertible.Read(IParser parser, Type expectedType, ObjectDeserializer nestedObjectDeserializer) { if (parser.TryConsume(out var @event)) { (Min, Max) = RangeFormatting.ParseFloatRange(@event.Value); return; } parser.Consume(); MappingEnd event2; while (!parser.Accept(out event2)) { string text = (parser.Consume().Value ?? "").Trim(); string text2 = text.ToLowerInvariant(); if (!(text2 == "min")) { if (!(text2 == "max")) { throw new YamlException("Unsupported range key '" + text + "'. Only 'min' and 'max' are supported."); } Max = RangeFormatting.ParseNullableFloat(parser.Consume().Value); } else { Min = RangeFormatting.ParseNullableFloat(parser.Consume().Value); } } parser.Consume(); } void IYamlConvertible.Write(IEmitter emitter, ObjectSerializer nestedObjectSerializer) { emitter.Emit(new YamlDotNet.Core.Events.Scalar(RangeFormatting.FormatShorthand(this))); } } internal static class RangeFormatting { internal static IntRangeDefinition? From(int? min, int? max) { if (!min.HasValue && !max.HasValue) { return null; } return new IntRangeDefinition { Min = min, Max = max }; } internal static IntRangeDefinition? FromReference(int actualMin, int actualMax, int defaultMin, int defaultMax) { if (actualMin == defaultMin && actualMax == defaultMax) { return null; } return From(actualMin, actualMax); } internal static FloatRangeDefinition? From(float? min, float? max) { if (!min.HasValue && !max.HasValue) { return null; } return new FloatRangeDefinition { Min = min, Max = max }; } internal static FloatRangeDefinition? FromReference(float actualMin, float actualMax, float defaultMin, float defaultMax) { if (Math.Abs(actualMin - defaultMin) < 0.0001f && Math.Abs(actualMax - defaultMax) < 0.0001f) { return null; } return From(actualMin, actualMax); } internal static int? GetMin(IntRangeDefinition? range, int? fallbackMin) { return range?.Min ?? fallbackMin; } internal static int? GetMax(IntRangeDefinition? range, int? fallbackMin, int? fallbackMax) { return range?.Max ?? range?.Min ?? fallbackMax ?? fallbackMin; } internal static float? GetMin(FloatRangeDefinition? range, float? fallbackMin) { return range?.Min ?? fallbackMin; } internal static float? GetMax(FloatRangeDefinition? range, float? fallbackMin, float? fallbackMax) { return range?.Max ?? range?.Min ?? fallbackMax ?? fallbackMin; } internal static bool NormalizeAscending(ref int? min, ref int? max) { if (min.HasValue && max.HasValue && min.Value > max.Value) { int? num = max; int? num2 = min; min = num; max = num2; return true; } return false; } internal static bool NormalizeAscending(ref float? min, ref float? max) { if (min.HasValue && max.HasValue && min.Value > max.Value) { float? num = max; float? num2 = min; min = num; max = num2; return true; } return false; } internal static string FormatShorthand(IntRangeDefinition? range) { if (range == null || !range.HasValues()) { return ""; } int? min = range.Min; int? max = range.Max; NormalizeDisplayOrder(ref min, ref max); return FormatShorthand(min, max, (int value) => value.ToString(CultureInfo.InvariantCulture)); } internal static string FormatShorthand(FloatRangeDefinition? range) { if (range == null || !range.HasValues()) { return ""; } float? min = range.Min; float? max = range.Max; NormalizeDisplayOrder(ref min, ref max); return FormatShorthand(min, max, (float value) => FormatYamlFloat(value)); } internal static string FormatInlineObject(IntRangeDefinition? range) { int? min = range?.Min; int? max = range?.Max; NormalizeDisplayOrder(ref min, ref max); return FormatInlineObject(min, max, (int value) => value.ToString(CultureInfo.InvariantCulture)); } internal static string FormatInlineObject(FloatRangeDefinition? range) { float? min = range?.Min; float? max = range?.Max; NormalizeDisplayOrder(ref min, ref max); return FormatInlineObject(min, max, (float value) => FormatYamlFloat(value)); } internal static (int? min, int? max) ParseIntRange(string? raw) { string text = (raw ?? "").Trim(); if (text.Length == 0 || text == "~") { return (null, null); } int num = text.IndexOf('~'); if (num < 0) { int value = ParseRequiredInt(text); return (value, value); } string raw2 = text.Substring(0, num).Trim(); string text2 = text; int num2 = num + 1; return new ValueTuple(item2: ParseNullableInt(text2.Substring(num2, text2.Length - num2).Trim()), item1: ParseNullableInt(raw2)); } internal static (float? min, float? max) ParseFloatRange(string? raw) { string text = (raw ?? "").Trim(); if (text.Length == 0 || text == "~") { return (null, null); } int num = text.IndexOf('~'); if (num < 0) { float value = ParseRequiredFloat(text); return (value, value); } string raw2 = text.Substring(0, num).Trim(); string text2 = text; int num2 = num + 1; return new ValueTuple(item2: ParseNullableFloat(text2.Substring(num2, text2.Length - num2).Trim()), item1: ParseNullableFloat(raw2)); } internal static int? ParseNullableInt(string? raw) { string text = (raw ?? "").Trim(); if (text.Length != 0) { return ParseRequiredInt(text); } return null; } internal static float? ParseNullableFloat(string? raw) { string text = (raw ?? "").Trim(); if (text.Length != 0) { return ParseRequiredFloat(text); } return null; } private static int ParseRequiredInt(string raw) { if (!int.TryParse(raw, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { throw new YamlException("'" + raw + "' is not a valid integer range value."); } return result; } private static float ParseRequiredFloat(string raw) { if (!float.TryParse(raw, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var result)) { throw new YamlException("'" + raw + "' is not a valid float range value."); } return result; } private static string FormatShorthand(T? min, T? max, Func formatter) where T : struct { if (min.HasValue && max.HasValue && EqualityComparer.Default.Equals(min.Value, max.Value)) { return formatter(min.Value); } return (min.HasValue ? formatter(min.Value) : "") + "~" + (max.HasValue ? formatter(max.Value) : ""); } private static string FormatInlineObject(T? min, T? max, Func formatter) where T : struct { return "{ min: " + (min.HasValue ? formatter(min.Value) : "") + ", max: " + (max.HasValue ? formatter(max.Value) : "") + " }"; } private static void NormalizeDisplayOrder(ref int? min, ref int? max) { NormalizeAscending(ref min, ref max); } private static void NormalizeDisplayOrder(ref float? min, ref float? max) { NormalizeAscending(ref min, ref max); } private static string FormatYamlFloat(float value) { return value.ToString("0.###", CultureInfo.InvariantCulture); } } internal sealed class RingBufferQueue { private T[] _buffer; private int _head; private int _count; internal int Count => _count; internal RingBufferQueue(int capacity = 16) { _buffer = new T[Math.Max(4, capacity)]; } internal void Enqueue(T item) { EnsureCapacity(_count + 1); int num = (_head + _count) % _buffer.Length; _buffer[num] = item; _count++; } internal bool TryPeek(out T item) { if (_count == 0) { item = default(T); return false; } item = _buffer[_head]; return true; } internal bool TryDequeue(out T item) { if (_count == 0) { item = default(T); return false; } item = _buffer[_head]; _buffer[_head] = default(T); _head = (_head + 1) % _buffer.Length; _count--; if (_count == 0) { _head = 0; } return true; } internal void Clear() { if (_count > 0) { for (int i = 0; i < _count; i++) { _buffer[(_head + i) % _buffer.Length] = default(T); } } _head = 0; _count = 0; } private void EnsureCapacity(int required) { if (required > _buffer.Length) { int num; for (num = _buffer.Length * 2; num < required; num *= 2) { } T[] array = new T[num]; for (int i = 0; i < _count; i++) { array[i] = _buffer[(_head + i) % _buffer.Length]; } _buffer = array; _head = 0; } } } internal static class SafeTypeLookup { internal static Type? FindLoadedType(string fullTypeName, string? preferredAssemblySimpleName = null) { if (string.IsNullOrWhiteSpace(fullTypeName)) { return null; } Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); Assembly[] array; if (!string.IsNullOrWhiteSpace(preferredAssemblySimpleName)) { array = assemblies; foreach (Assembly assembly in array) { if (string.Equals(assembly.GetName().Name, preferredAssemblySimpleName, StringComparison.OrdinalIgnoreCase)) { Type type = TryGetType(assembly, fullTypeName); if (type != null) { return type; } } } } array = assemblies; for (int i = 0; i < array.Length; i++) { Type type2 = TryGetType(array[i], fullTypeName); if (type2 != null) { return type2; } } return null; } private static Type? TryGetType(Assembly assembly, string fullTypeName) { try { return assembly.GetType(fullTypeName, throwOnError: false, ignoreCase: false); } catch { return null; } } } internal sealed class TimeOfDayDefinition : IYamlConvertible { public List Values { get; set; } = new List(); internal bool HasValues() { return Values.Count > 0; } internal void Normalize() { Values = TimeOfDayFormatting.NormalizeValues(Values); } void IYamlConvertible.Read(IParser parser, Type expectedType, ObjectDeserializer nestedObjectDeserializer) { if (parser.TryConsume(out var @event)) { Values = TimeOfDayFormatting.NormalizeValues(new string[1] { @event.Value ?? "" }); return; } parser.Consume(); List list = new List(); SequenceEnd event2; while (!parser.Accept(out event2)) { list.Add(parser.Consume().Value ?? ""); } parser.Consume(); Values = TimeOfDayFormatting.NormalizeValues(list); } void IYamlConvertible.Write(IEmitter emitter, ObjectSerializer nestedObjectSerializer) { emitter.Emit(new SequenceStart(null, null, isImplicit: false, SequenceStyle.Flow)); foreach (string value in Values) { emitter.Emit(new YamlDotNet.Core.Events.Scalar(value)); } emitter.Emit(new SequenceEnd()); } } internal static class TimeOfDayFormatting { private const float DayStartFraction = 0.15f; private const float NightStartFraction = 0.85f; private static readonly HashSet InvalidTokenWarnings = new HashSet(StringComparer.OrdinalIgnoreCase); private static readonly string[] SupportedTokens = new string[3] { "day", "afternoon", "night" }; internal static List NormalizeValues(IEnumerable? values) { List list = new List(); if (values == null) { return list; } foreach (string value in values) { string text = NormalizeToken(value); if (text != null && !list.Contains(text, StringComparer.OrdinalIgnoreCase)) { list.Add(text); } } return list; } internal static TimeOfDayDefinition? FromSpawnFlags(bool allowDay, bool allowNight) { if (allowDay && allowNight) { return new TimeOfDayDefinition { Values = new List { "day", "night" } }; } if (allowDay) { return new TimeOfDayDefinition { Values = new List { "day" } }; } if (allowNight) { return new TimeOfDayDefinition { Values = new List { "night" } }; } return new TimeOfDayDefinition(); } internal static bool MatchesCurrentTime(TimeOfDayDefinition? definition) { if (definition == null) { return true; } if (!definition.HasValues()) { return false; } return definition.Values.Any(MatchesCurrentTimeToken); } internal static void GetBroadSpawnFlags(TimeOfDayDefinition? definition, out bool allowDay, out bool allowNight) { if (definition == null) { allowDay = true; allowNight = true; return; } if (!definition.HasValues()) { allowDay = false; allowNight = false; return; } allowDay = definition.Values.Any(IsDayScopedToken); allowNight = definition.Values.Any((string value) => string.Equals(value, "night", StringComparison.OrdinalIgnoreCase)); } internal static void GetRuntimeSpawnFlags(TimeOfDayDefinition? definition, out bool allowDay, out bool allowNight) { GetBroadSpawnFlags(definition, out allowDay, out allowNight); if (definition != null && definition.HasValues()) { bool flag = MatchesCurrentTime(definition); if (EnvMan.IsDay() && !flag) { allowDay = false; } if (EnvMan.IsNight() && !flag) { allowNight = false; } } } internal static int GetCurrentRuntimePhaseMarker() { if ((Object)(object)EnvMan.instance == (Object)null) { return int.MinValue; } if (EnvMan.IsNight()) { return 0; } if (!MatchesConfiguredAfternoon()) { return 1; } return 2; } internal static string FormatInlineList(TimeOfDayDefinition? definition, TimeOfDayDefinition? fallback = null) { List values = ((definition != null && definition.HasValues()) ? definition.Values : ((fallback != null && fallback.HasValues()) ? fallback.Values : new List())); return "[" + string.Join(", ", values) + "]"; } private static string? NormalizeToken(string? rawValue) { string text = (rawValue ?? "").Trim().ToLowerInvariant(); if (text.Length == 0) { return null; } if (text == "daytime") { text = "day"; } if (SupportedTokens.Contains(text, StringComparer.OrdinalIgnoreCase)) { return text; } WarnInvalidToken(text); return null; } private static bool MatchesCurrentTimeToken(string token) { return token switch { "day" => EnvMan.IsDay(), "afternoon" => MatchesConfiguredAfternoon(), "night" => EnvMan.IsNight(), _ => false, }; } private static bool IsDayScopedToken(string token) { if (!token.Equals("day", StringComparison.OrdinalIgnoreCase)) { return token.Equals("afternoon", StringComparison.OrdinalIgnoreCase); } return true; } private static bool MatchesConfiguredAfternoon() { if (!EnvMan.IsDay()) { return false; } float rawDayFraction = GetRawDayFraction(); float afternoonStartFraction = PluginSettingsFacade.GetAfternoonStartFraction(); if (rawDayFraction >= afternoonStartFraction) { return rawDayFraction < 0.85f; } return false; } private static void WarnInvalidToken(string token) { if (InvalidTokenWarnings.Add(token)) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("Unsupported timeOfDay token '" + token + "' was ignored. Supported values: day, afternoon, night.")); } } private static float GetRawDayFraction() { float num = (((Object)(object)EnvMan.instance != (Object)null) ? EnvMan.instance.GetDayFraction() : 0f); if (num <= 0.25f) { return num / 0.25f * 0.15f; } if (num <= 0.75f) { return 0.15f + (num - 0.25f) / 0.5f * 0.70000005f; } return 0.85f + (num - 0.75f) / 0.25f * 0.14999998f; } } internal sealed class SpawnSystemConditionsDefinition { [YamlMember(Order = 0)] public float? NoSpawnRadius { get; set; } [YamlMember(Order = 1)] public int? MaxSpawned { get; set; } [YamlMember(Order = 2)] public FloatRangeDefinition? Tilt { get; set; } [YamlIgnore] public float? MinTilt { get; set; } [YamlIgnore] public float? MaxTilt { get; set; } [YamlMember(Order = 3)] public FloatRangeDefinition? Altitude { get; set; } [YamlIgnore] public float? MinAltitude { get; set; } [YamlIgnore] public float? MaxAltitude { get; set; } [YamlMember(Order = 4)] public FloatRangeDefinition? OceanDepth { get; set; } [YamlIgnore] public float? MinOceanDepth { get; set; } [YamlIgnore] public float? MaxOceanDepth { get; set; } [YamlMember(Order = 5)] public FloatRangeDefinition? DistanceFromCenter { get; set; } [YamlIgnore] public float? MinDistanceFromCenter { get; set; } [YamlIgnore] public float? MaxDistanceFromCenter { get; set; } [YamlMember(Order = 7)] public List? Biomes { get; set; } [YamlIgnore] public Biome? ResolvedBiomeMask { get; set; } [YamlMember(Order = 8)] public List? BiomeAreas { get; set; } [YamlMember(Order = 9)] public TimeOfDayDefinition? TimeOfDay { get; set; } [YamlMember(Order = 10)] public List? RequiredEnvironments { get; set; } [YamlMember(Order = 11)] public string? RequiredGlobalKey { get; set; } [YamlMember(Order = 12)] public bool? InLava { get; set; } [YamlMember(Order = 13)] public bool? InForest { get; set; } [YamlMember(Order = 14)] public bool? InsidePlayerBase { get; set; } [YamlMember(Order = 15)] public bool? CanSpawnCloseToPlayer { get; set; } } internal class SpawnSystemSpawnDefinition { [YamlMember(Order = 0)] public string? Name { get; set; } [YamlMember(Order = 1)] public bool? HuntPlayer { get; set; } [YamlMember(Order = 2)] public IntRangeDefinition? Level { get; set; } [YamlIgnore] public int? MinLevel { get; set; } [YamlIgnore] public int? MaxLevel { get; set; } [YamlMember(Order = 5)] public float? OverrideLevelUpChance { get; set; } [YamlMember(Order = 6)] public float? LevelUpMinCenterDistance { get; set; } [YamlMember(Order = 7)] public float? GroundOffset { get; set; } [YamlMember(Order = 8)] public float? GroundOffsetRandom { get; set; } [YamlMember(Order = 9)] public float? SpawnInterval { get; set; } [YamlMember(Order = 10)] public float? SpawnChance { get; set; } [YamlMember(Order = 11)] public FloatRangeDefinition? SpawnRadius { get; set; } [YamlIgnore] public float? SpawnRadiusMin { get; set; } [YamlIgnore] public float? SpawnRadiusMax { get; set; } [YamlMember(Order = 13)] public IntRangeDefinition? GroupSize { get; set; } [YamlIgnore] public int? GroupSizeMin { get; set; } [YamlIgnore] public int? GroupSizeMax { get; set; } [YamlMember(Order = 16)] public float? GroupRadius { get; set; } } internal sealed class SpawnSystemModifiersDefinition { [YamlMember(Order = 0)] public Dictionary? Fields { get; set; } [YamlMember(Order = 1)] public List? Objects { get; set; } [YamlMember(Order = 2)] public string? Data { get; set; } [YamlMember(Order = 3)] public string? Faction { get; set; } } internal sealed class CanonicalSpawnSystemEntry { [YamlMember(Order = 0)] public string? Prefab { get; set; } [YamlMember(Order = 1)] public bool Enabled { get; set; } = true; [YamlIgnore] public SpawnSystemSpawnDefinition? Spawn { get; set; } [YamlMember(Alias = "spawnSystem", Order = 2)] public SpawnSystemSpawnDefinition? SpawnSystem { get { return Spawn; } set { Spawn = value; } } [YamlMember(Order = 3)] public SpawnSystemConditionsDefinition? Conditions { get; set; } [YamlMember(Order = 4)] public SpawnSystemModifiersDefinition? Modifiers { get; set; } [YamlIgnore] public string RuleId { get; set; } = ""; [YamlIgnore] public string? SourcePath { get; set; } [YamlIgnore] public int? SourceLine { get; set; } [YamlIgnore] public int? SourceColumn { get; set; } [YamlIgnore] public string? ReferenceOwnerName { get; set; } } internal static class SpawnSystemCustomDataSupport { internal sealed class PreparedPayload { public DataEntry? CustomData { get; set; } public List? CustomObjects { get; set; } internal bool HasValues() { if (CustomData == null) { return (CustomObjects?.Count ?? 0) > 0; } return true; } } private static readonly Dictionary CustomDataBySpawnData = new Dictionary(); private static readonly Dictionary> ObjectsBySpawnData = new Dictionary>(); private static readonly int HashFaction = StringExtensionMethods.GetStableHashCode("faction"); internal static void ClearCustomData(SpawnSystem system) { if ((Object)(object)system == (Object)null) { return; } foreach (SpawnSystemList spawnList in system.m_spawnLists) { foreach (SpawnData spawner in spawnList.m_spawners) { CustomDataBySpawnData.Remove(spawner); ObjectsBySpawnData.Remove(spawner); } } } internal static void ClearAll() { CustomDataBySpawnData.Clear(); ObjectsBySpawnData.Clear(); } internal static void ApplyCustomData(SpawnData spawnData, CanonicalSpawnSystemEntry entry, string context) { if (spawnData != null) { ApplyPreparedPayload(spawnData, BuildPreparedPayload(spawnData, entry, context)); } } internal static PreparedPayload? BuildPreparedPayload(SpawnData spawnData, CanonicalSpawnSystemEntry entry, string context) { if (spawnData == null) { return null; } PreparedPayload preparedPayload = new PreparedPayload { CustomData = BuildCustomData(spawnData, entry, context), CustomObjects = BuildCustomObjects(entry.Modifiers?.Objects, context) }; if (!preparedPayload.HasValues()) { return null; } return preparedPayload; } internal static void ApplyPreparedPayload(SpawnData spawnData, PreparedPayload? payload) { if (spawnData != null) { if (payload?.CustomData == null) { CustomDataBySpawnData.Remove(spawnData); } else { CustomDataBySpawnData[spawnData] = payload.CustomData; } if (payload?.CustomObjects == null || payload.CustomObjects.Count == 0) { ObjectsBySpawnData.Remove(spawnData); } else { ObjectsBySpawnData[spawnData] = payload.CustomObjects; } } } internal static void InitializeSpawn(SpawnData critter, Vector3 spawnPoint) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) if (critter != null && CustomDataBySpawnData.TryGetValue(critter, out DataEntry value) && value != null) { DataHelper.Init(critter.m_prefab, spawnPoint, Quaternion.identity, (Vector3?)null, value); } } internal static void SpawnObjects(SpawnData critter, Vector3 spawnPoint) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) if (critter == null || !ObjectsBySpawnData.TryGetValue(critter, out List value) || value.Count == 0) { return; } foreach (BlueprintObject item in value) { if (!(item.Chance < 1f) || !(Random.value > item.Chance)) { Spawn.BPO(item, spawnPoint, Quaternion.identity, Vector3.one, (Func)ObjectDataIdentity, (Func)ObjectPrefabIdentity, (List)null); } } } private static DataEntry? BuildCustomData(SpawnData spawnData, CanonicalSpawnSystemEntry entry, string context) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Expected O, but got Unknown SpawnSystemModifiersDefinition? modifiers = entry.Modifiers; DataEntry val = null; string text = modifiers?.Data; if (text != null && !string.IsNullOrWhiteSpace(text)) { val = DataHelper.Get(text, "DropNSpawn_spawnsystem:" + context); } DataEntry val2 = null; string text2 = modifiers?.Faction; if (text2 != null && !string.IsNullOrWhiteSpace(text2)) { if (val2 == null) { val2 = new DataEntry(); } DataEntry val3 = val2; if (val3.Strings == null) { val3.Strings = new Dictionary(); } val2.Strings[HashFaction] = DataValue.Simple(text2); } Dictionary dictionary = modifiers?.Fields; if (dictionary != null && dictionary.Count > 0) { if (val2 == null) { val2 = new DataEntry(); } ExpandWorldFieldOverrideSupport.AddFieldOverrides(val2, spawnData.m_prefab, dictionary); } return DataHelper.Merge(val, val2); } private static List? BuildCustomObjects(List? configuredObjects, string context) { if (configuredObjects == null || configuredObjects.Count == 0) { return null; } List list = new List(); foreach (string configuredObject in configuredObjects) { if (TryParseObjectDefinition(configuredObject, context, out BlueprintObject obj)) { list.Add(obj); } } if (list.Count != 0) { return list; } return null; } private static bool TryParseObjectDefinition(string? rawDefinition, string context, out BlueprintObject? obj) { //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Expected O, but got Unknown obj = null; if (string.IsNullOrWhiteSpace(rawDefinition)) { return false; } string[] array = (from part in rawDefinition.Split(',') select part.Trim()).ToArray(); if (array.Length == 0 || array[0].Length == 0) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("Entry '" + context + "' contains an invalid objects entry '" + rawDefinition + "'. Expected format: Prefab,posX,posZ,posY,chance,data.")); return false; } if (!TryParseObjectFloat(array, 1, 0f, context, rawDefinition, out var value) || !TryParseObjectFloat(array, 2, 0f, context, rawDefinition, out var value2) || !TryParseObjectFloat(array, 3, 0f, context, rawDefinition, out var value3) || !TryParseObjectFloat(array, 4, 1f, context, rawDefinition, out var value4)) { return false; } DataEntry val = DataHelper.Get((array.Length > 5) ? array[5] : "", "DropNSpawn_spawnsystem:" + context); obj = new BlueprintObject(array[0], new Vector3(value, value3, value2), Quaternion.identity, Vector3.one, val, value4, false); return true; } private static bool TryParseObjectFloat(string[] split, int index, float defaultValue, string context, string rawDefinition, out float value) { value = defaultValue; if (index >= split.Length || split[index].Length == 0) { return true; } if (float.TryParse(split[index], NumberStyles.Any, CultureInfo.InvariantCulture, out value)) { return true; } DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("Entry '" + context + "' contains an invalid objects entry '" + rawDefinition + "'. '" + split[index] + "' is not a valid number.")); return false; } private static DataEntry? ObjectDataIdentity(DataEntry? data, string prefab) { return data; } private static string ObjectPrefabIdentity(string prefab) { return prefab; } } internal static class SpawnSystemManager { private readonly struct PendingLiveSystemAttach { public SpawnSystem System { get; } public int SystemId { get; } public int Epoch { get; } public int BuildVersion { get; } public CompiledSpawnSystemTable TargetTable { get; } public PendingLiveSystemAttach(SpawnSystem system, int systemId, int epoch, int buildVersion, CompiledSpawnSystemTable targetTable) { System = system; SystemId = systemId; Epoch = epoch; BuildVersion = buildVersion; TargetTable = targetTable; } } private sealed class SpawnSystemEntrySnapshot { public string RefId { get; set; } = ""; public int ListIndex { get; set; } public int EntryIndex { get; set; } public SpawnData Data { get; set; } } private sealed class SpawnSystemSnapshot { public int SystemId { get; set; } public int ListCount { get; set; } public List Entries { get; } = new List(); } private sealed class PreparedSpawnSystemEntry { public CanonicalSpawnSystemEntry Entry { get; set; } public SpawnData Data { get; set; } public string Context { get; set; } = ""; public SpawnSystemCustomDataSupport.PreparedPayload? CustomDataPayload { get; set; } public TimeOfDayDefinition? RuntimeTimeOfDay { get; set; } } private sealed class PreparedSpawnSystemModel { public CanonicalSpawnSystemEntry Entry { get; set; } public string RuleId { get; set; } = ""; public string EntrySignature { get; set; } = ""; public string Context { get; set; } = ""; public TimeOfDayDefinition? RuntimeTimeOfDay { get; set; } } private readonly struct InvalidEntryWarningSuppressionScope : IDisposable { private readonly bool _active; public InvalidEntryWarningSuppressionScope(bool active) { _active = active; if (_active) { _invalidEntryWarningSuppressionDepth++; } } public void Dispose() { if (_active) { _invalidEntryWarningSuppressionDepth--; } } } private sealed class FinalizedPreparedEntryCacheEntry { public int GameDataSignature { get; set; } public string RuleId { get; set; } = ""; public string EntrySignature { get; set; } = ""; public SpawnData Data { get; set; } public SpawnSystemCustomDataSupport.PreparedPayload? CustomDataPayload { get; set; } public TimeOfDayDefinition? RuntimeTimeOfDay { get; set; } } private sealed class PreparedEntriesBuildResult { public int BuildVersion { get; set; } public int GameDataSignature { get; set; } public bool DomainEnabled { get; set; } public string ApplyTargetSignature { get; set; } = ""; public bool QueueEspRefreshForLiveSystems { get; set; } public List Models { get; } = new List(); public string PreparedEntriesSignature { get; set; } = ""; } private sealed class PendingPreparedEntriesBuildRequest { public int BuildVersion { get; set; } public int GameDataSignature { get; set; } public bool DomainEnabled { get; set; } public string ApplyTargetSignature { get; set; } = ""; public bool QueueEspRefreshForLiveSystems { get; set; } public List ConfigurationSnapshot { get; } = new List(); } private sealed class PendingCompiledTableBuildState { public int BuildVersion { get; set; } public int GameDataSignature { get; set; } public bool DomainEnabled { get; set; } public bool EagerClientSyncBuild { get; set; } public string ApplyTargetSignature { get; set; } = ""; public bool QueueEspRefreshForLiveSystems { get; set; } public string PreparedEntriesSignature { get; set; } = ""; public List Models { get; } = new List(); public int NextFinalizeIndex { get; set; } public List FinalizedEntries { get; } = new List(); public int NextCompiledEntryIndex { get; set; } public CompiledSpawnSystemTable? BuildingActiveTable { get; set; } public List? BuildingLiveEntries { get; set; } public CompiledSpawnSystemTable? PreviousActiveTable { get; set; } public CompiledSpawnSystemTable? PreviousVanillaTable { get; set; } public bool RuntimeStateSwapped { get; set; } } private sealed class ParsedSpawnSystemConfigurationDocument { public List Configuration { get; } = new List(); public List Warnings { get; } = new List(); } private sealed class CompiledSpawnSystemTable { public int GameDataSignature { get; set; } public string Signature { get; set; } = ""; public int BaselineListCount { get; set; } public int BaselineRowCount { get; set; } public int BaselineContentHash { get; set; } public List Lists { get; } = new List(); public Dictionary RuntimeTimeOfDayBySpawnData { get; } = new Dictionary(); public Dictionary CustomPayloadsBySpawnData { get; } = new Dictionary(); } private struct SpawnListSummary { public int ListCount { get; set; } public int RowCount { get; set; } public int ContentHash { get; set; } public string SamplePrefabs { get; set; } } private sealed class PendingCompiledTableRetirement { public CompiledSpawnSystemTable Table { get; set; } public HashSet RemainingSystemIds { get; } = new HashSet(); } private sealed class SyncedSpawnSystemConfigurationState { public List Configuration { get; } = new List(); public string ConfigurationSignature { get; set; } = ""; public bool ConfigurationReady { get; set; } } private sealed class ReferenceCatalogSnapshot { public List LiveEntries { get; } = new List(); public string SourceSignature { get; set; } = ""; public bool HasAnyEntries => LiveEntries.Count > 0; } [CompilerGenerated] private sealed class d__247 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private string <>2__current; private int <>l__initialThreadId; private HashSet 5__2; private List.Enumerator <>7__wrap2; string IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__247(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(); } } 5__2 = null; <>7__wrap2 = default(List.Enumerator); <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; 5__2 = new HashSet(StringComparer.OrdinalIgnoreCase); <>7__wrap2 = _configuration.GetEnumerator(); <>1__state = -3; break; case 1: <>1__state = -3; break; } while (<>7__wrap2.MoveNext()) { string text = ReferenceRefreshSupport.NormalizeKey(<>7__wrap2.Current.Prefab); if (text.Length != 0) { GameObject? obj = ResolvePrefab(text); string item = text + ":" + ((obj != null) ? ((Object)obj).GetInstanceID() : 0).ToString(CultureInfo.InvariantCulture); if (5__2.Add(item)) { <>2__current = item; <>1__state = 1; return true; } } } <>m__Finally1(); <>7__wrap2 = default(List.Enumerator); 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; ((IDisposable)<>7__wrap2).Dispose(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; return this; } return new d__247(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__160 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private string <>2__current; private int <>l__initialThreadId; private IEnumerator <>7__wrap1; string IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public 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 == 2) { try { } finally { <>m__Finally1(); } } <>7__wrap1 = 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; } string primaryOverrideConfigurationPath = GetPrimaryOverrideConfigurationPath(); if (primaryOverrideConfigurationPath != null) { <>2__current = primaryOverrideConfigurationPath; <>1__state = 1; return true; } goto IL_005c; } case 1: <>1__state = -1; goto IL_005c; case 2: { <>1__state = -3; break; } IL_005c: <>7__wrap1 = EnumerateSupplementalOverrideConfigurationPaths().GetEnumerator(); <>1__state = -3; break; } if (<>7__wrap1.MoveNext()) { string current = <>7__wrap1.Current; <>2__current = current; <>1__state = 2; return true; } <>m__Finally1(); <>7__wrap1 = 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 (<>7__wrap1 != null) { <>7__wrap1.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; return this; } return new d__160(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__402 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private string <>2__current; private int <>l__initialThreadId; string IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__402(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = "- prefab: Boar"; <>1__state = 1; return true; case 1: <>1__state = -1; <>2__current = " spawnSystem: # SpawnSystem checks this block every spawnInterval seconds # rolls spawnChance # picks a spawn center within spawnRadius around one player # then spawns groupSize creatures within groupRadius around that center"; <>1__state = 2; return true; case 2: <>1__state = -1; <>2__current = " name: null # ex) Boar # Optional row name # Omit to default to the prefab name in this compressed format"; <>1__state = 3; return true; case 3: <>1__state = -1; <>2__current = " huntPlayer: false # True marks the spawned AI as hunting the player"; <>1__state = 4; return true; case 4: <>1__state = -1; <>2__current = " level: 1~1 # ex) 1~3 # Range of spawned creature levels"; <>1__state = 5; return true; case 5: <>1__state = -1; <>2__current = " overrideLevelUpChance: -1 # Use -1 to keep native behavior # Percent per extra level roll"; <>1__state = 6; return true; case 6: <>1__state = -1; <>2__current = " levelUpMinCenterDistance: 0 # Meters from the world center before native level-up rolls start"; <>1__state = 7; return true; case 7: <>1__state = -1; <>2__current = " groundOffset: 0.5 # Meters of vertical placement offset"; <>1__state = 8; return true; case 8: <>1__state = -1; <>2__current = " groundOffsetRandom: 0 # Range in meters of random vertical placement offset"; <>1__state = 9; return true; case 9: <>1__state = -1; <>2__current = " spawnInterval: 4 # ex) 100 # Seconds between spawn checks"; <>1__state = 10; return true; case 10: <>1__state = -1; <>2__current = " spawnChance: 100 # Percent chance per successful check"; <>1__state = 11; return true; case 11: <>1__state = -1; <>2__current = " spawnRadius: 0~0 # ex) 0~5 # Range in meters from one player to the chosen spawn center # 0~0 uses the native global spawn range"; <>1__state = 12; return true; case 12: <>1__state = -1; <>2__current = " groupSize: 1~1 # ex) 1~3 # Range of creatures spawned by one successful attempt"; <>1__state = 13; return true; case 13: <>1__state = -1; <>2__current = " groupRadius: 3 # Meters from the chosen spawn center to each spawned creature"; <>1__state = 14; return true; case 14: <>1__state = -1; <>2__current = " conditions:"; <>1__state = 15; return true; case 15: <>1__state = -1; <>2__current = " noSpawnRadius: 10 # Meters from the chosen spawn center used to block the attempt if the same prefab is already nearby"; <>1__state = 16; return true; case 16: <>1__state = -1; <>2__current = " maxSpawned: 1 # Active prefab count cap in the wider area loaded around players"; <>1__state = 17; return true; case 17: <>1__state = -1; <>2__current = " tilt: 0~35 # Range in degrees of allowed ground tilt"; <>1__state = 18; return true; case 18: <>1__state = -1; <>2__current = " altitude: -1000~1000 # Range in world-height meters"; <>1__state = 19; return true; case 19: <>1__state = -1; <>2__current = " oceanDepth: 0~0 # ex) 0~10 # Range in meters of water depth at the spawn point # 0~0 leaves the native depth check effectively unconstrained"; <>1__state = 20; return true; case 20: <>1__state = -1; <>2__current = " distanceFromCenter: 0~0 # ex) 0~10000 # Range in meters from the world center # 0~0 leaves the native distance check effectively unconstrained"; <>1__state = 21; return true; case 21: <>1__state = -1; <>2__current = " biomes: [Meadows] # Allowed spawn biomes # Expand World Data custom biome names and numeric biome masks also work when EWD is installed"; <>1__state = 22; return true; case 22: <>1__state = -1; <>2__current = " biomeAreas: [Everything] # Allowed values: Edge, Median, Everything # Edge = biome border band # Median = biome interior # Everything = both"; <>1__state = 23; return true; case 23: <>1__state = -1; <>2__current = " timeOfDay: null # ex) [day, night] # [day, afternoon, night] # day contains afternoon"; <>1__state = 24; return true; case 24: <>1__state = -1; <>2__current = " requiredEnvironments: [] # ex) [Rain, Clear] # Allowed environment names"; <>1__state = 25; return true; case 25: <>1__state = -1; <>2__current = " requiredGlobalKey: '' # ex) defeated_gdking # Native default is '' # Supports 'key 10' numeric syntax too"; <>1__state = 26; return true; case 26: <>1__state = -1; <>2__current = " inLava: false # True = lava only # False = outside lava only"; <>1__state = 27; return true; case 27: <>1__state = -1; <>2__current = " inForest: null # ex) true = forest only # false = outside forest only # null or no field allows both"; <>1__state = 28; return true; case 28: <>1__state = -1; <>2__current = " insidePlayerBase: false # False = outside player-base influence only"; <>1__state = 29; return true; case 29: <>1__state = -1; <>2__current = " canSpawnCloseToPlayer: false # True allows close-to-player spawns"; <>1__state = 30; return true; case 30: <>1__state = -1; <>2__current = " modifiers:"; <>1__state = 31; return true; case 31: <>1__state = -1; <>2__current = " fields: {} # ex) { Character.m_name: $enemy_boar, health: 200, damage: 2 } # Expand World Data field overrides"; <>1__state = 32; return true; case 32: <>1__state = -1; <>2__current = " objects: [] # ex) [Wood,0,0,0,1] # Expand World Data object entries"; <>1__state = 33; return true; case 33: <>1__state = -1; <>2__current = " data: null # Expand World Data data entry name from your EWD config"; <>1__state = 34; return true; case 34: <>1__state = -1; <>2__current = " faction: null # ex) ForestMonsters # Values: " + FactionIntegration.GetNativeFactionList(); <>1__state = 35; return true; case 35: <>1__state = -1; return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; return this; } return new d__402(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } private const int FinalizedPreparedEntriesPerStep = 1; private const int CompiledEntryBuildsPerStep = 8; internal static readonly DomainModuleDefinition Module = new DomainModuleDefinition("spawnsystem", DropNSpawnPlugin.ReloadDomain.SpawnSystem, "spawnsystem_yaml", 96, ShouldReloadForPath, ReloadConfiguration, OnGameDataReady, HandleExpandWorldDataReady, 2, DomainTransportProfile.LargeWithArtifacts, "spawnsystem", "spawnsystem", 40, (CanonicalSpawnSystemEntry entry) => entry.RuleId, ApplySyncedPayload, DomainWorkKinds.Runtime | DomainWorkKinds.Reconcile, null, null, HasPendingReconcileWork, ProcessQueuedReconcileStep, MarkSyncedPayloadPending, EnterPendingSyncedPayloadState, SpawnSystemTransportHooks.Instance); private static int _invalidEntryWarningSuppressionDepth; 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 Dictionary SnapshotsBySystemId = new Dictionary(); private static readonly HashSet InvalidEntryWarnings = new HashSet(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary TimeOfDayBySpawnData = new Dictionary(); private static readonly RingBufferQueue PendingLiveSystemAttaches = new RingBufferQueue(); private static readonly HashSet PendingLiveSystemAttachIds = new HashSet(); private static readonly HashSet PendingLiveSystemAttachEspRefreshIds = new HashSet(); private static readonly List PendingCompiledTableRetirements = new List(); private static readonly HashSet PreAttachedSpawnSystemIds = new HashSet(); private static readonly Dictionary LiveSystemsById = new Dictionary(); private static readonly List LiveSystemsSnapshot = new List(); private static readonly Dictionary FinalizedPreparedEntryCache = new Dictionary(StringComparer.Ordinal); private static readonly FieldInfo? SpawnSystemInstancesField = AccessTools.Field(typeof(SpawnSystem), "m_instances"); private static readonly string[] BiomeOutputOrder = new string[9] { "Meadows", "BlackForest", "Swamp", "Ocean", "Mountain", "Plains", "Mistlands", "AshLands", "DeepNorth" }; private static readonly Dictionary BiomeOutputOrderLookup = BuildBiomeOutputOrderLookup(); private static List _configuration = new List(); private static string _configurationSignature = ""; private static string _lastFailedConfigurationPayload = ""; private static bool _configurationReady; private static bool _initialized; private static int? _lastCompletedGameDataSignature; private static int? _pendingGameDataSignature; private static string _lastAppliedConfigurationSignature = ""; private static string _lastAppliedPreparedEntriesSignature = ""; private static int? _lastAppliedGameDataSignature; private static int? _lastCommittedAuthorityEpoch; private static bool? _lastAppliedDomainEnabled; private static int _reconcileQueueEpoch; private static int _requiredGlobalKeyEvaluationDepth; private static int? _lastRuntimeTimeOfDayPhaseMarker; private static int _lastRuntimeTimeOfDayRefreshFrame = -1; private static SpawnSystemSnapshot? _templateSnapshot; private static List? _preparedEntriesCache; private static bool _hasRuntimeTimeOfDayOverrides; private static int _preparedEntriesBuildVersion; private static bool _preparedEntriesBuildInFlight; private static bool _preparedEntriesBuildWorkerRunning; private static PreparedEntriesBuildResult? _completedPreparedEntriesBuildResult; private static PendingPreparedEntriesBuildRequest? _pendingPreparedEntriesBuildRequest; private static PendingCompiledTableBuildState? _pendingCompiledTableBuild; private static CompiledSpawnSystemTable? _activeCompiledTable; private static CompiledSpawnSystemTable? _vanillaCompiledTable; private static GameObject? _managedSpawnListHost; private static GameObject? _attachedSpawnListHost; private static bool _liveSystemsSnapshotDirty = true; private static bool _liveSystemsBootstrapAttempted; private static int? _liveSystemsRegistrySceneInstanceId; private static string _lastAppliedBuildTargetSignature = ""; private static string _pendingBuildTargetSignature = ""; private static bool _waitingForExpandWorldDataBiomeReady; private static bool _deferredQueueEspRefreshForLiveSystems; private static bool _deferredQueueLiveSystemAttach; private static bool _deferredPublishSyncedConfiguration; private static bool _loggedExpandWorldDataBiomeReadyWait; private static HashSet? _capturedStrictValidationWarnings; private static string _lastLoggedSyncedConfigPayloadToken = ""; private static bool _loggedPayloadWaiting; private static string _lastLoggedVanillaRetainedSignature = ""; private static string _lastLoggedRuntimeAttachSignature = ""; private static bool _forceApplyAfterSyncedCommit; private static string _lastLoggedApplySkipKey = ""; private static string _lastLoggedPreparedBuildQueuedSignature = ""; private static int _lastLoggedPreparedBuildCompletedVersion = -1; private static int _lastLoggedCompiledBuildStartedVersion = -1; private static int _lastLoggedCompiledBuildFinishedVersion = -1; private static string _lastLoggedAwakeRetriggerKey = ""; private static int _cachedGameDataSignatureFrame = -1; private static int _cachedGameDataSignatureValue; private static readonly List _cachedConfiguredSpawnSystemResolutionKeys = new List(); private static string _cachedConfiguredSpawnSystemResolutionKeysSignature = ""; private static int _cachedConfiguredSpawnSystemResolutionKeysSceneStamp = int.MinValue; private static readonly DomainConfigurationRuntime ConfigurationRuntime = new DomainConfigurationRuntime(new DomainLoadHooks(ParseLocalConfigurationDocuments, BuildSyncedConfigurationState, CommitConfigurationState, RejectLocalConfigurationPayload, (SyncedSpawnSystemConfigurationState state) => state.Configuration.Count, LogPartiallyAcceptedLocalConfiguration, LogLocalConfigurationLoaded, OnSourceOfTruthPayloadUnchanged, PublishSyncedConfigurationOrDeferLocked, CanStrictlyValidateLocalConfigurationNow, StrictValidateLocalConfiguration), new DomainSyncHooks(delegate(out List configuration, out string payloadToken) { return ConfigurationDomainHost.TryGetSyncedEntries(Descriptor, out configuration, out payloadToken, ClearPayloadWaitingLogState); }, (string payloadToken) => ConfigurationDomainHost.ShouldSkipSyncedPayload(LoadState, payloadToken, _configurationReady), BuildSyncedConfigurationState, CommitConfigurationState, (SyncedSpawnSystemConfigurationState state) => state.Configuration.Count, "ServerSync:DropNSpawnSpawnSystem", delegate { ConfigurationDomainHost.HandleWaitingForSyncedPayload(MarkSyncedPayloadPending, "Waiting for synchronized spawnsystem override payload from the server.", LogPayloadWaitingIfNeeded); }, LogSyncedSpawnSystemConfigurationLoaded, LogSyncedSpawnSystemConfigurationFailure)); internal static DomainDescriptor Descriptor => Module.DescriptorTyped; internal static DomainTransportMetadata TransportMetadata => Module.TransportMetadataTyped; private static DomainLoadState LoadState => ConfigurationRuntime.LoadState; private static string ReferenceConfigurationPath => Path.Combine(DropNSpawnPlugin.YamlConfigDirectoryPath, PluginSettingsFacade.GetYamlDomainFilePrefix("spawnsystem") + ".reference.yml"); private static string PrimaryOverrideConfigurationPathYml => Path.Combine(DropNSpawnPlugin.YamlConfigDirectoryPath, PluginSettingsFacade.GetYamlDomainFilePrefix("spawnsystem") + ".yml"); private static string PrimaryOverrideConfigurationPathYaml => Path.Combine(DropNSpawnPlugin.YamlConfigDirectoryPath, PluginSettingsFacade.GetYamlDomainFilePrefix("spawnsystem") + ".yaml"); private static string FullScaffoldConfigurationPath => Path.Combine(DropNSpawnPlugin.YamlConfigDirectoryPath, PluginSettingsFacade.GetYamlDomainFilePrefix("spawnsystem") + ".full.yml"); internal static bool ShouldReloadForPath(string? path) { if (PluginSettingsFacade.IsEligibleOverrideConfigurationPath(path)) { return IsOverrideConfigurationFileName(Path.GetFileName(path ?? "")); } return false; } private static bool ShouldApplyLocally() { return PluginSettingsFacade.IsSpawnSystemDomainEnabled(); } internal static void MarkSyncedPayloadPending() { lock (Sync) { ConfigurationRuntime.MarkSyncedPayloadPending(DropNSpawnPlugin.IsSourceOfTruth, delegate { ClearQueuedReconcileState(); ResetPreparedEntriesBuildPipelineLocked(clearPendingTargetSignature: true); ClearPayloadWaitingLogState(); _configurationReady = false; _forceApplyAfterSyncedCommit = false; }); } } internal static void EnterPendingSyncedPayloadState() { lock (Sync) { ConfigurationRuntime.EnterPendingSyncedPayloadState(DropNSpawnPlugin.IsSourceOfTruth, ResetLoadedConfigurationState, delegate { _configurationSignature = ""; _lastFailedConfigurationPayload = ""; _lastCommittedAuthorityEpoch = null; _lastAppliedConfigurationSignature = ""; _lastAppliedPreparedEntriesSignature = ""; _lastAppliedBuildTargetSignature = ""; _lastAppliedGameDataSignature = null; _lastAppliedDomainEnabled = null; _forceApplyAfterSyncedCommit = false; RestoreBaselineWhileWaitingForSyncedPayload(); }); } } private static bool CanRetainCurrentCompiledTableWhilePending(int gameDataSignature) { if (ShouldApplyLocally() && !DropNSpawnPlugin.IsSourceOfTruth && !_configurationReady && gameDataSignature != 0 && _activeCompiledTable != null && _activeCompiledTable.Lists.Count > 0 && _lastAppliedGameDataSignature == gameDataSignature) { return _lastCommittedAuthorityEpoch == NetworkPayloadSyncSupport.CurrentAuthorityEpoch; } return false; } private static void RestoreBaselineWhileWaitingForSyncedPayload() { int num = ComputeGameDataSignature(); if (num == 0) { _activeCompiledTable = null; return; } CompiledSpawnSystemTable? selectedCompiledTableForCurrentState = GetSelectedCompiledTableForCurrentState(); List liveSystems = GetLiveSystems(); EnsureVanillaCompiledTableCurrentLocked(num); _activeCompiledTable = null; CompiledSpawnSystemTable selectedCompiledTableForCurrentState2 = GetSelectedCompiledTableForCurrentState(); QueueLiveSystemAttachForTable(selectedCompiledTableForCurrentState2, _preparedEntriesBuildVersion, queueEspRefresh: true, liveSystems); RetireCompiledTableAfterMigrationLocked(selectedCompiledTableForCurrentState, selectedCompiledTableForCurrentState2, liveSystems); LogVanillaRetainedIfNeeded("cutover_pending|" + num.ToString(CultureInfo.InvariantCulture), "authority_cutover_pending", selectedCompiledTableForCurrentState2, liveSystems.Count); } internal static void Initialize() { lock (Sync) { if (!_initialized) { LoadConfiguration(); _initialized = true; } } } internal static void ReloadConfiguration() { lock (Sync) { InvalidatePreparedEntriesCache(); LoadConfiguration(); ApplyIfReady(queueEspRefreshForLiveSystems: true, queueLiveSystemAttach: true); } } internal static bool HandleExpandWorldDataReady() { lock (Sync) { if (!DropNSpawnPlugin.IsSourceOfTruth) { return false; } string lastLoadedPayload = LoadState.LastLoadedPayload; string configurationSignature = _configurationSignature; bool num = LoadState.PendingStrictPayload.Length > 0; bool flag = _waitingForExpandWorldDataBiomeReady || _deferredPublishSyncedConfiguration; LoadConfiguration(); ApplyIfReady(queueEspRefreshForLiveSystems: true, queueLiveSystemAttach: true); return num || flag || !string.Equals(lastLoadedPayload, LoadState.LastLoadedPayload, StringComparison.Ordinal) || !string.Equals(configurationSignature, _configurationSignature, StringComparison.Ordinal); } } internal static void ApplySyncedPayload() { lock (Sync) { ConfigurationRuntime.ApplySyncedPayload(delegate { _forceApplyAfterSyncedCommit = true; ApplyIfReady(queueEspRefreshForLiveSystems: true, queueLiveSystemAttach: true); }); } } internal static void OnGameDataReady(string source) { lock (Sync) { if (!_initialized) { Initialize(); } EnsureLiveSystemRegistrySessionLocked(); int num = ComputeGameDataSignature(); if (_lastCompletedGameDataSignature != num && _pendingGameDataSignature != num) { _pendingGameDataSignature = num; ClearQueuedReconcileState(); RefreshSnapshots(); InvalidatePreparedEntriesCache(); if (DropNSpawnPlugin.IsSourceOfTruth) { HandleSourceOfTruthGameDataReady(); } ApplyIfReady(queueEspRefreshForLiveSystems: false, queueLiveSystemAttach: true); DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)("SpawnSystem processing scheduled after " + source + ".")); } } } internal static void OnSpawnSystemAwake(SpawnSystem? system) { lock (Sync) { TrackLiveSystemLocked(system); if ((Object)(object)system == (Object)null || (Object)(object)ZNetScene.instance == (Object)null || (Object)(object)ObjectDB.instance == (Object)null || DropNSpawnPlugin.IsGameDataRefreshDeferred(DropNSpawnPlugin.ReloadDomain.SpawnSystem)) { return; } bool flag = PreAttachedSpawnSystemIds.Remove(((Object)system).GetInstanceID()); CompiledSpawnSystemTable selectedCompiledTableForCurrentState = GetSelectedCompiledTableForCurrentState(); bool flag2 = flag && !IsSystemAttachedToCompiledTable(system, selectedCompiledTableForCurrentState); bool flag3 = !flag || flag2; LogLiveSpawnListState("awake_postfix_entry", system, selectedCompiledTableForCurrentState, flag); if (DropNSpawnPlugin.IsSourceOfTruth) { if (HandleSourceOfTruthSpawnSystemAwake()) { ApplyIfReady(flag3); return; } } else if (!_configurationReady) { if (!CanRetainCurrentCompiledTableWhilePending(ComputeGameDataSignature())) { return; } } else if (_configurationReady && (_activeCompiledTable == null || _activeCompiledTable.Lists.Count == 0)) { LogAwakeRetriggerIfNeeded(system, GetLiveSystems().Count); ApplyIfReady(flag3, queueLiveSystemAttach: true); if (_activeCompiledTable == null || _activeCompiledTable.Lists.Count == 0) { return; } } AttachCompiledTableToAwakenedSystem(system, flag3); } } internal static void PreAttachCompiledTableToAwakeningSystem(SpawnSystem? system) { lock (Sync) { TrackLiveSystemLocked(system); if (!((Object)(object)system == (Object)null) && ShouldApplyLocally() && !DropNSpawnPlugin.IsGameDataRefreshDeferred(DropNSpawnPlugin.ReloadDomain.SpawnSystem) && (DropNSpawnPlugin.IsSourceOfTruth || ((!_configurationReady || (_activeCompiledTable != null && _activeCompiledTable.Lists.Count != 0)) && (_configurationReady || CanRetainCurrentCompiledTableWhilePending(ComputeGameDataSignature()))))) { CompiledSpawnSystemTable selectedCompiledTableForCurrentState = GetSelectedCompiledTableForCurrentState(); if (selectedCompiledTableForCurrentState != null) { AttachTableToSystem(system, selectedCompiledTableForCurrentState); LogLiveSpawnListState("awake_prefix_preattach", system, selectedCompiledTableForCurrentState, preAttached: true); PreAttachedSpawnSystemIds.Add(((Object)system).GetInstanceID()); } } } } internal static void UntrackLiveSystem(SpawnSystem? system) { lock (Sync) { UntrackLiveSystemLocked(system); } } internal static bool ShouldBlockClientSpawnSystemUpdate(SpawnSystem? system) { lock (Sync) { if (!ShouldApplyLocally() || DropNSpawnPlugin.IsSourceOfTruth) { return false; } if (!_configurationReady) { return true; } if (_activeCompiledTable == null || _activeCompiledTable.Lists.Count == 0) { return true; } return !IsSystemAttachedToCompiledTable(system, _activeCompiledTable); } } internal static bool ProcessQueuedReconcileStep(float deadline) { lock (Sync) { if (Time.realtimeSinceStartup >= deadline) { return false; } if (DropNSpawnPlugin.IsGameDataRefreshDeferred(DropNSpawnPlugin.ReloadDomain.SpawnSystem)) { return false; } if (TryActivateCompletedPreparedEntriesBuildLocked()) { return true; } if (TryProcessDeferredExpandWorldDataBiomeReadyLocked()) { return true; } if (TryProcessPendingCompiledTableBuild(deadline)) { return true; } if (TryProcessPendingLiveSystemAttach(deadline)) { return true; } if (EspSpawnSystemCompatibility.TryProcessPendingRefresh(deadline, _reconcileQueueEpoch)) { return true; } } return false; } internal static bool HasPendingReconcileWork() { lock (Sync) { return _completedPreparedEntriesBuildResult != null || _pendingCompiledTableBuild != null || _waitingForExpandWorldDataBiomeReady || _deferredPublishSyncedConfiguration || PendingLiveSystemAttaches.Count > 0 || EspSpawnSystemCompatibility.HasPendingRefreshes(); } } private static void HandleSourceOfTruthGameDataReady() { EnsurePrimaryOverrideConfigurationFileExists(); LoadConfiguration(); } private static void EnsureLiveSystemRegistrySessionLocked() { int num = (((Object)(object)ZNetScene.instance != (Object)null) ? ((Object)ZNetScene.instance).GetInstanceID() : 0); if (_liveSystemsRegistrySceneInstanceId != num) { FinalizeAllPendingCompiledTableRetirementsLocked(); _liveSystemsRegistrySceneInstanceId = num; LiveSystemsById.Clear(); LiveSystemsSnapshot.Clear(); _liveSystemsSnapshotDirty = true; _liveSystemsBootstrapAttempted = false; SnapshotsBySystemId.Clear(); _templateSnapshot = null; PendingLiveSystemAttaches.Clear(); PendingLiveSystemAttachIds.Clear(); PendingLiveSystemAttachEspRefreshIds.Clear(); EspSpawnSystemCompatibility.ClearPendingRefreshes(); PreAttachedSpawnSystemIds.Clear(); ResetPreparedEntriesBuildPipelineLocked(clearPendingTargetSignature: true); } } private static void TrackLiveSystemLocked(SpawnSystem? system) { EnsureLiveSystemRegistrySessionLocked(); if (!((Object)(object)system == (Object)null)) { int instanceID = ((Object)system).GetInstanceID(); LiveSystemsById[instanceID] = system; _liveSystemsSnapshotDirty = true; } } private static void UntrackLiveSystemLocked(SpawnSystem? system) { EnsureLiveSystemRegistrySessionLocked(); if (!((Object)(object)system == (Object)null)) { int instanceID = ((Object)system).GetInstanceID(); if (LiveSystemsById.Remove(instanceID)) { ClearAttachedRuntimeState(system); _liveSystemsSnapshotDirty = true; SnapshotsBySystemId.Remove(instanceID); _templateSnapshot = null; PendingLiveSystemAttachIds.Remove(instanceID); PendingLiveSystemAttachEspRefreshIds.Remove(instanceID); EspSpawnSystemCompatibility.RemovePendingRefresh(instanceID); PreAttachedSpawnSystemIds.Remove(instanceID); MarkSystemMigratedFromRetiredTablesLocked(instanceID); } } } private static bool HandleSourceOfTruthSpawnSystemAwake() { bool num = EnsurePrimaryOverrideConfigurationFileExists(); if (num) { LoadConfiguration(); } if (!num) { return _activeCompiledTable == null; } return true; } private static void AttachCompiledTableToAwakenedSystem(SpawnSystem system, bool queueEspRefresh) { CompiledSpawnSystemTable selectedCompiledTableForCurrentState = GetSelectedCompiledTableForCurrentState(); if (selectedCompiledTableForCurrentState != null) { AttachTableToSystem(system, selectedCompiledTableForCurrentState); LogLiveSpawnListState("awake_postfix_attached", system, selectedCompiledTableForCurrentState); MarkSystemMigratedFromRetiredTablesLocked(((Object)system).GetInstanceID()); if (queueEspRefresh) { QueueEspMarkerRefresh(system); } } } private static bool TryProcessPendingLiveSystemAttach(float deadline) { while (PendingLiveSystemAttaches.Count > 0) { if (Time.realtimeSinceStartup >= deadline) { return false; } if (!PendingLiveSystemAttaches.TryDequeue(out var item)) { continue; } bool flag = PendingLiveSystemAttachEspRefreshIds.Remove(item.SystemId); PendingLiveSystemAttachIds.Remove(item.SystemId); if (item.Epoch == _reconcileQueueEpoch && !((Object)(object)item.System == (Object)null)) { if (item.BuildVersion != _preparedEntriesBuildVersion || item.TargetTable != GetSelectedCompiledTableForCurrentState()) { return true; } if (item.TargetTable == null) { return true; } AttachTableToSystem(item.System, item.TargetTable); LogLiveSpawnListState("queued_attach_applied", item.System, item.TargetTable); MarkSystemMigratedFromRetiredTablesLocked(item.SystemId); if (flag) { QueueEspMarkerRefresh(item.System); } return true; } } return false; } internal static void RefreshRuntimeTimeOfDayState() { if (!_hasRuntimeTimeOfDayOverrides) { return; } int frameCount = Time.frameCount; if (_lastRuntimeTimeOfDayRefreshFrame == frameCount) { return; } lock (Sync) { if (!ShouldApplyLocally()) { _lastRuntimeTimeOfDayPhaseMarker = null; _lastRuntimeTimeOfDayRefreshFrame = -1; } else { if (!_hasRuntimeTimeOfDayOverrides || _lastRuntimeTimeOfDayRefreshFrame == frameCount) { return; } int currentRuntimePhaseMarker = TimeOfDayFormatting.GetCurrentRuntimePhaseMarker(); if (_lastRuntimeTimeOfDayPhaseMarker.HasValue && _lastRuntimeTimeOfDayPhaseMarker.Value == currentRuntimePhaseMarker) { _lastRuntimeTimeOfDayRefreshFrame = frameCount; return; } foreach (var (val2, definition) in TimeOfDayBySpawnData) { if (val2 != null) { TimeOfDayFormatting.GetRuntimeSpawnFlags(definition, out var allowDay, out var allowNight); val2.m_spawnAtDay = allowDay; val2.m_spawnAtNight = allowNight; } } _lastRuntimeTimeOfDayPhaseMarker = currentRuntimePhaseMarker; _lastRuntimeTimeOfDayRefreshFrame = frameCount; } } } private static void QueueEspMarkerRefresh(SpawnSystem? system) { EspSpawnSystemCompatibility.RequestRefresh(system, _reconcileQueueEpoch); } internal static void RecordDirectSpawnedObject(SpawnData critter, GameObject? spawnedObject) { lock (Sync) { if (critter != null) { _ = (Object)(object)spawnedObject == (Object)null; } } } internal static bool TryWriteFullScaffoldConfigurationFile(out string path, out string error) { lock (Sync) { path = FullScaffoldConfigurationPath; error = ""; if (!TryCaptureSnapshotsIfNeeded()) { error = "SpawnSystem game data is not ready yet."; return false; } Directory.CreateDirectory(DropNSpawnPlugin.YamlConfigDirectoryPath); File.WriteAllText(path, BuildFullScaffoldConfigurationTemplate()); DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)("Wrote spawnsystem full scaffold configuration to " + path + ".")); return true; } } internal static bool TryWriteReferenceConfigurationFile(out string path, out string error) { lock (Sync) { path = ReferenceConfigurationPath; error = ""; if ((Object)(object)ZNetScene.instance == (Object)null || (Object)(object)ObjectDB.instance == (Object)null) { error = "SpawnSystem game data is not ready yet."; return false; } ReferenceCatalogSnapshot referenceCatalogSnapshot = BuildCurrentReferenceCatalogSnapshot(); if (!referenceCatalogSnapshot.HasAnyEntries) { error = "SpawnSystem game data is not ready yet."; return false; } WriteReferenceConfigurationFile(BuildReferenceConfigurationTemplate(referenceCatalogSnapshot), "Updated spawnsystem reference configuration at " + ReferenceConfigurationPath + "."); path = ReferenceConfigurationPath; return true; } } internal static void RefreshReferenceConfigurationFile() { lock (Sync) { if (!((Object)(object)ZNetScene.instance == (Object)null) && !((Object)(object)ObjectDB.instance == (Object)null)) { ReferenceCatalogSnapshot referenceCatalogSnapshot = BuildCurrentReferenceCatalogSnapshot(); if (referenceCatalogSnapshot.HasAnyEntries) { WriteReferenceConfigurationFile(BuildReferenceConfigurationTemplate(referenceCatalogSnapshot), "Updated spawnsystem reference configuration at " + ReferenceConfigurationPath + "."); } } } } private static bool EnsurePrimaryOverrideConfigurationFileExists() { if (File.Exists(PrimaryOverrideConfigurationPathYml) || File.Exists(PrimaryOverrideConfigurationPathYaml) || EnumerateSupplementalOverrideConfigurationPaths().Any()) { return false; } SpawnSystemSnapshot templateSnapshot = GetTemplateSnapshot(); if (templateSnapshot == null || templateSnapshot.Entries.Count == 0) { return false; } Directory.CreateDirectory(DropNSpawnPlugin.YamlConfigDirectoryPath); File.WriteAllText(PrimaryOverrideConfigurationPathYml, BuildCompressedPrimaryOverrideConfigurationDocument(templateSnapshot)); DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)("Created spawnsystem override configuration at " + PrimaryOverrideConfigurationPathYml + ".")); return true; } private static void LoadConfiguration() { if (DropNSpawnPlugin.IsSourceOfTruth) { ConfigurationRuntime.ReloadSourceOfTruth(EnumerateOverrideConfigurationPaths().ToList()); } else { ConfigurationRuntime.ReloadSynced(); } } private static void ResetLoadedConfigurationState() { ClearQueuedReconcileState(); ClearPayloadWaitingLogState(); ResetPreparedEntriesBuildPipelineLocked(clearPendingTargetSignature: true); InvalidEntryWarnings.Clear(); _configuration = new List(); _configurationReady = false; _waitingForExpandWorldDataBiomeReady = false; _deferredQueueEspRefreshForLiveSystems = false; _deferredQueueLiveSystemAttach = false; _deferredPublishSyncedConfiguration = false; _loggedExpandWorldDataBiomeReadyWait = false; InvalidatePreparedEntriesCache(); } private static List CloneAndNormalizeConfigurationEntries(List? configuration, string sourceName) { List list = NetworkPayloadSyncSupport.CloneEntries(Descriptor, configuration); foreach (CanonicalSpawnSystemEntry item in list) { item.SourcePath = (string.IsNullOrWhiteSpace(item.SourcePath) ? sourceName : item.SourcePath); } if (list.Count > 0) { NormalizeConfiguration(list); } return list; } private static SyncedSpawnSystemConfigurationState BuildSyncedConfigurationState(List configuration, string sourceName) { using (BeginInvalidEntryWarningSuppressionForSyncedClientBuild(sourceName)) { SyncedSpawnSystemConfigurationState syncedSpawnSystemConfigurationState = new SyncedSpawnSystemConfigurationState { ConfigurationReady = true }; foreach (CanonicalSpawnSystemEntry item in CloneAndNormalizeConfigurationEntries(configuration, sourceName)) { syncedSpawnSystemConfigurationState.Configuration.Add(item); } syncedSpawnSystemConfigurationState.ConfigurationSignature = NetworkPayloadSyncSupport.ComputeSpawnSystemConfigurationSignature(syncedSpawnSystemConfigurationState.Configuration); return syncedSpawnSystemConfigurationState; } } private static LocalLoadResult ParseLocalConfigurationDocuments(List documents) { List list = new List(); List list2 = new List(); List list3 = new List(); int num = 0; foreach (ConfigurationLoadSupport.LocalYamlDocument document in documents) { if (document.ReadError != null) { list2.Add("Failed to read " + document.Path + ". " + document.ReadError); continue; } try { ParsedSpawnSystemConfigurationDocument parsedSpawnSystemConfigurationDocument = ParseConfiguration(document.Yaml ?? "", document.Path); list3.AddRange(parsedSpawnSystemConfigurationDocument.Warnings); List collection = CloneAndNormalizeConfigurationEntries(parsedSpawnSystemConfigurationDocument.Configuration, document.Path); list.AddRange(collection); num++; } catch (Exception ex) { list2.Add($"Failed to parse {document.Path}{FormatYamlExceptionLocation(ex)}. Spawnsystem authoritative YAML must start with a root list like '- prefab: Fox'. {ex}"); } } return new LocalLoadResult { Entries = list, Errors = list2, Warnings = list3, ParsedEntryCount = list.Count, LoadedFileCount = num }; } private static bool CanStrictlyValidateLocalConfigurationNow(IEnumerable configuration) { if ((Object)(object)ZNetScene.instance != (Object)null && (Object)(object)ObjectDB.instance != (Object)null) { return !ShouldDeferForExpandWorldDataBiomeReady(configuration); } return false; } private static List FilterStrictlyValidatedLocalConfiguration(IEnumerable configuration, out List warnings) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected O, but got Unknown warnings = new List(); List list = new List(); HashSet hashSet = (_capturedStrictValidationWarnings = new HashSet(StringComparer.OrdinalIgnoreCase)); try { List list2 = configuration?.ToList() ?? new List(); for (int i = 0; i < list2.Count; i++) { CanonicalSpawnSystemEntry canonicalSpawnSystemEntry = list2[i]; string text = CreateConfigurationContext(i, canonicalSpawnSystemEntry); int count = hashSet.Count; try { SpawnData val = new SpawnData(); if (!ApplyEntry(val, canonicalSpawnSystemEntry, text, applyCustomData: false)) { if (hashSet.Count == count) { warnings.Add("Entry '" + text + "' failed strict spawnsystem validation and was skipped."); } } else { SpawnSystemCustomDataSupport.BuildPreparedPayload(val, canonicalSpawnSystemEntry, text); list.Add(canonicalSpawnSystemEntry); } } catch (Exception ex) { warnings.Add("Entry '" + text + "' failed strict spawnsystem validation and was skipped. " + ex.Message); } } } finally { _capturedStrictValidationWarnings = null; } foreach (string item in hashSet) { warnings.Add(item); } return list; } private static StrictValidationResult StrictValidateLocalConfiguration(List configuration) { RefreshResolvedBiomeMasksForConfiguration(configuration); List warnings; List entries = FilterStrictlyValidatedLocalConfiguration(configuration, out warnings); return new StrictValidationResult { Entries = entries, Warnings = warnings }; } private static void LogPartiallyAcceptedLocalConfiguration(int totalEntries, int acceptedEntries, IEnumerable warnings) { int num = Math.Max(0, totalEntries - acceptedEntries); DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("Skipped " + num.ToString(CultureInfo.InvariantCulture) + " invalid spawnsystem entr" + ((num == 1) ? "y" : "ies") + " and kept " + acceptedEntries.ToString(CultureInfo.InvariantCulture) + " valid entr" + ((acceptedEntries == 1) ? "y" : "ies") + ".")); foreach (string item in warnings.Where((string message) => !string.IsNullOrWhiteSpace(message)).Distinct(StringComparer.OrdinalIgnoreCase)) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)item); } } private static string BuildStrictLocalValidationEnvironmentKey() { int num = ComputeGameDataSignature(); string text = (BiomeResolutionSupport.IsExpandWorldDataReadyOrUnavailable() ? "ready" : "waiting"); return num.ToString(CultureInfo.InvariantCulture) + "|" + text; } private static void RejectLocalConfigurationPayload(string payload, IEnumerable errors) { string text = BuildStrictLocalValidationEnvironmentKey(); if (string.Equals(LoadState.LastRejectedPayload, payload, StringComparison.Ordinal) && string.Equals(LoadState.LastRejectedValidationKey, text, StringComparison.Ordinal)) { return; } LoadState.LastRejectedPayload = payload; LoadState.LastRejectedValidationKey = text; LoadState.PendingStrictPayload = ""; DropNSpawnPlugin.DropNSpawnLogger.LogError((object)"Rejected spawnsystem reload. Keeping the previous authoritative spawnsystem configuration."); foreach (string item in errors.Where((string message) => !string.IsNullOrWhiteSpace(message)).Distinct(StringComparer.OrdinalIgnoreCase)) { DropNSpawnPlugin.DropNSpawnLogger.LogError((object)item); } } private static void CommitConfigurationState(SyncedSpawnSystemConfigurationState state, string payloadToken) { ResetLoadedConfigurationState(); _configuration = state.Configuration; _configurationReady = state.ConfigurationReady; _configurationSignature = state.ConfigurationSignature; _lastCommittedAuthorityEpoch = (DropNSpawnPlugin.IsSourceOfTruth ? null : new int?(NetworkPayloadSyncSupport.CurrentAuthorityEpoch)); LoadState.LastLoadedPayload = payloadToken; _lastFailedConfigurationPayload = ""; LoadState.LastRejectedPayload = ""; LoadState.LastRejectedValidationKey = ""; LoadState.PendingStrictPayload = ""; } private static void LogLocalConfigurationLoaded(int acceptedEntryCount, int loadedFileCount) { DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)$"Loaded {acceptedEntryCount} spawnsystem configuration(s) from {loadedFileCount} override file(s)."); } private static void OnSourceOfTruthPayloadUnchanged() { RefreshResolvedBiomeMasksForSourceOfTruthConfigurationLocked(); _configurationSignature = NetworkPayloadSyncSupport.ComputeSpawnSystemConfigurationSignature(_configuration); if (!NetworkPayloadSyncSupport.IsPayloadCurrent(Descriptor, _configurationSignature) || _waitingForExpandWorldDataBiomeReady || _deferredPublishSyncedConfiguration) { PublishSyncedConfigurationOrDeferLocked(); } } private static void LogSyncedSpawnSystemConfigurationLoaded(string payloadToken, int acceptedEntryCount) { LogSyncedConfigCommittedIfNeeded(payloadToken, acceptedEntryCount); } private static void LogSyncedSpawnSystemConfigurationFailure(string payloadToken, Exception ex) { LogSyncedConfigurationFailureOnce(payloadToken, ex); } private static void LogPayloadWaitingIfNeeded() { if (!_loggedPayloadWaiting) { _loggedPayloadWaiting = true; DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)("Spawnsystem sync stage=payload_waiting lastCommittedHash=" + ((LoadState.LastLoadedPayload.Length > 0) ? LoadState.LastLoadedPayload : ""))); } } private static void ClearPayloadWaitingLogState() { _loggedPayloadWaiting = false; } private static void LogSyncedConfigurationFailureOnce(string payloadToken, Exception ex) { if (!string.Equals(_lastFailedConfigurationPayload, payloadToken, StringComparison.Ordinal)) { DropNSpawnPlugin.DropNSpawnLogger.LogError((object)$"Failed to deserialize synchronized spawnsystem payload DTO. {ex}"); _lastFailedConfigurationPayload = payloadToken; } } private static void ClearQueuedReconcileState() { _reconcileQueueEpoch++; PendingLiveSystemAttaches.Clear(); PendingLiveSystemAttachIds.Clear(); PendingLiveSystemAttachEspRefreshIds.Clear(); EspSpawnSystemCompatibility.ClearPendingRefreshes(); PreAttachedSpawnSystemIds.Clear(); } private static void ResetPreparedEntriesBuildPipelineLocked(bool clearPendingTargetSignature) { _preparedEntriesBuildVersion++; _preparedEntriesBuildInFlight = false; _completedPreparedEntriesBuildResult = null; _pendingPreparedEntriesBuildRequest = null; _pendingCompiledTableBuild = null; _pendingGameDataSignature = null; if (clearPendingTargetSignature) { _pendingBuildTargetSignature = ""; } } [IteratorStateMachine(typeof(d__160))] private static IEnumerable EnumerateOverrideConfigurationPaths() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__160(-2); } private static IEnumerable EnumerateSupplementalOverrideConfigurationPaths() { return DomainConfigurationFileSupport.EnumerateSupplementalOverrideConfigurationPaths("spawnsystem", IsOverrideConfigurationFileName); } private static ParsedSpawnSystemConfigurationDocument ParseConfiguration(string yaml, string? sourcePath) { ParsedSpawnSystemConfigurationDocument parsedSpawnSystemConfigurationDocument = new ParsedSpawnSystemConfigurationDocument(); if (string.IsNullOrWhiteSpace(yaml)) { return parsedSpawnSystemConfigurationDocument; } checked { using StringReader input = new StringReader(yaml); YamlStream yamlStream = new YamlStream(); yamlStream.Load(input); if (yamlStream.Documents.Count == 0) { return parsedSpawnSystemConfigurationDocument; } YamlSequenceNode obj = yamlStream.Documents[0].RootNode as YamlSequenceNode; if (obj == null) { Mark start = yamlStream.Documents[0].RootNode.Start; Mark end = yamlStream.Documents[0].RootNode.End; throw new YamlException(in start, in end, "Spawnsystem authoritative YAML root must be a sequence."); } foreach (YamlNode child in obj.Children) { if (!(child is YamlMappingNode yamlMappingNode)) { parsedSpawnSystemConfigurationDocument.Warnings.Add("Skipped spawnsystem YAML node at " + FormatYamlNodeLocation(sourcePath, child.Start) + ". Expected a list item object like '- prefab: Fox' but found " + DescribeYamlNode(child) + "."); continue; } try { string input2 = SerializeYamlNode(yamlMappingNode); CanonicalSpawnSystemEntry canonicalSpawnSystemEntry = Deserializer.Deserialize(input2) ?? new CanonicalSpawnSystemEntry(); canonicalSpawnSystemEntry.SourceLine = (int)yamlMappingNode.Start.Line; canonicalSpawnSystemEntry.SourceColumn = (int)yamlMappingNode.Start.Column; parsedSpawnSystemConfigurationDocument.Configuration.Add(canonicalSpawnSystemEntry); } catch (Exception ex) { parsedSpawnSystemConfigurationDocument.Warnings.Add("Skipped invalid spawnsystem entry at " + FormatYamlNodeLocation(sourcePath, yamlMappingNode.Start) + ". " + FormatEntryParseFailure(ex)); } } return parsedSpawnSystemConfigurationDocument; } } private static string SerializeYamlNode(YamlNode node) { YamlStream yamlStream = new YamlStream(new YamlDocument(node)); using StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture); yamlStream.Save(stringWriter, assignAnchors: false); return stringWriter.ToString(); } private static string DescribeYamlNode(YamlNode node) { if (node is YamlScalarNode yamlScalarNode) { string text = yamlScalarNode.Value ?? ""; if (text.Length != 0) { return "scalar '" + text + "'"; } return "an empty scalar"; } if (node is YamlSequenceNode) { return "a nested sequence"; } if (node is YamlMappingNode) { return "a mapping"; } return "an unknown YAML node"; } private static string FormatYamlNodeLocation(string? sourcePath, Mark mark) { string text = (string.IsNullOrWhiteSpace(sourcePath) ? "inline YAML" : Path.GetFileName(sourcePath)); if (mark.Line > 0) { text = text + ":" + mark.Line.ToString(CultureInfo.InvariantCulture); } return text; } private static string FormatEntryParseFailure(Exception ex) { if (ex is YamlException ex2) { return ex2.Message; } return ex.Message; } private static void NormalizeConfiguration(List configuration) { if (configuration == null) { configuration = new List(); } Dictionary dictionary = new Dictionary(StringComparer.Ordinal); foreach (CanonicalSpawnSystemEntry item in configuration) { NormalizeEntry(item); string text = NormalizeOptionalRuleId(item.RuleId); if (text != null) { item.RuleId = text; continue; } string text2 = BuildRuleId(item); dictionary.TryGetValue(text2, out var value); item.RuleId = ((value == 0) ? text2 : $"{text2}#{value}"); dictionary[text2] = value + 1; } } private static void NormalizeEntry(CanonicalSpawnSystemEntry entry) { entry.Prefab = NormalizeOptionalString(entry.Prefab); string context = entry.SpawnSystem?.Name ?? entry.Prefab ?? "(unnamed)"; NormalizeSpawnSystemSpawn(entry.SpawnSystem, context); NormalizeSpawnSystemConditions(entry.Conditions, context); NormalizeSpawnSystemModifiers(entry.Modifiers); } private static string BuildRuleId(CanonicalSpawnSystemEntry entry) { CanonicalSpawnSystemEntry entry2 = new CanonicalSpawnSystemEntry { Prefab = entry.Prefab, Enabled = true, SpawnSystem = ((entry.SpawnSystem != null) ? ConfigurationEntryCloneSupport.CloneSpawnSystemSpawnDefinition(entry.SpawnSystem) : null), Conditions = ((entry.Conditions != null) ? ConfigurationEntryCloneSupport.CloneSpawnSystemConditionsDefinition(entry.Conditions) : null), Modifiers = ((entry.Modifiers != null) ? ConfigurationEntryCloneSupport.CloneSpawnSystemModifiersDefinition(entry.Modifiers) : null) }; return entry.Prefab + ":" + NetworkPayloadSyncSupport.ComputeSpawnSystemEntryIdentitySignature(entry2); } private static string? NormalizeOptionalRuleId(string? ruleId) { if (ruleId == null) { return null; } string text = ruleId.Trim(); if (text.Length != 0) { return text; } return null; } private static void ApplyIfReady(bool queueEspRefreshForLiveSystems, bool queueLiveSystemAttach = false) { int num = ComputeGameDataSignature(); if (num == 0) { LogApplySkipIfNeeded("game_data_unavailable", "Spawnsystem sync stage=apply_skipped reason=game_data_unavailable"); return; } bool flag = ShouldApplyLocally(); string text = BuildApplyTargetSignature(num, flag); if (!_forceApplyAfterSyncedCommit && string.Equals(_lastAppliedBuildTargetSignature, text, StringComparison.Ordinal)) { LogApplySkipIfNeeded("already_applied|" + text, "Spawnsystem sync stage=apply_skipped reason=already_applied target=" + text); return; } if (string.Equals(_pendingBuildTargetSignature, text, StringComparison.Ordinal) && (_preparedEntriesBuildInFlight || _completedPreparedEntriesBuildResult != null || _pendingCompiledTableBuild != null)) { LogApplySkipIfNeeded("pending_build|" + text, $"Spawnsystem sync stage=apply_skipped reason=pending_build target={text} prepared_in_flight={_preparedEntriesBuildInFlight} prepared_ready={_completedPreparedEntriesBuildResult != null} compiled_pending={_pendingCompiledTableBuild != null}"); return; } if (DropNSpawnPlugin.IsSourceOfTruth) { EnsurePrimaryOverrideConfigurationFileExists(); } bool flag2 = _lastAppliedGameDataSignature == num; if (!flag && flag2 && _lastAppliedDomainEnabled == false) { RecordAppliedState(num, flag, "", text); } else if (!flag) { ApplySelectedTableWithoutActiveBuild(num, flag, queueEspRefreshForLiveSystems, text); } else if (!_configurationReady) { if (CanRetainCurrentCompiledTableWhilePending(num)) { RetainCurrentCompiledTableWhilePending(num, queueEspRefreshForLiveSystems, queueLiveSystemAttach, text); } else { ApplySelectedTableWithoutActiveBuild(num, flag, queueEspRefreshForLiveSystems, text); } } else if (ShouldDeferForExpandWorldDataBiomeReadyLocked()) { DeferExpandWorldDataBiomeReadyLocked(queueEspRefreshForLiveSystems, queueLiveSystemAttach, publishSyncedConfiguration: false); } else { QueuePreparedEntriesBuildLocked(num, flag, text, queueEspRefreshForLiveSystems); } } private static void LogSyncedConfigCommittedIfNeeded(string payloadToken, int entryCount) { string text = payloadToken ?? ""; if (!string.Equals(_lastLoggedSyncedConfigPayloadToken, text, StringComparison.Ordinal)) { _lastLoggedSyncedConfigPayloadToken = text; if (PluginSettingsFacade.IsSpawnSystemDiagnosticsEnabled()) { DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)("Spawnsystem sync stage=config_committed hash=" + ((text.Length > 0) ? text : "") + " entries=" + entryCount.ToString(CultureInfo.InvariantCulture) + " build=" + DropNSpawnPlugin.RuntimeBuildStamp + " force_reapply=armed")); } else { DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)("Spawnsystem sync stage=config_committed hash=" + ((text.Length > 0) ? text : "") + " entries=" + entryCount.ToString(CultureInfo.InvariantCulture))); } } } private static void RetainCurrentCompiledTableWhilePending(int gameDataSignature, bool queueEspRefreshForLiveSystems, bool queueLiveSystemAttach, string applyTargetSignature) { if (_activeCompiledTable == null) { return; } List liveSystems = GetLiveSystems(); if (queueLiveSystemAttach) { QueueLiveSystemAttachForTable(_activeCompiledTable, _preparedEntriesBuildVersion, queueEspRefreshForLiveSystems, liveSystems); } else if (queueEspRefreshForLiveSystems) { foreach (SpawnSystem item in liveSystems) { QueueEspMarkerRefresh(item); } } LogRuntimeTableAttachedIfNeeded(applyTargetSignature, "retained_pending", _activeCompiledTable, liveSystems.Count); RecordAppliedState(gameDataSignature, domainEnabled: true, _lastAppliedPreparedEntriesSignature, applyTargetSignature); } private static void LogApplySkipIfNeeded(string key, string message) { if (PluginSettingsFacade.IsSpawnSystemDiagnosticsEnabled() && !string.Equals(_lastLoggedApplySkipKey, key, StringComparison.Ordinal)) { _lastLoggedApplySkipKey = key; DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)message); } } private static void LogPreparedBuildQueuedIfNeeded(int buildVersion, string applyTargetSignature, int entryCount) { if (PluginSettingsFacade.IsSpawnSystemDiagnosticsEnabled()) { string text = buildVersion.ToString(CultureInfo.InvariantCulture) + "|" + applyTargetSignature; if (!string.Equals(_lastLoggedPreparedBuildQueuedSignature, text, StringComparison.Ordinal)) { _lastLoggedPreparedBuildQueuedSignature = text; DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)("Spawnsystem sync stage=prepared_build_queued version=" + buildVersion.ToString(CultureInfo.InvariantCulture) + " entries=" + entryCount.ToString(CultureInfo.InvariantCulture) + " target=" + applyTargetSignature)); } } } private static void LogPreparedBuildCompletedIfNeeded(int buildVersion, int modelCount, string applyTargetSignature) { if (PluginSettingsFacade.IsSpawnSystemDiagnosticsEnabled() && _lastLoggedPreparedBuildCompletedVersion != buildVersion) { _lastLoggedPreparedBuildCompletedVersion = buildVersion; DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)("Spawnsystem sync stage=prepared_build_completed version=" + buildVersion.ToString(CultureInfo.InvariantCulture) + " models=" + modelCount.ToString(CultureInfo.InvariantCulture) + " target=" + applyTargetSignature)); } } private static void LogPreparedBuildActivatedIfNeeded(int buildVersion, int modelCount, string applyTargetSignature) { if (PluginSettingsFacade.IsSpawnSystemDiagnosticsEnabled()) { DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)("Spawnsystem sync stage=prepared_build_activated version=" + buildVersion.ToString(CultureInfo.InvariantCulture) + " models=" + modelCount.ToString(CultureInfo.InvariantCulture) + " target=" + applyTargetSignature)); } } private static void LogCompiledBuildStartedIfNeeded(int buildVersion, int finalizedEntryCount, string applyTargetSignature) { if (PluginSettingsFacade.IsSpawnSystemDiagnosticsEnabled() && _lastLoggedCompiledBuildStartedVersion != buildVersion) { _lastLoggedCompiledBuildStartedVersion = buildVersion; DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)("Spawnsystem sync stage=compiled_build_started version=" + buildVersion.ToString(CultureInfo.InvariantCulture) + " finalizedEntries=" + finalizedEntryCount.ToString(CultureInfo.InvariantCulture) + " target=" + applyTargetSignature)); } } private static void LogCompiledBuildFinishedIfNeeded(int buildVersion, int finalizedEntryCount, int liveSystemCount, string applyTargetSignature) { if (PluginSettingsFacade.IsSpawnSystemDiagnosticsEnabled() && _lastLoggedCompiledBuildFinishedVersion != buildVersion) { _lastLoggedCompiledBuildFinishedVersion = buildVersion; DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)("Spawnsystem sync stage=compiled_build_finished version=" + buildVersion.ToString(CultureInfo.InvariantCulture) + " finalizedEntries=" + finalizedEntryCount.ToString(CultureInfo.InvariantCulture) + " liveSystems=" + liveSystemCount.ToString(CultureInfo.InvariantCulture) + " target=" + applyTargetSignature)); } } private static void LogAwakeRetriggerIfNeeded(SpawnSystem system, int liveSystemCount) { if (PluginSettingsFacade.IsSpawnSystemDiagnosticsEnabled()) { string text = LoadState.LastLoadedPayload + "|" + ((Object)system).GetInstanceID().ToString(CultureInfo.InvariantCulture); if (!string.Equals(_lastLoggedAwakeRetriggerKey, text, StringComparison.Ordinal)) { _lastLoggedAwakeRetriggerKey = text; DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)("Spawnsystem sync stage=awake_retrigger version=" + _preparedEntriesBuildVersion.ToString(CultureInfo.InvariantCulture) + " liveSystems=" + liveSystemCount.ToString(CultureInfo.InvariantCulture) + " payloadHash=" + ((LoadState.LastLoadedPayload.Length > 0) ? LoadState.LastLoadedPayload : ""))); } } } private static void LogVanillaRetainedIfNeeded(string applyTargetSignature, string reason, CompiledSpawnSystemTable? table, int liveSystemCount) { if (!string.Equals(_lastLoggedVanillaRetainedSignature, applyTargetSignature, StringComparison.Ordinal)) { _lastLoggedVanillaRetainedSignature = applyTargetSignature; _lastLoggedRuntimeAttachSignature = ""; DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)("Spawnsystem sync stage=vanilla_retained reason=" + reason + " liveSystems=" + liveSystemCount.ToString(CultureInfo.InvariantCulture) + " rows=" + CountSpawnRows(table).ToString(CultureInfo.InvariantCulture))); } } private static void LogRuntimeTableAttachedIfNeeded(string applyTargetSignature, string kind, CompiledSpawnSystemTable? table, int liveSystemCount) { if (!string.Equals(_lastLoggedRuntimeAttachSignature, applyTargetSignature, StringComparison.Ordinal)) { _lastLoggedRuntimeAttachSignature = applyTargetSignature; _lastLoggedVanillaRetainedSignature = ""; DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)("Spawnsystem sync stage=runtime_table_attached kind=" + kind + " liveSystems=" + liveSystemCount.ToString(CultureInfo.InvariantCulture) + " rows=" + CountSpawnRows(table).ToString(CultureInfo.InvariantCulture))); } } private static void LogLiveSpawnListState(string stage, SpawnSystem? system, CompiledSpawnSystemTable? table, bool preAttached = false) { if (PluginSettingsFacade.IsSpawnSystemDiagnosticsEnabled() && !((Object)(object)system == (Object)null)) { SpawnListSummary spawnListSummary = SummarizeSpawnLists(system.m_spawnLists); SpawnListSummary spawnListSummary2 = SummarizeSpawnLists(table?.Lists); bool flag = IsSystemAttachedToCompiledTable(system, table); DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)($"Spawnsystem live stage={stage} systemId={((Object)system).GetInstanceID().ToString(CultureInfo.InvariantCulture)} preAttached={preAttached} attached={flag} " + "liveLists=" + spawnListSummary.ListCount.ToString(CultureInfo.InvariantCulture) + " liveRows=" + spawnListSummary.RowCount.ToString(CultureInfo.InvariantCulture) + " liveHash=" + spawnListSummary.ContentHash.ToString(CultureInfo.InvariantCulture) + " tableLists=" + spawnListSummary2.ListCount.ToString(CultureInfo.InvariantCulture) + " tableRows=" + spawnListSummary2.RowCount.ToString(CultureInfo.InvariantCulture) + " tableHash=" + spawnListSummary2.ContentHash.ToString(CultureInfo.InvariantCulture) + " baselineLists=" + (table?.BaselineListCount.ToString(CultureInfo.InvariantCulture) ?? "0") + " baselineRows=" + (table?.BaselineRowCount.ToString(CultureInfo.InvariantCulture) ?? "0") + " baselineHash=" + (table?.BaselineContentHash.ToString(CultureInfo.InvariantCulture) ?? "0") + " liveSample='" + spawnListSummary.SamplePrefabs + "' tableSample='" + spawnListSummary2.SamplePrefabs + "'")); } } private static SpawnListSummary SummarizeSpawnLists(IEnumerable? spawnLists) { SpawnListSummary result; if (spawnLists == null) { result = default(SpawnListSummary); result.ListCount = 0; result.RowCount = 0; result.ContentHash = 0; result.SamplePrefabs = ""; return result; } int num = 0; int num2 = 0; int num3 = 17; List list = new List(); foreach (SpawnSystemList spawnList in spawnLists) { if ((Object)(object)spawnList == (Object)null) { continue; } num++; num3 = num3 * 31 + num; List spawners = spawnList.m_spawners; int num4 = spawners?.Count ?? 0; num2 += num4; num3 = num3 * 31 + num4; if (spawners == null) { continue; } foreach (SpawnData item in spawners) { string text = (((Object)(object)item?.m_prefab != (Object)null) ? Utils.GetPrefabName(item.m_prefab) : (item?.m_name ?? "")); num3 = num3 * 31 + StringComparer.OrdinalIgnoreCase.GetHashCode(text); num3 = num3 * 31 + ((item?.m_enabled ?? false) ? 1 : 0); if (list.Count < 8) { list.Add(text); } } } result = default(SpawnListSummary); result.ListCount = num; result.RowCount = num2; result.ContentHash = num3; result.SamplePrefabs = ((list.Count > 0) ? string.Join(",", list) : ""); return result; } private static void FreezeCompiledTableBaseline(CompiledSpawnSystemTable? table) { if (table != null) { SpawnListSummary spawnListSummary = SummarizeSpawnLists(table.Lists); table.BaselineListCount = spawnListSummary.ListCount; table.BaselineRowCount = spawnListSummary.RowCount; table.BaselineContentHash = spawnListSummary.ContentHash; } } private static int CountSpawnRows(CompiledSpawnSystemTable? table) { if (table == null) { return 0; } int num = 0; foreach (SpawnSystemList list in table.Lists) { if (list?.m_spawners != null) { num += list.m_spawners.Count; } } return num; } private static void RecordAppliedState(int gameDataSignature, bool domainEnabled, string preparedEntriesSignature, string applyTargetSignature) { _lastAppliedGameDataSignature = gameDataSignature; _lastAppliedDomainEnabled = domainEnabled; _lastAppliedConfigurationSignature = _configurationSignature; _lastAppliedPreparedEntriesSignature = preparedEntriesSignature; _lastAppliedBuildTargetSignature = applyTargetSignature; _forceApplyAfterSyncedCommit = false; _lastCompletedGameDataSignature = gameDataSignature; if (_pendingGameDataSignature == gameDataSignature) { _pendingGameDataSignature = null; } } private static string BuildApplyTargetSignature(int gameDataSignature, bool domainEnabled) { return gameDataSignature.ToString(CultureInfo.InvariantCulture) + "|" + (domainEnabled ? "enabled" : "disabled") + "|" + (_configurationReady ? "config_ready" : "config_pending") + "|" + _configurationSignature; } private static void ApplySelectedTableWithoutActiveBuild(int gameDataSignature, bool domainEnabled, bool queueEspRefreshForLiveSystems, string applyTargetSignature) { CompiledSpawnSystemTable? selectedCompiledTableForCurrentState = GetSelectedCompiledTableForCurrentState(); List liveSystems = GetLiveSystems(); EnsureVanillaCompiledTableCurrentLocked(gameDataSignature); _activeCompiledTable = null; CompiledSpawnSystemTable selectedCompiledTableForCurrentState2 = GetSelectedCompiledTableForCurrentState(); QueueLiveSystemAttachForTable(selectedCompiledTableForCurrentState2, _preparedEntriesBuildVersion, queueEspRefreshForLiveSystems, liveSystems); RetireCompiledTableAfterMigrationLocked(selectedCompiledTableForCurrentState, selectedCompiledTableForCurrentState2, liveSystems); string reason = ((!domainEnabled) ? "domain_disabled" : (_configurationReady ? "authoritative_unavailable" : "config_not_ready")); LogVanillaRetainedIfNeeded(applyTargetSignature, reason, selectedCompiledTableForCurrentState2, liveSystems.Count); RecordAppliedState(gameDataSignature, domainEnabled, "", applyTargetSignature); } private static void EnsureVanillaCompiledTableCurrentLocked(int gameDataSignature) { if (_vanillaCompiledTable == null || _vanillaCompiledTable.GameDataSignature != gameDataSignature) { CompiledSpawnSystemTable? vanillaCompiledTable = _vanillaCompiledTable; _vanillaCompiledTable = BuildVanillaCompiledTable(gameDataSignature); DestroyCompiledTableIfInactiveLocked(vanillaCompiledTable); } } private static void QueuePreparedEntriesBuildLocked(int gameDataSignature, bool domainEnabled, string applyTargetSignature, bool queueEspRefreshForLiveSystems) { ClearQueuedReconcileState(); _preparedEntriesBuildVersion++; int preparedEntriesBuildVersion = _preparedEntriesBuildVersion; _preparedEntriesBuildInFlight = true; _completedPreparedEntriesBuildResult = null; _pendingCompiledTableBuild = null; _pendingBuildTargetSignature = applyTargetSignature; PendingPreparedEntriesBuildRequest pendingPreparedEntriesBuildRequest = new PendingPreparedEntriesBuildRequest { BuildVersion = preparedEntriesBuildVersion, GameDataSignature = gameDataSignature, DomainEnabled = domainEnabled, ApplyTargetSignature = applyTargetSignature, QueueEspRefreshForLiveSystems = queueEspRefreshForLiveSystems }; pendingPreparedEntriesBuildRequest.ConfigurationSnapshot.AddRange(_configuration); _pendingPreparedEntriesBuildRequest = pendingPreparedEntriesBuildRequest; LogPreparedBuildQueuedIfNeeded(preparedEntriesBuildVersion, applyTargetSignature, pendingPreparedEntriesBuildRequest.ConfigurationSnapshot.Count); EnsurePreparedEntriesBuildWorkerLocked(); } private static void EnsurePreparedEntriesBuildWorkerLocked() { if (!_preparedEntriesBuildWorkerRunning) { _preparedEntriesBuildWorkerRunning = true; ThreadPool.QueueUserWorkItem(delegate { ProcessPreparedEntriesBuildWorker(); }); } } private static void ProcessPreparedEntriesBuildWorker() { while (true) { PendingPreparedEntriesBuildRequest pendingPreparedEntriesBuildRequest; lock (Sync) { pendingPreparedEntriesBuildRequest = _pendingPreparedEntriesBuildRequest; _pendingPreparedEntriesBuildRequest = null; if (pendingPreparedEntriesBuildRequest == null) { _preparedEntriesBuildWorkerRunning = false; if (_completedPreparedEntriesBuildResult == null) { _preparedEntriesBuildInFlight = false; } break; } } try { PreparedEntriesBuildResult preparedEntriesBuildResult = BuildPreparedEntriesResult(pendingPreparedEntriesBuildRequest); if (preparedEntriesBuildResult == null) { continue; } lock (Sync) { if (IsPreparedEntriesBuildCurrentLocked(preparedEntriesBuildResult.BuildVersion, preparedEntriesBuildResult.ApplyTargetSignature)) { PruneFinalizedPreparedEntryCacheLocked(preparedEntriesBuildResult.GameDataSignature, preparedEntriesBuildResult.Models.Select((PreparedSpawnSystemModel model) => model.EntrySignature)); _completedPreparedEntriesBuildResult = preparedEntriesBuildResult; _preparedEntriesBuildInFlight = _pendingPreparedEntriesBuildRequest != null; LogPreparedBuildCompletedIfNeeded(preparedEntriesBuildResult.BuildVersion, preparedEntriesBuildResult.Models.Count, preparedEntriesBuildResult.ApplyTargetSignature); } } } catch (Exception arg) { lock (Sync) { if (pendingPreparedEntriesBuildRequest != null && IsPreparedEntriesBuildCurrentLocked(pendingPreparedEntriesBuildRequest.BuildVersion, pendingPreparedEntriesBuildRequest.ApplyTargetSignature)) { _preparedEntriesBuildInFlight = _pendingPreparedEntriesBuildRequest != null; _completedPreparedEntriesBuildResult = null; if (_pendingPreparedEntriesBuildRequest == null) { _pendingBuildTargetSignature = ""; _pendingGameDataSignature = null; } } } DropNSpawnPlugin.DropNSpawnLogger.LogError((object)$"Failed to prepare staged spawnsystem build. {arg}"); } } } private static bool IsPreparedEntriesBuildCurrentLocked(int buildVersion, string applyTargetSignature) { if (buildVersion == _preparedEntriesBuildVersion) { return string.Equals(_pendingBuildTargetSignature, applyTargetSignature, StringComparison.Ordinal); } return false; } private static bool IsPreparedEntriesBuildCurrent(int buildVersion, string applyTargetSignature) { lock (Sync) { return IsPreparedEntriesBuildCurrentLocked(buildVersion, applyTargetSignature); } } private static PreparedEntriesBuildResult? BuildPreparedEntriesResult(PendingPreparedEntriesBuildRequest request) { PreparedEntriesBuildResult preparedEntriesBuildResult = new PreparedEntriesBuildResult { BuildVersion = request.BuildVersion, GameDataSignature = request.GameDataSignature, DomainEnabled = request.DomainEnabled, ApplyTargetSignature = request.ApplyTargetSignature, QueueEspRefreshForLiveSystems = request.QueueEspRefreshForLiveSystems }; for (int i = 0; i < request.ConfigurationSnapshot.Count; i++) { if (!IsPreparedEntriesBuildCurrent(request.BuildVersion, request.ApplyTargetSignature)) { return null; } CanonicalSpawnSystemEntry canonicalSpawnSystemEntry = request.ConfigurationSnapshot[i]; preparedEntriesBuildResult.Models.Add(new PreparedSpawnSystemModel { Entry = canonicalSpawnSystemEntry, RuleId = canonicalSpawnSystemEntry.RuleId, EntrySignature = NetworkPayloadSyncSupport.ComputeSpawnSystemEntrySignature(canonicalSpawnSystemEntry), Context = CreateConfigurationContext(i, canonicalSpawnSystemEntry), RuntimeTimeOfDay = GetConfiguredTimeOfDay(canonicalSpawnSystemEntry) }); } if (!IsPreparedEntriesBuildCurrent(request.BuildVersion, request.ApplyTargetSignature)) { return null; } return preparedEntriesBuildResult; } private static void PruneFinalizedPreparedEntryCacheLocked(int gameDataSignature, IEnumerable? activeEntrySignatures = null) { if (FinalizedPreparedEntryCache.Count == 0) { return; } HashSet hashSet = null; if (activeEntrySignatures != null) { hashSet = new HashSet(activeEntrySignatures.Where((string signature) => !string.IsNullOrWhiteSpace(signature)), StringComparer.Ordinal); } List list = new List(); foreach (var (item, finalizedPreparedEntryCacheEntry2) in FinalizedPreparedEntryCache) { if (finalizedPreparedEntryCacheEntry2 == null) { list.Add(item); } else if (finalizedPreparedEntryCacheEntry2.GameDataSignature != gameDataSignature) { list.Add(item); } else if (hashSet != null && !hashSet.Contains(finalizedPreparedEntryCacheEntry2.EntrySignature)) { list.Add(item); } } foreach (string item2 in list) { FinalizedPreparedEntryCache.Remove(item2); } } private static void RefreshResolvedBiomeMasksForSourceOfTruthConfigurationLocked() { if (DropNSpawnPlugin.IsSourceOfTruth) { RefreshResolvedBiomeMasksForConfiguration(_configuration); } } private static void RefreshResolvedBiomeMasksForConfiguration(IEnumerable configuration) { foreach (CanonicalSpawnSystemEntry item in configuration ?? Enumerable.Empty()) { SpawnSystemConditionsDefinition conditions = item.Conditions; if (conditions != null) { conditions.ResolvedBiomeMask = BiomeResolutionSupport.ResolveBiomeMaskOrNull(conditions.Biomes); } } } private static void PublishSyncedConfigurationOrDeferLocked() { if (DropNSpawnPlugin.IsSourceOfTruth) { if (ShouldDeferForExpandWorldDataBiomeReadyLocked()) { DeferExpandWorldDataBiomeReadyLocked(queueEspRefreshForLiveSystems: false, queueLiveSystemAttach: false, publishSyncedConfiguration: true); return; } _deferredPublishSyncedConfiguration = false; ConfigurationDomainHost.PublishSyncedPayload(DropNSpawnPlugin.IsSourceOfTruth, Descriptor, _configuration, _configurationSignature); } } private static bool ShouldDeferForExpandWorldDataBiomeReadyLocked() { return ShouldDeferForExpandWorldDataBiomeReady(_configuration); } private static bool ShouldDeferForExpandWorldDataBiomeReady(IEnumerable configuration) { if (!BiomeResolutionSupport.IsExpandWorldDataPresent() || BiomeResolutionSupport.IsExpandWorldDataReadyOrUnavailable()) { return false; } foreach (CanonicalSpawnSystemEntry item in configuration ?? Enumerable.Empty()) { SpawnSystemConditionsDefinition conditions = item.Conditions; if (conditions != null && BiomeResolutionSupport.ShouldWaitForExpandWorldDataBiomeResolution(conditions.Biomes, conditions.ResolvedBiomeMask)) { return true; } } return false; } private static void DeferExpandWorldDataBiomeReadyLocked(bool queueEspRefreshForLiveSystems, bool queueLiveSystemAttach, bool publishSyncedConfiguration) { _waitingForExpandWorldDataBiomeReady = true; _deferredQueueEspRefreshForLiveSystems |= queueEspRefreshForLiveSystems; _deferredQueueLiveSystemAttach |= queueLiveSystemAttach; _deferredPublishSyncedConfiguration |= publishSyncedConfiguration; if (!_loggedExpandWorldDataBiomeReadyWait) { _loggedExpandWorldDataBiomeReadyWait = true; DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)"Deferring spawnsystem build until ExpandWorldData biome sync is ready."); } } private static bool TryProcessDeferredExpandWorldDataBiomeReadyLocked() { if (!_waitingForExpandWorldDataBiomeReady && !_deferredPublishSyncedConfiguration) { return false; } if (!BiomeResolutionSupport.IsExpandWorldDataReadyOrUnavailable()) { return false; } bool deferredQueueEspRefreshForLiveSystems = _deferredQueueEspRefreshForLiveSystems; bool deferredQueueLiveSystemAttach = _deferredQueueLiveSystemAttach; bool deferredPublishSyncedConfiguration = _deferredPublishSyncedConfiguration; _waitingForExpandWorldDataBiomeReady = false; _deferredQueueEspRefreshForLiveSystems = false; _deferredQueueLiveSystemAttach = false; _deferredPublishSyncedConfiguration = false; _loggedExpandWorldDataBiomeReadyWait = false; RefreshResolvedBiomeMasksForSourceOfTruthConfigurationLocked(); _configurationSignature = NetworkPayloadSyncSupport.ComputeSpawnSystemConfigurationSignature(_configuration); if (deferredPublishSyncedConfiguration) { ConfigurationDomainHost.PublishSyncedPayload(DropNSpawnPlugin.IsSourceOfTruth, Descriptor, _configuration, _configurationSignature); } ApplyIfReady(deferredQueueEspRefreshForLiveSystems, deferredQueueLiveSystemAttach); return true; } private static bool TryActivateCompletedPreparedEntriesBuildLocked() { if (_completedPreparedEntriesBuildResult == null) { return false; } PreparedEntriesBuildResult completedPreparedEntriesBuildResult = _completedPreparedEntriesBuildResult; _completedPreparedEntriesBuildResult = null; if (completedPreparedEntriesBuildResult.BuildVersion != _preparedEntriesBuildVersion || !string.Equals(_pendingBuildTargetSignature, completedPreparedEntriesBuildResult.ApplyTargetSignature, StringComparison.Ordinal)) { return true; } PendingCompiledTableBuildState pendingCompiledTableBuildState = new PendingCompiledTableBuildState { BuildVersion = completedPreparedEntriesBuildResult.BuildVersion, GameDataSignature = completedPreparedEntriesBuildResult.GameDataSignature, DomainEnabled = completedPreparedEntriesBuildResult.DomainEnabled, EagerClientSyncBuild = !DropNSpawnPlugin.IsSourceOfTruth, ApplyTargetSignature = completedPreparedEntriesBuildResult.ApplyTargetSignature, QueueEspRefreshForLiveSystems = completedPreparedEntriesBuildResult.QueueEspRefreshForLiveSystems, PreviousActiveTable = _activeCompiledTable, PreviousVanillaTable = _vanillaCompiledTable }; pendingCompiledTableBuildState.Models.AddRange(completedPreparedEntriesBuildResult.Models); _pendingCompiledTableBuild = pendingCompiledTableBuildState; LogPreparedBuildActivatedIfNeeded(pendingCompiledTableBuildState.BuildVersion, pendingCompiledTableBuildState.Models.Count, pendingCompiledTableBuildState.ApplyTargetSignature); return true; } private static bool TryProcessPendingCompiledTableBuild(float deadline) { if (_pendingCompiledTableBuild == null) { return false; } PendingCompiledTableBuildState pendingCompiledTableBuild = _pendingCompiledTableBuild; if (pendingCompiledTableBuild.BuildVersion != _preparedEntriesBuildVersion || !string.Equals(_pendingBuildTargetSignature, pendingCompiledTableBuild.ApplyTargetSignature, StringComparison.Ordinal)) { _pendingCompiledTableBuild = null; return true; } EnsureVanillaCompiledTableCurrentLocked(pendingCompiledTableBuild.GameDataSignature); if (pendingCompiledTableBuild.DomainEnabled && pendingCompiledTableBuild.NextFinalizeIndex < pendingCompiledTableBuild.Models.Count) { int num = 0; int num2 = ((!pendingCompiledTableBuild.EagerClientSyncBuild) ? 1 : int.MaxValue); while (pendingCompiledTableBuild.NextFinalizeIndex < pendingCompiledTableBuild.Models.Count && num < num2 && (pendingCompiledTableBuild.EagerClientSyncBuild || Time.realtimeSinceStartup < deadline)) { if (TryFinalizePreparedSpawnSystemModelLocked(pendingCompiledTableBuild.Models[pendingCompiledTableBuild.NextFinalizeIndex++], pendingCompiledTableBuild.GameDataSignature, out PreparedSpawnSystemEntry finalizedEntry)) { pendingCompiledTableBuild.FinalizedEntries.Add(finalizedEntry); } num++; } return num > 0; } if (pendingCompiledTableBuild.DomainEnabled) { pendingCompiledTableBuild.PreparedEntriesSignature = ComputePreparedEntriesSignature(pendingCompiledTableBuild.FinalizedEntries); if (pendingCompiledTableBuild.BuildingActiveTable == null) { pendingCompiledTableBuild.BuildingActiveTable = new CompiledSpawnSystemTable { GameDataSignature = pendingCompiledTableBuild.GameDataSignature, Signature = pendingCompiledTableBuild.PreparedEntriesSignature }; pendingCompiledTableBuild.BuildingLiveEntries = new List(pendingCompiledTableBuild.FinalizedEntries.Count); LogCompiledBuildStartedIfNeeded(pendingCompiledTableBuild.BuildVersion, pendingCompiledTableBuild.FinalizedEntries.Count, pendingCompiledTableBuild.ApplyTargetSignature); return true; } if (pendingCompiledTableBuild.NextCompiledEntryIndex < pendingCompiledTableBuild.FinalizedEntries.Count) { int num3 = 0; int num4 = (pendingCompiledTableBuild.EagerClientSyncBuild ? int.MaxValue : 8); while (pendingCompiledTableBuild.NextCompiledEntryIndex < pendingCompiledTableBuild.FinalizedEntries.Count && num3 < num4 && (pendingCompiledTableBuild.EagerClientSyncBuild || Time.realtimeSinceStartup < deadline)) { PreparedSpawnSystemEntry preparedSpawnSystemEntry = pendingCompiledTableBuild.FinalizedEntries[pendingCompiledTableBuild.NextCompiledEntryIndex++]; SpawnData val = preparedSpawnSystemEntry.Data.Clone(); StageCompiledRuntimeMetadata(pendingCompiledTableBuild.BuildingActiveTable, val, preparedSpawnSystemEntry.CustomDataPayload, preparedSpawnSystemEntry.RuntimeTimeOfDay); pendingCompiledTableBuild.BuildingLiveEntries.Add(val); num3++; } return num3 > 0; } if (pendingCompiledTableBuild.BuildingActiveTable.Lists.Count == 0) { pendingCompiledTableBuild.BuildingActiveTable.Lists.Add(CreateManagedSpawnList(pendingCompiledTableBuild.BuildingLiveEntries ?? new List())); FreezeCompiledTableBaseline(pendingCompiledTableBuild.BuildingActiveTable); return true; } } List liveSystems = GetLiveSystems(); CompiledSpawnSystemTable? selectedCompiledTableForCurrentState = GetSelectedCompiledTableForCurrentState(); _activeCompiledTable = (pendingCompiledTableBuild.DomainEnabled ? pendingCompiledTableBuild.BuildingActiveTable : null); QueueLiveSystemAttachForTable(_activeCompiledTable, pendingCompiledTableBuild.BuildVersion, pendingCompiledTableBuild.QueueEspRefreshForLiveSystems, liveSystems); RetireCompiledTableAfterMigrationLocked(selectedCompiledTableForCurrentState, _activeCompiledTable, liveSystems); LogCompiledBuildFinishedIfNeeded(pendingCompiledTableBuild.BuildVersion, pendingCompiledTableBuild.FinalizedEntries.Count, liveSystems.Count, pendingCompiledTableBuild.ApplyTargetSignature); LogRuntimeTableAttachedIfNeeded(pendingCompiledTableBuild.ApplyTargetSignature, "authoritative", _activeCompiledTable, liveSystems.Count); DestroyCompiledTableIfInactiveLocked(pendingCompiledTableBuild.PreviousActiveTable); DestroyCompiledTableIfInactiveLocked(pendingCompiledTableBuild.PreviousVanillaTable); RecordAppliedState(pendingCompiledTableBuild.GameDataSignature, pendingCompiledTableBuild.DomainEnabled, pendingCompiledTableBuild.PreparedEntriesSignature, pendingCompiledTableBuild.ApplyTargetSignature); _pendingBuildTargetSignature = ""; _pendingCompiledTableBuild = null; return true; } private static bool TryFinalizePreparedSpawnSystemModelLocked(PreparedSpawnSystemModel model, int gameDataSignature, out PreparedSpawnSystemEntry? finalizedEntry) { //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Expected O, but got Unknown finalizedEntry = null; if (model == null || model.Entry == null) { return false; } string ruleId2 = (model.RuleId = model.RuleId); string text2 = (model.EntrySignature = ((model.EntrySignature.Length > 0) ? model.EntrySignature : NetworkPayloadSyncSupport.ComputeSpawnSystemEntrySignature(model.Entry))); string key = gameDataSignature.ToString(CultureInfo.InvariantCulture) + "|" + text2; if (FinalizedPreparedEntryCache.TryGetValue(key, out FinalizedPreparedEntryCacheEntry value) && value != null && value.GameDataSignature == gameDataSignature) { finalizedEntry = new PreparedSpawnSystemEntry { Entry = model.Entry, Data = value.Data.Clone(), Context = model.Context, CustomDataPayload = value.CustomDataPayload, RuntimeTimeOfDay = value.RuntimeTimeOfDay }; return true; } SpawnData val = new SpawnData(); if (!ApplyEntry(val, model.Entry, model.Context, applyCustomData: false)) { return false; } SpawnSystemCustomDataSupport.PreparedPayload customDataPayload = SpawnSystemCustomDataSupport.BuildPreparedPayload(val, model.Entry, model.Context); FinalizedPreparedEntryCache[key] = new FinalizedPreparedEntryCacheEntry { GameDataSignature = gameDataSignature, RuleId = ruleId2, EntrySignature = text2, Data = val.Clone(), CustomDataPayload = customDataPayload, RuntimeTimeOfDay = model.RuntimeTimeOfDay }; finalizedEntry = new PreparedSpawnSystemEntry { Entry = model.Entry, Data = val, Context = model.Context, CustomDataPayload = customDataPayload, RuntimeTimeOfDay = model.RuntimeTimeOfDay }; return true; } private static void StageCompiledRuntimeMetadata(CompiledSpawnSystemTable? table, SpawnData spawnData, SpawnSystemCustomDataSupport.PreparedPayload? customDataPayload, TimeOfDayDefinition? timeOfDay) { if (table != null && spawnData != null) { if (timeOfDay != null && timeOfDay.HasValues()) { table.RuntimeTimeOfDayBySpawnData[spawnData] = timeOfDay; } if (customDataPayload != null) { table.CustomPayloadsBySpawnData[spawnData] = customDataPayload; } } } private static void AddCompiledRuntimeState(CompiledSpawnSystemTable? table) { if (table == null) { return; } SpawnData key; foreach (KeyValuePair runtimeTimeOfDayBySpawnDatum in table.RuntimeTimeOfDayBySpawnData) { runtimeTimeOfDayBySpawnDatum.Deconstruct(out key, out var value); SpawnData key2 = key; TimeOfDayDefinition value2 = value; TimeOfDayBySpawnData[key2] = value2; } foreach (KeyValuePair customPayloadsBySpawnDatum in table.CustomPayloadsBySpawnData) { customPayloadsBySpawnDatum.Deconstruct(out key, out var value3); SpawnData spawnData = key; SpawnSystemCustomDataSupport.PreparedPayload payload = value3; SpawnSystemCustomDataSupport.ApplyPreparedPayload(spawnData, payload); } _hasRuntimeTimeOfDayOverrides = TimeOfDayBySpawnData.Count > 0; } private static void RemoveCompiledRuntimeState(CompiledSpawnSystemTable? table) { if (table == null) { return; } InvalidateRuntimeTimeOfDayPhaseMarker(); foreach (SpawnData key in table.RuntimeTimeOfDayBySpawnData.Keys) { TimeOfDayBySpawnData.Remove(key); } foreach (SpawnData key2 in table.CustomPayloadsBySpawnData.Keys) { SpawnSystemCustomDataSupport.ApplyPreparedPayload(key2, null); } _hasRuntimeTimeOfDayOverrides = TimeOfDayBySpawnData.Count > 0; } private static void ClearRuntimeCompiledState() { InvalidateRuntimeTimeOfDayPhaseMarker(); TimeOfDayBySpawnData.Clear(); _hasRuntimeTimeOfDayOverrides = false; SpawnSystemCustomDataSupport.ClearAll(); } private static void RetireCompiledTableAfterMigrationLocked(CompiledSpawnSystemTable? previousSelectedTable, CompiledSpawnSystemTable? nextSelectedTable, IEnumerable liveSystems) { CompiledSpawnSystemTable previousSelectedTable2 = previousSelectedTable; if (previousSelectedTable2 == null || previousSelectedTable2 == nextSelectedTable) { return; } PendingCompiledTableRetirement pendingCompiledTableRetirement = PendingCompiledTableRetirements.FirstOrDefault((PendingCompiledTableRetirement retirement) => retirement.Table == previousSelectedTable2); if (pendingCompiledTableRetirement == null) { pendingCompiledTableRetirement = new PendingCompiledTableRetirement { Table = previousSelectedTable2 }; PendingCompiledTableRetirements.Add(pendingCompiledTableRetirement); } foreach (SpawnSystem liveSystem in liveSystems) { if ((Object)(object)liveSystem != (Object)null) { pendingCompiledTableRetirement.RemainingSystemIds.Add(((Object)liveSystem).GetInstanceID()); } } if (pendingCompiledTableRetirement.RemainingSystemIds.Count == 0) { FinalizeCompiledTableRetirementLocked(pendingCompiledTableRetirement); } } private static void MarkSystemMigratedFromRetiredTablesLocked(int systemId) { if (systemId == 0 || PendingCompiledTableRetirements.Count == 0) { return; } List list = null; foreach (PendingCompiledTableRetirement pendingCompiledTableRetirement in PendingCompiledTableRetirements) { if (pendingCompiledTableRetirement.RemainingSystemIds.Remove(systemId) && pendingCompiledTableRetirement.RemainingSystemIds.Count <= 0) { if (list == null) { list = new List(); } list.Add(pendingCompiledTableRetirement); } } if (list == null) { return; } foreach (PendingCompiledTableRetirement item in list) { FinalizeCompiledTableRetirementLocked(item); } } private static void FinalizeAllPendingCompiledTableRetirementsLocked() { if (PendingCompiledTableRetirements.Count == 0) { return; } foreach (PendingCompiledTableRetirement item in PendingCompiledTableRetirements.ToList()) { FinalizeCompiledTableRetirementLocked(item); } } private static void FinalizeCompiledTableRetirementLocked(PendingCompiledTableRetirement retirement) { if (retirement != null) { PendingCompiledTableRetirements.Remove(retirement); RemoveCompiledRuntimeState(retirement.Table); DestroyReplacedCompiledTable(retirement.Table); } } private static void DestroyCompiledTableIfInactiveLocked(CompiledSpawnSystemTable? table) { CompiledSpawnSystemTable table2 = table; if (table2 != null && !PendingCompiledTableRetirements.Any((PendingCompiledTableRetirement retirement) => retirement.Table == table2)) { DestroyReplacedCompiledTable(table2); } } private static void QueueLiveSystemAttachForTable(CompiledSpawnSystemTable? table, int buildVersion, bool queueEspRefresh, IEnumerable? systems = null) { QueueLiveSystemAttachForTableCore(table, buildVersion, queueEspRefresh, systems); } private static void QueueLiveSystemAttach(SpawnSystem? system, CompiledSpawnSystemTable targetTable, int buildVersion, bool queueEspRefresh) { QueueLiveSystemAttachCore(system, targetTable, buildVersion, queueEspRefresh); } private static void AttachTableToSystem(SpawnSystem? system, CompiledSpawnSystemTable? table) { AttachTableToSystemCore(system, table); } private static bool IsSystemAttachedToCompiledTable(SpawnSystem? system, CompiledSpawnSystemTable? table) { return IsSystemAttachedToCompiledTableCore(system, table); } private static List CloneAttachedSpawnLists(CompiledSpawnSystemTable table) { return CloneAttachedSpawnListsCore(table); } private static CompiledSpawnSystemTable? GetSelectedCompiledTableForCurrentState() { return GetSelectedCompiledTableForCurrentStateCore(); } private static CompiledSpawnSystemTable? BuildVanillaCompiledTable(int gameDataSignature) { return BuildVanillaCompiledTableCore(gameDataSignature); } private static CompiledSpawnSystemTable BuildActiveCompiledTable(int gameDataSignature, List entries, string preparedEntriesSignature) { return BuildActiveCompiledTableCore(gameDataSignature, entries, preparedEntriesSignature); } private static List GetVanillaSourceSpawnLists() { return GetVanillaSourceSpawnListsCore(); } private static SpawnSystem? GetZoneCtrlPrefabSpawnSystem() { return GetZoneCtrlPrefabSpawnSystemCore(); } private static SpawnSystemList CreateManagedSpawnList(List spawners) { return CreateManagedSpawnListCore(spawners); } private static SpawnSystemList CreateAttachedSpawnList(List spawners) { return CreateAttachedSpawnListCore(spawners); } private static GameObject GetManagedSpawnListHost() { return GetManagedSpawnListHostCore(); } private static GameObject GetAttachedSpawnListHost() { return GetAttachedSpawnListHostCore(); } private static void ClearAttachedRuntimeState(SpawnSystem? system) { ClearAttachedRuntimeStateCore(system); } private static void DestroyAttachedSpawnLists(IEnumerable? spawnLists) { DestroyAttachedSpawnListsCore(spawnLists); } private static void DestroyReplacedCompiledTable(CompiledSpawnSystemTable? table) { DestroyReplacedCompiledTableCore(table); } private static List BuildPreparedEntries() { return BuildPreparedEntriesCore(); } private static void InvalidatePreparedEntriesCache() { InvalidatePreparedEntriesCacheCore(); } private static string ComputePreparedEntriesSignature(List entries) { return ComputePreparedEntriesSignatureCore(entries); } private static bool ApplyEntry(SpawnData data, CanonicalSpawnSystemEntry entry, string context, bool applyCustomData = true) { //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) bool flag = true; bool flag2 = false; string text = null; SpawnSystemSpawnDefinition spawn = entry.Spawn; SpawnSystemConditionsDefinition conditions = entry.Conditions; _ = entry.Modifiers; if (spawn != null && spawn.Name != null) { data.m_name = spawn.Name; } data.m_enabled = entry.Enabled; if (string.IsNullOrWhiteSpace(entry.Prefab)) { WarnInvalidEntry("Entry '" + context + "' is missing required prefab."); flag = false; } else { string prefab = entry.Prefab; GameObject val = ResolvePrefab(prefab); if ((Object)(object)val == (Object)null) { WarnInvalidEntry("Entry '" + context + "' references unknown prefab '" + prefab + "'."); flag = false; } else { data.m_prefab = val; flag2 = true; text = ((Object)val).name; } } if (spawn?.Name == null && flag2 && !string.IsNullOrWhiteSpace(text)) { data.m_name = text; } if (conditions != null && conditions.ResolvedBiomeMask.HasValue) { data.m_biome = conditions.ResolvedBiomeMask.Value; } else if (conditions?.Biomes != null) { if (!TryParseBiomes(conditions.Biomes, context, out var biomes)) { flag = false; } else { data.m_biome = biomes; } } if (conditions?.BiomeAreas != null) { if (!TryParseBiomeAreas(conditions.BiomeAreas, context, out var biomeAreas)) { flag = false; } else { data.m_biomeArea = biomeAreas; } } if (conditions != null && conditions.RequiredGlobalKey != null) { data.m_requiredGlobalKey = conditions.RequiredGlobalKey; } if (conditions?.RequiredEnvironments != null) { data.m_requiredEnvironments = (from value in conditions.RequiredEnvironments select (value ?? "").Trim() into value where value.Length > 0 select value).ToList(); } TimeOfDayDefinition configuredTimeOfDay = GetConfiguredTimeOfDay(entry); if (configuredTimeOfDay != null) { TimeOfDayFormatting.GetBroadSpawnFlags(configuredTimeOfDay, out var allowDay, out var allowNight); data.m_spawnAtDay = allowDay; data.m_spawnAtNight = allowNight; } if (spawn != null && spawn.MinLevel.HasValue) { data.m_minLevel = Math.Max(1, spawn.MinLevel.Value); } if (spawn != null && spawn.MaxLevel.HasValue) { data.m_maxLevel = Math.Max(1, spawn.MaxLevel.Value); } else if (spawn != null && spawn.MinLevel.HasValue) { data.m_maxLevel = Math.Max(data.m_minLevel, data.m_maxLevel); } if (spawn != null && spawn.LevelUpMinCenterDistance.HasValue) { data.m_levelUpMinCenterDistance = spawn.LevelUpMinCenterDistance.Value; } if (spawn != null && spawn.OverrideLevelUpChance.HasValue) { data.m_overrideLevelupChance = spawn.OverrideLevelUpChance.Value; } if (conditions != null && conditions.MaxSpawned.HasValue) { data.m_maxSpawned = Math.Max(0, conditions.MaxSpawned.Value); } if (spawn != null && spawn.SpawnInterval.HasValue) { data.m_spawnInterval = Math.Max(0.01f, spawn.SpawnInterval.Value); } if (spawn != null && spawn.SpawnChance.HasValue) { data.m_spawnChance = spawn.SpawnChance.Value; } if (conditions != null && conditions.NoSpawnRadius.HasValue) { data.m_spawnDistance = Math.Max(0f, conditions.NoSpawnRadius.Value); } if (spawn != null && spawn.SpawnRadiusMin.HasValue) { data.m_spawnRadiusMin = Math.Max(0f, spawn.SpawnRadiusMin.Value); } if (spawn != null && spawn.SpawnRadiusMax.HasValue) { data.m_spawnRadiusMax = Math.Max(0f, spawn.SpawnRadiusMax.Value); } if (spawn != null && spawn.GroupSizeMin.HasValue) { data.m_groupSizeMin = Math.Max(1, spawn.GroupSizeMin.Value); } if (spawn != null && spawn.GroupSizeMax.HasValue) { data.m_groupSizeMax = Math.Max(1, spawn.GroupSizeMax.Value); } else if (spawn != null && spawn.GroupSizeMin.HasValue) { data.m_groupSizeMax = Math.Max(data.m_groupSizeMin, data.m_groupSizeMax); } if (spawn != null && spawn.GroupRadius.HasValue) { data.m_groupRadius = Math.Max(0f, spawn.GroupRadius.Value); } if (conditions != null && conditions.MinAltitude.HasValue) { data.m_minAltitude = conditions.MinAltitude.Value; } if (conditions != null && conditions.MaxAltitude.HasValue) { data.m_maxAltitude = conditions.MaxAltitude.Value; } if (conditions != null && conditions.MinTilt.HasValue) { data.m_minTilt = conditions.MinTilt.Value; } if (conditions != null && conditions.MaxTilt.HasValue) { data.m_maxTilt = conditions.MaxTilt.Value; } ApplyExclusiveZoneToggle(conditions?.InForest, ref data.m_inForest, ref data.m_outsideForest); ApplyExclusiveZoneToggle(conditions?.InLava, ref data.m_inLava, ref data.m_outsideLava); if (conditions != null && conditions.CanSpawnCloseToPlayer.HasValue) { data.m_canSpawnCloseToPlayer = conditions.CanSpawnCloseToPlayer.Value; } if (conditions != null && conditions.InsidePlayerBase.HasValue) { data.m_insidePlayerBase = conditions.InsidePlayerBase.Value; } if (conditions != null && conditions.MinOceanDepth.HasValue) { data.m_minOceanDepth = conditions.MinOceanDepth.Value; } if (conditions != null && conditions.MaxOceanDepth.HasValue) { data.m_maxOceanDepth = conditions.MaxOceanDepth.Value; } if (spawn != null && spawn.HuntPlayer.HasValue) { data.m_huntPlayer = spawn.HuntPlayer.Value; } if (spawn != null && spawn.GroundOffset.HasValue) { data.m_groundOffset = spawn.GroundOffset.Value; } if (spawn != null && spawn.GroundOffsetRandom.HasValue) { data.m_groundOffsetRandom = spawn.GroundOffsetRandom.Value; } if (conditions != null && conditions.MinDistanceFromCenter.HasValue) { data.m_minDistanceFromCenter = conditions.MinDistanceFromCenter.Value; } if (conditions != null && conditions.MaxDistanceFromCenter.HasValue) { data.m_maxDistanceFromCenter = conditions.MaxDistanceFromCenter.Value; } if (flag && applyCustomData) { SpawnSystemCustomDataSupport.ApplyCustomData(data, entry, context); } return flag; } private static void ApplyRuntimeMetadata(SpawnData spawnData, TimeOfDayDefinition? timeOfDay) { if (spawnData != null) { InvalidateRuntimeTimeOfDayPhaseMarker(); if (timeOfDay != null && timeOfDay.HasValues()) { TimeOfDayBySpawnData[spawnData] = timeOfDay; } else { TimeOfDayBySpawnData.Remove(spawnData); } _hasRuntimeTimeOfDayOverrides = TimeOfDayBySpawnData.Count > 0; } } private static void ClearRuntimeMetadata(SpawnSystem system) { if ((Object)(object)system == (Object)null) { return; } InvalidateRuntimeTimeOfDayPhaseMarker(); foreach (SpawnSystemList spawnList in system.m_spawnLists) { foreach (SpawnData spawner in spawnList.m_spawners) { TimeOfDayBySpawnData.Remove(spawner); } } _hasRuntimeTimeOfDayOverrides = TimeOfDayBySpawnData.Count > 0; } private static bool IsPreparedEntriesCacheValid() { return _preparedEntriesCache != null; } private static int ComputeGameDataSignature() { int frameCount = Time.frameCount; if (_cachedGameDataSignatureFrame == frameCount) { return _cachedGameDataSignatureValue; } int num = ComputeGameDataSignatureCore(); _cachedGameDataSignatureFrame = frameCount; _cachedGameDataSignatureValue = num; return num; } private static int ComputeGameDataSignatureCore() { if ((Object)(object)ZNetScene.instance == (Object)null || (Object)(object)ObjectDB.instance == (Object)null) { return 0; } List list = new List(); SpawnSystem zoneCtrlPrefabSpawnSystem = GetZoneCtrlPrefabSpawnSystem(); if ((Object)(object)zoneCtrlPrefabSpawnSystem != (Object)null) { list.Add(zoneCtrlPrefabSpawnSystem); } else { list = GetLiveSystems(); } if (list.Count == 0) { return 0; } int num = 17; num = num * 31 + ((Object)ZNetScene.instance).GetInstanceID(); num = num * 31 + ((Object)ObjectDB.instance).GetInstanceID(); num = HashConfiguredSpawnSystemResolutionKeys(num); foreach (SpawnSystem item in list) { num = num * 31 + ((Object)item).GetInstanceID(); num = num * 31 + item.m_spawnLists.Count; foreach (SpawnSystemList spawnList in item.m_spawnLists) { num = num * 31 + spawnList.m_spawners.Count; foreach (SpawnData spawner in spawnList.m_spawners) { num = num * 31 + (((Object)(object)spawner?.m_prefab != (Object)null) ? ((Object)spawner.m_prefab).GetInstanceID() : 0); } } } return num; } private static int HashConfiguredSpawnSystemResolutionKeys(int hash) { EnsureConfiguredSpawnSystemResolutionKeysCached(); foreach (string cachedConfiguredSpawnSystemResolutionKey in _cachedConfiguredSpawnSystemResolutionKeys) { hash = hash * 31 + StringComparer.OrdinalIgnoreCase.GetHashCode(cachedConfiguredSpawnSystemResolutionKey); } return hash; } private static void EnsureConfiguredSpawnSystemResolutionKeysCached() { if ((Object)(object)ZNetScene.instance == (Object)null) { _cachedConfiguredSpawnSystemResolutionKeys.Clear(); _cachedConfiguredSpawnSystemResolutionKeysSignature = ""; _cachedConfiguredSpawnSystemResolutionKeysSceneStamp = int.MinValue; return; } int num = ComputeConfiguredSpawnSystemResolutionKeysSceneStamp(); if (_cachedConfiguredSpawnSystemResolutionKeysSceneStamp != num || !string.Equals(_cachedConfiguredSpawnSystemResolutionKeysSignature, _configurationSignature, StringComparison.Ordinal)) { _cachedConfiguredSpawnSystemResolutionKeys.Clear(); _cachedConfiguredSpawnSystemResolutionKeys.AddRange(BuildConfiguredSpawnSystemResolutionKeys()); _cachedConfiguredSpawnSystemResolutionKeys.Sort(StringComparer.OrdinalIgnoreCase); _cachedConfiguredSpawnSystemResolutionKeysSignature = _configurationSignature; _cachedConfiguredSpawnSystemResolutionKeysSceneStamp = num; } } private static int ComputeConfiguredSpawnSystemResolutionKeysSceneStamp() { if ((Object)(object)ZNetScene.instance == (Object)null) { return int.MinValue; } return ((17 * 31 + ((Object)ZNetScene.instance).GetInstanceID()) * 31 + ZNetScene.instance.m_prefabs.Count) * 31 + ZNetScene.instance.m_nonNetViewPrefabs.Count; } private static int HashNormalizedKeys(int hash, IEnumerable keys) { foreach (string item in (from key in (keys ?? Enumerable.Empty()).Select(ReferenceRefreshSupport.NormalizeKey) where key.Length > 0 select key).OrderBy((string key) => key, StringComparer.OrdinalIgnoreCase)) { hash = hash * 31 + StringComparer.OrdinalIgnoreCase.GetHashCode(item); } return hash; } [IteratorStateMachine(typeof(d__247))] private static IEnumerable BuildConfiguredSpawnSystemResolutionKeys() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__247(-2); } private static string? GetPrimaryOverrideConfigurationPath() { return DomainConfigurationFileSupport.GetPreferredPrimaryOverridePath(PrimaryOverrideConfigurationPathYml, PrimaryOverrideConfigurationPathYaml, WarnInvalidEntry); } private static bool IsOverrideConfigurationFileName(string fileName) { if (string.IsNullOrWhiteSpace(fileName)) { return false; } if (!fileName.Equals(Path.GetFileName(PrimaryOverrideConfigurationPathYml), StringComparison.OrdinalIgnoreCase) && !fileName.Equals(Path.GetFileName(PrimaryOverrideConfigurationPathYaml), StringComparison.OrdinalIgnoreCase)) { if (fileName.StartsWith(PluginSettingsFacade.GetYamlDomainSupplementalPrefix("spawnsystem"), StringComparison.OrdinalIgnoreCase)) { if (!fileName.EndsWith(".yml", StringComparison.OrdinalIgnoreCase)) { return fileName.EndsWith(".yaml", StringComparison.OrdinalIgnoreCase); } return true; } return false; } return true; } private static bool TryEnumerateReferenceLiveSpawnData(IEnumerable? lists, out IEnumerable? spawnData) { List list = (from current in lists?.Where((SpawnSystemList spawnList) => (Object)(object)spawnList != (Object)null).SelectMany((SpawnSystemList spawnList) => spawnList.m_spawners ?? new List()) where current != null select current).ToList() ?? new List(); if (list.Count == 0) { spawnData = null; return false; } spawnData = list; return true; } private static bool TryParseBiomes(List names, string context, out Biome biomes) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Invalid comparison between Unknown and I4 //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_0084: Expected I4, but got Unknown biomes = (Biome)0; foreach (string name in names) { string text = (name ?? "").Trim(); if (text.Length != 0) { if (!TryResolveBiomeToken(text, out var biome)) { WarnInvalidEntry("Entry '" + context + "' contains unknown biome '" + text + "'."); biomes = (Biome)0; return false; } if ((int)biome == 895) { biomes = (Biome)895; return true; } biomes |= biome; } } return true; } private static bool TryResolveBiomeToken(string name, out Biome biome) { if (BiomeResolutionSupport.TryResolveBiomeToken(name, out biome)) { return true; } biome = (Biome)0; return false; } private static bool TryParseBiomeAreas(List names, string context, out BiomeArea biomeAreas) { //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Invalid comparison between Unknown and I4 //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected I4, but got Unknown biomeAreas = (BiomeArea)0; foreach (string name in names) { string text = (name ?? "").Trim(); if (text.Length != 0) { if (!Enum.TryParse(text, ignoreCase: true, out BiomeArea result)) { WarnInvalidEntry("Entry '" + context + "' contains unknown biomeArea '" + text + "'."); biomeAreas = (BiomeArea)0; return false; } if ((int)result == 3) { biomeAreas = (BiomeArea)3; return true; } biomeAreas |= result; } } return true; } private static List ConvertBiomes(Biome biomes) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected I4, but got Unknown //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Invalid comparison between Unknown and I4 //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Expected I4, but got Unknown List list = new List(); int num = (int)biomes; foreach (Biome value in Enum.GetValues(typeof(Biome))) { Biome val = value; if ((int)val != 0 && (int)val != 895 && (Biome)(biomes & val) == val) { list.Add(((object)(Biome)(ref val)).ToString()); num &= ~val; } } if (num != 0) { list.Add(num.ToString(CultureInfo.InvariantCulture)); } return list; } private static List ConvertBiomeAreas(BiomeArea biomeAreas) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Invalid comparison between Unknown and I4 //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) if ((int)biomeAreas == 3) { List list = new List(); BiomeArea val = (BiomeArea)3; list.Add(((object)(BiomeArea)(ref val)).ToString()); return list; } List list2 = new List(); foreach (BiomeArea value in Enum.GetValues(typeof(BiomeArea))) { BiomeArea val2 = value; if ((int)val2 != 3 && (BiomeArea)(biomeAreas & val2) == val2) { list2.Add(((object)(BiomeArea)(ref val2)).ToString()); } } return list2; } private static GameObject? ResolvePrefab(string prefabName) { string prefabName2 = prefabName; if ((Object)(object)ZNetScene.instance == (Object)null || string.IsNullOrWhiteSpace(prefabName2)) { return null; } GameObject prefab = ZNetScene.instance.GetPrefab(prefabName2); if ((Object)(object)prefab != (Object)null) { return prefab; } return ZNetScene.instance.m_prefabs.Concat(ZNetScene.instance.m_nonNetViewPrefabs).FirstOrDefault((Func)((GameObject candidate) => string.Equals(((Object)candidate).name, prefabName2, StringComparison.OrdinalIgnoreCase))); } private static string CreateConfigurationContext(int index, CanonicalSpawnSystemEntry entry) { string text = "entry[" + index.ToString(CultureInfo.InvariantCulture) + "]"; string text2 = entry.Prefab ?? "(no prefab)"; string text3 = entry.SpawnSystem?.Name ?? "(no name)"; string text4 = text + " " + text2 + " / " + text3; if (string.IsNullOrWhiteSpace(entry.SourcePath)) { return text4; } string text5 = Path.GetFileName(entry.SourcePath); if (entry.SourceLine.HasValue) { text5 = text5 + ":" + entry.SourceLine.Value.ToString(CultureInfo.InvariantCulture); } return text4 + " @ " + text5; } private static string FormatYamlExceptionLocation(Exception ex) { if (!(ex is YamlException ex2)) { return ""; } Mark start = ex2.Start; if (start.Line <= 0) { return ""; } return " at line " + start.Line.ToString(CultureInfo.InvariantCulture); } private static string? NormalizeOptionalString(string? value) { return value?.Trim(); } private static void NormalizeSpawnSystemConditions(SpawnSystemConditionsDefinition? conditions, string context) { if (conditions != null) { FloatRangeDefinition? tilt = conditions.Tilt; if (tilt != null && tilt.HasValues()) { conditions.MinTilt = RangeFormatting.GetMin(conditions.Tilt, conditions.MinTilt); conditions.MaxTilt = RangeFormatting.GetMax(conditions.Tilt, conditions.MinTilt, conditions.MaxTilt); float? min = conditions.MinTilt; float? max = conditions.MaxTilt; NormalizeSpawnSystemFloatRange(ref min, ref max, context, "tilt"); conditions.MinTilt = min; conditions.MaxTilt = max; } FloatRangeDefinition? altitude = conditions.Altitude; if (altitude != null && altitude.HasValues()) { conditions.MinAltitude = RangeFormatting.GetMin(conditions.Altitude, conditions.MinAltitude); conditions.MaxAltitude = RangeFormatting.GetMax(conditions.Altitude, conditions.MinAltitude, conditions.MaxAltitude); float? min2 = conditions.MinAltitude; float? max2 = conditions.MaxAltitude; NormalizeSpawnSystemFloatRange(ref min2, ref max2, context, "altitude"); conditions.MinAltitude = min2; conditions.MaxAltitude = max2; } FloatRangeDefinition? oceanDepth = conditions.OceanDepth; if (oceanDepth != null && oceanDepth.HasValues()) { conditions.MinOceanDepth = RangeFormatting.GetMin(conditions.OceanDepth, conditions.MinOceanDepth); conditions.MaxOceanDepth = RangeFormatting.GetMax(conditions.OceanDepth, conditions.MinOceanDepth, conditions.MaxOceanDepth); float? min3 = conditions.MinOceanDepth; float? max3 = conditions.MaxOceanDepth; NormalizeSpawnSystemFloatRange(ref min3, ref max3, context, "oceanDepth"); conditions.MinOceanDepth = min3; conditions.MaxOceanDepth = max3; } FloatRangeDefinition? distanceFromCenter = conditions.DistanceFromCenter; if (distanceFromCenter != null && distanceFromCenter.HasValues()) { conditions.MinDistanceFromCenter = RangeFormatting.GetMin(conditions.DistanceFromCenter, conditions.MinDistanceFromCenter); conditions.MaxDistanceFromCenter = RangeFormatting.GetMax(conditions.DistanceFromCenter, conditions.MinDistanceFromCenter, conditions.MaxDistanceFromCenter); float? min4 = conditions.MinDistanceFromCenter; float? max4 = conditions.MaxDistanceFromCenter; NormalizeSpawnSystemFloatRange(ref min4, ref max4, context, "distanceFromCenter"); conditions.MinDistanceFromCenter = min4; conditions.MaxDistanceFromCenter = max4; } conditions.Biomes = NormalizeOptionalStringList(conditions.Biomes); conditions.BiomeAreas = NormalizeOptionalStringList(conditions.BiomeAreas); conditions.RequiredGlobalKey = NormalizeOptionalString(conditions.RequiredGlobalKey); conditions.RequiredEnvironments = NormalizeOptionalStringList(conditions.RequiredEnvironments); conditions.TimeOfDay?.Normalize(); } } private static void NormalizeSpawnSystemSpawn(SpawnSystemSpawnDefinition? spawn, string context) { if (spawn != null) { spawn.Name = NormalizeOptionalString(spawn.Name); IntRangeDefinition? level = spawn.Level; if (level != null && level.HasValues()) { spawn.MinLevel = RangeFormatting.GetMin(spawn.Level, spawn.MinLevel); spawn.MaxLevel = RangeFormatting.GetMax(spawn.Level, spawn.MinLevel, spawn.MaxLevel); int? min = spawn.MinLevel; int? max = spawn.MaxLevel; NormalizeSpawnSystemIntRange(ref min, ref max, context, "level"); spawn.MinLevel = min; spawn.MaxLevel = max; } FloatRangeDefinition? spawnRadius = spawn.SpawnRadius; if (spawnRadius != null && spawnRadius.HasValues()) { spawn.SpawnRadiusMin = RangeFormatting.GetMin(spawn.SpawnRadius, spawn.SpawnRadiusMin); spawn.SpawnRadiusMax = RangeFormatting.GetMax(spawn.SpawnRadius, spawn.SpawnRadiusMin, spawn.SpawnRadiusMax); float? min2 = spawn.SpawnRadiusMin; float? max2 = spawn.SpawnRadiusMax; NormalizeSpawnSystemFloatRange(ref min2, ref max2, context, "spawnRadius"); spawn.SpawnRadiusMin = min2; spawn.SpawnRadiusMax = max2; } IntRangeDefinition? groupSize = spawn.GroupSize; if (groupSize != null && groupSize.HasValues()) { spawn.GroupSizeMin = RangeFormatting.GetMin(spawn.GroupSize, spawn.GroupSizeMin); spawn.GroupSizeMax = RangeFormatting.GetMax(spawn.GroupSize, spawn.GroupSizeMin, spawn.GroupSizeMax); int? min3 = spawn.GroupSizeMin; int? max3 = spawn.GroupSizeMax; NormalizeSpawnSystemIntRange(ref min3, ref max3, context, "groupSize"); spawn.GroupSizeMin = min3; spawn.GroupSizeMax = max3; } } } private static void NormalizeSpawnSystemModifiers(SpawnSystemModifiersDefinition? modifiers) { if (modifiers != null) { modifiers.Objects = NormalizeOptionalStringList(modifiers.Objects); modifiers.Fields = NormalizeOptionalStringDictionary(modifiers.Fields); modifiers.Data = NormalizeOptionalString(modifiers.Data); modifiers.Faction = NormalizeOptionalString(modifiers.Faction); } } private static List? NormalizeOptionalStringList(List? values) { if (values == null) { return null; } List list = (from value in values select (value ?? "").Trim() into value where value.Length > 0 select value).ToList(); if (list.Count != 0) { return list; } return null; } private static Dictionary? NormalizeOptionalStringDictionary(Dictionary? values) { if (values == null) { return null; } Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); foreach (KeyValuePair value in values) { object obj; string text3; (obj, text3) = (KeyValuePair)(ref value); if (obj == null) { obj = ""; } string text4 = ((string)obj).Trim(); if (text4.Length != 0) { dictionary[text4] = (text3 ?? "").Trim(); } } if (dictionary.Count != 0) { return dictionary; } return null; } private static TimeOfDayDefinition? GetConfiguredTimeOfDay(CanonicalSpawnSystemEntry? entry) { return entry?.Conditions?.TimeOfDay; } private static void NormalizeSpawnSystemIntRange(ref int? min, ref int? max, string context, string fieldName) { int? min2 = min; int? max2 = max; if (RangeFormatting.NormalizeAscending(ref min, ref max)) { WarnInvalidEntry("Entry '" + context + "' contains reversed " + fieldName + " range '" + RangeFormatting.FormatShorthand(RangeFormatting.From(min2, max2)) + "'. Normalized to '" + RangeFormatting.FormatShorthand(RangeFormatting.From(min, max)) + "'."); } } private static void NormalizeSpawnSystemFloatRange(ref float? min, ref float? max, string context, string fieldName) { float? min2 = min; float? max2 = max; if (RangeFormatting.NormalizeAscending(ref min, ref max)) { WarnInvalidEntry("Entry '" + context + "' contains reversed " + fieldName + " range '" + RangeFormatting.FormatShorthand(RangeFormatting.From(min2, max2)) + "'. Normalized to '" + RangeFormatting.FormatShorthand(RangeFormatting.From(min, max)) + "'."); } } private static string? NormalizeNullable(string? value) { string text = (value ?? "").Trim(); if (text.Length != 0) { return text; } return null; } private static string? NormalizeReferencePrefabName(GameObject? prefab) { if (!((Object)(object)prefab == (Object)null)) { return ((Object)prefab).name; } return null; } internal static void EnterRequiredGlobalKeyEvaluation() { _requiredGlobalKeyEvaluationDepth++; } internal static void ExitRequiredGlobalKeyEvaluation() { if (_requiredGlobalKeyEvaluationDepth > 0) { _requiredGlobalKeyEvaluationDepth--; } } internal static bool TryEvaluateExtendedRequiredGlobalKey(ZoneSystem? zoneSystem, string? rawValue, out bool result) { result = false; if (_requiredGlobalKeyEvaluationDepth <= 0 || (Object)(object)zoneSystem == (Object)null || !TryParseRequiredGlobalKeyThreshold(rawValue, out string key, out int amount)) { return false; } string s = default(string); if (!zoneSystem.GetGlobalKey(key, ref s) || !int.TryParse(s, NumberStyles.Any, CultureInfo.InvariantCulture, out var result2)) { result = false; return true; } result = result2 >= amount; return true; } internal static bool TryRewriteExtendedGlobalKeyMutation(ZoneSystem? zoneSystem, string? rawValue, out string rewrittenValue) { rewrittenValue = rawValue ?? ""; if ((Object)(object)zoneSystem == (Object)null || !TryParseGlobalKeyMutation(rawValue, out string key, out int delta)) { return false; } string s = default(string); if (zoneSystem.GetGlobalKey(key, ref s) && int.TryParse(s, NumberStyles.Any, CultureInfo.InvariantCulture, out var result)) { rewrittenValue = key + " " + (result + delta).ToString(CultureInfo.InvariantCulture); } else { rewrittenValue = key + " " + delta.ToString(CultureInfo.InvariantCulture); } return true; } internal static void ConsumeExtendedRequiredGlobalKeyAfterSpawn(SpawnData? critter) { if (!SpawnSystem.m_nospawn && critter != null && !((Object)(object)ZoneSystem.instance == (Object)null) && TryParseRequiredGlobalKeyThreshold(critter.m_requiredGlobalKey, out string key, out int amount) && amount > 0) { ZoneSystem.instance.SetGlobalKey(key + " --" + amount.ToString(CultureInfo.InvariantCulture)); } } private static bool TryParseRequiredGlobalKeyThreshold(string? rawValue, out string key, out int amount) { key = ""; amount = 0; if (string.IsNullOrWhiteSpace(rawValue)) { return false; } string text = rawValue.Trim(); GlobalKeys val = default(GlobalKeys); string text2 = default(string); key = ZoneSystem.GetKeyValue(text, ref text2, ref val); if (string.IsNullOrWhiteSpace(key) || string.IsNullOrWhiteSpace(text2)) { return false; } text2 = text2.Trim(); if (text2.StartsWith("++", StringComparison.OrdinalIgnoreCase) || text2.StartsWith("--", StringComparison.OrdinalIgnoreCase)) { return false; } return int.TryParse(text2, NumberStyles.Any, CultureInfo.InvariantCulture, out amount); } private static bool TryParseGlobalKeyMutation(string? rawValue, out string key, out int delta) { key = ""; delta = 0; if (string.IsNullOrWhiteSpace(rawValue)) { return false; } string text = rawValue.Trim(); GlobalKeys val = default(GlobalKeys); string text2 = default(string); key = ZoneSystem.GetKeyValue(text, ref text2, ref val); if (string.IsNullOrWhiteSpace(key) || string.IsNullOrWhiteSpace(text2)) { return false; } text2 = text2.Trim(); if (text2.StartsWith("++", StringComparison.OrdinalIgnoreCase)) { string text3 = text2; if (int.TryParse(text3.Substring(2, text3.Length - 2), NumberStyles.Any, CultureInfo.InvariantCulture, out var result)) { delta = result; return true; } } if (text2.StartsWith("--", StringComparison.OrdinalIgnoreCase)) { string text3 = text2; if (int.TryParse(text3.Substring(2, text3.Length - 2), NumberStyles.Any, CultureInfo.InvariantCulture, out var result2)) { delta = -result2; return true; } } return false; } private static void WarnInvalidEntry(string message) { if (_invalidEntryWarningSuppressionDepth <= 0 && !ShouldSuppressServerSourcedInvalidEntryWarning(message)) { if (_capturedStrictValidationWarnings != null) { _capturedStrictValidationWarnings.Add(message); } else if (InvalidEntryWarnings.Add(message)) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)message); } } } private static InvalidEntryWarningSuppressionScope BeginInvalidEntryWarningSuppressionForSyncedClientBuild(string sourceName) { if (DropNSpawnPlugin.IsSourceOfTruth || !sourceName.StartsWith("ServerSync:", StringComparison.Ordinal)) { return default(InvalidEntryWarningSuppressionScope); } return new InvalidEntryWarningSuppressionScope(active: true); } private static bool ShouldSuppressServerSourcedInvalidEntryWarning(string message) { if (!DropNSpawnPlugin.IsSourceOfTruth) { return message.IndexOf("ServerSync:", StringComparison.Ordinal) >= 0; } return false; } private static bool HasAnyConditionFields(SpawnSystemConditionsDefinition? conditions) { if (conditions != null) { if (!conditions.NoSpawnRadius.HasValue && !conditions.MaxSpawned.HasValue && (conditions.Biomes?.Count ?? 0) <= 0 && (conditions.BiomeAreas?.Count ?? 0) <= 0 && string.IsNullOrWhiteSpace(conditions.RequiredGlobalKey) && (conditions.RequiredEnvironments?.Count ?? 0) <= 0 && conditions.TimeOfDay == null) { FloatRangeDefinition? altitudeRange = GetAltitudeRange(conditions); if (altitudeRange == null || !altitudeRange.HasValues()) { FloatRangeDefinition? tiltRange = GetTiltRange(conditions); if ((tiltRange == null || !tiltRange.HasValues()) && !conditions.InForest.HasValue && !conditions.InLava.HasValue && !conditions.CanSpawnCloseToPlayer.HasValue && !conditions.InsidePlayerBase.HasValue) { FloatRangeDefinition? oceanDepthRange = GetOceanDepthRange(conditions); if (oceanDepthRange == null || !oceanDepthRange.HasValues()) { return GetDistanceFromCenterRange(conditions)?.HasValues() ?? false; } } } } return true; } return false; } private static bool HasAnySpawnFields(SpawnSystemSpawnDefinition? spawn) { if (spawn != null) { if (string.IsNullOrWhiteSpace(spawn.Name) && !spawn.HuntPlayer.HasValue) { IntRangeDefinition? levelRange = GetLevelRange(spawn); if ((levelRange == null || !levelRange.HasValues()) && !spawn.OverrideLevelUpChance.HasValue && !spawn.LevelUpMinCenterDistance.HasValue && !spawn.GroundOffset.HasValue && !spawn.GroundOffsetRandom.HasValue && !spawn.SpawnInterval.HasValue && !spawn.SpawnChance.HasValue) { FloatRangeDefinition? spawnRadiusRange = GetSpawnRadiusRange(spawn); if (spawnRadiusRange == null || !spawnRadiusRange.HasValues()) { IntRangeDefinition? groupSizeRange = GetGroupSizeRange(spawn); if (groupSizeRange == null || !groupSizeRange.HasValues()) { return spawn.GroupRadius.HasValue; } } } } return true; } return false; } private static bool HasAnyModifierFields(SpawnSystemModifiersDefinition? modifiers) { if (modifiers != null) { if (string.IsNullOrWhiteSpace(modifiers.Data) && string.IsNullOrWhiteSpace(modifiers.Faction) && (modifiers.Fields?.Count ?? 0) <= 0) { return (modifiers.Objects?.Count ?? 0) > 0; } return true; } return false; } private static IntRangeDefinition? GetLevelRange(CanonicalSpawnSystemEntry entry) { return GetLevelRange(entry.SpawnSystem); } private static IntRangeDefinition? GetLevelRange(SpawnSystemSpawnDefinition? spawn) { return spawn?.Level ?? RangeFormatting.From(spawn?.MinLevel, spawn?.MaxLevel ?? spawn?.MinLevel); } private static FloatRangeDefinition? GetSpawnRadiusRange(CanonicalSpawnSystemEntry entry) { return GetSpawnRadiusRange(entry.SpawnSystem); } private static FloatRangeDefinition? GetSpawnRadiusRange(SpawnSystemSpawnDefinition? spawn) { return spawn?.SpawnRadius ?? RangeFormatting.From(spawn?.SpawnRadiusMin, spawn?.SpawnRadiusMax); } private static IntRangeDefinition? GetGroupSizeRange(CanonicalSpawnSystemEntry entry) { return GetGroupSizeRange(entry.SpawnSystem); } private static IntRangeDefinition? GetGroupSizeRange(SpawnSystemSpawnDefinition? spawn) { return spawn?.GroupSize ?? RangeFormatting.From(spawn?.GroupSizeMin, spawn?.GroupSizeMax ?? spawn?.GroupSizeMin); } private static FloatRangeDefinition? GetAltitudeRange(CanonicalSpawnSystemEntry entry) { return GetAltitudeRange(entry.Conditions); } private static FloatRangeDefinition? GetAltitudeRange(SpawnSystemConditionsDefinition? conditions) { return conditions?.Altitude ?? RangeFormatting.From(conditions?.MinAltitude, conditions?.MaxAltitude); } private static FloatRangeDefinition? GetTiltRange(CanonicalSpawnSystemEntry entry) { return GetTiltRange(entry.Conditions); } private static FloatRangeDefinition? GetTiltRange(SpawnSystemConditionsDefinition? conditions) { return conditions?.Tilt ?? RangeFormatting.From(conditions?.MinTilt, conditions?.MaxTilt); } private static FloatRangeDefinition? GetOceanDepthRange(CanonicalSpawnSystemEntry entry) { return GetOceanDepthRange(entry.Conditions); } private static FloatRangeDefinition? GetOceanDepthRange(SpawnSystemConditionsDefinition? conditions) { return conditions?.OceanDepth ?? RangeFormatting.From(conditions?.MinOceanDepth, conditions?.MaxOceanDepth); } private static FloatRangeDefinition? GetDistanceFromCenterRange(CanonicalSpawnSystemEntry entry) { return GetDistanceFromCenterRange(entry.Conditions); } private static FloatRangeDefinition? GetDistanceFromCenterRange(SpawnSystemConditionsDefinition? conditions) { return conditions?.DistanceFromCenter ?? RangeFormatting.From(conditions?.MinDistanceFromCenter, conditions?.MaxDistanceFromCenter); } private static List> BuildBiomeOrderedSnapshotSections(SpawnSystemSnapshot snapshot) { List> list = PrefabOutputSections.BuildSections(snapshot.Entries, (SpawnSystemEntrySnapshot entry) => NormalizeReferencePrefabName(entry.Data.m_prefab) ?? ""); foreach (PrefabOwnerSection item in list) { item.Entries.Sort(CompareSpawnSystemEntriesForOutput); } return list; } private static List> BuildBiomeOrderedReferenceSections(IEnumerable entries) { PrefabOwnerResolver.OwnerSnapshot ownerSnapshot = PrefabOwnerResolver.GetSnapshot(); List> list = PrefabOutputSections.BuildSections(entries, (CanonicalSpawnSystemEntry entry) => (entry.Prefab ?? "").Trim(), (CanonicalSpawnSystemEntry entry) => string.IsNullOrWhiteSpace(entry.ReferenceOwnerName) ? ownerSnapshot.GetOwnerName((entry.Prefab ?? "").Trim()) : entry.ReferenceOwnerName); foreach (PrefabOwnerSection item in list) { item.Entries.Sort(CompareReferenceEntriesForOutput); } return list; } private static CanonicalSpawnSystemEntry ConvertToReferenceEntry(SpawnSystemEntrySnapshot snapshot) { return ConvertToReferenceEntry(snapshot.Data); } private static CanonicalSpawnSystemEntry ConvertToReferenceEntry(SpawnData data) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) SpawnData val = new SpawnData(); string text = NormalizeReferencePrefabName(data.m_prefab); string text2 = NormalizeNullable(data.m_name); SpawnSystemSpawnDefinition spawnSystemSpawnDefinition = new SpawnSystemSpawnDefinition { Name = (string.Equals(text2, text, StringComparison.OrdinalIgnoreCase) ? null : text2), Level = RangeFormatting.FromReference(data.m_minLevel, data.m_maxLevel, val.m_minLevel, val.m_maxLevel), LevelUpMinCenterDistance = GetReferenceFloatOrNull(data.m_levelUpMinCenterDistance, val.m_levelUpMinCenterDistance), OverrideLevelUpChance = GetReferenceFloatOrNull(data.m_overrideLevelupChance, val.m_overrideLevelupChance), SpawnInterval = GetReferenceFloatOrNull(data.m_spawnInterval, val.m_spawnInterval), SpawnChance = GetReferenceFloatOrNull(data.m_spawnChance, val.m_spawnChance), SpawnRadius = RangeFormatting.FromReference(data.m_spawnRadiusMin, data.m_spawnRadiusMax, val.m_spawnRadiusMin, val.m_spawnRadiusMax), GroupSize = RangeFormatting.FromReference(data.m_groupSizeMin, data.m_groupSizeMax, val.m_groupSizeMin, val.m_groupSizeMax), GroupRadius = GetReferenceFloatOrNull(data.m_groupRadius, val.m_groupRadius), HuntPlayer = GetReferenceBoolOrNull(data.m_huntPlayer, val.m_huntPlayer), GroundOffset = GetReferenceFloatOrNull(data.m_groundOffset, val.m_groundOffset), GroundOffsetRandom = GetReferenceFloatOrNull(data.m_groundOffsetRandom, val.m_groundOffsetRandom) }; SpawnSystemConditionsDefinition spawnSystemConditionsDefinition = new SpawnSystemConditionsDefinition { Biomes = ((data.m_biome == val.m_biome) ? null : ConvertBiomes(data.m_biome)), BiomeAreas = ((data.m_biomeArea == val.m_biomeArea) ? null : ConvertBiomeAreas(data.m_biomeArea)), RequiredGlobalKey = NormalizeNullable(data.m_requiredGlobalKey), RequiredEnvironments = NormalizeReferenceStringList(data.m_requiredEnvironments), TimeOfDay = ((data.m_spawnAtDay == val.m_spawnAtDay && data.m_spawnAtNight == val.m_spawnAtNight) ? null : TimeOfDayFormatting.FromSpawnFlags(data.m_spawnAtDay, data.m_spawnAtNight)), NoSpawnRadius = GetReferenceFloatOrNull(data.m_spawnDistance, val.m_spawnDistance), MaxSpawned = GetReferenceIntOrNull(data.m_maxSpawned, val.m_maxSpawned), Altitude = RangeFormatting.FromReference(data.m_minAltitude, data.m_maxAltitude, val.m_minAltitude, val.m_maxAltitude), Tilt = RangeFormatting.FromReference(data.m_minTilt, data.m_maxTilt, val.m_minTilt, val.m_maxTilt), InForest = GetReferenceExclusiveZoneToggle(data.m_inForest, data.m_outsideForest, val.m_inForest, val.m_outsideForest), InLava = GetReferenceExclusiveZoneToggle(data.m_inLava, data.m_outsideLava, val.m_inLava, val.m_outsideLava), CanSpawnCloseToPlayer = GetReferenceBoolOrNull(data.m_canSpawnCloseToPlayer, val.m_canSpawnCloseToPlayer), InsidePlayerBase = GetReferenceBoolOrNull(data.m_insidePlayerBase, val.m_insidePlayerBase), OceanDepth = RangeFormatting.FromReference(data.m_minOceanDepth, data.m_maxOceanDepth, val.m_minOceanDepth, val.m_maxOceanDepth), DistanceFromCenter = RangeFormatting.FromReference(data.m_minDistanceFromCenter, data.m_maxDistanceFromCenter, val.m_minDistanceFromCenter, val.m_maxDistanceFromCenter) }; return new CanonicalSpawnSystemEntry { Prefab = text, Enabled = data.m_enabled, SpawnSystem = (HasAnySpawnFields(spawnSystemSpawnDefinition) ? spawnSystemSpawnDefinition : null), Conditions = (HasAnyConditionFields(spawnSystemConditionsDefinition) ? spawnSystemConditionsDefinition : null) }; } internal static CanonicalSpawnSystemEntry CreateReferenceEntryForExternalProjection(SpawnData data, string? prefabNameFallback = null) { CanonicalSpawnSystemEntry canonicalSpawnSystemEntry = ConvertToReferenceEntry(data); if (string.IsNullOrWhiteSpace(canonicalSpawnSystemEntry.Prefab)) { canonicalSpawnSystemEntry.Prefab = NormalizeNullable(prefabNameFallback); } return canonicalSpawnSystemEntry; } private static CanonicalSpawnSystemEntry ConvertToConfigurationEntry(SpawnSystemEntrySnapshot snapshot) { //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) SpawnSystemSpawnDefinition spawnSystem = new SpawnSystemSpawnDefinition { Name = NormalizeNullable(snapshot.Data.m_name), HuntPlayer = snapshot.Data.m_huntPlayer, Level = RangeFormatting.From(snapshot.Data.m_minLevel, snapshot.Data.m_maxLevel), LevelUpMinCenterDistance = snapshot.Data.m_levelUpMinCenterDistance, OverrideLevelUpChance = snapshot.Data.m_overrideLevelupChance, SpawnInterval = snapshot.Data.m_spawnInterval, SpawnChance = snapshot.Data.m_spawnChance, SpawnRadius = RangeFormatting.From(snapshot.Data.m_spawnRadiusMin, snapshot.Data.m_spawnRadiusMax), GroupSize = RangeFormatting.From(snapshot.Data.m_groupSizeMin, snapshot.Data.m_groupSizeMax), GroupRadius = snapshot.Data.m_groupRadius, GroundOffset = snapshot.Data.m_groundOffset, GroundOffsetRandom = snapshot.Data.m_groundOffsetRandom }; SpawnSystemConditionsDefinition conditions = new SpawnSystemConditionsDefinition { Biomes = ConvertBiomes(snapshot.Data.m_biome), BiomeAreas = ConvertBiomeAreas(snapshot.Data.m_biomeArea), RequiredGlobalKey = NormalizeNullable(snapshot.Data.m_requiredGlobalKey), RequiredEnvironments = snapshot.Data.m_requiredEnvironments.Select((string environment) => environment.Trim()).ToList(), TimeOfDay = TimeOfDayFormatting.FromSpawnFlags(snapshot.Data.m_spawnAtDay, snapshot.Data.m_spawnAtNight), NoSpawnRadius = snapshot.Data.m_spawnDistance, MaxSpawned = snapshot.Data.m_maxSpawned, Altitude = RangeFormatting.From(snapshot.Data.m_minAltitude, snapshot.Data.m_maxAltitude), Tilt = RangeFormatting.From(snapshot.Data.m_minTilt, snapshot.Data.m_maxTilt), InForest = ConvertExclusiveZoneToggle(snapshot.Data.m_inForest, snapshot.Data.m_outsideForest), InLava = ConvertExclusiveZoneToggle(snapshot.Data.m_inLava, snapshot.Data.m_outsideLava), CanSpawnCloseToPlayer = snapshot.Data.m_canSpawnCloseToPlayer, InsidePlayerBase = snapshot.Data.m_insidePlayerBase, OceanDepth = RangeFormatting.From(snapshot.Data.m_minOceanDepth, snapshot.Data.m_maxOceanDepth), DistanceFromCenter = RangeFormatting.From(snapshot.Data.m_minDistanceFromCenter, snapshot.Data.m_maxDistanceFromCenter) }; return new CanonicalSpawnSystemEntry { Enabled = snapshot.Data.m_enabled, Prefab = NormalizeReferencePrefabName(snapshot.Data.m_prefab), SpawnSystem = spawnSystem, Conditions = conditions }; } private static int CompareSpawnSystemEntriesForOutput(SpawnSystemEntrySnapshot left, SpawnSystemEntrySnapshot right) { (int, string, int, int) biomeSortKey = GetBiomeSortKey(left); (int, string, int, int) biomeSortKey2 = GetBiomeSortKey(right); int num = biomeSortKey.Item1.CompareTo(biomeSortKey2.Item1); if (num != 0) { return num; } num = StringComparer.OrdinalIgnoreCase.Compare(biomeSortKey.Item2, biomeSortKey2.Item2); if (num != 0) { return num; } num = biomeSortKey.Item3.CompareTo(biomeSortKey2.Item3); if (num != 0) { return num; } num = biomeSortKey2.Item4.CompareTo(biomeSortKey.Item4); if (num != 0) { return num; } num = StringComparer.OrdinalIgnoreCase.Compare(NormalizeReferencePrefabName(left.Data.m_prefab) ?? "", NormalizeReferencePrefabName(right.Data.m_prefab) ?? ""); if (num != 0) { return num; } num = StringComparer.OrdinalIgnoreCase.Compare(left.Data.m_name ?? "", right.Data.m_name ?? ""); if (num != 0) { return num; } return StringComparer.Ordinal.Compare(GetStableReferenceSortKey(left), GetStableReferenceSortKey(right)); } private static string GetStableReferenceSortKey(SpawnSystemEntrySnapshot snapshot) { return GetStableReferenceSortKey(ConvertToReferenceEntry(snapshot)); } private static string GetStableReferenceSortKey(CanonicalSpawnSystemEntry entry) { return Serializer.Serialize(entry).TrimEnd('\r', '\n'); } private static (int GroupRank, string GroupName, int EarliestRank, int BiomeCount) GetBiomeSortKey(SpawnSystemEntrySnapshot snapshot) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return BuildBiomeSortKey(ConvertBiomes(snapshot.Data.m_biome)); } private static (int GroupRank, string GroupName, int EarliestRank, int BiomeCount) GetBiomeSortKey(CanonicalSpawnSystemEntry entry) { return BuildBiomeSortKey(entry.Conditions?.Biomes); } private static int CompareReferenceEntriesForOutput(CanonicalSpawnSystemEntry left, CanonicalSpawnSystemEntry right) { (int, string, int, int) biomeSortKey = GetBiomeSortKey(left); (int, string, int, int) biomeSortKey2 = GetBiomeSortKey(right); int num = biomeSortKey.Item1.CompareTo(biomeSortKey2.Item1); if (num != 0) { return num; } num = StringComparer.OrdinalIgnoreCase.Compare(biomeSortKey.Item2, biomeSortKey2.Item2); if (num != 0) { return num; } num = biomeSortKey.Item3.CompareTo(biomeSortKey2.Item3); if (num != 0) { return num; } num = biomeSortKey2.Item4.CompareTo(biomeSortKey.Item4); if (num != 0) { return num; } num = StringComparer.OrdinalIgnoreCase.Compare(left.Prefab ?? "", right.Prefab ?? ""); if (num != 0) { return num; } num = StringComparer.OrdinalIgnoreCase.Compare(left.SpawnSystem?.Name ?? "", right.SpawnSystem?.Name ?? ""); if (num != 0) { return num; } return StringComparer.Ordinal.Compare(GetStableReferenceSortKey(left), GetStableReferenceSortKey(right)); } private static (int GroupRank, string GroupName, int EarliestRank, int BiomeCount) BuildBiomeSortKey(List? biomes) { List list = (from value in biomes ?? new List() select (value ?? "").Trim() into value where value.Length > 0 select value).ToList(); if (list.Count == 0) { return (int.MaxValue, "", int.MaxValue, 0); } bool flag = false; int num = -1; int num2 = int.MaxValue; foreach (string item2 in list) { string text = NormalizeBiomeSortToken(item2); (string, int) value2; if (text == "all") { flag = true; } else if (BiomeOutputOrderLookup.TryGetValue(text, out value2)) { num = Math.Max(num, value2.Item2); num2 = Math.Min(num2, value2.Item2); } } if (flag) { num = Math.Max(num, BiomeOutputOrder.Length - 1); num2 = Math.Min(num2, 0); } if (num >= 0) { return (num, BiomeOutputOrder[num], num2, list.Count); } string item = list.OrderBy((string value) => value, StringComparer.OrdinalIgnoreCase).First(); return (BiomeOutputOrder.Length + 1, item, int.MaxValue, list.Count); } private static Dictionary BuildBiomeOutputOrderLookup() { Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); for (int i = 0; i < BiomeOutputOrder.Length; i++) { string text = BiomeOutputOrder[i]; dictionary[NormalizeBiomeSortToken(text)] = (text, i); } dictionary["ashlands"] = ("AshLands", Array.IndexOf(BiomeOutputOrder, "AshLands")); return dictionary; } private static string NormalizeBiomeSortToken(string? value) { return BiomeResolutionSupport.NormalizeBiomeToken(value); } private static bool HasAnyConditionFields(CanonicalSpawnSystemEntry entry) { return HasAnyConditionFields(entry.Conditions); } private static bool HasAnySpawnFields(CanonicalSpawnSystemEntry entry) { return HasAnySpawnFields(entry.SpawnSystem); } private static bool HasAnyModifierFields(CanonicalSpawnSystemEntry entry) { return HasAnyModifierFields(entry.Modifiers); } private static List? NormalizeReferenceStringList(IEnumerable? values) { if (values == null) { return null; } List list = (from value in values select (value ?? "").Trim() into value where value.Length > 0 select value).ToList(); if (list.Count <= 0) { return null; } return list; } private static bool? GetReferenceBoolOrNull(bool value, bool defaultValue) { if (value != defaultValue) { return value; } return null; } private static bool? ConvertExclusiveZoneToggle(bool allowInside, bool allowOutside) { if (allowInside && !allowOutside) { return true; } if (!allowInside && allowOutside) { return false; } return null; } private static bool? GetReferenceExclusiveZoneToggle(bool allowInside, bool allowOutside, bool defaultAllowInside, bool defaultAllowOutside) { bool? flag = ConvertExclusiveZoneToggle(allowInside, allowOutside); if (flag != ConvertExclusiveZoneToggle(defaultAllowInside, defaultAllowOutside)) { return flag; } return null; } private static void ApplyExclusiveZoneToggle(bool? value, ref bool allowInside, ref bool allowOutside) { if (value.HasValue) { allowInside = value.Value; allowOutside = !value.Value; } } private static int? GetReferenceIntOrNull(int value, int defaultValue) { if (value != defaultValue) { return value; } return null; } private static float? GetReferenceFloatOrNull(float value, float defaultValue) { if (!(Math.Abs(value - defaultValue) < 0.0001f)) { return value; } return null; } private static void AppendReferenceEntry(StringBuilder builder, CanonicalSpawnSystemEntry entry) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown AppendYamlListEntryLine(builder, 0, "prefab", entry.Prefab); if (!entry.Enabled) { AppendYamlOptionalBoolLine(builder, 1, "enabled", false); } AppendYamlSpawnSystemPayloadBlock(builder, 1, entry, new SpawnData(), includeEmptyPlaceholder: false); } private static void AppendConfigurationEntry(StringBuilder builder, CanonicalSpawnSystemEntry entry) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown SpawnData defaults = new SpawnData(); AppendYamlListEntryLine(builder, 0, "prefab", entry.Prefab); AppendYamlLine(builder, 1, "enabled: " + FormatYamlBool(entry.Enabled)); AppendYamlSpawnSystemPayloadBlock(builder, 1, entry, defaults, includeEmptyPlaceholder: true); } private static void AppendYamlSpawnSystemPayloadBlock(StringBuilder builder, int indent, CanonicalSpawnSystemEntry entry, SpawnData defaults, bool includeEmptyPlaceholder) { if (includeEmptyPlaceholder || HasAnySpawnFields(entry) || HasAnyConditionFields(entry) || HasAnyModifierFields(entry)) { AppendYamlLine(builder, indent, "spawnSystem:"); AppendYamlSpawnSystemSpawnBlock(builder, indent + 1, entry, defaults, includeEmptyPlaceholder); AppendYamlSpawnSystemConditionsBlock(builder, indent, entry, defaults, includeEmptyPlaceholder); AppendYamlSpawnSystemModifiersBlock(builder, indent, entry, includeEmptyPlaceholder); } } private static void AppendYamlSpawnSystemConditionsBlock(StringBuilder builder, int indent, CanonicalSpawnSystemEntry entry, SpawnData defaults, bool includeEmptyPlaceholder) { SpawnSystemConditionsDefinition conditions = entry.Conditions; if (includeEmptyPlaceholder || HasAnyConditionFields(conditions)) { AppendYamlLine(builder, indent, "conditions:"); TimeOfDayDefinition fallback = TimeOfDayFormatting.FromSpawnFlags(defaults.m_spawnAtDay, defaults.m_spawnAtNight); if (includeEmptyPlaceholder) { AppendYamlLine(builder, indent + 1, "noSpawnRadius: " + FormatYamlFloat(conditions?.NoSpawnRadius ?? defaults.m_spawnDistance)); AppendYamlLine(builder, indent + 1, $"maxSpawned: {conditions?.MaxSpawned ?? defaults.m_maxSpawned}"); AppendYamlLine(builder, indent + 1, "tilt: " + RangeFormatting.FormatInlineObject(GetTiltRange(entry) ?? RangeFormatting.From(defaults.m_minTilt, defaults.m_maxTilt))); AppendYamlLine(builder, indent + 1, "altitude: " + RangeFormatting.FormatInlineObject(GetAltitudeRange(entry) ?? RangeFormatting.From(defaults.m_minAltitude, defaults.m_maxAltitude))); AppendYamlLine(builder, indent + 1, "oceanDepth: " + RangeFormatting.FormatInlineObject(GetOceanDepthRange(entry) ?? RangeFormatting.From(defaults.m_minOceanDepth, defaults.m_maxOceanDepth))); AppendYamlLine(builder, indent + 1, "distanceFromCenter: " + RangeFormatting.FormatInlineObject(GetDistanceFromCenterRange(entry) ?? RangeFormatting.From(defaults.m_minDistanceFromCenter, defaults.m_maxDistanceFromCenter))); AppendYamlConditionalInlineListLine(builder, indent + 1, "biomes", conditions?.Biomes, includeEmptyPlaceholder); AppendYamlConditionalInlineListLine(builder, indent + 1, "biomeAreas", conditions?.BiomeAreas, includeEmptyPlaceholder); AppendYamlLine(builder, indent + 1, "timeOfDay: " + TimeOfDayFormatting.FormatInlineList(conditions?.TimeOfDay, fallback)); AppendYamlConditionalInlineListLine(builder, indent + 1, "requiredEnvironments", conditions?.RequiredEnvironments, includeEmptyPlaceholder); AppendYamlStringLine(builder, indent + 1, "requiredGlobalKey", conditions?.RequiredGlobalKey ?? defaults.m_requiredGlobalKey); AppendYamlLine(builder, indent + 1, "inLava: " + FormatYamlNullableBoolOrNull(conditions?.InLava)); AppendYamlLine(builder, indent + 1, "inForest: " + FormatYamlNullableBoolOrNull(conditions?.InForest)); AppendYamlLine(builder, indent + 1, "insidePlayerBase: " + FormatYamlBool(conditions?.InsidePlayerBase ?? defaults.m_insidePlayerBase)); AppendYamlLine(builder, indent + 1, "canSpawnCloseToPlayer: " + FormatYamlBool(conditions?.CanSpawnCloseToPlayer ?? defaults.m_canSpawnCloseToPlayer)); } else { AppendYamlOptionalFloatLine(builder, indent + 1, "noSpawnRadius", conditions?.NoSpawnRadius); AppendYamlOptionalIntLine(builder, indent + 1, "maxSpawned", conditions?.MaxSpawned); AppendYamlOptionalRangeLine(builder, indent + 1, "tilt", GetTiltRange(entry)); AppendYamlOptionalRangeLine(builder, indent + 1, "altitude", GetAltitudeRange(entry)); AppendYamlOptionalRangeLine(builder, indent + 1, "oceanDepth", GetOceanDepthRange(entry)); AppendYamlOptionalRangeLine(builder, indent + 1, "distanceFromCenter", GetDistanceFromCenterRange(entry)); AppendYamlOptionalInlineListLine(builder, indent + 1, "biomes", conditions?.Biomes); AppendYamlOptionalInlineListLine(builder, indent + 1, "biomeAreas", conditions?.BiomeAreas); AppendYamlOptionalTimeOfDayLine(builder, indent + 1, "timeOfDay", conditions?.TimeOfDay); AppendYamlOptionalInlineListLine(builder, indent + 1, "requiredEnvironments", conditions?.RequiredEnvironments); AppendYamlOptionalStringLine(builder, indent + 1, "requiredGlobalKey", conditions?.RequiredGlobalKey); AppendYamlOptionalBoolLine(builder, indent + 1, "inLava", conditions?.InLava); AppendYamlOptionalBoolLine(builder, indent + 1, "inForest", conditions?.InForest); AppendYamlOptionalBoolLine(builder, indent + 1, "insidePlayerBase", conditions?.InsidePlayerBase); AppendYamlOptionalBoolLine(builder, indent + 1, "canSpawnCloseToPlayer", conditions?.CanSpawnCloseToPlayer); } } } private static void AppendYamlSpawnSystemSpawnBlock(StringBuilder builder, int indent, CanonicalSpawnSystemEntry entry, SpawnData defaults, bool includeEmptyPlaceholder) { SpawnSystemSpawnDefinition spawnSystem = entry.SpawnSystem; if (includeEmptyPlaceholder || HasAnySpawnFields(spawnSystem)) { if (includeEmptyPlaceholder) { AppendYamlStringLine(builder, indent, "name", spawnSystem?.Name); AppendYamlLine(builder, indent, "huntPlayer: " + FormatYamlBool(spawnSystem?.HuntPlayer ?? defaults.m_huntPlayer)); AppendYamlLine(builder, indent, "level: " + RangeFormatting.FormatInlineObject(GetLevelRange(entry) ?? RangeFormatting.From(defaults.m_minLevel, defaults.m_maxLevel))); AppendYamlLine(builder, indent, "overrideLevelUpChance: " + FormatYamlFloat(spawnSystem?.OverrideLevelUpChance ?? defaults.m_overrideLevelupChance)); AppendYamlLine(builder, indent, "levelUpMinCenterDistance: " + FormatYamlFloat(spawnSystem?.LevelUpMinCenterDistance ?? defaults.m_levelUpMinCenterDistance)); AppendYamlLine(builder, indent, "groundOffset: " + FormatYamlFloat(spawnSystem?.GroundOffset ?? defaults.m_groundOffset)); AppendYamlLine(builder, indent, "groundOffsetRandom: " + FormatYamlFloat(spawnSystem?.GroundOffsetRandom ?? defaults.m_groundOffsetRandom)); AppendYamlLine(builder, indent, "spawnInterval: " + FormatYamlFloat(spawnSystem?.SpawnInterval ?? defaults.m_spawnInterval)); AppendYamlLine(builder, indent, "spawnChance: " + FormatYamlFloat(spawnSystem?.SpawnChance ?? defaults.m_spawnChance)); AppendYamlLine(builder, indent, "spawnRadius: " + RangeFormatting.FormatInlineObject(GetSpawnRadiusRange(entry) ?? RangeFormatting.From(defaults.m_spawnRadiusMin, defaults.m_spawnRadiusMax))); AppendYamlLine(builder, indent, "groupSize: " + RangeFormatting.FormatInlineObject(GetGroupSizeRange(entry) ?? RangeFormatting.From(defaults.m_groupSizeMin, defaults.m_groupSizeMax))); AppendYamlLine(builder, indent, "groupRadius: " + FormatYamlFloat(spawnSystem?.GroupRadius ?? defaults.m_groupRadius)); } else { AppendYamlOptionalStringLine(builder, indent, "name", spawnSystem?.Name); AppendYamlOptionalBoolLine(builder, indent, "huntPlayer", spawnSystem?.HuntPlayer); AppendYamlOptionalRangeLine(builder, indent, "level", GetLevelRange(entry)); AppendYamlOptionalFloatLine(builder, indent, "overrideLevelUpChance", spawnSystem?.OverrideLevelUpChance); AppendYamlOptionalFloatLine(builder, indent, "levelUpMinCenterDistance", spawnSystem?.LevelUpMinCenterDistance); AppendYamlOptionalFloatLine(builder, indent, "groundOffset", spawnSystem?.GroundOffset); AppendYamlOptionalFloatLine(builder, indent, "groundOffsetRandom", spawnSystem?.GroundOffsetRandom); AppendYamlOptionalFloatLine(builder, indent, "spawnInterval", spawnSystem?.SpawnInterval); AppendYamlOptionalFloatLine(builder, indent, "spawnChance", spawnSystem?.SpawnChance); AppendYamlOptionalRangeLine(builder, indent, "spawnRadius", GetSpawnRadiusRange(entry)); AppendYamlOptionalRangeLine(builder, indent, "groupSize", GetGroupSizeRange(entry)); AppendYamlOptionalFloatLine(builder, indent, "groupRadius", spawnSystem?.GroupRadius); } } } private static void AppendYamlSpawnSystemModifiersBlock(StringBuilder builder, int indent, CanonicalSpawnSystemEntry entry, bool includeEmptyPlaceholder) { SpawnSystemModifiersDefinition modifiers = entry.Modifiers; if (includeEmptyPlaceholder || HasAnyModifierFields(modifiers)) { AppendYamlLine(builder, indent, "modifiers:"); if (includeEmptyPlaceholder) { AppendYamlDictionaryLine(builder, indent + 1, "fields", modifiers?.Fields); AppendYamlInlineListLine(builder, indent + 1, "objects", modifiers?.Objects); AppendYamlStringLine(builder, indent + 1, "data", modifiers?.Data); AppendYamlStringLine(builder, indent + 1, "faction", modifiers?.Faction); } else { AppendYamlOptionalDictionaryLine(builder, indent + 1, "fields", modifiers?.Fields); AppendYamlOptionalInlineListLine(builder, indent + 1, "objects", modifiers?.Objects); AppendYamlOptionalStringLine(builder, indent + 1, "data", modifiers?.Data); AppendYamlOptionalStringLine(builder, indent + 1, "faction", modifiers?.Faction); } } } private static void AppendYamlLine(StringBuilder builder, int indent, string text) { builder.Append(' ', indent * 2); builder.AppendLine(text); } private static void AppendYamlListEntryLine(StringBuilder builder, int indent, string key, string? value) { builder.Append(' ', indent * 2); builder.Append("- ").Append(key).Append(": ") .AppendLine(FormatYamlString(value)); } private static void AppendYamlStringLine(StringBuilder builder, int indent, string key, string? value) { builder.Append(' ', indent * 2); builder.Append(key).Append(": "); if (value == null) { builder.Append("null"); } else { builder.Append(FormatYamlString(value)); } builder.AppendLine(); } private static void AppendYamlOptionalStringLine(StringBuilder builder, int indent, string key, string? value) { if (!string.IsNullOrWhiteSpace(value)) { AppendYamlStringLine(builder, indent, key, value); } } private static void AppendYamlInlineListLine(StringBuilder builder, int indent, string key, List? values) { builder.Append(' ', indent * 2); builder.Append(key).Append(": ").AppendLine(FormatYamlInlineList(values)); } private static void AppendYamlOptionalInlineListLine(StringBuilder builder, int indent, string key, List? values) { if (values != null && values.Count > 0) { AppendYamlInlineListLine(builder, indent, key, values); } } private static void AppendYamlConditionalInlineListLine(StringBuilder builder, int indent, string key, List? values, bool includeEmptyPlaceholder) { if (includeEmptyPlaceholder || (values?.Count ?? 0) > 0) { AppendYamlInlineListLine(builder, indent, key, values); } } private static void AppendYamlOptionalTimeOfDayLine(StringBuilder builder, int indent, string key, TimeOfDayDefinition? value) { if (value != null) { AppendYamlLine(builder, indent, key + ": " + TimeOfDayFormatting.FormatInlineList(value)); } } private static void AppendYamlOptionalBoolLine(StringBuilder builder, int indent, string key, bool? value) { if (value.HasValue) { AppendYamlLine(builder, indent, key + ": " + FormatYamlBool(value.Value)); } } private static void AppendYamlOptionalIntLine(StringBuilder builder, int indent, string key, int? value) { if (value.HasValue) { AppendYamlLine(builder, indent, $"{key}: {value.Value}"); } } private static void AppendYamlOptionalFloatLine(StringBuilder builder, int indent, string key, float? value) { if (value.HasValue) { AppendYamlLine(builder, indent, key + ": " + FormatYamlFloat(value.Value)); } } private static void AppendYamlOptionalRangeLine(StringBuilder builder, int indent, string key, IntRangeDefinition? range) { if (range != null && range.HasValues()) { AppendYamlLine(builder, indent, key + ": " + RangeFormatting.FormatShorthand(range)); } } private static void AppendYamlOptionalRangeLine(StringBuilder builder, int indent, string key, FloatRangeDefinition? range) { if (range != null && range.HasValues()) { AppendYamlLine(builder, indent, key + ": " + RangeFormatting.FormatShorthand(range)); } } private static void AppendYamlDictionaryLine(StringBuilder builder, int indent, string key, Dictionary? values) { if (values == null || values.Count == 0) { AppendYamlLine(builder, indent, key + ": {}"); return; } builder.Append(' ', indent * 2); builder.Append(key).Append(": { "); builder.Append(string.Join(", ", values.Select, string>((KeyValuePair pair) => FormatYamlString(pair.Key) + ": " + FormatYamlString(pair.Value)))); builder.AppendLine(" }"); } private static void AppendYamlOptionalDictionaryLine(StringBuilder builder, int indent, string key, Dictionary? values) { if (values != null && values.Count > 0) { AppendYamlDictionaryLine(builder, indent, key, values); } } private static string FormatYamlInlineList(List? values) { if (values == null || values.Count == 0) { return "[]"; } return "[" + string.Join(", ", values.Select(FormatYamlString)) + "]"; } private static string FormatYamlString(string? value) { string graph = value ?? ""; return Serializer.Serialize(graph).TrimEnd('\r', '\n'); } private static string FormatYamlBool(bool value) { if (!value) { return "false"; } return "true"; } private static string FormatYamlNullableBoolOrNull(bool? value) { if (!value.HasValue) { return "null"; } return FormatYamlBool(value.Value); } private static string FormatYamlRangeOrNull(IntRangeDefinition? value) { if (value == null || !value.HasValues()) { return "null"; } return RangeFormatting.FormatInlineObject(value); } private static string FormatYamlFloat(float value) { if (!(Math.Abs(value % 1f) < 0.0001f)) { return value.ToString("0.###", CultureInfo.InvariantCulture); } return ((int)MathF.Round(value)).ToString(CultureInfo.InvariantCulture); } private static void AppendTemplateComment(StringBuilder builder, string text) { builder.Append("# ").AppendLine(text); } private static void AppendTemplateBlankLine(StringBuilder builder) { builder.AppendLine("#"); } private static void QueueLiveSystemAttachForTableCore(CompiledSpawnSystemTable? table, int buildVersion, bool queueEspRefresh, IEnumerable? systems = null) { if (table == null) { return; } foreach (SpawnSystem item in systems ?? GetLiveSystems()) { QueueLiveSystemAttach(item, table, buildVersion, queueEspRefresh); } } private static void QueueLiveSystemAttachCore(SpawnSystem? system, CompiledSpawnSystemTable targetTable, int buildVersion, bool queueEspRefresh) { if ((Object)(object)system == (Object)null) { return; } int instanceID = ((Object)system).GetInstanceID(); if (!PendingLiveSystemAttachIds.Add(instanceID)) { if (queueEspRefresh) { PendingLiveSystemAttachEspRefreshIds.Add(instanceID); } return; } if (queueEspRefresh) { PendingLiveSystemAttachEspRefreshIds.Add(instanceID); } PendingLiveSystemAttaches.Enqueue(new PendingLiveSystemAttach(system, instanceID, _reconcileQueueEpoch, buildVersion, targetTable)); } private static void AttachTableToSystemCore(SpawnSystem? system, CompiledSpawnSystemTable? table) { if (!((Object)(object)system == (Object)null) && table != null && table.Lists.Count != 0) { ClearAttachedRuntimeState(system); SnapshotsBySystemId.Remove(((Object)system).GetInstanceID()); _templateSnapshot = null; system.m_spawnLists = CloneAttachedSpawnLists(table); } } private static bool IsSystemAttachedToCompiledTableCore(SpawnSystem? system, CompiledSpawnSystemTable? table) { if ((Object)(object)system == (Object)null || table == null || table.Lists.Count == 0) { return false; } SpawnListSummary spawnListSummary = SummarizeSpawnLists(system.m_spawnLists); int num = ((table.BaselineListCount > 0) ? table.BaselineListCount : table.Lists.Count); int num2 = ((table.BaselineListCount > 0 || table.BaselineRowCount > 0) ? table.BaselineRowCount : CountSpawnRows(table)); int num3 = ((table.BaselineContentHash != 0) ? table.BaselineContentHash : SummarizeSpawnLists(table.Lists).ContentHash); if (spawnListSummary.ListCount == num && spawnListSummary.RowCount == num2) { return spawnListSummary.ContentHash == num3; } return false; } private static List CloneAttachedSpawnListsCore(CompiledSpawnSystemTable table) { List list = new List(table.Lists.Count); foreach (SpawnSystemList list3 in table.Lists) { List list2 = new List((list3?.m_spawners?.Count).GetValueOrDefault()); if (list3?.m_spawners != null) { foreach (SpawnData spawner in list3.m_spawners) { if (spawner != null) { SpawnData val = spawner.Clone(); table.RuntimeTimeOfDayBySpawnData.TryGetValue(spawner, out TimeOfDayDefinition value); table.CustomPayloadsBySpawnData.TryGetValue(spawner, out SpawnSystemCustomDataSupport.PreparedPayload value2); SpawnSystemCustomDataSupport.ApplyPreparedPayload(val, value2); ApplyRuntimeMetadata(val, value); list2.Add(val); } } } list.Add(CreateAttachedSpawnList(list2)); } return list; } private static CompiledSpawnSystemTable? GetSelectedCompiledTableForCurrentStateCore() { if (!PluginSettingsFacade.IsSpawnSystemDomainEnabled()) { return _vanillaCompiledTable; } return _activeCompiledTable ?? _vanillaCompiledTable; } private static CompiledSpawnSystemTable? BuildVanillaCompiledTableCore(int gameDataSignature) { List vanillaSourceSpawnLists = GetVanillaSourceSpawnLists(); if (vanillaSourceSpawnLists.Count == 0) { return null; } CompiledSpawnSystemTable compiledSpawnSystemTable = new CompiledSpawnSystemTable { GameDataSignature = gameDataSignature, Signature = "vanilla:" + gameDataSignature.ToString(CultureInfo.InvariantCulture) }; foreach (SpawnSystemList item in vanillaSourceSpawnLists) { List spawners = (from spawnData in item.m_spawners where spawnData != null select spawnData.Clone()).ToList(); compiledSpawnSystemTable.Lists.Add(CreateManagedSpawnList(spawners)); } FreezeCompiledTableBaseline(compiledSpawnSystemTable); return compiledSpawnSystemTable; } private static CompiledSpawnSystemTable BuildActiveCompiledTableCore(int gameDataSignature, List entries, string preparedEntriesSignature) { CompiledSpawnSystemTable compiledSpawnSystemTable = new CompiledSpawnSystemTable { GameDataSignature = gameDataSignature, Signature = preparedEntriesSignature }; List list = new List(entries.Count); foreach (PreparedSpawnSystemEntry entry in entries) { SpawnData val = entry.Data.Clone(); SpawnSystemCustomDataSupport.ApplyPreparedPayload(val, entry.CustomDataPayload); ApplyRuntimeMetadata(val, entry.RuntimeTimeOfDay); list.Add(val); } compiledSpawnSystemTable.Lists.Add(CreateManagedSpawnList(list)); FreezeCompiledTableBaseline(compiledSpawnSystemTable); return compiledSpawnSystemTable; } private static List GetVanillaSourceSpawnListsCore() { SpawnSystem zoneCtrlPrefabSpawnSystem = GetZoneCtrlPrefabSpawnSystem(); if ((Object)(object)zoneCtrlPrefabSpawnSystem != (Object)null) { return zoneCtrlPrefabSpawnSystem.m_spawnLists.Where((SpawnSystemList spawnList) => (Object)(object)spawnList != (Object)null).ToList(); } SpawnSystem val = GetLiveSystems().FirstOrDefault(); if ((Object)(object)val == (Object)null) { return new List(); } return val.m_spawnLists.Where((SpawnSystemList spawnList) => (Object)(object)spawnList != (Object)null).ToList(); } private static SpawnSystem? GetZoneCtrlPrefabSpawnSystemCore() { if ((Object)(object)ZoneSystem.instance?.m_zoneCtrlPrefab == (Object)null) { return null; } return ZoneSystem.instance.m_zoneCtrlPrefab.GetComponent(); } private static SpawnSystemList CreateManagedSpawnListCore(List spawners) { SpawnSystemList obj = GetManagedSpawnListHost().AddComponent(); ((Object)obj).hideFlags = (HideFlags)61; obj.m_spawners = spawners ?? new List(); obj.m_biomeFolded = new List(); return obj; } private static SpawnSystemList CreateAttachedSpawnListCore(List spawners) { SpawnSystemList obj = GetAttachedSpawnListHost().AddComponent(); ((Object)obj).hideFlags = (HideFlags)61; obj.m_spawners = spawners ?? new List(); obj.m_biomeFolded = new List(); return obj; } private static GameObject GetManagedSpawnListHostCore() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown if ((Object)(object)_managedSpawnListHost != (Object)null) { return _managedSpawnListHost; } _managedSpawnListHost = new GameObject("DropNSpawn.SpawnSystemLists") { hideFlags = (HideFlags)61 }; Object.DontDestroyOnLoad((Object)(object)_managedSpawnListHost); if ((Object)(object)DropNSpawnPlugin.Instance != (Object)null) { _managedSpawnListHost.transform.SetParent(((Component)DropNSpawnPlugin.Instance).transform, false); } return _managedSpawnListHost; } private static GameObject GetAttachedSpawnListHostCore() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown if ((Object)(object)_attachedSpawnListHost != (Object)null) { return _attachedSpawnListHost; } _attachedSpawnListHost = new GameObject("DropNSpawn.SpawnSystemAttachedLists") { hideFlags = (HideFlags)61 }; Object.DontDestroyOnLoad((Object)(object)_attachedSpawnListHost); if ((Object)(object)DropNSpawnPlugin.Instance != (Object)null) { _attachedSpawnListHost.transform.SetParent(((Component)DropNSpawnPlugin.Instance).transform, false); } return _attachedSpawnListHost; } private static void ClearAttachedRuntimeStateCore(SpawnSystem? system) { if (!((Object)(object)system == (Object)null)) { ClearRuntimeMetadata(system); SpawnSystemCustomDataSupport.ClearCustomData(system); DestroyAttachedSpawnLists(system.m_spawnLists); } } private static void DestroyAttachedSpawnListsCore(IEnumerable? spawnLists) { if (spawnLists == null) { return; } foreach (SpawnSystemList spawnList in spawnLists) { if (!((Object)(object)spawnList == (Object)null) && (Object)(object)_attachedSpawnListHost != (Object)null && (Object)(object)((Component)spawnList).gameObject == (Object)(object)_attachedSpawnListHost) { Object.Destroy((Object)(object)spawnList); } } } private static void DestroyReplacedCompiledTableCore(CompiledSpawnSystemTable? table) { if (table == null || table == _activeCompiledTable || table == _vanillaCompiledTable) { return; } foreach (SpawnSystemList list in table.Lists) { if ((Object)(object)list != (Object)null) { Object.Destroy((Object)(object)list); } } table.Lists.Clear(); } private static bool TryCaptureSnapshotsIfNeeded() { List liveSystems = GetLiveSystems(); if (liveSystems.Count == 0 || (Object)(object)ZNetScene.instance == (Object)null || (Object)(object)ObjectDB.instance == (Object)null) { return false; } PruneSnapshots(liveSystems); foreach (SpawnSystem item in liveSystems) { CaptureSnapshotIfNeeded(item); } return SnapshotsBySystemId.Count > 0; } private static void RefreshSnapshots() { SnapshotsBySystemId.Clear(); _templateSnapshot = null; } private static void InvalidateRuntimeTimeOfDayPhaseMarker() { _lastRuntimeTimeOfDayPhaseMarker = null; _lastRuntimeTimeOfDayRefreshFrame = -1; } private static void PruneSnapshots(IEnumerable systems) { HashSet hashSet = (from system in systems where (Object)(object)system != (Object)null select ((Object)system).GetInstanceID()).ToHashSet(); if (SnapshotsBySystemId.Count == 0) { return; } List list = null; foreach (int key in SnapshotsBySystemId.Keys) { if (!hashSet.Contains(key)) { if (list == null) { list = new List(); } list.Add(key); } } if (list == null) { return; } foreach (int item in list) { SnapshotsBySystemId.Remove(item); } _templateSnapshot = null; } private static bool RefreshTemplateSnapshot() { if (SnapshotsBySystemId.Count > 0) { _templateSnapshot = CaptureTemplateSnapshot(SnapshotsBySystemId.Values); return _templateSnapshot != null; } List liveSystems = GetLiveSystems(); if (liveSystems.Count == 0 || (Object)(object)ZNetScene.instance == (Object)null || (Object)(object)ObjectDB.instance == (Object)null) { return false; } _templateSnapshot = CaptureTemplateSnapshot(liveSystems); return _templateSnapshot != null; } private static SpawnSystemSnapshot CaptureTemplateSnapshot(IEnumerable systems) { return CaptureTemplateSnapshot((from system in systems where (Object)(object)system != (Object)null orderby ((Object)system).GetInstanceID() select system).Select(CaptureSnapshot).ToList()); } private static SpawnSystemSnapshot CaptureTemplateSnapshot(IEnumerable snapshots) { List list = (from snapshot in snapshots where snapshot != null orderby snapshot.SystemId select snapshot).ToList(); if (list.Count == 0) { return new SpawnSystemSnapshot(); } SpawnSystemSnapshot spawnSystemSnapshot = new SpawnSystemSnapshot { SystemId = 0, ListCount = 1 }; Dictionary dictionary = new Dictionary(StringComparer.Ordinal); foreach (SpawnSystemSnapshot item in list) { Dictionary dictionary2 = new Dictionary(StringComparer.Ordinal); foreach (SpawnSystemEntrySnapshot item2 in item.Entries.OrderBy((SpawnSystemEntrySnapshot current) => current, Comparer.Create(CompareSpawnSystemEntriesForOutput))) { string stableReferenceSortKey = GetStableReferenceSortKey(item2); if (dictionary2.TryGetValue(stableReferenceSortKey, out var value)) { dictionary2[stableReferenceSortKey] = (value.Item1, value.Item2 + 1); } else { dictionary2[stableReferenceSortKey] = (item2, 1); } } foreach (var (key, tuple2) in dictionary2) { if (dictionary.TryGetValue(key, out var value2)) { dictionary[key] = (value2.Item1, Math.Max(value2.Item2, tuple2.Item2)); } else { dictionary[key] = (tuple2.Item1, tuple2.Item2); } } } List list2 = dictionary.Values.OrderBy<(SpawnSystemEntrySnapshot, int), SpawnSystemEntrySnapshot>(((SpawnSystemEntrySnapshot Representative, int MaxCount) entry) => entry.Representative, Comparer.Create(CompareSpawnSystemEntriesForOutput)).SelectMany<(SpawnSystemEntrySnapshot, int), SpawnSystemEntrySnapshot>(((SpawnSystemEntrySnapshot Representative, int MaxCount) entry) => from _ in Enumerable.Range(0, entry.MaxCount) select entry.Representative).ToList(); int num = 0; foreach (SpawnSystemEntrySnapshot item3 in list2) { spawnSystemSnapshot.Entries.Add(new SpawnSystemEntrySnapshot { ListIndex = 0, EntryIndex = num++, Data = item3.Data.Clone() }); } AssignReferenceIds(spawnSystemSnapshot); return spawnSystemSnapshot; } private static void AssignReferenceIds(SpawnSystemSnapshot snapshot) { Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); PrefabOwnerResolver.OwnerSnapshot snapshot2 = PrefabOwnerResolver.GetSnapshot(); foreach (SpawnSystemEntrySnapshot item in from current in snapshot.Entries orderby current.ListIndex, current.EntryIndex select current) { string text = NormalizeReferencePrefabName(item.Data.m_prefab) ?? "entry"; string ownerName = snapshot2.GetOwnerName(text); string key = ownerName + "|" + text; int value; int ordinal = (dictionary[key] = ((!dictionary.TryGetValue(key, out value)) ? 1 : (value + 1))); item.RefId = BuildReferenceId(ownerName, text, ordinal); } } private static string BuildReferenceId(string ownerName, string prefabName, int ordinal) { return "spawn_" + NormalizeRefIdToken(ownerName) + "_" + NormalizeRefIdToken(prefabName) + "_" + ordinal.ToString("000", CultureInfo.InvariantCulture); } private static string NormalizeRefIdToken(string? value) { StringBuilder stringBuilder = new StringBuilder(); bool flag = false; string text = (value ?? "").Trim().ToLowerInvariant(); foreach (char c in text) { if (char.IsLetterOrDigit(c)) { stringBuilder.Append(c); flag = false; } else if (!(stringBuilder.Length == 0 || flag)) { stringBuilder.Append('_'); flag = true; } } string text2 = stringBuilder.ToString().Trim('_'); if (text2.Length != 0) { return text2; } return "entry"; } private static SpawnSystemSnapshot CaptureSnapshotIfNeeded(SpawnSystem system) { int instanceID = ((Object)system).GetInstanceID(); if (SnapshotsBySystemId.TryGetValue(instanceID, out SpawnSystemSnapshot value)) { return value; } value = CaptureSnapshot(system); SnapshotsBySystemId[instanceID] = value; _templateSnapshot = null; return value; } private static SpawnSystemSnapshot CaptureSnapshot(SpawnSystem system) { SpawnSystemSnapshot spawnSystemSnapshot = new SpawnSystemSnapshot { SystemId = ((Object)system).GetInstanceID(), ListCount = Math.Max(1, system.m_spawnLists.Count) }; for (int i = 0; i < system.m_spawnLists.Count; i++) { SpawnSystemList val = system.m_spawnLists[i]; for (int j = 0; j < val.m_spawners.Count; j++) { SpawnData val2 = val.m_spawners[j]; SpawnSystemEntrySnapshot item = new SpawnSystemEntrySnapshot { ListIndex = i, EntryIndex = j, Data = val2.Clone() }; spawnSystemSnapshot.Entries.Add(item); } } AssignReferenceIds(spawnSystemSnapshot); return spawnSystemSnapshot; } private static List GetLiveSystems() { EnsureLiveSystemRegistrySessionLocked(); EnsureLiveSystemsBootstrappedLocked(); PruneTrackedLiveSystemsLocked(); if (!_liveSystemsSnapshotDirty) { return LiveSystemsSnapshot; } LiveSystemsSnapshot.Clear(); foreach (SpawnSystem value in LiveSystemsById.Values) { if ((Object)(object)value != (Object)null) { LiveSystemsSnapshot.Add(value); } } LiveSystemsSnapshot.Sort((SpawnSystem left, SpawnSystem right) => ((Object)left).GetInstanceID().CompareTo(((Object)right).GetInstanceID())); _liveSystemsSnapshotDirty = false; return LiveSystemsSnapshot; } private static void EnsureLiveSystemsBootstrappedLocked() { if (_liveSystemsBootstrapAttempted || LiveSystemsById.Count > 0) { return; } _liveSystemsBootstrapAttempted = true; if (SpawnSystemInstancesField?.GetValue(null) is List list) { foreach (SpawnSystem item in list) { TrackLiveSystemLocked(item); } if (LiveSystemsById.Count > 0) { return; } } SpawnSystem[] array = Object.FindObjectsByType((FindObjectsSortMode)0); for (int i = 0; i < array.Length; i++) { TrackLiveSystemLocked(array[i]); } } private static void PruneTrackedLiveSystemsLocked() { if (LiveSystemsById.Count == 0) { return; } List list = null; foreach (var (item, val2) in LiveSystemsById) { if (!((Object)(object)val2 != (Object)null)) { if (list == null) { list = new List(); } list.Add(item); } } if (list == null) { return; } foreach (int item2 in list) { LiveSystemsById.Remove(item2); SnapshotsBySystemId.Remove(item2); PendingLiveSystemAttachIds.Remove(item2); PendingLiveSystemAttachEspRefreshIds.Remove(item2); EspSpawnSystemCompatibility.RemovePendingRefresh(item2); PreAttachedSpawnSystemIds.Remove(item2); MarkSystemMigratedFromRetiredTablesLocked(item2); } _liveSystemsSnapshotDirty = true; _templateSnapshot = null; } private static SpawnSystemSnapshot? GetTemplateSnapshot() { if (_templateSnapshot == null) { RefreshTemplateSnapshot(); } return _templateSnapshot; } private static SpawnSystemSnapshot? GetCachedTemplateSnapshot() { if (_templateSnapshot != null) { return _templateSnapshot; } if (SnapshotsBySystemId.Count == 0) { return null; } _templateSnapshot = CaptureTemplateSnapshot(SnapshotsBySystemId.Values); return _templateSnapshot; } private static List BuildPreparedEntriesCore() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown if (IsPreparedEntriesCacheValid()) { return _preparedEntriesCache; } List list = new List(); for (int i = 0; i < _configuration.Count; i++) { CanonicalSpawnSystemEntry entry = _configuration[i]; SpawnData val = new SpawnData(); string context = CreateConfigurationContext(i, entry); if (ApplyEntry(val, entry, context, applyCustomData: false)) { list.Add(new PreparedSpawnSystemEntry { Entry = entry, Data = val, Context = context, CustomDataPayload = SpawnSystemCustomDataSupport.BuildPreparedPayload(val, entry, context), RuntimeTimeOfDay = GetConfiguredTimeOfDay(entry) }); } } _preparedEntriesCache = list; return _preparedEntriesCache; } private static void InvalidatePreparedEntriesCacheCore() { _preparedEntriesCache = null; } private static string ComputePreparedEntriesSignatureCore(List entries) { return NetworkPayloadSyncSupport.ComputeSpawnSystemProjectedConfigurationSignature(entries, (PreparedSpawnSystemEntry entry) => entry.Entry); } private static ReferenceCatalogSnapshot BuildCurrentReferenceCatalogSnapshot() { SpawnSystemSnapshot cachedTemplateSnapshot = GetCachedTemplateSnapshot(); if (cachedTemplateSnapshot != null && cachedTemplateSnapshot.Entries.Count > 0) { return BuildReferenceCatalogSnapshotFromTemplateSnapshot(cachedTemplateSnapshot); } return BuildReferenceCatalogSnapshot(GetLiveSystems()); } private static ReferenceCatalogSnapshot BuildReferenceCatalogSnapshotFromTemplateSnapshot(SpawnSystemSnapshot snapshot) { ReferenceCatalogSnapshot referenceCatalogSnapshot = new ReferenceCatalogSnapshot(); List collection = MergeUniqueReferenceEntriesWithExternalProjections(BuildTemplateReferenceEntries(snapshot), forceRefresh: true); referenceCatalogSnapshot.LiveEntries.AddRange(collection); referenceCatalogSnapshot.LiveEntries.Sort(CompareReferenceEntriesForOutput); string value = SerializeReferenceEntries(referenceCatalogSnapshot.LiveEntries); referenceCatalogSnapshot.SourceSignature = ReferenceRefreshSupport.ComputeStableHash(value); return referenceCatalogSnapshot; } private static string BuildReferenceConfigurationTemplate(ReferenceCatalogSnapshot? referenceCatalogSnapshot = null) { if (referenceCatalogSnapshot == null) { referenceCatalogSnapshot = BuildReferenceCatalogSnapshot(); } return SerializeReferenceEntries(referenceCatalogSnapshot.LiveEntries); } private static string SerializeReferenceEntries(IEnumerable entries) { StringBuilder stringBuilder = new StringBuilder(); bool flag = false; foreach (PrefabOwnerSection item in BuildBiomeOrderedReferenceSections(entries ?? Enumerable.Empty())) { if (item.Entries.Count == 0) { continue; } if (flag) { stringBuilder.AppendLine(); } PrefabOutputSections.AppendSectionHeaderComment(stringBuilder, item.OwnerName); foreach (CanonicalSpawnSystemEntry entry in item.Entries) { AppendReferenceEntry(stringBuilder, entry); flag = true; } } if (!flag) { return "[]" + Environment.NewLine; } return stringBuilder.ToString(); } private static void WriteReferenceConfigurationFile(string content, string logMessage) { Directory.CreateDirectory(DropNSpawnPlugin.YamlConfigDirectoryPath); if (GeneratedFileWriter.WriteAllTextIfChanged(ReferenceConfigurationPath, content)) { DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)logMessage); } } private static CreatureManagerSpawnReferenceSupport.ReferenceSnapshot? TryGetExternalReferenceProjectionSnapshot(bool forceRefresh) { try { return CreatureManagerSpawnReferenceSupport.GetReferenceSnapshot(forceRefresh); } catch (Exception arg) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)$"Failed to collect external spawnsystem reference projections. {arg}"); return null; } } private static List GetExternalReferenceProjectionEntries(bool forceRefresh) { return (from projection in TryGetExternalReferenceProjectionSnapshot(forceRefresh)?.Projections select projection.Entry into entry where entry != null && !string.IsNullOrWhiteSpace(entry.Prefab) select entry).ToList() ?? new List(); } private static List MergeUniqueReferenceEntriesWithExternalProjections(IEnumerable entries, bool forceRefresh) { List list = entries?.ToList() ?? new List(); HashSet hashSet = new HashSet(list.Select(GetStableReferenceSortKey), StringComparer.Ordinal); foreach (CanonicalSpawnSystemEntry externalReferenceProjectionEntry in GetExternalReferenceProjectionEntries(forceRefresh)) { if (hashSet.Add(GetStableReferenceSortKey(externalReferenceProjectionEntry))) { list.Add(externalReferenceProjectionEntry); } } return list; } private static List MergeScaffoldEntriesWithExternalProjections(IEnumerable entries, bool forceRefresh) { List list = entries?.ToList() ?? new List(); Dictionary dictionary = new Dictionary(StringComparer.Ordinal); foreach (CanonicalSpawnSystemEntry item in list) { string stableReferenceSortKey = GetStableReferenceSortKey(item); dictionary[stableReferenceSortKey] = ((!dictionary.TryGetValue(stableReferenceSortKey, out var value)) ? 1 : (value + 1)); } foreach (CanonicalSpawnSystemEntry externalReferenceProjectionEntry in GetExternalReferenceProjectionEntries(forceRefresh)) { string stableReferenceSortKey2 = GetStableReferenceSortKey(externalReferenceProjectionEntry); if (dictionary.TryGetValue(stableReferenceSortKey2, out var value2) && value2 > 0) { dictionary[stableReferenceSortKey2] = value2 - 1; } else { list.Add(externalReferenceProjectionEntry); } } return list; } private static List BuildTemplateReferenceEntries(SpawnSystemSnapshot snapshot) { List list = new List(); foreach (PrefabOwnerSection item in BuildBiomeOrderedSnapshotSections(snapshot)) { foreach (SpawnSystemEntrySnapshot entry in item.Entries) { CanonicalSpawnSystemEntry canonicalSpawnSystemEntry = ConvertToReferenceEntry(entry); canonicalSpawnSystemEntry.ReferenceOwnerName = item.OwnerName; list.Add(canonicalSpawnSystemEntry); } } return list; } private static List BuildTemplateFullScaffoldEntries(SpawnSystemSnapshot snapshot) { List list = new List(); foreach (PrefabOwnerSection item in BuildBiomeOrderedSnapshotSections(snapshot)) { foreach (SpawnSystemEntrySnapshot entry in item.Entries) { CanonicalSpawnSystemEntry canonicalSpawnSystemEntry = ConvertToConfigurationEntry(entry); canonicalSpawnSystemEntry.ReferenceOwnerName = item.OwnerName; list.Add(canonicalSpawnSystemEntry); } } return list; } private static ReferenceCatalogSnapshot BuildReferenceCatalogSnapshot(List? systems = null) { ReferenceCatalogSnapshot referenceCatalogSnapshot = new ReferenceCatalogSnapshot(); HashSet hashSet = new HashSet(StringComparer.Ordinal); foreach (SpawnData item in EnumerateReferenceLiveSpawnData(systems)) { CanonicalSpawnSystemEntry canonicalSpawnSystemEntry = ConvertToReferenceEntry(item); string stableReferenceSortKey = GetStableReferenceSortKey(canonicalSpawnSystemEntry); if (hashSet.Add(stableReferenceSortKey)) { referenceCatalogSnapshot.LiveEntries.Add(canonicalSpawnSystemEntry); } } List collection = MergeUniqueReferenceEntriesWithExternalProjections(referenceCatalogSnapshot.LiveEntries, forceRefresh: true); referenceCatalogSnapshot.LiveEntries.Clear(); referenceCatalogSnapshot.LiveEntries.AddRange(collection); referenceCatalogSnapshot.LiveEntries.Sort(CompareReferenceEntriesForOutput); string value = SerializeReferenceEntries(referenceCatalogSnapshot.LiveEntries); referenceCatalogSnapshot.SourceSignature = ReferenceRefreshSupport.ComputeStableHash(value); return referenceCatalogSnapshot; } private static IEnumerable EnumerateReferenceLiveSpawnData(List? systems = null) { if (TryEnumerateReferenceLiveSpawnData(GetSelectedCompiledTableForCurrentState()?.Lists, out IEnumerable spawnData2)) { return spawnData2; } SpawnSystemSnapshot cachedTemplateSnapshot = GetCachedTemplateSnapshot(); if (cachedTemplateSnapshot != null && cachedTemplateSnapshot.Entries.Count > 0) { return from entry in cachedTemplateSnapshot.Entries where entry?.Data != null select entry.Data; } if (systems == null) { systems = GetLiveSystems(); } return from spawnData in (from spawnList in (from current in systems where (Object)(object)current != (Object)null orderby ((Object)current).GetInstanceID() select current).SelectMany((SpawnSystem system) => system.m_spawnLists ?? new List()) where (Object)(object)spawnList != (Object)null select spawnList).SelectMany((SpawnSystemList spawnList) => spawnList.m_spawners ?? new List()) where spawnData != null select spawnData; } private static string BuildFullScaffoldConfigurationTemplate() { SpawnSystemSnapshot templateSnapshot = GetTemplateSnapshot(); if (templateSnapshot == null) { return ""; } StringBuilder stringBuilder = new StringBuilder(); bool flag = false; foreach (PrefabOwnerSection item in BuildBiomeOrderedReferenceSections(MergeScaffoldEntriesWithExternalProjections(BuildTemplateFullScaffoldEntries(templateSnapshot), forceRefresh: true))) { foreach (CanonicalSpawnSystemEntry entry in item.Entries) { if (flag) { stringBuilder.AppendLine(); } AppendConfigurationEntry(stringBuilder, entry); flag = true; } } if (!flag) { return "[]" + Environment.NewLine; } return stringBuilder.ToString(); } [IteratorStateMachine(typeof(d__402))] private static IEnumerable GetSpawnSystemShorthandFieldExampleLines() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__402(-2); } private static string BuildPrimaryOverrideConfigurationTemplate() { SpawnSystemSnapshot templateSnapshot = GetTemplateSnapshot(); if (templateSnapshot == null) { return "[]" + Environment.NewLine; } return BuildCompressedPrimaryOverrideConfigurationDocument(templateSnapshot); } private static string BuildCompressedPrimaryOverrideConfigurationDocument(SpawnSystemSnapshot snapshot) { StringBuilder stringBuilder = new StringBuilder(); AppendTemplateComment(stringBuilder, "This file is auto-loaded from " + Path.GetFileName(PrimaryOverrideConfigurationPathYml) + " or " + Path.GetFileName(PrimaryOverrideConfigurationPathYaml) + ", plus any " + PluginSettingsFacade.GetYamlDomainSupplementalPrefix("spawnsystem") + "*.yml/.yaml files."); AppendTemplateComment(stringBuilder, "Loaded files are concatenated in filename order after the primary file."); AppendTemplateComment(stringBuilder, "This auto-created override is seeded from the current live SpawnSystem snapshot only and does not merge external CreatureManager/Jotunn reference projections."); AppendTemplateComment(stringBuilder, "Use dns:reference spawnsystem when you want to export " + PluginSettingsFacade.GetYamlDomainFilePrefix("spawnsystem") + ".reference.yml for a compact reference snapshot, or " + PluginSettingsFacade.GetYamlDomainFilePrefix("spawnsystem") + ".full.yml for exhaustive field examples."); AppendTemplateComment(stringBuilder, "Applying this file still strictly replaces the live SpawnSystem table with the rows defined here."); AppendTemplateComment(stringBuilder, "requiredGlobalKey also supports 'key 10' to require at least that numeric value and consume it after each successful spawn."); foreach (string spawnSystemShorthandFieldExampleLine in GetSpawnSystemShorthandFieldExampleLines()) { AppendTemplateComment(stringBuilder, spawnSystemShorthandFieldExampleLine); } AppendTemplateBlankLine(stringBuilder); bool flag = false; foreach (PrefabOwnerSection item in BuildBiomeOrderedReferenceSections(BuildTemplateReferenceEntries(snapshot))) { if (item.Entries.Count == 0) { continue; } if (flag) { stringBuilder.AppendLine(); } foreach (CanonicalSpawnSystemEntry entry in item.Entries) { AppendReferenceEntry(stringBuilder, entry); stringBuilder.AppendLine(); } flag = true; } if (!flag) { return "[]" + Environment.NewLine; } return stringBuilder.ToString(); } private static string BuildAuthoritativeConfigurationDocument(SpawnSystemSnapshot snapshot, bool autoLoaded) { StringBuilder stringBuilder = new StringBuilder(); if (autoLoaded) { AppendTemplateComment(stringBuilder, "Authoritative strict full-replace SpawnSystem configuration."); AppendTemplateComment(stringBuilder, "reference = lookup snapshot, override = loaded file that changes live game data, full = exhaustive generated example file."); AppendTemplateComment(stringBuilder, "This file is auto-loaded from " + Path.GetFileName(PrimaryOverrideConfigurationPathYml) + " or " + Path.GetFileName(PrimaryOverrideConfigurationPathYaml) + ", plus any " + PluginSettingsFacade.GetYamlDomainSupplementalPrefix("spawnsystem") + "*.yml/.yaml files."); AppendTemplateComment(stringBuilder, "Loaded files are concatenated in filename order after the primary file."); } else { AppendTemplateComment(stringBuilder, "Generated by dns:full spawnsystem."); AppendTemplateComment(stringBuilder, "reference = lookup snapshot, override = loaded file that changes live game data, full = exhaustive generated example file."); AppendTemplateComment(stringBuilder, "This file is not auto-loaded. Replace " + Path.GetFileName(PrimaryOverrideConfigurationPathYml) + " or split its rows into " + PluginSettingsFacade.GetYamlDomainSupplementalPrefix("spawnsystem") + "*.yml/.yaml files if you want to adopt this table."); } AppendTemplateComment(stringBuilder, "Entries are grouped by owning mod and then biome priority (Meadows -> BlackForest -> Swamp -> Ocean -> Mountain -> Plains -> Mistlands -> AshLands -> DeepNorth)."); AppendTemplateComment(stringBuilder, "Rows with multiple biomes are grouped under their highest biome and listed near the top of that biome block."); AppendTemplateComment(stringBuilder, "Applying this file strictly replaces the live SpawnSystem table with the rows defined here."); AppendTemplateComment(stringBuilder, "enabled controls the native SpawnSystem enabled flag on that row. Delete a row from this file to remove it from the final authoritative table."); AppendTemplateComment(stringBuilder, "Rows use grouped blocks: spawnSystem = native spawn rule, conditions = selectors and limits, modifiers = post-spawn effects."); AppendTemplateComment(stringBuilder, "conditions.biomes also accepts Expand World Data custom biome names and numeric biome masks when Expand World Data is installed."); AppendTemplateComment(stringBuilder, "timeOfDay uses list syntax such as [day], [afternoon], [night], or [day, night]."); AppendTemplateComment(stringBuilder, "requiredGlobalKey also supports 'key 10' to require at least that numeric value and consume it after each successful spawn."); AppendTemplateComment(stringBuilder, "modifiers.data, modifiers.faction, modifiers.fields, and modifiers.objects require Expand World Data. modifiers.data references an Expand World Data data entry name."); AppendTemplateComment(stringBuilder, "objects entries use the upstream format Prefab,posX,posZ,posY,chance,data."); AppendTemplateBlankLine(stringBuilder); foreach (PrefabOwnerSection item in BuildBiomeOrderedSnapshotSections(snapshot)) { PrefabOutputSections.AppendSectionHeaderComment(stringBuilder, item.OwnerName); foreach (SpawnSystemEntrySnapshot entry2 in item.Entries) { CanonicalSpawnSystemEntry entry = ConvertToConfigurationEntry(entry2); AppendConfigurationEntry(stringBuilder, entry); stringBuilder.AppendLine(); } } return stringBuilder.ToString(); } } internal static class SceneTraversalSupport { internal static void VisitActiveLoadedSceneGameObjects(Action visitor) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) Action visitor2 = visitor; if (visitor2 == null) { return; } List pendingTransforms = new List(); int sceneCount = SceneManager.sceneCount; for (int i = 0; i < sceneCount; i++) { Scene sceneAt = SceneManager.GetSceneAt(i); if (!((Scene)(ref sceneAt)).isLoaded) { continue; } GameObject[] rootGameObjects = ((Scene)(ref sceneAt)).GetRootGameObjects(); foreach (GameObject val in rootGameObjects) { if ((Object)(object)val == (Object)null || !val.activeInHierarchy) { continue; } TraverseHierarchy(val.transform, delegate(Transform transform) { GameObject gameObject = ((Component)transform).gameObject; if ((Object)(object)gameObject != (Object)null && gameObject.activeInHierarchy) { visitor2(gameObject); } }, pendingTransforms); } } } internal static void TraverseHierarchy(Transform? root, Action visitor) { TraverseHierarchy(root, visitor, new List()); } private static void TraverseHierarchy(Transform? root, Action visitor, List pendingTransforms) { if ((Object)(object)root == (Object)null || visitor == null) { return; } pendingTransforms.Clear(); pendingTransforms.Add(root); while (pendingTransforms.Count > 0) { int index = pendingTransforms.Count - 1; Transform val = pendingTransforms[index]; pendingTransforms.RemoveAt(index); if ((Object)(object)val == (Object)null) { continue; } visitor(val); for (int i = 0; i < val.childCount; i++) { Transform child = val.GetChild(i); if ((Object)(object)child != (Object)null) { pendingTransforms.Add(child); } } } } } internal sealed class SpawnerConfigurationEntry { [YamlMember(Order = 1)] public string Prefab { get; set; } = ""; [YamlMember(Order = 2)] public bool Enabled { get; set; } = true; [YamlMember(Order = 3)] public string? Location { get; set; } [YamlMember(Order = 4)] public ConditionsDefinition? Conditions { get; set; } [YamlMember(Order = 5)] public SpawnAreaDefinition? SpawnArea { get; set; } [YamlMember(Order = 6)] public CreatureSpawnerDefinition? CreatureSpawner { get; set; } [YamlIgnore] public string RuleId { get; set; } = ""; [YamlIgnore] public string? SourcePath { get; set; } [YamlIgnore] public int SourceLine { get; set; } [YamlIgnore] public int SourceColumn { get; set; } } internal sealed class SpawnerReferenceEntry { [YamlMember(Order = 1)] public string Prefab { get; set; } = ""; [YamlMember(Order = 2)] public SpawnAreaDefinition? SpawnArea { get; set; } [YamlMember(Order = 3)] public CreatureSpawnerDefinition? CreatureSpawner { get; set; } } internal sealed class SpawnerLocationReferenceEntry { [YamlMember(Order = 1)] public string Prefab { get; set; } = ""; [YamlMember(Order = 2)] public List Locations { get; set; } = new List(); } internal sealed class SpawnAreaDefinition { [YamlMember(Order = 1)] public float? LevelUpChance { get; set; } [YamlMember(Order = 2)] public float? SpawnInterval { get; set; } [YamlMember(Order = 3)] public float? TriggerDistance { get; set; } [YamlMember(Order = 4)] public bool? SetPatrolSpawnPoint { get; set; } [YamlMember(Order = 5)] public float? SpawnRadius { get; set; } [YamlMember(Order = 6)] public float? NearRadius { get; set; } [YamlMember(Order = 7)] public float? FarRadius { get; set; } [YamlMember(Order = 8)] public int? MaxNear { get; set; } [YamlMember(Order = 9)] public int? MaxTotal { get; set; } [YamlMember(Order = 10)] public int? MaxTotalSpawns { get; set; } [YamlMember(Order = 11)] public bool? OnGroundOnly { get; set; } [YamlMember(Order = 12)] public List? Creatures { get; set; } } internal sealed class SpawnAreaSpawnDefinition { [YamlMember(Order = 1)] public string Creature { get; set; } = ""; [YamlMember(Order = 2)] public float? Weight { get; set; } [YamlMember(Order = 3)] public IntRangeDefinition? Level { get; set; } [YamlIgnore] public int? MinLevel { get; set; } [YamlIgnore] public int? MaxLevel { get; set; } [YamlMember(Order = 4)] public string? Faction { get; set; } [YamlMember(Order = 5)] public string? Data { get; set; } [YamlMember(Order = 6)] public Dictionary? Fields { get; set; } [YamlMember(Order = 7)] public List? Objects { get; set; } } internal sealed class CreatureSpawnerDefinition { [YamlMember(Order = 1)] public string? Creature { get; set; } [YamlMember(Order = 2)] public TimeOfDayDefinition? TimeOfDay { get; set; } [YamlMember(Order = 3)] public string? RequiredGlobalKey { get; set; } [YamlMember(Order = 4)] public string? BlockingGlobalKey { get; set; } [YamlMember(Order = 5)] public IntRangeDefinition? Level { get; set; } [YamlIgnore] public int? MinLevel { get; set; } [YamlIgnore] public int? MaxLevel { get; set; } [YamlMember(Order = 6)] public float? LevelUpChance { get; set; } [YamlMember(Order = 7)] public float? RespawnTimeMinutes { get; set; } [YamlMember(Order = 8)] public int? SpawnCheckInterval { get; set; } [YamlMember(Order = 9)] public int? SpawnGroupId { get; set; } [YamlMember(Order = 10)] public float? SpawnGroupRadius { get; set; } [YamlMember(Order = 11)] public float? SpawnerWeight { get; set; } [YamlMember(Order = 12)] public int? MaxGroupSpawned { get; set; } [YamlMember(Order = 13)] public float? TriggerDistance { get; set; } [YamlMember(Order = 14)] public float? TriggerNoise { get; set; } [YamlMember(Order = 15)] public bool? RequireSpawnArea { get; set; } [YamlMember(Order = 16)] public bool? AllowInsidePlayerBase { get; set; } [YamlMember(Order = 17)] public bool? WakeUpAnimation { get; set; } [YamlMember(Order = 18)] public bool? SetPatrolSpawnPoint { get; set; } [YamlMember(Order = 19)] public string? Faction { get; set; } [YamlMember(Order = 20)] public string? Data { get; set; } [YamlMember(Order = 21)] public Dictionary? Fields { get; set; } [YamlMember(Order = 22)] public List? Objects { get; set; } } internal static class SpawnerManager { private sealed class ParsedSpawnerConfigurationDocument { public List Configuration { get; } = new List(); public List Warnings { get; } = new List(); } private readonly struct InvalidEntryWarningSuppressionScope : IDisposable { private readonly bool _active; public InvalidEntryWarningSuppressionScope(bool active) { _active = active; if (_active) { _invalidEntryWarningSuppressionDepth++; } } public void Dispose() { if (_active) { _invalidEntryWarningSuppressionDepth--; } } } private readonly struct PendingSpawnAreaReconcile { public SpawnArea SpawnArea { get; } public int InstanceId { get; } public int Epoch { get; } public PendingSpawnAreaReconcile(SpawnArea spawnArea, int instanceId, int epoch) { SpawnArea = spawnArea; InstanceId = instanceId; Epoch = epoch; } } private readonly struct PendingCreatureSpawnerReconcile { public CreatureSpawner CreatureSpawner { get; } public int InstanceId { get; } public int Epoch { get; } public PendingCreatureSpawnerReconcile(CreatureSpawner creatureSpawner, int instanceId, int epoch) { CreatureSpawner = creatureSpawner; InstanceId = instanceId; Epoch = epoch; } } private sealed class MatchingEntryCache { private readonly List _entries = new List(); private readonly List _runtimeEntries = new List(); private readonly List _runtimeRequiredGlobalKeys = new List(); private readonly List _runtimeForbiddenGlobalKeys = new List(); public string ConfigPrefabName { get; set; } = ""; public string ResolvedLocationKey { get; set; } = ""; public bool UsesLocationSelector { get; set; } public bool HasRecordedLocationProvenanceEpoch { get; set; } public int RecordedLocationProvenanceEpoch { get; set; } public SharedMatchingEntryTemplate? SharedTemplate { get; private set; } public IReadOnlyList Entries => SharedTemplate?.Entries ?? _entries; public IReadOnlyList RuntimeEntries => SharedTemplate?.RuntimeEntries ?? _runtimeEntries; public Dictionary WinningEntriesByRuntimeSignature { get; } = new Dictionary(); public IReadOnlyList RuntimeRequiredGlobalKeys => SharedTemplate?.RuntimeRequiredGlobalKeys ?? _runtimeRequiredGlobalKeys; public IReadOnlyList RuntimeForbiddenGlobalKeys => SharedTemplate?.RuntimeForbiddenGlobalKeys ?? _runtimeForbiddenGlobalKeys; public bool UsesTimeOfDay { get; set; } public bool UsesRequiredEnvironments { get; set; } public bool UsesInsidePlayerBase { get; set; } internal List MutableEntries => _entries; internal List MutableRuntimeEntries => _runtimeEntries; internal List MutableRuntimeRequiredGlobalKeys => _runtimeRequiredGlobalKeys; internal List MutableRuntimeForbiddenGlobalKeys => _runtimeForbiddenGlobalKeys; public void UseSharedTemplate(SharedMatchingEntryTemplate template) { SharedTemplate = template; ConfigPrefabName = template.ConfigPrefabName; ResolvedLocationKey = template.ResolvedLocationKey; UsesLocationSelector = template.UsesLocationSelector; UsesTimeOfDay = template.UsesTimeOfDay; UsesRequiredEnvironments = template.UsesRequiredEnvironments; UsesInsidePlayerBase = template.UsesInsidePlayerBase; _entries.Clear(); _runtimeEntries.Clear(); _runtimeRequiredGlobalKeys.Clear(); _runtimeForbiddenGlobalKeys.Clear(); } } private sealed class SharedMatchingEntryTemplate { public string ConfigPrefabName { get; set; } = ""; public string ResolvedLocationKey { get; set; } = ""; public bool UsesLocationSelector { get; set; } public List Entries { get; } = new List(); public List RuntimeEntries { get; } = new List(); public List RuntimeRequiredGlobalKeys { get; } = new List(); public List RuntimeForbiddenGlobalKeys { get; } = new List(); public bool UsesTimeOfDay { get; set; } public bool UsesRequiredEnvironments { get; set; } public bool UsesInsidePlayerBase { get; set; } } private sealed class RuntimeContextSnapshot { public int Frame { get; set; } public int TimeOfDayPhaseMarker { get; set; } public string EnvironmentName { get; set; } = ""; public Dictionary GlobalKeyStates { get; } = new Dictionary(StringComparer.OrdinalIgnoreCase); } private sealed class LocalRuntimeState { public float LastInsidePlayerBaseSampleTime { get; set; } = float.NegativeInfinity; public float NextRuntimeEvaluationTime { get; set; } = float.NegativeInfinity; public bool IsInsidePlayerBase { get; set; } public int LastObservedTimeOfDayPhaseMarker { get; set; } = int.MinValue; public string LastObservedEnvironmentName { get; set; } = ""; public bool HasAppliedWinningEntrySelection { get; set; } public string LastAppliedConfigPrefabName { get; set; } = ""; public string LastAppliedResolvedLocationKey { get; set; } = ""; public string LastAppliedWinningEntryRuleId { get; set; } = ""; } private sealed class SpawnAreaResolvedSpawnEntry { public SpawnData SpawnData { get; set; } public SpawnAreaSpawnDefinition Definition { get; set; } public ExpandWorldSpawnDataPayload? DataPayload { get; set; } } private sealed class SpawnAreaSpawnSnapshot { public GameObject? Prefab { get; set; } public float Weight { get; set; } public int MinLevel { get; set; } public int MaxLevel { get; set; } } private sealed class SpawnAreaComponentSnapshot { public SpawnArea Component { get; set; } public string ConfigPrefabName { get; set; } = ""; public string RootPrefabName { get; set; } = ""; public string RelativePath { get; set; } = ""; public float LevelUpChance { get; set; } public float SpawnInterval { get; set; } public float TriggerDistance { get; set; } public bool SetPatrolSpawnPoint { get; set; } public float SpawnRadius { get; set; } public float NearRadius { get; set; } public float FarRadius { get; set; } public int MaxNear { get; set; } public int MaxTotal { get; set; } public bool OnGroundOnly { get; set; } public List Prefabs { get; set; } = new List(); } private sealed class SpawnAreaLiveSnapshot { public float LevelUpChance { get; set; } public float SpawnInterval { get; set; } public float TriggerDistance { get; set; } public bool SetPatrolSpawnPoint { get; set; } public float SpawnRadius { get; set; } public float NearRadius { get; set; } public float FarRadius { get; set; } public int MaxNear { get; set; } public int MaxTotal { get; set; } public bool OnGroundOnly { get; set; } public List Prefabs { get; set; } = new List(); } private sealed class CreatureSpawnerComponentSnapshot { public CreatureSpawner Component { get; set; } public string ConfigPrefabName { get; set; } = ""; public string RootPrefabName { get; set; } = ""; public string RelativePath { get; set; } = ""; public GameObject? CreaturePrefab { get; set; } public int MinLevel { get; set; } public int MaxLevel { get; set; } public float LevelUpChance { get; set; } public float RespawnTimeMinutes { get; set; } public float TriggerDistance { get; set; } public float TriggerNoise { get; set; } public bool SpawnAtNight { get; set; } public bool SpawnAtDay { get; set; } public bool RequireSpawnArea { get; set; } public bool SpawnInPlayerBase { get; set; } public bool WakeUpAnimation { get; set; } public int SpawnCheckInterval { get; set; } public string RequiredGlobalKey { get; set; } = ""; public string BlockingGlobalKey { get; set; } = ""; public bool SetPatrolSpawnPoint { get; set; } public int SpawnGroupId { get; set; } public int MaxGroupSpawned { get; set; } public float SpawnGroupRadius { get; set; } public float SpawnerWeight { get; set; } } private sealed class CreatureSpawnerLiveSnapshot { public GameObject? CreaturePrefab { get; set; } public int MinLevel { get; set; } public int MaxLevel { get; set; } public float LevelUpChance { get; set; } public float RespawnTimeMinutes { get; set; } public float TriggerDistance { get; set; } public float TriggerNoise { get; set; } public bool SpawnAtNight { get; set; } public bool SpawnAtDay { get; set; } public bool RequireSpawnArea { get; set; } public bool SpawnInPlayerBase { get; set; } public bool WakeUpAnimation { get; set; } public int SpawnCheckInterval { get; set; } public string RequiredGlobalKey { get; set; } = ""; public string BlockingGlobalKey { get; set; } = ""; public bool SetPatrolSpawnPoint { get; set; } public int SpawnGroupId { get; set; } public int MaxGroupSpawned { get; set; } public float SpawnGroupRadius { get; set; } public float SpawnerWeight { get; set; } } private sealed class SyncedSpawnerConfigurationState { public List Configuration { get; set; } = new List(); public List ActiveEntries { get; } = new List(); public Dictionary> ActiveEntriesByPrefab { get; } = new Dictionary>(StringComparer.OrdinalIgnoreCase); public HashSet ConfiguredSpawnAreaPrefabs { get; } = new HashSet(StringComparer.OrdinalIgnoreCase); public HashSet ConfiguredCreatureSpawnerPrefabs { get; } = new HashSet(StringComparer.OrdinalIgnoreCase); public HashSet RuntimeConfiguredSpawnAreaPrefabs { get; } = new HashSet(StringComparer.OrdinalIgnoreCase); public HashSet RuntimeConfiguredCreatureSpawnerPrefabs { get; } = new HashSet(StringComparer.OrdinalIgnoreCase); public Dictionary EntrySignaturesByPrefab { get; set; } = new Dictionary(StringComparer.OrdinalIgnoreCase); public string ConfigurationSignature { get; set; } = ""; } private sealed class SpawnerRuntimeEntry { public string Prefab { get; set; } = ""; public string RuleId { get; set; } = ""; public string Location { get; set; } = ""; public ConditionsDefinition? Conditions { get; set; } public bool RuntimeReconcile { get; set; } public SpawnAreaDefinition? SpawnArea { get; set; } public CreatureSpawnerDefinition? CreatureSpawner { get; set; } } private sealed class CompiledSpawnerPrefabPlan { public List SpawnAreaEntries { get; } = new List(); public List DynamicSpawnAreaEntries { get; } = new List(); public List CreatureSpawnerEntries { get; } = new List(); public List DynamicCreatureSpawnerEntries { get; } = new List(); public HashSet SpawnAreaSelectorLocationKeys { get; } = new HashSet(StringComparer.OrdinalIgnoreCase); public HashSet CreatureSpawnerSelectorLocationKeys { get; } = new HashSet(StringComparer.OrdinalIgnoreCase); public bool HasUnscopedSpawnAreaEntries { get; set; } public bool HasUnscopedCreatureSpawnerEntries { get; set; } } private sealed class SpawnerRuntimeConfigurationSnapshot { public static SpawnerRuntimeConfigurationSnapshot Empty { get; } = new SpawnerRuntimeConfigurationSnapshot(); public Dictionary PlansByPrefab { get; } = new Dictionary(StringComparer.OrdinalIgnoreCase); public HashSet ConfiguredSpawnAreaPrefabs { get; } = new HashSet(StringComparer.OrdinalIgnoreCase); public HashSet ConfiguredCreatureSpawnerPrefabs { get; } = new HashSet(StringComparer.OrdinalIgnoreCase); public HashSet RuntimeConfiguredSpawnAreaPrefabs { get; } = new HashSet(StringComparer.OrdinalIgnoreCase); public HashSet RuntimeConfiguredCreatureSpawnerPrefabs { get; } = new HashSet(StringComparer.OrdinalIgnoreCase); } private sealed class SpawnAreaComponentCatalog { public string ConfigPrefabName { get; set; } = ""; public string RootPrefabName { get; set; } = ""; public string RelativePath { get; set; } = ""; } private sealed class CreatureSpawnerComponentCatalog { public string ConfigPrefabName { get; set; } = ""; public string RootPrefabName { get; set; } = ""; public string RelativePath { get; set; } = ""; } private sealed class SpawnerLocationProvenance { public int Epoch { get; set; } public string LocationPrefab { get; set; } = ""; public string RelativePath { get; set; } = ""; } private sealed class CurrentLocationSpawnContext { public string LocationPrefab { get; set; } = ""; } private sealed class SpawnerApplyOperations : IStandardBaselineDesiredStateOperations { public static SpawnerApplyOperations Instance { get; } = new SpawnerApplyOperations(); public string DomainKey => "spawner"; public BaselineDesiredStateCapabilities Capabilities => BaselineDesiredStateCapabilities.Validation | BaselineDesiredStateCapabilities.LiveBaseline | BaselineDesiredStateCapabilities.LiveApply; public void Validate(SpawnerDesiredState desiredState) { ValidateSpawnerDesiredState(desiredState); } public void RestoreStaticBaseline(SpawnerDesiredState desiredState) { RestoreSpawnerStaticBaseline(desiredState); } public void ApplyDesiredStateToStaticBaseline(SpawnerDesiredState desiredState) { ApplySpawnerDesiredStateToStaticBaseline(desiredState); } public void PrepareLiveBaseline(SpawnerDesiredState desiredState) { PrepareSpawnerLiveBaseline(desiredState); } public void ApplyDesiredStateToLive(SpawnerDesiredState desiredState) { ApplySpawnerDesiredStateToLive(desiredState); } public void Commit(SpawnerDesiredState desiredState) { RecordAppliedState(desiredState.GameDataSignature, desiredState.DomainEnabled, desiredState.CurrentEntrySignatures); } public void HandleFailure(SpawnerDesiredState desiredState, StandardApplyFailureContext failureContext) { if (failureContext.LiveStageFailed && desiredState.ReloadPrefabs.Count != 0) { ReapplyOrQueueRegisteredLiveObjects(desiredState.DomainEnabled, desiredState.ReloadPrefabs); } } } private sealed class SpawnerDesiredState { public StandardDomainApplyPlan ApplyPlan { get; set; } public int GameDataSignature { get; set; } public Dictionary CurrentEntrySignatures { get; set; } = EmptyEntrySignatures; public bool DomainEnabled { get; set; } public bool QueueLiveReconcile { get; set; } public HashSet AvailablePrefabs { get; set; } = new HashSet(StringComparer.OrdinalIgnoreCase); public HashSet ReloadPrefabs { get; set; } = new HashSet(StringComparer.OrdinalIgnoreCase); public SpawnerRuntimeConfigurationSnapshot RuntimeConfigurationSnapshot { get; set; } = SpawnerRuntimeConfigurationSnapshot.Empty; } private sealed class SpawnerLiveReconcilerState { private readonly HashSet _missingComponentWarnings = new HashSet(StringComparer.OrdinalIgnoreCase); private readonly Dictionary _appliedCreatureSpawnerCheckIntervals = new Dictionary(); private readonly Dictionary _appliedCreatureSpawnerData = new Dictionary(); private readonly Dictionary _appliedCreatureSpawnerFaction = new Dictionary(); private readonly Dictionary _appliedCreatureSpawnerTimeOfDay = new Dictionary(); private readonly Dictionary> _appliedSpawnAreaPrefabsByInstance = new Dictionary>(); private readonly Dictionary _appliedSpawnAreaDataBySpawnData = new Dictionary(); private readonly Dictionary _appliedSpawnAreaFactionBySpawnData = new Dictionary(); private readonly Dictionary _appliedSpawnAreaTotalSpawnLimits = new Dictionary(); private readonly HashSet _pendingSpawnAreaTrackedAttempts = new HashSet(); private readonly Dictionary _pendingSpawnAreaSelections = new Dictionary(); private readonly Dictionary _pendingSpawnAreaSpawnPoints = new Dictionary(); private readonly Dictionary _pendingSpawnAreaSpawnedObjects = new Dictionary(); public bool TryAddMissingComponentWarning(string key) { return _missingComponentWarnings.Add(key); } public void ClearMissingComponentWarnings() { _missingComponentWarnings.Clear(); } public void ResetPendingSpawnAreaAttempt(SpawnArea? spawnArea) { if (!((Object)(object)spawnArea == (Object)null)) { _pendingSpawnAreaTrackedAttempts.Remove(spawnArea); _pendingSpawnAreaSelections.Remove(spawnArea); _pendingSpawnAreaSpawnPoints.Remove(spawnArea); _pendingSpawnAreaSpawnedObjects.Remove(spawnArea); } } public void BeginPendingSpawnAreaAttempt(SpawnArea spawnArea) { if (!((Object)(object)spawnArea == (Object)null)) { ResetPendingSpawnAreaAttempt(spawnArea); _pendingSpawnAreaTrackedAttempts.Add(spawnArea); } } public void RemovePendingSpawnAreaAttemptMarker(SpawnArea? spawnArea) { if (!((Object)(object)spawnArea == (Object)null)) { _pendingSpawnAreaTrackedAttempts.Remove(spawnArea); } } public bool HasPendingSpawnAreaAttempt(SpawnArea? spawnArea) { if ((Object)(object)spawnArea != (Object)null) { return _pendingSpawnAreaTrackedAttempts.Contains(spawnArea); } return false; } public void SetPendingSpawnAreaSelection(SpawnArea spawnArea, SpawnData? spawnData) { if (!((Object)(object)spawnArea == (Object)null)) { _pendingSpawnAreaSelections[spawnArea] = spawnData; } } public bool TryGetPendingSpawnAreaSelection(SpawnArea? spawnArea, out SpawnData? spawnData) { spawnData = null; if ((Object)(object)spawnArea != (Object)null) { return _pendingSpawnAreaSelections.TryGetValue(spawnArea, out spawnData); } return false; } public bool TryTakePendingSpawnAreaSelection(SpawnArea? spawnArea, out SpawnData? spawnData) { spawnData = null; if ((Object)(object)spawnArea == (Object)null || !_pendingSpawnAreaSelections.TryGetValue(spawnArea, out spawnData)) { return false; } _pendingSpawnAreaSelections.Remove(spawnArea); return true; } public void SetPendingSpawnAreaSpawnPoint(SpawnArea spawnArea, Vector3 spawnPoint) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)spawnArea == (Object)null)) { _pendingSpawnAreaSpawnPoints[spawnArea] = spawnPoint; } } public void RemovePendingSpawnAreaSpawnPoint(SpawnArea? spawnArea) { if (!((Object)(object)spawnArea == (Object)null)) { _pendingSpawnAreaSpawnPoints.Remove(spawnArea); } } public bool TryTakePendingSpawnAreaSpawnPoint(SpawnArea? spawnArea, out Vector3 spawnPoint) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) spawnPoint = default(Vector3); if ((Object)(object)spawnArea == (Object)null || !_pendingSpawnAreaSpawnPoints.TryGetValue(spawnArea, out spawnPoint)) { return false; } _pendingSpawnAreaSpawnPoints.Remove(spawnArea); return true; } public void SetPendingSpawnAreaSpawnedObject(SpawnArea spawnArea, GameObject spawnedObject) { if (!((Object)(object)spawnArea == (Object)null) && !((Object)(object)spawnedObject == (Object)null)) { _pendingSpawnAreaSpawnedObjects[spawnArea] = spawnedObject; } } public bool TryTakePendingSpawnAreaSpawnedObject(SpawnArea? spawnArea, out GameObject? spawnedObject) { spawnedObject = null; if ((Object)(object)spawnArea == (Object)null || !_pendingSpawnAreaSpawnedObjects.TryGetValue(spawnArea, out spawnedObject)) { return false; } _pendingSpawnAreaSpawnedObjects.Remove(spawnArea); return true; } public bool TryGetAppliedCreatureSpawnerData(CreatureSpawner? creatureSpawner, out ExpandWorldSpawnDataPayload payload) { if ((Object)(object)creatureSpawner != (Object)null && _appliedCreatureSpawnerData.TryGetValue(creatureSpawner, out ExpandWorldSpawnDataPayload value)) { payload = value; return true; } payload = null; return false; } public void SetAppliedCreatureSpawnerData(CreatureSpawner creatureSpawner, ExpandWorldSpawnDataPayload payload) { if (!((Object)(object)creatureSpawner == (Object)null) && payload != null) { _appliedCreatureSpawnerData[creatureSpawner] = payload; } } public void RemoveAppliedCreatureSpawnerData(CreatureSpawner? creatureSpawner) { if (!((Object)(object)creatureSpawner == (Object)null)) { _appliedCreatureSpawnerData.Remove(creatureSpawner); } } public bool TryGetAppliedCreatureSpawnerFaction(CreatureSpawner? creatureSpawner, out string faction) { if ((Object)(object)creatureSpawner != (Object)null && _appliedCreatureSpawnerFaction.TryGetValue(creatureSpawner, out string value)) { faction = value; return true; } faction = ""; return false; } public void SetAppliedCreatureSpawnerFaction(CreatureSpawner creatureSpawner, string faction) { if (!((Object)(object)creatureSpawner == (Object)null) && !string.IsNullOrWhiteSpace(faction)) { _appliedCreatureSpawnerFaction[creatureSpawner] = faction; } } public void RemoveAppliedCreatureSpawnerFaction(CreatureSpawner? creatureSpawner) { if (!((Object)(object)creatureSpawner == (Object)null)) { _appliedCreatureSpawnerFaction.Remove(creatureSpawner); } } public bool TryGetAppliedCreatureSpawnerTimeOfDay(CreatureSpawner? creatureSpawner, out TimeOfDayDefinition timeOfDay) { if ((Object)(object)creatureSpawner != (Object)null && _appliedCreatureSpawnerTimeOfDay.TryGetValue(creatureSpawner, out TimeOfDayDefinition value)) { timeOfDay = value; return true; } timeOfDay = null; return false; } public void SetAppliedCreatureSpawnerTimeOfDay(CreatureSpawner creatureSpawner, TimeOfDayDefinition timeOfDay) { if (!((Object)(object)creatureSpawner == (Object)null) && timeOfDay != null) { _appliedCreatureSpawnerTimeOfDay[creatureSpawner] = timeOfDay; } } public void RemoveAppliedCreatureSpawnerTimeOfDay(CreatureSpawner? creatureSpawner) { if (!((Object)(object)creatureSpawner == (Object)null)) { _appliedCreatureSpawnerTimeOfDay.Remove(creatureSpawner); } } public void ClearAppliedCreatureSpawnerOverrides(CreatureSpawner? creatureSpawner) { RemoveAppliedCreatureSpawnerData(creatureSpawner); RemoveAppliedCreatureSpawnerFaction(creatureSpawner); RemoveAppliedCreatureSpawnerTimeOfDay(creatureSpawner); } public bool TryGetAppliedCreatureSpawnerCheckInterval(int instanceId, out int interval) { return _appliedCreatureSpawnerCheckIntervals.TryGetValue(instanceId, out interval); } public void SetAppliedCreatureSpawnerCheckInterval(int instanceId, int interval) { _appliedCreatureSpawnerCheckIntervals[instanceId] = interval; } public void SetAppliedSpawnAreaPrefabs(SpawnArea spawnArea, List prefabs) { if (!((Object)(object)spawnArea == (Object)null) && prefabs != null) { _appliedSpawnAreaPrefabsByInstance[spawnArea] = prefabs; } } public bool TryGetAppliedSpawnAreaPrefabs(SpawnArea? spawnArea, out List prefabs) { if ((Object)(object)spawnArea != (Object)null && _appliedSpawnAreaPrefabsByInstance.TryGetValue(spawnArea, out List value)) { prefabs = value; return true; } prefabs = null; return false; } public bool TryTakeAppliedSpawnAreaPrefabs(SpawnArea? spawnArea, out List prefabs) { if ((Object)(object)spawnArea != (Object)null && _appliedSpawnAreaPrefabsByInstance.TryGetValue(spawnArea, out List value)) { prefabs = value; _appliedSpawnAreaPrefabsByInstance.Remove(spawnArea); return true; } prefabs = null; return false; } public bool TryGetAppliedSpawnAreaData(SpawnData? spawnData, out ExpandWorldSpawnDataPayload payload) { if (spawnData != null && _appliedSpawnAreaDataBySpawnData.TryGetValue(spawnData, out ExpandWorldSpawnDataPayload value)) { payload = value; return true; } payload = null; return false; } public void SetAppliedSpawnAreaData(SpawnData spawnData, ExpandWorldSpawnDataPayload payload) { if (spawnData != null && payload != null) { _appliedSpawnAreaDataBySpawnData[spawnData] = payload; } } public void RemoveAppliedSpawnAreaData(SpawnData? spawnData) { if (spawnData != null) { _appliedSpawnAreaDataBySpawnData.Remove(spawnData); } } public bool HasAppliedSpawnAreaData(SpawnData? spawnData) { if (spawnData != null) { return _appliedSpawnAreaDataBySpawnData.ContainsKey(spawnData); } return false; } public bool TryGetAppliedSpawnAreaFaction(SpawnData? spawnData, out string faction) { if (spawnData != null && _appliedSpawnAreaFactionBySpawnData.TryGetValue(spawnData, out string value)) { faction = value; return true; } faction = ""; return false; } public void SetAppliedSpawnAreaFaction(SpawnData spawnData, string faction) { if (spawnData != null && !string.IsNullOrWhiteSpace(faction)) { _appliedSpawnAreaFactionBySpawnData[spawnData] = faction; } } public void RemoveAppliedSpawnAreaFaction(SpawnData? spawnData) { if (spawnData != null) { _appliedSpawnAreaFactionBySpawnData.Remove(spawnData); } } public bool HasAppliedSpawnAreaFaction(SpawnData? spawnData) { if (spawnData != null) { return _appliedSpawnAreaFactionBySpawnData.ContainsKey(spawnData); } return false; } public bool TryGetAppliedSpawnAreaTotalSpawnLimit(SpawnArea? spawnArea, out SpawnAreaTotalSpawnLimitState state) { if ((Object)(object)spawnArea != (Object)null && _appliedSpawnAreaTotalSpawnLimits.TryGetValue(spawnArea, out state)) { return true; } state = default(SpawnAreaTotalSpawnLimitState); return false; } public void SetAppliedSpawnAreaTotalSpawnLimit(SpawnArea spawnArea, SpawnAreaTotalSpawnLimitState state) { if (!((Object)(object)spawnArea == (Object)null)) { _appliedSpawnAreaTotalSpawnLimits[spawnArea] = state; } } public void RemoveAppliedSpawnAreaTotalSpawnLimit(SpawnArea? spawnArea) { if (!((Object)(object)spawnArea == (Object)null)) { _appliedSpawnAreaTotalSpawnLimits.Remove(spawnArea); } } public void Clear() { _missingComponentWarnings.Clear(); _appliedCreatureSpawnerCheckIntervals.Clear(); _appliedCreatureSpawnerData.Clear(); _appliedCreatureSpawnerFaction.Clear(); _appliedCreatureSpawnerTimeOfDay.Clear(); _appliedSpawnAreaPrefabsByInstance.Clear(); _appliedSpawnAreaDataBySpawnData.Clear(); _appliedSpawnAreaFactionBySpawnData.Clear(); _appliedSpawnAreaTotalSpawnLimits.Clear(); _pendingSpawnAreaTrackedAttempts.Clear(); _pendingSpawnAreaSelections.Clear(); _pendingSpawnAreaSpawnPoints.Clear(); _pendingSpawnAreaSpawnedObjects.Clear(); } } private readonly struct TrackedSpawnerPrefabState { public string PrefabName { get; } public bool ConfiguredEligible { get; } public bool RuntimeEligible { get; } public int EligibilityEpoch { get; } public TrackedSpawnerPrefabState(string prefabName) { PrefabName = prefabName; ConfiguredEligible = false; RuntimeEligible = false; EligibilityEpoch = int.MinValue; } private TrackedSpawnerPrefabState(string prefabName, bool configuredEligible, bool runtimeEligible, int eligibilityEpoch) { PrefabName = prefabName; ConfiguredEligible = configuredEligible; RuntimeEligible = runtimeEligible; EligibilityEpoch = eligibilityEpoch; } public TrackedSpawnerPrefabState WithEligibility(bool configuredEligible, bool runtimeEligible, int eligibilityEpoch) { return new TrackedSpawnerPrefabState(PrefabName, configuredEligible, runtimeEligible, eligibilityEpoch); } } private sealed class SpawnerLiveRegistryStore { private readonly Dictionary _liveSpawnAreaSnapshots = new Dictionary(); private readonly Dictionary _liveCreatureSpawnerSnapshots = new Dictionary(); private readonly Dictionary> _liveSpawnAreasByPrefab = new Dictionary>(StringComparer.OrdinalIgnoreCase); private readonly Dictionary> _liveSpawnAreasByPrefabAndLocation = new Dictionary>(StringComparer.OrdinalIgnoreCase); private readonly Dictionary _liveSpawnAreaPrefabStates = new Dictionary(); private readonly Dictionary _spawnAreaLocationBucketByInstance = new Dictionary(); private readonly Dictionary> _liveCreatureSpawnersByPrefab = new Dictionary>(StringComparer.OrdinalIgnoreCase); private readonly Dictionary> _liveCreatureSpawnersByPrefabAndLocation = new Dictionary>(StringComparer.OrdinalIgnoreCase); private readonly Dictionary _liveCreatureSpawnerPrefabStates = new Dictionary(); private readonly Dictionary _creatureSpawnerLocationBucketByInstance = new Dictionary(); public bool TryGetTrackedPrefabName(SpawnArea? spawnArea, out string prefabName) { if ((Object)(object)spawnArea != (Object)null && _liveSpawnAreaPrefabStates.TryGetValue(spawnArea, out var value)) { prefabName = value.PrefabName; return true; } prefabName = ""; return false; } public bool TryGetTrackedPrefabName(CreatureSpawner? creatureSpawner, out string prefabName) { if ((Object)(object)creatureSpawner != (Object)null && _liveCreatureSpawnerPrefabStates.TryGetValue(creatureSpawner, out var value)) { prefabName = value.PrefabName; return true; } prefabName = ""; return false; } public bool TryGetTrackedState(SpawnArea? spawnArea, out TrackedSpawnerPrefabState trackedState) { if ((Object)(object)spawnArea != (Object)null && _liveSpawnAreaPrefabStates.TryGetValue(spawnArea, out trackedState)) { return true; } trackedState = default(TrackedSpawnerPrefabState); return false; } public bool TryGetTrackedState(CreatureSpawner? creatureSpawner, out TrackedSpawnerPrefabState trackedState) { if ((Object)(object)creatureSpawner != (Object)null && _liveCreatureSpawnerPrefabStates.TryGetValue(creatureSpawner, out trackedState)) { return true; } trackedState = default(TrackedSpawnerPrefabState); return false; } public bool HasLiveSnapshot(SpawnArea? spawnArea) { if ((Object)(object)spawnArea != (Object)null) { return _liveSpawnAreaSnapshots.ContainsKey(spawnArea); } return false; } public bool HasLiveSnapshot(CreatureSpawner? creatureSpawner) { if ((Object)(object)creatureSpawner != (Object)null) { return _liveCreatureSpawnerSnapshots.ContainsKey(creatureSpawner); } return false; } public void CaptureLiveSnapshot(SpawnArea spawnArea, SpawnAreaLiveSnapshot snapshot) { if (!((Object)(object)spawnArea == (Object)null)) { _liveSpawnAreaSnapshots[spawnArea] = snapshot; } } public void CaptureLiveSnapshot(CreatureSpawner creatureSpawner, CreatureSpawnerLiveSnapshot snapshot) { if (!((Object)(object)creatureSpawner == (Object)null)) { _liveCreatureSpawnerSnapshots[creatureSpawner] = snapshot; } } public bool TryGetLiveSnapshot(SpawnArea spawnArea, out SpawnAreaLiveSnapshot snapshot) { return _liveSpawnAreaSnapshots.TryGetValue(spawnArea, out snapshot); } public bool TryGetLiveSnapshot(CreatureSpawner creatureSpawner, out CreatureSpawnerLiveSnapshot snapshot) { return _liveCreatureSpawnerSnapshots.TryGetValue(creatureSpawner, out snapshot); } public void RemoveLiveSnapshot(SpawnArea? spawnArea) { if ((Object)(object)spawnArea != (Object)null) { _liveSpawnAreaSnapshots.Remove(spawnArea); } } public void RemoveLiveSnapshot(CreatureSpawner? creatureSpawner) { if ((Object)(object)creatureSpawner != (Object)null) { _liveCreatureSpawnerSnapshots.Remove(creatureSpawner); } } public void TrackSpawnAreaPrefab(SpawnArea spawnArea, string prefabName) { if (!((Object)(object)spawnArea == (Object)null) && !string.IsNullOrWhiteSpace(prefabName)) { _liveSpawnAreaPrefabStates[spawnArea] = new TrackedSpawnerPrefabState(prefabName); if (!_liveSpawnAreasByPrefab.TryGetValue(prefabName, out HashSet value)) { value = new HashSet(); _liveSpawnAreasByPrefab[prefabName] = value; } value.Add(spawnArea); } } public void TrackCreatureSpawnerPrefab(CreatureSpawner creatureSpawner, string prefabName) { if (!((Object)(object)creatureSpawner == (Object)null) && !string.IsNullOrWhiteSpace(prefabName)) { _liveCreatureSpawnerPrefabStates[creatureSpawner] = new TrackedSpawnerPrefabState(prefabName); if (!_liveCreatureSpawnersByPrefab.TryGetValue(prefabName, out HashSet value)) { value = new HashSet(); _liveCreatureSpawnersByPrefab[prefabName] = value; } value.Add(creatureSpawner); } } public bool UntrackSpawnAreaPrefab(SpawnArea? spawnArea, out string prefabName) { prefabName = ""; if ((Object)(object)spawnArea == (Object)null || !_liveSpawnAreaPrefabStates.Remove(spawnArea, out var value)) { return false; } prefabName = value.PrefabName; if (_liveSpawnAreasByPrefab.TryGetValue(prefabName, out HashSet value2)) { value2.Remove(spawnArea); if (value2.Count == 0) { _liveSpawnAreasByPrefab.Remove(prefabName); } } return true; } public bool UntrackCreatureSpawnerPrefab(CreatureSpawner? creatureSpawner, out string prefabName) { prefabName = ""; if ((Object)(object)creatureSpawner == (Object)null || !_liveCreatureSpawnerPrefabStates.Remove(creatureSpawner, out var value)) { return false; } prefabName = value.PrefabName; if (_liveCreatureSpawnersByPrefab.TryGetValue(prefabName, out HashSet value2)) { value2.Remove(creatureSpawner); if (value2.Count == 0) { _liveCreatureSpawnersByPrefab.Remove(prefabName); } } return true; } public void CollectDeadSpawnAreas(List target) { target.Clear(); foreach (KeyValuePair liveSpawnAreaPrefabState in _liveSpawnAreaPrefabStates) { if ((Object)(object)liveSpawnAreaPrefabState.Key == (Object)null || (Object)(object)((Component)liveSpawnAreaPrefabState.Key).gameObject == (Object)null) { target.Add(liveSpawnAreaPrefabState.Key); } } } public void CollectDeadCreatureSpawners(List target) { target.Clear(); foreach (KeyValuePair liveCreatureSpawnerPrefabState in _liveCreatureSpawnerPrefabStates) { if ((Object)(object)liveCreatureSpawnerPrefabState.Key == (Object)null || (Object)(object)((Component)liveCreatureSpawnerPrefabState.Key).gameObject == (Object)null) { target.Add(liveCreatureSpawnerPrefabState.Key); } } } public void ForEachTrackedSpawnArea(Action visitor) { foreach (KeyValuePair liveSpawnAreaPrefabState in _liveSpawnAreaPrefabStates) { if ((Object)(object)liveSpawnAreaPrefabState.Key != (Object)null) { visitor(liveSpawnAreaPrefabState.Key, liveSpawnAreaPrefabState.Value.PrefabName); } } } public void ForEachTrackedCreatureSpawner(Action visitor) { foreach (KeyValuePair liveCreatureSpawnerPrefabState in _liveCreatureSpawnerPrefabStates) { if ((Object)(object)liveCreatureSpawnerPrefabState.Key != (Object)null) { visitor(liveCreatureSpawnerPrefabState.Key, liveCreatureSpawnerPrefabState.Value.PrefabName); } } } public void UpdateTrackedEligibility(SpawnArea spawnArea, bool configuredEligible, bool runtimeEligible, int eligibilityEpoch) { if (!((Object)(object)spawnArea == (Object)null) && _liveSpawnAreaPrefabStates.TryGetValue(spawnArea, out var value)) { _liveSpawnAreaPrefabStates[spawnArea] = value.WithEligibility(configuredEligible, runtimeEligible, eligibilityEpoch); } } public void UpdateTrackedEligibility(CreatureSpawner creatureSpawner, bool configuredEligible, bool runtimeEligible, int eligibilityEpoch) { if (!((Object)(object)creatureSpawner == (Object)null) && _liveCreatureSpawnerPrefabStates.TryGetValue(creatureSpawner, out var value)) { _liveCreatureSpawnerPrefabStates[creatureSpawner] = value.WithEligibility(configuredEligible, runtimeEligible, eligibilityEpoch); } } public void AppendTrackedSpawnAreasForPrefab(string prefabName, List target) { if (!_liveSpawnAreasByPrefab.TryGetValue(prefabName, out HashSet value)) { return; } foreach (SpawnArea item in value) { if ((Object)(object)item != (Object)null && (Object)(object)((Component)item).gameObject != (Object)null) { target.Add(item); } } } public void AppendTrackedCreatureSpawnersForPrefab(string prefabName, List target) { if (!_liveCreatureSpawnersByPrefab.TryGetValue(prefabName, out HashSet value)) { return; } foreach (CreatureSpawner item in value) { if ((Object)(object)item != (Object)null && (Object)(object)((Component)item).gameObject != (Object)null) { target.Add(item); } } } public bool AppendTrackedSpawnAreasForBucket(string bucketKey, List target) { if (!_liveSpawnAreasByPrefabAndLocation.TryGetValue(bucketKey, out HashSet value)) { return false; } foreach (SpawnArea item in value) { if ((Object)(object)item != (Object)null && (Object)(object)((Component)item).gameObject != (Object)null) { target.Add(item); } } return true; } public bool AppendTrackedCreatureSpawnersForBucket(string bucketKey, List target) { if (!_liveCreatureSpawnersByPrefabAndLocation.TryGetValue(bucketKey, out HashSet value)) { return false; } foreach (CreatureSpawner item in value) { if ((Object)(object)item != (Object)null && (Object)(object)((Component)item).gameObject != (Object)null) { target.Add(item); } } return true; } public void UpdateSpawnAreaLocationBucket(SpawnArea spawnArea, string nextBucketKey) { if (!((Object)(object)spawnArea == (Object)null) && !string.IsNullOrWhiteSpace(nextBucketKey) && (!_spawnAreaLocationBucketByInstance.TryGetValue(spawnArea, out string value) || !string.Equals(value, nextBucketKey, StringComparison.OrdinalIgnoreCase))) { RemoveSpawnAreaLocationBucket(spawnArea); if (!_liveSpawnAreasByPrefabAndLocation.TryGetValue(nextBucketKey, out HashSet value2)) { value2 = new HashSet(); _liveSpawnAreasByPrefabAndLocation[nextBucketKey] = value2; } value2.Add(spawnArea); _spawnAreaLocationBucketByInstance[spawnArea] = nextBucketKey; } } public void UpdateCreatureSpawnerLocationBucket(CreatureSpawner creatureSpawner, string nextBucketKey) { if (!((Object)(object)creatureSpawner == (Object)null) && !string.IsNullOrWhiteSpace(nextBucketKey) && (!_creatureSpawnerLocationBucketByInstance.TryGetValue(creatureSpawner, out string value) || !string.Equals(value, nextBucketKey, StringComparison.OrdinalIgnoreCase))) { RemoveCreatureSpawnerLocationBucket(creatureSpawner); if (!_liveCreatureSpawnersByPrefabAndLocation.TryGetValue(nextBucketKey, out HashSet value2)) { value2 = new HashSet(); _liveCreatureSpawnersByPrefabAndLocation[nextBucketKey] = value2; } value2.Add(creatureSpawner); _creatureSpawnerLocationBucketByInstance[creatureSpawner] = nextBucketKey; } } public void RemoveSpawnAreaLocationBucket(SpawnArea? spawnArea) { if (!((Object)(object)spawnArea == (Object)null) && _spawnAreaLocationBucketByInstance.Remove(spawnArea, out string value) && _liveSpawnAreasByPrefabAndLocation.TryGetValue(value, out HashSet value2)) { value2.Remove(spawnArea); if (value2.Count == 0) { _liveSpawnAreasByPrefabAndLocation.Remove(value); } } } public void RemoveCreatureSpawnerLocationBucket(CreatureSpawner? creatureSpawner) { if (!((Object)(object)creatureSpawner == (Object)null) && _creatureSpawnerLocationBucketByInstance.Remove(creatureSpawner, out string value) && _liveCreatureSpawnersByPrefabAndLocation.TryGetValue(value, out HashSet value2)) { value2.Remove(creatureSpawner); if (value2.Count == 0) { _liveCreatureSpawnersByPrefabAndLocation.Remove(value); } } } public void ClearRuntimeView() { _liveSpawnAreaSnapshots.Clear(); _liveCreatureSpawnerSnapshots.Clear(); _liveSpawnAreasByPrefabAndLocation.Clear(); _spawnAreaLocationBucketByInstance.Clear(); _liveCreatureSpawnersByPrefabAndLocation.Clear(); _creatureSpawnerLocationBucketByInstance.Clear(); } public void ClearLiveRegistries() { _liveSpawnAreasByPrefab.Clear(); _liveSpawnAreaPrefabStates.Clear(); _liveCreatureSpawnersByPrefab.Clear(); _liveCreatureSpawnerPrefabStates.Clear(); } } private sealed class PendingLocationRootProvenanceScan { public int RootInstanceId { get; set; } public Transform RootTransform { get; set; } public string LocationPrefab { get; set; } = ""; public int Epoch { get; set; } public List? TraversalStack { get; set; } } private sealed class SpawnerProvenanceRegistry { private readonly Dictionary _spawnAreaLocationProvenance = new Dictionary(); private readonly Dictionary _creatureSpawnerLocationProvenance = new Dictionary(); private readonly Dictionary _spawnedLocationRootPrefabsByTransform = new Dictionary(); private readonly List _currentLocationSpawnContexts = new List(); private readonly RingBufferQueue _pendingLocationRootProvenanceScans = new RingBufferQueue(); private readonly HashSet _pendingLocationRootProvenanceScanIds = new HashSet(); private int _nextLocationProvenanceEpoch = 1; public void PushLocationSpawnContext(string? locationPrefab) { string locationPrefab2 = (locationPrefab ?? "").Trim(); _currentLocationSpawnContexts.Add(new CurrentLocationSpawnContext { LocationPrefab = locationPrefab2 }); } public void PopLocationSpawnContext() { if (_currentLocationSpawnContexts.Count != 0) { _currentLocationSpawnContexts.RemoveAt(_currentLocationSpawnContexts.Count - 1); } } public bool TryGetActiveLocationSpawnContextPrefab(out string locationPrefab) { locationPrefab = ""; for (int num = _currentLocationSpawnContexts.Count - 1; num >= 0; num--) { string text = (_currentLocationSpawnContexts[num].LocationPrefab ?? "").Trim(); if (text.Length != 0) { locationPrefab = text; return true; } } return false; } public bool TryQueueRootProvenanceScan(Transform? rootTransform, string? locationPrefab, int epoch) { string text = (locationPrefab ?? "").Trim(); if ((Object)(object)rootTransform == (Object)null || text.Length == 0) { return false; } int instanceID = ((Object)rootTransform).GetInstanceID(); if (!_pendingLocationRootProvenanceScanIds.Add(instanceID)) { return false; } _pendingLocationRootProvenanceScans.Enqueue(new PendingLocationRootProvenanceScan { RootInstanceId = instanceID, RootTransform = rootTransform, LocationPrefab = text, Epoch = epoch }); return true; } public bool HasPendingRootScans() { return _pendingLocationRootProvenanceScans.Count > 0; } public bool TryPeekPendingRootScan(out PendingLocationRootProvenanceScan pendingScan) { if (_pendingLocationRootProvenanceScans.TryPeek(out PendingLocationRootProvenanceScan item)) { pendingScan = item; return true; } pendingScan = null; return false; } public void DiscardPendingRootScan(PendingLocationRootProvenanceScan pendingScan) { if (pendingScan != null) { _pendingLocationRootProvenanceScans.TryDequeue(out PendingLocationRootProvenanceScan _); _pendingLocationRootProvenanceScanIds.Remove(pendingScan.RootInstanceId); } } public void ClearPendingRootScans() { _pendingLocationRootProvenanceScans.Clear(); _pendingLocationRootProvenanceScanIds.Clear(); } public int AllocateLocationProvenanceEpoch() { if (_nextLocationProvenanceEpoch == int.MaxValue) { _nextLocationProvenanceEpoch = 1; } return _nextLocationProvenanceEpoch++; } public void RecordSpawnedLocationRoot(Transform rootTransform, string locationPrefab) { if (!((Object)(object)rootTransform == (Object)null) && !string.IsNullOrWhiteSpace(locationPrefab)) { _spawnedLocationRootPrefabsByTransform[rootTransform] = locationPrefab; } } public void RemoveSpawnedLocationRoot(Transform? rootTransform) { if (!((Object)(object)rootTransform == (Object)null)) { _spawnedLocationRootPrefabsByTransform.Remove(rootTransform); } } public bool TryGetRecordedRootLocationPrefab(Transform? rootTransform, out string locationPrefab) { locationPrefab = ""; if ((Object)(object)rootTransform != (Object)null && _spawnedLocationRootPrefabsByTransform.TryGetValue(rootTransform, out locationPrefab)) { return !string.IsNullOrWhiteSpace(locationPrefab); } return false; } public bool TryFindRecordedLocationRoot(Transform? transform, out Transform? rootTransform, out string locationPrefab) { rootTransform = null; locationPrefab = ""; Transform val = transform; while ((Object)(object)val != (Object)null) { if (_spawnedLocationRootPrefabsByTransform.TryGetValue(val, out locationPrefab)) { rootTransform = val; return true; } val = val.parent; } return false; } public bool HasSpawnAreaProvenance(SpawnArea? spawnArea) { if ((Object)(object)spawnArea != (Object)null) { return _spawnAreaLocationProvenance.ContainsKey(spawnArea); } return false; } public bool TryGetSpawnAreaProvenance(SpawnArea? spawnArea, out SpawnerLocationProvenance provenance) { if ((Object)(object)spawnArea != (Object)null && _spawnAreaLocationProvenance.TryGetValue(spawnArea, out SpawnerLocationProvenance value)) { provenance = value; return true; } provenance = null; return false; } public void RecordSpawnAreaProvenance(SpawnArea spawnArea, SpawnerLocationProvenance provenance) { if (!((Object)(object)spawnArea == (Object)null) && provenance != null) { _spawnAreaLocationProvenance[spawnArea] = provenance; } } public void RemoveSpawnAreaProvenance(SpawnArea? spawnArea) { if (!((Object)(object)spawnArea == (Object)null)) { _spawnAreaLocationProvenance.Remove(spawnArea); } } public bool HasCreatureSpawnerProvenance(CreatureSpawner? creatureSpawner) { if ((Object)(object)creatureSpawner != (Object)null) { return _creatureSpawnerLocationProvenance.ContainsKey(creatureSpawner); } return false; } public bool TryGetCreatureSpawnerProvenance(CreatureSpawner? creatureSpawner, out SpawnerLocationProvenance provenance) { if ((Object)(object)creatureSpawner != (Object)null && _creatureSpawnerLocationProvenance.TryGetValue(creatureSpawner, out SpawnerLocationProvenance value)) { provenance = value; return true; } provenance = null; return false; } public void RecordCreatureSpawnerProvenance(CreatureSpawner creatureSpawner, SpawnerLocationProvenance provenance) { if (!((Object)(object)creatureSpawner == (Object)null) && provenance != null) { _creatureSpawnerLocationProvenance[creatureSpawner] = provenance; } } public void RemoveCreatureSpawnerProvenance(CreatureSpawner? creatureSpawner) { if (!((Object)(object)creatureSpawner == (Object)null)) { _creatureSpawnerLocationProvenance.Remove(creatureSpawner); } } public void Clear(bool clearCurrentContexts) { _spawnAreaLocationProvenance.Clear(); _creatureSpawnerLocationProvenance.Clear(); _spawnedLocationRootPrefabsByTransform.Clear(); ClearPendingRootScans(); if (clearCurrentContexts) { _currentLocationSpawnContexts.Clear(); } _nextLocationProvenanceEpoch = 1; } } private sealed class SpawnerReconcileQueue { private readonly RingBufferQueue _pendingSpawnAreaReconciles = new RingBufferQueue(); private readonly HashSet _pendingSpawnAreaReconcileIds = new HashSet(); private readonly RingBufferQueue _pendingCreatureSpawnerReconciles = new RingBufferQueue(); private readonly HashSet _pendingCreatureSpawnerReconcileIds = new HashSet(); public bool TryQueue(SpawnArea? spawnArea, int epoch) { if ((Object)(object)spawnArea == (Object)null) { return false; } int instanceID = ((Object)spawnArea).GetInstanceID(); if (!_pendingSpawnAreaReconcileIds.Add(instanceID)) { return false; } _pendingSpawnAreaReconciles.Enqueue(new PendingSpawnAreaReconcile(spawnArea, instanceID, epoch)); return true; } public bool TryQueue(CreatureSpawner? creatureSpawner, int epoch) { if ((Object)(object)creatureSpawner == (Object)null) { return false; } int instanceID = ((Object)creatureSpawner).GetInstanceID(); if (!_pendingCreatureSpawnerReconcileIds.Add(instanceID)) { return false; } _pendingCreatureSpawnerReconciles.Enqueue(new PendingCreatureSpawnerReconcile(creatureSpawner, instanceID, epoch)); return true; } public bool HasPendingWork() { if (_pendingSpawnAreaReconciles.Count <= 0) { return _pendingCreatureSpawnerReconciles.Count > 0; } return true; } public bool TryDequeueNextSpawnArea(int epoch, out SpawnArea? spawnArea) { spawnArea = null; while (_pendingSpawnAreaReconciles.Count > 0) { if (_pendingSpawnAreaReconciles.TryDequeue(out var item)) { _pendingSpawnAreaReconcileIds.Remove(item.InstanceId); if (item.Epoch == epoch && !((Object)(object)item.SpawnArea == (Object)null)) { spawnArea = item.SpawnArea; return true; } } } return false; } public bool TryDequeueNextCreatureSpawner(int epoch, out CreatureSpawner? creatureSpawner) { creatureSpawner = null; while (_pendingCreatureSpawnerReconciles.Count > 0) { if (_pendingCreatureSpawnerReconciles.TryDequeue(out var item)) { _pendingCreatureSpawnerReconcileIds.Remove(item.InstanceId); if (item.Epoch == epoch && !((Object)(object)item.CreatureSpawner == (Object)null)) { creatureSpawner = item.CreatureSpawner; return true; } } } return false; } public void Clear() { _pendingSpawnAreaReconciles.Clear(); _pendingSpawnAreaReconcileIds.Clear(); _pendingCreatureSpawnerReconciles.Clear(); _pendingCreatureSpawnerReconcileIds.Clear(); } } private sealed class TemplateAggregate { public string Prefab { get; set; } = ""; public string OwnerName { get; set; } = "Unknown / Untracked"; public HashSet RootPrefabs { get; } = new HashSet(StringComparer.OrdinalIgnoreCase); public HashSet LocationPrefabs { get; } = new HashSet(StringComparer.OrdinalIgnoreCase); public SpawnAreaComponentSnapshot? SpawnArea { get; set; } public CreatureSpawnerComponentSnapshot? CreatureSpawner { get; set; } } private sealed class SpawnerRuntimeStateStore { private readonly Dictionary _runtimeSpawnAreaSignatures = new Dictionary(); private readonly Dictionary _runtimeCreatureSpawnerSignatures = new Dictionary(); private readonly Dictionary _spawnAreaLocalRuntimeStates = new Dictionary(); private readonly Dictionary _creatureSpawnerLocalRuntimeStates = new Dictionary(); private RuntimeContextSnapshot? _runtimeContextSnapshot; public bool HasRuntimeSignature(SpawnArea spawnArea) { if ((Object)(object)spawnArea != (Object)null) { return _runtimeSpawnAreaSignatures.ContainsKey(spawnArea); } return false; } public bool HasRuntimeSignature(CreatureSpawner creatureSpawner) { if ((Object)(object)creatureSpawner != (Object)null) { return _runtimeCreatureSpawnerSignatures.ContainsKey(creatureSpawner); } return false; } public bool TryGetRuntimeSignature(SpawnArea spawnArea, out int signature) { if ((Object)(object)spawnArea != (Object)null && _runtimeSpawnAreaSignatures.TryGetValue(spawnArea, out signature)) { return true; } signature = 0; return false; } public bool TryGetRuntimeSignature(CreatureSpawner creatureSpawner, out int signature) { if ((Object)(object)creatureSpawner != (Object)null && _runtimeCreatureSpawnerSignatures.TryGetValue(creatureSpawner, out signature)) { return true; } signature = 0; return false; } public void SetRuntimeSignature(SpawnArea spawnArea, int signature) { if (!((Object)(object)spawnArea == (Object)null)) { _runtimeSpawnAreaSignatures[spawnArea] = signature; } } public void SetRuntimeSignature(CreatureSpawner creatureSpawner, int signature) { if (!((Object)(object)creatureSpawner == (Object)null)) { _runtimeCreatureSpawnerSignatures[creatureSpawner] = signature; } } public void RemoveRuntimeSignature(SpawnArea? spawnArea) { if (!((Object)(object)spawnArea == (Object)null)) { _runtimeSpawnAreaSignatures.Remove(spawnArea); } } public void RemoveRuntimeSignature(CreatureSpawner? creatureSpawner) { if (!((Object)(object)creatureSpawner == (Object)null)) { _runtimeCreatureSpawnerSignatures.Remove(creatureSpawner); } } public LocalRuntimeState GetOrCreateLocalRuntimeState(SpawnArea spawnArea) { if (!_spawnAreaLocalRuntimeStates.TryGetValue(spawnArea, out LocalRuntimeState value)) { value = new LocalRuntimeState(); _spawnAreaLocalRuntimeStates[spawnArea] = value; } return value; } public LocalRuntimeState GetOrCreateLocalRuntimeState(CreatureSpawner creatureSpawner) { if (!_creatureSpawnerLocalRuntimeStates.TryGetValue(creatureSpawner, out LocalRuntimeState value)) { value = new LocalRuntimeState(); _creatureSpawnerLocalRuntimeStates[creatureSpawner] = value; } return value; } public void RemoveLocalRuntimeState(SpawnArea? spawnArea) { if (!((Object)(object)spawnArea == (Object)null)) { _spawnAreaLocalRuntimeStates.Remove(spawnArea); } } public void RemoveLocalRuntimeState(CreatureSpawner? creatureSpawner) { if (!((Object)(object)creatureSpawner == (Object)null)) { _creatureSpawnerLocalRuntimeStates.Remove(creatureSpawner); } } public bool TryGetRuntimeContextSnapshot(int frame, out RuntimeContextSnapshot snapshot) { if (_runtimeContextSnapshot != null && _runtimeContextSnapshot.Frame == frame) { snapshot = _runtimeContextSnapshot; return true; } snapshot = null; return false; } public RuntimeContextSnapshot SetRuntimeContextSnapshot(RuntimeContextSnapshot snapshot) { _runtimeContextSnapshot = snapshot; return snapshot; } public void Clear() { _runtimeSpawnAreaSignatures.Clear(); _runtimeCreatureSpawnerSignatures.Clear(); _spawnAreaLocalRuntimeStates.Clear(); _creatureSpawnerLocalRuntimeStates.Clear(); _runtimeContextSnapshot = null; } public void ClearDynamicCaches() { _runtimeSpawnAreaSignatures.Clear(); _runtimeCreatureSpawnerSignatures.Clear(); _runtimeContextSnapshot = null; } } private sealed class SpawnerSelectorCacheStore { private readonly HashSet _locationSelectorDiagnostics = new HashSet(StringComparer.Ordinal); private readonly Dictionary _matchingSpawnAreaEntriesByInstance = new Dictionary(); private readonly Dictionary _matchingCreatureSpawnerEntriesByInstance = new Dictionary(); private readonly Dictionary _sharedMatchingEntryTemplates = new Dictionary(StringComparer.Ordinal); private readonly Dictionary _staticSelectorContextsByInstance = new Dictionary(); public bool TryAddLocationSelectorDiagnostic(string key) { return _locationSelectorDiagnostics.Add(key); } public bool TryGetSpawnAreaEntryCache(SpawnArea? spawnArea, out MatchingEntryCache entryCache) { if ((Object)(object)spawnArea != (Object)null && _matchingSpawnAreaEntriesByInstance.TryGetValue(spawnArea, out MatchingEntryCache value)) { entryCache = value; return true; } entryCache = null; return false; } public void SetSpawnAreaEntryCache(SpawnArea spawnArea, MatchingEntryCache entryCache) { if (!((Object)(object)spawnArea == (Object)null) && entryCache != null) { _matchingSpawnAreaEntriesByInstance[spawnArea] = entryCache; } } public void RemoveSpawnAreaEntryCache(SpawnArea? spawnArea) { if (!((Object)(object)spawnArea == (Object)null)) { _matchingSpawnAreaEntriesByInstance.Remove(spawnArea); } } public bool TryGetCreatureSpawnerEntryCache(CreatureSpawner? creatureSpawner, out MatchingEntryCache entryCache) { if ((Object)(object)creatureSpawner != (Object)null && _matchingCreatureSpawnerEntriesByInstance.TryGetValue(creatureSpawner, out MatchingEntryCache value)) { entryCache = value; return true; } entryCache = null; return false; } public void SetCreatureSpawnerEntryCache(CreatureSpawner creatureSpawner, MatchingEntryCache entryCache) { if (!((Object)(object)creatureSpawner == (Object)null) && entryCache != null) { _matchingCreatureSpawnerEntriesByInstance[creatureSpawner] = entryCache; } } public void RemoveCreatureSpawnerEntryCache(CreatureSpawner? creatureSpawner) { if (!((Object)(object)creatureSpawner == (Object)null)) { _matchingCreatureSpawnerEntriesByInstance.Remove(creatureSpawner); } } public bool TryGetSharedMatchingEntryTemplate(string cacheKey, out SharedMatchingEntryTemplate sharedTemplate) { if (_sharedMatchingEntryTemplates.TryGetValue(cacheKey, out SharedMatchingEntryTemplate value)) { sharedTemplate = value; return true; } sharedTemplate = null; return false; } public void SetSharedMatchingEntryTemplate(string cacheKey, SharedMatchingEntryTemplate sharedTemplate) { if (!string.IsNullOrWhiteSpace(cacheKey) && sharedTemplate != null) { _sharedMatchingEntryTemplates[cacheKey] = sharedTemplate; } } public void ClearSharedMatchingEntryTemplates() { _sharedMatchingEntryTemplates.Clear(); } public bool TryGetReusableStaticSelectorContext(GameObject gameObject, bool usesLocationFields, out StaticSelectorContextSnapshot snapshot) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) snapshot = null; if ((Object)(object)gameObject == (Object)null || !_staticSelectorContextsByInstance.TryGetValue(((Object)gameObject).GetInstanceID(), out StaticSelectorContextSnapshot value)) { return false; } if (value.Position != gameObject.transform.position) { return false; } if (!usesLocationFields) { snapshot = value; return true; } if (!value.HasRecordedLocationProvenanceEpoch || !TryGetRecordedLocationProvenanceEpoch(gameObject, out var provenanceEpoch) || value.RecordedLocationProvenanceEpoch != provenanceEpoch) { return false; } snapshot = value; return true; } public void StoreReusableStaticSelectorContext(GameObject gameObject, StaticSelectorContextSnapshot snapshot, bool storeForLocationFields) { if (!((Object)(object)gameObject == (Object)null) && snapshot != null && (!storeForLocationFields || snapshot.HasRecordedLocationProvenanceEpoch)) { _staticSelectorContextsByInstance[((Object)gameObject).GetInstanceID()] = snapshot; } } public void RemoveStaticSelectorContext(GameObject? gameObject) { if (!((Object)(object)gameObject == (Object)null)) { _staticSelectorContextsByInstance.Remove(((Object)gameObject).GetInstanceID()); } } public void Clear() { _locationSelectorDiagnostics.Clear(); _matchingSpawnAreaEntriesByInstance.Clear(); _matchingCreatureSpawnerEntriesByInstance.Clear(); _sharedMatchingEntryTemplates.Clear(); _staticSelectorContextsByInstance.Clear(); } } private sealed class StaticSelectorContextSnapshot { public Vector3 Position { get; set; } public bool HasRecordedLocationProvenanceEpoch { get; set; } public int RecordedLocationProvenanceEpoch { get; set; } public string ResolvedSelectorLocationPrefab { get; set; } = ""; public string SelectorSourceLabel { get; set; } = ""; public string SelectorLocationKey { get; set; } = ""; public string ConditionLocationName { get; set; } = ""; public Biome Biome { get; set; } public bool InDungeon { get; set; } } private readonly struct SpawnAreaTotalSpawnLimitState { public int MaxTotalSpawns { get; } public bool FromYamlOverride { get; } public SpawnAreaTotalSpawnLimitState(int maxTotalSpawns, bool fromYamlOverride) { MaxTotalSpawns = SpawnerGlobalConfig.ClampSpawnAreaMaxTotalSpawns(maxTotalSpawns); FromYamlOverride = fromYamlOverride; } } [CompilerGenerated] private sealed class d__116 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private string <>2__current; private int <>l__initialThreadId; private HashSet 5__2; private Dictionary>.Enumerator <>7__wrap2; private List.Enumerator <>7__wrap3; private SpawnerConfigurationEntry 5__5; private int 5__6; string IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__116(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 || (uint)(num - 1) <= 1u) { try { if (num == -4 || (uint)(num - 1) <= 1u) { try { } finally { <>m__Finally2(); } } } finally { <>m__Finally1(); } } 5__2 = null; <>7__wrap2 = default(Dictionary>.Enumerator); <>7__wrap3 = default(List.Enumerator); 5__5 = null; <>1__state = -2; } private bool MoveNext() { try { string text; switch (<>1__state) { default: return false; case 0: <>1__state = -1; 5__2 = new HashSet(StringComparer.OrdinalIgnoreCase); <>7__wrap2 = ActiveEntriesByPrefab.GetEnumerator(); <>1__state = -3; goto IL_0238; case 1: <>1__state = -4; goto IL_0158; case 2: { <>1__state = -4; goto IL_020f; } IL_0238: if (<>7__wrap2.MoveNext()) { <>7__wrap2.Current.Deconstruct(out string _, out List value); List list = value; <>7__wrap3 = list.GetEnumerator(); <>1__state = -4; goto IL_0216; } <>m__Finally1(); <>7__wrap2 = default(Dictionary>.Enumerator); return false; IL_0158: 5__6++; goto IL_016a; IL_0216: if (<>7__wrap3.MoveNext()) { 5__5 = <>7__wrap3.Current; if (5__5.SpawnArea?.Creatures != null) { 5__6 = 0; goto IL_016a; } goto IL_018a; } <>m__Finally2(); <>7__wrap3 = default(List.Enumerator); goto IL_0238; IL_018a: text = ReferenceRefreshSupport.NormalizeKey(5__5.CreatureSpawner?.Creature); if (text.Length != 0) { GameObject? obj = ResolveCreaturePrefabForSignature(text); string item = "creatureSpawner:" + text + ":" + ((obj != null) ? ((Object)obj).GetInstanceID() : 0).ToString(CultureInfo.InvariantCulture); if (5__2.Add(item)) { <>2__current = item; <>1__state = 2; return true; } goto IL_020f; } goto IL_0216; IL_016a: if (5__6 < 5__5.SpawnArea.Creatures.Count) { string text2 = ReferenceRefreshSupport.NormalizeKey(5__5.SpawnArea.Creatures[5__6]?.Creature); if (text2.Length != 0) { GameObject? obj2 = ResolveCreaturePrefabForSignature(text2); string item2 = "spawnArea:" + text2 + ":" + ((obj2 != null) ? ((Object)obj2).GetInstanceID() : 0).ToString(CultureInfo.InvariantCulture); if (5__2.Add(item2)) { <>2__current = item2; <>1__state = 1; return true; } } goto IL_0158; } goto IL_018a; IL_020f: 5__5 = null; goto IL_0216; } } 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)<>7__wrap2).Dispose(); } private void <>m__Finally2() { <>1__state = -3; ((IDisposable)<>7__wrap3).Dispose(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; return this; } return new d__116(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__104 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private string <>2__current; private int <>l__initialThreadId; private HashSet 5__2; private IEnumerator <>7__wrap2; private GameObject 5__4; private SpawnArea[] <>7__wrap4; private int <>7__wrap5; private CreatureSpawner[] <>7__wrap6; string IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__104(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || (uint)(num - 1) <= 1u) { try { } finally { <>m__Finally1(); } } 5__2 = null; <>7__wrap2 = null; 5__4 = null; <>7__wrap4 = null; <>7__wrap6 = null; <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; 5__2 = new HashSet(StringComparer.OrdinalIgnoreCase); <>7__wrap2 = EnumerateRootPrefabs().GetEnumerator(); <>1__state = -3; goto IL_01a7; case 1: <>1__state = -3; goto IL_00df; case 2: { <>1__state = -3; goto IL_017b; } IL_01a7: if (<>7__wrap2.MoveNext()) { 5__4 = <>7__wrap2.Current; <>7__wrap4 = 5__4.GetComponentsInChildren(true); <>7__wrap5 = 0; goto IL_00ed; } <>m__Finally1(); <>7__wrap2 = null; return false; IL_017b: <>7__wrap5++; goto IL_0189; IL_00df: <>7__wrap5++; goto IL_00ed; IL_00ed: if (<>7__wrap5 < <>7__wrap4.Length) { SpawnArea obj = <>7__wrap4[<>7__wrap5]; object key; if (obj == null) { key = null; } else { GameObject gameObject = ((Component)obj).gameObject; key = ((gameObject != null) ? ((Object)gameObject).name : null); } string text = ReferenceRefreshSupport.NormalizeKey((string?)key); if (text.Length > 0 && 5__2.Add(text)) { <>2__current = text; <>1__state = 1; return true; } goto IL_00df; } <>7__wrap4 = null; <>7__wrap6 = 5__4.GetComponentsInChildren(true); <>7__wrap5 = 0; goto IL_0189; IL_0189: if (<>7__wrap5 < <>7__wrap6.Length) { CreatureSpawner obj2 = <>7__wrap6[<>7__wrap5]; object key2; if (obj2 == null) { key2 = null; } else { GameObject gameObject2 = ((Component)obj2).gameObject; key2 = ((gameObject2 != null) ? ((Object)gameObject2).name : null); } string text2 = ReferenceRefreshSupport.NormalizeKey((string?)key2); if (text2.Length > 0 && 5__2.Add(text2)) { <>2__current = text2; <>1__state = 2; return true; } goto IL_017b; } <>7__wrap6 = null; 5__4 = null; goto IL_01a7; } } 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 (<>7__wrap2 != null) { <>7__wrap2.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; return this; } return new d__104(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__371 : IEnumerable<(string LocationPrefab, GameObject RootPrefab)>, IEnumerable, IEnumerator<(string LocationPrefab, GameObject RootPrefab)>, IDisposable, IEnumerator { private int <>1__state; private (string LocationPrefab, GameObject RootPrefab) <>2__current; private int <>l__initialThreadId; private HashSet 5__2; private List.Enumerator <>7__wrap2; (string, GameObject) IEnumerator<(string, GameObject)>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__371(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(); } } 5__2 = null; <>7__wrap2 = default(List.Enumerator); <>1__state = -2; } private bool MoveNext() { //IL_009e: Unknown result type (might be due to invalid IL or missing references) try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; if ((Object)(object)ZoneSystem.instance == (Object)null) { return false; } 5__2 = new HashSet(StringComparer.OrdinalIgnoreCase); <>7__wrap2 = ZoneSystem.instance.m_locations.GetEnumerator(); <>1__state = -3; break; case 1: <>1__state = -3; break; } while (<>7__wrap2.MoveNext()) { ZoneLocation current = <>7__wrap2.Current; if (!current.m_prefab.IsValid) { continue; } string zoneLocationPrefabName = GetZoneLocationPrefabName(current); if (zoneLocationPrefabName.Length != 0 && 5__2.Add(zoneLocationPrefabName)) { current.m_prefab.Load(); GameObject asset = current.m_prefab.Asset; if (!((Object)(object)asset == (Object)null)) { <>2__current = (zoneLocationPrefabName, asset); <>1__state = 1; return true; } } } <>m__Finally1(); <>7__wrap2 = default(List.Enumerator); 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; ((IDisposable)<>7__wrap2).Dispose(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator<(string LocationPrefab, GameObject RootPrefab)> IEnumerable<(string, GameObject)>.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; return this; } return new d__371(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<(string, GameObject)>)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__155 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private string <>2__current; private int <>l__initialThreadId; private IEnumerator <>7__wrap1; string IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__155(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(); } } <>7__wrap1 = 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_006a; case 1: <>1__state = -1; goto IL_006a; case 2: <>1__state = -1; goto IL_0093; case 3: { <>1__state = -3; break; } IL_006a: if (File.Exists(PrimaryOverrideConfigurationPathYaml)) { <>2__current = PrimaryOverrideConfigurationPathYaml; <>1__state = 2; return true; } goto IL_0093; IL_0093: <>7__wrap1 = EnumerateSupplementalOverrideConfigurationPaths().GetEnumerator(); <>1__state = -3; break; } if (<>7__wrap1.MoveNext()) { string current = <>7__wrap1.Current; <>2__current = current; <>1__state = 3; return true; } <>m__Finally1(); <>7__wrap1 = 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 (<>7__wrap1 != null) { <>7__wrap1.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; return this; } return new d__155(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__164 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private GameObject <>2__current; private int <>l__initialThreadId; private HashSet 5__2; private List.Enumerator <>7__wrap2; GameObject IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__164(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { switch (<>1__state) { case -3: case 1: try { } finally { <>m__Finally1(); } break; case -4: case 2: try { } finally { <>m__Finally2(); } break; } 5__2 = null; <>7__wrap2 = default(List.Enumerator); <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; 5__2 = new HashSet(); if ((Object)(object)ZNetScene.instance == (Object)null) { return false; } <>7__wrap2 = ZNetScene.instance.m_prefabs.GetEnumerator(); <>1__state = -3; goto IL_00bd; case 1: <>1__state = -3; goto IL_00bd; case 2: { <>1__state = -4; break; } IL_00bd: while (<>7__wrap2.MoveNext()) { GameObject current = <>7__wrap2.Current; if ((Object)(object)current != (Object)null && !((Object)current).name.StartsWith("JVLmock_", StringComparison.OrdinalIgnoreCase) && 5__2.Add(((Object)current).GetInstanceID())) { <>2__current = current; <>1__state = 1; return true; } } <>m__Finally1(); <>7__wrap2 = default(List.Enumerator); <>7__wrap2 = ZNetScene.instance.m_nonNetViewPrefabs.GetEnumerator(); <>1__state = -4; break; } while (<>7__wrap2.MoveNext()) { GameObject current2 = <>7__wrap2.Current; if ((Object)(object)current2 != (Object)null && !((Object)current2).name.StartsWith("JVLmock_", StringComparison.OrdinalIgnoreCase) && 5__2.Add(((Object)current2).GetInstanceID())) { <>2__current = current2; <>1__state = 2; return true; } } <>m__Finally2(); <>7__wrap2 = default(List.Enumerator); 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; ((IDisposable)<>7__wrap2).Dispose(); } private void <>m__Finally2() { <>1__state = -1; ((IDisposable)<>7__wrap2).Dispose(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; return this; } return new d__164(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__287 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private string <>2__current; private int <>l__initialThreadId; private HashSet selectorLocationKeys; public HashSet <>3__selectorLocationKeys; private HashSet.Enumerator <>7__wrap1; string IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__287(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(); } } <>7__wrap1 = default(HashSet.Enumerator); <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; if (selectorLocationKeys != null) { <>7__wrap1 = selectorLocationKeys.GetEnumerator(); <>1__state = -3; goto IL_0078; } goto IL_0097; case 1: <>1__state = -3; goto IL_0078; case 2: { <>1__state = -1; return false; } IL_0097: <>2__current = ""; <>1__state = 2; return true; IL_0078: while (<>7__wrap1.MoveNext()) { string current = <>7__wrap1.Current; if (!string.IsNullOrWhiteSpace(current)) { <>2__current = current; <>1__state = 1; return true; } } <>m__Finally1(); <>7__wrap1 = default(HashSet.Enumerator); goto IL_0097; } } 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)<>7__wrap1).Dispose(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__287 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__287(0); } d__.selectorLocationKeys = <>3__selectorLocationKeys; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__278 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private CreatureSpawner <>2__current; private int <>l__initialThreadId; private HashSet dirtyPrefabs; public HashSet <>3__dirtyPrefabs; private SpawnerRuntimeConfigurationSnapshot runtimeConfigurationSnapshot; public SpawnerRuntimeConfigurationSnapshot <>3__runtimeConfigurationSnapshot; private List 5__2; private HashSet.Enumerator <>7__wrap2; private List.Enumerator <>7__wrap3; CreatureSpawner IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__278(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if ((uint)(num - -5) <= 2u || (uint)(num - 1) <= 1u) { try { switch (num) { case -4: case 1: try { } finally { <>m__Finally2(); } break; case -5: case 2: try { } finally { <>m__Finally3(); } break; } } finally { <>m__Finally1(); } } 5__2 = null; <>7__wrap2 = default(HashSet.Enumerator); <>7__wrap3 = default(List.Enumerator); <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; CleanupRegisteredCreatureSpawners(); 5__2 = new List(); <>7__wrap2 = dirtyPrefabs.GetEnumerator(); <>1__state = -3; goto IL_0166; case 1: <>1__state = -4; goto IL_00d2; case 2: { <>1__state = -5; goto IL_0147; } IL_0166: if (<>7__wrap2.MoveNext()) { string current = <>7__wrap2.Current; 5__2.Clear(); if (TryGetTargetedSelectorLocationKeys(runtimeConfigurationSnapshot, current, forSpawnArea: false, out HashSet selectorLocationKeys) && TryGetRegisteredCreatureSpawnersFromLocationBuckets(current, selectorLocationKeys, 5__2)) { <>7__wrap3 = 5__2.GetEnumerator(); <>1__state = -4; goto IL_00d2; } LiveRegistryStore.AppendTrackedCreatureSpawnersForPrefab(current, 5__2); <>7__wrap3 = 5__2.GetEnumerator(); <>1__state = -5; goto IL_0147; } <>m__Finally1(); <>7__wrap2 = default(HashSet.Enumerator); return false; IL_0147: if (<>7__wrap3.MoveNext()) { CreatureSpawner current2 = <>7__wrap3.Current; <>2__current = current2; <>1__state = 2; return true; } <>m__Finally3(); <>7__wrap3 = default(List.Enumerator); goto IL_0166; IL_00d2: if (<>7__wrap3.MoveNext()) { CreatureSpawner current3 = <>7__wrap3.Current; <>2__current = current3; <>1__state = 1; return true; } <>m__Finally2(); <>7__wrap3 = default(List.Enumerator); goto IL_0166; } } 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)<>7__wrap2).Dispose(); } private void <>m__Finally2() { <>1__state = -3; ((IDisposable)<>7__wrap3).Dispose(); } private void <>m__Finally3() { <>1__state = -3; ((IDisposable)<>7__wrap3).Dispose(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__278 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__278(0); } d__.dirtyPrefabs = <>3__dirtyPrefabs; d__.runtimeConfigurationSnapshot = <>3__runtimeConfigurationSnapshot; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__276 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private SpawnArea <>2__current; private int <>l__initialThreadId; private HashSet dirtyPrefabs; public HashSet <>3__dirtyPrefabs; private SpawnerRuntimeConfigurationSnapshot runtimeConfigurationSnapshot; public SpawnerRuntimeConfigurationSnapshot <>3__runtimeConfigurationSnapshot; private List 5__2; private HashSet.Enumerator <>7__wrap2; private List.Enumerator <>7__wrap3; SpawnArea IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__276(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if ((uint)(num - -5) <= 2u || (uint)(num - 1) <= 1u) { try { switch (num) { case -4: case 1: try { } finally { <>m__Finally2(); } break; case -5: case 2: try { } finally { <>m__Finally3(); } break; } } finally { <>m__Finally1(); } } 5__2 = null; <>7__wrap2 = default(HashSet.Enumerator); <>7__wrap3 = default(List.Enumerator); <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; CleanupRegisteredSpawnAreas(); 5__2 = new List(); <>7__wrap2 = dirtyPrefabs.GetEnumerator(); <>1__state = -3; goto IL_0166; case 1: <>1__state = -4; goto IL_00d2; case 2: { <>1__state = -5; goto IL_0147; } IL_0166: if (<>7__wrap2.MoveNext()) { string current = <>7__wrap2.Current; 5__2.Clear(); if (TryGetTargetedSelectorLocationKeys(runtimeConfigurationSnapshot, current, forSpawnArea: true, out HashSet selectorLocationKeys) && TryGetRegisteredSpawnAreasFromLocationBuckets(current, selectorLocationKeys, 5__2)) { <>7__wrap3 = 5__2.GetEnumerator(); <>1__state = -4; goto IL_00d2; } LiveRegistryStore.AppendTrackedSpawnAreasForPrefab(current, 5__2); <>7__wrap3 = 5__2.GetEnumerator(); <>1__state = -5; goto IL_0147; } <>m__Finally1(); <>7__wrap2 = default(HashSet.Enumerator); return false; IL_0147: if (<>7__wrap3.MoveNext()) { SpawnArea current2 = <>7__wrap3.Current; <>2__current = current2; <>1__state = 2; return true; } <>m__Finally3(); <>7__wrap3 = default(List.Enumerator); goto IL_0166; IL_00d2: if (<>7__wrap3.MoveNext()) { SpawnArea current3 = <>7__wrap3.Current; <>2__current = current3; <>1__state = 1; return true; } <>m__Finally2(); <>7__wrap3 = default(List.Enumerator); goto IL_0166; } } 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)<>7__wrap2).Dispose(); } private void <>m__Finally2() { <>1__state = -3; ((IDisposable)<>7__wrap3).Dispose(); } private void <>m__Finally3() { <>1__state = -3; ((IDisposable)<>7__wrap3).Dispose(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__276 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__276(0); } d__.dirtyPrefabs = <>3__dirtyPrefabs; d__.runtimeConfigurationSnapshot = <>3__runtimeConfigurationSnapshot; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } private const string ReferenceAutoUpdateStateKey = "spawner"; private const string LocationReferenceAutoUpdateStateKey = "spawner.locations"; private const string UnresolvedSelectorLocationCacheKey = ""; private const float RuntimeEvaluationIntervalSeconds = 0.25f; private const float RuntimeEvaluationIntervalInsidePlayerBaseOnlySeconds = 0.5f; internal static readonly DomainModuleDefinition Module = new DomainModuleDefinition("spawner", DropNSpawnPlugin.ReloadDomain.Spawner, "spawner_yaml", 98, ShouldReloadForPath, ReloadConfiguration, OnGameDataReady, HandleExpandWorldDataReady, 6, DomainTransportProfile.MediumConfig, "spawner", "spawner", 30, (SpawnerConfigurationEntry entry) => entry.RuleId, ApplySyncedPayload, DomainWorkKinds.Runtime | DomainWorkKinds.Reconcile, null, null, HasPendingReconcileWork, ProcessQueuedReconcileStep, MarkSyncedPayloadPending, EnterPendingSyncedPayloadState); private static int _invalidEntryWarningSuppressionDepth; 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 SpawnAreaSnapshots = new List(); private static readonly List CreatureSpawnerSnapshots = new List(); private static readonly Dictionary SpawnAreaSnapshotsByExactKey = new Dictionary(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary CreatureSpawnerSnapshotsByExactKey = new Dictionary(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary> SpawnAreaSnapshotsByName = new Dictionary>(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary> CreatureSpawnerSnapshotsByName = new Dictionary>(StringComparer.OrdinalIgnoreCase); private static readonly List ActiveEntries = new List(); private static readonly Dictionary> ActiveEntriesByPrefab = new Dictionary>(StringComparer.OrdinalIgnoreCase); private static readonly HashSet ConfiguredSpawnAreaPrefabs = new HashSet(StringComparer.OrdinalIgnoreCase); private static readonly HashSet ConfiguredCreatureSpawnerPrefabs = new HashSet(StringComparer.OrdinalIgnoreCase); private static readonly HashSet RuntimeConfiguredSpawnAreaPrefabs = new HashSet(StringComparer.OrdinalIgnoreCase); private static readonly HashSet RuntimeConfiguredCreatureSpawnerPrefabs = new HashSet(StringComparer.OrdinalIgnoreCase); private static readonly HashSet InvalidEntryWarnings = new HashSet(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary SpawnAreaCatalogsByExactKey = new Dictionary(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary CreatureSpawnerCatalogsByExactKey = new Dictionary(StringComparer.OrdinalIgnoreCase); private static readonly HashSet CapturedRootPrefabNames = new HashSet(StringComparer.OrdinalIgnoreCase); private static readonly FieldInfo? CreatureSpawnerCheckedLocationField = AccessTools.Field(typeof(CreatureSpawner), "m_checkedLocation"); private static readonly FieldInfo? CreatureSpawnerLocationField = AccessTools.Field(typeof(CreatureSpawner), "m_location"); private static readonly FieldInfo? CreatureSpawnerSpawnGroupField = AccessTools.Field(typeof(CreatureSpawner), "m_spawnGroup"); private static List _configuration = new List(); private static string _configurationSignature = ""; private static bool _lastAppliedSynchronizedPayloadReady; private static bool _initialized; private static bool _snapshotsCaptured; private static int? _lastProcessedGameDataSignature; private static SpawnerRuntimeConfigurationSnapshot _runtimeConfigurationSnapshot = SpawnerRuntimeConfigurationSnapshot.Empty; private static bool _referenceArtifactsAutoRefreshConsumed; private static readonly Dictionary CurrentEntrySignaturesByPrefab = new Dictionary(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary _lastAppliedEntrySignaturesByPrefab = new Dictionary(StringComparer.OrdinalIgnoreCase); private static string _lastAppliedConfigurationSignature = ""; private static int? _lastAppliedGameDataSignature; private static bool? _lastAppliedDomainEnabled; private static int _reconcileQueueEpoch; private static int _trackedSpawnerEligibilityEpoch; private const string MockPrefabPrefix = "JVLmock_"; private static bool _synchronizedPayloadReady; private static readonly DomainConfigurationRuntime ConfigurationRuntime = new DomainConfigurationRuntime(new DomainLoadHooks(ParseLocalConfigurationDocuments, BuildSyncedConfigurationState, CommitSyncedConfigurationState, RejectLocalConfigurationPayload, (SyncedSpawnerConfigurationState state) => state.Configuration.Count, LogPartiallyAcceptedLocalConfiguration, LogLocalConfigurationLoaded, OnSourceOfTruthPayloadUnchanged, delegate { ConfigurationDomainHost.PublishSyncedPayload(DropNSpawnPlugin.IsSourceOfTruth, Descriptor, _configuration, _configurationSignature); }), new DomainSyncHooks(delegate(out List configuration, out string payloadToken) { return ConfigurationDomainHost.TryGetSyncedEntries(Descriptor, out configuration, out payloadToken); }, (string payloadToken) => ConfigurationDomainHost.ShouldSkipSyncedPayload(LoadState, payloadToken, Volatile.Read(ref _synchronizedPayloadReady)), BuildSyncedConfigurationState, CommitSyncedConfigurationState, (SyncedSpawnerConfigurationState state) => state.ActiveEntries.Count, "ServerSync:DropNSpawnSpawner", delegate { ConfigurationDomainHost.HandleWaitingForSyncedPayload(MarkSyncedPayloadPending, "Waiting for synchronized spawner override payload from the server."); }, LogSyncedSpawnerConfigurationLoaded, LogSyncedSpawnerConfigurationFailure)); private static readonly Dictionary EmptyEntrySignatures = new Dictionary(StringComparer.OrdinalIgnoreCase); private static readonly SpawnerLiveReconcilerState LiveReconcilerState = new SpawnerLiveReconcilerState(); private static readonly SpawnerLiveRegistryStore LiveRegistryStore = new SpawnerLiveRegistryStore(); private static readonly SpawnerProvenanceRegistry ProvenanceRegistry = new SpawnerProvenanceRegistry(); private static readonly SpawnerReconcileQueue ReconcileQueue = new SpawnerReconcileQueue(); private static readonly SpawnerRuntimeStateStore RuntimeStateStore = new SpawnerRuntimeStateStore(); private static readonly SpawnerSelectorCacheStore SelectorCacheStore = new SpawnerSelectorCacheStore(); private static readonly int SpawnAreaTotalSpawnCountZdoKey = StringExtensionMethods.GetStableHashCode("DropNSpawn.SpawnArea.TotalSpawnCount"); private static readonly int SpawnAreaMaxTotalSpawnsZdoKey = StringExtensionMethods.GetStableHashCode("DropNSpawn.SpawnArea.MaxTotalSpawns"); internal static DomainDescriptor Descriptor => Module.DescriptorTyped; internal static DomainTransportMetadata TransportMetadata => Module.TransportMetadataTyped; private static DomainLoadState LoadState => ConfigurationRuntime.LoadState; private static string ReferenceConfigurationPath => Path.Combine(DropNSpawnPlugin.YamlConfigDirectoryPath, PluginSettingsFacade.GetYamlDomainFilePrefix("spawner") + ".reference.yml"); private static string LocationReferenceConfigurationPath => Path.Combine(DropNSpawnPlugin.YamlConfigDirectoryPath, PluginSettingsFacade.GetYamlDomainFilePrefix("spawner") + ".locations.reference.yml"); private static string PrimaryOverrideConfigurationPathYml => Path.Combine(DropNSpawnPlugin.YamlConfigDirectoryPath, PluginSettingsFacade.GetYamlDomainFilePrefix("spawner") + ".yml"); private static string PrimaryOverrideConfigurationPathYaml => Path.Combine(DropNSpawnPlugin.YamlConfigDirectoryPath, PluginSettingsFacade.GetYamlDomainFilePrefix("spawner") + ".yaml"); private static string FullScaffoldConfigurationPath => Path.Combine(DropNSpawnPlugin.YamlConfigDirectoryPath, PluginSettingsFacade.GetYamlDomainFilePrefix("spawner") + ".full.yml"); private static void ApplyDesiredStateToLiveObjects(SpawnerDesiredState desiredState) { if (desiredState.ReloadPrefabs.Count != 0) { if (desiredState.QueueLiveReconcile) { ReapplyOrQueueRegisteredLiveObjects(desiredState.DomainEnabled, desiredState.ReloadPrefabs, desiredState.RuntimeConfigurationSnapshot); } else { ReapplyRegisteredLiveObjects(desiredState.DomainEnabled, desiredState.ReloadPrefabs, desiredState.RuntimeConfigurationSnapshot); } } } private static void ReapplyRegisteredLiveObjects(bool domainEnabled, HashSet prefabs, SpawnerRuntimeConfigurationSnapshot runtimeConfigurationSnapshot) { string configPrefabName; foreach (SpawnArea registeredSpawnArea in GetRegisteredSpawnAreas(prefabs, runtimeConfigurationSnapshot)) { TrackSpawnAreaInstanceInternal(registeredSpawnArea); if (domainEnabled && TryGetActiveSpawnAreaEntries(registeredSpawnArea, runtimeConfigurationSnapshot, out IReadOnlyList entries, out configPrefabName)) { ReconcileSpawnAreaInstanceInternal(registeredSpawnArea, entries); } else { RestoreSpawnAreaInstance(registeredSpawnArea); } } foreach (CreatureSpawner registeredCreatureSpawner in GetRegisteredCreatureSpawners(prefabs, runtimeConfigurationSnapshot)) { TrackCreatureSpawnerInstanceInternal(registeredCreatureSpawner); if (domainEnabled && TryGetActiveCreatureSpawnerEntries(registeredCreatureSpawner, runtimeConfigurationSnapshot, out IReadOnlyList entries2, out configPrefabName)) { ReconcileCreatureSpawnerInstanceInternal(registeredCreatureSpawner, entries2); } else { RestoreCreatureSpawnerInstance(registeredCreatureSpawner, refreshRuntimeState: true); } } } private static void ReapplyOrQueueRegisteredLiveObjects(bool domainEnabled, HashSet prefabs, SpawnerRuntimeConfigurationSnapshot runtimeConfigurationSnapshot) { foreach (SpawnArea registeredSpawnArea in GetRegisteredSpawnAreas(prefabs, runtimeConfigurationSnapshot)) { TrackSpawnAreaInstanceInternal(registeredSpawnArea); if (domainEnabled && TryGetActiveSpawnAreaEntryCache(registeredSpawnArea, runtimeConfigurationSnapshot, out MatchingEntryCache entryCache, out string configPrefabName)) { if (runtimeConfigurationSnapshot.RuntimeConfiguredSpawnAreaPrefabs.Contains(configPrefabName)) { QueueSpawnAreaReconcile(registeredSpawnArea); } else { ReconcileSpawnAreaInstanceInternal(registeredSpawnArea, entryCache.Entries, entryCache); } } else { RestoreSpawnAreaInstance(registeredSpawnArea); } } foreach (CreatureSpawner registeredCreatureSpawner in GetRegisteredCreatureSpawners(prefabs, runtimeConfigurationSnapshot)) { TrackCreatureSpawnerInstanceInternal(registeredCreatureSpawner); if (domainEnabled && TryGetActiveCreatureSpawnerEntryCache(registeredCreatureSpawner, runtimeConfigurationSnapshot, out MatchingEntryCache entryCache2, out string configPrefabName2)) { if (runtimeConfigurationSnapshot.RuntimeConfiguredCreatureSpawnerPrefabs.Contains(configPrefabName2)) { QueueCreatureSpawnerReconcile(registeredCreatureSpawner); } else { ReconcileCreatureSpawnerInstanceInternal(registeredCreatureSpawner, entryCache2.Entries, entryCache2); } } else { RestoreCreatureSpawnerInstance(registeredCreatureSpawner, refreshRuntimeState: true); } } } private static bool TryGetActiveSpawnAreaEntries(SpawnArea? spawnArea, SpawnerRuntimeConfigurationSnapshot runtimeConfigurationSnapshot, out IReadOnlyList? entries, out string configPrefabName) { entries = null; if (!TryGetActiveSpawnAreaEntryCache(spawnArea, runtimeConfigurationSnapshot, out MatchingEntryCache entryCache, out configPrefabName)) { return false; } entries = entryCache.Entries; return true; } private static bool TryGetActiveCreatureSpawnerEntries(CreatureSpawner? creatureSpawner, SpawnerRuntimeConfigurationSnapshot runtimeConfigurationSnapshot, out IReadOnlyList? entries, out string configPrefabName) { entries = null; if (!TryGetActiveCreatureSpawnerEntryCache(creatureSpawner, runtimeConfigurationSnapshot, out MatchingEntryCache entryCache, out configPrefabName)) { return false; } entries = entryCache.Entries; return true; } internal static bool ShouldReloadForPath(string? path) { if (PluginSettingsFacade.IsEligibleOverrideConfigurationPath(path)) { return IsOverrideConfigurationFileName(Path.GetFileName(path ?? "")); } return false; } private static bool ShouldApplyLocally() { return PluginSettingsFacade.IsSpawnerDomainEnabled(); } internal static void MarkSyncedPayloadPending() { lock (Sync) { ConfigurationRuntime.MarkSyncedPayloadPending(DropNSpawnPlugin.IsSourceOfTruth, delegate { Volatile.Write(ref _synchronizedPayloadReady, value: false); }); } } internal static void EnterPendingSyncedPayloadState() { lock (Sync) { Dictionary previousEntrySignatures = CloneCurrentEntrySignaturesByPrefab(); HashSet previouslyAppliedPrefabs = BuildLastAppliedPrefabs(); ConfigurationRuntime.EnterPendingSyncedPayloadState(DropNSpawnPlugin.IsSourceOfTruth, ResetLoadedConfigurationState, delegate { _configurationSignature = ""; _lastAppliedSynchronizedPayloadReady = false; ReapplyRegisteredLiveObjects(domainEnabled: false, previouslyAppliedPrefabs); RefreshVneiCompatibility(previousEntrySignatures); }); } } internal static bool ShouldBlockClientSpawnerUpdate() { if (!ShouldApplyLocally() || DropNSpawnPlugin.IsSourceOfTruth) { return false; } if (DropNSpawnPlugin.IsGameDataRefreshDeferred(DropNSpawnPlugin.ReloadDomain.Spawner)) { return true; } if (!IsGameDataReady()) { return true; } return !Volatile.Read(ref _synchronizedPayloadReady); } internal static void Initialize() { lock (Sync) { if (!_initialized) { LoadConfiguration(); _initialized = true; } } } internal static void ReloadConfiguration() { lock (Sync) { LoadConfiguration(); ApplyIfReady(queueLiveReconcile: true); } } internal static bool HandleExpandWorldDataReady() { lock (Sync) { if (!DropNSpawnPlugin.IsSourceOfTruth) { return false; } string text = NetworkPayloadSyncSupport.ComputeSpawnerConfigurationSignature(_configuration); if (string.Equals(text, _configurationSignature, StringComparison.Ordinal)) { return false; } _configurationSignature = text; ConfigurationDomainHost.PublishSyncedPayload(DropNSpawnPlugin.IsSourceOfTruth, Descriptor, _configuration, _configurationSignature); ApplyIfReady(queueLiveReconcile: true); return true; } } internal static void ApplySyncedPayload() { lock (Sync) { Dictionary previousEntrySignatures = CloneCurrentEntrySignaturesByPrefab(); ConfigurationRuntime.ApplySyncedPayload(delegate { RefreshVneiCompatibility(previousEntrySignatures, CloneCurrentEntrySignaturesByPrefab()); ApplyIfReady(queueLiveReconcile: true); }); } } internal static void OnGameDataReady(string source) { lock (Sync) { if (!_initialized) { Initialize(); } if (!IsGameDataReady()) { return; } int num = ComputeGameDataSignature(BuildCurrentSpawnerReferencePrefabKeys().ToHashSet(StringComparer.OrdinalIgnoreCase)); if (_lastProcessedGameDataSignature != num) { ResetReferenceSnapshots(); ResetRuntimeState(preserveLiveRegistries: true); CleanupRegisteredSpawnAreas(); CleanupRegisteredCreatureSpawners(); if (DropNSpawnPlugin.IsSourceOfTruth && !_referenceArtifactsAutoRefreshConsumed) { EnsureReferenceArtifactsUpToDate(); _referenceArtifactsAutoRefreshConsumed = true; } else if (!DropNSpawnPlugin.IsSourceOfTruth) { _referenceArtifactsAutoRefreshConsumed = true; } if (DropNSpawnPlugin.IsSourceOfTruth && EnsurePrimaryOverrideConfigurationFileExists()) { LoadConfiguration(); } ApplyIfReady(queueLiveReconcile: true); _lastProcessedGameDataSignature = num; DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)("Spawners processed after " + source + ".")); } } } internal static bool TryWriteFullScaffoldConfigurationFile(out string path, out string error) { lock (Sync) { path = FullScaffoldConfigurationPath; error = ""; if (!IsGameDataReady() && !_snapshotsCaptured) { error = "Spawner game data is not ready yet."; return false; } CaptureSnapshotsIfNeeded(); Directory.CreateDirectory(DropNSpawnPlugin.YamlConfigDirectoryPath); File.WriteAllText(path, BuildFullScaffoldConfigurationTemplate()); DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)("Wrote spawner full scaffold configuration to " + path + ".")); return true; } } internal static void RefreshReferenceConfigurationFile() { lock (Sync) { if (IsGameDataReady()) { CaptureSnapshotsIfNeeded(); string referenceContent = BuildReferenceConfigurationTemplate(); string locationReferenceContent = BuildLocationReferenceConfigurationTemplate(); WriteReferenceConfigurationFile(referenceContent, locationReferenceContent, "Updated spawner reference configurations at " + ReferenceConfigurationPath + " and " + LocationReferenceConfigurationPath + ".", writePrimaryReference: true, writeLocationReference: true); ReferenceRefreshSupport.RecordAutoUpdateState("spawner", ReferenceConfigurationPath, ComputeReferenceSourceSignature(), null, "2026-03-26-full-rewrite-v1"); ReferenceRefreshSupport.RecordAutoUpdateState("spawner.locations", LocationReferenceConfigurationPath, ComputeReferenceSourceSignature(), null, "2026-03-26-full-rewrite-v1"); ResetReferenceSnapshots(); } } } private static void EnsureReferenceArtifactsUpToDate() { if (IsGameDataReady() && EnsureSpawnerReferenceConfigurationUpToDate()) { ResetReferenceSnapshots(); } } private static bool EnsureSpawnerReferenceConfigurationUpToDate() { string sourceSignature = ComputeReferenceSourceSignature(); bool flag = File.Exists(ReferenceConfigurationPath); bool flag2 = File.Exists(LocationReferenceConfigurationPath); bool flag3 = PluginSettingsFacade.ShouldAutoCreateMissingReferenceFiles(); bool flag4 = !flag && flag3; bool num = !flag2 && flag3; bool flag5 = false; bool flag6 = false; if (PluginSettingsFacade.ShouldAutoUpdateReferenceFiles()) { if (flag) { flag5 = !ReferenceRefreshSupport.ShouldSkipAutoUpdate("spawner", ReferenceConfigurationPath, sourceSignature, "2026-03-26-full-rewrite-v1"); } if (flag2) { flag6 = !ReferenceRefreshSupport.ShouldSkipAutoUpdate("spawner.locations", LocationReferenceConfigurationPath, sourceSignature, "2026-03-26-full-rewrite-v1"); } } bool flag7 = flag4 || flag5; bool flag8 = num || flag6; if (!flag7 && !flag8) { return false; } CaptureSnapshotsIfNeeded(); string referenceContent = (flag7 ? BuildReferenceConfigurationTemplate() : null); string locationReferenceContent = (flag8 ? BuildLocationReferenceConfigurationTemplate() : null); string text = ((flag5 || flag6) ? "Updated" : "Created"); string text2 = ((flag7 && flag8) ? ("spawner reference configurations at " + ReferenceConfigurationPath + " and " + LocationReferenceConfigurationPath) : (flag7 ? ("spawner reference configuration at " + ReferenceConfigurationPath) : ("spawner location reference configuration at " + LocationReferenceConfigurationPath))); WriteReferenceConfigurationFile(referenceContent, locationReferenceContent, text + " " + text2 + ".", flag7, flag8); if (flag7) { ReferenceRefreshSupport.RecordAutoUpdateState("spawner", ReferenceConfigurationPath, sourceSignature, null, "2026-03-26-full-rewrite-v1"); } if (flag8) { ReferenceRefreshSupport.RecordAutoUpdateState("spawner.locations", LocationReferenceConfigurationPath, sourceSignature, null, "2026-03-26-full-rewrite-v1"); } return true; } [IteratorStateMachine(typeof(d__104))] private static IEnumerable BuildCurrentSpawnerReferencePrefabKeys() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__104(-2); } private static string ComputeReferenceSourceSignature() { return ReferenceRefreshSupport.ComputeStableHashForKeys(BuildCurrentSpawnerReferencePrefabKeys()); } internal static bool TryInspectCurrentTarget(out string[] lines, out string error) { lock (Sync) { lines = Array.Empty(); error = ""; if ((Object)(object)Player.m_localPlayer == (Object)null) { error = "Player is not available."; return false; } GameObject val = ResolveCurrentInspectionTarget(); if ((Object)(object)val == (Object)null) { error = "No hovered or nearby spawner target found."; return false; } List list = BuildInspectionLines(val); if (list.Count == 0) { error = "The current target is not a SpawnArea or CreatureSpawner."; return false; } lines = list.ToArray(); return true; } } internal static void RecordDirectSpawnAreaSpawnedObject(SpawnArea spawnArea, GameObject? spawnedObject) { lock (Sync) { if (!((Object)(object)spawnArea == (Object)null) && !((Object)(object)spawnedObject == (Object)null) && LiveReconcilerState.HasPendingSpawnAreaAttempt(spawnArea)) { LiveReconcilerState.SetPendingSpawnAreaSpawnedObject(spawnArea, spawnedObject); } } } internal static void FinalizeSpawnAreaSpawnAttempt(SpawnArea spawnArea, bool succeeded) { //IL_0089: Unknown result type (might be due to invalid IL or missing references) lock (Sync) { LiveReconcilerState.RemovePendingSpawnAreaAttemptMarker(spawnArea); LiveReconcilerState.TryTakePendingSpawnAreaSelection(spawnArea, out SpawnData spawnData); Vector3 spawnPoint; bool flag = LiveReconcilerState.TryTakePendingSpawnAreaSpawnPoint(spawnArea, out spawnPoint); string faction = null; ExpandWorldSpawnDataPayload payload = null; bool flag2 = spawnData != null && LiveReconcilerState.TryGetAppliedSpawnAreaFaction(spawnData, out faction); bool flag3 = spawnData != null && LiveReconcilerState.TryGetAppliedSpawnAreaData(spawnData, out payload) && payload.HasObjects; if (succeeded && flag && spawnData != null && (flag2 || flag3)) { if (flag3) { ExpandWorldSpawnDataSupport.SpawnObjects(spawnPoint, payload); } if (flag2) { GameObject spawnedObject; Character val = ((LiveReconcilerState.TryTakePendingSpawnAreaSpawnedObject(spawnArea, out spawnedObject) && (Object)(object)spawnedObject != (Object)null) ? spawnedObject.GetComponent() : null); if ((Object)(object)val != (Object)null) { string context = GetConfigPrefabName(((Component)spawnArea).gameObject, "SpawnArea") + "@" + DescribeInstance(((Component)spawnArea).gameObject) + "/spawnArea.spawn"; FactionIntegration.Apply(val, faction, context); } } } if (succeeded) { RecordSuccessfulSpawnAreaTotalSpawn(spawnArea); } } } internal static void ApplyCreatureSpawnerSpawnOverrides(CreatureSpawner creatureSpawner, ZNetView? spawnedView) { //IL_006f: Unknown result type (might be due to invalid IL or missing references) lock (Sync) { if (!((Object)(object)creatureSpawner == (Object)null) && !((Object)(object)spawnedView == (Object)null)) { string context = GetConfigPrefabName(((Component)creatureSpawner).gameObject, "CreatureSpawner") + "@" + DescribeInstance(((Component)creatureSpawner).gameObject) + "/creatureSpawner.spawn"; if (LiveReconcilerState.TryGetAppliedCreatureSpawnerData(creatureSpawner, out ExpandWorldSpawnDataPayload payload) && payload.HasObjects) { ExpandWorldSpawnDataSupport.SpawnObjects(((Component)spawnedView).transform.position, payload); } Character component = ((Component)spawnedView).GetComponent(); if (!((Object)(object)component == (Object)null) && LiveReconcilerState.TryGetAppliedCreatureSpawnerFaction(creatureSpawner, out string faction)) { FactionIntegration.Apply(component, faction, context); } } } } internal static void InitializeSpawnAreaSpawnData(SpawnArea spawnArea, GameObject? prefab, Vector3 spawnPoint) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) lock (Sync) { if (!((Object)(object)spawnArea == (Object)null) && !((Object)(object)prefab == (Object)null) && LiveReconcilerState.TryGetPendingSpawnAreaSelection(spawnArea, out SpawnData spawnData) && spawnData != null && LiveReconcilerState.TryGetAppliedSpawnAreaData(spawnData, out ExpandWorldSpawnDataPayload payload)) { ExpandWorldSpawnDataSupport.InitializeSpawn(prefab, spawnPoint, payload); } } } internal static void InitializeCreatureSpawnerSpawnData(CreatureSpawner creatureSpawner, GameObject? prefab, Vector3 spawnPoint) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) lock (Sync) { if (!((Object)(object)creatureSpawner == (Object)null) && !((Object)(object)prefab == (Object)null) && LiveReconcilerState.TryGetAppliedCreatureSpawnerData(creatureSpawner, out ExpandWorldSpawnDataPayload payload)) { ExpandWorldSpawnDataSupport.InitializeSpawn(prefab, spawnPoint, payload); } } } internal static bool IsCreatureSpawnerTimeOfDayAllowed(CreatureSpawner creatureSpawner) { lock (Sync) { TimeOfDayDefinition timeOfDay; return (Object)(object)creatureSpawner == (Object)null || !LiveReconcilerState.TryGetAppliedCreatureSpawnerTimeOfDay(creatureSpawner, out timeOfDay) || TimeOfDayFormatting.MatchesCurrentTime(timeOfDay); } } private static bool IsGameDataReady() { return (Object)(object)ZNetScene.instance != (Object)null; } private static int ComputeGameDataSignature(IEnumerable? availablePrefabs = null) { if (!IsGameDataReady() || (Object)(object)ZNetScene.instance == (Object)null) { return 0; } return HashNormalizedKeys(HashNormalizedKeys(17 * 31 + ((Object)ZNetScene.instance).GetInstanceID(), availablePrefabs ?? BuildCurrentSpawnerReferencePrefabKeys()), BuildConfiguredSpawnerResolutionKeys()); } private static int HashNormalizedKeys(int hash, IEnumerable keys) { foreach (string item in (from key in (keys ?? Enumerable.Empty()).Select(ReferenceRefreshSupport.NormalizeKey) where key.Length > 0 select key).OrderBy((string key) => key, StringComparer.OrdinalIgnoreCase)) { hash = hash * 31 + StringComparer.OrdinalIgnoreCase.GetHashCode(item); } return hash; } [IteratorStateMachine(typeof(d__116))] private static IEnumerable BuildConfiguredSpawnerResolutionKeys() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__116(-2); } private static GameObject? ResolveCreaturePrefabForSignature(string? prefabName) { string text = ReferenceRefreshSupport.NormalizeKey(prefabName); if (text.Length == 0) { return null; } ZNetScene instance = ZNetScene.instance; GameObject val = ((instance != null) ? instance.GetPrefab(text) : null); if ((Object)(object)val == (Object)null) { return null; } Character val2 = default(Character); BaseAI val3 = default(BaseAI); if (!val.TryGetComponent(ref val2) && !val.TryGetComponent(ref val3)) { return null; } return val; } 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 spawner override configuration at " + PrimaryOverrideConfigurationPathYml + ".")); return true; } private static void LoadConfiguration() { Dictionary previousEntrySignatures = CloneCurrentEntrySignaturesByPrefab(); if (DropNSpawnPlugin.IsSourceOfTruth) { EnsurePrimaryOverrideConfigurationFileExists(); if (ConfigurationRuntime.ReloadSourceOfTruth(EnumerateOverrideConfigurationPaths().ToList()) == DomainReloadOutcome.Loaded) { RefreshVneiCompatibility(previousEntrySignatures); } } else if (ConfigurationRuntime.ReloadSynced() == DomainReloadOutcome.Loaded) { RefreshVneiCompatibility(previousEntrySignatures, CloneCurrentEntrySignaturesByPrefab()); } } private static void RefreshVneiCompatibility(Dictionary previousEntrySignatures) { RefreshVneiCompatibility(previousEntrySignatures, CloneCurrentEntrySignaturesByPrefab()); } private static void RefreshVneiCompatibility(Dictionary previousEntrySignatures, Dictionary currentEntrySignatures) { VneiCompatibility.RefreshSpawnerPrefabs(BuildDirtyPrefabs(previousEntrySignatures, currentEntrySignatures)); } private static void ResetLoadedConfigurationState() { ClearQueuedReconcileState(); Volatile.Write(ref _synchronizedPayloadReady, value: false); Volatile.Write(ref _runtimeConfigurationSnapshot, SpawnerRuntimeConfigurationSnapshot.Empty); ActiveEntries.Clear(); ActiveEntriesByPrefab.Clear(); ConfiguredSpawnAreaPrefabs.Clear(); ConfiguredCreatureSpawnerPrefabs.Clear(); RuntimeConfiguredSpawnAreaPrefabs.Clear(); RuntimeConfiguredCreatureSpawnerPrefabs.Clear(); InvalidEntryWarnings.Clear(); LiveReconcilerState.ClearMissingComponentWarnings(); SelectorCacheStore.Clear(); RuntimeStateStore.Clear(); LiveRegistryStore.ClearRuntimeView(); ProvenanceRegistry.Clear(clearCurrentContexts: false); _configuration = new List(); CurrentEntrySignaturesByPrefab.Clear(); InvalidateTrackedSpawnerEligibility(); } private static List CloneAndNormalizeConfigurationEntries(List? configuration, string sourceName) { List list = NetworkPayloadSyncSupport.CloneEntries(Descriptor, configuration); foreach (SpawnerConfigurationEntry item in list) { item.SourcePath = (string.IsNullOrWhiteSpace(item.SourcePath) ? sourceName : item.SourcePath); NormalizeEntry(item); } return list; } private static List PrepareLocalConfigurationEntries(List? configuration, string sourceName, List warnings) { List list = CloneAndNormalizeConfigurationEntries(configuration, sourceName); List list2 = new List(); foreach (SpawnerConfigurationEntry item in list) { if (TryAcceptLocalConfigurationEntry(item, warnings)) { list2.Add(item); } } return list2; } private static bool TryAcceptLocalConfigurationEntry(SpawnerConfigurationEntry entry, List warnings) { if (!entry.Enabled) { return true; } string text = CreateConfigurationContext(entry); if (string.IsNullOrWhiteSpace(entry.Prefab)) { warnings.Add("Entry '" + text + "' is missing required prefab."); return false; } if (!TryResolveConfiguredSpawnerPrefab(entry.Prefab, out var hasSpawnerComponents)) { warnings.Add("Entry '" + text + "' references unknown spawner prefab '" + entry.Prefab + "'."); return false; } if (!hasSpawnerComponents) { warnings.Add("Entry '" + text + "' references '" + entry.Prefab + "', but it is not a SpawnArea/CreatureSpawner prefab."); return false; } return true; } private static bool TryResolveConfiguredSpawnerPrefab(string prefabName, out bool hasSpawnerComponents) { hasSpawnerComponents = true; if ((Object)(object)ZNetScene.instance == (Object)null || string.IsNullOrWhiteSpace(prefabName)) { return true; } GameObject prefab = ZNetScene.instance.GetPrefab(prefabName.Trim()); if ((Object)(object)prefab == (Object)null) { hasSpawnerComponents = false; return false; } hasSpawnerComponents = (Object)(object)prefab.GetComponentInChildren(true) != (Object)null || (Object)(object)prefab.GetComponentInChildren(true) != (Object)null; return true; } private static SyncedSpawnerConfigurationState BuildSyncedConfigurationState(List configuration, string sourceName) { using (BeginInvalidEntryWarningSuppressionForSyncedClientBuild(sourceName)) { SyncedSpawnerConfigurationState syncedSpawnerConfigurationState = new SyncedSpawnerConfigurationState(); foreach (SpawnerConfigurationEntry item in CloneAndNormalizeConfigurationEntries(configuration, sourceName)) { if (!string.IsNullOrWhiteSpace(item.Prefab)) { RemoveEffectiveConfigurationEntry(syncedSpawnerConfigurationState.Configuration, syncedSpawnerConfigurationState.ActiveEntries, syncedSpawnerConfigurationState.ActiveEntriesByPrefab, item.Prefab, item.RuleId); if (item.Enabled) { syncedSpawnerConfigurationState.Configuration.Add(item); syncedSpawnerConfigurationState.ActiveEntries.Add(item); GetOrCreateActiveEntries(syncedSpawnerConfigurationState.ActiveEntriesByPrefab, item.Prefab).Add(item); } } } RefreshConfiguredPrefabSets(syncedSpawnerConfigurationState.ActiveEntries, syncedSpawnerConfigurationState.ConfiguredSpawnAreaPrefabs, syncedSpawnerConfigurationState.ConfiguredCreatureSpawnerPrefabs, syncedSpawnerConfigurationState.RuntimeConfiguredSpawnAreaPrefabs, syncedSpawnerConfigurationState.RuntimeConfiguredCreatureSpawnerPrefabs); syncedSpawnerConfigurationState.EntrySignaturesByPrefab = BuildActiveEntrySignaturesByPrefab(syncedSpawnerConfigurationState.ActiveEntriesByPrefab); syncedSpawnerConfigurationState.ConfigurationSignature = NetworkPayloadSyncSupport.ComputeSpawnerConfigurationSignature(syncedSpawnerConfigurationState.Configuration); return syncedSpawnerConfigurationState; } } private static SpawnerRuntimeConfigurationSnapshot BuildRuntimeConfigurationSnapshot(SyncedSpawnerConfigurationState state) { SpawnerRuntimeConfigurationSnapshot spawnerRuntimeConfigurationSnapshot = new SpawnerRuntimeConfigurationSnapshot(); foreach (KeyValuePair> item in state.ActiveEntriesByPrefab) { item.Deconstruct(out var key, out var value); string key2 = key; List list = value; CompiledSpawnerPrefabPlan compiledSpawnerPrefabPlan = new CompiledSpawnerPrefabPlan(); for (int i = 0; i < list.Count; i++) { SpawnerConfigurationEntry spawnerConfigurationEntry = list[i]; SpawnerRuntimeEntry spawnerRuntimeEntry = BuildRuntimeEntry(spawnerConfigurationEntry); if (spawnerConfigurationEntry.SpawnArea != null && HasSpawnAreaOverride(spawnerConfigurationEntry.SpawnArea)) { compiledSpawnerPrefabPlan.SpawnAreaEntries.Add(spawnerRuntimeEntry); if (string.IsNullOrWhiteSpace(spawnerRuntimeEntry.Location)) { compiledSpawnerPrefabPlan.HasUnscopedSpawnAreaEntries = true; } else { compiledSpawnerPrefabPlan.SpawnAreaSelectorLocationKeys.Add(NormalizeSelectorLocationCacheKey(spawnerRuntimeEntry.Location)); } if (spawnerRuntimeEntry.RuntimeReconcile) { compiledSpawnerPrefabPlan.DynamicSpawnAreaEntries.Add(spawnerRuntimeEntry); } } if (spawnerConfigurationEntry.CreatureSpawner != null && HasCreatureSpawnerOverride(spawnerConfigurationEntry.CreatureSpawner)) { compiledSpawnerPrefabPlan.CreatureSpawnerEntries.Add(spawnerRuntimeEntry); if (string.IsNullOrWhiteSpace(spawnerRuntimeEntry.Location)) { compiledSpawnerPrefabPlan.HasUnscopedCreatureSpawnerEntries = true; } else { compiledSpawnerPrefabPlan.CreatureSpawnerSelectorLocationKeys.Add(NormalizeSelectorLocationCacheKey(spawnerRuntimeEntry.Location)); } if (spawnerRuntimeEntry.RuntimeReconcile) { compiledSpawnerPrefabPlan.DynamicCreatureSpawnerEntries.Add(spawnerRuntimeEntry); } } } spawnerRuntimeConfigurationSnapshot.PlansByPrefab[key2] = compiledSpawnerPrefabPlan; } spawnerRuntimeConfigurationSnapshot.ConfiguredSpawnAreaPrefabs.UnionWith(state.ConfiguredSpawnAreaPrefabs); spawnerRuntimeConfigurationSnapshot.ConfiguredCreatureSpawnerPrefabs.UnionWith(state.ConfiguredCreatureSpawnerPrefabs); spawnerRuntimeConfigurationSnapshot.RuntimeConfiguredSpawnAreaPrefabs.UnionWith(state.RuntimeConfiguredSpawnAreaPrefabs); spawnerRuntimeConfigurationSnapshot.RuntimeConfiguredCreatureSpawnerPrefabs.UnionWith(state.RuntimeConfiguredCreatureSpawnerPrefabs); return spawnerRuntimeConfigurationSnapshot; } private static SpawnerRuntimeEntry BuildRuntimeEntry(SpawnerConfigurationEntry entry) { return new SpawnerRuntimeEntry { Prefab = (entry.Prefab ?? ""), RuleId = (entry.RuleId ?? ""), Location = (entry.Location ?? ""), Conditions = entry.Conditions, RuntimeReconcile = ShouldRuntimeReconcile(entry), SpawnArea = entry.SpawnArea, CreatureSpawner = entry.CreatureSpawner }; } private static SpawnerRuntimeConfigurationSnapshot GetRuntimeConfigurationSnapshot() { return Volatile.Read(ref _runtimeConfigurationSnapshot) ?? SpawnerRuntimeConfigurationSnapshot.Empty; } private static void CommitSyncedConfigurationState(SyncedSpawnerConfigurationState state, string payloadToken) { SpawnerRuntimeConfigurationSnapshot value = BuildRuntimeConfigurationSnapshot(state); ResetLoadedConfigurationState(); _configuration = state.Configuration; ActiveEntries.AddRange(state.ActiveEntries); foreach (var (key, value2) in state.ActiveEntriesByPrefab) { ActiveEntriesByPrefab[key] = value2; } foreach (string configuredSpawnAreaPrefab in state.ConfiguredSpawnAreaPrefabs) { ConfiguredSpawnAreaPrefabs.Add(configuredSpawnAreaPrefab); } foreach (string configuredCreatureSpawnerPrefab in state.ConfiguredCreatureSpawnerPrefabs) { ConfiguredCreatureSpawnerPrefabs.Add(configuredCreatureSpawnerPrefab); } foreach (string runtimeConfiguredSpawnAreaPrefab in state.RuntimeConfiguredSpawnAreaPrefabs) { RuntimeConfiguredSpawnAreaPrefabs.Add(runtimeConfiguredSpawnAreaPrefab); } foreach (string runtimeConfiguredCreatureSpawnerPrefab in state.RuntimeConfiguredCreatureSpawnerPrefabs) { RuntimeConfiguredCreatureSpawnerPrefabs.Add(runtimeConfiguredCreatureSpawnerPrefab); } ReplaceEntrySignatures(CurrentEntrySignaturesByPrefab, state.EntrySignaturesByPrefab); _configurationSignature = state.ConfigurationSignature; LoadState.LastLoadedPayload = payloadToken; LoadState.LastRejectedPayload = ""; LoadState.PendingStrictPayload = ""; LoadState.LastRejectedValidationKey = ""; Volatile.Write(ref _runtimeConfigurationSnapshot, value); Volatile.Write(ref _synchronizedPayloadReady, value: true); InvalidateTrackedSpawnerEligibility(); } private static LocalLoadResult ParseLocalConfigurationDocuments(List documents) { List list = new List(); List list2 = new List(); List list3 = new List(); int num = 0; int num2 = 0; foreach (ConfigurationLoadSupport.LocalYamlDocument document in documents) { if (document.ReadError != null) { list2.Add("Failed to read " + document.Path + ". " + document.ReadError); continue; } try { ParsedSpawnerConfigurationDocument parsedSpawnerConfigurationDocument = ParseConfiguration(document.Yaml ?? "", document.Path); list3.AddRange(parsedSpawnerConfigurationDocument.Warnings); num += parsedSpawnerConfigurationDocument.Configuration.Count; List collection = PrepareLocalConfigurationEntries(parsedSpawnerConfigurationDocument.Configuration, document.Path, list3); list.AddRange(collection); num2++; } catch (Exception ex) { list2.Add($"Failed to parse {document.Path}{FormatYamlExceptionLocation(ex)}. Spawner override YAML must start with a root list like '- prefab: ...'. {ex}"); } } return new LocalLoadResult { Entries = list, Errors = list2, Warnings = list3, ParsedEntryCount = num, LoadedFileCount = num2 }; } private static void RejectLocalConfigurationPayload(string payload, IEnumerable errors) { if (string.Equals(LoadState.LastRejectedPayload, payload, StringComparison.Ordinal)) { return; } LoadState.LastRejectedPayload = payload; LoadState.PendingStrictPayload = ""; LoadState.LastRejectedValidationKey = ""; DropNSpawnPlugin.DropNSpawnLogger.LogError((object)"Rejected spawner reload. Keeping the previous authoritative spawner configuration."); foreach (string item in errors.Where((string message) => !string.IsNullOrWhiteSpace(message)).Distinct(StringComparer.OrdinalIgnoreCase)) { DropNSpawnPlugin.DropNSpawnLogger.LogError((object)item); } } private static void LoadLocalConfiguration(List documents) { if (documents.Count == 0) { DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)"Loaded 0 spawner configuration(s) from 0 override file(s)."); return; } int num = 0; int num2 = 0; List list = new List(); foreach (ConfigurationLoadSupport.LocalYamlDocument document in documents) { if (document.ReadError != null) { DropNSpawnPlugin.DropNSpawnLogger.LogError((object)("Failed to read " + document.Path + ". " + document.ReadError)); continue; } try { ParsedSpawnerConfigurationDocument parsedSpawnerConfigurationDocument = ParseConfiguration(document.Yaml ?? "", document.Path); list.AddRange(parsedSpawnerConfigurationDocument.Warnings); List configuration = PrepareLocalConfigurationEntries(parsedSpawnerConfigurationDocument.Configuration, document.Path, list); num2 += parsedSpawnerConfigurationDocument.Configuration.Count; MergeConfiguration(configuration); num++; } catch (Exception ex) { DropNSpawnPlugin.DropNSpawnLogger.LogError((object)$"Failed to parse {document.Path}{FormatYamlExceptionLocation(ex)}. Spawner override YAML must start with a root list like '- prefab: ...'. {ex}"); } } if (list.Count > 0) { LogPartiallyAcceptedLocalConfiguration(num2, _configuration.Count, list); } DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)$"Loaded {ActiveEntries.Count} spawner configuration(s) from {num} override file(s)."); } private static void MergeConfiguration(List configuration) { foreach (SpawnerConfigurationEntry item in configuration) { if (string.IsNullOrWhiteSpace(item.Prefab)) { continue; } RemoveEffectiveConfigurationEntry(item.Prefab, item.RuleId); if (!item.Enabled) { continue; } _configuration.Add(item); ActiveEntries.Add(item); if (!ActiveEntriesByPrefab.TryGetValue(item.Prefab, out List value)) { value = new List(); ActiveEntriesByPrefab[item.Prefab] = value; } value.Add(item); if (item.SpawnArea != null && HasSpawnAreaOverride(item.SpawnArea)) { ConfiguredSpawnAreaPrefabs.Add(item.Prefab); if (ShouldRuntimeReconcile(item)) { RuntimeConfiguredSpawnAreaPrefabs.Add(item.Prefab); } } if (item.CreatureSpawner != null && HasCreatureSpawnerOverride(item.CreatureSpawner)) { ConfiguredCreatureSpawnerPrefabs.Add(item.Prefab); if (ShouldRuntimeReconcile(item)) { RuntimeConfiguredCreatureSpawnerPrefabs.Add(item.Prefab); } } } RefreshConfiguredPrefabSets(ActiveEntries, ConfiguredSpawnAreaPrefabs, ConfiguredCreatureSpawnerPrefabs, RuntimeConfiguredSpawnAreaPrefabs, RuntimeConfiguredCreatureSpawnerPrefabs); InvalidateTrackedSpawnerEligibility(); } private static void InvalidateTrackedSpawnerEligibility() { _trackedSpawnerEligibilityEpoch++; if (_trackedSpawnerEligibilityEpoch == int.MinValue) { _trackedSpawnerEligibilityEpoch = 0; } } private static void RemoveEffectiveConfigurationEntry(string prefabName, string ruleId) { RemoveEffectiveConfigurationEntry(_configuration, ActiveEntries, ActiveEntriesByPrefab, prefabName, ruleId); } private static void RemoveEffectiveConfigurationEntry(List configuration, List activeEntries, Dictionary> activeEntriesByPrefab, string prefabName, string ruleId) { for (int num = configuration.Count - 1; num >= 0; num--) { SpawnerConfigurationEntry spawnerConfigurationEntry = configuration[num]; if (string.Equals(spawnerConfigurationEntry.Prefab, prefabName, StringComparison.OrdinalIgnoreCase) && string.Equals(spawnerConfigurationEntry.RuleId, ruleId, StringComparison.Ordinal)) { configuration.RemoveAt(num); } } for (int num2 = activeEntries.Count - 1; num2 >= 0; num2--) { SpawnerConfigurationEntry spawnerConfigurationEntry2 = activeEntries[num2]; if (string.Equals(spawnerConfigurationEntry2.Prefab, prefabName, StringComparison.OrdinalIgnoreCase) && string.Equals(spawnerConfigurationEntry2.RuleId, ruleId, StringComparison.Ordinal)) { activeEntries.RemoveAt(num2); } } if (!activeEntriesByPrefab.TryGetValue(prefabName, out List value)) { return; } for (int num3 = value.Count - 1; num3 >= 0; num3--) { if (string.Equals(value[num3].RuleId, ruleId, StringComparison.Ordinal)) { value.RemoveAt(num3); } } if (value.Count == 0) { activeEntriesByPrefab.Remove(prefabName); } } private static List GetOrCreateActiveEntries(Dictionary> activeEntriesByPrefab, string prefabName) { if (!activeEntriesByPrefab.TryGetValue(prefabName, out List value)) { value = (activeEntriesByPrefab[prefabName] = new List()); } return value; } private static void RefreshConfiguredPrefabSets(IEnumerable entries, HashSet configuredSpawnAreaPrefabs, HashSet configuredCreatureSpawnerPrefabs, HashSet runtimeConfiguredSpawnAreaPrefabs, HashSet runtimeConfiguredCreatureSpawnerPrefabs) { configuredSpawnAreaPrefabs.Clear(); configuredCreatureSpawnerPrefabs.Clear(); runtimeConfiguredSpawnAreaPrefabs.Clear(); runtimeConfiguredCreatureSpawnerPrefabs.Clear(); foreach (SpawnerConfigurationEntry entry in entries) { if (entry.SpawnArea != null && HasSpawnAreaOverride(entry.SpawnArea)) { configuredSpawnAreaPrefabs.Add(entry.Prefab); if (ShouldRuntimeReconcile(entry)) { runtimeConfiguredSpawnAreaPrefabs.Add(entry.Prefab); } } if (entry.CreatureSpawner != null && HasCreatureSpawnerOverride(entry.CreatureSpawner)) { configuredCreatureSpawnerPrefabs.Add(entry.Prefab); if (ShouldRuntimeReconcile(entry)) { runtimeConfiguredCreatureSpawnerPrefabs.Add(entry.Prefab); } } } } private static ParsedSpawnerConfigurationDocument ParseConfiguration(string yaml, string? sourcePath) { ParsedSpawnerConfigurationDocument parsedSpawnerConfigurationDocument = new ParsedSpawnerConfigurationDocument(); if (string.IsNullOrWhiteSpace(yaml)) { return parsedSpawnerConfigurationDocument; } checked { using StringReader input = new StringReader(yaml); YamlStream yamlStream = new YamlStream(); yamlStream.Load(input); if (yamlStream.Documents.Count == 0) { return parsedSpawnerConfigurationDocument; } YamlSequenceNode obj = yamlStream.Documents[0].RootNode as YamlSequenceNode; if (obj == null) { Mark start = yamlStream.Documents[0].RootNode.Start; Mark end = yamlStream.Documents[0].RootNode.End; throw new YamlException(in start, in end, "Spawner override YAML root must be a sequence."); } foreach (YamlNode child in obj.Children) { if (!(child is YamlMappingNode yamlMappingNode)) { parsedSpawnerConfigurationDocument.Warnings.Add("Skipped spawner YAML node at " + FormatYamlNodeLocation(sourcePath, child.Start) + ". Expected a list item object like '- prefab: Fox' but found " + DescribeYamlNode(child) + "."); continue; } try { string input2 = SerializeYamlNode(yamlMappingNode); SpawnerConfigurationEntry spawnerConfigurationEntry = Deserializer.Deserialize(input2) ?? new SpawnerConfigurationEntry(); spawnerConfigurationEntry.SourceLine = (int)yamlMappingNode.Start.Line; spawnerConfigurationEntry.SourceColumn = (int)yamlMappingNode.Start.Column; parsedSpawnerConfigurationDocument.Configuration.Add(spawnerConfigurationEntry); } catch (Exception ex) { parsedSpawnerConfigurationDocument.Warnings.Add("Skipped invalid spawner entry at " + FormatYamlNodeLocation(sourcePath, yamlMappingNode.Start) + ". " + FormatEntryParseFailure(ex)); } } return parsedSpawnerConfigurationDocument; } } private static string SerializeYamlNode(YamlNode node) { YamlStream yamlStream = new YamlStream(new YamlDocument(node)); using StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture); yamlStream.Save(stringWriter, assignAnchors: false); return stringWriter.ToString(); } private static string DescribeYamlNode(YamlNode node) { if (node is YamlScalarNode yamlScalarNode) { string text = yamlScalarNode.Value ?? ""; if (text.Length != 0) { return "scalar '" + text + "'"; } return "an empty scalar"; } if (node is YamlSequenceNode) { return "a nested sequence"; } if (node is YamlMappingNode) { return "a mapping"; } return "an unknown YAML node"; } private static string FormatYamlNodeLocation(string? sourcePath, Mark mark) { string text = (string.IsNullOrWhiteSpace(sourcePath) ? "inline YAML" : Path.GetFileName(sourcePath)); if (mark.Line > 0) { text = text + ":" + mark.Line.ToString(CultureInfo.InvariantCulture); } return text; } private static string FormatEntryParseFailure(Exception ex) { if (ex is YamlException ex2) { return ex2.Message; } return ex.Message; } private static void NormalizeEntry(SpawnerConfigurationEntry entry) { entry.Prefab = (entry.Prefab ?? "").Trim(); entry.Location = NormalizeOptionalString(entry.Location); NormalizeSpawnerConditions(entry.Conditions, entry.Prefab + ".conditions", allowCreatureSpawnerRuntimeOverlapKeys: true); if (entry.SpawnArea != null) { if (entry.SpawnArea.MaxTotalSpawns.HasValue) { entry.SpawnArea.MaxTotalSpawns = ClampSpawnAreaMaxTotalSpawns(entry.SpawnArea.MaxTotalSpawns.Value); } if (entry.SpawnArea.Creatures != null) { for (int i = 0; i < entry.SpawnArea.Creatures.Count; i++) { SpawnAreaSpawnDefinition spawnAreaSpawnDefinition = entry.SpawnArea.Creatures[i]; spawnAreaSpawnDefinition.Creature = (spawnAreaSpawnDefinition.Creature ?? "").Trim(); spawnAreaSpawnDefinition.Data = NormalizeOptionalString(spawnAreaSpawnDefinition.Data); spawnAreaSpawnDefinition.Fields = NormalizeOptionalStringDictionary(spawnAreaSpawnDefinition.Fields); spawnAreaSpawnDefinition.Objects = NormalizeOptionalStringList(spawnAreaSpawnDefinition.Objects); IntRangeDefinition? level = spawnAreaSpawnDefinition.Level; if (level != null && level.HasValues()) { spawnAreaSpawnDefinition.MinLevel = RangeFormatting.GetMin(spawnAreaSpawnDefinition.Level, spawnAreaSpawnDefinition.MinLevel); spawnAreaSpawnDefinition.MaxLevel = RangeFormatting.GetMax(spawnAreaSpawnDefinition.Level, spawnAreaSpawnDefinition.MinLevel, spawnAreaSpawnDefinition.MaxLevel); } spawnAreaSpawnDefinition.Faction = FactionIntegration.Normalize(spawnAreaSpawnDefinition.Faction); } } } if (entry.CreatureSpawner != null) { NormalizeCreatureSpawnerEntryConditions(entry.Conditions, entry.Prefab + ".conditions"); IntRangeDefinition? level2 = entry.CreatureSpawner.Level; if (level2 != null && level2.HasValues()) { entry.CreatureSpawner.MinLevel = RangeFormatting.GetMin(entry.CreatureSpawner.Level, entry.CreatureSpawner.MinLevel); entry.CreatureSpawner.MaxLevel = RangeFormatting.GetMax(entry.CreatureSpawner.Level, entry.CreatureSpawner.MinLevel, entry.CreatureSpawner.MaxLevel); } entry.CreatureSpawner.Data = NormalizeOptionalString(entry.CreatureSpawner.Data); entry.CreatureSpawner.Fields = NormalizeOptionalStringDictionary(entry.CreatureSpawner.Fields); entry.CreatureSpawner.Objects = NormalizeOptionalStringList(entry.CreatureSpawner.Objects); entry.CreatureSpawner.Faction = FactionIntegration.Normalize(entry.CreatureSpawner.Faction); entry.CreatureSpawner.TimeOfDay?.Normalize(); entry.CreatureSpawner.Creature = entry.CreatureSpawner.Creature?.Trim(); entry.CreatureSpawner.RequiredGlobalKey = entry.CreatureSpawner.RequiredGlobalKey?.Trim(); entry.CreatureSpawner.BlockingGlobalKey = entry.CreatureSpawner.BlockingGlobalKey?.Trim(); } entry.RuleId = NormalizeOptionalRuleId(entry.RuleId) ?? BuildRuleId(entry); } private static string BuildRuleId(SpawnerConfigurationEntry entry) { SpawnerConfigurationEntry entry2 = new SpawnerConfigurationEntry { Prefab = entry.Prefab, Enabled = true, Location = entry.Location, Conditions = entry.Conditions, SpawnArea = entry.SpawnArea, CreatureSpawner = entry.CreatureSpawner }; return entry.Prefab + ":" + NetworkPayloadSyncSupport.ComputeSpawnerEntryIdentitySignature(entry2); } private static string? NormalizeOptionalString(string? value) { if (value == null) { return null; } string text = value.Trim(); if (text.Length != 0) { return text; } return null; } private static string? NormalizeOptionalRuleId(string? ruleId) { if (ruleId == null) { return null; } string text = ruleId.Trim(); if (text.Length != 0) { return text; } return null; } private static List? NormalizeOptionalStringList(List? values) { if (values == null) { return null; } List list = (from value in values select (value ?? "").Trim() into value where value.Length > 0 select value).ToList(); if (list.Count != 0) { return list; } return null; } private static Dictionary? NormalizeOptionalStringDictionary(Dictionary? values) { if (values == null) { return null; } Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); foreach (KeyValuePair value in values) { object obj; string text3; (obj, text3) = (KeyValuePair)(ref value); if (obj == null) { obj = ""; } string text4 = ((string)obj).Trim(); if (text4.Length != 0) { dictionary[text4] = (text3 ?? "").Trim(); } } if (dictionary.Count != 0) { return dictionary; } return null; } private static void NormalizeSpawnerConditions(ConditionsDefinition? conditions, string context, bool allowCreatureSpawnerRuntimeOverlapKeys) { if (conditions == null) { return; } List? locations = conditions.Locations; if (locations != null && locations.Count > 0) { WarnInvalidEntry("Entry '" + context + "' uses conditions.locations, but spawner entries use the top-level location selector. The key was ignored."); conditions.Locations = null; } IntRangeDefinition? level = conditions.Level; if ((level != null && level.HasValues()) || conditions.MinLevel.HasValue) { WarnInvalidEntry("Entry '" + context + "' uses conditions.level, but level filters are not supported for spawner target conditions. The key was ignored."); conditions.Level = null; conditions.MinLevel = null; } if (conditions.MaxLevel.HasValue) { conditions.MaxLevel = null; } List? states = conditions.States; if (states != null && states.Count > 0) { WarnInvalidEntry("Entry '" + context + "' uses conditions.states, but state filters are only valid for character-drop conditions. The key was ignored."); conditions.States = null; } List? factions = conditions.Factions; if (factions != null && factions.Count > 0) { WarnInvalidEntry("Entry '" + context + "' uses conditions.factions, but faction filters are only valid for character-drop conditions. The key was ignored."); conditions.Factions = null; } if (!allowCreatureSpawnerRuntimeOverlapKeys) { if (conditions.TimeOfDay != null) { WarnInvalidEntry("Entry '" + context + "' uses conditions.timeOfDay, but creatureSpawner uses creatureSpawner.timeOfDay for runtime time-of-day gating. The key was ignored."); conditions.TimeOfDay = null; } if (conditions.InsidePlayerBase.HasValue) { WarnInvalidEntry("Entry '" + context + "' uses conditions.insidePlayerBase, but creatureSpawner uses allowInsidePlayerBase for runtime player-base gating. The key was ignored."); conditions.InsidePlayerBase = null; } List? requiredGlobalKeys = conditions.RequiredGlobalKeys; if (requiredGlobalKeys != null && requiredGlobalKeys.Count > 0) { WarnInvalidEntry("Entry '" + context + "' uses conditions.requiredGlobalKeys, but creatureSpawner uses requiredGlobalKey for runtime global-key gating. The key was ignored."); conditions.RequiredGlobalKeys = null; } List? forbiddenGlobalKeys = conditions.ForbiddenGlobalKeys; if (forbiddenGlobalKeys != null && forbiddenGlobalKeys.Count > 0) { WarnInvalidEntry("Entry '" + context + "' uses conditions.forbiddenGlobalKeys, but creatureSpawner uses blockingGlobalKey for runtime global-key blocking. The key was ignored."); conditions.ForbiddenGlobalKeys = null; } } } private static void NormalizeCreatureSpawnerEntryConditions(ConditionsDefinition? conditions, string context) { if (conditions != null) { if (conditions.TimeOfDay != null) { WarnInvalidEntry("Entry '" + context + "' uses conditions.timeOfDay, but creatureSpawner uses creatureSpawner.timeOfDay for runtime time-of-day gating. The key was ignored."); conditions.TimeOfDay = null; } if (conditions.InsidePlayerBase.HasValue) { WarnInvalidEntry("Entry '" + context + "' uses conditions.insidePlayerBase, but creatureSpawner does not support inside-only top-level player-base gating. Use allowInsidePlayerBase for the runtime permission flag instead. The key was ignored."); conditions.InsidePlayerBase = null; } List? requiredGlobalKeys = conditions.RequiredGlobalKeys; if (requiredGlobalKeys != null && requiredGlobalKeys.Count > 0) { WarnInvalidEntry("Entry '" + context + "' uses conditions.requiredGlobalKeys, but creatureSpawner uses requiredGlobalKey for runtime global-key gating. The key was ignored."); conditions.RequiredGlobalKeys = null; } List? forbiddenGlobalKeys = conditions.ForbiddenGlobalKeys; if (forbiddenGlobalKeys != null && forbiddenGlobalKeys.Count > 0) { WarnInvalidEntry("Entry '" + context + "' uses conditions.forbiddenGlobalKeys, but creatureSpawner uses blockingGlobalKey for runtime global-key blocking. The key was ignored."); conditions.ForbiddenGlobalKeys = null; } } } private static bool HasDuplicateSelector(List entries, SpawnerConfigurationEntry candidate) { foreach (SpawnerConfigurationEntry entry in entries) { if (string.Equals(entry.Location, candidate.Location, StringComparison.OrdinalIgnoreCase)) { bool num = entry.SpawnArea != null && candidate.SpawnArea != null && HasSpawnAreaOverride(entry.SpawnArea) && HasSpawnAreaOverride(candidate.SpawnArea); bool flag = entry.CreatureSpawner != null && candidate.CreatureSpawner != null && HasCreatureSpawnerOverride(entry.CreatureSpawner) && HasCreatureSpawnerOverride(candidate.CreatureSpawner); if (num || flag) { return true; } } } return false; } [IteratorStateMachine(typeof(d__155))] private static IEnumerable EnumerateOverrideConfigurationPaths() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__155(-2); } private static IEnumerable EnumerateSupplementalOverrideConfigurationPaths() { return DomainConfigurationFileSupport.EnumerateSupplementalOverrideConfigurationPaths("spawner", IsOverrideConfigurationFileName); } private static bool IsOverrideConfigurationFileName(string fileName) { if (string.IsNullOrWhiteSpace(fileName)) { return false; } if (!fileName.Equals(PluginSettingsFacade.GetYamlDomainFilePrefix("spawner") + ".yml", StringComparison.OrdinalIgnoreCase) && !fileName.Equals(PluginSettingsFacade.GetYamlDomainFilePrefix("spawner") + ".yaml", StringComparison.OrdinalIgnoreCase)) { if (fileName.StartsWith(PluginSettingsFacade.GetYamlDomainSupplementalPrefix("spawner"), StringComparison.OrdinalIgnoreCase)) { if (!fileName.EndsWith(".yml", StringComparison.OrdinalIgnoreCase)) { return fileName.EndsWith(".yaml", StringComparison.OrdinalIgnoreCase); } return true; } return false; } return true; } private static void CaptureSnapshotsIfNeeded() { if (_snapshotsCaptured) { return; } foreach (GameObject item in EnumerateRootPrefabs()) { CaptureSpawnAreaSnapshots(item); CaptureCreatureSpawnerSnapshots(item); CapturedRootPrefabNames.Add(((Object)item).name); } _snapshotsCaptured = true; DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)$"Captured {SpawnAreaSnapshots.Count} SpawnArea snapshot(s) and {CreatureSpawnerSnapshots.Count} CreatureSpawner snapshot(s)."); } private static void ResetReferenceSnapshots() { SpawnAreaSnapshots.Clear(); CreatureSpawnerSnapshots.Clear(); SpawnAreaSnapshotsByExactKey.Clear(); CreatureSpawnerSnapshotsByExactKey.Clear(); SpawnAreaSnapshotsByName.Clear(); CreatureSpawnerSnapshotsByName.Clear(); CapturedRootPrefabNames.Clear(); _snapshotsCaptured = false; } private static void ResetRuntimeState(bool preserveLiveRegistries) { ClearQueuedReconcileState(); LiveReconcilerState.Clear(); LiveRegistryStore.ClearRuntimeView(); SpawnAreaCatalogsByExactKey.Clear(); CreatureSpawnerCatalogsByExactKey.Clear(); SelectorCacheStore.Clear(); RuntimeStateStore.Clear(); ProvenanceRegistry.Clear(clearCurrentContexts: true); if (!preserveLiveRegistries) { LiveRegistryStore.ClearLiveRegistries(); } else { RebuildTrackedSpawnerLocationBuckets(); } } private static void RebuildTrackedSpawnerLocationBuckets() { SpawnerRuntimeConfigurationSnapshot runtimeConfigurationSnapshot = GetRuntimeConfigurationSnapshot(); LiveRegistryStore.ForEachTrackedSpawnArea(delegate(SpawnArea spawnArea, string prefabName) { if (!((Object)(object)((Component)spawnArea).gameObject == (Object)null) && !string.IsNullOrWhiteSpace(prefabName)) { RefreshSpawnAreaLocationBucketMembership(spawnArea, runtimeConfigurationSnapshot); } }); LiveRegistryStore.ForEachTrackedCreatureSpawner(delegate(CreatureSpawner creatureSpawner, string prefabName) { if (!((Object)(object)((Component)creatureSpawner).gameObject == (Object)null) && !string.IsNullOrWhiteSpace(prefabName)) { RefreshCreatureSpawnerLocationBucketMembership(creatureSpawner, runtimeConfigurationSnapshot); } }); } private static void RefreshSnapshots() { ResetReferenceSnapshots(); CaptureSnapshotsIfNeeded(); } private static void EnsureSnapshotsCapturedForRootPrefab(string? rootPrefabName) { if (_snapshotsCaptured || string.IsNullOrWhiteSpace(rootPrefabName) || (Object)(object)ZNetScene.instance == (Object)null) { return; } if (!CapturedRootPrefabNames.Contains(rootPrefabName)) { GameObject prefab = ZNetScene.instance.GetPrefab(rootPrefabName); if ((Object)(object)prefab == (Object)null || ((Object)prefab).name.StartsWith("JVLmock_", StringComparison.OrdinalIgnoreCase)) { CapturedRootPrefabNames.Add(rootPrefabName); return; } CaptureSpawnAreaSnapshots(prefab); CaptureCreatureSpawnerSnapshots(prefab); CapturedRootPrefabNames.Add(rootPrefabName); } } [IteratorStateMachine(typeof(d__164))] private static IEnumerable EnumerateRootPrefabs() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__164(-2); } private static void CaptureSpawnAreaSnapshots(GameObject rootPrefab) { SpawnArea[] componentsInChildren = rootPrefab.GetComponentsInChildren(true); foreach (SpawnArea val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).gameObject == (Object)null)) { SpawnAreaComponentSnapshot spawnAreaComponentSnapshot = new SpawnAreaComponentSnapshot { Component = val, ConfigPrefabName = ((Object)((Component)val).gameObject).name, RootPrefabName = ((Object)rootPrefab).name, RelativePath = GetRelativePath(rootPrefab.transform, ((Component)val).transform), LevelUpChance = val.m_levelupChance, SpawnInterval = val.m_spawnIntervalSec, TriggerDistance = val.m_triggerDistance, SetPatrolSpawnPoint = val.m_setPatrolSpawnPoint, SpawnRadius = val.m_spawnRadius, NearRadius = val.m_nearRadius, FarRadius = val.m_farRadius, MaxNear = val.m_maxNear, MaxTotal = val.m_maxTotal, OnGroundOnly = val.m_onGroundOnly, Prefabs = CloneSpawnAreaSnapshots(val.m_prefabs) }; SpawnAreaSnapshots.Add(spawnAreaComponentSnapshot); SpawnAreaSnapshotsByExactKey[BuildExactKey(spawnAreaComponentSnapshot.RootPrefabName, spawnAreaComponentSnapshot.RelativePath, "SpawnArea")] = spawnAreaComponentSnapshot; AddSnapshotByName(SpawnAreaSnapshotsByName, spawnAreaComponentSnapshot.ConfigPrefabName, spawnAreaComponentSnapshot); } } } private static void CaptureCreatureSpawnerSnapshots(GameObject rootPrefab) { CreatureSpawner[] componentsInChildren = rootPrefab.GetComponentsInChildren(true); foreach (CreatureSpawner val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).gameObject == (Object)null)) { CreatureSpawnerComponentSnapshot creatureSpawnerComponentSnapshot = new CreatureSpawnerComponentSnapshot { Component = val, ConfigPrefabName = ((Object)((Component)val).gameObject).name, RootPrefabName = ((Object)rootPrefab).name, RelativePath = GetRelativePath(rootPrefab.transform, ((Component)val).transform), CreaturePrefab = val.m_creaturePrefab, MinLevel = val.m_minLevel, MaxLevel = val.m_maxLevel, LevelUpChance = val.m_levelupChance, RespawnTimeMinutes = val.m_respawnTimeMinuts, TriggerDistance = val.m_triggerDistance, TriggerNoise = val.m_triggerNoise, SpawnAtNight = val.m_spawnAtNight, SpawnAtDay = val.m_spawnAtDay, RequireSpawnArea = val.m_requireSpawnArea, SpawnInPlayerBase = val.m_spawnInPlayerBase, WakeUpAnimation = val.m_wakeUpAnimation, SpawnCheckInterval = val.m_spawnInterval, RequiredGlobalKey = (val.m_requiredGlobalKey ?? ""), BlockingGlobalKey = (val.m_blockingGlobalKey ?? ""), SetPatrolSpawnPoint = val.m_setPatrolSpawnPoint, SpawnGroupId = val.m_spawnGroupID, MaxGroupSpawned = val.m_maxGroupSpawned, SpawnGroupRadius = val.m_spawnGroupRadius, SpawnerWeight = val.m_spawnerWeight }; CreatureSpawnerSnapshots.Add(creatureSpawnerComponentSnapshot); CreatureSpawnerSnapshotsByExactKey[BuildExactKey(creatureSpawnerComponentSnapshot.RootPrefabName, creatureSpawnerComponentSnapshot.RelativePath, "CreatureSpawner")] = creatureSpawnerComponentSnapshot; AddSnapshotByName(CreatureSpawnerSnapshotsByName, creatureSpawnerComponentSnapshot.ConfigPrefabName, creatureSpawnerComponentSnapshot); } } } private static List CloneSpawnAreaSnapshots(List prefabs) { List list = new List(); if (prefabs == null) { return list; } foreach (SpawnData prefab in prefabs) { list.Add(new SpawnAreaSpawnSnapshot { Prefab = prefab.m_prefab, Weight = prefab.m_weight, MinLevel = prefab.m_minLevel, MaxLevel = prefab.m_maxLevel }); } return list; } private static void ApplyIfReady(bool queueLiveReconcile = false) { if (IsGameDataReady() && (DropNSpawnPlugin.IsSourceOfTruth || Volatile.Read(ref _synchronizedPayloadReady))) { HashSet availablePrefabs = BuildCurrentSpawnerReferencePrefabKeys().ToHashSet(StringComparer.OrdinalIgnoreCase); int num = ComputeGameDataSignature(availablePrefabs); bool flag = ShouldApplyLocally(); Dictionary currentEntrySignatures = CloneCurrentEntrySignaturesByPrefab(); if (!StandardDomainApplySupport.IsAlreadyApplied(_lastAppliedGameDataSignature, num, _lastAppliedDomainEnabled, flag, _lastAppliedConfigurationSignature, _configurationSignature) || _lastAppliedSynchronizedPayloadReady != Volatile.Read(ref _synchronizedPayloadReady)) { RunApplyCoordinator(availablePrefabs, num, flag, currentEntrySignatures, queueLiveReconcile); } } } private static void ValidateConfiguredPrefabs(HashSet availablePrefabs) { foreach (var (text2, list2) in ActiveEntriesByPrefab) { if (availablePrefabs.Contains(text2)) { continue; } foreach (SpawnerConfigurationEntry item in list2) { WarnInvalidEntry("Spawner prefab '" + text2 + "' from " + DescribeEntrySource(item) + " was not found among SpawnArea/CreatureSpawner prefabs."); } } } private static void RecordAppliedState(int gameDataSignature, bool domainEnabled, Dictionary currentEntrySignatures) { _lastAppliedGameDataSignature = gameDataSignature; _lastAppliedDomainEnabled = domainEnabled; _lastAppliedConfigurationSignature = _configurationSignature; _lastAppliedSynchronizedPayloadReady = Volatile.Read(ref _synchronizedPayloadReady); ReplaceEntrySignatures(_lastAppliedEntrySignaturesByPrefab, currentEntrySignatures); } private static Dictionary CloneCurrentEntrySignaturesByPrefab() { return new Dictionary(CurrentEntrySignaturesByPrefab, StringComparer.OrdinalIgnoreCase); } private static HashSet BuildLastAppliedPrefabs() { HashSet hashSet = new HashSet(StringComparer.OrdinalIgnoreCase); if (!_lastAppliedDomainEnabled.GetValueOrDefault()) { return hashSet; } foreach (string key in _lastAppliedEntrySignaturesByPrefab.Keys) { hashSet.Add(key); } return hashSet; } private static Dictionary BuildActiveEntrySignaturesByPrefab() { return BuildActiveEntrySignaturesByPrefab(ActiveEntriesByPrefab); } private static Dictionary BuildActiveEntrySignaturesByPrefab(Dictionary> activeEntriesByPrefab) { return DomainEntrySignatureSupport.BuildSignaturesByKey(activeEntriesByPrefab, NetworkPayloadSyncSupport.ComputeSpawnerConfigurationSignature); } private static HashSet BuildDirtyPrefabs(Dictionary previous, Dictionary current) { return DomainDictionaryDiffSupport.BuildDirtyKeys(previous, current); } private static HashSet BuildRegisteredCatchupPrefabs(bool domainEnabled, Dictionary currentEntrySignatures) { HashSet hashSet = new HashSet(StringComparer.OrdinalIgnoreCase); if (domainEnabled) { foreach (string key in currentEntrySignatures.Keys) { hashSet.Add(key); } } if (_lastAppliedDomainEnabled.GetValueOrDefault()) { foreach (string key2 in _lastAppliedEntrySignaturesByPrefab.Keys) { hashSet.Add(key2); } } return hashSet; } private static void ReplaceEntrySignatures(Dictionary target, Dictionary source) { DomainDictionaryDiffSupport.ReplaceEntries(target, source); } private static void ReapplyRegisteredLiveObjects(bool domainEnabled, HashSet prefabs) { SpawnerRuntimeConfigurationSnapshot runtimeConfigurationSnapshot = GetRuntimeConfigurationSnapshot(); string configPrefabName; foreach (SpawnArea registeredSpawnArea in GetRegisteredSpawnAreas(prefabs, runtimeConfigurationSnapshot)) { TrackSpawnAreaInstanceInternal(registeredSpawnArea); if (domainEnabled && TryGetActiveSpawnAreaEntries(registeredSpawnArea, out IReadOnlyList entries, out configPrefabName)) { ReconcileSpawnAreaInstanceInternal(registeredSpawnArea, entries); } else { RestoreSpawnAreaInstance(registeredSpawnArea); } } foreach (CreatureSpawner registeredCreatureSpawner in GetRegisteredCreatureSpawners(prefabs, runtimeConfigurationSnapshot)) { TrackCreatureSpawnerInstanceInternal(registeredCreatureSpawner); if (domainEnabled && TryGetActiveCreatureSpawnerEntries(registeredCreatureSpawner, out IReadOnlyList entries2, out configPrefabName)) { ReconcileCreatureSpawnerInstanceInternal(registeredCreatureSpawner, entries2); } else { RestoreCreatureSpawnerInstance(registeredCreatureSpawner, refreshRuntimeState: true); } } } private static void ReapplyOrQueueRegisteredLiveObjects(bool domainEnabled, HashSet prefabs) { SpawnerRuntimeConfigurationSnapshot runtimeConfigurationSnapshot = GetRuntimeConfigurationSnapshot(); foreach (SpawnArea registeredSpawnArea in GetRegisteredSpawnAreas(prefabs, runtimeConfigurationSnapshot)) { TrackSpawnAreaInstanceInternal(registeredSpawnArea); if (domainEnabled && TryGetActiveSpawnAreaEntryCache(registeredSpawnArea, runtimeConfigurationSnapshot, out MatchingEntryCache entryCache, out string configPrefabName)) { if (runtimeConfigurationSnapshot.RuntimeConfiguredSpawnAreaPrefabs.Contains(configPrefabName)) { QueueSpawnAreaReconcile(registeredSpawnArea); } else { ReconcileSpawnAreaInstanceInternal(registeredSpawnArea, entryCache.Entries, entryCache); } } else { RestoreSpawnAreaInstance(registeredSpawnArea); } } foreach (CreatureSpawner registeredCreatureSpawner in GetRegisteredCreatureSpawners(prefabs, runtimeConfigurationSnapshot)) { TrackCreatureSpawnerInstanceInternal(registeredCreatureSpawner); if (domainEnabled && TryGetActiveCreatureSpawnerEntryCache(registeredCreatureSpawner, runtimeConfigurationSnapshot, out MatchingEntryCache entryCache2, out string configPrefabName2)) { if (runtimeConfigurationSnapshot.RuntimeConfiguredCreatureSpawnerPrefabs.Contains(configPrefabName2)) { QueueCreatureSpawnerReconcile(registeredCreatureSpawner); } else { ReconcileCreatureSpawnerInstanceInternal(registeredCreatureSpawner, entryCache2.Entries, entryCache2); } } else { RestoreCreatureSpawnerInstance(registeredCreatureSpawner, refreshRuntimeState: true); } } } private static bool TryGetTargetedSelectorLocationKeys(SpawnerRuntimeConfigurationSnapshot? runtimeConfigurationSnapshot, string prefabName, bool forSpawnArea, out HashSet? selectorLocationKeys) { selectorLocationKeys = null; if (runtimeConfigurationSnapshot == null || string.IsNullOrWhiteSpace(prefabName) || !runtimeConfigurationSnapshot.PlansByPrefab.TryGetValue(prefabName, out CompiledSpawnerPrefabPlan value)) { return false; } if (forSpawnArea) { if (value.HasUnscopedSpawnAreaEntries || value.SpawnAreaSelectorLocationKeys.Count == 0) { return false; } selectorLocationKeys = value.SpawnAreaSelectorLocationKeys; return true; } if (value.HasUnscopedCreatureSpawnerEntries || value.CreatureSpawnerSelectorLocationKeys.Count == 0) { return false; } selectorLocationKeys = value.CreatureSpawnerSelectorLocationKeys; return true; } private static void RestoreSpawnArea(SpawnArea target, SpawnAreaComponentSnapshot snapshot) { ClearAppliedSpawnAreaPostSpawnOverrides(target); ClearAppliedSpawnAreaTotalSpawnLimit(target); RestoreSpawnAreaValues(target, snapshot.LevelUpChance, snapshot.SpawnInterval, snapshot.TriggerDistance, snapshot.SetPatrolSpawnPoint, snapshot.SpawnRadius, snapshot.NearRadius, snapshot.FarRadius, snapshot.MaxNear, snapshot.MaxTotal, snapshot.OnGroundOnly, snapshot.Prefabs); } private static void RestoreSpawnArea(SpawnArea target, SpawnAreaLiveSnapshot snapshot) { ClearAppliedSpawnAreaPostSpawnOverrides(target); ClearAppliedSpawnAreaTotalSpawnLimit(target); RestoreSpawnAreaValues(target, snapshot.LevelUpChance, snapshot.SpawnInterval, snapshot.TriggerDistance, snapshot.SetPatrolSpawnPoint, snapshot.SpawnRadius, snapshot.NearRadius, snapshot.FarRadius, snapshot.MaxNear, snapshot.MaxTotal, snapshot.OnGroundOnly, snapshot.Prefabs); } private static void RestoreCreatureSpawner(CreatureSpawner target, CreatureSpawnerComponentSnapshot snapshot) { LiveReconcilerState.ClearAppliedCreatureSpawnerOverrides(target); RestoreCreatureSpawnerValues(target, snapshot.CreaturePrefab, snapshot.MinLevel, snapshot.MaxLevel, snapshot.LevelUpChance, snapshot.RespawnTimeMinutes, snapshot.TriggerDistance, snapshot.TriggerNoise, snapshot.SpawnAtNight, snapshot.SpawnAtDay, snapshot.RequireSpawnArea, snapshot.SpawnInPlayerBase, snapshot.WakeUpAnimation, snapshot.SpawnCheckInterval, snapshot.RequiredGlobalKey, snapshot.BlockingGlobalKey, snapshot.SetPatrolSpawnPoint, snapshot.SpawnGroupId, snapshot.MaxGroupSpawned, snapshot.SpawnGroupRadius, snapshot.SpawnerWeight); } private static void RestoreCreatureSpawner(CreatureSpawner target, CreatureSpawnerLiveSnapshot snapshot) { LiveReconcilerState.ClearAppliedCreatureSpawnerOverrides(target); RestoreCreatureSpawnerValues(target, snapshot.CreaturePrefab, snapshot.MinLevel, snapshot.MaxLevel, snapshot.LevelUpChance, snapshot.RespawnTimeMinutes, snapshot.TriggerDistance, snapshot.TriggerNoise, snapshot.SpawnAtNight, snapshot.SpawnAtDay, snapshot.RequireSpawnArea, snapshot.SpawnInPlayerBase, snapshot.WakeUpAnimation, snapshot.SpawnCheckInterval, snapshot.RequiredGlobalKey, snapshot.BlockingGlobalKey, snapshot.SetPatrolSpawnPoint, snapshot.SpawnGroupId, snapshot.MaxGroupSpawned, snapshot.SpawnGroupRadius, snapshot.SpawnerWeight); } private static void RestoreSpawnAreaValues(SpawnArea target, float levelUpChance, float spawnInterval, float triggerDistance, bool setPatrolSpawnPoint, float spawnRadius, float nearRadius, float farRadius, int maxNear, int maxTotal, bool onGroundOnly, List prefabs) { target.m_levelupChance = levelUpChance; target.m_spawnIntervalSec = spawnInterval; target.m_triggerDistance = triggerDistance; target.m_setPatrolSpawnPoint = setPatrolSpawnPoint; target.m_spawnRadius = spawnRadius; target.m_nearRadius = nearRadius; target.m_farRadius = farRadius; target.m_maxNear = maxNear; target.m_maxTotal = maxTotal; target.m_onGroundOnly = onGroundOnly; target.m_prefabs = BuildSpawnAreaPrefabs(prefabs); } private static void RestoreCreatureSpawnerValues(CreatureSpawner target, GameObject? creaturePrefab, int minLevel, int maxLevel, float levelUpChance, float respawnTimeMinutes, float triggerDistance, float triggerNoise, bool spawnAtNight, bool spawnAtDay, bool requireSpawnArea, bool spawnInPlayerBase, bool wakeUpAnimation, int spawnCheckInterval, string requiredGlobalKey, string blockingGlobalKey, bool setPatrolSpawnPoint, int spawnGroupId, int maxGroupSpawned, float spawnGroupRadius, float spawnerWeight) { target.m_creaturePrefab = creaturePrefab; target.m_minLevel = minLevel; target.m_maxLevel = maxLevel; target.m_levelupChance = levelUpChance; target.m_respawnTimeMinuts = respawnTimeMinutes; target.m_triggerDistance = triggerDistance; target.m_triggerNoise = triggerNoise; target.m_spawnAtNight = spawnAtNight; target.m_spawnAtDay = spawnAtDay; target.m_requireSpawnArea = requireSpawnArea; target.m_spawnInPlayerBase = spawnInPlayerBase; target.m_wakeUpAnimation = wakeUpAnimation; target.m_spawnInterval = Math.Max(1, spawnCheckInterval); target.m_requiredGlobalKey = requiredGlobalKey; target.m_blockingGlobalKey = blockingGlobalKey; target.m_setPatrolSpawnPoint = setPatrolSpawnPoint; target.m_spawnGroupID = spawnGroupId; target.m_maxGroupSpawned = maxGroupSpawned; target.m_spawnGroupRadius = spawnGroupRadius; target.m_spawnerWeight = spawnerWeight; } private static void ApplySpawnArea(SpawnArea target, SpawnAreaDefinition definition, string context) { if (definition.LevelUpChance.HasValue) { target.m_levelupChance = Mathf.Max(0f, definition.LevelUpChance.Value); } if (definition.SpawnInterval.HasValue) { target.m_spawnIntervalSec = Mathf.Max(0f, definition.SpawnInterval.Value); } if (definition.TriggerDistance.HasValue) { target.m_triggerDistance = Mathf.Max(0f, definition.TriggerDistance.Value); } if (definition.SetPatrolSpawnPoint.HasValue) { target.m_setPatrolSpawnPoint = definition.SetPatrolSpawnPoint.Value; } if (definition.SpawnRadius.HasValue) { target.m_spawnRadius = Mathf.Max(0f, definition.SpawnRadius.Value); } if (definition.NearRadius.HasValue) { target.m_nearRadius = Mathf.Max(0f, definition.NearRadius.Value); } if (definition.FarRadius.HasValue) { target.m_farRadius = Mathf.Max(0f, definition.FarRadius.Value); } if (definition.MaxNear.HasValue) { target.m_maxNear = Math.Max(0, definition.MaxNear.Value); } if (definition.MaxTotal.HasValue) { target.m_maxTotal = Math.Max(0, definition.MaxTotal.Value); } if (definition.OnGroundOnly.HasValue) { target.m_onGroundOnly = definition.OnGroundOnly.Value; } List list = null; if (definition.Creatures != null) { list = BuildResolvedSpawnAreaPrefabs(definition.Creatures, context); target.m_prefabs = list.Select((SpawnAreaResolvedSpawnEntry entry) => entry.SpawnData).ToList(); } UpdateAppliedSpawnAreaPostSpawnOverrides(target, definition, list); } private static void ApplyCreatureSpawner(CreatureSpawner target, CreatureSpawnerDefinition definition, string context) { if (definition.Creature != null) { string text = definition.Creature.Trim(); if (text.Length > 0) { GameObject val = ResolveCreaturePrefab(text, context); if ((Object)(object)val != (Object)null) { target.m_creaturePrefab = val; } } else { WarnInvalidEntry("Entry '" + context + "' set creature to an empty value. Leave the key out to keep the original creature."); } } ExpandWorldSpawnDataPayload expandWorldSpawnDataPayload = ExpandWorldSpawnDataSupport.BuildPayload(target.m_creaturePrefab, definition.Data, definition.Fields, definition.Objects, context); if (expandWorldSpawnDataPayload != null) { LiveReconcilerState.SetAppliedCreatureSpawnerData(target, expandWorldSpawnDataPayload); } else { LiveReconcilerState.RemoveAppliedCreatureSpawnerData(target); } if (definition.MinLevel.HasValue) { target.m_minLevel = Math.Max(1, definition.MinLevel.Value); } if (definition.MaxLevel.HasValue) { target.m_maxLevel = Math.Max(target.m_minLevel, Math.Max(1, definition.MaxLevel.Value)); } if (definition.LevelUpChance.HasValue) { target.m_levelupChance = Mathf.Max(0f, definition.LevelUpChance.Value); } if (definition.RespawnTimeMinutes.HasValue) { target.m_respawnTimeMinuts = Mathf.Max(0f, definition.RespawnTimeMinutes.Value); } if (definition.TriggerDistance.HasValue) { target.m_triggerDistance = Mathf.Max(0f, definition.TriggerDistance.Value); } if (definition.TriggerNoise.HasValue) { target.m_triggerNoise = Mathf.Max(0f, definition.TriggerNoise.Value); } TimeOfDayDefinition configuredTimeOfDay = GetConfiguredTimeOfDay(definition); if (configuredTimeOfDay != null) { TimeOfDayFormatting.GetBroadSpawnFlags(configuredTimeOfDay, out var allowDay, out var allowNight); target.m_spawnAtDay = allowDay; target.m_spawnAtNight = allowNight; if (configuredTimeOfDay.HasValues()) { LiveReconcilerState.SetAppliedCreatureSpawnerTimeOfDay(target, configuredTimeOfDay); } else { LiveReconcilerState.RemoveAppliedCreatureSpawnerTimeOfDay(target); } } else { LiveReconcilerState.RemoveAppliedCreatureSpawnerTimeOfDay(target); } if (definition.RequireSpawnArea.HasValue) { target.m_requireSpawnArea = definition.RequireSpawnArea.Value; } if (definition.AllowInsidePlayerBase.HasValue) { target.m_spawnInPlayerBase = definition.AllowInsidePlayerBase.Value; } if (definition.WakeUpAnimation.HasValue) { target.m_wakeUpAnimation = definition.WakeUpAnimation.Value; } if (definition.SpawnCheckInterval.HasValue) { target.m_spawnInterval = Math.Max(1, definition.SpawnCheckInterval.Value); } if (definition.RequiredGlobalKey != null) { target.m_requiredGlobalKey = definition.RequiredGlobalKey; } if (definition.BlockingGlobalKey != null) { target.m_blockingGlobalKey = definition.BlockingGlobalKey; } if (definition.SetPatrolSpawnPoint.HasValue) { target.m_setPatrolSpawnPoint = definition.SetPatrolSpawnPoint.Value; } if (definition.SpawnGroupId.HasValue) { target.m_spawnGroupID = definition.SpawnGroupId.Value; } if (definition.MaxGroupSpawned.HasValue) { target.m_maxGroupSpawned = Math.Max(0, definition.MaxGroupSpawned.Value); } if (definition.SpawnGroupRadius.HasValue) { target.m_spawnGroupRadius = Mathf.Max(0f, definition.SpawnGroupRadius.Value); } if (definition.SpawnerWeight.HasValue) { target.m_spawnerWeight = Mathf.Max(0f, definition.SpawnerWeight.Value); } if (FactionIntegration.HasFaction(definition.Faction)) { LiveReconcilerState.SetAppliedCreatureSpawnerFaction(target, definition.Faction); } else { LiveReconcilerState.RemoveAppliedCreatureSpawnerFaction(target); } } private static bool HasSpawnAreaOverride(SpawnAreaDefinition? definition) { if (definition != null) { if (!definition.LevelUpChance.HasValue && !definition.SpawnInterval.HasValue && !definition.TriggerDistance.HasValue && !definition.SetPatrolSpawnPoint.HasValue && !definition.SpawnRadius.HasValue && !definition.NearRadius.HasValue && !definition.FarRadius.HasValue && !definition.MaxNear.HasValue && !definition.MaxTotal.HasValue && !definition.MaxTotalSpawns.HasValue && !definition.OnGroundOnly.HasValue) { return definition.Creatures != null; } return true; } return false; } private static bool HasCreatureSpawnerOverride(CreatureSpawnerDefinition? definition) { if (definition != null) { if (!FactionIntegration.HasFaction(definition.Faction) && definition.Data == null && definition.Fields == null && definition.Objects == null && definition.TimeOfDay == null && definition.Creature == null && !definition.MinLevel.HasValue && !definition.MaxLevel.HasValue && !definition.LevelUpChance.HasValue && !definition.RespawnTimeMinutes.HasValue && !definition.TriggerDistance.HasValue && !definition.TriggerNoise.HasValue && !definition.RequireSpawnArea.HasValue && !definition.AllowInsidePlayerBase.HasValue && !definition.WakeUpAnimation.HasValue && !definition.SpawnCheckInterval.HasValue && definition.RequiredGlobalKey == null && definition.BlockingGlobalKey == null && !definition.SetPatrolSpawnPoint.HasValue && !definition.SpawnGroupId.HasValue && !definition.MaxGroupSpawned.HasValue && !definition.SpawnGroupRadius.HasValue) { return definition.SpawnerWeight.HasValue; } return true; } return false; } private static bool HasEntryConditions(SpawnerConfigurationEntry? entry) { if (entry != null) { return DropConditionEvaluator.HasConditions(entry.Conditions); } return false; } private static bool HasDynamicEntryConditions(SpawnerConfigurationEntry? entry) { if (entry != null) { return DropConditionEvaluator.HasDynamicConditions(entry.Conditions); } return false; } private static TimeOfDayDefinition? GetConfiguredTimeOfDay(CreatureSpawnerDefinition? definition) { if (definition == null) { return null; } if (definition.TimeOfDay != null) { return definition.TimeOfDay; } return null; } private static bool TryGetActiveSpawnAreaEntries(SpawnArea? spawnArea, out IReadOnlyList? entries, out string configPrefabName) { entries = null; if (!TryGetActiveSpawnAreaEntryCache(spawnArea, out MatchingEntryCache entryCache, out configPrefabName)) { return false; } entries = entryCache.Entries; return true; } private static bool TryGetActiveCreatureSpawnerEntries(CreatureSpawner? creatureSpawner, out IReadOnlyList? entries, out string configPrefabName) { entries = null; if (!TryGetActiveCreatureSpawnerEntryCache(creatureSpawner, out MatchingEntryCache entryCache, out configPrefabName)) { return false; } entries = entryCache.Entries; return true; } private static bool ShouldRuntimeReconcile(SpawnerConfigurationEntry? entry) { if (entry != null) { return HasDynamicEntryConditions(entry); } return false; } private static bool HasAnySpawnAreaSpawnFaction(List? prefabs) { return prefabs?.Any((SpawnAreaSpawnDefinition creature) => FactionIntegration.HasFaction(creature.Faction)) ?? false; } private static List BuildSpawnAreaPrefabs(List snapshots) { return ((IEnumerable)snapshots).Select((Func)((SpawnAreaSpawnSnapshot snapshot) => new SpawnData { m_prefab = snapshot.Prefab, m_weight = snapshot.Weight, m_minLevel = snapshot.MinLevel, m_maxLevel = snapshot.MaxLevel })).ToList(); } private static List BuildResolvedSpawnAreaPrefabs(List definitions, string context) { //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Expected O, but got Unknown List list = new List(); for (int i = 0; i < definitions.Count; i++) { SpawnAreaSpawnDefinition spawnAreaSpawnDefinition = definitions[i]; string text = (spawnAreaSpawnDefinition.Creature ?? "").Trim(); if (text.Length == 0) { WarnInvalidEntry("Entry '" + context + "' contains a SpawnArea creature entry without a creature name."); continue; } GameObject val = ResolveCreaturePrefab(text, context); if (!((Object)(object)val == (Object)null)) { int num = Math.Max(1, spawnAreaSpawnDefinition.MinLevel.GetValueOrDefault(1)); list.Add(new SpawnAreaResolvedSpawnEntry { SpawnData = new SpawnData { m_prefab = val, m_weight = Mathf.Max(0f, spawnAreaSpawnDefinition.Weight.GetValueOrDefault(1f)), m_minLevel = num, m_maxLevel = Math.Max(num, spawnAreaSpawnDefinition.MaxLevel.GetValueOrDefault(num)) }, Definition = spawnAreaSpawnDefinition, DataPayload = ExpandWorldSpawnDataSupport.BuildPayload(val, spawnAreaSpawnDefinition.Data, spawnAreaSpawnDefinition.Fields, spawnAreaSpawnDefinition.Objects, $"{context}.spawnArea.creatures[{i}]") }); } } return list; } private static void UpdateAppliedSpawnAreaPostSpawnOverrides(SpawnArea target, SpawnAreaDefinition definition, List? resolvedSpawnEntries) { ClearAppliedSpawnAreaPostSpawnOverrides(target); if (!HasAnySpawnAreaSpawnFaction(definition.Creatures) && !HasAnySpawnAreaSpawnData(definition.Creatures)) { return; } List source = target.m_prefabs ?? new List(); LiveReconcilerState.SetAppliedSpawnAreaPrefabs(target, source.ToList()); if (resolvedSpawnEntries == null || resolvedSpawnEntries.Count <= 0) { return; } foreach (SpawnAreaResolvedSpawnEntry resolvedSpawnEntry in resolvedSpawnEntries) { string text = FactionIntegration.Normalize(resolvedSpawnEntry.Definition.Faction); if (FactionIntegration.HasFaction(text)) { LiveReconcilerState.SetAppliedSpawnAreaFaction(resolvedSpawnEntry.SpawnData, text); } if (resolvedSpawnEntry.DataPayload != null) { LiveReconcilerState.SetAppliedSpawnAreaData(resolvedSpawnEntry.SpawnData, resolvedSpawnEntry.DataPayload); } } } private static void ClearAppliedSpawnAreaPostSpawnOverrides(SpawnArea? target) { if (!LiveReconcilerState.TryTakeAppliedSpawnAreaPrefabs(target, out List prefabs)) { return; } foreach (SpawnData item in prefabs) { LiveReconcilerState.RemoveAppliedSpawnAreaData(item); LiveReconcilerState.RemoveAppliedSpawnAreaFaction(item); } } private static bool HasAppliedSpawnAreaTrackedCustomizations(SpawnArea spawnArea) { if (LiveReconcilerState.TryGetAppliedSpawnAreaPrefabs(spawnArea, out List prefabs)) { return prefabs.Any((SpawnData prefab) => LiveReconcilerState.HasAppliedSpawnAreaData(prefab) || LiveReconcilerState.HasAppliedSpawnAreaFaction(prefab)); } return false; } private static bool RequiresSpawnAreaPostSpawnTracking(SpawnData? spawnData) { if (spawnData != null) { return LiveReconcilerState.HasAppliedSpawnAreaFaction(spawnData); } return false; } private static void MaybeRefreshCreatureSpawnerSchedule(CreatureSpawner creatureSpawner, int previousInterval) { int instanceID = ((Object)creatureSpawner).GetInstanceID(); int num = (creatureSpawner.m_spawnInterval = Math.Max(1, creatureSpawner.m_spawnInterval)); bool flag = previousInterval != num; if (LiveReconcilerState.TryGetAppliedCreatureSpawnerCheckInterval(instanceID, out var interval)) { flag = flag || interval != num; } LiveReconcilerState.SetAppliedCreatureSpawnerCheckInterval(instanceID, num); if (flag) { RefreshCreatureSpawnerSchedule(creatureSpawner); } } private static void RefreshCreatureSpawnerSchedule(CreatureSpawner creatureSpawner) { ((MonoBehaviour)creatureSpawner).CancelInvoke("UpdateSpawner"); ZNetView val = default(ZNetView); if (((Behaviour)creatureSpawner).isActiveAndEnabled && ((Component)creatureSpawner).gameObject.activeInHierarchy && ((Component)creatureSpawner).TryGetComponent(ref val) && !((Object)(object)val == (Object)null) && val.GetZDO() != null) { float num = Mathf.Max(1f, (float)creatureSpawner.m_spawnInterval); ((MonoBehaviour)creatureSpawner).InvokeRepeating("UpdateSpawner", Random.Range(num / 2f, num), num); } } private static void MaybeResetCreatureSpawnerCaches(CreatureSpawner creatureSpawner, int previousGroupId, int previousMaxGroupSpawned, float previousGroupRadius, float previousSpawnerWeight) { if (previousGroupId != creatureSpawner.m_spawnGroupID || previousMaxGroupSpawned != creatureSpawner.m_maxGroupSpawned || !Mathf.Approximately(previousGroupRadius, creatureSpawner.m_spawnGroupRadius) || !Mathf.Approximately(previousSpawnerWeight, creatureSpawner.m_spawnerWeight)) { CreatureSpawnerCheckedLocationField?.SetValue(creatureSpawner, false); CreatureSpawnerLocationField?.SetValue(creatureSpawner, null); CreatureSpawnerSpawnGroupField?.SetValue(creatureSpawner, null); } } private static GameObject? ResolveCreaturePrefab(string prefabName, string context) { ZNetScene instance = ZNetScene.instance; GameObject val = ((instance != null) ? instance.GetPrefab(prefabName) : null); if ((Object)(object)val == (Object)null) { WarnInvalidEntry("Entry '" + context + "' references unknown creature prefab '" + prefabName + "'."); return null; } Character val2 = default(Character); BaseAI val3 = default(BaseAI); if (!val.TryGetComponent(ref val2) && !val.TryGetComponent(ref val3)) { WarnInvalidEntry("Entry '" + context + "' references '" + prefabName + "', but it is not a creature prefab."); return null; } return val; } private static bool TryGetExactContext(GameObject gameObject, string componentType, out string exactKey) { string rootPrefabName; return TryGetExactContext(gameObject, componentType, out exactKey, out rootPrefabName); } private static bool TryGetExactContext(GameObject gameObject, string componentType, out string exactKey, out string rootPrefabName) { exactKey = ""; rootPrefabName = ""; if ((Object)(object)gameObject == (Object)null) { return false; } Transform rootTransform = GetRootTransform(gameObject.transform); rootPrefabName = GetResolvedPrefabName(((Component)rootTransform).gameObject); if (rootPrefabName.Length == 0) { return false; } exactKey = BuildExactKey(rootPrefabName, GetRelativePath(rootTransform, gameObject.transform), componentType); return true; } private static bool TryGetLiveLocationContext(GameObject gameObject, out string locationPrefab, out string relativePath) { string sourceLabel; return TryGetLiveLocationContext(gameObject, out locationPrefab, out relativePath, out sourceLabel); } private static bool TryGetLiveLocationContext(GameObject gameObject, out string locationPrefab, out string relativePath, out string sourceLabel) { locationPrefab = ""; relativePath = ""; sourceLabel = ""; if ((Object)(object)gameObject == (Object)null) { return false; } if (TryGetRecordedLocationContext(gameObject, out locationPrefab, out relativePath)) { sourceLabel = "Provenance"; return true; } if (TryGetCurrentLocationSpawnContext(gameObject, out locationPrefab, out relativePath)) { sourceLabel = "SpawnLocationContext"; return true; } if (TryGetLiveLocationProxyContext(gameObject, out locationPrefab, out relativePath)) { sourceLabel = "LocationProxy"; return true; } if (TryGetDirectLocationContext(gameObject, out locationPrefab, out relativePath)) { sourceLabel = "Location"; return true; } if (TryGetStaticLocationContext(gameObject, out locationPrefab, out relativePath)) { sourceLabel = "LocationStatic"; return true; } if (TryGetZoneLocationContext(gameObject, out locationPrefab)) { sourceLabel = "LocationZone"; relativePath = ""; return true; } if (TryPromoteSpatialContextToRecordedProvenance(gameObject, out locationPrefab, out relativePath)) { sourceLabel = "LocationRadius"; return true; } return false; } private static GameObject? ResolveCurrentInspectionTarget() { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if (TryResolveInspectionTargetFromObject((localPlayer != null) ? ((Humanoid)localPlayer).GetHoverObject() : null, out GameObject targetObject)) { return targetObject; } Vector3 probePoint = (((Object)(object)Player.m_localPlayer != (Object)null) ? (((Component)Player.m_localPlayer).transform.position + ((Component)Player.m_localPlayer).transform.forward * 5f) : Vector3.zero); RaycastHit val = default(RaycastHit); if ((Object)(object)GameCamera.instance != (Object)null && Physics.Raycast(((Component)GameCamera.instance).transform.position, ((Component)GameCamera.instance).transform.forward, ref val, 100f)) { Collider collider = ((RaycastHit)(ref val)).collider; object sourceObject; if (!((Object)(object)((collider != null) ? collider.attachedRigidbody : null) != (Object)null)) { Collider collider2 = ((RaycastHit)(ref val)).collider; sourceObject = ((collider2 != null) ? ((Component)collider2).gameObject : null); } else { sourceObject = ((Component)((RaycastHit)(ref val)).collider.attachedRigidbody).gameObject; } if (TryResolveInspectionTargetFromObject((GameObject?)sourceObject, out targetObject)) { return targetObject; } probePoint = ((RaycastHit)(ref val)).point; } if (!TryFindNearestInspectionTarget(probePoint, out targetObject)) { return null; } return targetObject; } private static bool TryResolveInspectionTargetFromObject(GameObject? sourceObject, out GameObject? targetObject) { targetObject = null; if ((Object)(object)sourceObject == (Object)null) { return false; } SpawnArea val = sourceObject.GetComponent() ?? sourceObject.GetComponentInParent(true); CreatureSpawner val2 = sourceObject.GetComponent() ?? sourceObject.GetComponentInParent(true); if ((Object)(object)val == (Object)null && (Object)(object)val2 == (Object)null) { return false; } if ((Object)(object)val != (Object)null && (Object)(object)val2 == (Object)null) { targetObject = ((Component)val).gameObject; return true; } if ((Object)(object)val2 != (Object)null && (Object)(object)val == (Object)null) { targetObject = ((Component)val2).gameObject; return true; } int ancestorDepth = GetAncestorDepth(sourceObject.transform, ((Component)val).transform); int ancestorDepth2 = GetAncestorDepth(sourceObject.transform, ((Component)val2).transform); targetObject = ((ancestorDepth <= ancestorDepth2) ? ((Component)val).gameObject : ((Component)val2).gameObject); return true; } private static int GetAncestorDepth(Transform source, Transform ancestor) { int num = 0; Transform val = source; while ((Object)(object)val != (Object)null) { if (val == ancestor) { return num; } val = val.parent; num++; } return int.MaxValue; } private static bool TryFindNearestInspectionTarget(Vector3 probePoint, out GameObject? targetObject) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) targetObject = null; float num = 64f; SpawnArea[] array = Object.FindObjectsByType((FindObjectsSortMode)0); Vector3 val2; foreach (SpawnArea val in array) { if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).gameObject == (Object)null)) { val2 = ((Component)val).transform.position - probePoint; float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude; if (!(sqrMagnitude >= num)) { num = sqrMagnitude; targetObject = ((Component)val).gameObject; } } } CreatureSpawner[] array2 = Object.FindObjectsByType((FindObjectsSortMode)0); foreach (CreatureSpawner val3 in array2) { if (!((Object)(object)val3 == (Object)null) && !((Object)(object)((Component)val3).gameObject == (Object)null)) { val2 = ((Component)val3).transform.position - probePoint; float sqrMagnitude2 = ((Vector3)(ref val2)).sqrMagnitude; if (!(sqrMagnitude2 >= num)) { num = sqrMagnitude2; targetObject = ((Component)val3).gameObject; } } } return (Object)(object)targetObject != (Object)null; } private static List BuildInspectionLines(GameObject targetObject) { List list = new List(); if ((Object)(object)targetObject == (Object)null) { return list; } SpawnArea spawnArea = default(SpawnArea); if (targetObject.TryGetComponent(ref spawnArea)) { AppendSpawnAreaInspectionLines(list, spawnArea); return list; } CreatureSpawner creatureSpawner = default(CreatureSpawner); if (targetObject.TryGetComponent(ref creatureSpawner)) { AppendCreatureSpawnerInspectionLines(list, creatureSpawner); } return list; } private static void AppendSpawnAreaInspectionLines(List lines, SpawnArea spawnArea) { string configPrefabName = GetConfigPrefabName(((Component)spawnArea).gameObject, "SpawnArea"); lines.Add("Spawner Inspect: SpawnArea"); lines.Add("Object: " + configPrefabName + "@" + DescribeInstance(((Component)spawnArea).gameObject)); AppendResolvedLocationLines(lines, ((Component)spawnArea).gameObject, spawnArea, null); List value; List list = (ActiveEntriesByPrefab.TryGetValue(configPrefabName, out value) ? value.Where((SpawnerConfigurationEntry entry) => entry.SpawnArea != null && HasSpawnAreaOverride(entry.SpawnArea)).ToList() : new List()); lines.Add($"Configured entries: {list.Count}"); MatchingEntryCache entryCache; string configPrefabName2; bool flag = TryGetActiveSpawnAreaEntryCache(spawnArea, out entryCache, out configPrefabName2); lines.Add($"Selector-matching entries: {(flag ? entryCache.Entries.Count : 0)}"); IReadOnlyList readOnlyList2; if (!flag) { IReadOnlyList readOnlyList = new List(); readOnlyList2 = readOnlyList; } else { readOnlyList2 = entryCache.Entries; } IReadOnlyList readOnlyList3 = readOnlyList2; if (readOnlyList3.Count > 0 && TrySelectWinningSpawnerEntry(((Component)spawnArea).gameObject, readOnlyList3, forSpawnArea: true, out SpawnerRuntimeEntry winningEntry) && winningEntry != null) { lines.Add("Winning entry: " + FormatInspectionEntrySummary(winningEntry)); } else { lines.Add("Winning entry: none"); } } private static void AppendCreatureSpawnerInspectionLines(List lines, CreatureSpawner creatureSpawner) { string configPrefabName = GetConfigPrefabName(((Component)creatureSpawner).gameObject, "CreatureSpawner"); lines.Add("Spawner Inspect: CreatureSpawner"); lines.Add("Object: " + configPrefabName + "@" + DescribeInstance(((Component)creatureSpawner).gameObject)); AppendResolvedLocationLines(lines, ((Component)creatureSpawner).gameObject, null, creatureSpawner); List value; List list = (ActiveEntriesByPrefab.TryGetValue(configPrefabName, out value) ? value.Where((SpawnerConfigurationEntry entry) => entry.CreatureSpawner != null && HasCreatureSpawnerOverride(entry.CreatureSpawner)).ToList() : new List()); lines.Add($"Configured entries: {list.Count}"); MatchingEntryCache entryCache; string configPrefabName2; bool flag = TryGetActiveCreatureSpawnerEntryCache(creatureSpawner, out entryCache, out configPrefabName2); lines.Add($"Selector-matching entries: {(flag ? entryCache.Entries.Count : 0)}"); IReadOnlyList readOnlyList2; if (!flag) { IReadOnlyList readOnlyList = new List(); readOnlyList2 = readOnlyList; } else { readOnlyList2 = entryCache.Entries; } IReadOnlyList readOnlyList3 = readOnlyList2; if (readOnlyList3.Count > 0 && TrySelectWinningSpawnerEntry(((Component)creatureSpawner).gameObject, readOnlyList3, forSpawnArea: false, out SpawnerRuntimeEntry winningEntry) && winningEntry != null) { lines.Add("Winning entry: " + FormatInspectionEntrySummary(winningEntry)); } else { lines.Add("Winning entry: none"); } } private static void AppendResolvedLocationLines(List lines, GameObject gameObject, SpawnArea? spawnArea, CreatureSpawner? creatureSpawner) { if (TryGetLiveLocationContext(gameObject, out string locationPrefab, out string relativePath, out string sourceLabel)) { lines.Add("Resolved location: " + locationPrefab); lines.Add("Resolved path: " + ((relativePath.Length > 0) ? relativePath : "(unavailable)")); lines.Add("Resolution source: " + sourceLabel); } else { lines.Add("Resolved location: unavailable"); lines.Add("Resolved path: unavailable"); lines.Add("Resolution source: unavailable"); } AppendLocationFallbackDiagnostics(lines, gameObject); SpawnerLocationProvenance provenance = null; if ((Object)(object)spawnArea != (Object)null) { ProvenanceRegistry.TryGetSpawnAreaProvenance(spawnArea, out provenance); } else if ((Object)(object)creatureSpawner != (Object)null) { ProvenanceRegistry.TryGetCreatureSpawnerProvenance(creatureSpawner, out provenance); } if (provenance != null) { lines.Add("Recorded provenance: location=" + provenance.LocationPrefab + ", path=" + provenance.RelativePath); } } private static void AppendLocationFallbackDiagnostics(List lines, GameObject gameObject) { if (TryGetStaticLocationContext(gameObject, out string locationPrefab, out string _)) { lines.Add("Static location: " + locationPrefab); } if (TryGetZoneLocationContext(gameObject, out string locationPrefab2)) { lines.Add("Zone location: " + locationPrefab2); } if (TryGetSpatialLocationContext(gameObject, out string locationPrefab3)) { lines.Add("Radius location: " + locationPrefab3); } } private static string FormatInspectionEntrySummary(SpawnerConfigurationEntry entry) { if (entry == null) { return "(null)"; } string text = ((entry.Location != null) ? ("location=" + entry.Location) : "prefab-only"); if (entry.CreatureSpawner != null) { return text + ", creatureSpawner.creature=" + (entry.CreatureSpawner.Creature ?? "(null)"); } if (entry.SpawnArea?.Creatures != null) { return $"{text}, spawnArea.creatures={entry.SpawnArea.Creatures.Count}"; } return text; } private static string FormatInspectionEntrySummary(SpawnerRuntimeEntry entry) { if (entry == null) { return "(null)"; } string text = ((entry.Location.Length > 0) ? ("location=" + entry.Location) : "prefab-only"); if (entry.CreatureSpawner != null) { return text + ", creatureSpawner.creature=" + (entry.CreatureSpawner.Creature ?? "(null)"); } if (entry.SpawnArea?.Creatures != null) { return $"{text}, spawnArea.creatures={entry.SpawnArea.Creatures.Count}"; } return text; } private static string BuildExactKey(string rootPrefabName, string relativePath, string componentType) { return rootPrefabName + "|" + relativePath + "|" + componentType; } private static string GetRelativePath(Transform root, Transform target) { if ((Object)(object)target == (Object)(object)root) { return "."; } List list = new List(); Transform val = target; while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)root) { list.Add($"{((Object)val).name}[{GetSameNameSiblingIndex(val)}]"); val = val.parent; } list.Reverse(); return string.Join("/", list); } private static int GetSameNameSiblingIndex(Transform transform) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown if ((Object)(object)transform.parent == (Object)null) { return 0; } int num = 0; foreach (Transform item in transform.parent) { Transform val = item; if (val == transform) { break; } if (string.Equals(((Object)val).name, ((Object)transform).name, StringComparison.Ordinal)) { num++; } } return num; } private static string DescribeInstance(GameObject gameObject) { Transform rootTransform = GetRootTransform(gameObject.transform); return GetResolvedPrefabName(((Component)rootTransform).gameObject) + "/" + GetRelativePath(rootTransform, gameObject.transform); } private static string GetConfigPrefabName(GameObject gameObject, string componentType) { if (TryGetExactContext(gameObject, componentType, out string exactKey, out string rootPrefabName)) { if (componentType == "SpawnArea" && SpawnAreaCatalogsByExactKey.TryGetValue(exactKey, out SpawnAreaComponentCatalog value)) { return value.ConfigPrefabName; } if (componentType == "CreatureSpawner" && CreatureSpawnerCatalogsByExactKey.TryGetValue(exactKey, out CreatureSpawnerComponentCatalog value2)) { return value2.ConfigPrefabName; } string liveComponentPrefabName = GetLiveComponentPrefabName(gameObject); string relativePath = GetRelativePath(GetRootTransform(gameObject.transform), gameObject.transform); if (componentType == "SpawnArea") { SpawnAreaCatalogsByExactKey[exactKey] = new SpawnAreaComponentCatalog { ConfigPrefabName = liveComponentPrefabName, RootPrefabName = rootPrefabName, RelativePath = relativePath }; } else if (componentType == "CreatureSpawner") { CreatureSpawnerCatalogsByExactKey[exactKey] = new CreatureSpawnerComponentCatalog { ConfigPrefabName = liveComponentPrefabName, RootPrefabName = rootPrefabName, RelativePath = relativePath }; } return liveComponentPrefabName; } return GetLiveComponentPrefabName(gameObject); } private static string GetLiveComponentPrefabName(GameObject? gameObject) { string text = TrimCloneSuffix(((gameObject != null) ? ((Object)gameObject).name : null) ?? ""); if (text.Length > 0) { return text; } return GetResolvedPrefabName(gameObject); } private static string GetLocationReferencePrefabName(GameObject? gameObject) { string text = NormalizeLocationReferencePrefabName(GetResolvedPrefabName(gameObject)); if (text.Length > 0) { return text; } return NormalizeLocationReferencePrefabName(GetLiveComponentPrefabName(gameObject)); } private static string GetResolvedPrefabName(GameObject? gameObject) { if ((Object)(object)gameObject == (Object)null) { return ""; } ZNetView component = gameObject.GetComponent(); 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 ((Object)prefab).name; } } string prefabName = Utils.GetPrefabName(gameObject); if (!string.IsNullOrWhiteSpace(prefabName)) { return prefabName; } string name = ((Object)gameObject).name; if (name.EndsWith("(Clone)", StringComparison.Ordinal)) { string text = name; int length = "(Clone)".Length; return text.Substring(0, text.Length - length).TrimEnd(); } return name; } private static string TrimCloneSuffix(string name) { if (string.IsNullOrWhiteSpace(name)) { return ""; } if (name.EndsWith("(Clone)", StringComparison.Ordinal)) { int length = "(Clone)".Length; return name.Substring(0, name.Length - length).TrimEnd(); } return name.Trim(); } private unsafe static string NormalizeLocationReferencePrefabName(string name) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) string text = TrimCloneSuffix(name); if (text.Length >= 4) { if (text[text.Length - 1] == ')') { int num = text.LastIndexOf(" (", StringComparison.Ordinal); if (num <= 0) { return text; } ReadOnlySpan val = MemoryExtensions.AsSpan(text, num + 2, text.Length - num - 3); if (val.Length == 0) { return text; } ReadOnlySpan val2 = val; for (int i = 0; i < val2.Length; i++) { if (!char.IsDigit(*(char*)val2[i])) { return text; } } return text.Substring(0, num).TrimEnd(); } } return text; } private static void AddSnapshotByName(Dictionary> snapshotsByName, string configPrefabName, T snapshot) { if (!snapshotsByName.TryGetValue(configPrefabName, out List value)) { value = (snapshotsByName[configPrefabName] = new List()); } value.Add(snapshot); } private static bool HasAnySpawnAreaSpawnData(List? prefabs) { return prefabs?.Any((SpawnAreaSpawnDefinition prefab) => prefab.Data != null || prefab.Fields != null || prefab.Objects != null) ?? false; } private static string FormatYamlBool(bool value) { if (!value) { return "false"; } return "true"; } private static string FormatYamlFloat(float value) { return value.ToString("0.###", CultureInfo.InvariantCulture); } private static bool IsReferenceDefault(float value, float defaultValue) { return Math.Abs(value - defaultValue) < 0.0001f; } private static string FormatYamlString(string value) { if (value.Length == 0) { return "''"; } if (!char.IsWhiteSpace(value[0]) && !char.IsWhiteSpace(value[value.Length - 1]) && value.IndexOfAny(new char[17] { ':', '#', '{', '}', '[', ']', ',', '\'', '"', '&', '*', '!', '|', '>', '%', '@', '`' }) < 0 && value[0] != '-' && value[0] != '?' && !string.Equals(value, "null", StringComparison.OrdinalIgnoreCase) && !string.Equals(value, "true", StringComparison.OrdinalIgnoreCase) && !string.Equals(value, "false", StringComparison.OrdinalIgnoreCase)) { return value; } return "'" + value.Replace("'", "''") + "'"; } private static void WarnMissingComponent(string key, string componentName) { if (LiveReconcilerState.TryAddMissingComponentWarning(key)) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("Spawner configuration references " + componentName + ", but no matching '" + key.Split(':')[0] + "' component name was found.")); } } private static void LogLocationSelectorDiagnostic(GameObject gameObject, SpawnerConfigurationEntry entry, string reason, string? resolvedLocation = null, string? resolvedPath = null) { if (!((Object)(object)gameObject == (Object)null) && entry != null) { string configPrefabName = GetConfigPrefabName(gameObject, (entry.SpawnArea != null) ? "SpawnArea" : "CreatureSpawner"); string key = string.Join("|", configPrefabName, DescribeInstance(gameObject), entry.RuleId, reason, entry.Location ?? "", resolvedLocation ?? ""); if (SelectorCacheStore.TryAddLocationSelectorDiagnostic(key)) { string text = "location='" + entry.Location + "'"; string text2 = ((resolvedLocation != null) ? ("resolved location='" + resolvedLocation + "'") : "resolved location unavailable"); DropNSpawnPlugin.DropNSpawnLogger.LogDebug((object)("Spawner selector mismatch for '" + configPrefabName + "@" + DescribeInstance(gameObject) + "' using " + text + ". " + reason + "; " + text2 + ".")); } } } private static void LogLocationSelectorDiagnostic(GameObject gameObject, SpawnerRuntimeEntry entry, string reason, string? resolvedLocation = null, string? resolvedPath = null) { if (!((Object)(object)gameObject == (Object)null) && entry != null) { string componentType = ResolveRuntimeSpawnerComponentName(gameObject); string configPrefabName = GetConfigPrefabName(gameObject, componentType); string key = string.Join("|", configPrefabName, DescribeInstance(gameObject), entry.RuleId, reason, entry.Location ?? "", resolvedLocation ?? ""); if (SelectorCacheStore.TryAddLocationSelectorDiagnostic(key)) { string text = "location='" + entry.Location + "'"; string text2 = ((resolvedLocation != null) ? ("resolved location='" + resolvedLocation + "'") : "resolved location unavailable"); DropNSpawnPlugin.DropNSpawnLogger.LogDebug((object)("Spawner selector mismatch for '" + configPrefabName + "@" + DescribeInstance(gameObject) + "' using " + text + ". " + reason + "; " + text2 + ".")); } } } private static string ResolveRuntimeSpawnerComponentName(GameObject gameObject) { SpawnArea val = default(SpawnArea); if ((Object)(object)gameObject != (Object)null && gameObject.TryGetComponent(ref val)) { return "SpawnArea"; } return "CreatureSpawner"; } private static void WarnInvalidEntry(string message) { if (_invalidEntryWarningSuppressionDepth <= 0 && !ShouldSuppressServerSourcedInvalidEntryWarning(message) && InvalidEntryWarnings.Add(message)) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)message); } } private static InvalidEntryWarningSuppressionScope BeginInvalidEntryWarningSuppressionForSyncedClientBuild(string sourceName) { if (DropNSpawnPlugin.IsSourceOfTruth || !sourceName.StartsWith("ServerSync:", StringComparison.Ordinal)) { return default(InvalidEntryWarningSuppressionScope); } return new InvalidEntryWarningSuppressionScope(active: true); } private static bool ShouldSuppressServerSourcedInvalidEntryWarning(string message) { if (!DropNSpawnPlugin.IsSourceOfTruth) { return message.IndexOf("ServerSync:", StringComparison.Ordinal) >= 0; } return false; } private static void LogPartiallyAcceptedLocalConfiguration(int totalEntries, int acceptedEntries, IEnumerable warnings) { int num = Math.Max(0, totalEntries - acceptedEntries); DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("Skipped " + num.ToString(CultureInfo.InvariantCulture) + " invalid spawner entr" + ((num == 1) ? "y" : "ies") + " and kept " + acceptedEntries.ToString(CultureInfo.InvariantCulture) + " valid entr" + ((acceptedEntries == 1) ? "y" : "ies") + ".")); foreach (string item in warnings.Where((string message) => !string.IsNullOrWhiteSpace(message)).Distinct(StringComparer.OrdinalIgnoreCase)) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)item); } } private static void LogLocalConfigurationLoaded(int acceptedEntryCount, int loadedFileCount) { DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)$"Loaded {acceptedEntryCount} spawner configuration(s) from {loadedFileCount} override file(s)."); } private static void OnSourceOfTruthPayloadUnchanged() { if (!NetworkPayloadSyncSupport.IsPayloadCurrent(Descriptor, _configurationSignature)) { ConfigurationDomainHost.PublishSyncedPayload(DropNSpawnPlugin.IsSourceOfTruth, Descriptor, _configuration, _configurationSignature); } } private static void LogSyncedSpawnerConfigurationLoaded(string payloadToken, int acceptedEntryCount) { DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)$"Loaded {acceptedEntryCount} synchronized spawner configuration(s) from the server."); } private static void LogSyncedSpawnerConfigurationFailure(string payloadToken, Exception ex) { DropNSpawnPlugin.DropNSpawnLogger.LogError((object)$"Failed to deserialize synchronized spawner payload DTO. {ex}"); } private static string CreateConfigurationContext(SpawnerConfigurationEntry entry) { return (string.IsNullOrWhiteSpace(entry.Prefab) ? "" : entry.Prefab) + " @ " + DescribeEntrySource(entry); } private static string DescribeEntrySource(SpawnerConfigurationEntry entry) { string text = DescribeEntrySource(entry.SourcePath); if (entry.SourceLine > 0) { text = text + ":" + entry.SourceLine.ToString(CultureInfo.InvariantCulture); } return text; } private static string DescribeEntrySource(string? sourcePath) { string text = sourcePath ?? ""; if (text.Length == 0) { return "unknown source"; } text.StartsWith("ServerSync:", StringComparison.Ordinal); return text; } private static string FormatYamlExceptionLocation(Exception ex) { if (!(ex is YamlException ex2)) { return ""; } Mark start = ex2.Start; if (start.Line <= 0) { return ""; } return " at line " + start.Line.ToString(CultureInfo.InvariantCulture); } private static void RunApplyCoordinator(HashSet availablePrefabs, int gameDataSignature, bool domainEnabled, Dictionary currentEntrySignatures, bool queueLiveReconcile) { SpawnerDesiredState spawnerDesiredState = BuildSpawnerDesiredState(availablePrefabs, gameDataSignature, domainEnabled, currentEntrySignatures, queueLiveReconcile); _ = StandardBaselineDesiredStateCoordinator.Run(spawnerDesiredState.ApplyPlan, spawnerDesiredState, SpawnerApplyOperations.Instance).Success; } private static SpawnerDesiredState BuildSpawnerDesiredState(HashSet availablePrefabs, int gameDataSignature, bool domainEnabled, Dictionary currentEntrySignatures, bool queueLiveReconcile) { StandardDomainApplyPlan applyPlan = StandardDomainApplySupport.BuildPlan(_lastAppliedGameDataSignature, gameDataSignature, _lastAppliedDomainEnabled, domainEnabled, _lastAppliedEntrySignaturesByPrefab, currentEntrySignatures, EmptyEntrySignatures, _lastAppliedGameDataSignature == gameDataSignature && _lastAppliedDomainEnabled.GetValueOrDefault()); return new SpawnerDesiredState { GameDataSignature = gameDataSignature, ApplyPlan = applyPlan, CurrentEntrySignatures = currentEntrySignatures, DomainEnabled = domainEnabled, QueueLiveReconcile = queueLiveReconcile, AvailablePrefabs = availablePrefabs, ReloadPrefabs = (applyPlan.DirtyKeys ?? BuildRegisteredCatchupPrefabs(domainEnabled, currentEntrySignatures)), RuntimeConfigurationSnapshot = GetRuntimeConfigurationSnapshot() }; } private static void RestoreSpawnerStaticBaseline(SpawnerDesiredState desiredState) { } private static void PrepareSpawnerLiveBaseline(SpawnerDesiredState desiredState) { ClearRuntimeReconcileState(); } private static void ValidateSpawnerDesiredState(SpawnerDesiredState desiredState) { ValidateConfiguredPrefabs(desiredState.AvailablePrefabs); } private static void ApplySpawnerDesiredStateToStaticBaseline(SpawnerDesiredState desiredState) { } private static void ApplySpawnerDesiredStateToLive(SpawnerDesiredState desiredState) { ApplyDesiredStateToLiveObjects(desiredState); } internal static void TrackSpawnAreaInstance(SpawnArea? spawnArea) { lock (Sync) { TrackSpawnAreaInstanceInternal(spawnArea); } } internal static void TrackCreatureSpawnerInstance(CreatureSpawner? creatureSpawner) { lock (Sync) { TrackCreatureSpawnerInstanceInternal(creatureSpawner); } } internal static void HandleSpawnAreaInstanceAwake(SpawnArea? spawnArea) { lock (Sync) { TrackSpawnAreaInstanceInternal(spawnArea); if (!((Object)(object)spawnArea == (Object)null) && !((Object)(object)((Component)spawnArea).gameObject == (Object)null) && ShouldApplyLocally() && !ShouldBlockClientSpawnerUpdate() && !DropNSpawnPlugin.IsGameDataRefreshDeferred(DropNSpawnPlugin.ReloadDomain.Spawner) && IsGameDataReady()) { SpawnerRuntimeConfigurationSnapshot runtimeConfigurationSnapshot = GetRuntimeConfigurationSnapshot(); if (TryGetTrackedOrCurrentSpawnAreaEligibility(spawnArea, runtimeConfigurationSnapshot, out string configPrefabName, out bool configuredEligible, out bool _) && configuredEligible && TryGetActiveSpawnAreaEntryCache(spawnArea, runtimeConfigurationSnapshot, out MatchingEntryCache entryCache, out configPrefabName)) { ReconcileSpawnAreaInstanceInternal(spawnArea, entryCache.Entries, entryCache); } } } } internal static void HandleCreatureSpawnerInstanceAwake(CreatureSpawner? creatureSpawner) { lock (Sync) { TrackCreatureSpawnerInstanceInternal(creatureSpawner); if (!((Object)(object)creatureSpawner == (Object)null) && !((Object)(object)((Component)creatureSpawner).gameObject == (Object)null) && ShouldApplyLocally() && !ShouldBlockClientSpawnerUpdate() && !DropNSpawnPlugin.IsGameDataRefreshDeferred(DropNSpawnPlugin.ReloadDomain.Spawner) && IsGameDataReady()) { SpawnerRuntimeConfigurationSnapshot runtimeConfigurationSnapshot = GetRuntimeConfigurationSnapshot(); if (TryGetTrackedOrCurrentCreatureSpawnerEligibility(creatureSpawner, runtimeConfigurationSnapshot, out string configPrefabName, out bool configuredEligible, out bool _) && configuredEligible && TryGetActiveCreatureSpawnerEntryCache(creatureSpawner, runtimeConfigurationSnapshot, out MatchingEntryCache entryCache, out configPrefabName)) { ReconcileCreatureSpawnerInstanceInternal(creatureSpawner, entryCache.Entries, entryCache); } } } } internal static void UntrackSpawnAreaInstance(SpawnArea? spawnArea) { lock (Sync) { ClearAppliedSpawnAreaPostSpawnOverrides(spawnArea); ClearAppliedSpawnAreaTotalSpawnLimit(spawnArea); LiveReconcilerState.ResetPendingSpawnAreaAttempt(spawnArea); if ((Object)(object)spawnArea != (Object)null && LiveRegistryStore.TryGetTrackedPrefabName(spawnArea, out string prefabName)) { UnregisterLiveSpawnArea(spawnArea, prefabName); } } } internal static void UntrackCreatureSpawnerInstance(CreatureSpawner? creatureSpawner) { lock (Sync) { if ((Object)(object)creatureSpawner != (Object)null && LiveRegistryStore.TryGetTrackedPrefabName(creatureSpawner, out string prefabName)) { UnregisterLiveCreatureSpawner(creatureSpawner, prefabName); } } } private static void RegisterLiveSpawnArea(SpawnArea? spawnArea) { if ((Object)(object)spawnArea == (Object)null || (Object)(object)((Component)spawnArea).gameObject == (Object)null) { return; } SpawnerRuntimeConfigurationSnapshot runtimeConfigurationSnapshot = GetRuntimeConfigurationSnapshot(); if (LiveRegistryStore.TryGetTrackedPrefabName(spawnArea, out string prefabName)) { CaptureSpawnAreaProvenanceIfAvailable(spawnArea); if (!string.IsNullOrWhiteSpace(prefabName)) { RefreshSpawnAreaLocationBucketMembership(spawnArea, runtimeConfigurationSnapshot); } return; } CaptureSpawnAreaProvenanceIfAvailable(spawnArea); string configPrefabName = GetConfigPrefabName(((Component)spawnArea).gameObject, "SpawnArea"); if (configPrefabName.Length == 0) { return; } if (LiveRegistryStore.TryGetTrackedPrefabName(spawnArea, out string prefabName2)) { if (string.Equals(prefabName2, configPrefabName, StringComparison.OrdinalIgnoreCase)) { return; } UnregisterLiveSpawnArea(spawnArea, prefabName2); } LiveRegistryStore.TrackSpawnAreaPrefab(spawnArea, configPrefabName); RefreshSpawnAreaLocationBucketMembership(spawnArea, runtimeConfigurationSnapshot); } private static void TrackSpawnAreaInstanceInternal(SpawnArea? spawnArea) { RegisterLiveSpawnArea(spawnArea); } private static void RegisterLiveCreatureSpawner(CreatureSpawner? creatureSpawner) { if ((Object)(object)creatureSpawner == (Object)null || (Object)(object)((Component)creatureSpawner).gameObject == (Object)null) { return; } SpawnerRuntimeConfigurationSnapshot runtimeConfigurationSnapshot = GetRuntimeConfigurationSnapshot(); if (LiveRegistryStore.TryGetTrackedPrefabName(creatureSpawner, out string prefabName)) { CaptureCreatureSpawnerProvenanceIfAvailable(creatureSpawner); if (!string.IsNullOrWhiteSpace(prefabName)) { RefreshCreatureSpawnerLocationBucketMembership(creatureSpawner, runtimeConfigurationSnapshot); } return; } CaptureCreatureSpawnerProvenanceIfAvailable(creatureSpawner); string configPrefabName = GetConfigPrefabName(((Component)creatureSpawner).gameObject, "CreatureSpawner"); if (configPrefabName.Length == 0) { return; } if (LiveRegistryStore.TryGetTrackedPrefabName(creatureSpawner, out string prefabName2)) { if (string.Equals(prefabName2, configPrefabName, StringComparison.OrdinalIgnoreCase)) { return; } UnregisterLiveCreatureSpawner(creatureSpawner, prefabName2); } LiveRegistryStore.TrackCreatureSpawnerPrefab(creatureSpawner, configPrefabName); RefreshCreatureSpawnerLocationBucketMembership(creatureSpawner, runtimeConfigurationSnapshot); } private static void TrackCreatureSpawnerInstanceInternal(CreatureSpawner? creatureSpawner) { RegisterLiveCreatureSpawner(creatureSpawner); } private static IEnumerable GetRegisteredSpawnAreas(HashSet dirtyPrefabs) { return GetRegisteredSpawnAreas(dirtyPrefabs, null); } [IteratorStateMachine(typeof(d__276))] private static IEnumerable GetRegisteredSpawnAreas(HashSet dirtyPrefabs, SpawnerRuntimeConfigurationSnapshot? runtimeConfigurationSnapshot) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__276(-2) { <>3__dirtyPrefabs = dirtyPrefabs, <>3__runtimeConfigurationSnapshot = runtimeConfigurationSnapshot }; } private static IEnumerable GetRegisteredCreatureSpawners(HashSet dirtyPrefabs) { return GetRegisteredCreatureSpawners(dirtyPrefabs, null); } [IteratorStateMachine(typeof(d__278))] private static IEnumerable GetRegisteredCreatureSpawners(HashSet dirtyPrefabs, SpawnerRuntimeConfigurationSnapshot? runtimeConfigurationSnapshot) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__278(-2) { <>3__dirtyPrefabs = dirtyPrefabs, <>3__runtimeConfigurationSnapshot = runtimeConfigurationSnapshot }; } private static bool TryGetTrackedOrCurrentSpawnAreaPrefabName(SpawnArea? spawnArea, out string configPrefabName) { configPrefabName = ""; if ((Object)(object)spawnArea == (Object)null || (Object)(object)((Component)spawnArea).gameObject == (Object)null) { return false; } configPrefabName = (LiveRegistryStore.TryGetTrackedPrefabName(spawnArea, out string prefabName) ? prefabName : GetConfigPrefabName(((Component)spawnArea).gameObject, "SpawnArea")); return configPrefabName.Length > 0; } private static bool TryGetTrackedOrCurrentCreatureSpawnerPrefabName(CreatureSpawner? creatureSpawner, out string configPrefabName) { configPrefabName = ""; if ((Object)(object)creatureSpawner == (Object)null || (Object)(object)((Component)creatureSpawner).gameObject == (Object)null) { return false; } configPrefabName = (LiveRegistryStore.TryGetTrackedPrefabName(creatureSpawner, out string prefabName) ? prefabName : GetConfigPrefabName(((Component)creatureSpawner).gameObject, "CreatureSpawner")); return configPrefabName.Length > 0; } private static bool TryGetTrackedOrCurrentSpawnAreaEligibility(SpawnArea? spawnArea, SpawnerRuntimeConfigurationSnapshot runtimeConfigurationSnapshot, out string configPrefabName, out bool configuredEligible, out bool runtimeEligible) { configPrefabName = ""; configuredEligible = false; runtimeEligible = false; if ((Object)(object)spawnArea == (Object)null || (Object)(object)((Component)spawnArea).gameObject == (Object)null) { return false; } if (LiveRegistryStore.TryGetTrackedState(spawnArea, out var trackedState)) { configPrefabName = trackedState.PrefabName; if (configPrefabName.Length == 0) { return false; } if (trackedState.EligibilityEpoch == _trackedSpawnerEligibilityEpoch) { configuredEligible = trackedState.ConfiguredEligible; runtimeEligible = trackedState.RuntimeEligible; return true; } configuredEligible = runtimeConfigurationSnapshot.ConfiguredSpawnAreaPrefabs.Contains(configPrefabName); runtimeEligible = runtimeConfigurationSnapshot.RuntimeConfiguredSpawnAreaPrefabs.Contains(configPrefabName); LiveRegistryStore.UpdateTrackedEligibility(spawnArea, configuredEligible, runtimeEligible, _trackedSpawnerEligibilityEpoch); return true; } configPrefabName = GetConfigPrefabName(((Component)spawnArea).gameObject, "SpawnArea"); if (configPrefabName.Length == 0) { return false; } configuredEligible = runtimeConfigurationSnapshot.ConfiguredSpawnAreaPrefabs.Contains(configPrefabName); runtimeEligible = runtimeConfigurationSnapshot.RuntimeConfiguredSpawnAreaPrefabs.Contains(configPrefabName); return true; } private static bool TryGetTrackedOrCurrentCreatureSpawnerEligibility(CreatureSpawner? creatureSpawner, SpawnerRuntimeConfigurationSnapshot runtimeConfigurationSnapshot, out string configPrefabName, out bool configuredEligible, out bool runtimeEligible) { configPrefabName = ""; configuredEligible = false; runtimeEligible = false; if ((Object)(object)creatureSpawner == (Object)null || (Object)(object)((Component)creatureSpawner).gameObject == (Object)null) { return false; } if (LiveRegistryStore.TryGetTrackedState(creatureSpawner, out var trackedState)) { configPrefabName = trackedState.PrefabName; if (configPrefabName.Length == 0) { return false; } if (trackedState.EligibilityEpoch == _trackedSpawnerEligibilityEpoch) { configuredEligible = trackedState.ConfiguredEligible; runtimeEligible = trackedState.RuntimeEligible; return true; } configuredEligible = runtimeConfigurationSnapshot.ConfiguredCreatureSpawnerPrefabs.Contains(configPrefabName); runtimeEligible = runtimeConfigurationSnapshot.RuntimeConfiguredCreatureSpawnerPrefabs.Contains(configPrefabName); LiveRegistryStore.UpdateTrackedEligibility(creatureSpawner, configuredEligible, runtimeEligible, _trackedSpawnerEligibilityEpoch); return true; } configPrefabName = GetConfigPrefabName(((Component)creatureSpawner).gameObject, "CreatureSpawner"); if (configPrefabName.Length == 0) { return false; } configuredEligible = runtimeConfigurationSnapshot.ConfiguredCreatureSpawnerPrefabs.Contains(configPrefabName); runtimeEligible = runtimeConfigurationSnapshot.RuntimeConfiguredCreatureSpawnerPrefabs.Contains(configPrefabName); return true; } private static void RefreshSpawnAreaLocationBucketMembership(SpawnArea? spawnArea, SpawnerRuntimeConfigurationSnapshot? runtimeConfigurationSnapshot = null) { if (!((Object)(object)spawnArea == (Object)null) && !((Object)(object)((Component)spawnArea).gameObject == (Object)null)) { SpawnerRuntimeConfigurationSnapshot runtimeConfigurationSnapshot2 = runtimeConfigurationSnapshot ?? GetRuntimeConfigurationSnapshot(); if (!TryGetTrackedOrCurrentSpawnAreaEligibility(spawnArea, runtimeConfigurationSnapshot2, out string configPrefabName, out bool configuredEligible, out bool _)) { RemoveSpawnAreaLocationBucket(spawnArea); } else if (!configuredEligible) { RemoveSpawnAreaLocationBucket(spawnArea); } else { UpdateSpawnAreaLocationBucket(spawnArea, configPrefabName); } } } private static void RefreshCreatureSpawnerLocationBucketMembership(CreatureSpawner? creatureSpawner, SpawnerRuntimeConfigurationSnapshot? runtimeConfigurationSnapshot = null) { if (!((Object)(object)creatureSpawner == (Object)null) && !((Object)(object)((Component)creatureSpawner).gameObject == (Object)null)) { SpawnerRuntimeConfigurationSnapshot runtimeConfigurationSnapshot2 = runtimeConfigurationSnapshot ?? GetRuntimeConfigurationSnapshot(); if (!TryGetTrackedOrCurrentCreatureSpawnerEligibility(creatureSpawner, runtimeConfigurationSnapshot2, out string configPrefabName, out bool configuredEligible, out bool _)) { RemoveCreatureSpawnerLocationBucket(creatureSpawner); } else if (!configuredEligible) { RemoveCreatureSpawnerLocationBucket(creatureSpawner); } else { UpdateCreatureSpawnerLocationBucket(creatureSpawner, configPrefabName); } } } private static bool TryGetRegisteredSpawnAreasFromLocationBuckets(string prefabName, HashSet selectorLocationKeys, List targetedSpawnAreas) { bool flag = false; foreach (string item in EnumerateTargetedLocationBucketKeys(selectorLocationKeys)) { string bucketKey = BuildPrefabLocationBucketKey(prefabName, item); flag |= LiveRegistryStore.AppendTrackedSpawnAreasForBucket(bucketKey, targetedSpawnAreas); } return flag; } private static bool TryGetRegisteredCreatureSpawnersFromLocationBuckets(string prefabName, HashSet selectorLocationKeys, List targetedCreatureSpawners) { bool flag = false; foreach (string item in EnumerateTargetedLocationBucketKeys(selectorLocationKeys)) { string bucketKey = BuildPrefabLocationBucketKey(prefabName, item); flag |= LiveRegistryStore.AppendTrackedCreatureSpawnersForBucket(bucketKey, targetedCreatureSpawners); } return flag; } [IteratorStateMachine(typeof(d__287))] private static IEnumerable EnumerateTargetedLocationBucketKeys(HashSet selectorLocationKeys) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__287(-2) { <>3__selectorLocationKeys = selectorLocationKeys }; } private static void CleanupRegisteredSpawnAreas() { List list = new List(); LiveRegistryStore.CollectDeadSpawnAreas(list); if (list.Count == 0) { return; } foreach (SpawnArea item in list) { if (LiveRegistryStore.TryGetTrackedPrefabName(item, out string prefabName)) { UnregisterLiveSpawnArea(item, prefabName); } } } private static void CleanupRegisteredCreatureSpawners() { List list = new List(); LiveRegistryStore.CollectDeadCreatureSpawners(list); if (list.Count == 0) { return; } foreach (CreatureSpawner item in list) { if (LiveRegistryStore.TryGetTrackedPrefabName(item, out string prefabName)) { UnregisterLiveCreatureSpawner(item, prefabName); } } } private static void UnregisterLiveSpawnArea(SpawnArea spawnArea, string prefabName) { ClearAppliedSpawnAreaPostSpawnOverrides(spawnArea); ClearAppliedSpawnAreaTotalSpawnLimit(spawnArea); LiveReconcilerState.ResetPendingSpawnAreaAttempt(spawnArea); LiveRegistryStore.UntrackSpawnAreaPrefab(spawnArea, out string _); RemoveSpawnAreaLocationBucket(spawnArea); LiveRegistryStore.RemoveLiveSnapshot(spawnArea); SelectorCacheStore.RemoveSpawnAreaEntryCache(spawnArea); SelectorCacheStore.RemoveStaticSelectorContext(((Component)spawnArea).gameObject); RuntimeStateStore.RemoveLocalRuntimeState(spawnArea); ProvenanceRegistry.RemoveSpawnAreaProvenance(spawnArea); } private static void UnregisterLiveCreatureSpawner(CreatureSpawner creatureSpawner, string prefabName) { LiveRegistryStore.UntrackCreatureSpawnerPrefab(creatureSpawner, out string _); RemoveCreatureSpawnerLocationBucket(creatureSpawner); LiveRegistryStore.RemoveLiveSnapshot(creatureSpawner); SelectorCacheStore.RemoveCreatureSpawnerEntryCache(creatureSpawner); SelectorCacheStore.RemoveStaticSelectorContext(((Component)creatureSpawner).gameObject); RuntimeStateStore.RemoveLocalRuntimeState(creatureSpawner); ProvenanceRegistry.RemoveCreatureSpawnerProvenance(creatureSpawner); } private static string BuildPrefabLocationBucketKey(string prefabName, string locationKey) { return prefabName + "|" + NormalizeSelectorLocationCacheKey(locationKey); } private static void UpdateSpawnAreaLocationBucket(SpawnArea spawnArea, string prefabName) { if (!((Object)(object)spawnArea == (Object)null) && !((Object)(object)((Component)spawnArea).gameObject == (Object)null) && !string.IsNullOrWhiteSpace(prefabName)) { string nextBucketKey = BuildPrefabLocationBucketKey(prefabName, BuildSelectorLocationCacheKey(((Component)spawnArea).gameObject)); LiveRegistryStore.UpdateSpawnAreaLocationBucket(spawnArea, nextBucketKey); } } private static void UpdateCreatureSpawnerLocationBucket(CreatureSpawner creatureSpawner, string prefabName) { if (!((Object)(object)creatureSpawner == (Object)null) && !((Object)(object)((Component)creatureSpawner).gameObject == (Object)null) && !string.IsNullOrWhiteSpace(prefabName)) { string nextBucketKey = BuildPrefabLocationBucketKey(prefabName, BuildSelectorLocationCacheKey(((Component)creatureSpawner).gameObject)); LiveRegistryStore.UpdateCreatureSpawnerLocationBucket(creatureSpawner, nextBucketKey); } } private static void RemoveSpawnAreaLocationBucket(SpawnArea spawnArea) { LiveRegistryStore.RemoveSpawnAreaLocationBucket(spawnArea); } private static void RemoveCreatureSpawnerLocationBucket(CreatureSpawner creatureSpawner) { LiveRegistryStore.RemoveCreatureSpawnerLocationBucket(creatureSpawner); } internal static void ReconcileSpawnAreaInstance(SpawnArea spawnArea) { lock (Sync) { ReconcileSpawnAreaInstanceCore(spawnArea); } } internal static void ReconcileCreatureSpawnerInstance(CreatureSpawner creatureSpawner) { lock (Sync) { ReconcileCreatureSpawnerInstanceCore(creatureSpawner); } } internal static void BeginSpawnAreaSpawnAttempt(SpawnArea spawnArea) { lock (Sync) { if (!((Object)(object)spawnArea == (Object)null)) { if (!HasAppliedSpawnAreaTrackedCustomizations(spawnArea)) { LiveReconcilerState.ResetPendingSpawnAreaAttempt(spawnArea); } else { LiveReconcilerState.BeginPendingSpawnAreaAttempt(spawnArea); } } } } internal static void RecordSelectedSpawnAreaPrefab(SpawnArea spawnArea, SpawnData? spawnData) { lock (Sync) { if (!((Object)(object)spawnArea == (Object)null) && LiveReconcilerState.HasPendingSpawnAreaAttempt(spawnArea)) { LiveReconcilerState.SetPendingSpawnAreaSelection(spawnArea, spawnData); } } } internal static void RecordSpawnAreaSpawnPoint(SpawnArea spawnArea, bool succeeded, Vector3 spawnPoint) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) lock (Sync) { if (!((Object)(object)spawnArea == (Object)null) && LiveReconcilerState.HasPendingSpawnAreaAttempt(spawnArea)) { if (!succeeded) { LiveReconcilerState.RemovePendingSpawnAreaSpawnPoint(spawnArea); } else { LiveReconcilerState.SetPendingSpawnAreaSpawnPoint(spawnArea, spawnPoint); } } } } private static void ReconcileSpawnAreaInstanceCore(SpawnArea? spawnArea) { TrackSpawnAreaInstanceInternal(spawnArea); if (IsGameDataReady() && !((Object)(object)spawnArea == (Object)null)) { if (ShouldApplyLocally() && TryGetActiveSpawnAreaEntryCache(spawnArea, out MatchingEntryCache entryCache, out string _)) { ReconcileSpawnAreaInstanceInternal(spawnArea, entryCache.Entries, entryCache); } else { RestoreSpawnAreaInstance(spawnArea); } } } private static void ReconcileCreatureSpawnerInstanceCore(CreatureSpawner? creatureSpawner) { TrackCreatureSpawnerInstanceInternal(creatureSpawner); if (IsGameDataReady() && !((Object)(object)creatureSpawner == (Object)null)) { if (ShouldApplyLocally() && TryGetActiveCreatureSpawnerEntryCache(creatureSpawner, out MatchingEntryCache entryCache, out string _)) { ReconcileCreatureSpawnerInstanceInternal(creatureSpawner, entryCache.Entries, entryCache); } else { RestoreCreatureSpawnerInstance(creatureSpawner, refreshRuntimeState: true); } } } private static void ReconcileSpawnAreaInstanceInternal(SpawnArea? spawnArea, IEnumerable? entries, MatchingEntryCache? entryCache = null, bool usePreselectedWinner = false, SpawnerRuntimeEntry? preselectedWinningEntry = null) { if (!((Object)(object)spawnArea == (Object)null) && !((Object)(object)((Component)spawnArea).gameObject == (Object)null)) { CaptureLiveSpawnAreaSnapshotIfNeeded(spawnArea); RestoreSpawnAreaInstance(spawnArea); SpawnerRuntimeEntry winningEntry = preselectedWinningEntry; bool flag = (usePreselectedWinner ? (winningEntry != null) : TrySelectWinningSpawnerEntry(((Component)spawnArea).gameObject, entries, forSpawnArea: true, out winningEntry)); if (flag && winningEntry?.SpawnArea != null) { ApplySpawnArea(spawnArea, winningEntry.SpawnArea, winningEntry.Prefab + "@" + DescribeInstance(((Component)spawnArea).gameObject)); } ApplySpawnAreaTotalSpawnLimit(spawnArea, (!flag) ? null : winningEntry?.SpawnArea?.MaxTotalSpawns); if (entryCache == null) { entryCache = (SelectorCacheStore.TryGetSpawnAreaEntryCache(spawnArea, out MatchingEntryCache entryCache2) ? entryCache2 : null); } UpdateSpawnAreaRuntimeSignature(spawnArea, entries, entryCache); } } private static void ReconcileCreatureSpawnerInstanceInternal(CreatureSpawner? creatureSpawner, IEnumerable? entries, MatchingEntryCache? entryCache = null, bool usePreselectedWinner = false, SpawnerRuntimeEntry? preselectedWinningEntry = null) { if (!((Object)(object)creatureSpawner == (Object)null) && !((Object)(object)((Component)creatureSpawner).gameObject == (Object)null)) { CaptureLiveCreatureSpawnerSnapshotIfNeeded(creatureSpawner); int previousInterval = Math.Max(1, creatureSpawner.m_spawnInterval); int spawnGroupID = creatureSpawner.m_spawnGroupID; int maxGroupSpawned = creatureSpawner.m_maxGroupSpawned; float spawnGroupRadius = creatureSpawner.m_spawnGroupRadius; float spawnerWeight = creatureSpawner.m_spawnerWeight; RestoreCreatureSpawnerInstance(creatureSpawner); SpawnerRuntimeEntry winningEntry = preselectedWinningEntry; if ((usePreselectedWinner ? (winningEntry != null) : TrySelectWinningSpawnerEntry(((Component)creatureSpawner).gameObject, entries, forSpawnArea: false, out winningEntry)) && winningEntry?.CreatureSpawner != null) { ApplyCreatureSpawner(creatureSpawner, winningEntry.CreatureSpawner, winningEntry.Prefab + "@" + DescribeInstance(((Component)creatureSpawner).gameObject)); } if (entryCache == null) { entryCache = (SelectorCacheStore.TryGetCreatureSpawnerEntryCache(creatureSpawner, out MatchingEntryCache entryCache2) ? entryCache2 : null); } UpdateCreatureSpawnerRuntimeSignature(creatureSpawner, entries, entryCache); MaybeRefreshCreatureSpawnerSchedule(creatureSpawner, previousInterval); MaybeResetCreatureSpawnerCaches(creatureSpawner, spawnGroupID, maxGroupSpawned, spawnGroupRadius, spawnerWeight); } } private static void CaptureLiveSpawnAreaSnapshotIfNeeded(SpawnArea spawnArea) { if (!((Object)(object)spawnArea == (Object)null) && !LiveRegistryStore.HasLiveSnapshot(spawnArea)) { LiveRegistryStore.CaptureLiveSnapshot(spawnArea, new SpawnAreaLiveSnapshot { LevelUpChance = spawnArea.m_levelupChance, SpawnInterval = spawnArea.m_spawnIntervalSec, TriggerDistance = spawnArea.m_triggerDistance, SetPatrolSpawnPoint = spawnArea.m_setPatrolSpawnPoint, SpawnRadius = spawnArea.m_spawnRadius, NearRadius = spawnArea.m_nearRadius, FarRadius = spawnArea.m_farRadius, MaxNear = spawnArea.m_maxNear, MaxTotal = spawnArea.m_maxTotal, OnGroundOnly = spawnArea.m_onGroundOnly, Prefabs = CloneSpawnAreaSnapshots(spawnArea.m_prefabs) }); } } private static void CaptureLiveCreatureSpawnerSnapshotIfNeeded(CreatureSpawner creatureSpawner) { if (!((Object)(object)creatureSpawner == (Object)null) && !LiveRegistryStore.HasLiveSnapshot(creatureSpawner)) { LiveRegistryStore.CaptureLiveSnapshot(creatureSpawner, new CreatureSpawnerLiveSnapshot { CreaturePrefab = creatureSpawner.m_creaturePrefab, MinLevel = creatureSpawner.m_minLevel, MaxLevel = creatureSpawner.m_maxLevel, LevelUpChance = creatureSpawner.m_levelupChance, RespawnTimeMinutes = creatureSpawner.m_respawnTimeMinuts, TriggerDistance = creatureSpawner.m_triggerDistance, TriggerNoise = creatureSpawner.m_triggerNoise, SpawnAtNight = creatureSpawner.m_spawnAtNight, SpawnAtDay = creatureSpawner.m_spawnAtDay, RequireSpawnArea = creatureSpawner.m_requireSpawnArea, SpawnInPlayerBase = creatureSpawner.m_spawnInPlayerBase, WakeUpAnimation = creatureSpawner.m_wakeUpAnimation, SpawnCheckInterval = creatureSpawner.m_spawnInterval, RequiredGlobalKey = (creatureSpawner.m_requiredGlobalKey ?? ""), BlockingGlobalKey = (creatureSpawner.m_blockingGlobalKey ?? ""), SetPatrolSpawnPoint = creatureSpawner.m_setPatrolSpawnPoint, SpawnGroupId = creatureSpawner.m_spawnGroupID, MaxGroupSpawned = creatureSpawner.m_maxGroupSpawned, SpawnGroupRadius = creatureSpawner.m_spawnGroupRadius, SpawnerWeight = creatureSpawner.m_spawnerWeight }); } } private static void RestoreSpawnAreaInstance(SpawnArea spawnArea) { RuntimeStateStore.RemoveRuntimeSignature(spawnArea); ClearAppliedSpawnAreaPostSpawnOverrides(spawnArea); ClearAppliedSpawnAreaTotalSpawnLimit(spawnArea); if (LiveRegistryStore.TryGetLiveSnapshot(spawnArea, out SpawnAreaLiveSnapshot snapshot)) { RestoreSpawnArea(spawnArea, snapshot); } } private static void RestoreCreatureSpawnerInstance(CreatureSpawner creatureSpawner, bool refreshRuntimeState = false) { int previousInterval = Math.Max(1, creatureSpawner.m_spawnInterval); int spawnGroupID = creatureSpawner.m_spawnGroupID; int maxGroupSpawned = creatureSpawner.m_maxGroupSpawned; float spawnGroupRadius = creatureSpawner.m_spawnGroupRadius; float spawnerWeight = creatureSpawner.m_spawnerWeight; LiveReconcilerState.ClearAppliedCreatureSpawnerOverrides(creatureSpawner); if (LiveRegistryStore.TryGetLiveSnapshot(creatureSpawner, out CreatureSpawnerLiveSnapshot snapshot)) { RestoreCreatureSpawner(creatureSpawner, snapshot); if (refreshRuntimeState) { RuntimeStateStore.RemoveRuntimeSignature(creatureSpawner); MaybeRefreshCreatureSpawnerSchedule(creatureSpawner, previousInterval); MaybeResetCreatureSpawnerCaches(creatureSpawner, spawnGroupID, maxGroupSpawned, spawnGroupRadius, spawnerWeight); } } } internal static void RecordSpawnedLocationProxyProvenance(LocationProxy? proxy, GameObject? spawnedRoot) { lock (Sync) { if (!((Object)(object)proxy == (Object)null) && !((Object)(object)spawnedRoot == (Object)null) && (TryGetActiveLocationSpawnContextPrefab(out string locationPrefab) || TryGetLocationProxyPrefabName(proxy, out locationPrefab))) { Transform transform = spawnedRoot.transform; RecordSpawnedLocationRootProvenance(transform, locationPrefab); QueueSpawnedLocationRootProvenanceScan(transform, locationPrefab); } } } internal static void BeginLocationSpawnContext(ZoneLocation? location) { lock (Sync) { PushLocationSpawnContext(GetZoneLocationPrefabName(location)); } } internal static void BeginLocationSpawnContext(string? locationPrefab) { lock (Sync) { PushLocationSpawnContext(locationPrefab); } } internal static bool TryBeginDerivedLocationSpawnContext(Component? source) { lock (Sync) { if ((Object)(object)source == (Object)null || (Object)(object)source.gameObject == (Object)null) { return false; } if (!TryResolveLocationSpawnContext(source.gameObject, out string locationPrefab)) { return false; } PushLocationSpawnContext(locationPrefab); return true; } } internal static void EndLocationSpawnContext() { lock (Sync) { ProvenanceRegistry.PopLocationSpawnContext(); } } private static void PushLocationSpawnContext(string? locationPrefab) { ProvenanceRegistry.PushLocationSpawnContext(locationPrefab); } private static bool TryResolveLocationSpawnContext(GameObject gameObject, out string locationPrefab) { locationPrefab = ""; if ((Object)(object)gameObject == (Object)null) { return false; } if (TryGetActiveLocationSpawnContextPrefab(out locationPrefab)) { return locationPrefab.Length > 0; } if (TryFindRecordedLocationRoot(gameObject.transform, out Transform _, out locationPrefab)) { return locationPrefab.Length > 0; } if (TryGetLiveLocationProxyPrefab(gameObject, out locationPrefab)) { return locationPrefab.Length > 0; } Location componentInParent = gameObject.GetComponentInParent(true); if ((Object)(object)componentInParent != (Object)null && TryGetLocationPrefabName(componentInParent, out locationPrefab)) { return locationPrefab.Length > 0; } if (TryGetStaticLocationContext(gameObject, out locationPrefab, out string _)) { return locationPrefab.Length > 0; } if (TryGetZoneLocationContext(gameObject, out locationPrefab)) { return locationPrefab.Length > 0; } if (TryGetSpatialLocationContext(gameObject, out locationPrefab)) { return locationPrefab.Length > 0; } return false; } internal static bool TryGetResolvedLocationNameForConditions(GameObject? gameObject, out string locationPrefab) { lock (Sync) { locationPrefab = ""; if ((Object)(object)gameObject == (Object)null) { return false; } if (TryGetRecordedLocationContext(gameObject, out locationPrefab, out string relativePath)) { return locationPrefab.Length > 0; } if (TryGetCurrentLocationSpawnContext(gameObject, out locationPrefab, out relativePath)) { return locationPrefab.Length > 0; } if (TryGetLiveLocationProxyContext(gameObject, out locationPrefab, out relativePath)) { return locationPrefab.Length > 0; } if (TryGetStaticLocationContext(gameObject, out locationPrefab, out relativePath)) { return locationPrefab.Length > 0; } if (TryGetZoneLocationContext(gameObject, out locationPrefab)) { return locationPrefab.Length > 0; } return false; } } internal static void UntrackLocationInstanceProvenance(Location? location) { lock (Sync) { if (!((Object)(object)location == (Object)null)) { ProvenanceRegistry.RemoveSpawnedLocationRoot(((Component)location).transform); } } } private static bool TryGetLiveLocationProxyContext(GameObject gameObject, out string locationPrefab, out string relativePath) { locationPrefab = ""; relativePath = ""; if ((Object)(object)gameObject == (Object)null) { return false; } LocationProxy componentInParent = gameObject.GetComponentInParent(true); if ((Object)(object)componentInParent == (Object)null || !TryGetLocationProxyPrefabName(componentInParent, out locationPrefab)) { return false; } Transform locationProxySpawnedRootTransform = GetLocationProxySpawnedRootTransform(((Component)componentInParent).transform, gameObject.transform); if ((Object)(object)locationProxySpawnedRootTransform == (Object)null) { return false; } relativePath = GetRelativePath(locationProxySpawnedRootTransform, gameObject.transform); return relativePath.Length > 0; } private static bool TryGetLocationProxyPrefabName(LocationProxy proxy, out string prefabName) { return LocationManager.TryResolveLocationProxyPrefabName(proxy, out prefabName); } private static bool TryGetDirectLocationContext(GameObject gameObject, out string locationPrefab, out string relativePath) { locationPrefab = ""; relativePath = ""; if ((Object)(object)gameObject == (Object)null) { return false; } Location componentInParent = gameObject.GetComponentInParent(true); if ((Object)(object)componentInParent == (Object)null || !TryGetLocationPrefabName(componentInParent, out locationPrefab)) { return false; } relativePath = GetRelativePath(((Component)componentInParent).transform, gameObject.transform); return locationPrefab.Length > 0; } private static bool TryGetStaticLocationContext(GameObject gameObject, out string locationPrefab, out string relativePath) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) locationPrefab = ""; relativePath = ""; if ((Object)(object)gameObject == (Object)null) { return false; } Location val = Location.GetLocation(gameObject.transform.position, true); if ((Object)(object)val == (Object)null) { val = Location.GetZoneLocation(gameObject.transform.position); } if ((Object)(object)val == (Object)null || !TryGetLocationPrefabName(val, out locationPrefab)) { return false; } relativePath = TryGetRelativePathIfDescendant(((Component)val).transform, gameObject.transform); return locationPrefab.Length > 0; } private static bool TryGetRecordedLocationContext(GameObject gameObject, out string locationPrefab, out string relativePath) { locationPrefab = ""; relativePath = ""; if ((Object)(object)gameObject == (Object)null) { return false; } SpawnArea spawnArea = default(SpawnArea); if (gameObject.TryGetComponent(ref spawnArea) && ProvenanceRegistry.TryGetSpawnAreaProvenance(spawnArea, out SpawnerLocationProvenance provenance)) { locationPrefab = provenance.LocationPrefab; relativePath = provenance.RelativePath; return locationPrefab.Length > 0; } CreatureSpawner creatureSpawner = default(CreatureSpawner); if (gameObject.TryGetComponent(ref creatureSpawner) && ProvenanceRegistry.TryGetCreatureSpawnerProvenance(creatureSpawner, out SpawnerLocationProvenance provenance2)) { locationPrefab = provenance2.LocationPrefab; relativePath = provenance2.RelativePath; return locationPrefab.Length > 0; } return false; } private static bool TryGetCurrentLocationSpawnContext(GameObject gameObject, out string locationPrefab, out string relativePath) { locationPrefab = ""; relativePath = ""; if ((Object)(object)gameObject == (Object)null || !TryGetActiveLocationSpawnContextPrefab(out locationPrefab)) { return false; } SpawnArea val = default(SpawnArea); CreatureSpawner val2 = default(CreatureSpawner); if (!gameObject.TryGetComponent(ref val) && !gameObject.TryGetComponent(ref val2)) { return false; } return locationPrefab.Length > 0; } private static bool TryGetSpatialLocationContext(GameObject gameObject, out string locationPrefab) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) locationPrefab = ""; if ((Object)(object)gameObject == (Object)null || (Object)(object)ZoneSystem.instance == (Object)null) { return false; } Vector3 position = gameObject.transform.position; float num = float.MaxValue; bool flag = false; foreach (LocationInstance value in ZoneSystem.instance.m_locationInstances.Values) { string zoneLocationPrefabName = GetZoneLocationPrefabName(value.m_location); if (zoneLocationPrefabName.Length == 0) { continue; } float num2 = Mathf.Max(value.m_location.m_exteriorRadius, value.m_location.m_interiorRadius); if (!(num2 <= 0f)) { float num3 = Utils.DistanceXZ(value.m_position, position); if (!(num3 > num2) && (!flag || num3 < num)) { num = num3; locationPrefab = zoneLocationPrefabName; flag = true; } } } return flag; } private static bool TryGetZoneLocationContext(GameObject gameObject, out string locationPrefab) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) locationPrefab = ""; if ((Object)(object)gameObject == (Object)null || (Object)(object)ZoneSystem.instance == (Object)null) { return false; } Vector2i zone = ZoneSystem.GetZone(gameObject.transform.position); if (!ZoneSystem.instance.m_locationInstances.TryGetValue(zone, out var value)) { return false; } string zoneLocationPrefabName = GetZoneLocationPrefabName(value.m_location); if (zoneLocationPrefabName.Length == 0) { return false; } locationPrefab = zoneLocationPrefabName; return true; } private static Transform? GetLocationProxySpawnedRootTransform(Transform proxyTransform, Transform target) { Transform val = target; while ((Object)(object)val != (Object)null && (Object)(object)val.parent != (Object)null) { if (val.parent == proxyTransform) { return val; } val = val.parent; } return null; } private static void RecordSpawnedLocationRootProvenance(Transform rootTransform, string locationPrefab) { ProvenanceRegistry.RecordSpawnedLocationRoot(rootTransform, locationPrefab); } private static void QueueSpawnedLocationRootProvenanceScan(Transform rootTransform, string locationPrefab) { ProvenanceRegistry.TryQueueRootProvenanceScan(rootTransform, locationPrefab, _reconcileQueueEpoch); } private static bool ProcessQueuedLocationRootProvenanceStep(float deadline) { PendingLocationRootProvenanceScan pendingScan; SpawnArea val2 = default(SpawnArea); CreatureSpawner val3 = default(CreatureSpawner); while (ProvenanceRegistry.TryPeekPendingRootScan(out pendingScan)) { if (pendingScan.Epoch != _reconcileQueueEpoch) { ProvenanceRegistry.DiscardPendingRootScan(pendingScan); continue; } if ((Object)(object)pendingScan.RootTransform == (Object)null || string.IsNullOrWhiteSpace(pendingScan.LocationPrefab)) { ProvenanceRegistry.DiscardPendingRootScan(pendingScan); return true; } PendingLocationRootProvenanceScan pendingLocationRootProvenanceScan = pendingScan; if (pendingLocationRootProvenanceScan.TraversalStack == null) { List obj = new List { pendingScan.RootTransform }; List list = obj; pendingLocationRootProvenanceScan.TraversalStack = obj; } int num = 0; while (pendingScan.TraversalStack.Count > 0) { if ((num & 0xF) == 0 && Time.realtimeSinceStartup >= deadline) { return num > 0; } int index = pendingScan.TraversalStack.Count - 1; Transform val = pendingScan.TraversalStack[index]; pendingScan.TraversalStack.RemoveAt(index); num++; if ((Object)(object)val == (Object)null) { continue; } if (((Component)val).TryGetComponent(ref val2) && (Object)(object)val2 != (Object)null) { RecordSpawnAreaProvenance(val2, pendingScan.RootTransform, pendingScan.LocationPrefab); } if (((Component)val).TryGetComponent(ref val3) && (Object)(object)val3 != (Object)null) { RecordCreatureSpawnerProvenance(val3, pendingScan.RootTransform, pendingScan.LocationPrefab); } for (int num2 = val.childCount - 1; num2 >= 0; num2--) { Transform child = val.GetChild(num2); if ((Object)(object)child != (Object)null) { pendingScan.TraversalStack.Add(child); } } } ProvenanceRegistry.DiscardPendingRootScan(pendingScan); return true; } return false; } private static void CaptureSpawnAreaProvenanceIfAvailable(SpawnArea spawnArea) { if (!((Object)(object)spawnArea == (Object)null) && !ProvenanceRegistry.HasSpawnAreaProvenance(spawnArea) && TryResolveSpawnerProvenance(((Component)spawnArea).gameObject, out Transform rootTransform, out string locationPrefab, out string relativePath)) { RecordSpawnAreaProvenance(spawnArea, rootTransform, locationPrefab, relativePath); } } private static void CaptureCreatureSpawnerProvenanceIfAvailable(CreatureSpawner creatureSpawner) { if (!((Object)(object)creatureSpawner == (Object)null) && !ProvenanceRegistry.HasCreatureSpawnerProvenance(creatureSpawner) && TryResolveSpawnerProvenance(((Component)creatureSpawner).gameObject, out Transform rootTransform, out string locationPrefab, out string relativePath)) { RecordCreatureSpawnerProvenance(creatureSpawner, rootTransform, locationPrefab, relativePath); } } private static bool TryResolveSpawnerProvenance(GameObject gameObject, out Transform? rootTransform, out string locationPrefab, out string relativePath) { rootTransform = null; locationPrefab = ""; relativePath = ""; if ((Object)(object)gameObject == (Object)null) { return false; } if (TryFindRecordedLocationRoot(gameObject.transform, out rootTransform, out locationPrefab)) { relativePath = GetRelativePath(rootTransform, gameObject.transform); return locationPrefab.Length > 0; } if (TryGetActiveLocationSpawnContextPrefab(out locationPrefab)) { rootTransform = GetRootTransform(gameObject.transform); return locationPrefab.Length > 0; } if (TryGetLiveLocationProxyContext(gameObject, out locationPrefab, out relativePath)) { rootTransform = GetLocationContextRootTransform(gameObject); return relativePath.Length > 0; } Location componentInParent = gameObject.GetComponentInParent(true); if ((Object)(object)componentInParent != (Object)null && TryGetLocationPrefabName(componentInParent, out locationPrefab)) { rootTransform = ((Component)componentInParent).transform; relativePath = GetRelativePath(((Component)componentInParent).transform, gameObject.transform); return locationPrefab.Length > 0; } if (TryPromoteZoneContextToRecordedProvenance(gameObject, out locationPrefab, out relativePath)) { rootTransform = GetRootTransform(gameObject.transform); return locationPrefab.Length > 0; } if (TryPromoteSpatialContextToRecordedProvenance(gameObject, out locationPrefab, out relativePath)) { rootTransform = GetRootTransform(gameObject.transform); return locationPrefab.Length > 0; } return false; } private static bool TryFindRecordedLocationRoot(Transform transform, out Transform? rootTransform, out string locationPrefab) { return ProvenanceRegistry.TryFindRecordedLocationRoot(transform, out rootTransform, out locationPrefab); } private static Transform? GetLocationContextRootTransform(GameObject gameObject) { if ((Object)(object)gameObject == (Object)null) { return null; } LocationProxy componentInParent = gameObject.GetComponentInParent(true); if ((Object)(object)componentInParent != (Object)null) { return GetLocationProxySpawnedRootTransform(((Component)componentInParent).transform, gameObject.transform); } Location componentInParent2 = gameObject.GetComponentInParent(true); if (componentInParent2 == null) { return null; } return ((Component)componentInParent2).transform; } private static int AllocateLocationProvenanceEpoch() { return ProvenanceRegistry.AllocateLocationProvenanceEpoch(); } private static void RecordSpawnAreaProvenance(SpawnArea? spawnArea, Transform? rootTransform, string locationPrefab, string? relativePath = null) { if (!((Object)(object)spawnArea == (Object)null) && !string.IsNullOrWhiteSpace(locationPrefab)) { string relativePath2 = relativePath ?? (((Object)(object)rootTransform != (Object)null) ? GetRelativePath(rootTransform, ((Component)spawnArea).transform) : ""); ProvenanceRegistry.RecordSpawnAreaProvenance(spawnArea, new SpawnerLocationProvenance { Epoch = AllocateLocationProvenanceEpoch(), LocationPrefab = locationPrefab, RelativePath = relativePath2 }); SelectorCacheStore.RemoveSpawnAreaEntryCache(spawnArea); if (LiveRegistryStore.TryGetTrackedPrefabName(spawnArea, out string _)) { RefreshSpawnAreaLocationBucketMembership(spawnArea); } } } private static void RecordCreatureSpawnerProvenance(CreatureSpawner? creatureSpawner, Transform? rootTransform, string locationPrefab, string? relativePath = null) { if (!((Object)(object)creatureSpawner == (Object)null) && !string.IsNullOrWhiteSpace(locationPrefab)) { string relativePath2 = relativePath ?? (((Object)(object)rootTransform != (Object)null) ? GetRelativePath(rootTransform, ((Component)creatureSpawner).transform) : ""); ProvenanceRegistry.RecordCreatureSpawnerProvenance(creatureSpawner, new SpawnerLocationProvenance { Epoch = AllocateLocationProvenanceEpoch(), LocationPrefab = locationPrefab, RelativePath = relativePath2 }); SelectorCacheStore.RemoveCreatureSpawnerEntryCache(creatureSpawner); if (LiveRegistryStore.TryGetTrackedPrefabName(creatureSpawner, out string _)) { RefreshCreatureSpawnerLocationBucketMembership(creatureSpawner); } } } private static bool TryGetActiveLocationSpawnContextPrefab(out string locationPrefab) { return ProvenanceRegistry.TryGetActiveLocationSpawnContextPrefab(out locationPrefab); } private static bool TryPromoteSpatialContextToRecordedProvenance(GameObject gameObject, out string locationPrefab, out string relativePath) { locationPrefab = ""; relativePath = ""; if ((Object)(object)gameObject == (Object)null || !TryGetSpatialLocationContext(gameObject, out locationPrefab)) { return false; } SpawnArea spawnArea = default(SpawnArea); if (gameObject.TryGetComponent(ref spawnArea)) { RecordSpawnAreaProvenance(spawnArea, GetRootTransform(gameObject.transform), locationPrefab, relativePath); return true; } CreatureSpawner creatureSpawner = default(CreatureSpawner); if (gameObject.TryGetComponent(ref creatureSpawner)) { RecordCreatureSpawnerProvenance(creatureSpawner, GetRootTransform(gameObject.transform), locationPrefab, relativePath); return true; } return false; } private static bool TryPromoteZoneContextToRecordedProvenance(GameObject gameObject, out string locationPrefab, out string relativePath) { locationPrefab = ""; relativePath = ""; if ((Object)(object)gameObject == (Object)null || !TryGetZoneLocationContext(gameObject, out locationPrefab)) { return false; } SpawnArea spawnArea = default(SpawnArea); if (gameObject.TryGetComponent(ref spawnArea)) { RecordSpawnAreaProvenance(spawnArea, GetRootTransform(gameObject.transform), locationPrefab, relativePath); return true; } CreatureSpawner creatureSpawner = default(CreatureSpawner); if (gameObject.TryGetComponent(ref creatureSpawner)) { RecordCreatureSpawnerProvenance(creatureSpawner, GetRootTransform(gameObject.transform), locationPrefab, relativePath); return true; } return false; } private static bool TryGetLocationPrefabName(Location location, out string prefabName) { return LocationManager.TryResolveRuntimeLocationPrefabName(location, out prefabName); } private static string GetZoneLocationPrefabName(ZoneLocation? location) { return (location?.m_prefabName ?? location?.m_prefab.Name ?? "").Trim(); } private static string TryGetRelativePathIfDescendant(Transform root, Transform target) { if ((Object)(object)root == (Object)null || (Object)(object)target == (Object)null) { return ""; } if (root == target || target.IsChildOf(root)) { return GetRelativePath(root, target); } return ""; } private static Transform GetRootTransform(Transform transform) { Transform val = transform; while ((Object)(object)val.parent != (Object)null) { val = val.parent; } return val; } internal static void QueueSpawnAreaReconcile(SpawnArea? spawnArea) { lock (Sync) { if (!((Object)(object)spawnArea == (Object)null) && !((Object)(object)((Component)spawnArea).gameObject == (Object)null)) { ReconcileQueue.TryQueue(spawnArea, _reconcileQueueEpoch); } } } internal static void QueueCreatureSpawnerReconcile(CreatureSpawner? creatureSpawner) { lock (Sync) { if (!((Object)(object)creatureSpawner == (Object)null) && !((Object)(object)((Component)creatureSpawner).gameObject == (Object)null)) { ReconcileQueue.TryQueue(creatureSpawner, _reconcileQueueEpoch); } } } internal static bool HasPendingReconcileWork() { lock (Sync) { return ProvenanceRegistry.HasPendingRootScans() || ReconcileQueue.HasPendingWork(); } } internal static bool ProcessQueuedReconcileStep(float deadline) { lock (Sync) { if (Time.realtimeSinceStartup >= deadline) { return false; } if (ShouldBlockClientSpawnerUpdate() || !IsGameDataReady() || DropNSpawnPlugin.IsGameDataRefreshDeferred(DropNSpawnPlugin.ReloadDomain.Spawner)) { return false; } if (ProcessQueuedLocationRootProvenanceStep(deadline)) { return true; } if (ReconcileQueue.TryDequeueNextSpawnArea(_reconcileQueueEpoch, out SpawnArea spawnArea)) { ReconcileSpawnAreaInstanceCore(spawnArea); return true; } if (ReconcileQueue.TryDequeueNextCreatureSpawner(_reconcileQueueEpoch, out CreatureSpawner creatureSpawner)) { ReconcileCreatureSpawnerInstanceCore(creatureSpawner); return true; } } return false; } private static void ClearQueuedReconcileState() { _reconcileQueueEpoch++; ProvenanceRegistry.ClearPendingRootScans(); ReconcileQueue.Clear(); } private static List BuildTemplateAggregates() { Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); Dictionary> locationPrefabsBySpawnerPrefab = BuildLocationReferenceLookup(); foreach (SpawnAreaComponentSnapshot spawnAreaSnapshot in SpawnAreaSnapshots) { if (!dictionary.TryGetValue(spawnAreaSnapshot.ConfigPrefabName, out var value)) { value = new TemplateAggregate { Prefab = spawnAreaSnapshot.ConfigPrefabName }; dictionary[spawnAreaSnapshot.ConfigPrefabName] = value; } TemplateAggregate templateAggregate = value; if (templateAggregate.SpawnArea == null) { SpawnAreaComponentSnapshot spawnAreaComponentSnapshot2 = (templateAggregate.SpawnArea = spawnAreaSnapshot); } TrackAggregateRootPrefab(value, spawnAreaSnapshot.RootPrefabName); TrackAggregateLocationPrefabs(value, locationPrefabsBySpawnerPrefab, spawnAreaSnapshot.ConfigPrefabName); } foreach (CreatureSpawnerComponentSnapshot creatureSpawnerSnapshot in CreatureSpawnerSnapshots) { if (!dictionary.TryGetValue(creatureSpawnerSnapshot.ConfigPrefabName, out var value2)) { value2 = new TemplateAggregate { Prefab = creatureSpawnerSnapshot.ConfigPrefabName }; dictionary[creatureSpawnerSnapshot.ConfigPrefabName] = value2; } TemplateAggregate templateAggregate = value2; if (templateAggregate.CreatureSpawner == null) { CreatureSpawnerComponentSnapshot creatureSpawnerComponentSnapshot2 = (templateAggregate.CreatureSpawner = creatureSpawnerSnapshot); } TrackAggregateRootPrefab(value2, creatureSpawnerSnapshot.RootPrefabName); TrackAggregateLocationPrefabs(value2, locationPrefabsBySpawnerPrefab, creatureSpawnerSnapshot.ConfigPrefabName); } List list = dictionary.Values.ToList(); foreach (TemplateAggregate item in list) { item.OwnerName = ResolveSpawnerOwnerName(item.Prefab, item.LocationPrefabs, item.RootPrefabs); } list.Sort(CompareSpawnerAggregatesForOutput); return list; } private static List> BuildTemplateAggregateSections() { List> list = PrefabOutputSections.BuildSections(BuildTemplateAggregates(), (TemplateAggregate aggregate) => aggregate.Prefab, (TemplateAggregate aggregate) => aggregate.OwnerName); foreach (PrefabOwnerSection item in list) { item.Entries.Sort(CompareSpawnerAggregatesForOutput); } return list; } private static List> BuildConfigurationTemplate() { return (from section in BuildTemplateAggregateSections() select new PrefabOwnerSection(section.OwnerName, section.Entries.Select(BuildConfigurationEntry).ToList())).ToList(); } private static string BuildReferenceConfigurationTemplate() { return PrefabOutputSections.SerializeReferenceSections((from section in BuildTemplateAggregateSections() select new PrefabOwnerSection(section.OwnerName, section.Entries.Select((TemplateAggregate aggregate) => new SpawnerReferenceEntry { Prefab = aggregate.Prefab, SpawnArea = ((aggregate.SpawnArea != null) ? ConvertSpawnArea(aggregate.SpawnArea) : null), CreatureSpawner = ((aggregate.CreatureSpawner != null) ? ConvertCreatureSpawner(aggregate.CreatureSpawner) : null) }).ToList())).ToList(), Serializer); } private static string SerializeReferenceEntries(IEnumerable entries) { return ReferenceRefreshSupport.SerializeReferenceSections(entries, (SpawnerReferenceEntry entry) => entry.Prefab, Serializer); } private static string BuildLocationReferenceConfigurationTemplate() { List source = BuildTemplateAggregates(); return SerializeLocationReferenceEntries(ownerNamesByPrefab: source.ToDictionary((TemplateAggregate aggregate) => aggregate.Prefab, (TemplateAggregate aggregate) => aggregate.OwnerName, StringComparer.OrdinalIgnoreCase), entries: (from aggregate in source.Where((TemplateAggregate aggregate) => aggregate.LocationPrefabs.Count > 0).OrderBy((TemplateAggregate aggregate) => aggregate.Prefab, StringComparer.OrdinalIgnoreCase) select new SpawnerLocationReferenceEntry { Prefab = aggregate.Prefab, Locations = aggregate.LocationPrefabs.OrderBy((string location) => location, StringComparer.OrdinalIgnoreCase).ToList() }).ToList()); } private static Dictionary> BuildLocationReferenceLookup() { Dictionary> dictionary = new Dictionary>(StringComparer.OrdinalIgnoreCase); foreach (var item3 in EnumerateLocationRootPrefabs()) { string item = item3.LocationPrefab; GameObject item2 = item3.RootPrefab; SpawnArea[] componentsInChildren = item2.GetComponentsInChildren(true); foreach (SpawnArea val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).gameObject == (Object)null)) { AddLocationReferenceLocation(dictionary, GetLocationReferencePrefabName(((Component)val).gameObject), item); } } CreatureSpawner[] componentsInChildren2 = item2.GetComponentsInChildren(true); foreach (CreatureSpawner val2 in componentsInChildren2) { if (!((Object)(object)val2 == (Object)null) && !((Object)(object)((Component)val2).gameObject == (Object)null)) { AddLocationReferenceLocation(dictionary, GetLocationReferencePrefabName(((Component)val2).gameObject), item); } } } return dictionary; } private static string SerializeLocationReferenceEntries(IEnumerable entries, IReadOnlyDictionary ownerNamesByPrefab) { IReadOnlyDictionary ownerNamesByPrefab2 = ownerNamesByPrefab; List> list = PrefabOutputSections.BuildSections(entries, (SpawnerLocationReferenceEntry entry) => entry.Prefab, (SpawnerLocationReferenceEntry entry) => ResolveSpawnerLocationReferenceOwnerName(entry, ownerNamesByPrefab2)); foreach (PrefabOwnerSection item in list) { item.Entries.Sort((SpawnerLocationReferenceEntry left, SpawnerLocationReferenceEntry right) => StringComparer.OrdinalIgnoreCase.Compare(left.Prefab, right.Prefab)); } return PrefabOutputSections.SerializeReferenceSections(list, Serializer); } private static void WriteReferenceConfigurationFile(string? referenceContent, string? locationReferenceContent, string logMessage, bool writePrimaryReference, bool writeLocationReference) { Directory.CreateDirectory(DropNSpawnPlugin.YamlConfigDirectoryPath); if (writePrimaryReference && referenceContent != null) { GeneratedFileWriter.WriteAllTextIfChanged(ReferenceConfigurationPath, referenceContent); } if (writeLocationReference && locationReferenceContent != null) { GeneratedFileWriter.WriteAllTextIfChanged(LocationReferenceConfigurationPath, locationReferenceContent); } DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)logMessage); } [IteratorStateMachine(typeof(d__371))] private static IEnumerable<(string LocationPrefab, GameObject RootPrefab)> EnumerateLocationRootPrefabs() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__371(-2); } private static void AddLocationReferenceLocation(Dictionary> groupedLocations, string configPrefabName, string locationPrefab) { string text = (configPrefabName ?? "").Trim(); string text2 = (locationPrefab ?? "").Trim(); if (text.Length != 0 && text2.Length != 0) { if (!groupedLocations.TryGetValue(text, out SortedSet value)) { value = (groupedLocations[text] = new SortedSet(StringComparer.OrdinalIgnoreCase)); } value.Add(text2); } } private static SpawnerConfigurationEntry BuildConfigurationEntry(TemplateAggregate aggregate) { return new SpawnerConfigurationEntry { Prefab = aggregate.Prefab, Enabled = true, SpawnArea = ((aggregate.SpawnArea != null) ? ConvertSpawnArea(aggregate.SpawnArea) : null), CreatureSpawner = ((aggregate.CreatureSpawner != null) ? ConvertCreatureSpawner(aggregate.CreatureSpawner) : null) }; } private static void TrackAggregateRootPrefab(TemplateAggregate aggregate, string rootPrefabName) { string text = (rootPrefabName ?? "").Trim(); if (text.Length > 0) { aggregate.RootPrefabs.Add(text); } } private static void TrackAggregateLocationPrefabs(TemplateAggregate aggregate, Dictionary> locationPrefabsBySpawnerPrefab, string configPrefabName) { string text = (configPrefabName ?? "").Trim(); if (text.Length == 0 || !locationPrefabsBySpawnerPrefab.TryGetValue(text, out SortedSet value)) { return; } foreach (string item in value) { if (!string.IsNullOrWhiteSpace(item)) { aggregate.LocationPrefabs.Add(item.Trim()); } } } private static string ResolveSpawnerOwnerName(string prefabName, IEnumerable locationPrefabs, IEnumerable rootPrefabs) { PrefabOwnerResolver.OwnerSnapshot snapshot = PrefabOwnerResolver.GetSnapshot(); List list = (from ownerName in locationPrefabs.Select(snapshot.GetOwnerName) where !string.Equals(ownerName, "Unknown / Untracked", StringComparison.OrdinalIgnoreCase) select ownerName).Distinct(StringComparer.OrdinalIgnoreCase).ToList(); if (list.Count == 1) { return list[0]; } if (list.Count > 1) { return "Unknown / Untracked"; } List list2 = (from ownerName in rootPrefabs.Select(snapshot.GetOwnerName) where !string.Equals(ownerName, "Unknown / Untracked", StringComparison.OrdinalIgnoreCase) select ownerName).Distinct(StringComparer.OrdinalIgnoreCase).ToList(); if (list2.Count == 1) { return list2[0]; } if (list2.Count > 1) { return "Unknown / Untracked"; } return snapshot.GetOwnerName(prefabName); } private static string ResolveSpawnerLocationReferenceOwnerName(SpawnerLocationReferenceEntry entry, IReadOnlyDictionary ownerNamesByPrefab) { if (ownerNamesByPrefab.TryGetValue(entry.Prefab, out string value) && !string.IsNullOrWhiteSpace(value)) { return value; } return ResolveSpawnerOwnerName(entry.Prefab, entry.Locations ?? new List(), Array.Empty()); } private static int CompareSpawnerAggregatesForOutput(TemplateAggregate? left, TemplateAggregate? right) { if (left == right) { return 0; } if (left == null) { return 1; } if (right == null) { return -1; } int num = GetSpawnerPrimaryComponentRank(left).CompareTo(GetSpawnerPrimaryComponentRank(right)); if (num != 0) { return num; } int num2 = GetSpawnerComponentSignatureMask(left).CompareTo(GetSpawnerComponentSignatureMask(right)); if (num2 != 0) { return num2; } return string.Compare(left.Prefab, right.Prefab, StringComparison.OrdinalIgnoreCase); } private static int GetSpawnerPrimaryComponentRank(TemplateAggregate aggregate) { if (aggregate.SpawnArea != null) { return 0; } if (aggregate.CreatureSpawner != null) { return 1; } return 2; } private static int GetSpawnerComponentSignatureMask(TemplateAggregate aggregate) { int num = 0; if (aggregate.SpawnArea != null) { num |= 1; } if (aggregate.CreatureSpawner != null) { num |= 2; } return num; } private static SpawnAreaDefinition ConvertSpawnArea(SpawnAreaComponentSnapshot snapshot) { List list = (from entry in snapshot.Prefabs.Select(delegate(SpawnAreaSpawnSnapshot prefab) { GameObject? prefab2 = prefab.Prefab; return new { Name = (((prefab2 != null) ? ((Object)prefab2).name : null) ?? ""), Prefab = prefab }; }) where !string.IsNullOrWhiteSpace(entry.Name) select new SpawnAreaSpawnDefinition { Creature = entry.Name, Weight = (IsReferenceDefault(entry.Prefab.Weight, 1f) ? null : new float?(entry.Prefab.Weight)), Level = RangeFormatting.FromReference(entry.Prefab.MinLevel, entry.Prefab.MaxLevel, 1, 1) }).ToList(); return new SpawnAreaDefinition { LevelUpChance = (IsReferenceDefault(snapshot.LevelUpChance, 15f) ? null : new float?(snapshot.LevelUpChance)), SpawnInterval = (IsReferenceDefault(snapshot.SpawnInterval, 30f) ? null : new float?(snapshot.SpawnInterval)), TriggerDistance = (IsReferenceDefault(snapshot.TriggerDistance, 256f) ? null : new float?(snapshot.TriggerDistance)), SetPatrolSpawnPoint = (snapshot.SetPatrolSpawnPoint ? null : new bool?(false)), SpawnRadius = (IsReferenceDefault(snapshot.SpawnRadius, 2f) ? null : new float?(snapshot.SpawnRadius)), NearRadius = (IsReferenceDefault(snapshot.NearRadius, 10f) ? null : new float?(snapshot.NearRadius)), FarRadius = (IsReferenceDefault(snapshot.FarRadius, 1000f) ? null : new float?(snapshot.FarRadius)), MaxNear = ((snapshot.MaxNear == 3) ? null : new int?(snapshot.MaxNear)), MaxTotal = ((snapshot.MaxTotal == 20) ? null : new int?(snapshot.MaxTotal)), OnGroundOnly = (snapshot.OnGroundOnly ? new bool?(true) : null), Creatures = ((list.Count > 0) ? list : null) }; } private static CreatureSpawnerDefinition ConvertCreatureSpawner(CreatureSpawnerComponentSnapshot snapshot) { return new CreatureSpawnerDefinition { Creature = (((Object)(object)snapshot.CreaturePrefab != (Object)null) ? ((Object)snapshot.CreaturePrefab).name : null), Level = RangeFormatting.FromReference(snapshot.MinLevel, snapshot.MaxLevel, 1, 1), LevelUpChance = (IsReferenceDefault(snapshot.LevelUpChance, 10f) ? null : new float?(snapshot.LevelUpChance)), RespawnTimeMinutes = (IsReferenceDefault(snapshot.RespawnTimeMinutes, 20f) ? null : new float?(snapshot.RespawnTimeMinutes)), TriggerDistance = (IsReferenceDefault(snapshot.TriggerDistance, 60f) ? null : new float?(snapshot.TriggerDistance)), TriggerNoise = (IsReferenceDefault(snapshot.TriggerNoise, 0f) ? null : new float?(snapshot.TriggerNoise)), TimeOfDay = ((snapshot.SpawnAtDay && snapshot.SpawnAtNight) ? null : TimeOfDayFormatting.FromSpawnFlags(snapshot.SpawnAtDay, snapshot.SpawnAtNight)), AllowInsidePlayerBase = (snapshot.SpawnInPlayerBase ? new bool?(true) : null), WakeUpAnimation = (snapshot.WakeUpAnimation ? new bool?(true) : null), SpawnCheckInterval = ((snapshot.SpawnCheckInterval == 5) ? null : new int?(snapshot.SpawnCheckInterval)), RequiredGlobalKey = ((snapshot.RequiredGlobalKey.Length > 0) ? snapshot.RequiredGlobalKey : null), BlockingGlobalKey = ((snapshot.BlockingGlobalKey.Length > 0) ? snapshot.BlockingGlobalKey : null), SetPatrolSpawnPoint = (snapshot.SetPatrolSpawnPoint ? new bool?(true) : null), SpawnGroupId = ((snapshot.SpawnGroupId == 0) ? null : new int?(snapshot.SpawnGroupId)), MaxGroupSpawned = ((snapshot.MaxGroupSpawned == 1) ? null : new int?(snapshot.MaxGroupSpawned)), SpawnGroupRadius = (IsReferenceDefault(snapshot.SpawnGroupRadius, 0f) ? null : new float?(snapshot.SpawnGroupRadius)), SpawnerWeight = (IsReferenceDefault(snapshot.SpawnerWeight, 1f) ? null : new float?(snapshot.SpawnerWeight)) }; } internal static void ReconcileSpawnAreaRuntime(SpawnArea spawnArea) { ReconcileSpawnAreaRuntimeCore(spawnArea); } internal static bool PrepareSpawnAreaForUpdate(SpawnArea spawnArea) { ReconcileSpawnAreaRuntimeCore(spawnArea); return PrepareSpawnAreaTotalSpawnLimit(spawnArea); } internal static void ReconcileCreatureSpawnerRuntime(CreatureSpawner creatureSpawner) { ReconcileCreatureSpawnerRuntimeCore(creatureSpawner); } internal static bool PrepareCreatureSpawnerForUpdate(CreatureSpawner creatureSpawner) { return PrepareCreatureSpawnerForUpdateCore(creatureSpawner); } private static void ReconcileSpawnAreaRuntimeCore(SpawnArea? spawnArea) { if ((Object)(object)spawnArea == (Object)null) { return; } if (!ShouldApplyLocally()) { ClearSpawnAreaDynamicRuntimeState(spawnArea); return; } SpawnerRuntimeConfigurationSnapshot runtimeConfigurationSnapshot = GetRuntimeConfigurationSnapshot(); if (!TryGetTrackedOrCurrentSpawnAreaEligibility(spawnArea, runtimeConfigurationSnapshot, out string configPrefabName, out bool _, out bool runtimeEligible) || !runtimeEligible) { ClearSpawnAreaDynamicRuntimeState(spawnArea); return; } TrackSpawnAreaInstanceInternal(spawnArea); if (!IsGameDataReady()) { return; } if (!TryGetActiveSpawnAreaEntryCache(spawnArea, runtimeConfigurationSnapshot, out MatchingEntryCache entryCache, out string _)) { ClearSpawnAreaDynamicRuntimeState(spawnArea, clearMatchingCache: true); return; } if (entryCache.RuntimeEntries.Count == 0) { ClearSpawnAreaDynamicRuntimeState(spawnArea, clearMatchingCache: true); return; } LocalRuntimeState orCreateLocalRuntimeState = RuntimeStateStore.GetOrCreateLocalRuntimeState(spawnArea); RuntimeContextSnapshot runtimeContextSnapshot = GetRuntimeContextSnapshot(); if (!ShouldEvaluateRuntimeState(entryCache, orCreateLocalRuntimeState, runtimeContextSnapshot) && RuntimeStateStore.HasRuntimeSignature(spawnArea)) { return; } ArmNextRuntimeEvaluationWindow(entryCache, orCreateLocalRuntimeState, runtimeContextSnapshot); int num = ComputeRuntimeConditionSignature(((Component)spawnArea).gameObject, entryCache, orCreateLocalRuntimeState, runtimeContextSnapshot); if (!RuntimeStateStore.TryGetRuntimeSignature(spawnArea, out var signature) || signature != num) { TrySelectWinningSpawnerEntryForRuntime(((Component)spawnArea).gameObject, entryCache, forSpawnArea: true, runtimeContextSnapshot, orCreateLocalRuntimeState, num, out SpawnerRuntimeEntry winningEntry); if (HasMatchingAppliedWinningEntry(orCreateLocalRuntimeState, entryCache, configPrefabName, winningEntry)) { RuntimeStateStore.SetRuntimeSignature(spawnArea, num); return; } ReconcileSpawnAreaInstanceInternal(spawnArea, null, entryCache, usePreselectedWinner: true, winningEntry); RecordAppliedWinningEntry(orCreateLocalRuntimeState, entryCache, configPrefabName, winningEntry); } } private static void ReconcileCreatureSpawnerRuntimeCore(CreatureSpawner? creatureSpawner) { if ((Object)(object)creatureSpawner == (Object)null) { return; } if (!ShouldApplyLocally()) { ClearCreatureSpawnerDynamicRuntimeState(creatureSpawner); return; } SpawnerRuntimeConfigurationSnapshot runtimeConfigurationSnapshot = GetRuntimeConfigurationSnapshot(); if (!TryGetTrackedOrCurrentCreatureSpawnerEligibility(creatureSpawner, runtimeConfigurationSnapshot, out string configPrefabName, out bool _, out bool runtimeEligible) || !runtimeEligible) { ClearCreatureSpawnerDynamicRuntimeState(creatureSpawner); return; } TrackCreatureSpawnerInstanceInternal(creatureSpawner); if (!IsGameDataReady()) { return; } if (!TryGetActiveCreatureSpawnerEntryCache(creatureSpawner, runtimeConfigurationSnapshot, out MatchingEntryCache entryCache, out string _)) { ClearCreatureSpawnerDynamicRuntimeState(creatureSpawner, clearMatchingCache: true); return; } if (entryCache.RuntimeEntries.Count == 0) { ClearCreatureSpawnerDynamicRuntimeState(creatureSpawner, clearMatchingCache: true); return; } LocalRuntimeState orCreateLocalRuntimeState = RuntimeStateStore.GetOrCreateLocalRuntimeState(creatureSpawner); RuntimeContextSnapshot runtimeContextSnapshot = GetRuntimeContextSnapshot(); if (!ShouldEvaluateRuntimeState(entryCache, orCreateLocalRuntimeState, runtimeContextSnapshot) && RuntimeStateStore.HasRuntimeSignature(creatureSpawner)) { return; } ArmNextRuntimeEvaluationWindow(entryCache, orCreateLocalRuntimeState, runtimeContextSnapshot); int num = ComputeRuntimeConditionSignature(((Component)creatureSpawner).gameObject, entryCache, orCreateLocalRuntimeState, runtimeContextSnapshot); if (!RuntimeStateStore.TryGetRuntimeSignature(creatureSpawner, out var signature) || signature != num) { TrySelectWinningSpawnerEntryForRuntime(((Component)creatureSpawner).gameObject, entryCache, forSpawnArea: false, runtimeContextSnapshot, orCreateLocalRuntimeState, num, out SpawnerRuntimeEntry winningEntry); if (HasMatchingAppliedWinningEntry(orCreateLocalRuntimeState, entryCache, configPrefabName, winningEntry)) { RuntimeStateStore.SetRuntimeSignature(creatureSpawner, num); return; } ReconcileCreatureSpawnerInstanceInternal(creatureSpawner, null, entryCache, usePreselectedWinner: true, winningEntry); RecordAppliedWinningEntry(orCreateLocalRuntimeState, entryCache, configPrefabName, winningEntry); } } private static bool PrepareCreatureSpawnerForUpdateCore(CreatureSpawner? creatureSpawner) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) ReconcileCreatureSpawnerRuntimeCore(creatureSpawner); if ((Object)(object)creatureSpawner == (Object)null) { return true; } if (LiveReconcilerState.TryGetAppliedCreatureSpawnerTimeOfDay(creatureSpawner, out TimeOfDayDefinition timeOfDay) && !TimeOfDayFormatting.MatchesCurrentTime(timeOfDay)) { return false; } if (BossRulesManager.ShouldBlockConfiguredSameBossSpawn(creatureSpawner.m_creaturePrefab, ((Component)creatureSpawner).transform.position)) { return false; } return true; } private static void ClearRuntimeReconcileState() { RuntimeStateStore.ClearDynamicCaches(); SelectorCacheStore.ClearSharedMatchingEntryTemplates(); } private static void UpdateSpawnAreaRuntimeSignature(SpawnArea spawnArea, IEnumerable? entries, MatchingEntryCache? entryCache = null) { IReadOnlyList readOnlyList = entryCache?.RuntimeEntries ?? entries?.Where((SpawnerRuntimeEntry entry) => entry.RuntimeReconcile).ToList() ?? new List(); if (readOnlyList.Count == 0) { ClearSpawnAreaDynamicRuntimeState(spawnArea); } else { RuntimeStateStore.SetRuntimeSignature(spawnArea, (entryCache != null) ? ComputeSpawnAreaRuntimeSignature(spawnArea, entryCache) : ComputeSpawnAreaRuntimeSignature(spawnArea, readOnlyList)); } } private static void UpdateCreatureSpawnerRuntimeSignature(CreatureSpawner creatureSpawner, IEnumerable? entries, MatchingEntryCache? entryCache = null) { IReadOnlyList readOnlyList = entryCache?.RuntimeEntries ?? entries?.Where((SpawnerRuntimeEntry entry) => entry.RuntimeReconcile).ToList() ?? new List(); if (readOnlyList.Count == 0) { ClearCreatureSpawnerDynamicRuntimeState(creatureSpawner); } else { RuntimeStateStore.SetRuntimeSignature(creatureSpawner, (entryCache != null) ? ComputeCreatureSpawnerRuntimeSignature(creatureSpawner, entryCache) : ComputeCreatureSpawnerRuntimeSignature(creatureSpawner, readOnlyList)); } } private static int ComputeSpawnAreaRuntimeSignature(SpawnArea spawnArea, MatchingEntryCache entryCache) { return ComputeRuntimeConditionSignature(((Component)spawnArea).gameObject, entryCache, RuntimeStateStore.GetOrCreateLocalRuntimeState(spawnArea)); } private static int ComputeCreatureSpawnerRuntimeSignature(CreatureSpawner creatureSpawner, MatchingEntryCache entryCache) { return ComputeRuntimeConditionSignature(((Component)creatureSpawner).gameObject, entryCache, RuntimeStateStore.GetOrCreateLocalRuntimeState(creatureSpawner)); } private static int ComputeSpawnAreaRuntimeSignature(SpawnArea spawnArea, IEnumerable entries) { int num = 17; foreach (SpawnerRuntimeEntry item in entries ?? Enumerable.Empty()) { if (item.RuntimeReconcile) { num = CombineRuntimeSignature(num, item.RuleId); bool value = !HasRuntimeEntryConditions(item) || DropConditionEvaluator.AreSatisfied(((Component)spawnArea).gameObject, item.Conditions); num = CombineRuntimeSignature(num, value); } } return num; } private static int ComputeRuntimeConditionSignature(GameObject gameObject, MatchingEntryCache entryCache, LocalRuntimeState localRuntimeState) { return ComputeRuntimeConditionSignature(gameObject, entryCache, localRuntimeState, GetRuntimeContextSnapshot()); } private static int ComputeRuntimeConditionSignature(GameObject gameObject, MatchingEntryCache entryCache, LocalRuntimeState localRuntimeState, RuntimeContextSnapshot runtimeContext) { int num = 17; foreach (SpawnerRuntimeEntry runtimeEntry in entryCache.RuntimeEntries) { num = CombineRuntimeSignature(num, runtimeEntry.RuleId); } if (entryCache.UsesTimeOfDay) { num = CombineRuntimeSignature(num, runtimeContext.TimeOfDayPhaseMarker); } if (entryCache.UsesRequiredEnvironments) { num = CombineRuntimeSignature(num, runtimeContext.EnvironmentName); } if (entryCache.UsesInsidePlayerBase) { num = CombineRuntimeSignature(num, GetInsidePlayerBaseState(gameObject, localRuntimeState)); } foreach (string runtimeRequiredGlobalKey in entryCache.RuntimeRequiredGlobalKeys) { num = CombineRuntimeSignature(num, runtimeRequiredGlobalKey); num = CombineRuntimeSignature(num, GetGlobalKeyState(runtimeContext, runtimeRequiredGlobalKey)); } foreach (string runtimeForbiddenGlobalKey in entryCache.RuntimeForbiddenGlobalKeys) { num = CombineRuntimeSignature(num, runtimeForbiddenGlobalKey); num = CombineRuntimeSignature(num, GetGlobalKeyState(runtimeContext, runtimeForbiddenGlobalKey)); } return num; } private static int ComputeCreatureSpawnerRuntimeSignature(CreatureSpawner creatureSpawner, IEnumerable entries) { int num = 17; foreach (SpawnerRuntimeEntry item in entries ?? Enumerable.Empty()) { if (item.RuntimeReconcile) { num = CombineRuntimeSignature(num, item.RuleId); bool value = !HasRuntimeEntryConditions(item) || DropConditionEvaluator.AreSatisfied(((Component)creatureSpawner).gameObject, item.Conditions); num = CombineRuntimeSignature(num, value); } } return num; } private static void ClearSpawnAreaDynamicRuntimeState(SpawnArea? spawnArea, bool clearMatchingCache = false) { if (!((Object)(object)spawnArea == (Object)null)) { RuntimeStateStore.RemoveRuntimeSignature(spawnArea); RuntimeStateStore.RemoveLocalRuntimeState(spawnArea); if (clearMatchingCache) { SelectorCacheStore.RemoveSpawnAreaEntryCache(spawnArea); } } } private static void ClearCreatureSpawnerDynamicRuntimeState(CreatureSpawner? creatureSpawner, bool clearMatchingCache = false) { if (!((Object)(object)creatureSpawner == (Object)null)) { RuntimeStateStore.RemoveRuntimeSignature(creatureSpawner); RuntimeStateStore.RemoveLocalRuntimeState(creatureSpawner); if (clearMatchingCache) { SelectorCacheStore.RemoveCreatureSpawnerEntryCache(creatureSpawner); } } } private static bool HasMatchingAppliedWinningEntry(LocalRuntimeState localRuntimeState, MatchingEntryCache entryCache, string configPrefabName, SpawnerRuntimeEntry? winningEntry) { if (!localRuntimeState.HasAppliedWinningEntrySelection) { return false; } if (!string.Equals(localRuntimeState.LastAppliedConfigPrefabName, configPrefabName, StringComparison.OrdinalIgnoreCase)) { return false; } if (!string.Equals(localRuntimeState.LastAppliedResolvedLocationKey, entryCache.ResolvedLocationKey, StringComparison.OrdinalIgnoreCase)) { return false; } string b = winningEntry?.RuleId ?? ""; return string.Equals(localRuntimeState.LastAppliedWinningEntryRuleId, b, StringComparison.Ordinal); } private static void RecordAppliedWinningEntry(LocalRuntimeState localRuntimeState, MatchingEntryCache entryCache, string configPrefabName, SpawnerRuntimeEntry? winningEntry) { localRuntimeState.HasAppliedWinningEntrySelection = true; localRuntimeState.LastAppliedConfigPrefabName = configPrefabName ?? ""; localRuntimeState.LastAppliedResolvedLocationKey = entryCache.ResolvedLocationKey ?? ""; localRuntimeState.LastAppliedWinningEntryRuleId = winningEntry?.RuleId ?? ""; } private static int CombineRuntimeSignature(int current, bool value) { return current * 31 + (value ? 1 : 0); } private static int CombineRuntimeSignature(int current, int value) { return current * 31 + value; } private static int CombineRuntimeSignature(int current, string value) { return current * 31 + (value?.GetHashCode() ?? 0); } private static RuntimeContextSnapshot GetRuntimeContextSnapshot() { int frameCount = Time.frameCount; if (RuntimeStateStore.TryGetRuntimeContextSnapshot(frameCount, out RuntimeContextSnapshot snapshot)) { return snapshot; } RuntimeContextSnapshot obj = new RuntimeContextSnapshot { Frame = frameCount, TimeOfDayPhaseMarker = TimeOfDayFormatting.GetCurrentRuntimePhaseMarker() }; EnvMan instance = EnvMan.instance; obj.EnvironmentName = ((instance == null) ? null : instance.GetCurrentEnvironment()?.m_name) ?? ""; RuntimeContextSnapshot runtimeContextSnapshot = obj; return RuntimeStateStore.SetRuntimeContextSnapshot(runtimeContextSnapshot); } private static bool GetInsidePlayerBaseState(GameObject gameObject, LocalRuntimeState localRuntimeState) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) float realtimeSinceStartup = Time.realtimeSinceStartup; if (realtimeSinceStartup - localRuntimeState.LastInsidePlayerBaseSampleTime >= 0.5f) { localRuntimeState.IsInsidePlayerBase = (Object)(object)EffectArea.IsPointInsideArea(gameObject.transform.position, (Type)4, 0f) != (Object)null; localRuntimeState.LastInsidePlayerBaseSampleTime = realtimeSinceStartup; } return localRuntimeState.IsInsidePlayerBase; } private static bool GetGlobalKeyState(RuntimeContextSnapshot runtimeContext, string key) { if (runtimeContext.GlobalKeyStates.TryGetValue(key, out var value)) { return value; } value = (Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetGlobalKey(key); runtimeContext.GlobalKeyStates[key] = value; return value; } private static bool ShouldEvaluateRuntimeState(MatchingEntryCache entryCache, LocalRuntimeState localRuntimeState, RuntimeContextSnapshot runtimeContext) { if (localRuntimeState.NextRuntimeEvaluationTime == float.NegativeInfinity) { return true; } if (entryCache.UsesTimeOfDay && localRuntimeState.LastObservedTimeOfDayPhaseMarker != runtimeContext.TimeOfDayPhaseMarker) { return true; } if (entryCache.UsesRequiredEnvironments && !string.Equals(localRuntimeState.LastObservedEnvironmentName, runtimeContext.EnvironmentName, StringComparison.Ordinal)) { return true; } return Time.realtimeSinceStartup >= localRuntimeState.NextRuntimeEvaluationTime; } private static void ArmNextRuntimeEvaluationWindow(MatchingEntryCache entryCache, LocalRuntimeState localRuntimeState, RuntimeContextSnapshot runtimeContext) { localRuntimeState.LastObservedTimeOfDayPhaseMarker = runtimeContext.TimeOfDayPhaseMarker; localRuntimeState.LastObservedEnvironmentName = runtimeContext.EnvironmentName; float num = ((entryCache.UsesInsidePlayerBase && !entryCache.UsesTimeOfDay && !entryCache.UsesRequiredEnvironments && entryCache.RuntimeRequiredGlobalKeys.Count == 0 && entryCache.RuntimeForbiddenGlobalKeys.Count == 0) ? 0.5f : 0.25f); localRuntimeState.NextRuntimeEvaluationTime = Time.realtimeSinceStartup + num; } private static bool AreRuntimeSpawnerConditionsSatisfied(GameObject gameObject, ConditionsDefinition? conditions, RuntimeContextSnapshot runtimeContext, LocalRuntimeState localRuntimeState) { RuntimeContextSnapshot runtimeContext2 = runtimeContext; return DropConditionEvaluator.AreDynamicConditionsSatisfied(conditions, runtimeContext2.TimeOfDayPhaseMarker, runtimeContext2.EnvironmentName, GetInsidePlayerBaseState(gameObject, localRuntimeState), (string key) => GetGlobalKeyState(runtimeContext2, key)); } private static string BuildFullScaffoldConfigurationTemplate() { StringBuilder stringBuilder = new StringBuilder(); bool flag = false; foreach (PrefabOwnerSection item in BuildConfigurationTemplate()) { foreach (SpawnerConfigurationEntry entry in item.Entries) { if (flag) { AppendScaffoldBlankLine(stringBuilder); } AppendScaffoldListEntryLine(stringBuilder, 0, "prefab", entry.Prefab); AppendScaffoldLine(stringBuilder, 1, "enabled: " + FormatYamlBool(entry.Enabled)); AppendScaffoldStringLine(stringBuilder, 1, "location", null); AppendScaffoldConditionsBlock(stringBuilder, 1, entry.SpawnArea != null); if (entry.SpawnArea != null) { AppendScaffoldSpawnAreaBlock(stringBuilder, entry.SpawnArea); } if (entry.CreatureSpawner != null) { AppendScaffoldCreatureSpawnerBlock(stringBuilder, entry.CreatureSpawner); } flag = true; } } if (!flag) { return "[]" + Environment.NewLine; } return stringBuilder.ToString(); } private static void AppendScaffoldSpawnAreaBlock(StringBuilder builder, SpawnAreaDefinition definition) { AppendScaffoldLine(builder, 1, "spawnArea:"); AppendScaffoldLine(builder, 2, "levelUpChance: " + FormatYamlFloat(definition.LevelUpChance.GetValueOrDefault(15f))); AppendScaffoldLine(builder, 2, "spawnInterval: " + FormatYamlFloat(definition.SpawnInterval.GetValueOrDefault(30f))); AppendScaffoldLine(builder, 2, "triggerDistance: " + FormatYamlFloat(definition.TriggerDistance.GetValueOrDefault(256f))); AppendScaffoldLine(builder, 2, "setPatrolSpawnPoint: " + FormatYamlBool(definition.SetPatrolSpawnPoint.GetValueOrDefault(true))); AppendScaffoldLine(builder, 2, "spawnRadius: " + FormatYamlFloat(definition.SpawnRadius.GetValueOrDefault(2f))); AppendScaffoldLine(builder, 2, "nearRadius: " + FormatYamlFloat(definition.NearRadius.GetValueOrDefault(10f))); AppendScaffoldLine(builder, 2, "farRadius: " + FormatYamlFloat(definition.FarRadius.GetValueOrDefault(1000f))); AppendScaffoldLine(builder, 2, $"maxNear: {definition.MaxNear.GetValueOrDefault(3)}"); AppendScaffoldLine(builder, 2, $"maxTotal: {definition.MaxTotal.GetValueOrDefault(20)}"); AppendScaffoldLine(builder, 2, $"maxTotalSpawns: {definition.MaxTotalSpawns.GetValueOrDefault()}"); AppendScaffoldLine(builder, 2, "onGroundOnly: " + FormatYamlBool(definition.OnGroundOnly.GetValueOrDefault())); List list = definition.Creatures ?? new List(); if (list.Count > 0) { AppendScaffoldLine(builder, 2, "creatures:"); { foreach (SpawnAreaSpawnDefinition item in list) { AppendScaffoldListEntryLine(builder, 3, "creature", item.Creature); AppendScaffoldLine(builder, 4, "weight: " + FormatYamlFloat(item.Weight.GetValueOrDefault(1f))); AppendScaffoldLine(builder, 4, "level: " + RangeFormatting.FormatInlineObject(GetLevelRange(item) ?? RangeFormatting.From(1, 1))); AppendScaffoldStringLine(builder, 4, "faction", item.Faction); AppendScaffoldStringLine(builder, 4, "data", item.Data); AppendScaffoldLine(builder, 4, "fields: {}"); AppendScaffoldLine(builder, 4, "objects: []"); } return; } } AppendScaffoldLine(builder, 2, "creatures: []"); } private static void AppendScaffoldCreatureSpawnerBlock(StringBuilder builder, CreatureSpawnerDefinition definition) { AppendScaffoldLine(builder, 1, "creatureSpawner:"); AppendScaffoldStringLine(builder, 2, "creature", definition.Creature); AppendScaffoldLine(builder, 2, "timeOfDay: " + TimeOfDayFormatting.FormatInlineList(GetConfiguredTimeOfDay(definition), TimeOfDayFormatting.FromSpawnFlags(allowDay: true, allowNight: true))); AppendScaffoldStringLine(builder, 2, "requiredGlobalKey", definition.RequiredGlobalKey ?? ""); AppendScaffoldStringLine(builder, 2, "blockingGlobalKey", definition.BlockingGlobalKey ?? ""); AppendScaffoldLine(builder, 2, "level: " + RangeFormatting.FormatInlineObject(GetLevelRange(definition) ?? RangeFormatting.From(1, 1))); AppendScaffoldLine(builder, 2, "levelUpChance: " + FormatYamlFloat(definition.LevelUpChance.GetValueOrDefault(10f))); AppendScaffoldLine(builder, 2, "respawnTimeMinutes: " + FormatYamlFloat(definition.RespawnTimeMinutes.GetValueOrDefault(20f))); AppendScaffoldLine(builder, 2, $"spawnCheckInterval: {definition.SpawnCheckInterval.GetValueOrDefault(5)}"); AppendScaffoldLine(builder, 2, $"spawnGroupId: {definition.SpawnGroupId.GetValueOrDefault()}"); AppendScaffoldLine(builder, 2, "spawnGroupRadius: " + FormatYamlFloat(definition.SpawnGroupRadius.GetValueOrDefault())); AppendScaffoldLine(builder, 2, "spawnerWeight: " + FormatYamlFloat(definition.SpawnerWeight.GetValueOrDefault(1f))); AppendScaffoldLine(builder, 2, $"maxGroupSpawned: {definition.MaxGroupSpawned.GetValueOrDefault(1)}"); AppendScaffoldLine(builder, 2, "triggerDistance: " + FormatYamlFloat(definition.TriggerDistance.GetValueOrDefault(60f))); AppendScaffoldLine(builder, 2, "triggerNoise: " + FormatYamlFloat(definition.TriggerNoise.GetValueOrDefault())); AppendScaffoldLine(builder, 2, "allowInsidePlayerBase: " + FormatYamlBool(definition.AllowInsidePlayerBase.GetValueOrDefault())); AppendScaffoldLine(builder, 2, "wakeUpAnimation: " + FormatYamlBool(definition.WakeUpAnimation.GetValueOrDefault())); AppendScaffoldLine(builder, 2, "setPatrolSpawnPoint: " + FormatYamlBool(definition.SetPatrolSpawnPoint.GetValueOrDefault())); AppendScaffoldStringLine(builder, 2, "faction", definition.Faction); AppendScaffoldStringLine(builder, 2, "data", definition.Data); AppendScaffoldLine(builder, 2, "fields: {}"); AppendScaffoldLine(builder, 2, "objects: []"); } private static IntRangeDefinition? GetLevelRange(SpawnAreaSpawnDefinition definition) { return definition.Level ?? RangeFormatting.From(definition.MinLevel, definition.MaxLevel ?? definition.MinLevel); } private static IntRangeDefinition? GetLevelRange(CreatureSpawnerDefinition definition) { return definition.Level ?? RangeFormatting.From(definition.MinLevel, definition.MaxLevel ?? definition.MinLevel); } private static void AppendScaffoldComment(StringBuilder builder, string text) { builder.Append("# "); builder.AppendLine(text); } private static void AppendScaffoldLine(StringBuilder builder, int indent, string text) { builder.Append(' ', indent * 2); builder.AppendLine(text); } private static void AppendScaffoldBlankLine(StringBuilder builder) { builder.AppendLine(); } private static void AppendScaffoldConditionsBlock(StringBuilder builder, int indent, bool includeSpawnAreaOnlyFields) { AppendScaffoldLine(builder, indent, "conditions:"); AppendScaffoldLine(builder, indent + 1, "altitude: null"); AppendScaffoldLine(builder, indent + 1, "distanceFromCenter: null"); AppendScaffoldLine(builder, indent + 1, "biomes: []"); if (includeSpawnAreaOnlyFields) { AppendScaffoldLine(builder, indent + 1, "timeOfDay: null"); } AppendScaffoldLine(builder, indent + 1, "requiredEnvironments: []"); if (includeSpawnAreaOnlyFields) { AppendScaffoldLine(builder, indent + 1, "requiredGlobalKeys: []"); AppendScaffoldLine(builder, indent + 1, "forbiddenGlobalKeys: []"); } AppendScaffoldLine(builder, indent + 1, "inForest: null"); AppendScaffoldLine(builder, indent + 1, "inDungeon: null"); if (includeSpawnAreaOnlyFields) { AppendScaffoldLine(builder, indent + 1, "insidePlayerBase: null"); } } private static void AppendScaffoldStringLine(StringBuilder builder, int indent, string key, string? value) { if (value == null) { AppendScaffoldLine(builder, indent, key + ": null"); } else { AppendScaffoldLine(builder, indent, key + ": " + FormatYamlString(value)); } } private static void AppendScaffoldListEntryLine(StringBuilder builder, int indent, string key, string? value) { if (value == null) { AppendScaffoldLine(builder, indent, "- " + key + ": null"); } else { AppendScaffoldLine(builder, indent, "- " + key + ": " + FormatYamlString(value)); } } private static SpawnerConfigurationEntry? GetBestPrefabOnlyEntry(List? entries, bool forSpawnArea) { if (entries == null || entries.Count == 0) { return null; } for (int num = entries.Count - 1; num >= 0; num--) { SpawnerConfigurationEntry spawnerConfigurationEntry = entries[num]; if (spawnerConfigurationEntry.Location == null) { if (forSpawnArea) { if (spawnerConfigurationEntry.SpawnArea != null && HasSpawnAreaOverride(spawnerConfigurationEntry.SpawnArea)) { return spawnerConfigurationEntry; } } else if (spawnerConfigurationEntry.CreatureSpawner != null && HasCreatureSpawnerOverride(spawnerConfigurationEntry.CreatureSpawner)) { return spawnerConfigurationEntry; } } } return null; } private static bool TryGetActiveSpawnAreaEntryCache(SpawnArea? spawnArea, out MatchingEntryCache? entryCache, out string configPrefabName) { return TryGetActiveSpawnAreaEntryCache(spawnArea, GetRuntimeConfigurationSnapshot(), out entryCache, out configPrefabName); } private static bool TryGetActiveSpawnAreaEntryCache(SpawnArea? spawnArea, SpawnerRuntimeConfigurationSnapshot runtimeConfigurationSnapshot, out MatchingEntryCache? entryCache, out string configPrefabName) { entryCache = null; configPrefabName = ""; if ((Object)(object)spawnArea == (Object)null || (Object)(object)((Component)spawnArea).gameObject == (Object)null) { return false; } configPrefabName = (LiveRegistryStore.TryGetTrackedPrefabName(spawnArea, out string prefabName) ? prefabName : GetConfigPrefabName(((Component)spawnArea).gameObject, "SpawnArea")); if (configPrefabName.Length == 0) { return false; } if (SelectorCacheStore.TryGetSpawnAreaEntryCache(spawnArea, out entryCache) && IsMatchingEntryCacheValid(((Component)spawnArea).gameObject, configPrefabName, entryCache)) { if (!ShouldPersistMatchingEntryCache(entryCache)) { SelectorCacheStore.RemoveSpawnAreaEntryCache(spawnArea); ClearSpawnAreaDynamicRuntimeState(spawnArea); } return entryCache.Entries.Count > 0; } entryCache = BuildMatchingEntryCache(((Component)spawnArea).gameObject, configPrefabName, runtimeConfigurationSnapshot, forSpawnArea: true); if (ShouldPersistMatchingEntryCache(entryCache)) { SelectorCacheStore.SetSpawnAreaEntryCache(spawnArea, entryCache); } else { SelectorCacheStore.RemoveSpawnAreaEntryCache(spawnArea); ClearSpawnAreaDynamicRuntimeState(spawnArea); } return entryCache.Entries.Count > 0; } private static bool TryGetActiveCreatureSpawnerEntryCache(CreatureSpawner? creatureSpawner, out MatchingEntryCache? entryCache, out string configPrefabName) { return TryGetActiveCreatureSpawnerEntryCache(creatureSpawner, GetRuntimeConfigurationSnapshot(), out entryCache, out configPrefabName); } private static bool TryGetActiveCreatureSpawnerEntryCache(CreatureSpawner? creatureSpawner, SpawnerRuntimeConfigurationSnapshot runtimeConfigurationSnapshot, out MatchingEntryCache? entryCache, out string configPrefabName) { entryCache = null; configPrefabName = ""; if ((Object)(object)creatureSpawner == (Object)null || (Object)(object)((Component)creatureSpawner).gameObject == (Object)null) { return false; } configPrefabName = (LiveRegistryStore.TryGetTrackedPrefabName(creatureSpawner, out string prefabName) ? prefabName : GetConfigPrefabName(((Component)creatureSpawner).gameObject, "CreatureSpawner")); if (configPrefabName.Length == 0) { return false; } if (SelectorCacheStore.TryGetCreatureSpawnerEntryCache(creatureSpawner, out entryCache) && IsMatchingEntryCacheValid(((Component)creatureSpawner).gameObject, configPrefabName, entryCache)) { if (!ShouldPersistMatchingEntryCache(entryCache)) { SelectorCacheStore.RemoveCreatureSpawnerEntryCache(creatureSpawner); ClearCreatureSpawnerDynamicRuntimeState(creatureSpawner); } return entryCache.Entries.Count > 0; } entryCache = BuildMatchingEntryCache(((Component)creatureSpawner).gameObject, configPrefabName, runtimeConfigurationSnapshot, forSpawnArea: false); if (ShouldPersistMatchingEntryCache(entryCache)) { SelectorCacheStore.SetCreatureSpawnerEntryCache(creatureSpawner, entryCache); } else { SelectorCacheStore.RemoveCreatureSpawnerEntryCache(creatureSpawner); ClearCreatureSpawnerDynamicRuntimeState(creatureSpawner); } return entryCache.Entries.Count > 0; } private static MatchingEntryCache BuildMatchingEntryCache(GameObject gameObject, string configPrefabName, SpawnerRuntimeConfigurationSnapshot runtimeConfigurationSnapshot, bool forSpawnArea) { MatchingEntryCache matchingEntryCache = new MatchingEntryCache { ConfigPrefabName = configPrefabName }; if ((Object)(object)gameObject == (Object)null || string.IsNullOrWhiteSpace(configPrefabName)) { return matchingEntryCache; } if (forSpawnArea) { if (!runtimeConfigurationSnapshot.ConfiguredSpawnAreaPrefabs.Contains(configPrefabName)) { return matchingEntryCache; } } else if (!runtimeConfigurationSnapshot.ConfiguredCreatureSpawnerPrefabs.Contains(configPrefabName)) { return matchingEntryCache; } if (!runtimeConfigurationSnapshot.PlansByPrefab.TryGetValue(configPrefabName, out CompiledSpawnerPrefabPlan value)) { return matchingEntryCache; } List list = (forSpawnArea ? value.SpawnAreaEntries : value.CreatureSpawnerEntries); if (list.Count == 0) { return matchingEntryCache; } bool flag = list.Any((SpawnerRuntimeEntry candidate) => !string.IsNullOrWhiteSpace(candidate.Location)); string locationPrefab = ""; string sourceLabel = ""; bool flag2 = !flag || TryGetLiveLocationContextForSelector(gameObject, out locationPrefab, out sourceLabel); matchingEntryCache.UsesLocationSelector = flag; matchingEntryCache.ResolvedLocationKey = (flag ? NormalizeSelectorLocationCacheKey(flag2 ? locationPrefab : null) : ""); CaptureRecordedLocationProvenanceEpoch(gameObject, matchingEntryCache); if (TryGetSharedMatchingEntryTemplate(gameObject, configPrefabName, list, forSpawnArea, flag2, flag2 ? locationPrefab : null, out SharedMatchingEntryTemplate sharedTemplate)) { MatchingEntryCache matchingEntryCache2 = new MatchingEntryCache(); matchingEntryCache2.UseSharedTemplate(sharedTemplate); CaptureRecordedLocationProvenanceEpoch(gameObject, matchingEntryCache2); return matchingEntryCache2; } foreach (SpawnerRuntimeEntry item in list) { if (TryGetEntryMatchSpecificity(gameObject, item, flag2, flag2 ? locationPrefab : null, flag2 ? sourceLabel : "", out var _) && (!HasRuntimeEntryConditions(item) || DropConditionEvaluator.AreStaticConditionsSatisfied(gameObject, item.Conditions, flag2 ? locationPrefab : null))) { matchingEntryCache.MutableEntries.Add(item); if (item.RuntimeReconcile) { matchingEntryCache.MutableRuntimeEntries.Add(item); AccumulateRuntimeConditionUsage(matchingEntryCache, item.Conditions); } } } return matchingEntryCache; } private static bool TryGetSharedMatchingEntryTemplate(GameObject gameObject, string configPrefabName, List entries, bool forSpawnArea, bool hasResolvedLocation, string? resolvedLocationPrefab, out SharedMatchingEntryTemplate? sharedTemplate) { sharedTemplate = null; if (!TryBuildSharedMatchingEntryTemplateKey(gameObject, configPrefabName, entries, forSpawnArea, hasResolvedLocation, resolvedLocationPrefab, out StaticSelectorContextSnapshot contextSnapshot, out string cacheKey, out string resolvedLocationKey)) { return false; } if (SelectorCacheStore.TryGetSharedMatchingEntryTemplate(cacheKey, out sharedTemplate)) { return true; } sharedTemplate = BuildSharedMatchingEntryTemplate(gameObject, configPrefabName, entries, hasResolvedLocation, resolvedLocationPrefab, resolvedLocationKey, contextSnapshot); SelectorCacheStore.SetSharedMatchingEntryTemplate(cacheKey, sharedTemplate); return true; } private static bool TryBuildSharedMatchingEntryTemplateKey(GameObject gameObject, string configPrefabName, List entries, bool forSpawnArea, bool hasResolvedLocation, string? resolvedLocationPrefab, out StaticSelectorContextSnapshot contextSnapshot, out string cacheKey, out string resolvedLocationKey) { //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Expected I4, but got Unknown contextSnapshot = null; cacheKey = ""; resolvedLocationKey = (hasResolvedLocation ? NormalizeSelectorLocationCacheKey(resolvedLocationPrefab) : ""); bool flag = false; bool flag2 = false; bool flag3 = false; bool flag4 = false; foreach (SpawnerRuntimeEntry entry in entries) { ConditionsDefinition conditions = entry.Conditions; if (!CanUseSharedMatchingEntryTemplate(conditions)) { return false; } flag |= !string.IsNullOrWhiteSpace(entry.Location); flag2 |= conditions != null && (conditions.Locations?.Any((string name) => !string.IsNullOrWhiteSpace(name))).GetValueOrDefault(); flag3 |= (conditions != null && conditions.ResolvedBiomeMask.HasValue) || (conditions != null && (conditions.Biomes?.Any((string name) => !string.IsNullOrWhiteSpace(name))).GetValueOrDefault()); flag4 |= conditions?.InDungeon.HasValue ?? false; } contextSnapshot = GetOrBuildStaticSelectorContextSnapshot(gameObject, flag, flag2, flag3, flag4, hasResolvedLocation, resolvedLocationPrefab); StringBuilder stringBuilder = new StringBuilder(configPrefabName.Length + 64); stringBuilder.Append(forSpawnArea ? "spawnarea|" : "creaturespawner|"); stringBuilder.Append(configPrefabName); stringBuilder.Append("|selector:"); stringBuilder.Append(flag ? resolvedLocationKey : ""); if (flag2) { stringBuilder.Append("|condloc:"); stringBuilder.Append(contextSnapshot.ConditionLocationName); } if (flag3) { stringBuilder.Append("|biome:"); stringBuilder.Append((int)contextSnapshot.Biome); } if (flag4) { stringBuilder.Append("|dungeon:"); stringBuilder.Append(contextSnapshot.InDungeon ? '1' : '0'); } cacheKey = stringBuilder.ToString(); return true; } private static bool CanUseSharedMatchingEntryTemplate(ConditionsDefinition? conditions) { if (conditions != null) { if (!conditions.InForest.HasValue) { FloatRangeDefinition? distanceFromCenter = conditions.DistanceFromCenter; if ((distanceFromCenter == null || !distanceFromCenter.HasValues()) && !conditions.MinDistanceFromCenter.HasValue && !conditions.MaxDistanceFromCenter.HasValue) { FloatRangeDefinition? altitude = conditions.Altitude; if ((altitude == null || !altitude.HasValues()) && !conditions.MinAltitude.HasValue) { return !conditions.MaxAltitude.HasValue; } } } return false; } return true; } private static SharedMatchingEntryTemplate BuildSharedMatchingEntryTemplate(GameObject gameObject, string configPrefabName, List entries, bool hasResolvedLocation, string? resolvedLocationPrefab, string resolvedLocationKey, StaticSelectorContextSnapshot contextSnapshot) { SharedMatchingEntryTemplate sharedMatchingEntryTemplate = new SharedMatchingEntryTemplate { ConfigPrefabName = configPrefabName, UsesLocationSelector = entries.Any((SpawnerRuntimeEntry entry) => !string.IsNullOrWhiteSpace(entry.Location)), ResolvedLocationKey = resolvedLocationKey }; foreach (SpawnerRuntimeEntry entry in entries) { if (TryGetEntryMatchSpecificity(gameObject, entry, hasResolvedLocation, hasResolvedLocation ? resolvedLocationPrefab : null, "", out var _) && (!HasRuntimeEntryConditions(entry) || DropConditionEvaluator.AreStaticConditionsSatisfied(gameObject, entry.Conditions, contextSnapshot.ConditionLocationName))) { sharedMatchingEntryTemplate.Entries.Add(entry); if (entry.RuntimeReconcile) { sharedMatchingEntryTemplate.RuntimeEntries.Add(entry); AccumulateRuntimeConditionUsage(sharedMatchingEntryTemplate.RuntimeRequiredGlobalKeys, sharedMatchingEntryTemplate.RuntimeForbiddenGlobalKeys, entry.Conditions, out var usesTimeOfDay, out var usesRequiredEnvironments, out var usesInsidePlayerBase); sharedMatchingEntryTemplate.UsesTimeOfDay |= usesTimeOfDay; sharedMatchingEntryTemplate.UsesRequiredEnvironments |= usesRequiredEnvironments; sharedMatchingEntryTemplate.UsesInsidePlayerBase |= usesInsidePlayerBase; } } } return sharedMatchingEntryTemplate; } private static StaticSelectorContextSnapshot GetOrBuildStaticSelectorContextSnapshot(GameObject gameObject, bool usesSelector, bool usesConditionLocation, bool usesBiome, bool usesInDungeon, bool hasResolvedLocation, string? resolvedLocationPrefab) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) bool flag = usesSelector || usesConditionLocation; if (SelectorCacheStore.TryGetReusableStaticSelectorContext(gameObject, flag, out StaticSelectorContextSnapshot snapshot)) { return snapshot; } Vector3 position = gameObject.transform.position; StaticSelectorContextSnapshot staticSelectorContextSnapshot = new StaticSelectorContextSnapshot { Position = position, ResolvedSelectorLocationPrefab = (hasResolvedLocation ? (resolvedLocationPrefab ?? "").Trim() : ""), SelectorLocationKey = (hasResolvedLocation ? NormalizeSelectorLocationCacheKey(resolvedLocationPrefab) : "") }; if (usesSelector && !hasResolvedLocation) { if (TryGetLiveLocationContextForSelector(gameObject, out string locationPrefab, out string sourceLabel)) { staticSelectorContextSnapshot.ResolvedSelectorLocationPrefab = locationPrefab; staticSelectorContextSnapshot.SelectorSourceLabel = sourceLabel; staticSelectorContextSnapshot.SelectorLocationKey = NormalizeSelectorLocationCacheKey(locationPrefab); } } else if (usesSelector && hasResolvedLocation) { staticSelectorContextSnapshot.SelectorSourceLabel = "Cached"; } if (usesConditionLocation) { staticSelectorContextSnapshot.ConditionLocationName = (TryGetResolvedLocationNameForConditions(gameObject, out string locationPrefab2) ? locationPrefab2 : ""); } if (usesBiome) { WorldGenerator instance = WorldGenerator.instance; staticSelectorContextSnapshot.Biome = ((instance != null) ? instance.GetBiome(position) : Heightmap.FindBiome(position)); } if (usesInDungeon) { staticSelectorContextSnapshot.InDungeon = Character.InInterior(position); } if (flag && TryGetRecordedLocationProvenanceEpoch(gameObject, out var provenanceEpoch)) { staticSelectorContextSnapshot.HasRecordedLocationProvenanceEpoch = true; staticSelectorContextSnapshot.RecordedLocationProvenanceEpoch = provenanceEpoch; } SelectorCacheStore.StoreReusableStaticSelectorContext(gameObject, staticSelectorContextSnapshot, flag); return staticSelectorContextSnapshot; } private static bool ShouldPersistMatchingEntryCache(MatchingEntryCache? entryCache) { if (entryCache != null) { return entryCache.Entries.Count > 0; } return false; } private static void CaptureRecordedLocationProvenanceEpoch(GameObject gameObject, MatchingEntryCache cache) { cache.HasRecordedLocationProvenanceEpoch = false; cache.RecordedLocationProvenanceEpoch = 0; if (!((Object)(object)gameObject == (Object)null) && cache != null && cache.UsesLocationSelector && TryGetRecordedLocationProvenanceEpoch(gameObject, out var provenanceEpoch)) { cache.HasRecordedLocationProvenanceEpoch = true; cache.RecordedLocationProvenanceEpoch = provenanceEpoch; } } private static bool TryGetRecordedLocationProvenanceEpoch(GameObject gameObject, out int provenanceEpoch) { provenanceEpoch = 0; if ((Object)(object)gameObject == (Object)null) { return false; } SpawnArea spawnArea = default(SpawnArea); if (gameObject.TryGetComponent(ref spawnArea) && ProvenanceRegistry.TryGetSpawnAreaProvenance(spawnArea, out SpawnerLocationProvenance provenance)) { provenanceEpoch = provenance.Epoch; return provenanceEpoch != 0; } CreatureSpawner creatureSpawner = default(CreatureSpawner); if (gameObject.TryGetComponent(ref creatureSpawner) && ProvenanceRegistry.TryGetCreatureSpawnerProvenance(creatureSpawner, out SpawnerLocationProvenance provenance2)) { provenanceEpoch = provenance2.Epoch; return provenanceEpoch != 0; } return false; } private static bool IsMatchingEntryCacheValid(GameObject gameObject, string configPrefabName, MatchingEntryCache? entryCache) { if ((Object)(object)gameObject == (Object)null || entryCache == null) { return false; } if (!string.Equals(entryCache.ConfigPrefabName, configPrefabName, StringComparison.OrdinalIgnoreCase)) { return false; } if (!entryCache.UsesLocationSelector) { return true; } if (TryGetRecordedLocationProvenanceEpoch(gameObject, out var provenanceEpoch)) { if (entryCache.HasRecordedLocationProvenanceEpoch) { return entryCache.RecordedLocationProvenanceEpoch == provenanceEpoch; } return false; } if (entryCache.HasRecordedLocationProvenanceEpoch) { return false; } return string.Equals(entryCache.ResolvedLocationKey, BuildSelectorLocationCacheKey(gameObject), StringComparison.OrdinalIgnoreCase); } private static string BuildSelectorLocationCacheKey(GameObject gameObject) { if (!TryGetLiveLocationContextForSelector(gameObject, out string locationPrefab, out string _)) { return ""; } return NormalizeSelectorLocationCacheKey(locationPrefab); } private static string NormalizeSelectorLocationCacheKey(string? locationPrefab) { string text = (locationPrefab ?? "").Trim(); if (text.Length <= 0) { return ""; } return text; } private static void AccumulateRuntimeConditionUsage(MatchingEntryCache cache, ConditionsDefinition? conditions) { if (conditions != null) { AccumulateRuntimeConditionUsage(cache.MutableRuntimeRequiredGlobalKeys, cache.MutableRuntimeForbiddenGlobalKeys, conditions, out var usesTimeOfDay, out var usesRequiredEnvironments, out var usesInsidePlayerBase); cache.UsesTimeOfDay |= usesTimeOfDay; cache.UsesRequiredEnvironments |= usesRequiredEnvironments; cache.UsesInsidePlayerBase |= usesInsidePlayerBase; } } private static void AccumulateRuntimeConditionUsage(List runtimeRequiredGlobalKeys, List runtimeForbiddenGlobalKeys, ConditionsDefinition? conditions, out bool usesTimeOfDay, out bool usesRequiredEnvironments, out bool usesInsidePlayerBase) { usesTimeOfDay = false; usesRequiredEnvironments = false; usesInsidePlayerBase = false; if (conditions != null) { usesTimeOfDay = conditions.TimeOfDay != null; usesRequiredEnvironments = HasConfiguredValues(conditions.RequiredEnvironments); usesInsidePlayerBase = conditions.InsidePlayerBase.HasValue; AddNormalizedConditionValues(runtimeRequiredGlobalKeys, conditions.RequiredGlobalKeys); AddNormalizedConditionValues(runtimeForbiddenGlobalKeys, conditions.ForbiddenGlobalKeys); } } private static bool HasConfiguredValues(List? values) { return values?.Any((string value) => !string.IsNullOrWhiteSpace(value)) ?? false; } private static void AddNormalizedConditionValues(List target, List? values) { if (values == null) { return; } foreach (string value in values) { string text = (value ?? "").Trim(); if (text.Length != 0 && !target.Contains(text, StringComparer.OrdinalIgnoreCase)) { target.Add(text); } } } private static bool HasRuntimeEntryConditions(SpawnerRuntimeEntry? entry) { if (entry != null) { return DropConditionEvaluator.HasConditions(entry.Conditions); } return false; } private static bool TrySelectWinningSpawnerEntryForRuntime(GameObject gameObject, MatchingEntryCache entryCache, bool forSpawnArea, RuntimeContextSnapshot runtimeContext, LocalRuntimeState localRuntimeState, int runtimeSignature, out SpawnerRuntimeEntry? winningEntry) { if (entryCache.WinningEntriesByRuntimeSignature.TryGetValue(runtimeSignature, out winningEntry)) { return winningEntry != null; } winningEntry = null; int num = -1; foreach (SpawnerRuntimeEntry entry in entryCache.Entries) { if (!entry.RuntimeReconcile || AreRuntimeSpawnerConditionsSatisfied(gameObject, entry.Conditions, runtimeContext, localRuntimeState)) { int num2 = ((!string.IsNullOrWhiteSpace(entry.Location)) ? 1 : 0); if (num2 >= num) { winningEntry = entry; num = num2; } } } if (entryCache.WinningEntriesByRuntimeSignature.Count >= 16) { entryCache.WinningEntriesByRuntimeSignature.Clear(); } entryCache.WinningEntriesByRuntimeSignature[runtimeSignature] = winningEntry; return winningEntry != null; } private static bool TrySelectWinningSpawnerEntry(GameObject gameObject, IEnumerable? entries, bool forSpawnArea, out SpawnerRuntimeEntry? winningEntry) { winningEntry = null; if ((Object)(object)gameObject == (Object)null || entries == null) { return false; } bool flag = false; bool flag2 = false; string locationPrefab = ""; string sourceLabel = ""; int num = -1; foreach (SpawnerRuntimeEntry entry in entries) { if (entry == null) { continue; } if (forSpawnArea) { if (entry.SpawnArea == null || !HasSpawnAreaOverride(entry.SpawnArea)) { continue; } } else if (entry.CreatureSpawner == null || !HasCreatureSpawnerOverride(entry.CreatureSpawner)) { continue; } if (!flag && !string.IsNullOrWhiteSpace(entry.Location)) { flag2 = TryGetLiveLocationContextForSelector(gameObject, out locationPrefab, out sourceLabel); flag = true; } if (TryGetEntryMatchSpecificity(gameObject, entry, flag2, flag2 ? locationPrefab : null, flag2 ? sourceLabel : "", out var specificity) && (!HasRuntimeEntryConditions(entry) || DropConditionEvaluator.AreSatisfied(gameObject, entry.Conditions)) && specificity >= num) { winningEntry = entry; num = specificity; } } return winningEntry != null; } private static bool TrySelectWinningSpawnerEntry(GameObject gameObject, IEnumerable? entries, bool forSpawnArea, out SpawnerConfigurationEntry? winningEntry) { winningEntry = null; if ((Object)(object)gameObject == (Object)null || entries == null) { return false; } bool flag = false; bool flag2 = false; string locationPrefab = ""; string sourceLabel = ""; int num = -1; foreach (SpawnerConfigurationEntry entry in entries) { if (entry == null) { continue; } if (forSpawnArea) { if (entry.SpawnArea == null || !HasSpawnAreaOverride(entry.SpawnArea)) { continue; } } else if (entry.CreatureSpawner == null || !HasCreatureSpawnerOverride(entry.CreatureSpawner)) { continue; } if (!flag && !string.IsNullOrWhiteSpace(entry.Location)) { flag2 = TryGetLiveLocationContextForSelector(gameObject, out locationPrefab, out sourceLabel); flag = true; } if (TryGetEntryMatchSpecificity(gameObject, entry, flag2, flag2 ? locationPrefab : null, flag2 ? sourceLabel : "", out var specificity) && (!HasEntryConditions(entry) || DropConditionEvaluator.AreSatisfied(gameObject, entry.Conditions)) && specificity >= num) { winningEntry = entry; num = specificity; } } return winningEntry != null; } private static bool TryGetEntryMatchSpecificity(GameObject gameObject, SpawnerConfigurationEntry entry, out int specificity) { string locationPrefab; string sourceLabel; bool flag = TryGetLiveLocationContextForSelector(gameObject, out locationPrefab, out sourceLabel); return TryGetEntryMatchSpecificity(gameObject, entry, flag, flag ? locationPrefab : null, flag ? sourceLabel : "", out specificity); } private static bool TryGetEntryMatchSpecificity(GameObject gameObject, SpawnerRuntimeEntry entry, out int specificity) { string locationPrefab; string sourceLabel; bool flag = TryGetLiveLocationContextForSelector(gameObject, out locationPrefab, out sourceLabel); return TryGetEntryMatchSpecificity(gameObject, entry, flag, flag ? locationPrefab : null, flag ? sourceLabel : "", out specificity); } private static bool TryGetEntryMatchSpecificity(GameObject gameObject, SpawnerConfigurationEntry entry, bool hasResolvedLocation, string? resolvedLocationPrefab, string sourceLabel, out int specificity) { specificity = 0; if ((Object)(object)gameObject == (Object)null) { return false; } if (string.IsNullOrWhiteSpace(entry.Location)) { return true; } if (!hasResolvedLocation) { LogLocationSelectorDiagnostic(gameObject, entry, "no live location context"); return false; } if (!string.Equals(entry.Location, resolvedLocationPrefab, StringComparison.OrdinalIgnoreCase)) { LogLocationSelectorDiagnostic(gameObject, entry, "location mismatch via " + sourceLabel, resolvedLocationPrefab ?? ""); return false; } specificity = 1; return true; } private static bool TryGetEntryMatchSpecificity(GameObject gameObject, SpawnerRuntimeEntry entry, bool hasResolvedLocation, string? resolvedLocationPrefab, string sourceLabel, out int specificity) { specificity = 0; if ((Object)(object)gameObject == (Object)null) { return false; } if (string.IsNullOrWhiteSpace(entry.Location)) { return true; } if (!hasResolvedLocation) { LogLocationSelectorDiagnostic(gameObject, entry, "no live location context"); return false; } if (!string.Equals(entry.Location, resolvedLocationPrefab, StringComparison.OrdinalIgnoreCase)) { LogLocationSelectorDiagnostic(gameObject, entry, "location mismatch via " + sourceLabel, resolvedLocationPrefab ?? ""); return false; } specificity = 1; return true; } private static bool TryGetLiveLocationContextForSelector(GameObject gameObject, out string locationPrefab, out string sourceLabel) { locationPrefab = ""; sourceLabel = ""; if ((Object)(object)gameObject == (Object)null) { return false; } if (TryGetRecordedLocationContext(gameObject, out locationPrefab, out string relativePath)) { sourceLabel = "Provenance"; return locationPrefab.Length > 0; } if (TryGetActiveLocationSpawnContextPrefab(out locationPrefab)) { sourceLabel = "SpawnLocationContext"; return locationPrefab.Length > 0; } if (TryGetLiveLocationProxyPrefab(gameObject, out locationPrefab)) { sourceLabel = "LocationProxy"; return locationPrefab.Length > 0; } if (TryGetDirectLocationContext(gameObject, out locationPrefab, out relativePath)) { sourceLabel = "LocationComponent"; return locationPrefab.Length > 0; } if (TryGetStaticLocationContext(gameObject, out locationPrefab, out relativePath)) { sourceLabel = "LocationStatic"; return locationPrefab.Length > 0; } if (TryGetZoneLocationContext(gameObject, out locationPrefab)) { sourceLabel = "LocationZone"; return locationPrefab.Length > 0; } if (TryPromoteSpatialContextToRecordedProvenance(gameObject, out locationPrefab, out relativePath)) { sourceLabel = "LocationRadius"; return locationPrefab.Length > 0; } return false; } private static bool TryGetLiveLocationProxyPrefab(GameObject gameObject, out string locationPrefab) { locationPrefab = ""; if ((Object)(object)gameObject == (Object)null) { return false; } Transform locationContextRootTransform = GetLocationContextRootTransform(gameObject); if ((Object)(object)locationContextRootTransform == (Object)null) { return false; } return ProvenanceRegistry.TryGetRecordedRootLocationPrefab(locationContextRootTransform, out locationPrefab); } private static int ClampSpawnAreaMaxTotalSpawns(int value) { return SpawnerGlobalConfig.ClampSpawnAreaMaxTotalSpawns(value); } private static int ResolveSpawnAreaMaxTotalSpawns(int? configuredMaxTotalSpawns) { if (!configuredMaxTotalSpawns.HasValue) { return PluginSettingsFacade.GetDefaultSpawnAreaMaxTotalSpawns(); } return ClampSpawnAreaMaxTotalSpawns(configuredMaxTotalSpawns.Value); } private static bool ApplySpawnAreaTotalSpawnLimit(SpawnArea? spawnArea, int? configuredMaxTotalSpawns) { if ((Object)(object)spawnArea == (Object)null) { return true; } bool hasValue = configuredMaxTotalSpawns.HasValue; int num = ResolveSpawnAreaMaxTotalSpawns(configuredMaxTotalSpawns); if (num <= 0 && !hasValue) { ClearAppliedSpawnAreaTotalSpawnLimit(spawnArea); return true; } SpawnAreaTotalSpawnLimitState state = new SpawnAreaTotalSpawnLimitState(num, hasValue); SpawnAreaTotalSpawnLimitState state2; bool num2 = !LiveReconcilerState.TryGetAppliedSpawnAreaTotalSpawnLimit(spawnArea, out state2) || state2.MaxTotalSpawns != state.MaxTotalSpawns || state2.FromYamlOverride != state.FromYamlOverride; LiveReconcilerState.SetAppliedSpawnAreaTotalSpawnLimit(spawnArea, state); if (num2 && TryGetSpawnAreaZdo(spawnArea, out ZDO zdo)) { zdo.Set(SpawnAreaMaxTotalSpawnsZdoKey, num, false); } return !DestroySpawnAreaIfTotalSpawnLimitExhausted(spawnArea, num); } private static bool PrepareSpawnAreaTotalSpawnLimit(SpawnArea? spawnArea) { if ((Object)(object)spawnArea == (Object)null) { return true; } if (LiveReconcilerState.TryGetAppliedSpawnAreaTotalSpawnLimit(spawnArea, out var state) && state.FromYamlOverride) { return !DestroySpawnAreaIfTotalSpawnLimitExhausted(spawnArea, state.MaxTotalSpawns); } return ApplySpawnAreaTotalSpawnLimit(spawnArea, null); } private static void RecordSuccessfulSpawnAreaTotalSpawn(SpawnArea? spawnArea) { if (!((Object)(object)spawnArea == (Object)null) && PrepareSpawnAreaTotalSpawnLimit(spawnArea) && LiveReconcilerState.TryGetAppliedSpawnAreaTotalSpawnLimit(spawnArea, out var state) && state.MaxTotalSpawns > 0 && TryGetSpawnAreaZdo(spawnArea, out ZDO zdo)) { int num = Mathf.Max(0, zdo.GetInt(SpawnAreaTotalSpawnCountZdoKey, 0)) + 1; zdo.Set(SpawnAreaTotalSpawnCountZdoKey, num, false); zdo.Set(SpawnAreaMaxTotalSpawnsZdoKey, state.MaxTotalSpawns, false); if (num >= state.MaxTotalSpawns) { DestroySpawnAreaForTotalSpawnLimit(spawnArea); } } } private static bool DestroySpawnAreaIfTotalSpawnLimitExhausted(SpawnArea? spawnArea, int maxTotalSpawns) { if ((Object)(object)spawnArea == (Object)null || maxTotalSpawns <= 0 || !TryGetSpawnAreaZdo(spawnArea, out ZDO zdo)) { return false; } if (Mathf.Max(0, zdo.GetInt(SpawnAreaTotalSpawnCountZdoKey, 0)) < maxTotalSpawns) { return false; } return DestroySpawnAreaForTotalSpawnLimit(spawnArea); } private static bool DestroySpawnAreaForTotalSpawnLimit(SpawnArea? spawnArea) { if ((Object)(object)spawnArea == (Object)null || (Object)(object)((Component)spawnArea).gameObject == (Object)null) { return false; } ZNetView component = ((Component)spawnArea).GetComponent(); if ((Object)(object)component == (Object)null || !component.IsValid() || !component.IsOwner()) { return false; } Destructible component2 = ((Component)spawnArea).GetComponent(); if ((Object)(object)component2 != (Object)null) { component2.Destroy((HitData)null); return true; } component.Destroy(); return true; } private static bool TryGetSpawnAreaZdo(SpawnArea? spawnArea, out ZDO zdo) { zdo = null; if ((Object)(object)spawnArea == (Object)null) { return false; } ZNetView component = ((Component)spawnArea).GetComponent(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return false; } ZDO zDO = component.GetZDO(); if (zDO == null) { return false; } zdo = zDO; return true; } private static void ClearAppliedSpawnAreaTotalSpawnLimit(SpawnArea? spawnArea) { LiveReconcilerState.RemoveAppliedSpawnAreaTotalSpawnLimit(spawnArea); } private static string BuildPrimaryOverrideConfigurationTemplate() { StringBuilder stringBuilder = new StringBuilder(); AppendTemplateComment(stringBuilder, "Any file named " + PluginSettingsFacade.GetYamlDomainSupplementalPrefix("spawner") + "*.yml or " + PluginSettingsFacade.GetYamlDomainSupplementalPrefix("spawner") + "*.yaml is also loaded."); AppendTemplateComment(stringBuilder, "Use " + PluginSettingsFacade.GetYamlDomainFilePrefix("spawner") + ".reference.yml to look up real spawner object names and " + PluginSettingsFacade.GetYamlDomainFilePrefix("spawner") + ".locations.reference.yml to look up valid location names"); AppendTemplateComment(stringBuilder, "Run `dns:full spawner` to regenerate " + PluginSettingsFacade.GetYamlDomainFilePrefix("spawner") + ".full.yml for exhaustive field examples"); AppendTemplateComment(stringBuilder, "Only the most specific passing entry is applied # Less specific entries act as fallback # If multiple passing entries share the same specificity, the later loaded one wins"); AppendTemplateBlankLine(stringBuilder); AppendTemplateComment(stringBuilder, "spawnArea"); AppendTemplateBlankLine(stringBuilder); AppendTemplateLine(stringBuilder, 0, "- prefab: BonePileSpawner"); AppendTemplateLine(stringBuilder, 1, "enabled: true"); AppendTemplateLine(stringBuilder, 1, "location: Grave1 # ex) locations[] from " + PluginSettingsFacade.GetYamlDomainFilePrefix("spawner") + ".locations.reference.yml # Optional"); AppendTemplateLine(stringBuilder, 1, "conditions: # If these conditions fail, this custom entry is ignored and the original spawner behavior is used"); AppendTemplateLine(stringBuilder, 2, "altitude: null # ex) -1000~1000 # Range in world-height meters"); AppendTemplateLine(stringBuilder, 2, "distanceFromCenter: null # ex) 0~10000 # Range in meters from the world center"); AppendTemplateLine(stringBuilder, 2, "biomes: [] # ex) [BlackForest, Mistlands] # Allowed biomes # EWD custom biome names also work when EWD is installed"); AppendTemplateLine(stringBuilder, 2, "timeOfDay: null # ex) [night] # [day, afternoon, night] # day contains afternoon"); AppendTemplateLine(stringBuilder, 2, "requiredEnvironments: [] # ex) [Rain] # Allowed environment names"); AppendTemplateLine(stringBuilder, 2, "requiredGlobalKeys: [] # ex) [defeated_gdking] # Required global keys"); AppendTemplateLine(stringBuilder, 2, "forbiddenGlobalKeys: [] # ex) [nomap] # Forbidden global keys"); AppendTemplateLine(stringBuilder, 2, "inForest: null # ex) true = forest only # false = outside forest only # null or no field allows both"); AppendTemplateLine(stringBuilder, 2, "inDungeon: null # ex) true = dungeon only # false = overworld only # null or no field allows both"); AppendTemplateLine(stringBuilder, 2, "insidePlayerBase: null # ex) true = near player base only # false = away from player base only # null or no field allows both # Valid for spawnArea-only entry gating"); AppendTemplateLine(stringBuilder, 1, "spawnArea:"); AppendTemplateLine(stringBuilder, 2, "levelUpChance: 15 # Percent chance for each extra level roll when creature level is a range"); AppendTemplateLine(stringBuilder, 2, "spawnInterval: 30 # Seconds between spawn attempts after the timer passes"); AppendTemplateLine(stringBuilder, 2, "triggerDistance: 256 # Meters from the spawner within which players must be present for spawning to tick"); AppendTemplateLine(stringBuilder, 2, "setPatrolSpawnPoint: true # True gives spawned AI this spawner as its patrol or home point"); AppendTemplateLine(stringBuilder, 2, "spawnRadius: 2 # Meters around the SpawnArea center used for spawn placement"); AppendTemplateLine(stringBuilder, 2, "nearRadius: 10 # Meters used by the native near-count cap"); AppendTemplateLine(stringBuilder, 2, "farRadius: 1000 # Meters used by the native total-count cap"); AppendTemplateLine(stringBuilder, 2, "maxNear: 3 # Native cap on living creatures inside nearRadius"); AppendTemplateLine(stringBuilder, 2, "maxTotal: 20 # Native cap on living creatures inside farRadius"); AppendTemplateLine(stringBuilder, 2, "maxTotalSpawns: null # Optional total successful-spawn limit for this SpawnArea # null uses General / Default SpawnArea Max Total Spawns # 0 disables # 1~1000 destroys after that many successful spawns"); AppendTemplateLine(stringBuilder, 2, "onGroundOnly: false # True restricts spawn placement to grounded points only"); AppendTemplateLine(stringBuilder, 2, "creatures:"); AppendTemplateLine(stringBuilder, 2, "- creature: null # ex) Draugr # Required creature prefab name"); AppendTemplateLine(stringBuilder, 3, "weight: 1 # Relative weight versus other entries in the same SpawnArea list"); AppendTemplateLine(stringBuilder, 3, "level: 1~1 # ex) 1~2 # Range of spawned creature levels"); AppendTemplateLine(stringBuilder, 3, "data: null # Optional Expand World Data entry applied to the spawned creature"); AppendTemplateLine(stringBuilder, 3, "fields: {} # ex) { Character.m_name: $enemy_draugr, health: 200 } # Expand World Data field overrides layered on top of data"); AppendTemplateLine(stringBuilder, 3, "objects: [] # ex) [Wood,0,0,0,1] # Expand World Data object entries spawned at the final spawn point"); AppendTemplateLine(stringBuilder, 3, "faction: null # ex) Boss # Values: " + FactionIntegration.GetNativeFactionList()); AppendTemplateBlankLine(stringBuilder); AppendTemplateComment(stringBuilder, "creatureSpawner"); AppendTemplateBlankLine(stringBuilder); AppendTemplateLine(stringBuilder, 0, "- prefab: Spawner_Boar"); AppendTemplateLine(stringBuilder, 1, "enabled: true"); AppendTemplateLine(stringBuilder, 1, "location: Runestone_Boars # ex) locations[] from " + PluginSettingsFacade.GetYamlDomainFilePrefix("spawner") + ".locations.reference.yml # Optional"); AppendTemplateLine(stringBuilder, 1, "conditions:"); AppendTemplateLine(stringBuilder, 2, "altitude: null"); AppendTemplateLine(stringBuilder, 2, "distanceFromCenter: null"); AppendTemplateLine(stringBuilder, 2, "biomes: []"); AppendTemplateLine(stringBuilder, 2, "requiredEnvironments: []"); AppendTemplateLine(stringBuilder, 2, "inForest: null"); AppendTemplateLine(stringBuilder, 2, "inDungeon: null"); AppendTemplateLine(stringBuilder, 1, "creatureSpawner:"); AppendTemplateLine(stringBuilder, 2, "creature: null # ex) Skeleton # Required creature prefab name"); AppendTemplateLine(stringBuilder, 2, "timeOfDay: [day, night] # ex) [afternoon] # Runtime gate for this spawner # day contains afternoon"); AppendTemplateLine(stringBuilder, 2, "requiredGlobalKey: '' # ex) defeated_gdking # Use '' to clear the native requirement # Omit the key to keep the current value"); AppendTemplateLine(stringBuilder, 2, "blockingGlobalKey: '' # ex) nomap # Use '' to clear the native block key # Omit the key to keep the current value"); AppendTemplateLine(stringBuilder, 2, "level: 1~1 # ex) 1~2 # Range of spawned creature levels"); AppendTemplateLine(stringBuilder, 2, "levelUpChance: 10 # Percent chance for each extra level roll when level is a range"); AppendTemplateLine(stringBuilder, 2, "respawnTimeMinutes: 20 # 0 disables respawn after the first successful spawn # Minutes before this spawner can respawn after the previous creature is gone"); AppendTemplateLine(stringBuilder, 2, "spawnCheckInterval: 5 # Seconds between UpdateSpawner checks for this spawner"); AppendTemplateLine(stringBuilder, 2, "spawnGroupId: 0 # Use spawnGroupRadius: 0 to avoid grouping # Nearby spawners with the same id can share native group blocking"); AppendTemplateLine(stringBuilder, 2, "spawnGroupRadius: 0 # Meters used to link nearby same-id spawners into one native group"); AppendTemplateLine(stringBuilder, 2, "spawnerWeight: 1 # Relative weight when a native spawn group chooses one spawner to fire"); AppendTemplateLine(stringBuilder, 2, "maxGroupSpawned: 1 # Max living creatures allowed across the native spawn group"); AppendTemplateLine(stringBuilder, 2, "triggerDistance: 60 # Meters from this spawner within which players must be present for UpdateSpawner to pass"); AppendTemplateLine(stringBuilder, 2, "triggerNoise: 0 # 0 ignores noise # Meters-equivalent native noise threshold required inside triggerDistance"); AppendTemplateLine(stringBuilder, 2, "allowInsidePlayerBase: false # True allows spawning inside player-base suppression areas"); AppendTemplateLine(stringBuilder, 2, "wakeUpAnimation: false # True plays the wake-up animation when the creature appears"); AppendTemplateLine(stringBuilder, 2, "setPatrolSpawnPoint: false # True makes spawned AI patrol around this spawner"); AppendTemplateLine(stringBuilder, 2, "faction: null"); AppendTemplateLine(stringBuilder, 2, "data: null"); AppendTemplateLine(stringBuilder, 2, "fields: {}"); AppendTemplateLine(stringBuilder, 2, "objects: []"); AppendTemplateBlankLine(stringBuilder); return stringBuilder.ToString(); } private static void AppendTemplateComment(StringBuilder builder, string text) { builder.Append("# "); builder.AppendLine(text); } private static void AppendTemplateLine(StringBuilder builder, int indent, string text) { builder.Append("# "); builder.Append(' ', indent * 2); builder.AppendLine(text); } private static void AppendTemplateBlankLine(StringBuilder builder) { builder.AppendLine("#"); } internal static bool HasVneiRelevantSpawnAreaEntries(string prefabName) { lock (Sync) { List value; return ActiveEntriesByPrefab.TryGetValue(prefabName ?? "", out value) && value.Any((SpawnerConfigurationEntry entry) => entry.SpawnArea?.Creatures != null); } } internal static bool TryGetVneiDisplayForSpawnArea(SpawnArea spawnArea, out List results) { lock (Sync) { results = new List(); if ((Object)(object)spawnArea == (Object)null) { return false; } string configPrefabName = GetConfigPrefabName(((Component)spawnArea).gameObject, "SpawnArea"); ActiveEntriesByPrefab.TryGetValue(configPrefabName, out List value); SpawnerConfigurationEntry spawnerConfigurationEntry = null; IEnumerable enumerable = value; foreach (SpawnerConfigurationEntry item in enumerable ?? Enumerable.Empty()) { if (item.SpawnArea?.Creatures != null && !DropConditionEvaluator.HasConditions(item.Conditions) && string.IsNullOrWhiteSpace(item.Location)) { spawnerConfigurationEntry = item; } } Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); if (spawnerConfigurationEntry?.SpawnArea?.Creatures != null) { AddVneiSpawnAreaWeights(dictionary, spawnerConfigurationEntry.SpawnArea.Creatures); } else { AddVneiSpawnAreaWeights(dictionary, spawnArea.m_prefabs); } enumerable = value; foreach (SpawnerConfigurationEntry item2 in enumerable ?? Enumerable.Empty()) { if (item2 != spawnerConfigurationEntry && item2.SpawnArea?.Creatures != null) { AddVneiSpawnAreaWeights(dictionary, item2.SpawnArea.Creatures); } } if (dictionary.Count == 0) { return true; } float num = dictionary.Values.Sum((float weight) => Mathf.Max(0f, weight)); float num2 = ((dictionary.Count == 0) ? 1f : (1f / (float)dictionary.Count)); foreach (KeyValuePair item3 in dictionary.OrderBy, string>((KeyValuePair pair) => pair.Key, StringComparer.OrdinalIgnoreCase)) { item3.Deconstruct(out var key, out var value2); string prefabName = key; float num3 = value2; float chance = ((num <= 0f) ? num2 : Mathf.Clamp01(Mathf.Max(0f, num3) / num)); results.Add(new VneiRecipeResult(prefabName, 1, 1, 1f, 1, 1, chance)); } return dictionary.Count > 0 || (value?.Count ?? 0) > 0 || spawnArea.m_prefabs.Count > 0; } } private static void AddVneiSpawnAreaWeights(Dictionary weightsByPrefab, IEnumerable? prefabs) { foreach (SpawnData item in prefabs ?? Enumerable.Empty()) { if (!((Object)(object)item?.m_prefab == (Object)null)) { string name = ((Object)item.m_prefab).name; if (!weightsByPrefab.TryGetValue(name, out var value)) { value = 0f; } weightsByPrefab[name] = value + Mathf.Max(0f, item.m_weight); } } } private static void AddVneiSpawnAreaWeights(Dictionary weightsByPrefab, IEnumerable? definitions) { foreach (SpawnAreaSpawnDefinition item in definitions ?? Enumerable.Empty()) { string text = (item.Creature ?? "").Trim(); if (text.Length != 0) { if (!weightsByPrefab.TryGetValue(text, out var value)) { value = 0f; } weightsByPrefab[text] = value + Mathf.Max(0f, item.Weight.GetValueOrDefault(1f)); } } } } internal static class VneiCompatibility { private enum ManagedRecipeKind { CharacterDrop, Container, DropOnDestroyed, MineRock, MineRock5, Pickable, Fish, SpawnArea, Destructible, TreeBase } private readonly struct ManagedRecipeKey : IEquatable { public string PrefabName { get; } public ManagedRecipeKind Kind { get; } public ManagedRecipeKey(string prefabName, ManagedRecipeKind kind) { PrefabName = prefabName ?? ""; Kind = kind; } public bool Equals(ManagedRecipeKey other) { if (Kind == other.Kind) { return string.Equals(PrefabName, other.PrefabName, StringComparison.OrdinalIgnoreCase); } return false; } public override bool Equals(object? obj) { if (obj is ManagedRecipeKey other) { return Equals(other); } return false; } public override int GetHashCode() { return (StringComparer.OrdinalIgnoreCase.GetHashCode(PrefabName) * 397) ^ (int)Kind; } } private sealed class ManagedRecipeBinding { public object Recipe { get; set; } public Object? Source { get; set; } public bool IsSupplemental { get; set; } public bool DisableSourceItemWhenRemoved { get; set; } public string LastDisplayFingerprint { get; set; } = ""; } [CompilerGenerated] private sealed class d__49 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private ManagedRecipeKey <>2__current; private int <>l__initialThreadId; private string prefabName; public string <>3__prefabName; ManagedRecipeKey IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__49(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = new ManagedRecipeKey(prefabName, ManagedRecipeKind.Container); <>1__state = 1; return true; case 1: <>1__state = -1; <>2__current = new ManagedRecipeKey(prefabName, ManagedRecipeKind.DropOnDestroyed); <>1__state = 2; return true; case 2: <>1__state = -1; <>2__current = new ManagedRecipeKey(prefabName, ManagedRecipeKind.MineRock); <>1__state = 3; return true; case 3: <>1__state = -1; <>2__current = new ManagedRecipeKey(prefabName, ManagedRecipeKind.MineRock5); <>1__state = 4; return true; case 4: <>1__state = -1; <>2__current = new ManagedRecipeKey(prefabName, ManagedRecipeKind.Pickable); <>1__state = 5; return true; case 5: <>1__state = -1; <>2__current = new ManagedRecipeKey(prefabName, ManagedRecipeKind.Fish); <>1__state = 6; return true; case 6: <>1__state = -1; <>2__current = new ManagedRecipeKey(prefabName, ManagedRecipeKind.Destructible); <>1__state = 7; return true; case 7: <>1__state = -1; <>2__current = new ManagedRecipeKey(prefabName, ManagedRecipeKind.TreeBase); <>1__state = 8; return true; case 8: <>1__state = -1; return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__49 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__49(0); } d__.prefabName = <>3__prefabName; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__89 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; private int <>l__initialThreadId; private IDictionary groups; public IDictionary <>3__groups; private IDictionaryEnumerator <>7__wrap1; private IEnumerator <>7__wrap2; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__89(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(); } } <>7__wrap1 = null; <>7__wrap2 = 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_00cb; } <>1__state = -1; if (groups == null) { return false; } <>7__wrap1 = groups.GetEnumerator(); <>1__state = -3; goto IL_00e5; IL_00cb: while (<>7__wrap2.MoveNext()) { object current = <>7__wrap2.Current; object obj = ((current == null) ? null : _partItemField?.GetValue(current)); if (obj != null) { <>2__current = obj; <>1__state = 1; return true; } } <>m__Finally2(); <>7__wrap2 = null; goto IL_00e5; IL_00e5: IEnumerable enumerable; do { if (<>7__wrap1.MoveNext()) { enumerable = ((DictionaryEntry)<>7__wrap1.Current).Value as IEnumerable; continue; } <>m__Finally1(); <>7__wrap1 = null; return false; } while (enumerable == null); <>7__wrap2 = enumerable.GetEnumerator(); <>1__state = -4; goto IL_00cb; } 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 (<>7__wrap1 is IDisposable disposable) { disposable.Dispose(); } } private void <>m__Finally2() { <>1__state = -3; if (<>7__wrap2 is IDisposable disposable) { disposable.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__89 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__89(0); } d__.groups = <>3__groups; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__88 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; private int <>l__initialThreadId; private object recipe; public object <>3__recipe; private IEnumerator <>7__wrap1; private IEnumerator <>7__wrap2; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__88(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { switch (<>1__state) { case -3: case 1: try { } finally { <>m__Finally1(); } break; case -4: case 2: try { } finally { <>m__Finally2(); } break; case -5: case 3: try { } finally { <>m__Finally3(); } break; } <>7__wrap1 = null; <>7__wrap2 = null; <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>7__wrap1 = EnumerateItemsFromGroupDictionary(_ingredientsProperty?.GetValue(recipe) as IDictionary).GetEnumerator(); <>1__state = -3; goto IL_008a; case 1: <>1__state = -3; goto IL_008a; case 2: <>1__state = -4; goto IL_0105; case 3: { <>1__state = -5; goto IL_019d; } IL_0105: if (<>7__wrap1.MoveNext()) { object current = <>7__wrap1.Current; <>2__current = current; <>1__state = 2; return true; } <>m__Finally2(); <>7__wrap1 = null; if (!(_stationsProperty?.GetValue(recipe) is IEnumerable enumerable)) { break; } <>7__wrap2 = enumerable.GetEnumerator(); <>1__state = -5; goto IL_019d; IL_019d: while (<>7__wrap2.MoveNext()) { object current2 = <>7__wrap2.Current; object obj = ((current2 == null) ? null : _partItemField?.GetValue(current2)); if (obj != null) { <>2__current = obj; <>1__state = 3; return true; } } <>m__Finally3(); <>7__wrap2 = null; break; IL_008a: if (<>7__wrap1.MoveNext()) { object current3 = <>7__wrap1.Current; <>2__current = current3; <>1__state = 1; return true; } <>m__Finally1(); <>7__wrap1 = null; <>7__wrap1 = EnumerateItemsFromGroupDictionary(_resultsProperty?.GetValue(recipe) as IDictionary).GetEnumerator(); <>1__state = -4; goto IL_0105; } 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 (<>7__wrap1 != null) { <>7__wrap1.Dispose(); } } private void <>m__Finally2() { <>1__state = -1; if (<>7__wrap1 != null) { <>7__wrap1.Dispose(); } } private void <>m__Finally3() { <>1__state = -1; if (<>7__wrap2 is IDisposable disposable) { disposable.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__88 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__88(0); } d__.recipe = <>3__recipe; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__51 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__51(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = null; <>1__state = 1; return true; case 1: <>1__state = -1; break; case 2: <>1__state = -1; break; } if (CanRefresh()) { ProcessQueuedRefreshes(8, Time.realtimeSinceStartup + 0.0015f); } lock (RefreshSync) { if (PendingRefreshWorkItems.Count == 0) { _pendingRefreshCoroutine = null; return false; } } <>2__current = null; <>1__state = 2; return true; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private const string VneiPluginGuid = "com.maxsch.valheim.vnei"; private const float RefreshFrameBudgetSeconds = 0.0015f; private const int MaxRefreshJobsPerFrame = 8; private static bool _initialized; private static bool _available; private static Type? _recipeInfoType; private static Type? _indexingType; private static Type? _amountType; private static Type? _itemType; private static Type? _partType; private static ConstructorInfo? _emptyRecipeCtor; private static ConstructorInfo? _rangeAmountCtor; private static ConstructorInfo? _singleAmountCtor; private static MethodInfo? _addIngredientMethod; private static MethodInfo? _addResultMethod; private static MethodInfo? _addRecipeToItemsMethod; private static MethodInfo? _getItemMethod; private static MethodInfo? _hasIndexedMethod; private static MethodInfo? _combineGroupAmountsMethod; private static MethodInfo? _recipeCalculateIsOnBlacklistMethod; private static MethodInfo? _recipeCalculateWidthMethod; private static MethodInfo? _recipeUpdateKnownMethod; private static MethodInfo? _itemUpdateKnownMethod; private static PropertyInfo? _ingredientsProperty; private static PropertyInfo? _resultsProperty; private static PropertyInfo? _stationsProperty; private static PropertyInfo? _recipesProperty; private static FieldInfo? _itemIsActiveField; private static FieldInfo? _itemResultField; private static FieldInfo? _itemIngredientField; private static FieldInfo? _partItemField; private static FieldInfo? _recipeIsOnBlacklistBackingField; private static readonly Dictionary ManagedRecipesByKey = new Dictionary(); private static readonly object RefreshSync = new object(); private static readonly RingBufferQueue PendingRefreshWorkItems = new RingBufferQueue(); private static readonly HashSet PendingRefreshWorkSet = new HashSet(); private static Coroutine? _pendingRefreshCoroutine; internal static void Initialize(Harmony harmony) { if (_initialized) { return; } _initialized = true; if (!Chainloader.PluginInfos.ContainsKey("com.maxsch.valheim.vnei")) { return; } _recipeInfoType = AccessTools.TypeByName("VNEI.Logic.RecipeInfo"); _indexingType = AccessTools.TypeByName("VNEI.Logic.Indexing"); _amountType = AccessTools.TypeByName("VNEI.Logic.Amount"); _itemType = AccessTools.TypeByName("VNEI.Logic.Item"); _partType = AccessTools.TypeByName("VNEI.Logic.Part"); if (_recipeInfoType == null || _indexingType == null || _amountType == null || _itemType == null || _partType == null) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)"VNEI detected, but one or more compatibility types could not be resolved."); return; } _emptyRecipeCtor = AccessTools.Constructor(_recipeInfoType, Type.EmptyTypes, false); _rangeAmountCtor = AccessTools.Constructor(_amountType, new Type[3] { typeof(int), typeof(int), typeof(float) }, false); _singleAmountCtor = AccessTools.Constructor(_amountType, new Type[2] { typeof(int), typeof(float) }, false); _addIngredientMethod = AccessTools.Method(_recipeInfoType, "AddIngredient", new Type[4] { typeof(string), _amountType, _amountType, typeof(int) }, (Type[])null); _addResultMethod = AccessTools.Method(_recipeInfoType, "AddResult", new Type[4] { typeof(string), _amountType, _amountType, typeof(int) }, (Type[])null); _addRecipeToItemsMethod = AccessTools.Method(_indexingType, "AddRecipeToItems", new Type[1] { _recipeInfoType }, (Type[])null); _getItemMethod = AccessTools.Method(_indexingType, "GetItem", new Type[1] { typeof(string) }, (Type[])null); _hasIndexedMethod = AccessTools.Method(_indexingType, "HasIndexed", Type.EmptyTypes, (Type[])null); _combineGroupAmountsMethod = AccessTools.Method(_recipeInfoType, "CombineGroupAmounts", new Type[1] { typeof(Dictionary<, >).MakeGenericType(_amountType, typeof(List<>).MakeGenericType(_partType)) }, (Type[])null); _recipeCalculateIsOnBlacklistMethod = AccessTools.Method(_recipeInfoType, "CalculateIsOnBlacklist", Type.EmptyTypes, (Type[])null); _recipeCalculateWidthMethod = AccessTools.Method(_recipeInfoType, "CalculateWidth", Type.EmptyTypes, (Type[])null); _recipeUpdateKnownMethod = AccessTools.Method(_recipeInfoType, "UpdateKnown", Type.EmptyTypes, (Type[])null); _itemUpdateKnownMethod = AccessTools.Method(_itemType, "UpdateKnown", Type.EmptyTypes, (Type[])null); _ingredientsProperty = AccessTools.Property(_recipeInfoType, "Ingredients"); _resultsProperty = AccessTools.Property(_recipeInfoType, "Results"); _stationsProperty = AccessTools.Property(_recipeInfoType, "Stations"); _recipesProperty = AccessTools.Property(_recipeInfoType, "Recipes"); _itemIsActiveField = AccessTools.Field(_itemType, "isActive"); _itemResultField = AccessTools.Field(_itemType, "result"); _itemIngredientField = AccessTools.Field(_itemType, "ingredient"); _partItemField = AccessTools.Field(_partType, "item"); _recipeIsOnBlacklistBackingField = AccessTools.Field(_recipeInfoType, "k__BackingField"); _available = _emptyRecipeCtor != null && _rangeAmountCtor != null && _singleAmountCtor != null && _addIngredientMethod != null && _addResultMethod != null && _addRecipeToItemsMethod != null && _getItemMethod != null && _hasIndexedMethod != null && _combineGroupAmountsMethod != null && _recipeCalculateIsOnBlacklistMethod != null && _recipeCalculateWidthMethod != null && _recipeUpdateKnownMethod != null && _itemUpdateKnownMethod != null && _ingredientsProperty != null && _resultsProperty != null && _stationsProperty != null && _recipesProperty != null && _itemResultField != null && _itemIngredientField != null && _partItemField != null; if (!_available) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)"VNEI detected, but one or more compatibility members could not be resolved."); return; } PatchConstructor(harmony, new Type[1] { typeof(CharacterDrop) }, "CharacterDropCtorPostfix"); PatchConstructor(harmony, new Type[2] { typeof(GameObject), typeof(DropTable) }, "DropTableCtorPostfix"); PatchConstructor(harmony, new Type[2] { typeof(GameObject), typeof(Pickable) }, "PickableCtorPostfix"); PatchConstructor(harmony, new Type[1] { typeof(SpawnArea) }, "SpawnAreaCtorPostfix"); PatchConstructor(harmony, new Type[1] { typeof(Destructible) }, "DestructibleCtorPostfix"); PatchConstructor(harmony, new Type[1] { typeof(TreeBase) }, "TreeBaseCtorPostfix"); System.Reflection.EventInfo @event = _indexingType.GetEvent("OnIndexingItemRecipes", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (@event != null) { @event.AddEventHandler(null, new Action(HandleIndexingItemRecipes)); } DropNSpawnPlugin.DropNSpawnLogger.LogInfo((object)"VNEI compatibility enabled."); } internal static void RefreshCharacterPrefabs(IEnumerable prefabNames) { EnqueueRefresh(from prefabName in NormalizePrefabNames(prefabNames) select new ManagedRecipeKey(prefabName, ManagedRecipeKind.CharacterDrop)); } internal static void RefreshObjectPrefabs(IEnumerable prefabNames) { EnqueueRefresh(ExpandObjectPrefabNames(prefabNames).SelectMany(BuildObjectRefreshWorkItems)); } internal static void RefreshSpawnerPrefabs(IEnumerable prefabNames) { EnqueueRefresh(from prefabName in NormalizePrefabNames(prefabNames) select new ManagedRecipeKey(prefabName, ManagedRecipeKind.SpawnArea)); } private static bool CanRefresh() { if (_available) { return HasIndexed(); } return false; } private static bool HasIndexed() { try { return _hasIndexedMethod != null && (bool)(_hasIndexedMethod.Invoke(null, Array.Empty()) ?? ((object)false)); } catch { return false; } } private static IEnumerable NormalizePrefabNames(IEnumerable prefabNames) { return (from name in prefabNames ?? Array.Empty() select (name ?? "").Trim() into name where name.Length > 0 select name).Distinct(StringComparer.OrdinalIgnoreCase); } private static HashSet ExpandObjectPrefabNames(IEnumerable prefabNames) { HashSet hashSet = NormalizePrefabNames(prefabNames).ToHashSet(StringComparer.OrdinalIgnoreCase); if (hashSet.Count == 0 || (Object)(object)ZNetScene.instance == (Object)null) { return hashSet; } HashSet hashSet2 = new HashSet(ZNetScene.instance.m_prefabs); hashSet2.UnionWith(ZNetScene.instance.m_namedPrefabs.Values); TreeBase val = default(TreeBase); foreach (GameObject item in hashSet2) { if (!((Object)(object)item == (Object)null) && !hashSet.Contains(((Object)item).name) && item.TryGetComponent(ref val) && TreeBaseUsesAnyChangedLog(val.m_logPrefab, hashSet, 0)) { hashSet.Add(((Object)item).name); } } return hashSet; } private static bool TreeBaseUsesAnyChangedLog(GameObject? logPrefab, HashSet changedPrefabs, int depth) { if ((Object)(object)logPrefab == (Object)null || depth > 50) { return false; } if (changedPrefabs.Contains(((Object)logPrefab).name)) { return true; } TreeLog val = default(TreeLog); if (!logPrefab.TryGetComponent(ref val) || val.m_subLogPoints == null || val.m_subLogPoints.Length == 0) { return false; } return TreeBaseUsesAnyChangedLog(val.m_subLogPrefab, changedPrefabs, depth + 1); } [IteratorStateMachine(typeof(d__49))] private static IEnumerable BuildObjectRefreshWorkItems(string prefabName) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__49(-2) { <>3__prefabName = prefabName }; } private static void EnqueueRefresh(IEnumerable workItems) { if (!_available) { return; } bool flag = false; lock (RefreshSync) { foreach (ManagedRecipeKey workItem in workItems) { if (PendingRefreshWorkSet.Add(workItem)) { PendingRefreshWorkItems.Enqueue(workItem); } } if (_pendingRefreshCoroutine == null && (Object)(object)DropNSpawnPlugin.Instance != (Object)null && PendingRefreshWorkItems.Count > 0) { flag = true; _pendingRefreshCoroutine = ((MonoBehaviour)DropNSpawnPlugin.Instance).StartCoroutine(ProcessQueuedRefreshesCoroutine()); } } if (!flag && (Object)(object)DropNSpawnPlugin.Instance == (Object)null) { ProcessQueuedRefreshes(int.MaxValue, float.PositiveInfinity); } } [IteratorStateMachine(typeof(d__51))] private static IEnumerator ProcessQueuedRefreshesCoroutine() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__51(0); } private static bool ProcessQueuedRefreshes(int maxJobs, float deadline) { if (!CanRefresh()) { return false; } int i = 0; HashSet hashSet = null; for (; i < maxJobs; i++) { if (!(Time.realtimeSinceStartup < deadline)) { break; } if (!TryDequeueRefreshWorkItem(out var workItem)) { break; } if (hashSet == null) { hashSet = new HashSet(); } ProcessQueuedRefreshWorkItem(workItem, hashSet); } if (hashSet != null && hashSet.Count > 0) { UpdateKnownForItems(hashSet); } return i > 0; } private static bool TryDequeueRefreshWorkItem(out ManagedRecipeKey workItem) { lock (RefreshSync) { if (!PendingRefreshWorkItems.TryDequeue(out workItem)) { return false; } PendingRefreshWorkSet.Remove(workItem); return true; } } private static void ProcessQueuedRefreshWorkItem(ManagedRecipeKey workItem, HashSet affectedItems) { switch (workItem.Kind) { case ManagedRecipeKind.CharacterDrop: RefreshCharacterPrefab(workItem.PrefabName, affectedItems); break; case ManagedRecipeKind.Container: RefreshContainerPrefab(workItem.PrefabName, affectedItems); break; case ManagedRecipeKind.DropOnDestroyed: case ManagedRecipeKind.MineRock: case ManagedRecipeKind.MineRock5: RefreshDropTablePrefab(workItem.PrefabName, workItem.Kind, affectedItems); break; case ManagedRecipeKind.Pickable: RefreshPickablePrefab(workItem.PrefabName, affectedItems); break; case ManagedRecipeKind.Fish: RefreshFishPrefab(workItem.PrefabName, affectedItems); break; case ManagedRecipeKind.SpawnArea: RefreshSpawnAreaPrefab(workItem.PrefabName, affectedItems); break; case ManagedRecipeKind.Destructible: RefreshDestructiblePrefab(workItem.PrefabName, affectedItems); break; case ManagedRecipeKind.TreeBase: RefreshTreeBasePrefab(workItem.PrefabName, affectedItems); break; } } private static void PatchConstructor(Harmony harmony, Type[] argumentTypes, string postfixName) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown if (!(_recipeInfoType == null)) { ConstructorInfo constructorInfo = AccessTools.Constructor(_recipeInfoType, argumentTypes, false); MethodInfo methodInfo = AccessTools.Method(typeof(VneiCompatibility), postfixName, (Type[])null, (Type[])null); if (!(constructorInfo == null) && !(methodInfo == null)) { harmony.Patch((MethodBase)constructorInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } } private static void CharacterDropCtorPostfix(object __instance, [HarmonyArgument(0)] CharacterDrop characterDrop) { if (_available && !((Object)(object)characterDrop == (Object)null) && !((Object)(object)((Component)characterDrop).gameObject == (Object)null)) { ManagedRecipeBinding managedRecipeBinding = RegisterManagedRecipe(new ManagedRecipeKey(((Object)((Component)characterDrop).gameObject).name, ManagedRecipeKind.CharacterDrop), __instance, (Object?)(object)characterDrop, isSupplemental: false, disableSourceItemWhenRemoved: false); if (CharacterDropManager.HasVneiRelevantEntries(((Object)((Component)characterDrop).gameObject).name) && CharacterDropManager.TryGetVneiDisplayResults(characterDrop, out List results)) { RewriteRecipeResults(__instance, results); managedRecipeBinding.LastDisplayFingerprint = BuildResultsFingerprint(results); } } } private static void DropTableCtorPostfix(object __instance, [HarmonyArgument(0)] GameObject from, [HarmonyArgument(1)] DropTable dropTable) { if (_available && !((Object)(object)from == (Object)null) && dropTable != null && TryGetDropTableRecipeKey(from, dropTable, out var key)) { ManagedRecipeBinding managedRecipeBinding = RegisterManagedRecipe(key, __instance, (Object?)(object)from, isSupplemental: false, disableSourceItemWhenRemoved: false); if (ShouldRewriteDropTableRecipe(key) && ObjectDropManager.TryGetVneiDisplayForDropTable(from, dropTable, out List results)) { RewriteRecipeResults(__instance, results); managedRecipeBinding.LastDisplayFingerprint = BuildResultsFingerprint(results); } } } private static void PickableCtorPostfix(object __instance, [HarmonyArgument(0)] GameObject prefab, [HarmonyArgument(1)] Pickable pickable) { if (_available && !((Object)(object)prefab == (Object)null) && !((Object)(object)pickable == (Object)null)) { ManagedRecipeBinding managedRecipeBinding = RegisterManagedRecipe(new ManagedRecipeKey(((Object)prefab).name, ManagedRecipeKind.Pickable), __instance, (Object?)(object)pickable, isSupplemental: false, disableSourceItemWhenRemoved: false); if (ObjectDropManager.HasVneiRelevantPickableOverride(((Object)prefab).name) && ObjectDropManager.TryGetVneiDisplayForPickable(prefab, pickable, out List results)) { RewriteRecipeResults(__instance, results); managedRecipeBinding.LastDisplayFingerprint = BuildResultsFingerprint(results); } } } private static void SpawnAreaCtorPostfix(object __instance, [HarmonyArgument(0)] SpawnArea spawnArea) { if (_available && !((Object)(object)spawnArea == (Object)null) && !((Object)(object)((Component)spawnArea).gameObject == (Object)null)) { ManagedRecipeBinding managedRecipeBinding = RegisterManagedRecipe(new ManagedRecipeKey(((Object)((Component)spawnArea).gameObject).name, ManagedRecipeKind.SpawnArea), __instance, (Object?)(object)spawnArea, isSupplemental: false, disableSourceItemWhenRemoved: false); if (SpawnerManager.HasVneiRelevantSpawnAreaEntries(((Object)((Component)spawnArea).gameObject).name) && SpawnerManager.TryGetVneiDisplayForSpawnArea(spawnArea, out List results)) { RewriteRecipeResults(__instance, results); managedRecipeBinding.LastDisplayFingerprint = BuildResultsFingerprint(results); } } } private static void DestructibleCtorPostfix(object __instance, [HarmonyArgument(0)] Destructible destructible) { if (_available && !((Object)(object)destructible == (Object)null) && !((Object)(object)((Component)destructible).gameObject == (Object)null)) { ManagedRecipeBinding managedRecipeBinding = RegisterManagedRecipe(new ManagedRecipeKey(((Object)((Component)destructible).gameObject).name, ManagedRecipeKind.Destructible), __instance, (Object?)(object)destructible, isSupplemental: false, disableSourceItemWhenRemoved: false); if (ObjectDropManager.HasVneiRelevantDestructibleOverride(((Object)((Component)destructible).gameObject).name) && ObjectDropManager.TryGetVneiDisplayForDestructible(destructible, out List results)) { RewriteRecipeResults(__instance, results); managedRecipeBinding.LastDisplayFingerprint = BuildResultsFingerprint(results); } } } private static void TreeBaseCtorPostfix(object __instance, [HarmonyArgument(0)] TreeBase treeBase) { if (_available && !((Object)(object)treeBase == (Object)null) && !((Object)(object)((Component)treeBase).gameObject == (Object)null)) { ManagedRecipeBinding managedRecipeBinding = RegisterManagedRecipe(new ManagedRecipeKey(((Object)((Component)treeBase).gameObject).name, ManagedRecipeKind.TreeBase), __instance, (Object?)(object)treeBase, isSupplemental: false, disableSourceItemWhenRemoved: false); if (ObjectDropManager.HasVneiRelevantTreeBaseOverride(((Object)((Component)treeBase).gameObject).name) && ObjectDropManager.TryGetVneiDisplayForTreeBase(treeBase, out List results)) { RewriteRecipeResults(__instance, results); managedRecipeBinding.LastDisplayFingerprint = BuildResultsFingerprint(results); } } } private static void HandleIndexingItemRecipes(GameObject prefab) { try { TryAddMissingContainerRecipe(prefab); TryAddMissingDestructibleRecipe(prefab); TryAddMissingFishRecipe(prefab); } catch (Exception ex) { DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("VNEI compatibility failed while indexing '" + ((prefab != null) ? ((Object)prefab).name : null) + "': " + ex.Message)); } } private static void TryAddMissingContainerRecipe(GameObject prefab) { if (ShouldUseSupplementalContainerRecipe(prefab, out List results)) { CreateAndRegisterSupplementalRecipe(new ManagedRecipeKey(((Object)prefab).name, ManagedRecipeKind.Container), (Object)(object)prefab, results, enableSourceItem: false, disableSourceItemWhenRemoved: false); } } private static bool ShouldUseSupplementalContainerRecipe(GameObject? prefab, out List results) { results = new List(); Piece val = default(Piece); Container val2 = default(Container); if ((Object)(object)prefab != (Object)null && prefab.TryGetComponent(ref val) && prefab.TryGetComponent(ref val2) && val2.m_defaultItems != null && val2.m_defaultItems.m_drops.Count == 0 && ObjectDropManager.TryGetVneiDisplayForContainer(prefab, out results)) { return results.Count > 0; } return false; } private static void TryAddMissingDestructibleRecipe(GameObject prefab) { if (ShouldUseSupplementalDestructibleRecipe(prefab, out Destructible destructible, out List results)) { CreateAndRegisterSupplementalRecipe(new ManagedRecipeKey(((Object)prefab).name, ManagedRecipeKind.Destructible), (Object)(object)destructible, results, enableSourceItem: true, disableSourceItemWhenRemoved: true); } } private static bool ShouldUseSupplementalDestructibleRecipe(GameObject? prefab, out Destructible? destructible, out List results) { destructible = null; results = new List(); if ((Object)(object)prefab != (Object)null && prefab.TryGetComponent(ref destructible) && (Object)(object)prefab.GetComponent() == (Object)null && (Object)(object)prefab.GetComponent() == (Object)null && (Object)(object)destructible != (Object)null && ((Object)(object)destructible.m_spawnWhenDestroyed == (Object)null || TryResolveVneiItem(((Object)destructible.m_spawnWhenDestroyed).name) == null) && ObjectDropManager.TryGetVneiDisplayForDestructible(destructible, out results)) { return results.Count > 0; } return false; } private static void TryAddMissingFishRecipe(GameObject prefab) { ManagedRecipeKey key = new ManagedRecipeKey(((Object)prefab).name, ManagedRecipeKind.Fish); if (!ManagedRecipesByKey.ContainsKey(key) && ShouldUseSupplementalFishRecipe(prefab, out Fish fish, out List results)) { CreateAndRegisterSupplementalRecipe(key, (Object)(object)fish, results, enableSourceItem: true, disableSourceItemWhenRemoved: false); } } private static bool ShouldUseSupplementalFishRecipe(GameObject? prefab, out Fish? fish, out List results) { fish = null; results = new List(); if ((Object)(object)prefab != (Object)null && prefab.TryGetComponent(ref fish) && ObjectDropManager.TryGetVneiDisplayForFish(fish, out results)) { return results.Count > 0; } return false; } private static void RefreshCharacterPrefab(string prefabName, HashSet affectedItems) { ManagedRecipeKey key = new ManagedRecipeKey(prefabName, ManagedRecipeKind.CharacterDrop); if (ManagedRecipesByKey.TryGetValue(key, out ManagedRecipeBinding value)) { Object? source = value.Source; CharacterDrop val = (CharacterDrop)(object)((source is CharacterDrop) ? source : null); if (val != null && CharacterDropManager.TryGetVneiDisplayResults(val, out List results)) { RefreshManagedRecipe(key, value, results, affectedItems); } } } private static void RefreshSpawnAreaPrefab(string prefabName, HashSet affectedItems) { ManagedRecipeKey key = new ManagedRecipeKey(prefabName, ManagedRecipeKind.SpawnArea); if (ManagedRecipesByKey.TryGetValue(key, out ManagedRecipeBinding value)) { Object? source = value.Source; SpawnArea val = (SpawnArea)(object)((source is SpawnArea) ? source : null); if (val != null && SpawnerManager.TryGetVneiDisplayForSpawnArea(val, out List results)) { RefreshManagedRecipe(key, value, results, affectedItems); } } } private static void RefreshContainerPrefab(string prefabName, HashSet affectedItems) { ManagedRecipeKey key = new ManagedRecipeKey(prefabName, ManagedRecipeKind.Container); GameObject val = ResolvePrefab(prefabName); List results2; if (ManagedRecipesByKey.TryGetValue(key, out ManagedRecipeBinding value)) { if ((Object)(object)val != (Object)null && ObjectDropManager.TryGetVneiDisplayForContainer(val, out List results)) { RefreshManagedRecipe(key, value, results, affectedItems); } else if (value.IsSupplemental) { RemoveManagedRecipe(key, value, affectedItems); } } else if (ShouldUseSupplementalContainerRecipe(val, out results2)) { CreateAndRegisterSupplementalRecipe(key, (Object)(object)val, results2, enableSourceItem: false, disableSourceItemWhenRemoved: false, affectedItems); } } private static void RefreshDropTablePrefab(string prefabName, ManagedRecipeKind kind, HashSet affectedItems) { ManagedRecipeKey key = new ManagedRecipeKey(prefabName, kind); if (ManagedRecipesByKey.TryGetValue(key, out ManagedRecipeBinding value)) { Object? source = value.Source; GameObject val = (GameObject)(object)((source is GameObject) ? source : null); if (val != null && TryGetDropTableForKind(val, kind, out DropTable dropTable) && dropTable != null && ObjectDropManager.TryGetVneiDisplayForDropTable(val, dropTable, out List results)) { RefreshManagedRecipe(key, value, results, affectedItems); } } } private static void RefreshPickablePrefab(string prefabName, HashSet affectedItems) { ManagedRecipeKey key = new ManagedRecipeKey(prefabName, ManagedRecipeKind.Pickable); if (ManagedRecipesByKey.TryGetValue(key, out ManagedRecipeBinding value)) { Object? source = value.Source; Pickable val = (Pickable)(object)((source is Pickable) ? source : null); if (val != null && ObjectDropManager.TryGetVneiDisplayForPickable(((Component)val).gameObject, val, out List results)) { RefreshManagedRecipe(key, value, results, affectedItems); } } } private static void RefreshFishPrefab(string prefabName, HashSet affectedItems) { ManagedRecipeKey key = new ManagedRecipeKey(prefabName, ManagedRecipeKind.Fish); GameObject val = ResolvePrefab(prefabName); Fish fish; List results2; if (ManagedRecipesByKey.TryGetValue(key, out ManagedRecipeBinding value)) { Object? source = value.Source; Fish val2 = (Fish)(((object)((source is Fish) ? source : null)) ?? ((object)((val != null) ? val.GetComponent() : null))); if ((Object)(object)val2 != (Object)null && ObjectDropManager.TryGetVneiDisplayForFish(val2, out List results)) { RefreshManagedRecipe(key, value, results, affectedItems); } else if (value.IsSupplemental) { RemoveManagedRecipe(key, value, affectedItems); } } else if (ShouldUseSupplementalFishRecipe(val, out fish, out results2)) { CreateAndRegisterSupplementalRecipe(key, (Object)(object)fish, results2, enableSourceItem: true, disableSourceItemWhenRemoved: false, affectedItems); } } private static void RefreshDestructiblePrefab(string prefabName, HashSet affectedItems) { ManagedRecipeKey key = new ManagedRecipeKey(prefabName, ManagedRecipeKind.Destructible); GameObject prefab = ResolvePrefab(prefabName); Destructible destructible; List results2; if (ManagedRecipesByKey.TryGetValue(key, out ManagedRecipeBinding value)) { Object? source = value.Source; Destructible val = (Destructible)(object)((source is Destructible) ? source : null); if (val != null && ObjectDropManager.TryGetVneiDisplayForDestructible(val, out List results)) { RefreshManagedRecipe(key, value, results, affectedItems); } else if (value.IsSupplemental) { RemoveManagedRecipe(key, value, affectedItems); } } else if (ShouldUseSupplementalDestructibleRecipe(prefab, out destructible, out results2)) { CreateAndRegisterSupplementalRecipe(key, (Object)(object)destructible, results2, enableSourceItem: true, disableSourceItemWhenRemoved: true, affectedItems); } } private static void RefreshTreeBasePrefab(string prefabName, HashSet affectedItems) { ManagedRecipeKey key = new ManagedRecipeKey(prefabName, ManagedRecipeKind.TreeBase); if (ManagedRecipesByKey.TryGetValue(key, out ManagedRecipeBinding value)) { Object? source = value.Source; TreeBase val = (TreeBase)(object)((source is TreeBase) ? source : null); if (val != null && ObjectDropManager.TryGetVneiDisplayForTreeBase(val, out List results)) { RefreshManagedRecipe(key, value, results, affectedItems); } } } private static void RefreshManagedRecipe(ManagedRecipeKey key, ManagedRecipeBinding binding, List results, HashSet affectedItems) { if (binding.IsSupplemental && results.Count == 0) { RemoveManagedRecipe(key, binding, affectedItems); return; } string text = BuildResultsFingerprint(results); if (!string.Equals(binding.LastDisplayFingerprint, text, StringComparison.Ordinal)) { affectedItems.UnionWith(CollectRecipeItems(binding.Recipe)); DetachRecipeFromItems(binding.Recipe, removeFromRecipesList: false); RewriteRecipeResults(binding.Recipe, results); ResetAndRecalculateRecipe(binding.Recipe); _addRecipeToItemsMethod?.Invoke(null, new object[1] { binding.Recipe }); affectedItems.UnionWith(CollectRecipeItems(binding.Recipe)); binding.LastDisplayFingerprint = text; if (binding.IsSupplemental && binding.DisableSourceItemWhenRemoved) { SetVneiItemActive(key.PrefabName, active: true); } } } private static void RemoveManagedRecipe(ManagedRecipeKey key, ManagedRecipeBinding binding, HashSet affectedItems) { affectedItems.UnionWith(CollectRecipeItems(binding.Recipe)); DetachRecipeFromItems(binding.Recipe, removeFromRecipesList: true); ManagedRecipesByKey.Remove(key); if (binding.IsSupplemental && binding.DisableSourceItemWhenRemoved) { SetVneiItemActive(key.PrefabName, active: false); } } private static ManagedRecipeBinding RegisterManagedRecipe(ManagedRecipeKey key, object recipe, Object? source, bool isSupplemental, bool disableSourceItemWhenRemoved) { ManagedRecipeBinding managedRecipeBinding = new ManagedRecipeBinding { Recipe = recipe, Source = source, IsSupplemental = isSupplemental, DisableSourceItemWhenRemoved = disableSourceItemWhenRemoved }; ManagedRecipesByKey[key] = managedRecipeBinding; return managedRecipeBinding; } private static void CreateAndRegisterSupplementalRecipe(ManagedRecipeKey key, Object source, List results, bool enableSourceItem, bool disableSourceItemWhenRemoved, HashSet? affectedItems = null) { if (!(_emptyRecipeCtor == null) && !(_addIngredientMethod == null) && !(_addRecipeToItemsMethod == null)) { object obj = _emptyRecipeCtor.Invoke(Array.Empty()); AddIngredient(obj, source.name, 1, 1, 1f, 1, 1, 1f); RewriteRecipeResults(obj, results); ResetAndRecalculateRecipe(obj); _addRecipeToItemsMethod.Invoke(null, new object[1] { obj }); HashSet hashSet = CollectRecipeItems(obj); if (affectedItems != null) { affectedItems.UnionWith(hashSet); } else { UpdateKnownForItems(hashSet); } RegisterManagedRecipe(key, obj, source, isSupplemental: true, disableSourceItemWhenRemoved).LastDisplayFingerprint = BuildResultsFingerprint(results); if (enableSourceItem) { SetVneiItemActive(source.name, active: true); } } } private static bool ShouldRewriteDropTableRecipe(ManagedRecipeKey key) { return key.Kind switch { ManagedRecipeKind.Container => ObjectDropManager.HasVneiRelevantContainerOverride(key.PrefabName), ManagedRecipeKind.DropOnDestroyed => ObjectDropManager.HasVneiRelevantDropOnDestroyedOverride(key.PrefabName), ManagedRecipeKind.MineRock => ObjectDropManager.HasVneiRelevantMineRockOverride(key.PrefabName), ManagedRecipeKind.MineRock5 => ObjectDropManager.HasVneiRelevantMineRock5Override(key.PrefabName), ManagedRecipeKind.Fish => ObjectDropManager.HasVneiRelevantFishOverride(key.PrefabName), _ => false, }; } private static bool TryGetDropTableRecipeKey(GameObject from, DropTable dropTable, out ManagedRecipeKey key) { Container val = default(Container); if (from.TryGetComponent(ref val) && val.m_defaultItems == dropTable) { key = new ManagedRecipeKey(((Object)from).name, ManagedRecipeKind.Container); return true; } DropOnDestroyed val2 = default(DropOnDestroyed); if (from.TryGetComponent(ref val2) && val2.m_dropWhenDestroyed == dropTable) { key = new ManagedRecipeKey(((Object)from).name, ManagedRecipeKind.DropOnDestroyed); return true; } MineRock val3 = default(MineRock); if (from.TryGetComponent(ref val3) && val3.m_dropItems == dropTable) { key = new ManagedRecipeKey(((Object)from).name, ManagedRecipeKind.MineRock); return true; } MineRock5 val4 = default(MineRock5); if (from.TryGetComponent(ref val4) && val4.m_dropItems == dropTable) { key = new ManagedRecipeKey(((Object)from).name, ManagedRecipeKind.MineRock5); return true; } Fish val5 = default(Fish); if (from.TryGetComponent(ref val5) && val5.m_extraDrops == dropTable) { key = new ManagedRecipeKey(((Object)from).name, ManagedRecipeKind.Fish); return true; } key = default(ManagedRecipeKey); return false; } private static bool TryGetDropTableForKind(GameObject prefab, ManagedRecipeKind kind, out DropTable? dropTable) { dropTable = null; switch (kind) { case ManagedRecipeKind.Container: { Container val2 = default(Container); if (prefab.TryGetComponent(ref val2)) { dropTable = val2.m_defaultItems; return true; } return false; } case ManagedRecipeKind.DropOnDestroyed: { DropOnDestroyed val5 = default(DropOnDestroyed); if (prefab.TryGetComponent(ref val5)) { dropTable = val5.m_dropWhenDestroyed; return true; } return false; } case ManagedRecipeKind.MineRock: { MineRock val3 = default(MineRock); if (prefab.TryGetComponent(ref val3)) { dropTable = val3.m_dropItems; return true; } return false; } case ManagedRecipeKind.MineRock5: { MineRock5 val4 = default(MineRock5); if (prefab.TryGetComponent(ref val4)) { dropTable = val4.m_dropItems; return true; } return false; } case ManagedRecipeKind.Fish: { Fish val = default(Fish); if (prefab.TryGetComponent(ref val)) { dropTable = val.m_extraDrops; return true; } return false; } default: return false; } } private static GameObject? ResolvePrefab(string prefabName) { ZNetScene instance = ZNetScene.instance; if (instance == null) { return null; } return instance.GetPrefab(prefabName); } private static void RewriteRecipeResults(object recipe, List results) { if (!(_resultsProperty?.GetValue(recipe) is IDictionary dictionary)) { return; } dictionary.Clear(); foreach (VneiRecipeResult result in results) { AddResult(recipe, result.PrefabName, result.GroupMin, result.GroupMax, result.GroupChance, result.Min, result.Max, result.Chance); } MethodInfo? combineGroupAmountsMethod = _combineGroupAmountsMethod; if ((object)combineGroupAmountsMethod != null) { object[] parameters = new IDictionary[1] { dictionary }; combineGroupAmountsMethod.Invoke(recipe, parameters); } } private static void ResetAndRecalculateRecipe(object recipe) { _recipeIsOnBlacklistBackingField?.SetValue(recipe, false); _recipeCalculateIsOnBlacklistMethod?.Invoke(recipe, Array.Empty()); _recipeCalculateWidthMethod?.Invoke(recipe, Array.Empty()); _recipeUpdateKnownMethod?.Invoke(recipe, Array.Empty()); } private static HashSet CollectRecipeItems(object recipe) { HashSet hashSet = new HashSet(); foreach (object item in EnumerateRecipeItems(recipe)) { hashSet.Add(item); } return hashSet; } [IteratorStateMachine(typeof(d__88))] private static IEnumerable EnumerateRecipeItems(object recipe) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__88(-2) { <>3__recipe = recipe }; } [IteratorStateMachine(typeof(d__89))] private static IEnumerable EnumerateItemsFromGroupDictionary(IDictionary? groups) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__89(-2) { <>3__groups = groups }; } private static void DetachRecipeFromItems(object recipe, bool removeFromRecipesList) { if (_itemResultField == null || _itemIngredientField == null) { return; } if (_ingredientsProperty?.GetValue(recipe) is IDictionary dictionary) { foreach (DictionaryEntry item in dictionary) { if (!(item.Value is IEnumerable enumerable)) { continue; } foreach (object item2 in enumerable) { object obj = ((item2 == null) ? null : _partItemField?.GetValue(item2)); if (obj != null) { RemoveRecipeReference(_itemIngredientField.GetValue(obj), recipe); } } } } if (_resultsProperty?.GetValue(recipe) is IDictionary dictionary2) { foreach (DictionaryEntry item3 in dictionary2) { if (!(item3.Value is IEnumerable enumerable2)) { continue; } foreach (object item4 in enumerable2) { object obj2 = ((item4 == null) ? null : _partItemField?.GetValue(item4)); if (obj2 != null) { RemoveRecipeReference(_itemResultField.GetValue(obj2), recipe); } } } } if (_stationsProperty?.GetValue(recipe) is IEnumerable enumerable3) { foreach (object item5 in enumerable3) { object obj3 = ((item5 == null) ? null : _partItemField?.GetValue(item5)); if (obj3 != null) { RemoveRecipeReference(_itemIngredientField.GetValue(obj3), recipe); } } } if (removeFromRecipesList && _recipesProperty?.GetValue(null) is IList list) { list.Remove(recipe); } } private static void UpdateKnownForItems(IEnumerable items) { foreach (object item in items.Distinct()) { _itemUpdateKnownMethod?.Invoke(item, Array.Empty()); } } private static void RemoveRecipeReference(object? collection, object recipe) { collection?.GetType().GetMethod("Remove", new Type[1] { recipe.GetType() })?.Invoke(collection, new object[1] { recipe }); } private static void AddIngredient(object recipe, string prefabName, int groupMin, int groupMax, float groupChance, int min, int max, float chance) { if (!(_addIngredientMethod == null)) { _addIngredientMethod.Invoke(recipe, new object[4] { prefabName, CreateAmount(groupMin, groupMax, groupChance), CreateAmount(min, max, chance), 1 }); } } private static void AddResult(object recipe, string prefabName, int groupMin, int groupMax, float groupChance, int min, int max, float chance) { if (!(_addResultMethod == null)) { _addResultMethod.Invoke(recipe, new object[4] { prefabName, CreateAmount(groupMin, groupMax, groupChance), CreateAmount(min, max, chance), 1 }); } } private static object CreateAmount(int min, int max, float chance) { if (_singleAmountCtor == null || _rangeAmountCtor == null) { throw new InvalidOperationException("VNEI Amount constructors are unavailable."); } if (min == max) { return _singleAmountCtor.Invoke(new object[2] { min, chance }); } return _rangeAmountCtor.Invoke(new object[3] { min, max, chance }); } private static object? TryResolveVneiItem(string prefabName) { return _getItemMethod?.Invoke(null, new object[1] { prefabName }); } private static void SetVneiItemActive(string prefabName, bool active) { object obj = TryResolveVneiItem(prefabName); if (obj != null && _itemIsActiveField != null) { _itemIsActiveField.SetValue(obj, active); } } private static string BuildResultsFingerprint(List results) { if (results == null || results.Count == 0) { return ""; } StringBuilder stringBuilder = new StringBuilder(); foreach (VneiRecipeResult result in results) { stringBuilder.Append(result.PrefabName ?? "").Append('\n').Append(result.GroupMin) .Append('\n') .Append(result.GroupMax) .Append('\n') .Append(result.GroupChance.ToString("R")) .Append('\n') .Append(result.Min) .Append('\n') .Append(result.Max) .Append('\n') .Append(result.Chance.ToString("R")) .Append('\n'); } return stringBuilder.ToString(); } } internal readonly struct VneiRecipeResult { public readonly string PrefabName; public readonly int GroupMin; public readonly int GroupMax; public readonly float GroupChance; public readonly int Min; public readonly int Max; public readonly float Chance; public VneiRecipeResult(string prefabName, int groupMin, int groupMax, float groupChance, int min, int max, float chance) { PrefabName = prefabName; GroupMin = groupMin; GroupMax = groupMax; GroupChance = groupChance; Min = min; Max = max; Chance = chance; } } internal static class VanillaPrefabCatalog { private enum CatalogState { Uninitialized, Loaded, Unavailable } private static readonly object Sync = new object(); private static readonly HashSet PrefabNames = new HashSet(StringComparer.OrdinalIgnoreCase); private static CatalogState _state; internal static bool IsAvailable { get { EnsureLoaded(); return _state == CatalogState.Loaded; } } internal static bool IsVanilla(string prefabName) { EnsureLoaded(); if (_state == CatalogState.Loaded && !string.IsNullOrWhiteSpace(prefabName)) { return PrefabNames.Contains(prefabName); } return false; } private static void EnsureLoaded() { if (_state != 0) { return; } lock (Sync) { if (_state != 0) { return; } string text = Path.Combine(Application.dataPath, "StreamingAssets", "SoftRef", "manifest_extended"); if (!File.Exists(text)) { _state = CatalogState.Unavailable; DropNSpawnPlugin.DropNSpawnLogger.LogWarning((object)("Vanilla prefab manifest was not found at '" + text + "'. Prefab owner grouping will still track bundle-backed modded prefabs, but unmapped prefabs will fall under 'Unknown / Untracked'.")); return; } foreach (string item in File.ReadLines(text)) { int num = item.IndexOf("path in bundle:", StringComparison.OrdinalIgnoreCase); if (num < 0) { continue; } string text2 = item.Substring(num + "path in bundle:".Length).Trim(); if (text2.EndsWith(".prefab", StringComparison.OrdinalIgnoreCase)) { string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(text2); if (!string.IsNullOrWhiteSpace(fileNameWithoutExtension)) { PrefabNames.Add(fileNameWithoutExtension); } } } _state = CatalogState.Loaded; DropNSpawnPlugin.DropNSpawnLogger.LogDebug((object)$"Loaded {PrefabNames.Count} vanilla prefab names from '{text}'."); } } } } namespace ServerSync { [PublicAPI] internal abstract class OwnConfigEntryBase { public object? LocalBaseValue; public bool SynchronizedConfig = true; public abstract ConfigEntryBase BaseConfig { get; } } [PublicAPI] internal class SyncedConfigEntry : OwnConfigEntryBase { public readonly ConfigEntry SourceConfig; public override ConfigEntryBase BaseConfig => (ConfigEntryBase)(object)SourceConfig; public T Value { get { return SourceConfig.Value; } set { SourceConfig.Value = value; } } public SyncedConfigEntry(ConfigEntry sourceConfig) { SourceConfig = sourceConfig; base..ctor(); } public void AssignLocalValue(T value) { if (LocalBaseValue == null) { Value = value; } else { LocalBaseValue = value; } } } internal abstract class CustomSyncedValueBase { public object? LocalBaseValue; public readonly string Identifier; public readonly Type Type; private object? boxedValue; protected bool localIsOwner; public readonly int Priority; public object? BoxedValue { get { return boxedValue; } set { boxedValue = value; this.ValueChanged?.Invoke(); } } public event Action? ValueChanged; protected CustomSyncedValueBase(ConfigSync configSync, string identifier, Type type, int priority) { Priority = priority; Identifier = identifier; Type = type; configSync.AddCustomValue(this); localIsOwner = configSync.IsSourceOfTruth; configSync.SourceOfTruthChanged += delegate(bool truth) { localIsOwner = truth; }; } } [PublicAPI] internal sealed class CustomSyncedValue : CustomSyncedValueBase { public T Value { get { return (T)base.BoxedValue; } set { base.BoxedValue = value; } } public CustomSyncedValue(ConfigSync configSync, string identifier, T value = default(T), int priority = 0) : base(configSync, identifier, typeof(T), priority) { Value = value; } public void AssignLocalValue(T value) { if (localIsOwner) { Value = value; } else { LocalBaseValue = value; } } } internal class ConfigurationManagerAttributes { [UsedImplicitly] public bool? ReadOnly = false; } [PublicAPI] internal class ConfigSync { [HarmonyPatch(typeof(ZRpc), "HandlePackage")] private static class SnatchCurrentlyHandlingRPC { public static ZRpc? currentRpc; [HarmonyPrefix] private static void Prefix(ZRpc __instance) { currentRpc = __instance; } } [HarmonyPatch(typeof(ZNet), "Awake")] internal static class RegisterRPCPatch { [HarmonyPostfix] private static void Postfix(ZNet __instance) { isServer = __instance.IsServer(); foreach (ConfigSync configSync2 in configSyncs) { ZRoutedRpc.instance.Register(configSync2.Name + " ConfigSync", (Action)configSync2.RPC_FromOtherClientConfigSync); if (isServer) { configSync2.InitialSyncDone = true; Debug.Log((object)("Registered '" + configSync2.Name + " ConfigSync' RPC - waiting for incoming connections")); } } if (isServer) { ((MonoBehaviour)__instance).StartCoroutine(WatchAdminListChanges()); } static void SendAdmin(List peers, bool isAdmin) { ZPackage package = ConfigsToPackage(null, null, new PackageEntry[1] { new PackageEntry { section = "Internal", key = "lockexempt", type = typeof(bool), value = isAdmin } }); ConfigSync configSync = configSyncs.First(); if (configSync != null) { ((MonoBehaviour)ZNet.instance).StartCoroutine(configSync.sendZPackage(peers, package)); } } static IEnumerator WatchAdminListChanges() { MethodInfo listContainsId = AccessTools.DeclaredMethod(typeof(ZNet), "ListContainsId", (Type[])null, (Type[])null); SyncedList adminList = (SyncedList)AccessTools.DeclaredField(typeof(ZNet), "m_adminList").GetValue(ZNet.instance); List CurrentList = new List(adminList.GetList()); while (true) { yield return (object)new WaitForSeconds(30f); if (!adminList.GetList().SequenceEqual(CurrentList)) { CurrentList = new List(adminList.GetList()); List adminPeer = ZNet.instance.GetPeers().Where(delegate(ZNetPeer p) { string hostName = p.m_rpc.GetSocket().GetHostName(); return ((object)listContainsId == null) ? adminList.Contains(hostName) : ((bool)listContainsId.Invoke(ZNet.instance, new object[2] { adminList, hostName })); }).ToList(); List nonAdminPeer = ZNet.instance.GetPeers().Except(adminPeer).ToList(); SendAdmin(nonAdminPeer, isAdmin: false); SendAdmin(adminPeer, isAdmin: true); } } } } } [HarmonyPatch(typeof(ZNet), "OnNewConnection")] private static class RegisterClientRPCPatch { [HarmonyPostfix] private static void Postfix(ZNet __instance, ZNetPeer peer) { if (__instance.IsServer()) { return; } foreach (ConfigSync configSync in configSyncs) { peer.m_rpc.Register(configSync.Name + " ConfigSync", (Action)configSync.RPC_FromServerConfigSync); } } } private class ParsedConfigs { public readonly Dictionary configValues = new Dictionary(); public readonly Dictionary customValues = new Dictionary(); } [HarmonyPatch(typeof(ZNet), "Shutdown")] private class ResetConfigsOnShutdown { [HarmonyPostfix] private static void Postfix() { ProcessingServerUpdate = true; foreach (ConfigSync configSync in configSyncs) { configSync.resetConfigsFromServer(); configSync.IsSourceOfTruth = true; configSync.InitialSyncDone = false; } ProcessingServerUpdate = false; } } [HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")] private class SendConfigsAfterLogin { private class BufferingSocket : ZPlayFabSocket, ISocket { public volatile bool finished = false; public volatile int versionMatchQueued = -1; public readonly List Package = new List(); public readonly ISocket Original; public BufferingSocket(ISocket original) { Original = original; ((ZPlayFabSocket)this)..ctor(); } public bool IsConnected() { return Original.IsConnected(); } public ZPackage Recv() { return Original.Recv(); } public int GetSendQueueSize() { return Original.GetSendQueueSize(); } public int GetCurrentSendRate() { return Original.GetCurrentSendRate(); } public bool IsHost() { return Original.IsHost(); } public void Dispose() { Original.Dispose(); } public bool GotNewData() { return Original.GotNewData(); } public void Close() { Original.Close(); } public string GetEndPointString() { return Original.GetEndPointString(); } public void GetAndResetStats(out int totalSent, out int totalRecv) { Original.GetAndResetStats(ref totalSent, ref totalRecv); } public void GetConnectionQuality(out float localQuality, out float remoteQuality, out int ping, out float outByteSec, out float inByteSec) { Original.GetConnectionQuality(ref localQuality, ref remoteQuality, ref ping, ref outByteSec, ref inByteSec); } public ISocket Accept() { return Original.Accept(); } public int GetHostPort() { return Original.GetHostPort(); } public bool Flush() { return Original.Flush(); } public string GetHostName() { return Original.GetHostName(); } public void VersionMatch() { if (finished) { Original.VersionMatch(); } else { versionMatchQueued = Package.Count; } } public void Send(ZPackage pkg) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected O, but got Unknown int pos = pkg.GetPos(); pkg.SetPos(0); int num = pkg.ReadInt(); if ((num == StringExtensionMethods.GetStableHashCode("PeerInfo") || num == StringExtensionMethods.GetStableHashCode("RoutedRPC") || num == StringExtensionMethods.GetStableHashCode("ZDOData")) && !finished) { ZPackage val = new ZPackage(pkg.GetArray()); val.SetPos(pos); Package.Add(val); } else { pkg.SetPos(pos); Original.Send(pkg); } } } [HarmonyPriority(800)] [HarmonyPrefix] private static void Prefix(ref Dictionary? __state, ZNet __instance, ZRpc rpc) { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Invalid comparison between Unknown and I4 if (!__instance.IsServer()) { return; } BufferingSocket bufferingSocket = new BufferingSocket(rpc.GetSocket()); AccessTools.DeclaredField(typeof(ZRpc), "m_socket").SetValue(rpc, bufferingSocket); object? obj = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance, new object[1] { rpc }); ZNetPeer val = (ZNetPeer)((obj is ZNetPeer) ? obj : null); if (val != null && (int)ZNet.m_onlineBackend > 0) { FieldInfo fieldInfo = AccessTools.DeclaredField(typeof(ZNetPeer), "m_socket"); object? value = fieldInfo.GetValue(val); ZPlayFabSocket val2 = (ZPlayFabSocket)((value is ZPlayFabSocket) ? value : null); if (val2 != null) { typeof(ZPlayFabSocket).GetField("m_remotePlayerId").SetValue(bufferingSocket, val2.m_remotePlayerId); } fieldInfo.SetValue(val, bufferingSocket); } if (__state == null) { __state = new Dictionary(); } __state[Assembly.GetExecutingAssembly()] = bufferingSocket; } [HarmonyPostfix] private static void Postfix(Dictionary __state, ZNet __instance, ZRpc rpc) { ZRpc rpc2 = rpc; ZNet __instance2 = __instance; Dictionary __state2 = __state; ZNetPeer peer; if (__instance2.IsServer()) { object obj = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance2, new object[1] { rpc2 }); peer = (ZNetPeer)((obj is ZNetPeer) ? obj : null); if (peer == null) { SendBufferedData(); } else { ((MonoBehaviour)__instance2).StartCoroutine(sendAsync()); } } void SendBufferedData() { if (rpc2.GetSocket() is BufferingSocket bufferingSocket) { AccessTools.DeclaredField(typeof(ZRpc), "m_socket").SetValue(rpc2, bufferingSocket.Original); object? obj2 = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance2, new object[1] { rpc2 }); ZNetPeer val = (ZNetPeer)((obj2 is ZNetPeer) ? obj2 : null); if (val != null) { AccessTools.DeclaredField(typeof(ZNetPeer), "m_socket").SetValue(val, bufferingSocket.Original); } } BufferingSocket bufferingSocket2 = __state2[Assembly.GetExecutingAssembly()]; bufferingSocket2.finished = true; for (int i = 0; i < bufferingSocket2.Package.Count; i++) { if (i == bufferingSocket2.versionMatchQueued) { bufferingSocket2.Original.VersionMatch(); } bufferingSocket2.Original.Send(bufferingSocket2.Package[i]); } if (bufferingSocket2.Package.Count == bufferingSocket2.versionMatchQueued) { bufferingSocket2.Original.VersionMatch(); } } IEnumerator sendAsync() { foreach (ConfigSync configSync in configSyncs) { List entries = new List(); if (configSync.CurrentVersion != null) { entries.Add(new PackageEntry { section = "Internal", key = "serverversion", type = typeof(string), value = configSync.CurrentVersion }); } MethodInfo listContainsId = AccessTools.DeclaredMethod(typeof(ZNet), "ListContainsId", (Type[])null, (Type[])null); SyncedList adminList = (SyncedList)AccessTools.DeclaredField(typeof(ZNet), "m_adminList").GetValue(ZNet.instance); entries.Add(new PackageEntry { section = "Internal", key = "lockexempt", type = typeof(bool), value = (((object)listContainsId == null) ? ((object)adminList.Contains(rpc2.GetSocket().GetHostName())) : listContainsId.Invoke(ZNet.instance, new object[2] { adminList, rpc2.GetSocket().GetHostName() })) }); ZPackage package = ConfigsToPackage(configSync.allConfigs.Select((OwnConfigEntryBase c) => c.BaseConfig), configSync.allCustomValues, entries, partial: false); yield return ((MonoBehaviour)__instance2).StartCoroutine(configSync.sendZPackage(new List { peer }, package)); } SendBufferedData(); } } } private class PackageEntry { public string section = null; public string key = null; public Type type = null; public object? value; } [HarmonyPatch(typeof(ConfigEntryBase), "GetSerializedValue")] private static class PreventSavingServerInfo { [HarmonyPrefix] private static bool Prefix(ConfigEntryBase __instance, ref string __result) { OwnConfigEntryBase ownConfigEntryBase = configData(__instance); if (ownConfigEntryBase == null || isWritableConfig(ownConfigEntryBase)) { return true; } __result = TomlTypeConverter.ConvertToString(ownConfigEntryBase.LocalBaseValue, __instance.SettingType); return false; } } [HarmonyPatch(typeof(ConfigEntryBase), "SetSerializedValue")] private static class PreventConfigRereadChangingValues { [HarmonyPrefix] private static bool Prefix(ConfigEntryBase __instance, string value) { OwnConfigEntryBase ownConfigEntryBase = configData(__instance); if (ownConfigEntryBase == null || ownConfigEntryBase.LocalBaseValue == null) { return true; } try { ownConfigEntryBase.LocalBaseValue = TomlTypeConverter.ConvertToValue(value, __instance.SettingType); } catch (Exception ex) { Debug.LogWarning((object)$"Config value of setting \"{__instance.Definition}\" could not be parsed and will be ignored. Reason: {ex.Message}; Value: {value}"); } return false; } } private class InvalidDeserializationTypeException : Exception { public string expected = null; public string received = null; public string field = ""; } public static bool ProcessingServerUpdate; public readonly string Name; public string? DisplayName; public string? CurrentVersion; public string? MinimumRequiredVersion; public bool ModRequired = false; private bool? forceConfigLocking; private bool isSourceOfTruth = true; private static readonly HashSet configSyncs; private readonly HashSet allConfigs = new HashSet(); private HashSet allCustomValues = new HashSet(); private static bool isServer; private static bool lockExempt; private OwnConfigEntryBase? lockedConfig = null; private const byte PARTIAL_CONFIGS = 1; private const byte FRAGMENTED_CONFIG = 2; private const byte COMPRESSED_CONFIG = 4; private readonly Dictionary> configValueCache = new Dictionary>(); private readonly List> cacheExpirations = new List>(); private static long packageCounter; public bool IsLocked { get { bool? flag = forceConfigLocking; bool num; if (!flag.HasValue) { if (lockedConfig == null) { goto IL_0052; } num = ((IConvertible)lockedConfig.BaseConfig.BoxedValue).ToInt32(CultureInfo.InvariantCulture) != 0; } else { num = flag.GetValueOrDefault(); } if (!num) { goto IL_0052; } int result = ((!lockExempt) ? 1 : 0); goto IL_0053; IL_0053: return (byte)result != 0; IL_0052: result = 0; goto IL_0053; } set { forceConfigLocking = value; } } public bool IsAdmin => lockExempt || isSourceOfTruth; public bool IsSourceOfTruth { get { return isSourceOfTruth; } private set { if (value != isSourceOfTruth) { isSourceOfTruth = value; this.SourceOfTruthChanged?.Invoke(value); } } } public bool InitialSyncDone { get; private set; } = false; public event Action? SourceOfTruthChanged; private event Action? lockedConfigChanged; static ConfigSync() { ProcessingServerUpdate = false; configSyncs = new HashSet(); lockExempt = false; packageCounter = 0L; RuntimeHelpers.RunClassConstructor(typeof(VersionCheck).TypeHandle); } public ConfigSync(string name) { Name = name; configSyncs.Add(this); new VersionCheck(this); } public SyncedConfigEntry AddConfigEntry(ConfigEntry configEntry) { ConfigEntry configEntry2 = configEntry; OwnConfigEntryBase ownConfigEntryBase = configData((ConfigEntryBase)(object)configEntry2); SyncedConfigEntry syncedEntry = ownConfigEntryBase as SyncedConfigEntry; if (syncedEntry == null) { syncedEntry = new SyncedConfigEntry(configEntry2); AccessTools.DeclaredField(typeof(ConfigDescription), "k__BackingField").SetValue(((ConfigEntryBase)configEntry2).Description, new object[1] { new ConfigurationManagerAttributes() }.Concat(((ConfigEntryBase)configEntry2).Description.Tags ?? Array.Empty()).Concat(new SyncedConfigEntry[1] { syncedEntry }).ToArray()); configEntry2.SettingChanged += delegate { if (!ProcessingServerUpdate && syncedEntry.SynchronizedConfig) { Broadcast(ZRoutedRpc.Everybody, (ConfigEntryBase)configEntry2); } }; allConfigs.Add(syncedEntry); } return syncedEntry; } public SyncedConfigEntry AddLockingConfigEntry(ConfigEntry lockingConfig) where T : IConvertible { if (lockedConfig != null) { throw new Exception("Cannot initialize locking ConfigEntry twice"); } lockedConfig = AddConfigEntry(lockingConfig); lockingConfig.SettingChanged += delegate { this.lockedConfigChanged?.Invoke(); }; return (SyncedConfigEntry)lockedConfig; } internal void AddCustomValue(CustomSyncedValueBase customValue) { CustomSyncedValueBase customValue2 = customValue; if (allCustomValues.Select((CustomSyncedValueBase v) => v.Identifier).Concat(new string[1] { "serverversion" }).Contains(customValue2.Identifier)) { throw new Exception("Cannot have multiple settings with the same name or with a reserved name (serverversion)"); } allCustomValues.Add(customValue2); allCustomValues = new HashSet(allCustomValues.OrderByDescending((CustomSyncedValueBase v) => v.Priority)); customValue2.ValueChanged += delegate { if (!ProcessingServerUpdate) { Broadcast(ZRoutedRpc.Everybody, customValue2); } }; } private void RPC_FromServerConfigSync(ZRpc rpc, ZPackage package) { lockedConfigChanged += serverLockedSettingChanged; IsSourceOfTruth = false; if (HandleConfigSyncRPC(0L, package, clientUpdate: false)) { InitialSyncDone = true; } } private void RPC_FromOtherClientConfigSync(long sender, ZPackage package) { HandleConfigSyncRPC(sender, package, clientUpdate: true); } private bool HandleConfigSyncRPC(long sender, ZPackage package, bool clientUpdate) { //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected O, but got Unknown //IL_0250: Unknown result type (might be due to invalid IL or missing references) //IL_0257: Expected O, but got Unknown //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Expected O, but got Unknown try { if (isServer && IsLocked) { ZRpc? currentRpc = SnatchCurrentlyHandlingRPC.currentRpc; object obj; if (currentRpc == null) { obj = null; } else { ISocket socket = currentRpc.GetSocket(); obj = ((socket != null) ? socket.GetHostName() : null); } string text = (string)obj; if (text != null) { MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(ZNet), "ListContainsId", (Type[])null, (Type[])null); SyncedList val = (SyncedList)AccessTools.DeclaredField(typeof(ZNet), "m_adminList").GetValue(ZNet.instance); if (!(((object)methodInfo == null) ? val.Contains(text) : ((bool)methodInfo.Invoke(ZNet.instance, new object[2] { val, text })))) { return false; } } } cacheExpirations.RemoveAll(delegate(KeyValuePair kv) { if (kv.Key < DateTimeOffset.Now.Ticks) { configValueCache.Remove(kv.Value); return true; } return false; }); byte b = package.ReadByte(); if ((b & 2u) != 0) { long num = package.ReadLong(); string text2 = sender.ToString() + num; if (!configValueCache.TryGetValue(text2, out SortedDictionary value)) { value = new SortedDictionary(); configValueCache[text2] = value; cacheExpirations.Add(new KeyValuePair(DateTimeOffset.Now.AddSeconds(60.0).Ticks, text2)); } int key = package.ReadInt(); int num2 = package.ReadInt(); value.Add(key, package.ReadByteArray()); if (value.Count < num2) { return false; } configValueCache.Remove(text2); package = new ZPackage(value.Values.SelectMany((byte[] a) => a).ToArray()); b = package.ReadByte(); } ProcessingServerUpdate = true; if ((b & 4u) != 0) { byte[] buffer = package.ReadByteArray(); MemoryStream stream = new MemoryStream(buffer); MemoryStream memoryStream = new MemoryStream(); using (DeflateStream deflateStream = new DeflateStream(stream, CompressionMode.Decompress)) { deflateStream.CopyTo(memoryStream); } package = new ZPackage(memoryStream.ToArray()); b = package.ReadByte(); } if ((b & 1) == 0) { resetConfigsFromServer(); } ParsedConfigs parsedConfigs = ReadConfigsFromPackage(package); ConfigFile val2 = null; bool saveOnConfigSet = false; foreach (KeyValuePair configValue in parsedConfigs.configValues) { if (!isServer && configValue.Key.LocalBaseValue == null) { configValue.Key.LocalBaseValue = configValue.Key.BaseConfig.BoxedValue; } if (val2 == null) { val2 = configValue.Key.BaseConfig.ConfigFile; saveOnConfigSet = val2.SaveOnConfigSet; val2.SaveOnConfigSet = false; } configValue.Key.BaseConfig.BoxedValue = configValue.Value; } if (val2 != null) { val2.SaveOnConfigSet = saveOnConfigSet; val2.Save(); } foreach (KeyValuePair customValue in parsedConfigs.customValues) { if (!isServer) { CustomSyncedValueBase key2 = customValue.Key; if (key2.LocalBaseValue == null) { key2.LocalBaseValue = customValue.Key.BoxedValue; } } customValue.Key.BoxedValue = customValue.Value; } Debug.Log((object)string.Format("Received {0} configs and {1} custom values from {2} for mod {3}", parsedConfigs.configValues.Count, parsedConfigs.customValues.Count, (isServer || clientUpdate) ? $"client {sender}" : "the server", DisplayName ?? Name)); if (!isServer) { serverLockedSettingChanged(); } return true; } finally { ProcessingServerUpdate = false; } } private ParsedConfigs ReadConfigsFromPackage(ZPackage package) { ParsedConfigs parsedConfigs = new ParsedConfigs(); Dictionary dictionary = allConfigs.Where((OwnConfigEntryBase c) => c.SynchronizedConfig).ToDictionary((OwnConfigEntryBase c) => c.BaseConfig.Definition.Section + "_" + c.BaseConfig.Definition.Key, (OwnConfigEntryBase c) => c); Dictionary dictionary2 = allCustomValues.ToDictionary((CustomSyncedValueBase c) => c.Identifier, (CustomSyncedValueBase c) => c); int num = package.ReadInt(); for (int i = 0; i < num; i++) { string text = package.ReadString(); string text2 = package.ReadString(); string text3 = package.ReadString(); Type type = Type.GetType(text3); if (text3 == "" || type != null) { object obj; try { obj = ((text3 == "") ? null : ReadValueWithTypeFromZPackage(package, type)); } catch (InvalidDeserializationTypeException ex) { Debug.LogWarning((object)("Got unexpected struct internal type " + ex.received + " for field " + ex.field + " struct " + text3 + " for " + text2 + " in section " + text + " for mod " + (DisplayName ?? Name) + ", expecting " + ex.expected)); continue; } OwnConfigEntryBase value2; if (text == "Internal") { CustomSyncedValueBase value; if (text2 == "serverversion") { if (obj?.ToString() != CurrentVersion) { Debug.LogWarning((object)("Received server version is not equal: server version = " + (obj?.ToString() ?? "null") + "; local version = " + (CurrentVersion ?? "unknown"))); } } else if (text2 == "lockexempt") { if (obj is bool flag) { lockExempt = flag; } } else if (dictionary2.TryGetValue(text2, out value)) { if ((text3 == "" && (!value.Type.IsValueType || Nullable.GetUnderlyingType(value.Type) != null)) || GetZPackageTypeString(value.Type) == text3) { parsedConfigs.customValues[value] = obj; continue; } Debug.LogWarning((object)("Got unexpected type " + text3 + " for internal value " + text2 + " for mod " + (DisplayName ?? Name) + ", expecting " + value.Type.AssemblyQualifiedName)); } } else if (dictionary.TryGetValue(text + "_" + text2, out value2)) { Type type2 = configType(value2.BaseConfig); if ((text3 == "" && (!type2.IsValueType || Nullable.GetUnderlyingType(type2) != null)) || GetZPackageTypeString(type2) == text3) { parsedConfigs.configValues[value2] = obj; continue; } Debug.LogWarning((object)("Got unexpected type " + text3 + " for " + text2 + " in section " + text + " for mod " + (DisplayName ?? Name) + ", expecting " + type2.AssemblyQualifiedName)); } else { Debug.LogWarning((object)("Received unknown config entry " + text2 + " in section " + text + " for mod " + (DisplayName ?? Name) + ". This may happen if client and server versions of the mod do not match.")); } continue; } Debug.LogWarning((object)("Got invalid type " + text3 + ", abort reading of received configs")); return new ParsedConfigs(); } return parsedConfigs; } private static bool isWritableConfig(OwnConfigEntryBase config) { OwnConfigEntryBase config2 = config; ConfigSync configSync = configSyncs.FirstOrDefault((ConfigSync cs) => cs.allConfigs.Contains(config2)); if (configSync == null) { return true; } return configSync.IsSourceOfTruth || !config2.SynchronizedConfig || config2.LocalBaseValue == null || (!configSync.IsLocked && (config2 != configSync.lockedConfig || lockExempt)); } private void serverLockedSettingChanged() { foreach (OwnConfigEntryBase allConfig in allConfigs) { configAttribute(allConfig.BaseConfig).ReadOnly = !isWritableConfig(allConfig); } } private void resetConfigsFromServer() { ConfigFile val = null; bool saveOnConfigSet = false; foreach (OwnConfigEntryBase item in allConfigs.Where((OwnConfigEntryBase config) => config.LocalBaseValue != null)) { if (val == null) { val = item.BaseConfig.ConfigFile; saveOnConfigSet = val.SaveOnConfigSet; val.SaveOnConfigSet = false; } item.BaseConfig.BoxedValue = item.LocalBaseValue; item.LocalBaseValue = null; } if (val != null) { val.SaveOnConfigSet = saveOnConfigSet; } foreach (CustomSyncedValueBase item2 in allCustomValues.Where((CustomSyncedValueBase config) => config.LocalBaseValue != null)) { item2.BoxedValue = item2.LocalBaseValue; item2.LocalBaseValue = null; } lockedConfigChanged -= serverLockedSettingChanged; serverLockedSettingChanged(); } private IEnumerator distributeConfigToPeers(ZNetPeer peer, ZPackage package) { ZNetPeer peer2 = peer; ZRoutedRpc rpc = ZRoutedRpc.instance; if (rpc == null) { yield break; } byte[] data = package.GetArray(); if (data != null && data.LongLength > 250000) { int fragments = (int)(1 + (data.LongLength - 1) / 250000); long packageIdentifier = ++packageCounter; int fragment = 0; while (fragment < fragments) { foreach (bool item in waitForQueue()) { yield return item; } if (peer2.m_socket.IsConnected()) { ZPackage fragmentedPackage = new ZPackage(); fragmentedPackage.Write((byte)2); fragmentedPackage.Write(packageIdentifier); fragmentedPackage.Write(fragment); fragmentedPackage.Write(fragments); fragmentedPackage.Write(data.Skip(250000 * fragment).Take(250000).ToArray()); SendPackage(fragmentedPackage); if (fragment != fragments - 1) { yield return true; } int num = fragment + 1; fragment = num; continue; } break; } yield break; } foreach (bool item2 in waitForQueue()) { yield return item2; } SendPackage(package); void SendPackage(ZPackage pkg) { string text = Name + " ConfigSync"; if (isServer) { peer2.m_rpc.Invoke(text, new object[1] { pkg }); } else { rpc.InvokeRoutedRPC(peer2.m_server ? 0 : peer2.m_uid, text, new object[1] { pkg }); } } IEnumerable waitForQueue() { float timeout = Time.time + 30f; while (peer2.m_socket.GetSendQueueSize() > 20000) { if (Time.time > timeout) { Debug.Log((object)$"Disconnecting {peer2.m_uid} after 30 seconds config sending timeout"); peer2.m_rpc.Invoke("Error", new object[1] { (object)(ConnectionStatus)5 }); ZNet.instance.Disconnect(peer2); break; } yield return false; } } } private IEnumerator sendZPackage(long target, ZPackage package) { if (!Object.op_Implicit((Object)(object)ZNet.instance)) { return Enumerable.Empty().GetEnumerator(); } List list = (List)AccessTools.DeclaredField(typeof(ZRoutedRpc), "m_peers").GetValue(ZRoutedRpc.instance); if (target != ZRoutedRpc.Everybody) { list = list.Where((ZNetPeer p) => p.m_uid == target).ToList(); } return sendZPackage(list, package); } private IEnumerator sendZPackage(List peers, ZPackage package) { ZPackage package2 = package; if (!Object.op_Implicit((Object)(object)ZNet.instance)) { yield break; } byte[] rawData = package2.GetArray(); if (rawData != null && rawData.LongLength > 10000) { ZPackage compressedPackage = new ZPackage(); compressedPackage.Write((byte)4); MemoryStream output = new MemoryStream(); using (DeflateStream deflateStream = new DeflateStream(output, CompressionLevel.Optimal)) { deflateStream.Write(rawData, 0, rawData.Length); } compressedPackage.Write(output.ToArray()); package2 = compressedPackage; } List> writers = (from peer in peers where peer.IsReady() select peer into p select distributeConfigToPeers(p, package2)).ToList(); writers.RemoveAll((IEnumerator writer) => !writer.MoveNext()); while (writers.Count > 0) { yield return null; writers.RemoveAll((IEnumerator writer) => !writer.MoveNext()); } } private void Broadcast(long target, params ConfigEntryBase[] configs) { if (!IsLocked || isServer) { ZPackage package = ConfigsToPackage(configs); ZNet instance = ZNet.instance; if (instance != null) { ((MonoBehaviour)instance).StartCoroutine(sendZPackage(target, package)); } } } private void Broadcast(long target, params CustomSyncedValueBase[] customValues) { if (!IsLocked || isServer) { ZPackage package = ConfigsToPackage(null, customValues); ZNet instance = ZNet.instance; if (instance != null) { ((MonoBehaviour)instance).StartCoroutine(sendZPackage(target, package)); } } } private static OwnConfigEntryBase? configData(ConfigEntryBase config) { return config.Description.Tags?.OfType().SingleOrDefault(); } public static SyncedConfigEntry? ConfigData(ConfigEntry config) { return ((ConfigEntryBase)config).Description.Tags?.OfType>().SingleOrDefault(); } private static T configAttribute(ConfigEntryBase config) { return config.Description.Tags.OfType().First(); } private static Type configType(ConfigEntryBase config) { return configType(config.SettingType); } private static Type configType(Type type) { return type.IsEnum ? Enum.GetUnderlyingType(type) : type; } private static ZPackage ConfigsToPackage(IEnumerable? configs = null, IEnumerable? customValues = null, IEnumerable? packageEntries = null, bool partial = true) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown List list = configs?.Where((ConfigEntryBase config) => configData(config).SynchronizedConfig).ToList() ?? new List(); List list2 = customValues?.ToList() ?? new List(); ZPackage val = new ZPackage(); val.Write((byte)(partial ? 1 : 0)); val.Write(list.Count + list2.Count + (packageEntries?.Count() ?? 0)); foreach (PackageEntry item in packageEntries ?? Array.Empty()) { AddEntryToPackage(val, item); } foreach (CustomSyncedValueBase item2 in list2) { AddEntryToPackage(val, new PackageEntry { section = "Internal", key = item2.Identifier, type = item2.Type, value = item2.BoxedValue }); } foreach (ConfigEntryBase item3 in list) { AddEntryToPackage(val, new PackageEntry { section = item3.Definition.Section, key = item3.Definition.Key, type = configType(item3), value = item3.BoxedValue }); } return val; } private static void AddEntryToPackage(ZPackage package, PackageEntry entry) { package.Write(entry.section); package.Write(entry.key); package.Write((entry.value == null) ? "" : GetZPackageTypeString(entry.type)); AddValueToZPackage(package, entry.value); } private static string GetZPackageTypeString(Type type) { return type.AssemblyQualifiedName; } private static void AddValueToZPackage(ZPackage package, object? value) { Type type = value?.GetType(); if (value is Enum) { value = ((IConvertible)value).ToType(Enum.GetUnderlyingType(value.GetType()), CultureInfo.InvariantCulture); } else { if (value is ICollection collection) { package.Write(collection.Count); { foreach (object item in collection) { AddValueToZPackage(package, item); } return; } } if ((object)type != null && type.IsValueType && !type.IsPrimitive) { FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); package.Write(fields.Length); FieldInfo[] array = fields; foreach (FieldInfo fieldInfo in array) { package.Write(GetZPackageTypeString(fieldInfo.FieldType)); AddValueToZPackage(package, fieldInfo.GetValue(value)); } return; } } ZRpc.Serialize(new object[1] { value }, ref package); } private static object ReadValueWithTypeFromZPackage(ZPackage package, Type type) { if ((object)type != null && type.IsValueType && !type.IsPrimitive && !type.IsEnum) { FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); int num = package.ReadInt(); if (num != fields.Length) { throw new InvalidDeserializationTypeException { received = $"(field count: {num})", expected = $"(field count: {fields.Length})" }; } object uninitializedObject = FormatterServices.GetUninitializedObject(type); FieldInfo[] array = fields; foreach (FieldInfo fieldInfo in array) { string text = package.ReadString(); if (text != GetZPackageTypeString(fieldInfo.FieldType)) { throw new InvalidDeserializationTypeException { received = text, expected = GetZPackageTypeString(fieldInfo.FieldType), field = fieldInfo.Name }; } fieldInfo.SetValue(uninitializedObject, ReadValueWithTypeFromZPackage(package, fieldInfo.FieldType)); } return uninitializedObject; } if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<, >)) { int num2 = package.ReadInt(); IDictionary dictionary = (IDictionary)Activator.CreateInstance(type); Type type2 = typeof(KeyValuePair<, >).MakeGenericType(type.GenericTypeArguments); FieldInfo field = type2.GetField("key", BindingFlags.Instance | BindingFlags.NonPublic); FieldInfo field2 = type2.GetField("value", BindingFlags.Instance | BindingFlags.NonPublic); for (int j = 0; j < num2; j++) { object obj = ReadValueWithTypeFromZPackage(package, type2); dictionary.Add(field.GetValue(obj), field2.GetValue(obj)); } return dictionary; } if (type != typeof(List) && type.IsGenericType) { Type type3 = typeof(ICollection<>).MakeGenericType(type.GenericTypeArguments[0]); if ((object)type3 != null && type3.IsAssignableFrom(type)) { int num3 = package.ReadInt(); object obj2 = Activator.CreateInstance(type); MethodInfo method = type3.GetMethod("Add"); for (int k = 0; k < num3; k++) { method.Invoke(obj2, new object[1] { ReadValueWithTypeFromZPackage(package, type.GenericTypeArguments[0]) }); } return obj2; } } ParameterInfo parameterInfo = (ParameterInfo)FormatterServices.GetUninitializedObject(typeof(ParameterInfo)); AccessTools.DeclaredField(typeof(ParameterInfo), "ClassImpl").SetValue(parameterInfo, type); List source = new List(); ZRpc.Deserialize(new ParameterInfo[2] { null, parameterInfo }, package, ref source); return source.First(); } } [PublicAPI] [HarmonyPatch] internal class VersionCheck { private static readonly HashSet versionChecks; private static readonly Dictionary notProcessedNames; public string Name; private string? displayName; private string? currentVersion; private string? minimumRequiredVersion; public bool ModRequired = true; private string? ReceivedCurrentVersion; private string? ReceivedMinimumRequiredVersion; private readonly List ValidatedClients = new List(); private ConfigSync? ConfigSync; public string DisplayName { get { return displayName ?? Name; } set { displayName = value; } } public string CurrentVersion { get { return currentVersion ?? "0.0.0"; } set { currentVersion = value; } } public string MinimumRequiredVersion { get { return minimumRequiredVersion ?? (ModRequired ? CurrentVersion : "0.0.0"); } set { minimumRequiredVersion = value; } } private static void PatchServerSync() { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown Patches patchInfo = PatchProcessor.GetPatchInfo((MethodBase)AccessTools.DeclaredMethod(typeof(ZNet), "Awake", (Type[])null, (Type[])null)); if (patchInfo != null && patchInfo.Postfixes.Count((Patch p) => p.PatchMethod.DeclaringType == typeof(ConfigSync.RegisterRPCPatch)) > 0) { return; } Harmony val = new Harmony("org.bepinex.helpers.ServerSync"); foreach (Type item in from t in typeof(ConfigSync).GetNestedTypes(BindingFlags.NonPublic).Concat(new Type[1] { typeof(VersionCheck) }) where t.IsClass select t) { val.PatchAll(item); } } static VersionCheck() { versionChecks = new HashSet(); notProcessedNames = new Dictionary(); typeof(ThreadingHelper).GetMethod("StartSyncInvoke").Invoke(ThreadingHelper.Instance, new object[1] { new Action(PatchServerSync) }); } public VersionCheck(string name) { Name = name; ModRequired = true; versionChecks.Add(this); } public VersionCheck(ConfigSync configSync) { ConfigSync = configSync; Name = ConfigSync.Name; versionChecks.Add(this); } public void Initialize() { ReceivedCurrentVersion = null; ReceivedMinimumRequiredVersion = null; if (ConfigSync != null) { Name = ConfigSync.Name; DisplayName = ConfigSync.DisplayName; CurrentVersion = ConfigSync.CurrentVersion; MinimumRequiredVersion = ConfigSync.MinimumRequiredVersion; ModRequired = ConfigSync.ModRequired; } } private bool IsVersionOk() { if (ReceivedMinimumRequiredVersion == null || ReceivedCurrentVersion == null) { return !ModRequired; } bool flag = new System.Version(CurrentVersion) >= new System.Version(ReceivedMinimumRequiredVersion); bool flag2 = new System.Version(ReceivedCurrentVersion) >= new System.Version(MinimumRequiredVersion); return flag && flag2; } private string ErrorClient() { if (ReceivedMinimumRequiredVersion == null) { return DisplayName + " is not installed on the server."; } return (new System.Version(CurrentVersion) >= new System.Version(ReceivedMinimumRequiredVersion)) ? (DisplayName + " may not be higher than version " + ReceivedCurrentVersion + ". You have version " + CurrentVersion + ".") : (DisplayName + " needs to be at least version " + ReceivedMinimumRequiredVersion + ". You have version " + CurrentVersion + "."); } private string ErrorServer(ZRpc rpc) { return "Disconnect: The client (" + rpc.GetSocket().GetHostName() + ") doesn't have the correct " + DisplayName + " version " + MinimumRequiredVersion; } private string Error(ZRpc? rpc = null) { return (rpc == null) ? ErrorClient() : ErrorServer(rpc); } private static VersionCheck[] GetFailedClient() { return versionChecks.Where((VersionCheck check) => !check.IsVersionOk()).ToArray(); } private static VersionCheck[] GetFailedServer(ZRpc rpc) { ZRpc rpc2 = rpc; return versionChecks.Where((VersionCheck check) => check.ModRequired && !check.ValidatedClients.Contains(rpc2)).ToArray(); } private static void Logout() { Game.instance.Logout(true, true); AccessTools.DeclaredField(typeof(ZNet), "m_connectionStatus").SetValue(null, (object)(ConnectionStatus)3); } private static void DisconnectClient(ZRpc rpc) { rpc.Invoke("Error", new object[1] { 3 }); } private static void CheckVersion(ZRpc rpc, ZPackage pkg) { CheckVersion(rpc, pkg, null); } private static void CheckVersion(ZRpc rpc, ZPackage pkg, Action? original) { string text = pkg.ReadString(); string text2 = pkg.ReadString(); string text3 = pkg.ReadString(); bool flag = false; foreach (VersionCheck versionCheck in versionChecks) { if (!(text != versionCheck.Name)) { Debug.Log((object)("Received " + versionCheck.DisplayName + " version " + text3 + " and minimum version " + text2 + " from the " + (ZNet.instance.IsServer() ? "client" : "server") + ".")); versionCheck.ReceivedMinimumRequiredVersion = text2; versionCheck.ReceivedCurrentVersion = text3; if (ZNet.instance.IsServer() && versionCheck.IsVersionOk()) { versionCheck.ValidatedClients.Add(rpc); } flag = true; } } if (flag) { return; } pkg.SetPos(0); if (original != null) { original(rpc, pkg); if (pkg.GetPos() == 0) { notProcessedNames.Add(text, text3); } } } [HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")] [HarmonyPrefix] private static bool RPC_PeerInfo(ZRpc rpc, ZNet __instance) { VersionCheck[] array = (__instance.IsServer() ? GetFailedServer(rpc) : GetFailedClient()); if (array.Length == 0) { return true; } VersionCheck[] array2 = array; foreach (VersionCheck versionCheck in array2) { Debug.LogWarning((object)versionCheck.Error(rpc)); } if (__instance.IsServer()) { DisconnectClient(rpc); } else { Logout(); } return false; } [HarmonyPatch(typeof(ZNet), "OnNewConnection")] [HarmonyPrefix] private static void RegisterAndCheckVersion(ZNetPeer peer, ZNet __instance) { //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Expected O, but got Unknown notProcessedNames.Clear(); IDictionary dictionary = (IDictionary)typeof(ZRpc).GetField("m_functions", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(peer.m_rpc); if (dictionary.Contains(StringExtensionMethods.GetStableHashCode("ServerSync VersionCheck"))) { object obj = dictionary[StringExtensionMethods.GetStableHashCode("ServerSync VersionCheck")]; Action action = (Action)obj.GetType().GetField("m_action", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(obj); peer.m_rpc.Register("ServerSync VersionCheck", (Action)delegate(ZRpc rpc, ZPackage pkg) { CheckVersion(rpc, pkg, action); }); } else { peer.m_rpc.Register("ServerSync VersionCheck", (Action)CheckVersion); } foreach (VersionCheck versionCheck in versionChecks) { versionCheck.Initialize(); if (versionCheck.ModRequired || __instance.IsServer()) { Debug.Log((object)("Sending " + versionCheck.DisplayName + " version " + versionCheck.CurrentVersion + " and minimum version " + versionCheck.MinimumRequiredVersion + " to the " + (__instance.IsServer() ? "client" : "server") + ".")); ZPackage val = new ZPackage(); val.Write(versionCheck.Name); val.Write(versionCheck.MinimumRequiredVersion); val.Write(versionCheck.CurrentVersion); peer.m_rpc.Invoke("ServerSync VersionCheck", new object[1] { val }); } } } [HarmonyPatch(typeof(ZNet), "Disconnect")] [HarmonyPrefix] private static void RemoveDisconnected(ZNetPeer peer, ZNet __instance) { if (!__instance.IsServer()) { return; } foreach (VersionCheck versionCheck in versionChecks) { versionCheck.ValidatedClients.Remove(peer.m_rpc); } } [HarmonyPatch(typeof(FejdStartup), "ShowConnectError")] [HarmonyPostfix] private static void ShowConnectionError(FejdStartup __instance) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Invalid comparison between Unknown and I4 //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) if (!__instance.m_connectionFailedPanel.activeSelf || (int)ZNet.GetConnectionStatus() != 3) { return; } bool flag = false; VersionCheck[] failedClient = GetFailedClient(); if (failedClient.Length != 0) { string text = string.Join("\n", failedClient.Select((VersionCheck check) => check.Error())); TMP_Text connectionFailedError = __instance.m_connectionFailedError; connectionFailedError.text = connectionFailedError.text + "\n" + text; flag = true; } foreach (KeyValuePair item in notProcessedNames.OrderBy, string>((KeyValuePair kv) => kv.Key)) { if (!__instance.m_connectionFailedError.text.Contains(item.Key)) { TMP_Text connectionFailedError2 = __instance.m_connectionFailedError; connectionFailedError2.text = connectionFailedError2.text + "\nServer expects you to have " + item.Key + " (Version: " + item.Value + ") installed."; flag = true; } } if (flag) { RectTransform component = ((Component)__instance.m_connectionFailedPanel.transform.Find("Image")).GetComponent(); Vector2 sizeDelta = component.sizeDelta; sizeDelta.x = 675f; component.sizeDelta = sizeDelta; __instance.m_connectionFailedError.ForceMeshUpdate(false, false); float num = __instance.m_connectionFailedError.renderedHeight + 105f; RectTransform component2 = ((Component)((Component)component).transform.Find("ButtonOk")).GetComponent(); component2.anchoredPosition = new Vector2(component2.anchoredPosition.x, component2.anchoredPosition.y - (num - component.sizeDelta.y) / 2f); sizeDelta = component.sizeDelta; sizeDelta.y = num; component.sizeDelta = sizeDelta; } } } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class IsReadOnlyAttribute : Attribute { } } namespace YamlDotNet { internal sealed class CultureInfoAdapter : CultureInfo { private readonly IFormatProvider provider; public CultureInfoAdapter(CultureInfo baseCulture, IFormatProvider provider) : base(baseCulture.Name) { this.provider = provider; } public override object? GetFormat(Type formatType) { return provider.GetFormat(formatType); } } internal static class Polyfills { [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static bool Contains(this string source, char c) { return source.IndexOf(c) != -1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static bool EndsWith(this string source, char c) { if (source.Length > 0) { return source[source.Length - 1] == c; } return false; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static bool StartsWith(this string source, char c) { if (source.Length > 0) { return source[0] == c; } return false; } } internal static class PropertyInfoExtensions { public static object? ReadValue(this PropertyInfo property, object target) { return property.GetValue(target, null); } } internal static class ReflectionExtensions { private static readonly Func IsInstance = (PropertyInfo property) => !(property.GetMethod ?? property.SetMethod).IsStatic; private static readonly Func IsInstancePublic = (PropertyInfo property) => IsInstance(property) && (property.GetMethod ?? property.SetMethod).IsPublic; public static Type? BaseType(this Type type) { return type.GetTypeInfo().BaseType; } public static bool IsValueType(this Type type) { return type.GetTypeInfo().IsValueType; } public static bool IsGenericType(this Type type) { return type.GetTypeInfo().IsGenericType; } public static bool IsGenericTypeDefinition(this Type type) { return type.GetTypeInfo().IsGenericTypeDefinition; } public static Type? GetImplementationOfOpenGenericInterface(this Type type, Type openGenericType) { if (!openGenericType.IsGenericType || !openGenericType.IsInterface) { throw new ArgumentException("The type must be a generic type definition and an interface", "openGenericType"); } if (IsGenericDefinitionOfType(type, openGenericType)) { return type; } return type.FindInterfaces((Type t, object context) => IsGenericDefinitionOfType(t, context), openGenericType).FirstOrDefault(); static bool IsGenericDefinitionOfType(Type t, object? context) { if (t.IsGenericType) { return t.GetGenericTypeDefinition() == (Type)context; } return false; } } public static bool IsInterface(this Type type) { return type.GetTypeInfo().IsInterface; } public static bool IsEnum(this Type type) { return type.GetTypeInfo().IsEnum; } public static bool IsRequired(this MemberInfo member) { return member.GetCustomAttributes(inherit: true).Any((object x) => x.GetType().FullName == "System.Runtime.CompilerServices.RequiredMemberAttribute"); } public static bool HasDefaultConstructor(this Type type, bool allowPrivateConstructors) { BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public; if (allowPrivateConstructors) { bindingFlags |= BindingFlags.NonPublic; } if (!type.IsValueType) { return type.GetConstructor(bindingFlags, null, Type.EmptyTypes, null) != null; } return true; } public static bool IsAssignableFrom(this Type type, Type source) { return type.IsAssignableFrom(source.GetTypeInfo()); } public static bool IsAssignableFrom(this Type type, TypeInfo source) { return type.GetTypeInfo().IsAssignableFrom(source); } public static TypeCode GetTypeCode(this Type type) { if (type.IsEnum()) { type = Enum.GetUnderlyingType(type); } if (type == typeof(bool)) { return TypeCode.Boolean; } if (type == typeof(char)) { return TypeCode.Char; } if (type == typeof(sbyte)) { return TypeCode.SByte; } if (type == typeof(byte)) { return TypeCode.Byte; } if (type == typeof(short)) { return TypeCode.Int16; } if (type == typeof(ushort)) { return TypeCode.UInt16; } if (type == typeof(int)) { return TypeCode.Int32; } if (type == typeof(uint)) { return TypeCode.UInt32; } if (type == typeof(long)) { return TypeCode.Int64; } if (type == typeof(ulong)) { return TypeCode.UInt64; } if (type == typeof(float)) { return TypeCode.Single; } if (type == typeof(double)) { return TypeCode.Double; } if (type == typeof(decimal)) { return TypeCode.Decimal; } if (type == typeof(DateTime)) { return TypeCode.DateTime; } if (type == typeof(string)) { return TypeCode.String; } return TypeCode.Object; } public static bool IsDbNull(this object value) { return value?.GetType()?.FullName == "System.DBNull"; } public static Type[] GetGenericArguments(this Type type) { return type.GetTypeInfo().GenericTypeArguments; } public static PropertyInfo? GetPublicProperty(this Type type, string name) { string name2 = name; return type.GetProperties(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public).FirstOrDefault((PropertyInfo p) => p.Name == name2); } public static FieldInfo? GetPublicStaticField(this Type type, string name) { return type.GetRuntimeField(name); } public static IEnumerable GetProperties(this Type type, bool includeNonPublic) { Func predicate = (includeNonPublic ? IsInstance : IsInstancePublic); if (!type.IsInterface()) { return type.GetRuntimeProperties().Where(predicate); } return new Type[1] { type }.Concat(type.GetInterfaces()).SelectMany((Type i) => i.GetRuntimeProperties().Where(predicate)); } public static IEnumerable GetPublicProperties(this Type type) { return type.GetProperties(includeNonPublic: false); } public static IEnumerable GetPublicFields(this Type type) { return from f in type.GetRuntimeFields() where !f.IsStatic && f.IsPublic select f; } public static IEnumerable GetPublicStaticMethods(this Type type) { return from m in type.GetRuntimeMethods() where m.IsPublic && m.IsStatic select m; } public static MethodInfo GetPrivateStaticMethod(this Type type, string name) { string name2 = name; return type.GetRuntimeMethods().FirstOrDefault((MethodInfo m) => !m.IsPublic && m.IsStatic && m.Name.Equals(name2)) ?? throw new MissingMethodException("Expected to find a method named '" + name2 + "' in '" + type.FullName + "'."); } public static MethodInfo? GetPublicStaticMethod(this Type type, string name, params Type[] parameterTypes) { string name2 = name; Type[] parameterTypes2 = parameterTypes; return type.GetRuntimeMethods().FirstOrDefault(delegate(MethodInfo m) { if (m.IsPublic && m.IsStatic && m.Name.Equals(name2)) { ParameterInfo[] parameters = m.GetParameters(); if (parameters.Length == parameterTypes2.Length) { return parameters.Zip(parameterTypes2, (ParameterInfo pi, Type pt) => pi.ParameterType == pt).All((bool r) => r); } return false; } return false; }); } public static MethodInfo? GetPublicInstanceMethod(this Type type, string name) { string name2 = name; return type.GetRuntimeMethods().FirstOrDefault((MethodInfo m) => m.IsPublic && !m.IsStatic && m.Name.Equals(name2)); } public static MethodInfo? GetGetMethod(this PropertyInfo property, bool nonPublic) { MethodInfo methodInfo = property.GetMethod; if (!nonPublic && !methodInfo.IsPublic) { methodInfo = null; } return methodInfo; } public static MethodInfo? GetSetMethod(this PropertyInfo property) { return property.SetMethod; } public static IEnumerable GetInterfaces(this Type type) { return type.GetTypeInfo().ImplementedInterfaces; } public static bool IsInstanceOf(this Type type, object o) { if (!(o.GetType() == type)) { return o.GetType().GetTypeInfo().IsSubclassOf(type); } return true; } public static Attribute[] GetAllCustomAttributes(this PropertyInfo member) { return Attribute.GetCustomAttributes(member, typeof(TAttribute), inherit: true); } public static bool AcceptsNull(this MemberInfo member) { object[] customAttributes = member.DeclaringType.GetCustomAttributes(inherit: true); object obj = customAttributes.FirstOrDefault((object x) => x.GetType().FullName == "System.Runtime.CompilerServices.NullableContextAttribute"); int num = 0; if (obj != null) { Type type = obj.GetType(); PropertyInfo property = type.GetProperty("Flag"); num = (byte)property.GetValue(obj); } object[] customAttributes2 = member.GetCustomAttributes(inherit: true); object obj2 = customAttributes2.FirstOrDefault((object x) => x.GetType().FullName == "System.Runtime.CompilerServices.NullableAttribute"); PropertyInfo propertyInfo = (obj2?.GetType())?.GetProperty("NullableFlags"); byte[] source = (byte[])propertyInfo.GetValue(obj2); return source.Any((byte x) => x == 2) || num == 2; } } internal static class StandardRegexOptions { public const RegexOptions Compiled = RegexOptions.Compiled; } } namespace YamlDotNet.Serialization { internal abstract class BuilderSkeleton where TBuilder : BuilderSkeleton { internal INamingConvention namingConvention = NullNamingConvention.Instance; internal INamingConvention enumNamingConvention = NullNamingConvention.Instance; internal ITypeResolver typeResolver; internal readonly YamlAttributeOverrides overrides; internal readonly LazyComponentRegistrationList typeConverterFactories; internal readonly LazyComponentRegistrationList typeInspectorFactories; internal bool ignoreFields; internal bool includeNonPublicProperties; internal Settings settings; internal YamlFormatter yamlFormatter = YamlFormatter.Default; protected abstract TBuilder Self { get; } internal BuilderSkeleton(ITypeResolver typeResolver) { overrides = new YamlAttributeOverrides(); typeConverterFactories = new LazyComponentRegistrationList { { typeof(YamlDotNet.Serialization.Converters.GuidConverter), (Nothing _) => new YamlDotNet.Serialization.Converters.GuidConverter(jsonCompatible: false) }, { typeof(SystemTypeConverter), (Nothing _) => new SystemTypeConverter() } }; typeInspectorFactories = new LazyComponentRegistrationList(); this.typeResolver = typeResolver ?? throw new ArgumentNullException("typeResolver"); settings = new Settings(); } public TBuilder IgnoreFields() { ignoreFields = true; return Self; } public TBuilder IncludeNonPublicProperties() { includeNonPublicProperties = true; return Self; } public TBuilder EnablePrivateConstructors() { settings.AllowPrivateConstructors = true; return Self; } public TBuilder WithNamingConvention(INamingConvention namingConvention) { this.namingConvention = namingConvention ?? throw new ArgumentNullException("namingConvention"); return Self; } public TBuilder WithEnumNamingConvention(INamingConvention enumNamingConvention) { this.enumNamingConvention = enumNamingConvention; return Self; } public TBuilder WithTypeResolver(ITypeResolver typeResolver) { this.typeResolver = typeResolver ?? throw new ArgumentNullException("typeResolver"); return Self; } public abstract TBuilder WithTagMapping(TagName tag, Type type); public TBuilder WithAttributeOverride(Expression> propertyAccessor, Attribute attribute) { overrides.Add(propertyAccessor, attribute); return Self; } public TBuilder WithAttributeOverride(Type type, string member, Attribute attribute) { overrides.Add(type, member, attribute); return Self; } public TBuilder WithTypeConverter(IYamlTypeConverter typeConverter) { return WithTypeConverter(typeConverter, delegate(IRegistrationLocationSelectionSyntax w) { w.OnTop(); }); } public TBuilder WithTypeConverter(IYamlTypeConverter typeConverter, Action> where) { IYamlTypeConverter typeConverter2 = typeConverter; if (typeConverter2 == null) { throw new ArgumentNullException("typeConverter"); } if (where == null) { throw new ArgumentNullException("where"); } where(typeConverterFactories.CreateRegistrationLocationSelector(typeConverter2.GetType(), (Nothing _) => typeConverter2)); return Self; } public TBuilder WithTypeConverter(WrapperFactory typeConverterFactory, Action> where) where TYamlTypeConverter : IYamlTypeConverter { WrapperFactory typeConverterFactory2 = typeConverterFactory; if (typeConverterFactory2 == null) { throw new ArgumentNullException("typeConverterFactory"); } if (where == null) { throw new ArgumentNullException("where"); } where(typeConverterFactories.CreateTrackingRegistrationLocationSelector(typeof(TYamlTypeConverter), (IYamlTypeConverter wrapped, Nothing _) => typeConverterFactory2(wrapped))); return Self; } public TBuilder WithoutTypeConverter() where TYamlTypeConverter : IYamlTypeConverter { return WithoutTypeConverter(typeof(TYamlTypeConverter)); } public TBuilder WithoutTypeConverter(Type converterType) { if (converterType == null) { throw new ArgumentNullException("converterType"); } typeConverterFactories.Remove(converterType); return Self; } public TBuilder WithTypeInspector(Func typeInspectorFactory) where TTypeInspector : ITypeInspector { return WithTypeInspector(typeInspectorFactory, delegate(IRegistrationLocationSelectionSyntax w) { w.OnTop(); }); } public TBuilder WithTypeInspector(Func typeInspectorFactory, Action> where) where TTypeInspector : ITypeInspector { Func typeInspectorFactory2 = typeInspectorFactory; if (typeInspectorFactory2 == null) { throw new ArgumentNullException("typeInspectorFactory"); } if (where == null) { throw new ArgumentNullException("where"); } where(typeInspectorFactories.CreateRegistrationLocationSelector(typeof(TTypeInspector), (ITypeInspector inner) => typeInspectorFactory2(inner))); return Self; } public TBuilder WithTypeInspector(WrapperFactory typeInspectorFactory, Action> where) where TTypeInspector : ITypeInspector { WrapperFactory typeInspectorFactory2 = typeInspectorFactory; if (typeInspectorFactory2 == null) { throw new ArgumentNullException("typeInspectorFactory"); } if (where == null) { throw new ArgumentNullException("where"); } where(typeInspectorFactories.CreateTrackingRegistrationLocationSelector(typeof(TTypeInspector), (ITypeInspector wrapped, ITypeInspector inner) => typeInspectorFactory2(wrapped, inner))); return Self; } public TBuilder WithoutTypeInspector() where TTypeInspector : ITypeInspector { return WithoutTypeInspector(typeof(TTypeInspector)); } public TBuilder WithoutTypeInspector(Type inspectorType) { if (inspectorType == null) { throw new ArgumentNullException("inspectorType"); } typeInspectorFactories.Remove(inspectorType); return Self; } public TBuilder WithYamlFormatter(YamlFormatter formatter) { yamlFormatter = formatter ?? throw new ArgumentNullException("formatter"); return Self; } protected IEnumerable BuildTypeConverters() { return typeConverterFactories.BuildComponentList(); } } internal delegate TComponent WrapperFactory(TComponentBase wrapped) where TComponent : TComponentBase; internal delegate TComponent WrapperFactory(TComponentBase wrapped, TArgument argument) where TComponent : TComponentBase; [Flags] internal enum DefaultValuesHandling { Preserve = 0, OmitNull = 1, OmitDefaults = 2, OmitEmptyCollections = 4 } internal sealed class Deserializer : IDeserializer { private readonly IValueDeserializer valueDeserializer; public Deserializer() : this(new DeserializerBuilder().BuildValueDeserializer()) { } private Deserializer(IValueDeserializer valueDeserializer) { this.valueDeserializer = valueDeserializer ?? throw new ArgumentNullException("valueDeserializer"); } public static Deserializer FromValueDeserializer(IValueDeserializer valueDeserializer) { return new Deserializer(valueDeserializer); } public T Deserialize(string input) { using StringReader input2 = new StringReader(input); return Deserialize(input2); } public T Deserialize(TextReader input) { return Deserialize(new Parser(input)); } public T Deserialize(IParser parser) { return (T)Deserialize(parser, typeof(T)); } public object? Deserialize(string input) { return Deserialize(input); } public object? Deserialize(TextReader input) { return Deserialize(input); } public object? Deserialize(IParser parser) { return Deserialize(parser); } public object? Deserialize(string input, Type type) { using StringReader input2 = new StringReader(input); return Deserialize(input2, type); } public object? Deserialize(TextReader input, Type type) { return Deserialize(new Parser(input), type); } public object? Deserialize(IParser parser, Type type) { if (parser == null) { throw new ArgumentNullException("parser"); } if (type == null) { throw new ArgumentNullException("type"); } YamlDotNet.Core.Events.StreamStart @event; bool flag = parser.TryConsume(out @event); YamlDotNet.Core.Events.DocumentStart event2; bool flag2 = parser.TryConsume(out event2); object result = null; if (!parser.Accept(out var _) && !parser.Accept(out var _)) { using SerializerState serializerState = new SerializerState(); result = valueDeserializer.DeserializeValue(parser, type, serializerState, valueDeserializer); serializerState.OnDeserialization(); } if (flag2) { parser.Consume(); } if (flag) { parser.Consume(); } return result; } } internal sealed class DeserializerBuilder : BuilderSkeleton { private Lazy objectFactory; private readonly LazyComponentRegistrationList nodeDeserializerFactories; private readonly LazyComponentRegistrationList nodeTypeResolverFactories; private readonly Dictionary tagMappings; private readonly Dictionary typeMappings; private readonly ITypeConverter typeConverter; private bool ignoreUnmatched; private bool duplicateKeyChecking; private bool attemptUnknownTypeDeserialization; private bool enforceNullability; private bool caseInsensitivePropertyMatching; private bool enforceRequiredProperties; protected override DeserializerBuilder Self => this; public DeserializerBuilder() : base((ITypeResolver)new StaticTypeResolver()) { typeMappings = new Dictionary(); objectFactory = new Lazy(() => new DefaultObjectFactory(typeMappings, settings), isThreadSafe: true); tagMappings = new Dictionary { { FailsafeSchema.Tags.Map, typeof(Dictionary) }, { FailsafeSchema.Tags.Str, typeof(string) }, { JsonSchema.Tags.Bool, typeof(bool) }, { JsonSchema.Tags.Float, typeof(double) }, { JsonSchema.Tags.Int, typeof(int) }, { DefaultSchema.Tags.Timestamp, typeof(DateTime) } }; typeInspectorFactories.Add(typeof(CachedTypeInspector), (ITypeInspector inner) => new CachedTypeInspector(inner)); typeInspectorFactories.Add(typeof(NamingConventionTypeInspector), (ITypeInspector inner) => (!(namingConvention is NullNamingConvention)) ? new NamingConventionTypeInspector(inner, namingConvention) : inner); typeInspectorFactories.Add(typeof(YamlAttributesTypeInspector), (ITypeInspector inner) => new YamlAttributesTypeInspector(inner)); typeInspectorFactories.Add(typeof(YamlAttributeOverridesInspector), (ITypeInspector inner) => (overrides == null) ? inner : new YamlAttributeOverridesInspector(inner, overrides.Clone())); typeInspectorFactories.Add(typeof(ReadableAndWritablePropertiesTypeInspector), (ITypeInspector inner) => new ReadableAndWritablePropertiesTypeInspector(inner)); nodeDeserializerFactories = new LazyComponentRegistrationList { { typeof(YamlConvertibleNodeDeserializer), (Nothing _) => new YamlConvertibleNodeDeserializer(objectFactory.Value) }, { typeof(YamlSerializableNodeDeserializer), (Nothing _) => new YamlSerializableNodeDeserializer(objectFactory.Value) }, { typeof(TypeConverterNodeDeserializer), (Nothing _) => new TypeConverterNodeDeserializer(BuildTypeConverters()) }, { typeof(NullNodeDeserializer), (Nothing _) => new NullNodeDeserializer() }, { typeof(ScalarNodeDeserializer), (Nothing _) => new ScalarNodeDeserializer(attemptUnknownTypeDeserialization, typeConverter, BuildTypeInspector(), yamlFormatter, enumNamingConvention) }, { typeof(ArrayNodeDeserializer), (Nothing _) => new ArrayNodeDeserializer(enumNamingConvention, BuildTypeInspector()) }, { typeof(DictionaryNodeDeserializer), (Nothing _) => new DictionaryNodeDeserializer(objectFactory.Value, duplicateKeyChecking) }, { typeof(CollectionNodeDeserializer), (Nothing _) => new CollectionNodeDeserializer(objectFactory.Value, enumNamingConvention, BuildTypeInspector()) }, { typeof(EnumerableNodeDeserializer), (Nothing _) => new EnumerableNodeDeserializer() }, { typeof(ObjectNodeDeserializer), (Nothing _) => new ObjectNodeDeserializer(objectFactory.Value, BuildTypeInspector(), ignoreUnmatched, duplicateKeyChecking, typeConverter, enumNamingConvention, enforceNullability, caseInsensitivePropertyMatching, enforceRequiredProperties, BuildTypeConverters()) }, { typeof(FsharpListNodeDeserializer), (Nothing _) => new FsharpListNodeDeserializer(BuildTypeInspector(), enumNamingConvention) } }; nodeTypeResolverFactories = new LazyComponentRegistrationList { { typeof(MappingNodeTypeResolver), (Nothing _) => new MappingNodeTypeResolver(typeMappings) }, { typeof(YamlConvertibleTypeResolver), (Nothing _) => new YamlConvertibleTypeResolver() }, { typeof(YamlSerializableTypeResolver), (Nothing _) => new YamlSerializableTypeResolver() }, { typeof(TagNodeTypeResolver), (Nothing _) => new TagNodeTypeResolver(tagMappings) }, { typeof(PreventUnknownTagsNodeTypeResolver), (Nothing _) => new PreventUnknownTagsNodeTypeResolver() }, { typeof(DefaultContainersNodeTypeResolver), (Nothing _) => new DefaultContainersNodeTypeResolver() } }; typeConverter = new ReflectionTypeConverter(); } public ITypeInspector BuildTypeInspector() { ITypeInspector typeInspector = new WritablePropertiesTypeInspector(typeResolver, includeNonPublicProperties); if (!ignoreFields) { typeInspector = new CompositeTypeInspector(new ReadableFieldsTypeInspector(typeResolver), typeInspector); } return typeInspectorFactories.BuildComponentChain(typeInspector); } public DeserializerBuilder WithAttemptingUnquotedStringTypeDeserialization() { attemptUnknownTypeDeserialization = true; return this; } public DeserializerBuilder WithObjectFactory(IObjectFactory objectFactory) { IObjectFactory objectFactory2 = objectFactory; if (objectFactory2 == null) { throw new ArgumentNullException("objectFactory"); } this.objectFactory = new Lazy(() => objectFactory2, isThreadSafe: true); return this; } public DeserializerBuilder WithObjectFactory(Func objectFactory) { if (objectFactory == null) { throw new ArgumentNullException("objectFactory"); } return WithObjectFactory(new LambdaObjectFactory(objectFactory)); } public DeserializerBuilder WithNodeDeserializer(INodeDeserializer nodeDeserializer) { return WithNodeDeserializer(nodeDeserializer, delegate(IRegistrationLocationSelectionSyntax w) { w.OnTop(); }); } public DeserializerBuilder WithNodeDeserializer(INodeDeserializer nodeDeserializer, Action> where) { INodeDeserializer nodeDeserializer2 = nodeDeserializer; if (nodeDeserializer2 == null) { throw new ArgumentNullException("nodeDeserializer"); } if (where == null) { throw new ArgumentNullException("where"); } where(nodeDeserializerFactories.CreateRegistrationLocationSelector(nodeDeserializer2.GetType(), (Nothing _) => nodeDeserializer2)); return this; } public DeserializerBuilder WithNodeDeserializer(WrapperFactory nodeDeserializerFactory, Action> where) where TNodeDeserializer : INodeDeserializer { WrapperFactory nodeDeserializerFactory2 = nodeDeserializerFactory; if (nodeDeserializerFactory2 == null) { throw new ArgumentNullException("nodeDeserializerFactory"); } if (where == null) { throw new ArgumentNullException("where"); } where(nodeDeserializerFactories.CreateTrackingRegistrationLocationSelector(typeof(TNodeDeserializer), (INodeDeserializer wrapped, Nothing _) => nodeDeserializerFactory2(wrapped))); return this; } public DeserializerBuilder WithoutNodeDeserializer() where TNodeDeserializer : INodeDeserializer { return WithoutNodeDeserializer(typeof(TNodeDeserializer)); } public DeserializerBuilder WithoutNodeDeserializer(Type nodeDeserializerType) { if (nodeDeserializerType == null) { throw new ArgumentNullException("nodeDeserializerType"); } nodeDeserializerFactories.Remove(nodeDeserializerType); return this; } public DeserializerBuilder WithTypeDiscriminatingNodeDeserializer(Action configureTypeDiscriminatingNodeDeserializerOptions, int maxDepth = -1, int maxLength = -1) { TypeDiscriminatingNodeDeserializerOptions typeDiscriminatingNodeDeserializerOptions = new TypeDiscriminatingNodeDeserializerOptions(); configureTypeDiscriminatingNodeDeserializerOptions(typeDiscriminatingNodeDeserializerOptions); TypeDiscriminatingNodeDeserializer nodeDeserializer = new TypeDiscriminatingNodeDeserializer(nodeDeserializerFactories.BuildComponentList(), typeDiscriminatingNodeDeserializerOptions.discriminators, maxDepth, maxLength); return WithNodeDeserializer(nodeDeserializer, delegate(IRegistrationLocationSelectionSyntax s) { s.Before(); }); } public DeserializerBuilder WithNodeTypeResolver(INodeTypeResolver nodeTypeResolver) { return WithNodeTypeResolver(nodeTypeResolver, delegate(IRegistrationLocationSelectionSyntax w) { w.OnTop(); }); } public DeserializerBuilder WithNodeTypeResolver(INodeTypeResolver nodeTypeResolver, Action> where) { INodeTypeResolver nodeTypeResolver2 = nodeTypeResolver; if (nodeTypeResolver2 == null) { throw new ArgumentNullException("nodeTypeResolver"); } if (where == null) { throw new ArgumentNullException("where"); } where(nodeTypeResolverFactories.CreateRegistrationLocationSelector(nodeTypeResolver2.GetType(), (Nothing _) => nodeTypeResolver2)); return this; } public DeserializerBuilder WithNodeTypeResolver(WrapperFactory nodeTypeResolverFactory, Action> where) where TNodeTypeResolver : INodeTypeResolver { WrapperFactory nodeTypeResolverFactory2 = nodeTypeResolverFactory; if (nodeTypeResolverFactory2 == null) { throw new ArgumentNullException("nodeTypeResolverFactory"); } if (where == null) { throw new ArgumentNullException("where"); } where(nodeTypeResolverFactories.CreateTrackingRegistrationLocationSelector(typeof(TNodeTypeResolver), (INodeTypeResolver wrapped, Nothing _) => nodeTypeResolverFactory2(wrapped))); return this; } public DeserializerBuilder WithCaseInsensitivePropertyMatching() { caseInsensitivePropertyMatching = true; return this; } public DeserializerBuilder WithEnforceNullability() { enforceNullability = true; return this; } public DeserializerBuilder WithEnforceRequiredMembers() { enforceRequiredProperties = true; return this; } public DeserializerBuilder WithoutNodeTypeResolver() where TNodeTypeResolver : INodeTypeResolver { return WithoutNodeTypeResolver(typeof(TNodeTypeResolver)); } public DeserializerBuilder WithoutNodeTypeResolver(Type nodeTypeResolverType) { if (nodeTypeResolverType == null) { throw new ArgumentNullException("nodeTypeResolverType"); } nodeTypeResolverFactories.Remove(nodeTypeResolverType); return this; } public override DeserializerBuilder WithTagMapping(TagName tag, Type type) { if (tag.IsEmpty) { throw new ArgumentException("Non-specific tags cannot be maped"); } if (type == null) { throw new ArgumentNullException("type"); } if (tagMappings.TryGetValue(tag, out Type value)) { throw new ArgumentException($"Type already has a registered type '{value.FullName}' for tag '{tag}'", "tag"); } tagMappings.Add(tag, type); return this; } public DeserializerBuilder WithTypeMapping() where TConcrete : TInterface { Type typeFromHandle = typeof(TInterface); Type typeFromHandle2 = typeof(TConcrete); if (!typeFromHandle.IsAssignableFrom(typeFromHandle2)) { throw new InvalidOperationException("The type '" + typeFromHandle2.Name + "' does not implement interface '" + typeFromHandle.Name + "'."); } if (!DictionaryExtensions.TryAdd(typeMappings, typeFromHandle, typeFromHandle2)) { typeMappings[typeFromHandle] = typeFromHandle2; } return this; } public DeserializerBuilder WithoutTagMapping(TagName tag) { if (tag.IsEmpty) { throw new ArgumentException("Non-specific tags cannot be maped"); } if (!tagMappings.Remove(tag)) { throw new KeyNotFoundException($"Tag '{tag}' is not registered"); } return this; } public DeserializerBuilder IgnoreUnmatchedProperties() { ignoreUnmatched = true; return this; } public DeserializerBuilder WithDuplicateKeyChecking() { duplicateKeyChecking = true; return this; } public IDeserializer Build() { if (FsharpHelper.Instance == null) { FsharpHelper.Instance = new DefaultFsharpHelper(); } return Deserializer.FromValueDeserializer(BuildValueDeserializer()); } public IValueDeserializer BuildValueDeserializer() { return new AliasValueDeserializer(new NodeValueDeserializer(nodeDeserializerFactories.BuildComponentList(), nodeTypeResolverFactories.BuildComponentList(), typeConverter, enumNamingConvention, BuildTypeInspector())); } } internal sealed class EmissionPhaseObjectGraphVisitorArgs { private readonly IEnumerable> preProcessingPhaseVisitors; public IObjectGraphVisitor InnerVisitor { get; private set; } public IEventEmitter EventEmitter { get; private set; } public ObjectSerializer NestedObjectSerializer { get; private set; } public IEnumerable TypeConverters { get; private set; } public EmissionPhaseObjectGraphVisitorArgs(IObjectGraphVisitor innerVisitor, IEventEmitter eventEmitter, IEnumerable> preProcessingPhaseVisitors, IEnumerable typeConverters, ObjectSerializer nestedObjectSerializer) { InnerVisitor = innerVisitor ?? throw new ArgumentNullException("innerVisitor"); EventEmitter = eventEmitter ?? throw new ArgumentNullException("eventEmitter"); this.preProcessingPhaseVisitors = preProcessingPhaseVisitors ?? throw new ArgumentNullException("preProcessingPhaseVisitors"); TypeConverters = typeConverters ?? throw new ArgumentNullException("typeConverters"); NestedObjectSerializer = nestedObjectSerializer ?? throw new ArgumentNullException("nestedObjectSerializer"); } public T GetPreProcessingPhaseObjectGraphVisitor() where T : IObjectGraphVisitor { return preProcessingPhaseVisitors.OfType().Single(); } } internal abstract class EventInfo { public IObjectDescriptor Source { get; } protected EventInfo(IObjectDescriptor source) { Source = source ?? throw new ArgumentNullException("source"); } } internal class AliasEventInfo : EventInfo { public AnchorName Alias { get; } public bool NeedsExpansion { get; set; } public AliasEventInfo(IObjectDescriptor source, AnchorName alias) : base(source) { if (alias.IsEmpty) { throw new ArgumentNullException("alias"); } Alias = alias; } } internal class ObjectEventInfo : EventInfo { public AnchorName Anchor { get; set; } public TagName Tag { get; set; } protected ObjectEventInfo(IObjectDescriptor source) : base(source) { } } internal sealed class ScalarEventInfo : ObjectEventInfo { public string RenderedValue { get; set; } public ScalarStyle Style { get; set; } public bool IsPlainImplicit { get; set; } public bool IsQuotedImplicit { get; set; } public ScalarEventInfo(IObjectDescriptor source) : base(source) { Style = source.ScalarStyle; RenderedValue = string.Empty; } } internal sealed class MappingStartEventInfo : ObjectEventInfo { public bool IsImplicit { get; set; } public MappingStyle Style { get; set; } public MappingStartEventInfo(IObjectDescriptor source) : base(source) { } } internal sealed class MappingEndEventInfo : EventInfo { public MappingEndEventInfo(IObjectDescriptor source) : base(source) { } } internal sealed class SequenceStartEventInfo : ObjectEventInfo { public bool IsImplicit { get; set; } public SequenceStyle Style { get; set; } public SequenceStartEventInfo(IObjectDescriptor source) : base(source) { } } internal sealed class SequenceEndEventInfo : EventInfo { public SequenceEndEventInfo(IObjectDescriptor source) : base(source) { } } internal interface IAliasProvider { AnchorName GetAlias(object target); } internal interface IDeserializer { T Deserialize(string input); T Deserialize(TextReader input); T Deserialize(IParser parser); object? Deserialize(string input); object? Deserialize(TextReader input); object? Deserialize(IParser parser); object? Deserialize(string input, Type type); object? Deserialize(TextReader input, Type type); object? Deserialize(IParser parser, Type type); } internal interface IEventEmitter { void Emit(AliasEventInfo eventInfo, IEmitter emitter); void Emit(ScalarEventInfo eventInfo, IEmitter emitter); void Emit(MappingStartEventInfo eventInfo, IEmitter emitter); void Emit(MappingEndEventInfo eventInfo, IEmitter emitter); void Emit(SequenceStartEventInfo eventInfo, IEmitter emitter); void Emit(SequenceEndEventInfo eventInfo, IEmitter emitter); } internal interface INamingConvention { string Apply(string value); string Reverse(string value); } internal interface INodeDeserializer { bool Deserialize(IParser reader, Type expectedType, Func nestedObjectDeserializer, out object? value, ObjectDeserializer rootDeserializer); } internal interface INodeTypeResolver { bool Resolve(NodeEvent? nodeEvent, ref Type currentType); } internal interface IObjectAccessor { void Set(string name, object target, object value); object? Read(string name, object target); } internal interface IObjectDescriptor { object? Value { get; } Type Type { get; } Type StaticType { get; } ScalarStyle ScalarStyle { get; } } internal static class ObjectDescriptorExtensions { public static object NonNullValue(this IObjectDescriptor objectDescriptor) { return objectDescriptor.Value ?? throw new InvalidOperationException("Attempted to use a IObjectDescriptor of type '" + objectDescriptor.Type.FullName + "' whose Value is null at a point whete it is invalid to do so. This may indicate a bug in YamlDotNet."); } } internal interface IObjectFactory { object Create(Type type); object? CreatePrimitive(Type type); bool GetDictionary(IObjectDescriptor descriptor, out IDictionary? dictionary, out Type[]? genericArguments); Type GetValueType(Type type); void ExecuteOnDeserializing(object value); void ExecuteOnDeserialized(object value); void ExecuteOnSerializing(object value); void ExecuteOnSerialized(object value); } internal interface IObjectGraphTraversalStrategy { void Traverse(IObjectDescriptor graph, IObjectGraphVisitor visitor, TContext context, ObjectSerializer serializer); } internal interface IObjectGraphVisitor { bool Enter(IPropertyDescriptor? propertyDescriptor, IObjectDescriptor value, TContext context, ObjectSerializer serializer); bool EnterMapping(IObjectDescriptor key, IObjectDescriptor value, TContext context, ObjectSerializer serializer); bool EnterMapping(IPropertyDescriptor key, IObjectDescriptor value, TContext context, ObjectSerializer serializer); void VisitScalar(IObjectDescriptor scalar, TContext context, ObjectSerializer serializer); void VisitMappingStart(IObjectDescriptor mapping, Type keyType, Type valueType, TContext context, ObjectSerializer serializer); void VisitMappingEnd(IObjectDescriptor mapping, TContext context, ObjectSerializer serializer); void VisitSequenceStart(IObjectDescriptor sequence, Type elementType, TContext context, ObjectSerializer serializer); void VisitSequenceEnd(IObjectDescriptor sequence, TContext context, ObjectSerializer serializer); } internal interface IPropertyDescriptor { string Name { get; } bool AllowNulls { get; } bool CanWrite { get; } Type Type { get; } Type? TypeOverride { get; set; } int Order { get; set; } ScalarStyle ScalarStyle { get; set; } bool Required { get; } Type? ConverterType { get; } T? GetCustomAttribute() where T : Attribute; IObjectDescriptor Read(object target); void Write(object target, object? value); } internal interface IRegistrationLocationSelectionSyntax { void InsteadOf() where TRegistrationType : TBaseRegistrationType; void Before() where TRegistrationType : TBaseRegistrationType; void After() where TRegistrationType : TBaseRegistrationType; void OnTop(); void OnBottom(); } internal interface ITrackingRegistrationLocationSelectionSyntax { void InsteadOf() where TRegistrationType : TBaseRegistrationType; } internal interface ISerializer { string Serialize(object? graph); string Serialize(object? graph, Type type); void Serialize(TextWriter writer, object? graph); void Serialize(TextWriter writer, object? graph, Type type); void Serialize(IEmitter emitter, object? graph); void Serialize(IEmitter emitter, object? graph, Type type); } internal interface ITypeInspector { IEnumerable GetProperties(Type type, object? container); IPropertyDescriptor GetProperty(Type type, object? container, string name, [MaybeNullWhen(true)] bool ignoreUnmatched, bool caseInsensitivePropertyMatching); string GetEnumName(Type enumType, string name); string GetEnumValue(object enumValue); } internal interface ITypeResolver { Type Resolve(Type staticType, object? actualValue); } internal interface IValueDeserializer { object? DeserializeValue(IParser parser, Type expectedType, SerializerState state, IValueDeserializer nestedObjectDeserializer); } internal interface IValuePromise { event Action ValueAvailable; } internal interface IValueSerializer { void SerializeValue(IEmitter emitter, object? value, Type? type); } internal interface IYamlConvertible { void Read(IParser parser, Type expectedType, ObjectDeserializer nestedObjectDeserializer); void Write(IEmitter emitter, ObjectSerializer nestedObjectSerializer); } internal delegate object? ObjectDeserializer(Type type); internal delegate void ObjectSerializer(object? value, Type? type = null); [Obsolete("Please use IYamlConvertible instead")] internal interface IYamlSerializable { void ReadYaml(IParser parser); void WriteYaml(IEmitter emitter); } internal interface IYamlTypeConverter { bool Accepts(Type type); object? ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer); void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer); } internal sealed class LazyComponentRegistrationList : IEnumerable>, IEnumerable { public sealed class LazyComponentRegistration { public readonly Type ComponentType; public readonly Func Factory; public LazyComponentRegistration(Type componentType, Func factory) { ComponentType = componentType; Factory = factory; } } public sealed class TrackingLazyComponentRegistration { public readonly Type ComponentType; public readonly Func Factory; public TrackingLazyComponentRegistration(Type componentType, Func factory) { ComponentType = componentType; Factory = factory; } } private class RegistrationLocationSelector : IRegistrationLocationSelectionSyntax { private readonly LazyComponentRegistrationList registrations; private readonly LazyComponentRegistration newRegistration; public RegistrationLocationSelector(LazyComponentRegistrationList registrations, LazyComponentRegistration newRegistration) { this.registrations = registrations; this.newRegistration = newRegistration; } void IRegistrationLocationSelectionSyntax.InsteadOf() { if (newRegistration.ComponentType != typeof(TRegistrationType)) { registrations.EnsureNoDuplicateRegistrationType(newRegistration.ComponentType); } int index = registrations.EnsureRegistrationExists(); registrations.entries[index] = newRegistration; } void IRegistrationLocationSelectionSyntax.After() { registrations.EnsureNoDuplicateRegistrationType(newRegistration.ComponentType); int num = registrations.EnsureRegistrationExists(); registrations.entries.Insert(num + 1, newRegistration); } void IRegistrationLocationSelectionSyntax.Before() { registrations.EnsureNoDuplicateRegistrationType(newRegistration.ComponentType); int index = registrations.EnsureRegistrationExists(); registrations.entries.Insert(index, newRegistration); } void IRegistrationLocationSelectionSyntax.OnBottom() { registrations.EnsureNoDuplicateRegistrationType(newRegistration.ComponentType); registrations.entries.Add(newRegistration); } void IRegistrationLocationSelectionSyntax.OnTop() { registrations.EnsureNoDuplicateRegistrationType(newRegistration.ComponentType); registrations.entries.Insert(0, newRegistration); } } private class TrackingRegistrationLocationSelector : ITrackingRegistrationLocationSelectionSyntax { private readonly LazyComponentRegistrationList registrations; private readonly TrackingLazyComponentRegistration newRegistration; public TrackingRegistrationLocationSelector(LazyComponentRegistrationList registrations, TrackingLazyComponentRegistration newRegistration) { this.registrations = registrations; this.newRegistration = newRegistration; } void ITrackingRegistrationLocationSelectionSyntax.InsteadOf() { if (newRegistration.ComponentType != typeof(TRegistrationType)) { registrations.EnsureNoDuplicateRegistrationType(newRegistration.ComponentType); } int index = registrations.EnsureRegistrationExists(); Func innerComponentFactory = registrations.entries[index].Factory; registrations.entries[index] = new LazyComponentRegistration(newRegistration.ComponentType, (TArgument arg) => newRegistration.Factory(innerComponentFactory(arg), arg)); } } private readonly List entries = new List(); public int Count => entries.Count; public IEnumerable> InReverseOrder { get { int i = entries.Count - 1; while (i >= 0) { yield return entries[i].Factory; int num = i - 1; i = num; } } } public LazyComponentRegistrationList Clone() { LazyComponentRegistrationList lazyComponentRegistrationList = new LazyComponentRegistrationList(); foreach (LazyComponentRegistration entry in entries) { lazyComponentRegistrationList.entries.Add(entry); } return lazyComponentRegistrationList; } public void Clear() { entries.Clear(); } public void Add(Type componentType, Func factory) { entries.Add(new LazyComponentRegistration(componentType, factory)); } public void Remove(Type componentType) { for (int i = 0; i < entries.Count; i++) { if (entries[i].ComponentType == componentType) { entries.RemoveAt(i); return; } } throw new KeyNotFoundException("A component registration of type '" + componentType.FullName + "' was not found."); } public IRegistrationLocationSelectionSyntax CreateRegistrationLocationSelector(Type componentType, Func factory) { return new RegistrationLocationSelector(this, new LazyComponentRegistration(componentType, factory)); } public ITrackingRegistrationLocationSelectionSyntax CreateTrackingRegistrationLocationSelector(Type componentType, Func factory) { return new TrackingRegistrationLocationSelector(this, new TrackingLazyComponentRegistration(componentType, factory)); } public IEnumerator> GetEnumerator() { return entries.Select((LazyComponentRegistration e) => e.Factory).GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } private int IndexOfRegistration(Type registrationType) { for (int i = 0; i < entries.Count; i++) { if (registrationType == entries[i].ComponentType) { return i; } } return -1; } private void EnsureNoDuplicateRegistrationType(Type componentType) { if (IndexOfRegistration(componentType) != -1) { throw new InvalidOperationException("A component of type '" + componentType.FullName + "' has already been registered."); } } private int EnsureRegistrationExists() { int num = IndexOfRegistration(typeof(TRegistrationType)); if (num == -1) { throw new InvalidOperationException("A component of type '" + typeof(TRegistrationType).FullName + "' has not been registered."); } return num; } } internal static class LazyComponentRegistrationListExtensions { public static TComponent BuildComponentChain(this LazyComponentRegistrationList registrations, TComponent innerComponent) { return registrations.InReverseOrder.Aggregate(innerComponent, (TComponent inner, Func factory) => factory(inner)); } public static TComponent BuildComponentChain(this LazyComponentRegistrationList registrations, TComponent innerComponent, Func argumentBuilder) { Func argumentBuilder2 = argumentBuilder; return registrations.InReverseOrder.Aggregate(innerComponent, (TComponent inner, Func factory) => factory(argumentBuilder2(inner))); } public static List BuildComponentList(this LazyComponentRegistrationList registrations) { return registrations.Select((Func factory) => factory(default(Nothing))).ToList(); } public static List BuildComponentList(this LazyComponentRegistrationList registrations, TArgument argument) { TArgument argument2 = argument; return registrations.Select((Func factory) => factory(argument2)).ToList(); } } [StructLayout(LayoutKind.Sequential, Size = 1)] internal struct Nothing { } internal sealed class ObjectDescriptor : IObjectDescriptor { public object? Value { get; private set; } public Type Type { get; private set; } public Type StaticType { get; private set; } public ScalarStyle ScalarStyle { get; private set; } public ObjectDescriptor(object? value, Type type, Type staticType) : this(value, type, staticType, ScalarStyle.Any) { } public ObjectDescriptor(object? value, Type type, Type staticType, ScalarStyle scalarStyle) { Value = value; Type = type ?? throw new ArgumentNullException("type"); StaticType = staticType ?? throw new ArgumentNullException("staticType"); ScalarStyle = scalarStyle; } } internal delegate IObjectGraphTraversalStrategy ObjectGraphTraversalStrategyFactory(ITypeInspector typeInspector, ITypeResolver typeResolver, IEnumerable typeConverters, int maximumRecursion); internal sealed class PropertyDescriptor : IPropertyDescriptor { private readonly IPropertyDescriptor baseDescriptor; public bool AllowNulls => baseDescriptor.AllowNulls; public string Name { get; set; } public bool Required => baseDescriptor.Required; public Type Type => baseDescriptor.Type; public Type? TypeOverride { get { return baseDescriptor.TypeOverride; } set { baseDescriptor.TypeOverride = value; } } public Type? ConverterType => baseDescriptor.ConverterType; public int Order { get; set; } public ScalarStyle ScalarStyle { get { return baseDescriptor.ScalarStyle; } set { baseDescriptor.ScalarStyle = value; } } public bool CanWrite => baseDescriptor.CanWrite; public PropertyDescriptor(IPropertyDescriptor baseDescriptor) { this.baseDescriptor = baseDescriptor; Name = baseDescriptor.Name; } public void Write(object target, object? value) { baseDescriptor.Write(target, value); } public T? GetCustomAttribute() where T : Attribute { return baseDescriptor.GetCustomAttribute(); } public IObjectDescriptor Read(object target) { return baseDescriptor.Read(target); } } internal sealed class Serializer : ISerializer { private readonly IValueSerializer valueSerializer; private readonly EmitterSettings emitterSettings; public Serializer() : this(new SerializerBuilder().BuildValueSerializer(), EmitterSettings.Default) { } private Serializer(IValueSerializer valueSerializer, EmitterSettings emitterSettings) { this.valueSerializer = valueSerializer ?? throw new ArgumentNullException("valueSerializer"); this.emitterSettings = emitterSettings ?? throw new ArgumentNullException("emitterSettings"); } public static Serializer FromValueSerializer(IValueSerializer valueSerializer, EmitterSettings emitterSettings) { return new Serializer(valueSerializer, emitterSettings); } public string Serialize(object? graph) { using StringWriter stringWriter = new StringWriter(); Serialize(stringWriter, graph); return stringWriter.ToString(); } public string Serialize(object? graph, Type type) { using StringWriter stringWriter = new StringWriter(); Serialize(stringWriter, graph, type); return stringWriter.ToString(); } public void Serialize(TextWriter writer, object? graph) { Serialize(new Emitter(writer, emitterSettings), graph); } public void Serialize(TextWriter writer, object? graph, Type type) { Serialize(new Emitter(writer, emitterSettings), graph, type); } public void Serialize(IEmitter emitter, object? graph) { if (emitter == null) { throw new ArgumentNullException("emitter"); } EmitDocument(emitter, graph, null); } public void Serialize(IEmitter emitter, object? graph, Type type) { if (emitter == null) { throw new ArgumentNullException("emitter"); } if (type == null) { throw new ArgumentNullException("type"); } EmitDocument(emitter, graph, type); } private void EmitDocument(IEmitter emitter, object? graph, Type? type) { emitter.Emit(new YamlDotNet.Core.Events.StreamStart()); emitter.Emit(new YamlDotNet.Core.Events.DocumentStart()); valueSerializer.SerializeValue(emitter, graph, type); emitter.Emit(new YamlDotNet.Core.Events.DocumentEnd(isImplicit: true)); emitter.Emit(new YamlDotNet.Core.Events.StreamEnd()); } } internal sealed class SerializerBuilder : BuilderSkeleton { private class ValueSerializer : IValueSerializer { private readonly IObjectGraphTraversalStrategy traversalStrategy; private readonly IEventEmitter eventEmitter; private readonly IEnumerable typeConverters; private readonly LazyComponentRegistrationList, IObjectGraphVisitor> preProcessingPhaseObjectGraphVisitorFactories; private readonly LazyComponentRegistrationList> emissionPhaseObjectGraphVisitorFactories; public ValueSerializer(IObjectGraphTraversalStrategy traversalStrategy, IEventEmitter eventEmitter, IEnumerable typeConverters, LazyComponentRegistrationList, IObjectGraphVisitor> preProcessingPhaseObjectGraphVisitorFactories, LazyComponentRegistrationList> emissionPhaseObjectGraphVisitorFactories) { this.traversalStrategy = traversalStrategy; this.eventEmitter = eventEmitter; this.typeConverters = typeConverters; this.preProcessingPhaseObjectGraphVisitorFactories = preProcessingPhaseObjectGraphVisitorFactories; this.emissionPhaseObjectGraphVisitorFactories = emissionPhaseObjectGraphVisitorFactories; } public void SerializeValue(IEmitter emitter, object? value, Type? type) { IEmitter emitter2 = emitter; Type type2 = type ?? ((value != null) ? value.GetType() : typeof(object)); Type staticType = type ?? typeof(object); ObjectDescriptor graph = new ObjectDescriptor(value, type2, staticType); List> preProcessingPhaseObjectGraphVisitors = preProcessingPhaseObjectGraphVisitorFactories.BuildComponentList(typeConverters); IObjectGraphVisitor visitor = emissionPhaseObjectGraphVisitorFactories.BuildComponentChain>(new EmittingObjectGraphVisitor(eventEmitter), (IObjectGraphVisitor inner) => new EmissionPhaseObjectGraphVisitorArgs(inner, eventEmitter, preProcessingPhaseObjectGraphVisitors, typeConverters, NestedObjectSerializer)); foreach (IObjectGraphVisitor item in preProcessingPhaseObjectGraphVisitors) { traversalStrategy.Traverse(graph, item, default(Nothing), NestedObjectSerializer); } traversalStrategy.Traverse(graph, visitor, emitter2, NestedObjectSerializer); void NestedObjectSerializer(object? v, Type? t) { SerializeValue(emitter2, v, t); } } } private ObjectGraphTraversalStrategyFactory objectGraphTraversalStrategyFactory; private readonly LazyComponentRegistrationList, IObjectGraphVisitor> preProcessingPhaseObjectGraphVisitorFactories; private readonly LazyComponentRegistrationList> emissionPhaseObjectGraphVisitorFactories; private readonly LazyComponentRegistrationList eventEmitterFactories; private readonly Dictionary tagMappings = new Dictionary(); private readonly IObjectFactory objectFactory; private int maximumRecursion = 50; private EmitterSettings emitterSettings = EmitterSettings.Default; private DefaultValuesHandling defaultValuesHandlingConfiguration; private ScalarStyle defaultScalarStyle; private bool quoteNecessaryStrings; private bool quoteYaml1_1Strings; protected override SerializerBuilder Self => this; public SerializerBuilder() : base((ITypeResolver)new DynamicTypeResolver()) { typeInspectorFactories.Add(typeof(CachedTypeInspector), (ITypeInspector inner) => new CachedTypeInspector(inner)); typeInspectorFactories.Add(typeof(NamingConventionTypeInspector), (ITypeInspector inner) => (!(namingConvention is NullNamingConvention)) ? new NamingConventionTypeInspector(inner, namingConvention) : inner); typeInspectorFactories.Add(typeof(YamlAttributesTypeInspector), (ITypeInspector inner) => new YamlAttributesTypeInspector(inner)); typeInspectorFactories.Add(typeof(YamlAttributeOverridesInspector), (ITypeInspector inner) => (overrides == null) ? inner : new YamlAttributeOverridesInspector(inner, overrides.Clone())); preProcessingPhaseObjectGraphVisitorFactories = new LazyComponentRegistrationList, IObjectGraphVisitor> { { typeof(AnchorAssigner), (IEnumerable typeConverters) => new AnchorAssigner(typeConverters) } }; emissionPhaseObjectGraphVisitorFactories = new LazyComponentRegistrationList> { { typeof(CustomSerializationObjectGraphVisitor), (EmissionPhaseObjectGraphVisitorArgs args) => new CustomSerializationObjectGraphVisitor(args.InnerVisitor, args.TypeConverters, args.NestedObjectSerializer) }, { typeof(AnchorAssigningObjectGraphVisitor), (EmissionPhaseObjectGraphVisitorArgs args) => new AnchorAssigningObjectGraphVisitor(args.InnerVisitor, args.EventEmitter, args.GetPreProcessingPhaseObjectGraphVisitor()) }, { typeof(DefaultValuesObjectGraphVisitor), (EmissionPhaseObjectGraphVisitorArgs args) => new DefaultValuesObjectGraphVisitor(defaultValuesHandlingConfiguration, args.InnerVisitor, new DefaultObjectFactory()) }, { typeof(CommentsObjectGraphVisitor), (EmissionPhaseObjectGraphVisitorArgs args) => new CommentsObjectGraphVisitor(args.InnerVisitor) } }; eventEmitterFactories = new LazyComponentRegistrationList { { typeof(TypeAssigningEventEmitter), (IEventEmitter inner) => new TypeAssigningEventEmitter(inner, tagMappings, quoteNecessaryStrings, quoteYaml1_1Strings, defaultScalarStyle, yamlFormatter, enumNamingConvention, BuildTypeInspector()) } }; objectFactory = new DefaultObjectFactory(); objectGraphTraversalStrategyFactory = (ITypeInspector typeInspector, ITypeResolver typeResolver, IEnumerable typeConverters, int maximumRecursion) => new FullObjectGraphTraversalStrategy(typeInspector, typeResolver, maximumRecursion, namingConvention, objectFactory); } public SerializerBuilder WithQuotingNecessaryStrings(bool quoteYaml1_1Strings = false) { quoteNecessaryStrings = true; this.quoteYaml1_1Strings = quoteYaml1_1Strings; return this; } public SerializerBuilder WithDefaultScalarStyle(ScalarStyle style) { defaultScalarStyle = style; return this; } public SerializerBuilder WithMaximumRecursion(int maximumRecursion) { if (maximumRecursion <= 0) { throw new ArgumentOutOfRangeException("maximumRecursion", $"The maximum recursion specified ({maximumRecursion}) is invalid. It should be a positive integer."); } this.maximumRecursion = maximumRecursion; return this; } public SerializerBuilder WithEventEmitter(Func eventEmitterFactory) where TEventEmitter : IEventEmitter { return WithEventEmitter(eventEmitterFactory, delegate(IRegistrationLocationSelectionSyntax w) { w.OnTop(); }); } public SerializerBuilder WithEventEmitter(Func eventEmitterFactory) where TEventEmitter : IEventEmitter { return WithEventEmitter(eventEmitterFactory, delegate(IRegistrationLocationSelectionSyntax w) { w.OnTop(); }); } public SerializerBuilder WithEventEmitter(Func eventEmitterFactory, Action> where) where TEventEmitter : IEventEmitter { Func eventEmitterFactory2 = eventEmitterFactory; return WithEventEmitter((IEventEmitter e, ITypeInspector _) => eventEmitterFactory2(e), where); } public SerializerBuilder WithEventEmitter(Func eventEmitterFactory, Action> where) where TEventEmitter : IEventEmitter { Func eventEmitterFactory2 = eventEmitterFactory; if (eventEmitterFactory2 == null) { throw new ArgumentNullException("eventEmitterFactory"); } if (where == null) { throw new ArgumentNullException("where"); } where(eventEmitterFactories.CreateRegistrationLocationSelector(typeof(TEventEmitter), (IEventEmitter inner) => eventEmitterFactory2(inner, BuildTypeInspector()))); return Self; } public SerializerBuilder WithEventEmitter(WrapperFactory eventEmitterFactory, Action> where) where TEventEmitter : IEventEmitter { WrapperFactory eventEmitterFactory2 = eventEmitterFactory; if (eventEmitterFactory2 == null) { throw new ArgumentNullException("eventEmitterFactory"); } if (where == null) { throw new ArgumentNullException("where"); } where(eventEmitterFactories.CreateTrackingRegistrationLocationSelector(typeof(TEventEmitter), (IEventEmitter wrapped, IEventEmitter inner) => eventEmitterFactory2(wrapped, inner))); return Self; } public SerializerBuilder WithoutEventEmitter() where TEventEmitter : IEventEmitter { return WithoutEventEmitter(typeof(TEventEmitter)); } public SerializerBuilder WithoutEventEmitter(Type eventEmitterType) { if (eventEmitterType == null) { throw new ArgumentNullException("eventEmitterType"); } eventEmitterFactories.Remove(eventEmitterType); return this; } public override SerializerBuilder WithTagMapping(TagName tag, Type type) { if (tag.IsEmpty) { throw new ArgumentException("Non-specific tags cannot be maped"); } if (type == null) { throw new ArgumentNullException("type"); } if (tagMappings.TryGetValue(type, out var value)) { throw new ArgumentException($"Type already has a registered tag '{value}' for type '{type.FullName}'", "type"); } tagMappings.Add(type, tag); return this; } public SerializerBuilder WithoutTagMapping(Type type) { if (type == null) { throw new ArgumentNullException("type"); } if (!tagMappings.Remove(type)) { throw new KeyNotFoundException("Tag for type '" + type.FullName + "' is not registered"); } return this; } public SerializerBuilder EnsureRoundtrip() { objectGraphTraversalStrategyFactory = (ITypeInspector typeInspector, ITypeResolver typeResolver, IEnumerable typeConverters, int maximumRecursion) => new RoundtripObjectGraphTraversalStrategy(typeConverters, typeInspector, typeResolver, maximumRecursion, namingConvention, settings, objectFactory); WithEventEmitter((IEventEmitter inner) => new TypeAssigningEventEmitter(inner, tagMappings, quoteNecessaryStrings, quoteYaml1_1Strings, defaultScalarStyle, yamlFormatter, enumNamingConvention, BuildTypeInspector()), delegate(IRegistrationLocationSelectionSyntax loc) { loc.InsteadOf(); }); return WithTypeInspector((ITypeInspector inner) => new ReadableAndWritablePropertiesTypeInspector(inner), delegate(IRegistrationLocationSelectionSyntax loc) { loc.OnBottom(); }); } public SerializerBuilder DisableAliases() { preProcessingPhaseObjectGraphVisitorFactories.Remove(typeof(AnchorAssigner)); emissionPhaseObjectGraphVisitorFactories.Remove(typeof(AnchorAssigningObjectGraphVisitor)); return this; } [Obsolete("The default behavior is now to always emit default values, thefore calling this method has no effect. This behavior is now controlled by ConfigureDefaultValuesHandling.", true)] public SerializerBuilder EmitDefaults() { return ConfigureDefaultValuesHandling(DefaultValuesHandling.Preserve); } public SerializerBuilder ConfigureDefaultValuesHandling(DefaultValuesHandling configuration) { defaultValuesHandlingConfiguration = configuration; return this; } public SerializerBuilder JsonCompatible() { emitterSettings = emitterSettings.WithMaxSimpleKeyLength(int.MaxValue).WithoutAnchorName().WithUtf16SurrogatePairs(); return WithTypeConverter(new YamlDotNet.Serialization.Converters.GuidConverter(jsonCompatible: true), delegate(IRegistrationLocationSelectionSyntax w) { w.InsteadOf(); }).WithTypeConverter(new DateTime8601Converter(ScalarStyle.DoubleQuoted)).WithEventEmitter((IEventEmitter inner) => new JsonEventEmitter(inner, yamlFormatter, enumNamingConvention, BuildTypeInspector()), delegate(IRegistrationLocationSelectionSyntax loc) { loc.InsteadOf(); }); } public SerializerBuilder WithNewLine(string newLine) { emitterSettings = emitterSettings.WithNewLine(newLine); return this; } public SerializerBuilder WithPreProcessingPhaseObjectGraphVisitor(TObjectGraphVisitor objectGraphVisitor) where TObjectGraphVisitor : IObjectGraphVisitor { return WithPreProcessingPhaseObjectGraphVisitor(objectGraphVisitor, delegate(IRegistrationLocationSelectionSyntax> w) { w.OnTop(); }); } public SerializerBuilder WithPreProcessingPhaseObjectGraphVisitor(Func, TObjectGraphVisitor> objectGraphVisitorFactory) where TObjectGraphVisitor : IObjectGraphVisitor { return WithPreProcessingPhaseObjectGraphVisitor(objectGraphVisitorFactory, delegate(IRegistrationLocationSelectionSyntax> w) { w.OnTop(); }); } public SerializerBuilder WithPreProcessingPhaseObjectGraphVisitor(TObjectGraphVisitor objectGraphVisitor, Action>> where) where TObjectGraphVisitor : IObjectGraphVisitor { TObjectGraphVisitor objectGraphVisitor2 = objectGraphVisitor; if (objectGraphVisitor2 == null) { throw new ArgumentNullException("objectGraphVisitor"); } if (where == null) { throw new ArgumentNullException("where"); } where(preProcessingPhaseObjectGraphVisitorFactories.CreateRegistrationLocationSelector(typeof(TObjectGraphVisitor), (IEnumerable _) => objectGraphVisitor2)); return this; } public SerializerBuilder WithPreProcessingPhaseObjectGraphVisitor(Func, TObjectGraphVisitor> objectGraphVisitorFactory, Action>> where) where TObjectGraphVisitor : IObjectGraphVisitor { Func, TObjectGraphVisitor> objectGraphVisitorFactory2 = objectGraphVisitorFactory; if (objectGraphVisitorFactory2 == null) { throw new ArgumentNullException("objectGraphVisitorFactory"); } if (where == null) { throw new ArgumentNullException("where"); } where(preProcessingPhaseObjectGraphVisitorFactories.CreateRegistrationLocationSelector(typeof(TObjectGraphVisitor), (IEnumerable typeConverters) => objectGraphVisitorFactory2(typeConverters))); return this; } public SerializerBuilder WithPreProcessingPhaseObjectGraphVisitor(WrapperFactory, TObjectGraphVisitor> objectGraphVisitorFactory, Action>> where) where TObjectGraphVisitor : IObjectGraphVisitor { WrapperFactory, TObjectGraphVisitor> objectGraphVisitorFactory2 = objectGraphVisitorFactory; if (objectGraphVisitorFactory2 == null) { throw new ArgumentNullException("objectGraphVisitorFactory"); } if (where == null) { throw new ArgumentNullException("where"); } where(preProcessingPhaseObjectGraphVisitorFactories.CreateTrackingRegistrationLocationSelector(typeof(TObjectGraphVisitor), (IObjectGraphVisitor wrapped, IEnumerable _) => objectGraphVisitorFactory2(wrapped))); return this; } public SerializerBuilder WithPreProcessingPhaseObjectGraphVisitor(WrapperFactory, IObjectGraphVisitor, TObjectGraphVisitor> objectGraphVisitorFactory, Action>> where) where TObjectGraphVisitor : IObjectGraphVisitor { WrapperFactory, IObjectGraphVisitor, TObjectGraphVisitor> objectGraphVisitorFactory2 = objectGraphVisitorFactory; if (objectGraphVisitorFactory2 == null) { throw new ArgumentNullException("objectGraphVisitorFactory"); } if (where == null) { throw new ArgumentNullException("where"); } where(preProcessingPhaseObjectGraphVisitorFactories.CreateTrackingRegistrationLocationSelector(typeof(TObjectGraphVisitor), (IObjectGraphVisitor wrapped, IEnumerable typeConverters) => objectGraphVisitorFactory2(wrapped, typeConverters))); return this; } public SerializerBuilder WithoutPreProcessingPhaseObjectGraphVisitor() where TObjectGraphVisitor : IObjectGraphVisitor { return WithoutPreProcessingPhaseObjectGraphVisitor(typeof(TObjectGraphVisitor)); } public SerializerBuilder WithoutPreProcessingPhaseObjectGraphVisitor(Type objectGraphVisitorType) { if (objectGraphVisitorType == null) { throw new ArgumentNullException("objectGraphVisitorType"); } preProcessingPhaseObjectGraphVisitorFactories.Remove(objectGraphVisitorType); return this; } public SerializerBuilder WithObjectGraphTraversalStrategyFactory(ObjectGraphTraversalStrategyFactory objectGraphTraversalStrategyFactory) { this.objectGraphTraversalStrategyFactory = objectGraphTraversalStrategyFactory; return this; } public SerializerBuilder WithEmissionPhaseObjectGraphVisitor(Func objectGraphVisitorFactory) where TObjectGraphVisitor : IObjectGraphVisitor { return WithEmissionPhaseObjectGraphVisitor(objectGraphVisitorFactory, delegate(IRegistrationLocationSelectionSyntax> w) { w.OnTop(); }); } public SerializerBuilder WithEmissionPhaseObjectGraphVisitor(Func objectGraphVisitorFactory, Action>> where) where TObjectGraphVisitor : IObjectGraphVisitor { Func objectGraphVisitorFactory2 = objectGraphVisitorFactory; if (objectGraphVisitorFactory2 == null) { throw new ArgumentNullException("objectGraphVisitorFactory"); } if (where == null) { throw new ArgumentNullException("where"); } where(emissionPhaseObjectGraphVisitorFactories.CreateRegistrationLocationSelector(typeof(TObjectGraphVisitor), (EmissionPhaseObjectGraphVisitorArgs args) => objectGraphVisitorFactory2(args))); return this; } public SerializerBuilder WithEmissionPhaseObjectGraphVisitor(WrapperFactory, TObjectGraphVisitor> objectGraphVisitorFactory, Action>> where) where TObjectGraphVisitor : IObjectGraphVisitor { WrapperFactory, TObjectGraphVisitor> objectGraphVisitorFactory2 = objectGraphVisitorFactory; if (objectGraphVisitorFactory2 == null) { throw new ArgumentNullException("objectGraphVisitorFactory"); } if (where == null) { throw new ArgumentNullException("where"); } where(emissionPhaseObjectGraphVisitorFactories.CreateTrackingRegistrationLocationSelector(typeof(TObjectGraphVisitor), (IObjectGraphVisitor wrapped, EmissionPhaseObjectGraphVisitorArgs args) => objectGraphVisitorFactory2(wrapped, args))); return this; } public SerializerBuilder WithoutEmissionPhaseObjectGraphVisitor() where TObjectGraphVisitor : IObjectGraphVisitor { return WithoutEmissionPhaseObjectGraphVisitor(typeof(TObjectGraphVisitor)); } public SerializerBuilder WithoutEmissionPhaseObjectGraphVisitor(Type objectGraphVisitorType) { if (objectGraphVisitorType == null) { throw new ArgumentNullException("objectGraphVisitorType"); } emissionPhaseObjectGraphVisitorFactories.Remove(objectGraphVisitorType); return this; } public SerializerBuilder WithIndentedSequences() { emitterSettings = emitterSettings.WithIndentedSequences(); return this; } public ISerializer Build() { if (FsharpHelper.Instance == null) { FsharpHelper.Instance = new DefaultFsharpHelper(); } return Serializer.FromValueSerializer(BuildValueSerializer(), emitterSettings); } public IValueSerializer BuildValueSerializer() { IEnumerable typeConverters = BuildTypeConverters(); ITypeInspector typeInspector = BuildTypeInspector(); IObjectGraphTraversalStrategy traversalStrategy = objectGraphTraversalStrategyFactory(typeInspector, typeResolver, typeConverters, maximumRecursion); IEventEmitter eventEmitter = eventEmitterFactories.BuildComponentChain(new WriterEventEmitter()); return new ValueSerializer(traversalStrategy, eventEmitter, typeConverters, preProcessingPhaseObjectGraphVisitorFactories.Clone(), emissionPhaseObjectGraphVisitorFactories.Clone()); } public ITypeInspector BuildTypeInspector() { ITypeInspector typeInspector = new ReadablePropertiesTypeInspector(typeResolver, includeNonPublicProperties); if (!ignoreFields) { typeInspector = new CompositeTypeInspector(new ReadableFieldsTypeInspector(typeResolver), typeInspector); } return typeInspectorFactories.BuildComponentChain(typeInspector); } } internal class Settings { public bool AllowPrivateConstructors { get; set; } } internal abstract class StaticBuilderSkeleton where TBuilder : StaticBuilderSkeleton { internal INamingConvention namingConvention = NullNamingConvention.Instance; internal INamingConvention enumNamingConvention = NullNamingConvention.Instance; internal ITypeResolver typeResolver; internal readonly LazyComponentRegistrationList typeConverterFactories; internal readonly LazyComponentRegistrationList typeInspectorFactories; internal bool includeNonPublicProperties; internal Settings settings; internal YamlFormatter yamlFormatter = YamlFormatter.Default; protected abstract TBuilder Self { get; } internal StaticBuilderSkeleton(ITypeResolver typeResolver) { typeConverterFactories = new LazyComponentRegistrationList { { typeof(YamlDotNet.Serialization.Converters.GuidConverter), (Nothing _) => new YamlDotNet.Serialization.Converters.GuidConverter(jsonCompatible: false) } }; typeInspectorFactories = new LazyComponentRegistrationList(); this.typeResolver = typeResolver ?? throw new ArgumentNullException("typeResolver"); settings = new Settings(); } public TBuilder WithNamingConvention(INamingConvention namingConvention) { this.namingConvention = namingConvention ?? throw new ArgumentNullException("namingConvention"); return Self; } public TBuilder WithEnumNamingConvention(INamingConvention enumNamingConvention) { this.enumNamingConvention = enumNamingConvention ?? throw new ArgumentNullException("enumNamingConvention"); return Self; } public TBuilder WithTypeResolver(ITypeResolver typeResolver) { this.typeResolver = typeResolver ?? throw new ArgumentNullException("typeResolver"); return Self; } public abstract TBuilder WithTagMapping(TagName tag, Type type); public TBuilder WithTypeConverter(IYamlTypeConverter typeConverter) { return WithTypeConverter(typeConverter, delegate(IRegistrationLocationSelectionSyntax w) { w.OnTop(); }); } public TBuilder WithTypeConverter(IYamlTypeConverter typeConverter, Action> where) { IYamlTypeConverter typeConverter2 = typeConverter; if (typeConverter2 == null) { throw new ArgumentNullException("typeConverter"); } if (where == null) { throw new ArgumentNullException("where"); } where(typeConverterFactories.CreateRegistrationLocationSelector(typeConverter2.GetType(), (Nothing _) => typeConverter2)); return Self; } public TBuilder WithTypeConverter(WrapperFactory typeConverterFactory, Action> where) where TYamlTypeConverter : IYamlTypeConverter { WrapperFactory typeConverterFactory2 = typeConverterFactory; if (typeConverterFactory2 == null) { throw new ArgumentNullException("typeConverterFactory"); } if (where == null) { throw new ArgumentNullException("where"); } where(typeConverterFactories.CreateTrackingRegistrationLocationSelector(typeof(TYamlTypeConverter), (IYamlTypeConverter wrapped, Nothing _) => typeConverterFactory2(wrapped))); return Self; } public TBuilder WithoutTypeConverter() where TYamlTypeConverter : IYamlTypeConverter { return WithoutTypeConverter(typeof(TYamlTypeConverter)); } public TBuilder WithoutTypeConverter(Type converterType) { if (converterType == null) { throw new ArgumentNullException("converterType"); } typeConverterFactories.Remove(converterType); return Self; } public TBuilder WithTypeInspector(Func typeInspectorFactory) where TTypeInspector : ITypeInspector { return WithTypeInspector(typeInspectorFactory, delegate(IRegistrationLocationSelectionSyntax w) { w.OnTop(); }); } public TBuilder WithTypeInspector(Func typeInspectorFactory, Action> where) where TTypeInspector : ITypeInspector { Func typeInspectorFactory2 = typeInspectorFactory; if (typeInspectorFactory2 == null) { throw new ArgumentNullException("typeInspectorFactory"); } if (where == null) { throw new ArgumentNullException("where"); } where(typeInspectorFactories.CreateRegistrationLocationSelector(typeof(TTypeInspector), (ITypeInspector inner) => typeInspectorFactory2(inner))); return Self; } public TBuilder WithTypeInspector(WrapperFactory typeInspectorFactory, Action> where) where TTypeInspector : ITypeInspector { WrapperFactory typeInspectorFactory2 = typeInspectorFactory; if (typeInspectorFactory2 == null) { throw new ArgumentNullException("typeInspectorFactory"); } if (where == null) { throw new ArgumentNullException("where"); } where(typeInspectorFactories.CreateTrackingRegistrationLocationSelector(typeof(TTypeInspector), (ITypeInspector wrapped, ITypeInspector inner) => typeInspectorFactory2(wrapped, inner))); return Self; } public TBuilder WithoutTypeInspector() where TTypeInspector : ITypeInspector { return WithoutTypeInspector(typeof(TTypeInspector)); } public TBuilder WithoutTypeInspector(Type inspectorType) { if (inspectorType == null) { throw new ArgumentNullException("inspectorType"); } typeInspectorFactories.Remove(inspectorType); return Self; } public TBuilder WithYamlFormatter(YamlFormatter formatter) { yamlFormatter = formatter ?? throw new ArgumentNullException("formatter"); return Self; } protected IEnumerable BuildTypeConverters() { return typeConverterFactories.BuildComponentList(); } } internal abstract class StaticContext { public virtual bool IsKnownType(Type type) { throw new NotImplementedException(); } public virtual ITypeResolver GetTypeResolver() { throw new NotImplementedException(); } public virtual StaticObjectFactory GetFactory() { throw new NotImplementedException(); } public virtual ITypeInspector GetTypeInspector() { throw new NotImplementedException(); } } internal sealed class StaticDeserializerBuilder : StaticBuilderSkeleton { private readonly StaticContext context; private readonly StaticObjectFactory factory; private readonly LazyComponentRegistrationList nodeDeserializerFactories; private readonly LazyComponentRegistrationList nodeTypeResolverFactories; private readonly Dictionary tagMappings; private readonly ITypeConverter typeConverter; private readonly Dictionary typeMappings; private bool ignoreUnmatched; private bool duplicateKeyChecking; private bool attemptUnknownTypeDeserialization; private bool enforceNullability; private bool caseInsensitivePropertyMatching; protected override StaticDeserializerBuilder Self => this; public StaticDeserializerBuilder(StaticContext context) : base(context.GetTypeResolver()) { this.context = context; factory = context.GetFactory(); typeMappings = new Dictionary(); tagMappings = new Dictionary { { FailsafeSchema.Tags.Map, typeof(Dictionary) }, { FailsafeSchema.Tags.Str, typeof(string) }, { JsonSchema.Tags.Bool, typeof(bool) }, { JsonSchema.Tags.Float, typeof(double) }, { JsonSchema.Tags.Int, typeof(int) }, { DefaultSchema.Tags.Timestamp, typeof(DateTime) } }; typeInspectorFactories.Add(typeof(CachedTypeInspector), (ITypeInspector inner) => new CachedTypeInspector(inner)); typeInspectorFactories.Add(typeof(NamingConventionTypeInspector), (ITypeInspector inner) => (!(namingConvention is NullNamingConvention)) ? new NamingConventionTypeInspector(inner, namingConvention) : inner); typeInspectorFactories.Add(typeof(YamlAttributesTypeInspector), (ITypeInspector inner) => new YamlAttributesTypeInspector(inner)); nodeDeserializerFactories = new LazyComponentRegistrationList { { typeof(YamlConvertibleNodeDeserializer), (Nothing _) => new YamlConvertibleNodeDeserializer(factory) }, { typeof(YamlSerializableNodeDeserializer), (Nothing _) => new YamlSerializableNodeDeserializer(factory) }, { typeof(TypeConverterNodeDeserializer), (Nothing _) => new TypeConverterNodeDeserializer(BuildTypeConverters()) }, { typeof(NullNodeDeserializer), (Nothing _) => new NullNodeDeserializer() }, { typeof(ScalarNodeDeserializer), (Nothing _) => new ScalarNodeDeserializer(attemptUnknownTypeDeserialization, typeConverter, BuildTypeInspector(), yamlFormatter, enumNamingConvention) }, { typeof(StaticArrayNodeDeserializer), (Nothing _) => new StaticArrayNodeDeserializer(factory) }, { typeof(StaticDictionaryNodeDeserializer), (Nothing _) => new StaticDictionaryNodeDeserializer(factory, duplicateKeyChecking) }, { typeof(StaticCollectionNodeDeserializer), (Nothing _) => new StaticCollectionNodeDeserializer(factory) }, { typeof(ObjectNodeDeserializer), (Nothing _) => new ObjectNodeDeserializer(factory, BuildTypeInspector(), ignoreUnmatched, duplicateKeyChecking, typeConverter, enumNamingConvention, enforceNullability, caseInsensitivePropertyMatching, enforceRequiredProperties: false, BuildTypeConverters()) } }; nodeTypeResolverFactories = new LazyComponentRegistrationList { { typeof(MappingNodeTypeResolver), (Nothing _) => new MappingNodeTypeResolver(typeMappings) }, { typeof(YamlConvertibleTypeResolver), (Nothing _) => new YamlConvertibleTypeResolver() }, { typeof(YamlSerializableTypeResolver), (Nothing _) => new YamlSerializableTypeResolver() }, { typeof(TagNodeTypeResolver), (Nothing _) => new TagNodeTypeResolver(tagMappings) }, { typeof(PreventUnknownTagsNodeTypeResolver), (Nothing _) => new PreventUnknownTagsNodeTypeResolver() }, { typeof(DefaultContainersNodeTypeResolver), (Nothing _) => new DefaultContainersNodeTypeResolver() } }; typeConverter = new NullTypeConverter(); } public ITypeInspector BuildTypeInspector() { ITypeInspector typeInspector = context.GetTypeInspector(); return typeInspectorFactories.BuildComponentChain(typeInspector); } public StaticDeserializerBuilder WithAttemptingUnquotedStringTypeDeserialization() { attemptUnknownTypeDeserialization = true; return this; } public StaticDeserializerBuilder WithNodeDeserializer(INodeDeserializer nodeDeserializer) { return WithNodeDeserializer(nodeDeserializer, delegate(IRegistrationLocationSelectionSyntax w) { w.OnTop(); }); } public StaticDeserializerBuilder WithNodeDeserializer(INodeDeserializer nodeDeserializer, Action> where) { INodeDeserializer nodeDeserializer2 = nodeDeserializer; if (nodeDeserializer2 == null) { throw new ArgumentNullException("nodeDeserializer"); } if (where == null) { throw new ArgumentNullException("where"); } where(nodeDeserializerFactories.CreateRegistrationLocationSelector(nodeDeserializer2.GetType(), (Nothing _) => nodeDeserializer2)); return this; } public StaticDeserializerBuilder WithNodeDeserializer(WrapperFactory nodeDeserializerFactory, Action> where) where TNodeDeserializer : INodeDeserializer { WrapperFactory nodeDeserializerFactory2 = nodeDeserializerFactory; if (nodeDeserializerFactory2 == null) { throw new ArgumentNullException("nodeDeserializerFactory"); } if (where == null) { throw new ArgumentNullException("where"); } where(nodeDeserializerFactories.CreateTrackingRegistrationLocationSelector(typeof(TNodeDeserializer), (INodeDeserializer wrapped, Nothing _) => nodeDeserializerFactory2(wrapped))); return this; } public StaticDeserializerBuilder WithCaseInsensitivePropertyMatching() { caseInsensitivePropertyMatching = true; return this; } public StaticDeserializerBuilder WithEnforceNullability() { enforceNullability = true; return this; } public StaticDeserializerBuilder WithoutNodeDeserializer() where TNodeDeserializer : INodeDeserializer { return WithoutNodeDeserializer(typeof(TNodeDeserializer)); } public StaticDeserializerBuilder WithoutNodeDeserializer(Type nodeDeserializerType) { if (nodeDeserializerType == null) { throw new ArgumentNullException("nodeDeserializerType"); } nodeDeserializerFactories.Remove(nodeDeserializerType); return this; } public StaticDeserializerBuilder WithTypeDiscriminatingNodeDeserializer(Action configureTypeDiscriminatingNodeDeserializerOptions, int maxDepth = -1, int maxLength = -1) { TypeDiscriminatingNodeDeserializerOptions typeDiscriminatingNodeDeserializerOptions = new TypeDiscriminatingNodeDeserializerOptions(); configureTypeDiscriminatingNodeDeserializerOptions(typeDiscriminatingNodeDeserializerOptions); TypeDiscriminatingNodeDeserializer nodeDeserializer = new TypeDiscriminatingNodeDeserializer(nodeDeserializerFactories.BuildComponentList(), typeDiscriminatingNodeDeserializerOptions.discriminators, maxDepth, maxLength); return WithNodeDeserializer(nodeDeserializer, delegate(IRegistrationLocationSelectionSyntax s) { s.Before(); }); } public StaticDeserializerBuilder WithNodeTypeResolver(INodeTypeResolver nodeTypeResolver) { return WithNodeTypeResolver(nodeTypeResolver, delegate(IRegistrationLocationSelectionSyntax w) { w.OnTop(); }); } public StaticDeserializerBuilder WithNodeTypeResolver(INodeTypeResolver nodeTypeResolver, Action> where) { INodeTypeResolver nodeTypeResolver2 = nodeTypeResolver; if (nodeTypeResolver2 == null) { throw new ArgumentNullException("nodeTypeResolver"); } if (where == null) { throw new ArgumentNullException("where"); } where(nodeTypeResolverFactories.CreateRegistrationLocationSelector(nodeTypeResolver2.GetType(), (Nothing _) => nodeTypeResolver2)); return this; } public StaticDeserializerBuilder WithNodeTypeResolver(WrapperFactory nodeTypeResolverFactory, Action> where) where TNodeTypeResolver : INodeTypeResolver { WrapperFactory nodeTypeResolverFactory2 = nodeTypeResolverFactory; if (nodeTypeResolverFactory2 == null) { throw new ArgumentNullException("nodeTypeResolverFactory"); } if (where == null) { throw new ArgumentNullException("where"); } where(nodeTypeResolverFactories.CreateTrackingRegistrationLocationSelector(typeof(TNodeTypeResolver), (INodeTypeResolver wrapped, Nothing _) => nodeTypeResolverFactory2(wrapped))); return this; } public StaticDeserializerBuilder WithoutNodeTypeResolver() where TNodeTypeResolver : INodeTypeResolver { return WithoutNodeTypeResolver(typeof(TNodeTypeResolver)); } public StaticDeserializerBuilder WithoutNodeTypeResolver(Type nodeTypeResolverType) { if (nodeTypeResolverType == null) { throw new ArgumentNullException("nodeTypeResolverType"); } nodeTypeResolverFactories.Remove(nodeTypeResolverType); return this; } public override StaticDeserializerBuilder WithTagMapping(TagName tag, Type type) { if (tag.IsEmpty) { throw new ArgumentException("Non-specific tags cannot be maped"); } if (type == null) { throw new ArgumentNullException("type"); } if (tagMappings.TryGetValue(tag, out Type value)) { throw new ArgumentException($"Type already has a registered type '{value.FullName}' for tag '{tag}'", "tag"); } tagMappings.Add(tag, type); return this; } public StaticDeserializerBuilder WithTypeMapping() where TConcrete : TInterface { Type typeFromHandle = typeof(TInterface); Type typeFromHandle2 = typeof(TConcrete); if (!typeFromHandle.IsAssignableFrom(typeFromHandle2)) { throw new InvalidOperationException("The type '" + typeFromHandle2.Name + "' does not implement interface '" + typeFromHandle.Name + "'."); } typeMappings[typeFromHandle] = typeFromHandle2; return this; } public StaticDeserializerBuilder WithoutTagMapping(TagName tag) { if (tag.IsEmpty) { throw new ArgumentException("Non-specific tags cannot be maped"); } if (!tagMappings.Remove(tag)) { throw new KeyNotFoundException($"Tag '{tag}' is not registered"); } return this; } public StaticDeserializerBuilder IgnoreUnmatchedProperties() { ignoreUnmatched = true; return this; } public StaticDeserializerBuilder WithDuplicateKeyChecking() { duplicateKeyChecking = true; return this; } public IDeserializer Build() { return Deserializer.FromValueDeserializer(BuildValueDeserializer()); } public IValueDeserializer BuildValueDeserializer() { return new AliasValueDeserializer(new NodeValueDeserializer(nodeDeserializerFactories.BuildComponentList(), nodeTypeResolverFactories.BuildComponentList(), typeConverter, enumNamingConvention, BuildTypeInspector())); } } internal sealed class StaticSerializerBuilder : StaticBuilderSkeleton { private class ValueSerializer : IValueSerializer { private readonly IObjectGraphTraversalStrategy traversalStrategy; private readonly IEventEmitter eventEmitter; private readonly IEnumerable typeConverters; private readonly LazyComponentRegistrationList, IObjectGraphVisitor> preProcessingPhaseObjectGraphVisitorFactories; private readonly LazyComponentRegistrationList> emissionPhaseObjectGraphVisitorFactories; public ValueSerializer(IObjectGraphTraversalStrategy traversalStrategy, IEventEmitter eventEmitter, IEnumerable typeConverters, LazyComponentRegistrationList, IObjectGraphVisitor> preProcessingPhaseObjectGraphVisitorFactories, LazyComponentRegistrationList> emissionPhaseObjectGraphVisitorFactories) { this.traversalStrategy = traversalStrategy; this.eventEmitter = eventEmitter; this.typeConverters = typeConverters; this.preProcessingPhaseObjectGraphVisitorFactories = preProcessingPhaseObjectGraphVisitorFactories; this.emissionPhaseObjectGraphVisitorFactories = emissionPhaseObjectGraphVisitorFactories; } public void SerializeValue(IEmitter emitter, object? value, Type? type) { IEmitter emitter2 = emitter; Type type2 = type ?? ((value != null) ? value.GetType() : typeof(object)); Type staticType = type ?? typeof(object); ObjectDescriptor graph = new ObjectDescriptor(value, type2, staticType); List> preProcessingPhaseObjectGraphVisitors = preProcessingPhaseObjectGraphVisitorFactories.BuildComponentList(typeConverters); foreach (IObjectGraphVisitor item in preProcessingPhaseObjectGraphVisitors) { traversalStrategy.Traverse(graph, item, default(Nothing), NestedObjectSerializer); } IObjectGraphVisitor visitor = emissionPhaseObjectGraphVisitorFactories.BuildComponentChain>(new EmittingObjectGraphVisitor(eventEmitter), (IObjectGraphVisitor inner) => new EmissionPhaseObjectGraphVisitorArgs(inner, eventEmitter, preProcessingPhaseObjectGraphVisitors, typeConverters, NestedObjectSerializer)); traversalStrategy.Traverse(graph, visitor, emitter2, NestedObjectSerializer); void NestedObjectSerializer(object? v, Type? t) { SerializeValue(emitter2, v, t); } } } private readonly StaticContext context; private readonly StaticObjectFactory factory; private ObjectGraphTraversalStrategyFactory objectGraphTraversalStrategyFactory; private readonly LazyComponentRegistrationList, IObjectGraphVisitor> preProcessingPhaseObjectGraphVisitorFactories; private readonly LazyComponentRegistrationList> emissionPhaseObjectGraphVisitorFactories; private readonly LazyComponentRegistrationList eventEmitterFactories; private readonly Dictionary tagMappings = new Dictionary(); private int maximumRecursion = 50; private EmitterSettings emitterSettings = EmitterSettings.Default; private DefaultValuesHandling defaultValuesHandlingConfiguration; private bool quoteNecessaryStrings; private bool quoteYaml1_1Strings; private ScalarStyle defaultScalarStyle; protected override StaticSerializerBuilder Self => this; public StaticSerializerBuilder(StaticContext context) : base((ITypeResolver)new DynamicTypeResolver()) { this.context = context; factory = context.GetFactory(); typeInspectorFactories.Add(typeof(CachedTypeInspector), (ITypeInspector inner) => new CachedTypeInspector(inner)); typeInspectorFactories.Add(typeof(NamingConventionTypeInspector), (ITypeInspector inner) => (!(namingConvention is NullNamingConvention)) ? new NamingConventionTypeInspector(inner, namingConvention) : inner); typeInspectorFactories.Add(typeof(YamlAttributesTypeInspector), (ITypeInspector inner) => new YamlAttributesTypeInspector(inner)); preProcessingPhaseObjectGraphVisitorFactories = new LazyComponentRegistrationList, IObjectGraphVisitor> { { typeof(AnchorAssigner), (IEnumerable typeConverters) => new AnchorAssigner(typeConverters) } }; emissionPhaseObjectGraphVisitorFactories = new LazyComponentRegistrationList> { { typeof(CustomSerializationObjectGraphVisitor), (EmissionPhaseObjectGraphVisitorArgs args) => new CustomSerializationObjectGraphVisitor(args.InnerVisitor, args.TypeConverters, args.NestedObjectSerializer) }, { typeof(AnchorAssigningObjectGraphVisitor), (EmissionPhaseObjectGraphVisitorArgs args) => new AnchorAssigningObjectGraphVisitor(args.InnerVisitor, args.EventEmitter, args.GetPreProcessingPhaseObjectGraphVisitor()) }, { typeof(DefaultValuesObjectGraphVisitor), (EmissionPhaseObjectGraphVisitorArgs args) => new DefaultValuesObjectGraphVisitor(defaultValuesHandlingConfiguration, args.InnerVisitor, factory) }, { typeof(CommentsObjectGraphVisitor), (EmissionPhaseObjectGraphVisitorArgs args) => new CommentsObjectGraphVisitor(args.InnerVisitor) } }; eventEmitterFactories = new LazyComponentRegistrationList { { typeof(TypeAssigningEventEmitter), (IEventEmitter inner) => new TypeAssigningEventEmitter(inner, tagMappings, quoteNecessaryStrings, quoteYaml1_1Strings, defaultScalarStyle, yamlFormatter, enumNamingConvention, BuildTypeInspector()) } }; objectGraphTraversalStrategyFactory = (ITypeInspector typeInspector, ITypeResolver typeResolver, IEnumerable typeConverters, int maximumRecursion) => new FullObjectGraphTraversalStrategy(typeInspector, typeResolver, maximumRecursion, namingConvention, factory); } public StaticSerializerBuilder WithQuotingNecessaryStrings(bool quoteYaml1_1Strings = false) { quoteNecessaryStrings = true; this.quoteYaml1_1Strings = quoteYaml1_1Strings; return this; } public StaticSerializerBuilder WithQuotingNecessaryStrings() { quoteNecessaryStrings = true; return this; } public StaticSerializerBuilder WithDefaultScalarStyle(ScalarStyle style) { defaultScalarStyle = style; return this; } public StaticSerializerBuilder WithMaximumRecursion(int maximumRecursion) { if (maximumRecursion <= 0) { throw new ArgumentOutOfRangeException("maximumRecursion", $"The maximum recursion specified ({maximumRecursion}) is invalid. It should be a positive integer."); } this.maximumRecursion = maximumRecursion; return this; } public StaticSerializerBuilder WithEventEmitter(Func eventEmitterFactory) where TEventEmitter : IEventEmitter { return WithEventEmitter(eventEmitterFactory, delegate(IRegistrationLocationSelectionSyntax w) { w.OnTop(); }); } public StaticSerializerBuilder WithEventEmitter(Func eventEmitterFactory) where TEventEmitter : IEventEmitter { return WithEventEmitter(eventEmitterFactory, delegate(IRegistrationLocationSelectionSyntax w) { w.OnTop(); }); } public StaticSerializerBuilder WithEventEmitter(Func eventEmitterFactory, Action> where) where TEventEmitter : IEventEmitter { Func eventEmitterFactory2 = eventEmitterFactory; return WithEventEmitter((IEventEmitter e, ITypeInspector _) => eventEmitterFactory2(e), where); } public StaticSerializerBuilder WithEventEmitter(Func eventEmitterFactory, Action> where) where TEventEmitter : IEventEmitter { Func eventEmitterFactory2 = eventEmitterFactory; if (eventEmitterFactory2 == null) { throw new ArgumentNullException("eventEmitterFactory"); } if (where == null) { throw new ArgumentNullException("where"); } where(eventEmitterFactories.CreateRegistrationLocationSelector(typeof(TEventEmitter), (IEventEmitter inner) => eventEmitterFactory2(inner, BuildTypeInspector()))); return Self; } public StaticSerializerBuilder WithEventEmitter(WrapperFactory eventEmitterFactory, Action> where) where TEventEmitter : IEventEmitter { WrapperFactory eventEmitterFactory2 = eventEmitterFactory; if (eventEmitterFactory2 == null) { throw new ArgumentNullException("eventEmitterFactory"); } if (where == null) { throw new ArgumentNullException("where"); } where(eventEmitterFactories.CreateTrackingRegistrationLocationSelector(typeof(TEventEmitter), (IEventEmitter wrapped, IEventEmitter inner) => eventEmitterFactory2(wrapped, inner))); return Self; } public StaticSerializerBuilder WithoutEventEmitter() where TEventEmitter : IEventEmitter { return WithoutEventEmitter(typeof(TEventEmitter)); } public StaticSerializerBuilder WithoutEventEmitter(Type eventEmitterType) { if (eventEmitterType == null) { throw new ArgumentNullException("eventEmitterType"); } eventEmitterFactories.Remove(eventEmitterType); return this; } public override StaticSerializerBuilder WithTagMapping(TagName tag, Type type) { if (tag.IsEmpty) { throw new ArgumentException("Non-specific tags cannot be maped"); } if (type == null) { throw new ArgumentNullException("type"); } if (tagMappings.TryGetValue(type, out var value)) { throw new ArgumentException($"Type already has a registered tag '{value}' for type '{type.FullName}'", "type"); } tagMappings.Add(type, tag); return this; } public StaticSerializerBuilder WithoutTagMapping(Type type) { if (type == null) { throw new ArgumentNullException("type"); } if (!tagMappings.Remove(type)) { throw new KeyNotFoundException("Tag for type '" + type.FullName + "' is not registered"); } return this; } public StaticSerializerBuilder EnsureRoundtrip() { objectGraphTraversalStrategyFactory = (ITypeInspector typeInspector, ITypeResolver typeResolver, IEnumerable typeConverters, int maximumRecursion) => new RoundtripObjectGraphTraversalStrategy(typeConverters, typeInspector, typeResolver, maximumRecursion, namingConvention, settings, factory); WithEventEmitter((IEventEmitter inner) => new TypeAssigningEventEmitter(inner, tagMappings, quoteNecessaryStrings, quoteYaml1_1Strings: false, ScalarStyle.Plain, YamlFormatter.Default, enumNamingConvention, BuildTypeInspector()), delegate(IRegistrationLocationSelectionSyntax loc) { loc.InsteadOf(); }); return WithTypeInspector((ITypeInspector inner) => new ReadableAndWritablePropertiesTypeInspector(inner), delegate(IRegistrationLocationSelectionSyntax loc) { loc.OnBottom(); }); } public StaticSerializerBuilder DisableAliases() { preProcessingPhaseObjectGraphVisitorFactories.Remove(typeof(AnchorAssigner)); emissionPhaseObjectGraphVisitorFactories.Remove(typeof(AnchorAssigningObjectGraphVisitor)); return this; } [Obsolete("The default behavior is now to always emit default values, thefore calling this method has no effect. This behavior is now controlled by ConfigureDefaultValuesHandling.", true)] public StaticSerializerBuilder EmitDefaults() { return ConfigureDefaultValuesHandling(DefaultValuesHandling.Preserve); } public StaticSerializerBuilder ConfigureDefaultValuesHandling(DefaultValuesHandling configuration) { defaultValuesHandlingConfiguration = configuration; return this; } public StaticSerializerBuilder JsonCompatible() { emitterSettings = emitterSettings.WithMaxSimpleKeyLength(int.MaxValue).WithoutAnchorName().WithUtf16SurrogatePairs(); return WithTypeConverter(new YamlDotNet.Serialization.Converters.GuidConverter(jsonCompatible: true), delegate(IRegistrationLocationSelectionSyntax w) { w.InsteadOf(); }).WithTypeConverter(new DateTime8601Converter(ScalarStyle.DoubleQuoted)).WithEventEmitter((IEventEmitter inner) => new JsonEventEmitter(inner, yamlFormatter, enumNamingConvention, BuildTypeInspector()), delegate(IRegistrationLocationSelectionSyntax loc) { loc.InsteadOf(); }); } public StaticSerializerBuilder WithNewLine(string newLine) { emitterSettings = emitterSettings.WithNewLine(newLine); return this; } public StaticSerializerBuilder WithPreProcessingPhaseObjectGraphVisitor(TObjectGraphVisitor objectGraphVisitor) where TObjectGraphVisitor : IObjectGraphVisitor { return WithPreProcessingPhaseObjectGraphVisitor(objectGraphVisitor, delegate(IRegistrationLocationSelectionSyntax> w) { w.OnTop(); }); } public StaticSerializerBuilder WithPreProcessingPhaseObjectGraphVisitor(Func, TObjectGraphVisitor> objectGraphVisitorFactory) where TObjectGraphVisitor : IObjectGraphVisitor { return WithPreProcessingPhaseObjectGraphVisitor(objectGraphVisitorFactory, delegate(IRegistrationLocationSelectionSyntax> w) { w.OnTop(); }); } public StaticSerializerBuilder WithPreProcessingPhaseObjectGraphVisitor(TObjectGraphVisitor objectGraphVisitor, Action>> where) where TObjectGraphVisitor : IObjectGraphVisitor { TObjectGraphVisitor objectGraphVisitor2 = objectGraphVisitor; if (objectGraphVisitor2 == null) { throw new ArgumentNullException("objectGraphVisitor"); } if (where == null) { throw new ArgumentNullException("where"); } where(preProcessingPhaseObjectGraphVisitorFactories.CreateRegistrationLocationSelector(typeof(TObjectGraphVisitor), (IEnumerable _) => objectGraphVisitor2)); return this; } public StaticSerializerBuilder WithPreProcessingPhaseObjectGraphVisitor(Func, TObjectGraphVisitor> objectGraphVisitorFactory, Action>> where) where TObjectGraphVisitor : IObjectGraphVisitor { Func, TObjectGraphVisitor> objectGraphVisitorFactory2 = objectGraphVisitorFactory; if (objectGraphVisitorFactory2 == null) { throw new ArgumentNullException("objectGraphVisitorFactory"); } if (where == null) { throw new ArgumentNullException("where"); } where(preProcessingPhaseObjectGraphVisitorFactories.CreateRegistrationLocationSelector(typeof(TObjectGraphVisitor), (IEnumerable typeConverters) => objectGraphVisitorFactory2(typeConverters))); return this; } public StaticSerializerBuilder WithPreProcessingPhaseObjectGraphVisitor(WrapperFactory, TObjectGraphVisitor> objectGraphVisitorFactory, Action>> where) where TObjectGraphVisitor : IObjectGraphVisitor { WrapperFactory, TObjectGraphVisitor> objectGraphVisitorFactory2 = objectGraphVisitorFactory; if (objectGraphVisitorFactory2 == null) { throw new ArgumentNullException("objectGraphVisitorFactory"); } if (where == null) { throw new ArgumentNullException("where"); } where(preProcessingPhaseObjectGraphVisitorFactories.CreateTrackingRegistrationLocationSelector(typeof(TObjectGraphVisitor), (IObjectGraphVisitor wrapped, IEnumerable _) => objectGraphVisitorFactory2(wrapped))); return this; } public StaticSerializerBuilder WithPreProcessingPhaseObjectGraphVisitor(WrapperFactory, IObjectGraphVisitor, TObjectGraphVisitor> objectGraphVisitorFactory, Action>> where) where TObjectGraphVisitor : IObjectGraphVisitor { WrapperFactory, IObjectGraphVisitor, TObjectGraphVisitor> objectGraphVisitorFactory2 = objectGraphVisitorFactory; if (objectGraphVisitorFactory2 == null) { throw new ArgumentNullException("objectGraphVisitorFactory"); } if (where == null) { throw new ArgumentNullException("where"); } where(preProcessingPhaseObjectGraphVisitorFactories.CreateTrackingRegistrationLocationSelector(typeof(TObjectGraphVisitor), (IObjectGraphVisitor wrapped, IEnumerable typeConverters) => objectGraphVisitorFactory2(wrapped, typeConverters))); return this; } public StaticSerializerBuilder WithoutPreProcessingPhaseObjectGraphVisitor() where TObjectGraphVisitor : IObjectGraphVisitor { return WithoutPreProcessingPhaseObjectGraphVisitor(typeof(TObjectGraphVisitor)); } public StaticSerializerBuilder WithoutPreProcessingPhaseObjectGraphVisitor(Type objectGraphVisitorType) { if (objectGraphVisitorType == null) { throw new ArgumentNullException("objectGraphVisitorType"); } preProcessingPhaseObjectGraphVisitorFactories.Remove(objectGraphVisitorType); return this; } public StaticSerializerBuilder WithObjectGraphTraversalStrategyFactory(ObjectGraphTraversalStrategyFactory objectGraphTraversalStrategyFactory) { this.objectGraphTraversalStrategyFactory = objectGraphTraversalStrategyFactory; return this; } public StaticSerializerBuilder WithEmissionPhaseObjectGraphVisitor(Func objectGraphVisitorFactory) where TObjectGraphVisitor : IObjectGraphVisitor { return WithEmissionPhaseObjectGraphVisitor(objectGraphVisitorFactory, delegate(IRegistrationLocationSelectionSyntax> w) { w.OnTop(); }); } public StaticSerializerBuilder WithEmissionPhaseObjectGraphVisitor(Func objectGraphVisitorFactory, Action>> where) where TObjectGraphVisitor : IObjectGraphVisitor { Func objectGraphVisitorFactory2 = objectGraphVisitorFactory; if (objectGraphVisitorFactory2 == null) { throw new ArgumentNullException("objectGraphVisitorFactory"); } if (where == null) { throw new ArgumentNullException("where"); } where(emissionPhaseObjectGraphVisitorFactories.CreateRegistrationLocationSelector(typeof(TObjectGraphVisitor), (EmissionPhaseObjectGraphVisitorArgs args) => objectGraphVisitorFactory2(args))); return this; } public StaticSerializerBuilder WithEmissionPhaseObjectGraphVisitor(WrapperFactory, TObjectGraphVisitor> objectGraphVisitorFactory, Action>> where) where TObjectGraphVisitor : IObjectGraphVisitor { WrapperFactory, TObjectGraphVisitor> objectGraphVisitorFactory2 = objectGraphVisitorFactory; if (objectGraphVisitorFactory2 == null) { throw new ArgumentNullException("objectGraphVisitorFactory"); } if (where == null) { throw new ArgumentNullException("where"); } where(emissionPhaseObjectGraphVisitorFactories.CreateTrackingRegistrationLocationSelector(typeof(TObjectGraphVisitor), (IObjectGraphVisitor wrapped, EmissionPhaseObjectGraphVisitorArgs args) => objectGraphVisitorFactory2(wrapped, args))); return this; } public StaticSerializerBuilder WithoutEmissionPhaseObjectGraphVisitor() where TObjectGraphVisitor : IObjectGraphVisitor { return WithoutEmissionPhaseObjectGraphVisitor(typeof(TObjectGraphVisitor)); } public StaticSerializerBuilder WithoutEmissionPhaseObjectGraphVisitor(Type objectGraphVisitorType) { if (objectGraphVisitorType == null) { throw new ArgumentNullException("objectGraphVisitorType"); } emissionPhaseObjectGraphVisitorFactories.Remove(objectGraphVisitorType); return this; } public StaticSerializerBuilder WithIndentedSequences() { emitterSettings = emitterSettings.WithIndentedSequences(); return this; } public ISerializer Build() { return Serializer.FromValueSerializer(BuildValueSerializer(), emitterSettings); } public IValueSerializer BuildValueSerializer() { IEnumerable typeConverters = BuildTypeConverters(); ITypeInspector typeInspector = BuildTypeInspector(); IObjectGraphTraversalStrategy traversalStrategy = objectGraphTraversalStrategyFactory(typeInspector, typeResolver, typeConverters, maximumRecursion); IEventEmitter eventEmitter = eventEmitterFactories.BuildComponentChain(new WriterEventEmitter()); return new ValueSerializer(traversalStrategy, eventEmitter, typeConverters, preProcessingPhaseObjectGraphVisitorFactories.Clone(), emissionPhaseObjectGraphVisitorFactories.Clone()); } public ITypeInspector BuildTypeInspector() { ITypeInspector typeInspector = context.GetTypeInspector(); return typeInspectorFactories.BuildComponentChain(typeInspector); } } internal sealed class StreamFragment : IYamlConvertible { private readonly List events = new List(); public IList Events => events; void IYamlConvertible.Read(IParser parser, Type expectedType, ObjectDeserializer nestedObjectDeserializer) { events.Clear(); int num = 0; do { if (!parser.MoveNext()) { throw new InvalidOperationException("The parser has reached the end before deserialization completed."); } ParsingEvent current = parser.Current; events.Add(current); num += current.NestingIncrease; } while (num > 0); } void IYamlConvertible.Write(IEmitter emitter, ObjectSerializer nestedObjectSerializer) { foreach (ParsingEvent @event in events) { emitter.Emit(@event); } } } internal sealed class TagMappings { private readonly Dictionary mappings; public TagMappings() { mappings = new Dictionary(); } public TagMappings(IDictionary mappings) { this.mappings = new Dictionary(mappings); } public void Add(string tag, Type mapping) { mappings.Add(tag, mapping); } internal Type? GetMapping(string tag) { if (!mappings.TryGetValue(tag, out Type value)) { return null; } return value; } } internal sealed class YamlAttributeOverrides { private readonly struct AttributeKey { public readonly Type AttributeType; public readonly string PropertyName; public AttributeKey(Type attributeType, string propertyName) { AttributeType = attributeType; PropertyName = propertyName; } public override bool Equals(object? obj) { if (obj is AttributeKey attributeKey && AttributeType.Equals(attributeKey.AttributeType)) { return PropertyName.Equals(attributeKey.PropertyName); } return false; } public override int GetHashCode() { return YamlDotNet.Core.HashCode.CombineHashCodes(AttributeType.GetHashCode(), PropertyName.GetHashCode()); } } private sealed class AttributeMapping { public readonly Type RegisteredType; public readonly Attribute Attribute; public AttributeMapping(Type registeredType, Attribute attribute) { RegisteredType = registeredType; Attribute = attribute; } public override bool Equals(object? obj) { if (obj is AttributeMapping attributeMapping && RegisteredType.Equals(attributeMapping.RegisteredType)) { return Attribute.Equals(attributeMapping.Attribute); } return false; } public override int GetHashCode() { return YamlDotNet.Core.HashCode.CombineHashCodes(RegisteredType.GetHashCode(), Attribute.GetHashCode()); } public int Matches(Type matchType) { int num = 0; Type type = matchType; while (type != null) { num++; if (type == RegisteredType) { return num; } type = type.BaseType(); } if (matchType.GetInterfaces().Contains(RegisteredType)) { return num; } return 0; } } private readonly Dictionary> overrides = new Dictionary>(); [return: MaybeNull] public T GetAttribute(Type type, string member) where T : Attribute { if (overrides.TryGetValue(new AttributeKey(typeof(T), member), out List value)) { int num = 0; AttributeMapping attributeMapping = null; foreach (AttributeMapping item in value) { int num2 = item.Matches(type); if (num2 > num) { num = num2; attributeMapping = item; } } if (num > 0) { return (T)attributeMapping.Attribute; } } return null; } public void Add(Type type, string member, Attribute attribute) { AttributeMapping item = new AttributeMapping(type, attribute); AttributeKey key = new AttributeKey(attribute.GetType(), member); if (!overrides.TryGetValue(key, out List value)) { value = new List(); overrides.Add(key, value); } else if (value.Contains(item)) { throw new InvalidOperationException($"Attribute ({attribute}) already set for Type {type.FullName}, Member {member}"); } value.Add(item); } public YamlAttributeOverrides Clone() { YamlAttributeOverrides yamlAttributeOverrides = new YamlAttributeOverrides(); foreach (KeyValuePair> @override in overrides) { foreach (AttributeMapping item in @override.Value) { yamlAttributeOverrides.Add(item.RegisteredType, @override.Key.PropertyName, item.Attribute); } } return yamlAttributeOverrides; } public void Add(Expression> propertyAccessor, Attribute attribute) { PropertyInfo propertyInfo = propertyAccessor.AsProperty(); Add(typeof(TClass), propertyInfo.Name, attribute); } } internal sealed class YamlAttributeOverridesInspector : ReflectionTypeInspector { public sealed class OverridePropertyDescriptor : IPropertyDescriptor { private readonly IPropertyDescriptor baseDescriptor; private readonly YamlAttributeOverrides overrides; private readonly Type classType; public string Name => baseDescriptor.Name; public bool Required => baseDescriptor.Required; public bool AllowNulls => baseDescriptor.AllowNulls; public bool CanWrite => baseDescriptor.CanWrite; public Type Type => baseDescriptor.Type; public Type? TypeOverride { get { return baseDescriptor.TypeOverride; } set { baseDescriptor.TypeOverride = value; } } public Type? ConverterType => GetCustomAttribute()?.ConverterType ?? baseDescriptor.ConverterType; public int Order { get { return baseDescriptor.Order; } set { baseDescriptor.Order = value; } } public ScalarStyle ScalarStyle { get { return baseDescriptor.ScalarStyle; } set { baseDescriptor.ScalarStyle = value; } } public OverridePropertyDescriptor(IPropertyDescriptor baseDescriptor, YamlAttributeOverrides overrides, Type classType) { this.baseDescriptor = baseDescriptor; this.overrides = overrides; this.classType = classType; } public void Write(object target, object? value) { baseDescriptor.Write(target, value); } public T? GetCustomAttribute() where T : Attribute { T attribute = overrides.GetAttribute(classType, Name); return attribute ?? baseDescriptor.GetCustomAttribute(); } public IObjectDescriptor Read(object target) { return baseDescriptor.Read(target); } } private readonly ITypeInspector innerTypeDescriptor; private readonly YamlAttributeOverrides overrides; public YamlAttributeOverridesInspector(ITypeInspector innerTypeDescriptor, YamlAttributeOverrides overrides) { this.innerTypeDescriptor = innerTypeDescriptor; this.overrides = overrides; } public override IEnumerable GetProperties(Type type, object? container) { Type type2 = type; IEnumerable enumerable = innerTypeDescriptor.GetProperties(type2, container); if (overrides != null) { enumerable = enumerable.Select((Func)((IPropertyDescriptor p) => new OverridePropertyDescriptor(p, overrides, type2))); } return enumerable; } } internal sealed class YamlAttributesTypeInspector : TypeInspectorSkeleton { private readonly ITypeInspector innerTypeDescriptor; public YamlAttributesTypeInspector(ITypeInspector innerTypeDescriptor) { this.innerTypeDescriptor = innerTypeDescriptor; } public override string GetEnumName(Type enumType, string name) { return innerTypeDescriptor.GetEnumName(enumType, name); } public override string GetEnumValue(object enumValue) { return innerTypeDescriptor.GetEnumValue(enumValue); } public override IEnumerable GetProperties(Type type, object? container) { return from p in (from p in innerTypeDescriptor.GetProperties(type, container) where p.GetCustomAttribute() == null select p).Select((Func)delegate(IPropertyDescriptor p) { PropertyDescriptor propertyDescriptor = new PropertyDescriptor(p); YamlMemberAttribute customAttribute = p.GetCustomAttribute(); if (customAttribute != null) { if (customAttribute.SerializeAs != null) { propertyDescriptor.TypeOverride = customAttribute.SerializeAs; } propertyDescriptor.Order = customAttribute.Order; propertyDescriptor.ScalarStyle = customAttribute.ScalarStyle; if (customAttribute.Alias != null) { propertyDescriptor.Name = customAttribute.Alias; } } return propertyDescriptor; }) orderby p.Order select p; } } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] internal sealed class YamlConverterAttribute : Attribute { public Type ConverterType { get; } public YamlConverterAttribute(Type converterType) { ConverterType = converterType; } } internal class YamlFormatter { public static YamlFormatter Default { get; } = new YamlFormatter(); public NumberFormatInfo NumberFormat { get; set; } = new NumberFormatInfo { CurrencyDecimalSeparator = ".", CurrencyGroupSeparator = "_", CurrencyGroupSizes = new int[1] { 3 }, CurrencySymbol = string.Empty, CurrencyDecimalDigits = 99, NumberDecimalSeparator = ".", NumberGroupSeparator = "_", NumberGroupSizes = new int[1] { 3 }, NumberDecimalDigits = 99, NaNSymbol = ".nan", PositiveInfinitySymbol = ".inf", NegativeInfinitySymbol = "-.inf" }; public virtual Func FormatEnum { get; set; } = delegate(object value, ITypeInspector typeInspector, INamingConvention enumNamingConvention) { string empty = string.Empty; empty = ((value != null) ? typeInspector.GetEnumValue(value) : string.Empty); return enumNamingConvention.Apply(empty); }; public virtual Func PotentiallyQuoteEnums { get; set; } = (object _) => true; public string FormatNumber(object number) { return Convert.ToString(number, NumberFormat); } public string FormatNumber(double number) { return number.ToString("G", NumberFormat); } public string FormatNumber(float number) { return number.ToString("G", NumberFormat); } public string FormatBoolean(object boolean) { if (!boolean.Equals(true)) { return "false"; } return "true"; } public string FormatDateTime(object dateTime) { return ((DateTime)dateTime).ToString("o", CultureInfo.InvariantCulture); } public string FormatTimeSpan(object timeSpan) { return ((TimeSpan)timeSpan).ToString(); } } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)] internal sealed class YamlIgnoreAttribute : Attribute { } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)] internal sealed class YamlMemberAttribute : Attribute { private DefaultValuesHandling? defaultValuesHandling; public string? Description { get; set; } public Type? SerializeAs { get; set; } public int Order { get; set; } public string? Alias { get; set; } public bool ApplyNamingConventions { get; set; } public ScalarStyle ScalarStyle { get; set; } public DefaultValuesHandling DefaultValuesHandling { get { return defaultValuesHandling.GetValueOrDefault(); } set { defaultValuesHandling = value; } } public bool IsDefaultValuesHandlingSpecified => defaultValuesHandling.HasValue; public YamlMemberAttribute() { ScalarStyle = ScalarStyle.Any; ApplyNamingConventions = true; } public YamlMemberAttribute(Type serializeAs) : this() { SerializeAs = serializeAs ?? throw new ArgumentNullException("serializeAs"); } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum, Inherited = false, AllowMultiple = true)] internal sealed class YamlSerializableAttribute : Attribute { public YamlSerializableAttribute() { } public YamlSerializableAttribute(Type serializableType) { } } [AttributeUsage(AttributeTargets.Class)] internal sealed class YamlStaticContextAttribute : Attribute { } } namespace YamlDotNet.Serialization.ValueDeserializers { internal sealed class AliasValueDeserializer : IValueDeserializer { private sealed class AliasState : Dictionary, IPostDeserializationCallback { public void OnDeserialization() { foreach (ValuePromise value in base.Values) { if (!value.HasValue) { YamlDotNet.Core.Events.AnchorAlias alias = value.Alias; Mark start = alias.Start; Mark end = alias.End; throw new AnchorNotFoundException(in start, in end, $"Anchor '{alias.Value}' not found"); } } } } private sealed class ValuePromise : IValuePromise { private object? value; public readonly YamlDotNet.Core.Events.AnchorAlias? Alias; public bool HasValue { get; private set; } public object? Value { get { if (!HasValue) { throw new InvalidOperationException("Value not set"); } return value; } set { if (HasValue) { throw new InvalidOperationException("Value already set"); } HasValue = true; this.value = value; this.ValueAvailable?.Invoke(value); } } public event Action? ValueAvailable; public ValuePromise(YamlDotNet.Core.Events.AnchorAlias alias) { Alias = alias; } public ValuePromise(object? value) { HasValue = true; this.value = value; } } private readonly IValueDeserializer innerDeserializer; public AliasValueDeserializer(IValueDeserializer innerDeserializer) { this.innerDeserializer = innerDeserializer ?? throw new ArgumentNullException("innerDeserializer"); } public object? DeserializeValue(IParser parser, Type expectedType, SerializerState state, IValueDeserializer nestedObjectDeserializer) { if (parser.TryConsume(out var @event)) { AliasState aliasState = state.Get(); if (!aliasState.TryGetValue(@event.Value, out ValuePromise value)) { Mark start = @event.Start; Mark end = @event.End; throw new AnchorNotFoundException(in start, in end, $"Alias ${@event.Value} cannot precede anchor declaration"); } if (!value.HasValue) { return value; } return value.Value; } AnchorName anchorName = AnchorName.Empty; if (parser.Accept(out var event2) && !event2.Anchor.IsEmpty) { anchorName = event2.Anchor; AliasState aliasState2 = state.Get(); if (!aliasState2.ContainsKey(anchorName)) { aliasState2[anchorName] = new ValuePromise(new YamlDotNet.Core.Events.AnchorAlias(anchorName)); } } object obj = innerDeserializer.DeserializeValue(parser, expectedType, state, nestedObjectDeserializer); if (!anchorName.IsEmpty) { AliasState aliasState3 = state.Get(); if (!aliasState3.TryGetValue(anchorName, out ValuePromise value2)) { aliasState3.Add(anchorName, new ValuePromise(obj)); } else if (!value2.HasValue) { value2.Value = obj; } else { aliasState3[anchorName] = new ValuePromise(obj); } } return obj; } } internal sealed class NodeValueDeserializer : IValueDeserializer { private readonly IList deserializers; private readonly IList typeResolvers; private readonly ITypeConverter typeConverter; private readonly INamingConvention enumNamingConvention; private readonly ITypeInspector typeInspector; public NodeValueDeserializer(IList deserializers, IList typeResolvers, ITypeConverter typeConverter, INamingConvention enumNamingConvention, ITypeInspector typeInspector) { this.deserializers = deserializers ?? throw new ArgumentNullException("deserializers"); this.typeResolvers = typeResolvers ?? throw new ArgumentNullException("typeResolvers"); this.typeConverter = typeConverter ?? throw new ArgumentNullException("typeConverter"); this.enumNamingConvention = enumNamingConvention ?? throw new ArgumentNullException("enumNamingConvention"); this.typeInspector = typeInspector; } public object? DeserializeValue(IParser parser, Type expectedType, SerializerState state, IValueDeserializer nestedObjectDeserializer) { IParser parser2 = parser; SerializerState state2 = state; IValueDeserializer nestedObjectDeserializer2 = nestedObjectDeserializer; parser2.Accept(out var @event); Type typeFromEvent = GetTypeFromEvent(@event, expectedType); ObjectDeserializer rootDeserializer = (Type x) => DeserializeValue(parser2, x, state2, nestedObjectDeserializer2); Mark start; Mark end; try { foreach (INodeDeserializer deserializer in deserializers) { if (deserializer.Deserialize(parser2, typeFromEvent, (IParser r, Type t) => nestedObjectDeserializer2.DeserializeValue(r, t, state2, nestedObjectDeserializer2), out object value, rootDeserializer)) { return typeConverter.ChangeType(value, expectedType, enumNamingConvention, typeInspector); } } } catch (YamlException) { throw; } catch (Exception innerException) { start = @event?.Start ?? Mark.Empty; end = @event?.End ?? Mark.Empty; throw new YamlException(in start, in end, "Exception during deserialization", innerException); } start = @event?.Start ?? Mark.Empty; end = @event?.End ?? Mark.Empty; throw new YamlException(in start, in end, "No node deserializer was able to deserialize the node into type " + expectedType.AssemblyQualifiedName); } private Type GetTypeFromEvent(NodeEvent? nodeEvent, Type currentType) { foreach (INodeTypeResolver typeResolver in typeResolvers) { if (typeResolver.Resolve(nodeEvent, ref currentType)) { break; } } return currentType; } } } namespace YamlDotNet.Serialization.Utilities { internal interface IPostDeserializationCallback { void OnDeserialization(); } internal interface ITypeConverter { object? ChangeType(object? value, Type expectedType, INamingConvention enumNamingConvention, ITypeInspector typeInspector); } internal class NullTypeConverter : ITypeConverter { public object? ChangeType(object? value, Type expectedType, INamingConvention enumNamingConvention, ITypeInspector typeInspector) { return value; } } internal sealed class ObjectAnchorCollection { private readonly Dictionary objectsByAnchor = new Dictionary(); private readonly Dictionary anchorsByObject = new Dictionary(); public object this[string anchor] { get { if (objectsByAnchor.TryGetValue(anchor, out object value)) { return value; } throw new AnchorNotFoundException("The anchor '" + anchor + "' does not exists"); } } public void Add(string anchor, object @object) { objectsByAnchor.Add(anchor, @object); if (@object != null) { anchorsByObject.Add(@object, anchor); } } public bool TryGetAnchor(object @object, [MaybeNullWhen(false)] out string? anchor) { return anchorsByObject.TryGetValue(@object, out anchor); } } internal class ReflectionTypeConverter : ITypeConverter { public object? ChangeType(object? value, Type expectedType, ITypeInspector typeInspector) { return ChangeType(value, expectedType, NullNamingConvention.Instance, typeInspector); } public object? ChangeType(object? value, Type expectedType, INamingConvention enumNamingConvention, ITypeInspector typeInspector) { return TypeConverter.ChangeType(value, expectedType, enumNamingConvention, typeInspector); } } internal sealed class SerializerState : IDisposable { private readonly Dictionary items = new Dictionary(); public T Get() where T : class, new() { if (!items.TryGetValue(typeof(T), out object value)) { value = new T(); items.Add(typeof(T), value); } return (T)value; } public void OnDeserialization() { foreach (IPostDeserializationCallback item in items.Values.OfType()) { item.OnDeserialization(); } } public void Dispose() { foreach (IDisposable item in items.Values.OfType()) { item.Dispose(); } } } internal static class StringExtensions { private static string ToCamelOrPascalCase(string str, Func firstLetterTransform) { string text = Regex.Replace(str, "([_\\-])(?[a-z])", (Match match) => match.Groups["char"].Value.ToUpperInvariant(), RegexOptions.IgnoreCase); return firstLetterTransform(text[0]) + text.Substring(1); } public static string ToCamelCase(this string str) { return ToCamelOrPascalCase(str, char.ToLowerInvariant); } public static string ToPascalCase(this string str) { return ToCamelOrPascalCase(str, char.ToUpperInvariant); } public static string FromCamelCase(this string str, string separator) { string separator2 = separator; str = char.ToLower(str[0], CultureInfo.InvariantCulture) + str.Substring(1); str = Regex.Replace(str.ToCamelCase(), "(?[A-Z])", (Match match) => separator2 + match.Groups["char"].Value.ToLowerInvariant()); return str; } } internal static class TypeConverter { public static T ChangeType(object? value, INamingConvention enumNamingConvention, ITypeInspector typeInspector) { return (T)ChangeType(value, typeof(T), enumNamingConvention, typeInspector); } public static object? ChangeType(object? value, Type destinationType, INamingConvention enumNamingConvention, ITypeInspector typeInspector) { return ChangeType(value, destinationType, CultureInfo.InvariantCulture, enumNamingConvention, typeInspector); } public static object? ChangeType(object? value, Type destinationType, IFormatProvider provider, INamingConvention enumNamingConvention, ITypeInspector typeInspector) { return ChangeType(value, destinationType, new CultureInfoAdapter(CultureInfo.CurrentCulture, provider), enumNamingConvention, typeInspector); } public static object? ChangeType(object? value, Type destinationType, CultureInfo culture, INamingConvention enumNamingConvention, ITypeInspector typeInspector) { if (value == null || value.IsDbNull()) { if (!destinationType.IsValueType()) { return null; } return Activator.CreateInstance(destinationType); } Type type = value.GetType(); if (destinationType == type || destinationType.IsAssignableFrom(type)) { return value; } if (destinationType.IsGenericType()) { Type genericTypeDefinition = destinationType.GetGenericTypeDefinition(); if (genericTypeDefinition == typeof(Nullable<>) || FsharpHelper.IsOptionType(genericTypeDefinition)) { Type destinationType2 = destinationType.GetGenericArguments()[0]; object obj = ChangeType(value, destinationType2, culture, enumNamingConvention, typeInspector); return Activator.CreateInstance(destinationType, obj); } } if (destinationType.IsEnum()) { object result = value; if (value is string value2) { string name = enumNamingConvention.Reverse(value2); name = typeInspector.GetEnumName(destinationType, name); result = Enum.Parse(destinationType, name, ignoreCase: true); } return result; } if (destinationType == typeof(bool)) { if ("0".Equals(value)) { return false; } if ("1".Equals(value)) { return true; } } System.ComponentModel.TypeConverter converter = TypeDescriptor.GetConverter(type); if (converter != null && converter.CanConvertTo(destinationType)) { return converter.ConvertTo(null, culture, value, destinationType); } System.ComponentModel.TypeConverter converter2 = TypeDescriptor.GetConverter(destinationType); if (converter2 != null && converter2.CanConvertFrom(type)) { return converter2.ConvertFrom(null, culture, value); } Type[] array = new Type[2] { type, destinationType }; foreach (Type type2 in array) { foreach (MethodInfo publicStaticMethod2 in type2.GetPublicStaticMethods()) { if (!publicStaticMethod2.IsSpecialName || (!(publicStaticMethod2.Name == "op_Implicit") && !(publicStaticMethod2.Name == "op_Explicit")) || !destinationType.IsAssignableFrom(publicStaticMethod2.ReturnParameter.ParameterType)) { continue; } ParameterInfo[] parameters = publicStaticMethod2.GetParameters(); if (parameters.Length == 1 && parameters[0].ParameterType.IsAssignableFrom(type)) { try { return publicStaticMethod2.Invoke(null, new object[1] { value }); } catch (TargetInvocationException ex) { throw ex.InnerException; } } } } if (type == typeof(string)) { try { MethodInfo publicStaticMethod = destinationType.GetPublicStaticMethod("Parse", typeof(string), typeof(IFormatProvider)); if (publicStaticMethod != null) { return publicStaticMethod.Invoke(null, new object[2] { value, culture }); } publicStaticMethod = destinationType.GetPublicStaticMethod("Parse", typeof(string)); if (publicStaticMethod != null) { return publicStaticMethod.Invoke(null, new object[1] { value }); } } catch (TargetInvocationException ex2) { throw ex2.InnerException; } } if (destinationType == typeof(TimeSpan)) { return TimeSpan.Parse((string)ChangeType(value, typeof(string), CultureInfo.InvariantCulture, enumNamingConvention, typeInspector), CultureInfo.InvariantCulture); } return Convert.ChangeType(value, destinationType, CultureInfo.InvariantCulture); } public static void RegisterTypeConverter() where TConverter : System.ComponentModel.TypeConverter { if (!TypeDescriptor.GetAttributes(typeof(TConvertible)).OfType().Any((TypeConverterAttribute a) => a.ConverterTypeName == typeof(TConverter).AssemblyQualifiedName)) { TypeDescriptor.AddAttributes(typeof(TConvertible), new TypeConverterAttribute(typeof(TConverter))); } } } internal sealed class TypeConverterCache { private readonly IYamlTypeConverter[] typeConverters; private readonly ConcurrentDictionary cache = new ConcurrentDictionary(); public TypeConverterCache(IEnumerable? typeConverters) : this(typeConverters?.ToArray() ?? Array.Empty()) { } public TypeConverterCache(IYamlTypeConverter[] typeConverters) { this.typeConverters = typeConverters; } public bool TryGetConverterForType(Type type, [NotNullWhen(true)] out IYamlTypeConverter? typeConverter) { (bool, IYamlTypeConverter) orAdd = DictionaryExtensions.GetOrAdd(cache, type, (Type t, IYamlTypeConverter[] tc) => LookupTypeConverter(t, tc), typeConverters); typeConverter = orAdd.Item2; return orAdd.Item1; } public IYamlTypeConverter GetConverterByType(Type converter) { IYamlTypeConverter[] array = typeConverters; foreach (IYamlTypeConverter yamlTypeConverter in array) { if (yamlTypeConverter.GetType() == converter) { return yamlTypeConverter; } } throw new ArgumentException("IYamlTypeConverter of type " + converter.FullName + " not found", "converter"); } private static (bool HasMatch, IYamlTypeConverter? TypeConverter) LookupTypeConverter(Type type, IYamlTypeConverter[] typeConverters) { foreach (IYamlTypeConverter yamlTypeConverter in typeConverters) { if (yamlTypeConverter.Accepts(type)) { return (true, yamlTypeConverter); } } return (false, null); } } } namespace YamlDotNet.Serialization.TypeResolvers { internal sealed class DynamicTypeResolver : ITypeResolver { public Type Resolve(Type staticType, object? actualValue) { if (actualValue == null) { return staticType; } return actualValue.GetType(); } } internal class StaticTypeResolver : ITypeResolver { public virtual Type Resolve(Type staticType, object? actualValue) { if (actualValue != null) { if (actualValue.GetType().IsEnum) { return staticType; } switch (actualValue.GetType().GetTypeCode()) { case TypeCode.Boolean: return typeof(bool); case TypeCode.Char: return typeof(char); case TypeCode.SByte: return typeof(sbyte); case TypeCode.Byte: return typeof(byte); case TypeCode.Int16: return typeof(short); case TypeCode.UInt16: return typeof(ushort); case TypeCode.Int32: return typeof(int); case TypeCode.UInt32: return typeof(uint); case TypeCode.Int64: return typeof(long); case TypeCode.UInt64: return typeof(ulong); case TypeCode.Single: return typeof(float); case TypeCode.Double: return typeof(double); case TypeCode.Decimal: return typeof(decimal); case TypeCode.String: return typeof(string); case TypeCode.DateTime: return typeof(DateTime); } } return staticType; } } } namespace YamlDotNet.Serialization.TypeInspectors { internal class CachedTypeInspector : TypeInspectorSkeleton { private readonly ITypeInspector innerTypeDescriptor; private readonly ConcurrentDictionary> cache = new ConcurrentDictionary>(); private readonly ConcurrentDictionary> enumNameCache = new ConcurrentDictionary>(); private readonly ConcurrentDictionary enumValueCache = new ConcurrentDictionary(); public CachedTypeInspector(ITypeInspector innerTypeDescriptor) { this.innerTypeDescriptor = innerTypeDescriptor ?? throw new ArgumentNullException("innerTypeDescriptor"); } public override string GetEnumName(Type enumType, string name) { ConcurrentDictionary orAdd = enumNameCache.GetOrAdd(enumType, (Type _) => new ConcurrentDictionary()); return DictionaryExtensions.GetOrAdd(orAdd, name, delegate(string n, (Type enumType, ITypeInspector innerTypeDescriptor) context) { var (enumType2, typeInspector) = context; return typeInspector.GetEnumName(enumType2, n); }, (enumType, innerTypeDescriptor)); } public override string GetEnumValue(object enumValue) { return DictionaryExtensions.GetOrAdd(enumValueCache, enumValue, delegate(object _, (object enumValue, ITypeInspector innerTypeDescriptor) context) { var (enumValue2, typeInspector) = context; return typeInspector.GetEnumValue(enumValue2); }, (enumValue, innerTypeDescriptor)); } public override IEnumerable GetProperties(Type type, object? container) { return DictionaryExtensions.GetOrAdd(cache, type, delegate(Type t, (object container, ITypeInspector innerTypeDescriptor) context) { var (container2, typeInspector) = context; return typeInspector.GetProperties(t, container2).ToList(); }, (container, innerTypeDescriptor)); } } internal class CompositeTypeInspector : TypeInspectorSkeleton { private readonly IEnumerable typeInspectors; public CompositeTypeInspector(params ITypeInspector[] typeInspectors) : this((IEnumerable)typeInspectors) { } public CompositeTypeInspector(IEnumerable typeInspectors) { this.typeInspectors = typeInspectors?.ToList() ?? throw new ArgumentNullException("typeInspectors"); } public override string GetEnumName(Type enumType, string name) { foreach (ITypeInspector typeInspector in typeInspectors) { try { return typeInspector.GetEnumName(enumType, name); } catch { } } throw new ArgumentOutOfRangeException("enumType,name", "Name not found on enum type"); } public override string GetEnumValue(object enumValue) { if (enumValue == null) { throw new ArgumentNullException("enumValue"); } foreach (ITypeInspector typeInspector in typeInspectors) { try { return typeInspector.GetEnumValue(enumValue); } catch { } } throw new ArgumentOutOfRangeException("enumValue", $"Value not found for ({enumValue})"); } public override IEnumerable GetProperties(Type type, object? container) { Type type2 = type; object container2 = container; return typeInspectors.SelectMany((ITypeInspector i) => i.GetProperties(type2, container2)); } } internal class NamingConventionTypeInspector : TypeInspectorSkeleton { private readonly ITypeInspector innerTypeDescriptor; private readonly INamingConvention namingConvention; public NamingConventionTypeInspector(ITypeInspector innerTypeDescriptor, INamingConvention namingConvention) { this.innerTypeDescriptor = innerTypeDescriptor ?? throw new ArgumentNullException("innerTypeDescriptor"); this.namingConvention = namingConvention ?? throw new ArgumentNullException("namingConvention"); } public override string GetEnumName(Type enumType, string name) { return innerTypeDescriptor.GetEnumName(enumType, name); } public override string GetEnumValue(object enumValue) { return innerTypeDescriptor.GetEnumValue(enumValue); } public override IEnumerable GetProperties(Type type, object? container) { return innerTypeDescriptor.GetProperties(type, container).Select(delegate(IPropertyDescriptor p) { YamlMemberAttribute customAttribute = p.GetCustomAttribute(); return (customAttribute != null && !customAttribute.ApplyNamingConventions) ? p : new PropertyDescriptor(p) { Name = namingConvention.Apply(p.Name) }; }); } } internal class ReadableAndWritablePropertiesTypeInspector : TypeInspectorSkeleton { private readonly ITypeInspector innerTypeDescriptor; public ReadableAndWritablePropertiesTypeInspector(ITypeInspector innerTypeDescriptor) { this.innerTypeDescriptor = innerTypeDescriptor ?? throw new ArgumentNullException("innerTypeDescriptor"); } public override string GetEnumName(Type enumType, string name) { return innerTypeDescriptor.GetEnumName(enumType, name); } public override string GetEnumValue(object enumValue) { return innerTypeDescriptor.GetEnumValue(enumValue); } public override IEnumerable GetProperties(Type type, object? container) { return from p in innerTypeDescriptor.GetProperties(type, container) where p.CanWrite select p; } } internal class ReadableFieldsTypeInspector : ReflectionTypeInspector { protected class ReflectionFieldDescriptor : IPropertyDescriptor { private readonly FieldInfo fieldInfo; private readonly ITypeResolver typeResolver; public string Name => fieldInfo.Name; public bool Required => fieldInfo.IsRequired(); public Type Type => fieldInfo.FieldType; public Type? ConverterType { get; } public Type? TypeOverride { get; set; } public bool AllowNulls => fieldInfo.AcceptsNull(); public int Order { get; set; } public bool CanWrite => !fieldInfo.IsInitOnly; public ScalarStyle ScalarStyle { get; set; } public ReflectionFieldDescriptor(FieldInfo fieldInfo, ITypeResolver typeResolver) { this.fieldInfo = fieldInfo; this.typeResolver = typeResolver; YamlConverterAttribute customAttribute = fieldInfo.GetCustomAttribute(); if (customAttribute != null) { ConverterType = customAttribute.ConverterType; } ScalarStyle = ScalarStyle.Any; } public void Write(object target, object? value) { fieldInfo.SetValue(target, value); } public T? GetCustomAttribute() where T : Attribute { object[] customAttributes = fieldInfo.GetCustomAttributes(typeof(T), inherit: true); return (T)customAttributes.FirstOrDefault(); } public IObjectDescriptor Read(object target) { object value = fieldInfo.GetValue(target); Type type = TypeOverride ?? typeResolver.Resolve(Type, value); return new ObjectDescriptor(value, type, Type, ScalarStyle); } } private readonly ITypeResolver typeResolver; public ReadableFieldsTypeInspector(ITypeResolver typeResolver) { this.typeResolver = typeResolver ?? throw new ArgumentNullException("typeResolver"); } public override IEnumerable GetProperties(Type type, object? container) { return type.GetPublicFields().Select((Func)((FieldInfo p) => new ReflectionFieldDescriptor(p, typeResolver))); } } internal class ReadablePropertiesTypeInspector : ReflectionTypeInspector { protected class ReflectionPropertyDescriptor : IPropertyDescriptor { private readonly PropertyInfo propertyInfo; private readonly ITypeResolver typeResolver; public string Name => propertyInfo.Name; public bool Required => propertyInfo.IsRequired(); public Type Type => propertyInfo.PropertyType; public Type? TypeOverride { get; set; } public Type? ConverterType { get; set; } public bool AllowNulls => propertyInfo.AcceptsNull(); public int Order { get; set; } public bool CanWrite => propertyInfo.CanWrite; public ScalarStyle ScalarStyle { get; set; } public ReflectionPropertyDescriptor(PropertyInfo propertyInfo, ITypeResolver typeResolver) { this.propertyInfo = propertyInfo ?? throw new ArgumentNullException("propertyInfo"); this.typeResolver = typeResolver ?? throw new ArgumentNullException("typeResolver"); ScalarStyle = ScalarStyle.Any; YamlConverterAttribute customAttribute = propertyInfo.GetCustomAttribute(); if (customAttribute != null) { ConverterType = customAttribute.ConverterType; } } public void Write(object target, object? value) { propertyInfo.SetValue(target, value, null); } public T? GetCustomAttribute() where T : Attribute { Attribute[] allCustomAttributes = propertyInfo.GetAllCustomAttributes(); return (T)allCustomAttributes.FirstOrDefault(); } public IObjectDescriptor Read(object target) { object obj = propertyInfo.ReadValue(target); Type type = TypeOverride ?? typeResolver.Resolve(Type, obj); return new ObjectDescriptor(obj, type, Type, ScalarStyle); } } private readonly ITypeResolver typeResolver; private readonly bool includeNonPublicProperties; public ReadablePropertiesTypeInspector(ITypeResolver typeResolver) : this(typeResolver, includeNonPublicProperties: false) { } public ReadablePropertiesTypeInspector(ITypeResolver typeResolver, bool includeNonPublicProperties) { this.typeResolver = typeResolver ?? throw new ArgumentNullException("typeResolver"); this.includeNonPublicProperties = includeNonPublicProperties; } private static bool IsValidProperty(PropertyInfo property) { if (property.CanRead) { return property.GetGetMethod(nonPublic: true).GetParameters().Length == 0; } return false; } public override IEnumerable GetProperties(Type type, object? container) { return type.GetProperties(includeNonPublicProperties).Where(IsValidProperty).Select((Func)((PropertyInfo p) => new ReflectionPropertyDescriptor(p, typeResolver))); } } internal abstract class ReflectionTypeInspector : TypeInspectorSkeleton { public override string GetEnumName(Type enumType, string name) { return name; } public override string GetEnumValue(object enumValue) { if (enumValue == null) { return string.Empty; } return enumValue.ToString(); } } internal abstract class TypeInspectorSkeleton : ITypeInspector { public abstract string GetEnumName(Type enumType, string name); public abstract string GetEnumValue(object enumValue); public abstract IEnumerable GetProperties(Type type, object? container); public IPropertyDescriptor GetProperty(Type type, object? container, string name, [MaybeNullWhen(true)] bool ignoreUnmatched, bool caseInsensitivePropertyMatching) { string name2 = name; IEnumerable enumerable = ((!caseInsensitivePropertyMatching) ? (from p in GetProperties(type, container) where p.Name == name2 select p) : (from p in GetProperties(type, container) where p.Name.Equals(name2, StringComparison.OrdinalIgnoreCase) select p)); using IEnumerator enumerator = enumerable.GetEnumerator(); if (!enumerator.MoveNext()) { if (ignoreUnmatched) { return null; } throw new SerializationException("Property '" + name2 + "' not found on type '" + type.FullName + "'."); } IPropertyDescriptor current = enumerator.Current; if (enumerator.MoveNext()) { throw new SerializationException("Multiple properties with the name/alias '" + name2 + "' already exists on type '" + type.FullName + "', maybe you're misusing YamlAlias or maybe you are using the wrong naming convention? The matching properties are: " + string.Join(", ", enumerable.Select((IPropertyDescriptor p) => p.Name).ToArray())); } return current; } } internal class WritablePropertiesTypeInspector : ReflectionTypeInspector { protected class ReflectionPropertyDescriptor : IPropertyDescriptor { private readonly PropertyInfo propertyInfo; private readonly ITypeResolver typeResolver; public string Name => propertyInfo.Name; public bool Required => propertyInfo.IsRequired(); public Type Type => propertyInfo.PropertyType; public Type? TypeOverride { get; set; } public Type? ConverterType { get; set; } public bool AllowNulls => propertyInfo.AcceptsNull(); public int Order { get; set; } public bool CanWrite => propertyInfo.CanWrite; public ScalarStyle ScalarStyle { get; set; } public ReflectionPropertyDescriptor(PropertyInfo propertyInfo, ITypeResolver typeResolver) { this.propertyInfo = propertyInfo ?? throw new ArgumentNullException("propertyInfo"); this.typeResolver = typeResolver ?? throw new ArgumentNullException("typeResolver"); ScalarStyle = ScalarStyle.Any; YamlConverterAttribute customAttribute = propertyInfo.GetCustomAttribute(); if (customAttribute != null) { ConverterType = customAttribute.ConverterType; } } public void Write(object target, object? value) { propertyInfo.SetValue(target, value, null); } public T? GetCustomAttribute() where T : Attribute { Attribute[] allCustomAttributes = propertyInfo.GetAllCustomAttributes(); return (T)allCustomAttributes.FirstOrDefault(); } public IObjectDescriptor Read(object target) { object obj = propertyInfo.ReadValue(target); Type type = TypeOverride ?? typeResolver.Resolve(Type, obj); return new ObjectDescriptor(obj, type, Type, ScalarStyle); } } private readonly ITypeResolver typeResolver; private readonly bool includeNonPublicProperties; public WritablePropertiesTypeInspector(ITypeResolver typeResolver) : this(typeResolver, includeNonPublicProperties: false) { } public WritablePropertiesTypeInspector(ITypeResolver typeResolver, bool includeNonPublicProperties) { this.typeResolver = typeResolver ?? throw new ArgumentNullException("typeResolver"); this.includeNonPublicProperties = includeNonPublicProperties; } private static bool IsValidProperty(PropertyInfo property) { if (property.CanWrite) { return property.GetSetMethod(nonPublic: true).GetParameters().Length == 1; } return false; } public override IEnumerable GetProperties(Type type, object? container) { return type.GetProperties(includeNonPublicProperties).Where(IsValidProperty).Select((Func)((PropertyInfo p) => new ReflectionPropertyDescriptor(p, typeResolver))) .ToArray(); } } } namespace YamlDotNet.Serialization.Schemas { internal sealed class FailsafeSchema { public static class Tags { public static readonly TagName Map = new TagName("tag:yaml.org,2002:map"); public static readonly TagName Seq = new TagName("tag:yaml.org,2002:seq"); public static readonly TagName Str = new TagName("tag:yaml.org,2002:str"); } } internal sealed class JsonSchema { public static class Tags { public static readonly TagName Null = new TagName("tag:yaml.org,2002:null"); public static readonly TagName Bool = new TagName("tag:yaml.org,2002:bool"); public static readonly TagName Int = new TagName("tag:yaml.org,2002:int"); public static readonly TagName Float = new TagName("tag:yaml.org,2002:float"); } } internal sealed class CoreSchema { public static class Tags { } } internal sealed class DefaultSchema { public static class Tags { public static readonly TagName Timestamp = new TagName("tag:yaml.org,2002:timestamp"); } } } namespace YamlDotNet.Serialization.ObjectGraphVisitors { internal sealed class AnchorAssigner : PreProcessingPhaseObjectGraphVisitorSkeleton, IAliasProvider { private class AnchorAssignment { public AnchorName Anchor; } private readonly Dictionary assignments = new Dictionary(); private uint nextId; public AnchorAssigner(IEnumerable typeConverters) : base(typeConverters) { } protected override bool Enter(IObjectDescriptor value, ObjectSerializer serializer) { if (value.Value != null && assignments.TryGetValue(value.Value, out AnchorAssignment value2)) { if (value2.Anchor.IsEmpty) { value2.Anchor = new AnchorName("o" + nextId.ToString(CultureInfo.InvariantCulture)); nextId++; } return false; } return true; } protected override bool EnterMapping(IObjectDescriptor key, IObjectDescriptor value, ObjectSerializer serializer) { return true; } protected override bool EnterMapping(IPropertyDescriptor key, IObjectDescriptor value, ObjectSerializer serializer) { return true; } protected override void VisitScalar(IObjectDescriptor scalar, ObjectSerializer serializer) { } protected override void VisitMappingStart(IObjectDescriptor mapping, Type keyType, Type valueType, ObjectSerializer serializer) { VisitObject(mapping); } protected override void VisitMappingEnd(IObjectDescriptor mapping, ObjectSerializer serializer) { } protected override void VisitSequenceStart(IObjectDescriptor sequence, Type elementType, ObjectSerializer serializer) { VisitObject(sequence); } protected override void VisitSequenceEnd(IObjectDescriptor sequence, ObjectSerializer serializer) { } private void VisitObject(IObjectDescriptor value) { if (value.Value != null) { assignments.Add(value.Value, new AnchorAssignment()); } } AnchorName IAliasProvider.GetAlias(object target) { if (target != null && assignments.TryGetValue(target, out AnchorAssignment value)) { return value.Anchor; } return AnchorName.Empty; } } internal sealed class AnchorAssigningObjectGraphVisitor : ChainedObjectGraphVisitor { private readonly IEventEmitter eventEmitter; private readonly IAliasProvider aliasProvider; private readonly HashSet emittedAliases = new HashSet(); public AnchorAssigningObjectGraphVisitor(IObjectGraphVisitor nextVisitor, IEventEmitter eventEmitter, IAliasProvider aliasProvider) : base(nextVisitor) { this.eventEmitter = eventEmitter; this.aliasProvider = aliasProvider; } public override bool Enter(IPropertyDescriptor? propertyDescriptor, IObjectDescriptor value, IEmitter context, ObjectSerializer serializer) { if (value.Value != null) { AnchorName alias = aliasProvider.GetAlias(value.Value); if (!alias.IsEmpty && !emittedAliases.Add(alias)) { AliasEventInfo aliasEventInfo = new AliasEventInfo(value, alias); eventEmitter.Emit(aliasEventInfo, context); return aliasEventInfo.NeedsExpansion; } } return base.Enter(propertyDescriptor, value, context, serializer); } public override void VisitMappingStart(IObjectDescriptor mapping, Type keyType, Type valueType, IEmitter context, ObjectSerializer serializer) { AnchorName alias = aliasProvider.GetAlias(mapping.NonNullValue()); eventEmitter.Emit(new MappingStartEventInfo(mapping) { Anchor = alias }, context); } public override void VisitSequenceStart(IObjectDescriptor sequence, Type elementType, IEmitter context, ObjectSerializer serializer) { AnchorName alias = aliasProvider.GetAlias(sequence.NonNullValue()); eventEmitter.Emit(new SequenceStartEventInfo(sequence) { Anchor = alias }, context); } public override void VisitScalar(IObjectDescriptor scalar, IEmitter context, ObjectSerializer serializer) { ScalarEventInfo scalarEventInfo = new ScalarEventInfo(scalar); if (scalar.Value != null) { scalarEventInfo.Anchor = aliasProvider.GetAlias(scalar.Value); } eventEmitter.Emit(scalarEventInfo, context); } } internal abstract class ChainedObjectGraphVisitor : IObjectGraphVisitor { private readonly IObjectGraphVisitor nextVisitor; protected ChainedObjectGraphVisitor(IObjectGraphVisitor nextVisitor) { this.nextVisitor = nextVisitor; } public virtual bool Enter(IPropertyDescriptor? propertyDescriptor, IObjectDescriptor value, IEmitter context, ObjectSerializer serializer) { return nextVisitor.Enter(propertyDescriptor, value, context, serializer); } public virtual bool EnterMapping(IObjectDescriptor key, IObjectDescriptor value, IEmitter context, ObjectSerializer serializer) { return nextVisitor.EnterMapping(key, value, context, serializer); } public virtual bool EnterMapping(IPropertyDescriptor key, IObjectDescriptor value, IEmitter context, ObjectSerializer serializer) { return nextVisitor.EnterMapping(key, value, context, serializer); } public virtual void VisitScalar(IObjectDescriptor scalar, IEmitter context, ObjectSerializer serializer) { nextVisitor.VisitScalar(scalar, context, serializer); } public virtual void VisitMappingStart(IObjectDescriptor mapping, Type keyType, Type valueType, IEmitter context, ObjectSerializer serializer) { nextVisitor.VisitMappingStart(mapping, keyType, valueType, context, serializer); } public virtual void VisitMappingEnd(IObjectDescriptor mapping, IEmitter context, ObjectSerializer serializer) { nextVisitor.VisitMappingEnd(mapping, context, serializer); } public virtual void VisitSequenceStart(IObjectDescriptor sequence, Type elementType, IEmitter context, ObjectSerializer serializer) { nextVisitor.VisitSequenceStart(sequence, elementType, context, serializer); } public virtual void VisitSequenceEnd(IObjectDescriptor sequence, IEmitter context, ObjectSerializer serializer) { nextVisitor.VisitSequenceEnd(sequence, context, serializer); } } internal sealed class CommentsObjectGraphVisitor : ChainedObjectGraphVisitor { public CommentsObjectGraphVisitor(IObjectGraphVisitor nextVisitor) : base(nextVisitor) { } public override bool EnterMapping(IPropertyDescriptor key, IObjectDescriptor value, IEmitter context, ObjectSerializer serializer) { YamlMemberAttribute customAttribute = key.GetCustomAttribute(); if (customAttribute != null && customAttribute.Description != null) { context.Emit(new YamlDotNet.Core.Events.Comment(customAttribute.Description, isInline: false)); } return base.EnterMapping(key, value, context, serializer); } } internal sealed class CustomSerializationObjectGraphVisitor : ChainedObjectGraphVisitor { private readonly TypeConverterCache typeConverters; private readonly ObjectSerializer nestedObjectSerializer; public CustomSerializationObjectGraphVisitor(IObjectGraphVisitor nextVisitor, IEnumerable typeConverters, ObjectSerializer nestedObjectSerializer) : base(nextVisitor) { this.typeConverters = new TypeConverterCache(typeConverters); this.nestedObjectSerializer = nestedObjectSerializer; } public override bool Enter(IPropertyDescriptor? propertyDescriptor, IObjectDescriptor value, IEmitter context, ObjectSerializer serializer) { if (propertyDescriptor?.ConverterType != null) { IYamlTypeConverter converterByType = typeConverters.GetConverterByType(propertyDescriptor.ConverterType); converterByType.WriteYaml(context, value.Value, value.Type, serializer); return false; } if (typeConverters.TryGetConverterForType(value.Type, out IYamlTypeConverter typeConverter)) { typeConverter.WriteYaml(context, value.Value, value.Type, serializer); return false; } if (value.Value is IYamlConvertible yamlConvertible) { yamlConvertible.Write(context, nestedObjectSerializer); return false; } if (value.Value is IYamlSerializable yamlSerializable) { yamlSerializable.WriteYaml(context); return false; } return base.Enter(propertyDescriptor, value, context, serializer); } } internal sealed class DefaultExclusiveObjectGraphVisitor : ChainedObjectGraphVisitor { public DefaultExclusiveObjectGraphVisitor(IObjectGraphVisitor nextVisitor) : base(nextVisitor) { } private static object? GetDefault(Type type) { if (!type.IsValueType()) { return null; } return Activator.CreateInstance(type); } public override bool EnterMapping(IObjectDescriptor key, IObjectDescriptor value, IEmitter context, ObjectSerializer serializer) { if (!object.Equals(value.Value, GetDefault(value.Type))) { return base.EnterMapping(key, value, context, serializer); } return false; } public override bool EnterMapping(IPropertyDescriptor key, IObjectDescriptor value, IEmitter context, ObjectSerializer serializer) { DefaultValueAttribute customAttribute = key.GetCustomAttribute(); object objB = ((customAttribute != null) ? customAttribute.Value : GetDefault(key.Type)); if (!object.Equals(value.Value, objB)) { return base.EnterMapping(key, value, context, serializer); } return false; } } internal sealed class DefaultValuesObjectGraphVisitor : ChainedObjectGraphVisitor { private readonly DefaultValuesHandling handling; private readonly IObjectFactory factory; public DefaultValuesObjectGraphVisitor(DefaultValuesHandling handling, IObjectGraphVisitor nextVisitor, IObjectFactory factory) : base(nextVisitor) { this.handling = handling; this.factory = factory; } private object? GetDefault(Type type) { return factory.CreatePrimitive(type); } public override bool EnterMapping(IPropertyDescriptor key, IObjectDescriptor value, IEmitter context, ObjectSerializer serializer) { DefaultValuesHandling defaultValuesHandling = handling; YamlMemberAttribute customAttribute = key.GetCustomAttribute(); if (customAttribute != null && customAttribute.IsDefaultValuesHandlingSpecified) { defaultValuesHandling = customAttribute.DefaultValuesHandling; } if ((defaultValuesHandling & DefaultValuesHandling.OmitNull) != 0 && value.Value == null) { return false; } if ((defaultValuesHandling & DefaultValuesHandling.OmitEmptyCollections) != 0 && value.Value is IEnumerable enumerable) { IEnumerator enumerator = enumerable.GetEnumerator(); bool flag = enumerator.MoveNext(); if (enumerator is IDisposable disposable) { disposable.Dispose(); } if (!flag) { return false; } } if ((defaultValuesHandling & DefaultValuesHandling.OmitDefaults) != 0) { object objB = key.GetCustomAttribute()?.Value ?? GetDefault(key.Type); if (object.Equals(value.Value, objB)) { return false; } } return base.EnterMapping(key, value, context, serializer); } } internal sealed class EmittingObjectGraphVisitor : IObjectGraphVisitor { private readonly IEventEmitter eventEmitter; public EmittingObjectGraphVisitor(IEventEmitter eventEmitter) { this.eventEmitter = eventEmitter; } bool IObjectGraphVisitor.Enter(IPropertyDescriptor? propertyDescriptor, IObjectDescriptor value, IEmitter context, ObjectSerializer serializer) { return true; } bool IObjectGraphVisitor.EnterMapping(IObjectDescriptor key, IObjectDescriptor value, IEmitter context, ObjectSerializer serializer) { return true; } bool IObjectGraphVisitor.EnterMapping(IPropertyDescriptor key, IObjectDescriptor value, IEmitter context, ObjectSerializer serializer) { return true; } void IObjectGraphVisitor.VisitScalar(IObjectDescriptor scalar, IEmitter context, ObjectSerializer serializer) { eventEmitter.Emit(new ScalarEventInfo(scalar), context); } void IObjectGraphVisitor.VisitMappingStart(IObjectDescriptor mapping, Type keyType, Type valueType, IEmitter context, ObjectSerializer serializer) { eventEmitter.Emit(new MappingStartEventInfo(mapping), context); } void IObjectGraphVisitor.VisitMappingEnd(IObjectDescriptor mapping, IEmitter context, ObjectSerializer serializer) { eventEmitter.Emit(new MappingEndEventInfo(mapping), context); } void IObjectGraphVisitor.VisitSequenceStart(IObjectDescriptor sequence, Type elementType, IEmitter context, ObjectSerializer serializer) { eventEmitter.Emit(new SequenceStartEventInfo(sequence), context); } void IObjectGraphVisitor.VisitSequenceEnd(IObjectDescriptor sequence, IEmitter context, ObjectSerializer serializer) { eventEmitter.Emit(new SequenceEndEventInfo(sequence), context); } } internal abstract class PreProcessingPhaseObjectGraphVisitorSkeleton : IObjectGraphVisitor { protected readonly IEnumerable typeConverters; private readonly TypeConverterCache typeConverterCache; public PreProcessingPhaseObjectGraphVisitorSkeleton(IEnumerable typeConverters) { typeConverterCache = new TypeConverterCache((IYamlTypeConverter[])(this.typeConverters = typeConverters?.ToArray() ?? Array.Empty())); } bool IObjectGraphVisitor.Enter(IPropertyDescriptor? propertyDescriptor, IObjectDescriptor value, Nothing context, ObjectSerializer serializer) { if (typeConverterCache.TryGetConverterForType(value.Type, out IYamlTypeConverter _)) { return false; } if (value.Value is IYamlConvertible) { return false; } if (value.Value is IYamlSerializable) { return false; } return Enter(value, serializer); } bool IObjectGraphVisitor.EnterMapping(IPropertyDescriptor key, IObjectDescriptor value, Nothing context, ObjectSerializer serializer) { return EnterMapping(key, value, serializer); } bool IObjectGraphVisitor.EnterMapping(IObjectDescriptor key, IObjectDescriptor value, Nothing context, ObjectSerializer serializer) { return EnterMapping(key, value, serializer); } void IObjectGraphVisitor.VisitMappingEnd(IObjectDescriptor mapping, Nothing context, ObjectSerializer serializer) { VisitMappingEnd(mapping, serializer); } void IObjectGraphVisitor.VisitMappingStart(IObjectDescriptor mapping, Type keyType, Type valueType, Nothing context, ObjectSerializer serializer) { VisitMappingStart(mapping, keyType, valueType, serializer); } void IObjectGraphVisitor.VisitScalar(IObjectDescriptor scalar, Nothing context, ObjectSerializer serializer) { VisitScalar(scalar, serializer); } void IObjectGraphVisitor.VisitSequenceEnd(IObjectDescriptor sequence, Nothing context, ObjectSerializer serializer) { VisitSequenceEnd(sequence, serializer); } void IObjectGraphVisitor.VisitSequenceStart(IObjectDescriptor sequence, Type elementType, Nothing context, ObjectSerializer serializer) { VisitSequenceStart(sequence, elementType, serializer); } protected abstract bool Enter(IObjectDescriptor value, ObjectSerializer serializer); protected abstract bool EnterMapping(IPropertyDescriptor key, IObjectDescriptor value, ObjectSerializer serializer); protected abstract bool EnterMapping(IObjectDescriptor key, IObjectDescriptor value, ObjectSerializer serializer); protected abstract void VisitMappingEnd(IObjectDescriptor mapping, ObjectSerializer serializer); protected abstract void VisitMappingStart(IObjectDescriptor mapping, Type keyType, Type valueType, ObjectSerializer serializer); protected abstract void VisitScalar(IObjectDescriptor scalar, ObjectSerializer serializer); protected abstract void VisitSequenceEnd(IObjectDescriptor sequence, ObjectSerializer serializer); protected abstract void VisitSequenceStart(IObjectDescriptor sequence, Type elementType, ObjectSerializer serializer); } } namespace YamlDotNet.Serialization.ObjectGraphTraversalStrategies { internal class FullObjectGraphTraversalStrategy : IObjectGraphTraversalStrategy { protected readonly struct ObjectPathSegment { public readonly object Name; public readonly IObjectDescriptor Value; public ObjectPathSegment(object name, IObjectDescriptor value) { Name = name; Value = value; } } private readonly int maxRecursion; private readonly ITypeInspector typeDescriptor; private readonly ITypeResolver typeResolver; private readonly INamingConvention namingConvention; private readonly IObjectFactory objectFactory; public FullObjectGraphTraversalStrategy(ITypeInspector typeDescriptor, ITypeResolver typeResolver, int maxRecursion, INamingConvention namingConvention, IObjectFactory objectFactory) { if (maxRecursion <= 0) { throw new ArgumentOutOfRangeException("maxRecursion", maxRecursion, "maxRecursion must be greater than 1"); } this.typeDescriptor = typeDescriptor ?? throw new ArgumentNullException("typeDescriptor"); this.typeResolver = typeResolver ?? throw new ArgumentNullException("typeResolver"); this.maxRecursion = maxRecursion; this.namingConvention = namingConvention ?? throw new ArgumentNullException("namingConvention"); this.objectFactory = objectFactory ?? throw new ArgumentNullException("objectFactory"); } void IObjectGraphTraversalStrategy.Traverse(IObjectDescriptor graph, IObjectGraphVisitor visitor, TContext context, ObjectSerializer serializer) { Traverse(null, "", graph, visitor, context, new Stack(maxRecursion), serializer); } protected virtual void Traverse(IPropertyDescriptor? propertyDescriptor, object name, IObjectDescriptor value, IObjectGraphVisitor visitor, TContext context, Stack path, ObjectSerializer serializer) { if (path.Count >= maxRecursion) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("Too much recursion when traversing the object graph."); stringBuilder.AppendLine("The path to reach this recursion was:"); Stack> stack = new Stack>(path.Count); int num = 0; foreach (ObjectPathSegment item in path) { string text = item.Name?.ToString() ?? string.Empty; num = Math.Max(num, text.Length); stack.Push(new KeyValuePair(text, item.Value.Type.FullName)); } foreach (KeyValuePair item2 in stack) { stringBuilder.Append(" -> ").Append(item2.Key.PadRight(num)).Append(" [") .Append(item2.Value) .AppendLine("]"); } throw new MaximumRecursionLevelReachedException(stringBuilder.ToString()); } if (!visitor.Enter(propertyDescriptor, value, context, serializer)) { return; } path.Push(new ObjectPathSegment(name, value)); try { TypeCode typeCode = value.Type.GetTypeCode(); switch (typeCode) { case TypeCode.Boolean: case TypeCode.Char: case TypeCode.SByte: case TypeCode.Byte: case TypeCode.Int16: case TypeCode.UInt16: case TypeCode.Int32: case TypeCode.UInt32: case TypeCode.Int64: case TypeCode.UInt64: case TypeCode.Single: case TypeCode.Double: case TypeCode.Decimal: case TypeCode.DateTime: case TypeCode.String: visitor.VisitScalar(value, context, serializer); return; case TypeCode.Empty: throw new NotSupportedException($"TypeCode.{typeCode} is not supported."); } if (value.IsDbNull()) { visitor.VisitScalar(new ObjectDescriptor(null, typeof(object), typeof(object)), context, serializer); } if (value.Value == null || value.Type == typeof(TimeSpan)) { visitor.VisitScalar(value, context, serializer); return; } Type underlyingType = Nullable.GetUnderlyingType(value.Type); Type type = underlyingType ?? FsharpHelper.GetOptionUnderlyingType(value.Type); object obj = ((type != null) ? FsharpHelper.GetValue(value) : null); if (underlyingType != null) { Traverse(propertyDescriptor, "Value", new ObjectDescriptor(value.Value, underlyingType, value.Type, value.ScalarStyle), visitor, context, path, serializer); } else if (type != null && obj != null) { Traverse(propertyDescriptor, "Value", new ObjectDescriptor(FsharpHelper.GetValue(value), type, value.Type, value.ScalarStyle), visitor, context, path, serializer); } else { TraverseObject(propertyDescriptor, value, visitor, context, path, serializer); } } finally { path.Pop(); } } protected virtual void TraverseObject(IPropertyDescriptor? propertyDescriptor, IObjectDescriptor value, IObjectGraphVisitor visitor, TContext context, Stack path, ObjectSerializer serializer) { IDictionary dictionary; Type[] genericArguments; if (typeof(IDictionary).IsAssignableFrom(value.Type)) { TraverseDictionary(propertyDescriptor, value, visitor, typeof(object), typeof(object), context, path, serializer); } else if (objectFactory.GetDictionary(value, out dictionary, out genericArguments)) { TraverseDictionary(propertyDescriptor, new ObjectDescriptor(dictionary, value.Type, value.StaticType, value.ScalarStyle), visitor, genericArguments[0], genericArguments[1], context, path, serializer); } else if (typeof(IEnumerable).IsAssignableFrom(value.Type)) { TraverseList(propertyDescriptor, value, visitor, context, path, serializer); } else { TraverseProperties(value, visitor, context, path, serializer); } } protected virtual void TraverseDictionary(IPropertyDescriptor? propertyDescriptor, IObjectDescriptor dictionary, IObjectGraphVisitor visitor, Type keyType, Type valueType, TContext context, Stack path, ObjectSerializer serializer) { visitor.VisitMappingStart(dictionary, keyType, valueType, context, serializer); bool flag = dictionary.Type.FullName.Equals("System.Dynamic.ExpandoObject"); foreach (DictionaryEntry? item in (IDictionary)dictionary.NonNullValue()) { DictionaryEntry value = item.Value; object obj = (flag ? namingConvention.Apply(value.Key.ToString()) : value.Key); ObjectDescriptor objectDescriptor = GetObjectDescriptor(obj, keyType); ObjectDescriptor objectDescriptor2 = GetObjectDescriptor(value.Value, valueType); if (visitor.EnterMapping(objectDescriptor, objectDescriptor2, context, serializer)) { Traverse(propertyDescriptor, obj, objectDescriptor, visitor, context, path, serializer); Traverse(propertyDescriptor, obj, objectDescriptor2, visitor, context, path, serializer); } } visitor.VisitMappingEnd(dictionary, context, serializer); } private void TraverseList(IPropertyDescriptor propertyDescriptor, IObjectDescriptor value, IObjectGraphVisitor visitor, TContext context, Stack path, ObjectSerializer serializer) { Type valueType = objectFactory.GetValueType(value.Type); visitor.VisitSequenceStart(value, valueType, context, serializer); int num = 0; foreach (object item in (IEnumerable)value.NonNullValue()) { Traverse(propertyDescriptor, num, GetObjectDescriptor(item, valueType), visitor, context, path, serializer); num++; } visitor.VisitSequenceEnd(value, context, serializer); } protected virtual void TraverseProperties(IObjectDescriptor value, IObjectGraphVisitor visitor, TContext context, Stack path, ObjectSerializer serializer) { if (context.GetType() != typeof(Nothing)) { objectFactory.ExecuteOnSerializing(value.Value); } visitor.VisitMappingStart(value, typeof(string), typeof(object), context, serializer); object obj = value.NonNullValue(); foreach (IPropertyDescriptor property in typeDescriptor.GetProperties(value.Type, obj)) { IObjectDescriptor value2 = property.Read(obj); if (visitor.EnterMapping(property, value2, context, serializer)) { Traverse(null, property.Name, new ObjectDescriptor(property.Name, typeof(string), typeof(string), ScalarStyle.Plain), visitor, context, path, serializer); Traverse(property, property.Name, value2, visitor, context, path, serializer); } } visitor.VisitMappingEnd(value, context, serializer); if (context.GetType() != typeof(Nothing)) { objectFactory.ExecuteOnSerialized(value.Value); } } private ObjectDescriptor GetObjectDescriptor(object? value, Type staticType) { return new ObjectDescriptor(value, typeResolver.Resolve(staticType, value), staticType); } } internal class RoundtripObjectGraphTraversalStrategy : FullObjectGraphTraversalStrategy { private readonly TypeConverterCache converters; private readonly Settings settings; public RoundtripObjectGraphTraversalStrategy(IEnumerable converters, ITypeInspector typeDescriptor, ITypeResolver typeResolver, int maxRecursion, INamingConvention namingConvention, Settings settings, IObjectFactory factory) : base(typeDescriptor, typeResolver, maxRecursion, namingConvention, factory) { this.converters = new TypeConverterCache(converters); this.settings = settings; } protected override void TraverseProperties(IObjectDescriptor value, IObjectGraphVisitor visitor, TContext context, Stack path, ObjectSerializer serializer) { if (!value.Type.HasDefaultConstructor(settings.AllowPrivateConstructors) && !converters.TryGetConverterForType(value.Type, out IYamlTypeConverter _)) { throw new InvalidOperationException($"Type '{value.Type}' cannot be deserialized because it does not have a default constructor or a type converter."); } base.TraverseProperties(value, visitor, context, path, serializer); } } } namespace YamlDotNet.Serialization.ObjectFactories { internal class DefaultObjectFactory : ObjectFactoryBase { private readonly Dictionary> stateMethods = new Dictionary> { { typeof(YamlDotNet.Serialization.Callbacks.OnDeserializedAttribute), new ConcurrentDictionary() }, { typeof(YamlDotNet.Serialization.Callbacks.OnDeserializingAttribute), new ConcurrentDictionary() }, { typeof(YamlDotNet.Serialization.Callbacks.OnSerializedAttribute), new ConcurrentDictionary() }, { typeof(YamlDotNet.Serialization.Callbacks.OnSerializingAttribute), new ConcurrentDictionary() } }; private readonly Dictionary defaultGenericInterfaceImplementations = new Dictionary { { typeof(IEnumerable<>), typeof(List<>) }, { typeof(ICollection<>), typeof(List<>) }, { typeof(IList<>), typeof(List<>) }, { typeof(IDictionary<, >), typeof(Dictionary<, >) } }; private readonly Dictionary defaultNonGenericInterfaceImplementations = new Dictionary { { typeof(IEnumerable), typeof(List) }, { typeof(ICollection), typeof(List) }, { typeof(IList), typeof(List) }, { typeof(IDictionary), typeof(Dictionary) } }; private readonly Settings settings; public DefaultObjectFactory() : this(new Dictionary(), new Settings()) { } public DefaultObjectFactory(IDictionary mappings) : this(mappings, new Settings()) { } public DefaultObjectFactory(IDictionary mappings, Settings settings) { foreach (KeyValuePair mapping in mappings) { if (!mapping.Key.IsAssignableFrom(mapping.Value)) { throw new InvalidOperationException($"Type '{mapping.Value}' does not implement type '{mapping.Key}'."); } defaultNonGenericInterfaceImplementations.Add(mapping.Key, mapping.Value); } this.settings = settings; } public override object Create(Type type) { if (type.IsInterface()) { Type value2; if (type.IsGenericType()) { if (defaultGenericInterfaceImplementations.TryGetValue(type.GetGenericTypeDefinition(), out Type value)) { type = value.MakeGenericType(type.GetGenericArguments()); } } else if (defaultNonGenericInterfaceImplementations.TryGetValue(type, out value2)) { type = value2; } } try { return Activator.CreateInstance(type, settings.AllowPrivateConstructors); } catch (Exception innerException) { string message = "Failed to create an instance of type '" + type.FullName + "'."; throw new InvalidOperationException(message, innerException); } } public override void ExecuteOnDeserialized(object value) { ExecuteState(typeof(YamlDotNet.Serialization.Callbacks.OnDeserializedAttribute), value); } public override void ExecuteOnDeserializing(object value) { ExecuteState(typeof(YamlDotNet.Serialization.Callbacks.OnDeserializingAttribute), value); } public override void ExecuteOnSerialized(object value) { ExecuteState(typeof(YamlDotNet.Serialization.Callbacks.OnSerializedAttribute), value); } public override void ExecuteOnSerializing(object value) { ExecuteState(typeof(YamlDotNet.Serialization.Callbacks.OnSerializingAttribute), value); } private void ExecuteState(Type attributeType, object value) { if (value != null) { Type type = value.GetType(); MethodInfo[] array = GetStateMethods(attributeType, type); MethodInfo[] array2 = array; foreach (MethodInfo methodInfo in array2) { methodInfo.Invoke(value, null); } } } private MethodInfo[] GetStateMethods(Type attributeType, Type valueType) { Type attributeType2 = attributeType; ConcurrentDictionary concurrentDictionary = stateMethods[attributeType2]; return concurrentDictionary.GetOrAdd(valueType, delegate(Type type) { MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); return methods.Where((MethodInfo x) => x.GetCustomAttributes(attributeType2, inherit: true).Length != 0).ToArray(); }); } } internal sealed class LambdaObjectFactory : ObjectFactoryBase { private readonly Func factory; public LambdaObjectFactory(Func factory) { this.factory = factory ?? throw new ArgumentNullException("factory"); } public override object Create(Type type) { return factory(type); } } internal abstract class ObjectFactoryBase : IObjectFactory { public abstract object Create(Type type); public virtual object? CreatePrimitive(Type type) { if (!type.IsValueType()) { return null; } return Activator.CreateInstance(type); } public virtual void ExecuteOnDeserialized(object value) { } public virtual void ExecuteOnDeserializing(object value) { } public virtual void ExecuteOnSerialized(object value) { } public virtual void ExecuteOnSerializing(object value) { } public virtual bool GetDictionary(IObjectDescriptor descriptor, out IDictionary? dictionary, out Type[]? genericArguments) { Type implementationOfOpenGenericInterface = descriptor.Type.GetImplementationOfOpenGenericInterface(typeof(IDictionary<, >)); if (implementationOfOpenGenericInterface != null) { genericArguments = implementationOfOpenGenericInterface.GetGenericArguments(); object obj = Activator.CreateInstance(typeof(GenericDictionaryToNonGenericAdapter<, >).MakeGenericType(genericArguments), descriptor.Value); dictionary = obj as IDictionary; return true; } genericArguments = null; dictionary = null; return false; } public virtual Type GetValueType(Type type) { Type implementationOfOpenGenericInterface = type.GetImplementationOfOpenGenericInterface(typeof(IEnumerable<>)); return (implementationOfOpenGenericInterface != null) ? implementationOfOpenGenericInterface.GetGenericArguments()[0] : typeof(object); } } internal abstract class StaticObjectFactory : IObjectFactory { public abstract object Create(Type type); public abstract Array CreateArray(Type type, int count); public abstract bool IsDictionary(Type type); public abstract bool IsArray(Type type); public abstract bool IsList(Type type); public abstract Type GetKeyType(Type type); public abstract Type GetValueType(Type type); public virtual object? CreatePrimitive(Type type) { return Type.GetTypeCode(type) switch { TypeCode.Boolean => false, TypeCode.Byte => (byte)0, TypeCode.Int16 => (short)0, TypeCode.Int32 => 0, TypeCode.Int64 => 0L, TypeCode.SByte => (sbyte)0, TypeCode.UInt16 => (ushort)0, TypeCode.UInt32 => 0u, TypeCode.UInt64 => 0uL, TypeCode.Single => 0f, TypeCode.Double => 0.0, TypeCode.Decimal => 0m, TypeCode.Char => '\0', TypeCode.DateTime => default(DateTime), _ => null, }; } public bool GetDictionary(IObjectDescriptor descriptor, out IDictionary? dictionary, out Type[]? genericArguments) { dictionary = null; genericArguments = null; return false; } public abstract void ExecuteOnDeserializing(object value); public abstract void ExecuteOnDeserialized(object value); public abstract void ExecuteOnSerializing(object value); public abstract void ExecuteOnSerialized(object value); } } namespace YamlDotNet.Serialization.NodeTypeResolvers { internal sealed class DefaultContainersNodeTypeResolver : INodeTypeResolver { bool INodeTypeResolver.Resolve(NodeEvent? nodeEvent, ref Type currentType) { if (currentType == typeof(object)) { if (nodeEvent is SequenceStart) { currentType = typeof(List); return true; } if (nodeEvent is MappingStart) { currentType = typeof(Dictionary); return true; } } return false; } } internal class MappingNodeTypeResolver : INodeTypeResolver { private readonly IDictionary mappings; public MappingNodeTypeResolver(IDictionary mappings) { if (mappings == null) { throw new ArgumentNullException("mappings"); } foreach (KeyValuePair mapping in mappings) { if (!mapping.Key.IsAssignableFrom(mapping.Value)) { throw new InvalidOperationException($"Type '{mapping.Value}' does not implement type '{mapping.Key}'."); } } this.mappings = mappings; } public bool Resolve(NodeEvent? nodeEvent, ref Type currentType) { if (mappings.TryGetValue(currentType, out Type value)) { currentType = value; return true; } return false; } } internal class PreventUnknownTagsNodeTypeResolver : INodeTypeResolver { bool INodeTypeResolver.Resolve(NodeEvent? nodeEvent, ref Type currentType) { if (nodeEvent != null && !nodeEvent.Tag.IsEmpty) { Mark start = nodeEvent.Start; Mark end = nodeEvent.End; throw new YamlException(in start, in end, $"Encountered an unresolved tag '{nodeEvent.Tag}'"); } return false; } } internal sealed class TagNodeTypeResolver : INodeTypeResolver { private readonly IDictionary tagMappings; public TagNodeTypeResolver(IDictionary tagMappings) { this.tagMappings = tagMappings ?? throw new ArgumentNullException("tagMappings"); } bool INodeTypeResolver.Resolve(NodeEvent? nodeEvent, ref Type currentType) { if (nodeEvent != null && !nodeEvent.Tag.IsEmpty && tagMappings.TryGetValue(nodeEvent.Tag, out Type value)) { currentType = value; return true; } return false; } } [Obsolete("The mechanism that this class uses to specify type names is non-standard. Register the tags explicitly instead of using this convention.")] internal sealed class TypeNameInTagNodeTypeResolver : INodeTypeResolver { bool INodeTypeResolver.Resolve(NodeEvent? nodeEvent, ref Type currentType) { if (nodeEvent != null && !nodeEvent.Tag.IsEmpty) { Type type = Type.GetType(nodeEvent.Tag.Value.Substring(1), throwOnError: false); if (type != null) { currentType = type; return true; } } return false; } } internal sealed class YamlConvertibleTypeResolver : INodeTypeResolver { public bool Resolve(NodeEvent? nodeEvent, ref Type currentType) { return typeof(IYamlConvertible).IsAssignableFrom(currentType); } } internal sealed class YamlSerializableTypeResolver : INodeTypeResolver { public bool Resolve(NodeEvent? nodeEvent, ref Type currentType) { return typeof(IYamlSerializable).IsAssignableFrom(currentType); } } } namespace YamlDotNet.Serialization.NodeDeserializers { internal sealed class ArrayNodeDeserializer : INodeDeserializer { private sealed class ArrayList : IList, ICollection, IEnumerable { private object?[] data; public bool IsFixedSize => false; public bool IsReadOnly => false; public object? this[int index] { get { return data[index]; } set { data[index] = value; } } public int Count { get; private set; } public bool IsSynchronized => false; public object SyncRoot => data; public ArrayList() { Clear(); } public int Add(object? value) { if (Count == data.Length) { Array.Resize(ref data, data.Length * 2); } data[Count] = value; return Count++; } public void Clear() { data = new object[10]; Count = 0; } bool IList.Contains(object? value) { throw new NotSupportedException(); } int IList.IndexOf(object? value) { throw new NotSupportedException(); } void IList.Insert(int index, object? value) { throw new NotSupportedException(); } void IList.Remove(object? value) { throw new NotSupportedException(); } void IList.RemoveAt(int index) { throw new NotSupportedException(); } public void CopyTo(Array array, int index) { Array.Copy(data, 0, array, index, Count); } public IEnumerator GetEnumerator() { int i = 0; while (i < Count) { yield return data[i]; int num = i + 1; i = num; } } } private readonly INamingConvention enumNamingConvention; private readonly ITypeInspector typeInspector; public ArrayNodeDeserializer(INamingConvention enumNamingConvention, ITypeInspector typeInspector) { this.enumNamingConvention = enumNamingConvention; this.typeInspector = typeInspector; } public bool Deserialize(IParser parser, Type expectedType, Func nestedObjectDeserializer, out object? value, ObjectDeserializer rootDeserializer) { if (!expectedType.IsArray) { value = false; return false; } Type itemType = expectedType.GetElementType(); ArrayList arrayList = new ArrayList(); Array array = null; CollectionNodeDeserializer.DeserializeHelper(itemType, parser, nestedObjectDeserializer, arrayList, canUpdate: true, enumNamingConvention, typeInspector, PromiseResolvedHandler); array = Array.CreateInstance(itemType, arrayList.Count); arrayList.CopyTo(array, 0); value = array; return true; void PromiseResolvedHandler(int index, object? value) { if (array == null) { throw new InvalidOperationException("Destination array is still null"); } array.SetValue(YamlDotNet.Serialization.Utilities.TypeConverter.ChangeType(value, itemType, enumNamingConvention, typeInspector), index); } } } internal abstract class CollectionDeserializer { protected static void DeserializeHelper(Type tItem, IParser parser, Func nestedObjectDeserializer, IList result, bool canUpdate, IObjectFactory objectFactory) { IList result2 = result; parser.Consume(); SequenceEnd @event; while (!parser.TryConsume(out @event)) { ParsingEvent current = parser.Current; object obj = nestedObjectDeserializer(parser, tItem); if (obj is IValuePromise valuePromise) { if (!canUpdate) { Mark start = current?.Start ?? Mark.Empty; Mark end = current?.End ?? Mark.Empty; throw new ForwardAnchorNotSupportedException(in start, in end, "Forward alias references are not allowed because this type does not implement IList<>"); } int index = result2.Add(objectFactory.CreatePrimitive(tItem)); valuePromise.ValueAvailable += delegate(object? v) { result2[index] = v; }; } else { result2.Add(obj); } } } } internal sealed class CollectionNodeDeserializer : INodeDeserializer { private readonly IObjectFactory objectFactory; private readonly INamingConvention enumNamingConvention; private readonly ITypeInspector typeInspector; public CollectionNodeDeserializer(IObjectFactory objectFactory, INamingConvention enumNamingConvention, ITypeInspector typeInspector) { this.objectFactory = objectFactory ?? throw new ArgumentNullException("objectFactory"); this.enumNamingConvention = enumNamingConvention; this.typeInspector = typeInspector; } public bool Deserialize(IParser parser, Type expectedType, Func nestedObjectDeserializer, out object? value, ObjectDeserializer rootDeserializer) { bool canUpdate = true; Type implementationOfOpenGenericInterface = expectedType.GetImplementationOfOpenGenericInterface(typeof(ICollection<>)); Type type; IList list; if (implementationOfOpenGenericInterface != null) { Type[] genericArguments = implementationOfOpenGenericInterface.GetGenericArguments(); type = genericArguments[0]; value = objectFactory.Create(expectedType); list = value as IList; if (list == null) { Type implementationOfOpenGenericInterface2 = expectedType.GetImplementationOfOpenGenericInterface(typeof(IList<>)); canUpdate = implementationOfOpenGenericInterface2 != null; list = (IList)Activator.CreateInstance(typeof(GenericCollectionToNonGenericAdapter<>).MakeGenericType(type), value); } } else { if (!typeof(IList).IsAssignableFrom(expectedType)) { value = null; return false; } type = typeof(object); value = objectFactory.Create(expectedType); list = (IList)value; } DeserializeHelper(type, parser, nestedObjectDeserializer, list, canUpdate, enumNamingConvention, typeInspector); return true; } internal static void DeserializeHelper(Type tItem, IParser parser, Func nestedObjectDeserializer, IList result, bool canUpdate, INamingConvention enumNamingConvention, ITypeInspector typeInspector, Action? promiseResolvedHandler = null) { Action promiseResolvedHandler2 = promiseResolvedHandler; IList result2 = result; Type tItem2 = tItem; INamingConvention enumNamingConvention2 = enumNamingConvention; ITypeInspector typeInspector2 = typeInspector; parser.Consume(); SequenceEnd @event; while (!parser.TryConsume(out @event)) { ParsingEvent current = parser.Current; object obj = nestedObjectDeserializer(parser, tItem2); if (obj is IValuePromise valuePromise) { if (!canUpdate) { Mark start = current?.Start ?? Mark.Empty; Mark end = current?.End ?? Mark.Empty; throw new ForwardAnchorNotSupportedException(in start, in end, "Forward alias references are not allowed because this type does not implement IList<>"); } int index = result2.Add(tItem2.IsValueType() ? Activator.CreateInstance(tItem2) : null); if (promiseResolvedHandler2 != null) { valuePromise.ValueAvailable += delegate(object? v) { promiseResolvedHandler2(index, v); }; } else { valuePromise.ValueAvailable += delegate(object? v) { result2[index] = YamlDotNet.Serialization.Utilities.TypeConverter.ChangeType(v, tItem2, enumNamingConvention2, typeInspector2); }; } } else { result2.Add(YamlDotNet.Serialization.Utilities.TypeConverter.ChangeType(obj, tItem2, enumNamingConvention2, typeInspector2)); } } } } internal abstract class DictionaryDeserializer { private readonly bool duplicateKeyChecking; public DictionaryDeserializer(bool duplicateKeyChecking) { this.duplicateKeyChecking = duplicateKeyChecking; } private void TryAssign(IDictionary result, object key, object value, MappingStart propertyName) { if (duplicateKeyChecking && result.Contains(key)) { Mark start = propertyName.Start; Mark end = propertyName.End; throw new YamlException(in start, in end, $"Encountered duplicate key {key}"); } result[key] = value; } protected virtual void Deserialize(Type tKey, Type tValue, IParser parser, Func nestedObjectDeserializer, IDictionary result, ObjectDeserializer rootDeserializer) { IDictionary result2 = result; MappingStart property = parser.Consume(); MappingEnd @event; while (!parser.TryConsume(out @event)) { object key = nestedObjectDeserializer(parser, tKey); object value = nestedObjectDeserializer(parser, tValue); IValuePromise valuePromise = value as IValuePromise; if (key is IValuePromise valuePromise2) { if (valuePromise == null) { valuePromise2.ValueAvailable += delegate(object? v) { result2[v] = value; }; continue; } bool hasFirstPart = false; valuePromise2.ValueAvailable += delegate(object? v) { if (hasFirstPart) { TryAssign(result2, v, value, property); } else { key = v; hasFirstPart = true; } }; valuePromise.ValueAvailable += delegate(object? v) { if (hasFirstPart) { TryAssign(result2, key, v, property); } else { value = v; hasFirstPart = true; } }; continue; } if (key == null) { throw new ArgumentException("Empty key names are not supported yet.", "tKey"); } if (valuePromise == null) { TryAssign(result2, key, value, property); continue; } valuePromise.ValueAvailable += delegate(object? v) { result2[key] = v; }; } } } internal class DictionaryNodeDeserializer : DictionaryDeserializer, INodeDeserializer { private readonly IObjectFactory objectFactory; public DictionaryNodeDeserializer(IObjectFactory objectFactory, bool duplicateKeyChecking) : base(duplicateKeyChecking) { this.objectFactory = objectFactory ?? throw new ArgumentNullException("objectFactory"); } public bool Deserialize(IParser parser, Type expectedType, Func nestedObjectDeserializer, out object? value, ObjectDeserializer rootDeserializer) { Type implementationOfOpenGenericInterface = expectedType.GetImplementationOfOpenGenericInterface(typeof(IDictionary<, >)); Type type; Type type2; IDictionary dictionary; if (implementationOfOpenGenericInterface != null) { Type[] genericArguments = implementationOfOpenGenericInterface.GetGenericArguments(); type = genericArguments[0]; type2 = genericArguments[1]; value = objectFactory.Create(expectedType); dictionary = value as IDictionary; if (dictionary == null) { dictionary = (IDictionary)Activator.CreateInstance(typeof(GenericDictionaryToNonGenericAdapter<, >).MakeGenericType(type, type2), value); } } else { if (!typeof(IDictionary).IsAssignableFrom(expectedType)) { value = null; return false; } type = typeof(object); type2 = typeof(object); value = objectFactory.Create(expectedType); dictionary = (IDictionary)value; } Deserialize(type, type2, parser, nestedObjectDeserializer, dictionary, rootDeserializer); return true; } } internal sealed class EnumerableNodeDeserializer : INodeDeserializer { public bool Deserialize(IParser parser, Type expectedType, Func nestedObjectDeserializer, out object? value, ObjectDeserializer rootDeserializer) { Type type; if (expectedType == typeof(IEnumerable)) { type = typeof(object); } else { Type implementationOfOpenGenericInterface = expectedType.GetImplementationOfOpenGenericInterface(typeof(IEnumerable<>)); if (implementationOfOpenGenericInterface != expectedType) { value = null; return false; } type = implementationOfOpenGenericInterface.GetGenericArguments()[0]; } Type arg = typeof(List<>).MakeGenericType(type); value = nestedObjectDeserializer(parser, arg); return true; } } internal sealed class FsharpListNodeDeserializer : INodeDeserializer { private readonly ITypeInspector typeInspector; private readonly INamingConvention enumNamingConvention; public FsharpListNodeDeserializer(ITypeInspector typeInspector, INamingConvention enumNamingConvention) { this.typeInspector = typeInspector; this.enumNamingConvention = enumNamingConvention; } public bool Deserialize(IParser parser, Type expectedType, Func nestedObjectDeserializer, out object? value, ObjectDeserializer rootDeserializer) { if (!FsharpHelper.IsFsharpListType(expectedType)) { value = false; return false; } Type type = expectedType.GetGenericArguments()[0]; Type t = expectedType.GetGenericTypeDefinition().MakeGenericType(type); ArrayList arrayList = new ArrayList(); CollectionNodeDeserializer.DeserializeHelper(type, parser, nestedObjectDeserializer, arrayList, canUpdate: true, enumNamingConvention, typeInspector); Array array = Array.CreateInstance(type, arrayList.Count); arrayList.CopyTo(array, 0); object obj = FsharpHelper.CreateFsharpListFromArray(t, type, array); value = obj; return true; } } internal sealed class NullNodeDeserializer : INodeDeserializer { public bool Deserialize(IParser parser, Type expectedType, Func nestedObjectDeserializer, out object? value, ObjectDeserializer rootDeserializer) { value = null; if (parser.Accept(out var @event) && NodeIsNull(@event)) { parser.SkipThisAndNestedEvents(); return true; } return false; } private static bool NodeIsNull(NodeEvent nodeEvent) { if (nodeEvent.Tag == "tag:yaml.org,2002:null") { return true; } if (nodeEvent is YamlDotNet.Core.Events.Scalar scalar && scalar.Style == ScalarStyle.Plain && !scalar.IsKey) { string value = scalar.Value; switch (value) { default: return value == "NULL"; case "": case "~": case "null": case "Null": return true; } } return false; } } internal sealed class ObjectNodeDeserializer : INodeDeserializer { private readonly IObjectFactory objectFactory; private readonly ITypeInspector typeInspector; private readonly bool ignoreUnmatched; private readonly bool duplicateKeyChecking; private readonly ITypeConverter typeConverter; private readonly INamingConvention enumNamingConvention; private readonly bool enforceNullability; private readonly bool caseInsensitivePropertyMatching; private readonly bool enforceRequiredProperties; private readonly TypeConverterCache typeConverters; public ObjectNodeDeserializer(IObjectFactory objectFactory, ITypeInspector typeInspector, bool ignoreUnmatched, bool duplicateKeyChecking, ITypeConverter typeConverter, INamingConvention enumNamingConvention, bool enforceNullability, bool caseInsensitivePropertyMatching, bool enforceRequiredProperties, IEnumerable typeConverters) { this.objectFactory = objectFactory ?? throw new ArgumentNullException("objectFactory"); this.typeInspector = typeInspector ?? throw new ArgumentNullException("typeInspector"); this.ignoreUnmatched = ignoreUnmatched; this.duplicateKeyChecking = duplicateKeyChecking; this.typeConverter = typeConverter ?? throw new ArgumentNullException("typeConverter"); this.enumNamingConvention = enumNamingConvention ?? throw new ArgumentNullException("enumNamingConvention"); this.enforceNullability = enforceNullability; this.caseInsensitivePropertyMatching = caseInsensitivePropertyMatching; this.enforceRequiredProperties = enforceRequiredProperties; this.typeConverters = new TypeConverterCache(typeConverters); } public bool Deserialize(IParser parser, Type expectedType, Func nestedObjectDeserializer, out object? value, ObjectDeserializer rootDeserializer) { if (!parser.TryConsume(out var _)) { value = null; return false; } Type type = Nullable.GetUnderlyingType(expectedType) ?? FsharpHelper.GetOptionUnderlyingType(expectedType) ?? expectedType; value = objectFactory.Create(type); objectFactory.ExecuteOnDeserializing(value); HashSet hashSet = new HashSet(StringComparer.Ordinal); HashSet hashSet2 = new HashSet(StringComparer.Ordinal); Mark start = Mark.Empty; MappingEnd event2; while (!parser.TryConsume(out event2)) { YamlDotNet.Core.Events.Scalar propertyName = parser.Consume(); if (duplicateKeyChecking && !hashSet.Add(propertyName.Value)) { Mark start2 = propertyName.Start; Mark end = propertyName.End; throw new YamlException(in start2, in end, "Encountered duplicate key " + propertyName.Value); } try { IPropertyDescriptor property = typeInspector.GetProperty(type, null, propertyName.Value, ignoreUnmatched, caseInsensitivePropertyMatching); if (property == null) { parser.SkipThisAndNestedEvents(); continue; } hashSet2.Add(property.Name); object obj; if (property.ConverterType != null) { IYamlTypeConverter converterByType = typeConverters.GetConverterByType(property.ConverterType); obj = converterByType.ReadYaml(parser, property.Type, rootDeserializer); } else { obj = nestedObjectDeserializer(parser, property.Type); } if (obj is IValuePromise valuePromise) { object valueRef = value; valuePromise.ValueAvailable += delegate(object? v) { object value3 = typeConverter.ChangeType(v, property.Type, enumNamingConvention, typeInspector); NullCheck(value3, property, propertyName); property.Write(valueRef, value3); }; } else { object value2 = typeConverter.ChangeType(obj, property.Type, enumNamingConvention, typeInspector); NullCheck(value2, property, propertyName); property.Write(value, value2); } goto IL_0267; } catch (SerializationException ex) { Mark start2 = propertyName.Start; Mark end = propertyName.End; throw new YamlException(in start2, in end, ex.Message); } catch (YamlException) { throw; } catch (Exception innerException) { Mark start2 = propertyName.Start; Mark end = propertyName.End; throw new YamlException(in start2, in end, "Exception during deserialization", innerException); } IL_0267: start = propertyName.End; } if (enforceRequiredProperties) { IEnumerable properties = typeInspector.GetProperties(type, value); List list = new List(); foreach (IPropertyDescriptor item in properties) { if (item.Required && !hashSet2.Contains(item.Name)) { list.Add(item.Name); } } if (list.Count > 0) { string text = string.Join(",", list); throw new YamlException(in start, in start, "Missing properties, '" + text + "' in source yaml."); } } objectFactory.ExecuteOnDeserialized(value); return true; } public void NullCheck(object value, IPropertyDescriptor property, YamlDotNet.Core.Events.Scalar propertyName) { if (enforceNullability && value == null && !property.AllowNulls) { Mark start = propertyName.Start; Mark end = propertyName.End; throw new YamlException(in start, in end, "Strict nullability enforcement error.", new NullReferenceException("Yaml value is null when target property requires non null values.")); } } } internal sealed class ScalarNodeDeserializer : INodeDeserializer { private const string BooleanTruePattern = "^(true|y|yes|on)$"; private const string BooleanFalsePattern = "^(false|n|no|off)$"; private readonly bool attemptUnknownTypeDeserialization; private readonly ITypeConverter typeConverter; private readonly ITypeInspector typeInspector; private readonly YamlFormatter formatter; private readonly INamingConvention enumNamingConvention; public ScalarNodeDeserializer(bool attemptUnknownTypeDeserialization, ITypeConverter typeConverter, ITypeInspector typeInspector, YamlFormatter formatter, INamingConvention enumNamingConvention) { this.attemptUnknownTypeDeserialization = attemptUnknownTypeDeserialization; this.typeConverter = typeConverter ?? throw new ArgumentNullException("typeConverter"); this.typeInspector = typeInspector; this.formatter = formatter; this.enumNamingConvention = enumNamingConvention; } public bool Deserialize(IParser parser, Type expectedType, Func nestedObjectDeserializer, out object? value, ObjectDeserializer rootDeserializer) { if (!parser.TryConsume(out var @event)) { value = null; return false; } Type type = Nullable.GetUnderlyingType(expectedType) ?? FsharpHelper.GetOptionUnderlyingType(expectedType) ?? expectedType; if (type.IsEnum()) { string name = enumNamingConvention.Reverse(@event.Value); name = typeInspector.GetEnumName(type, name); value = Enum.Parse(type, name, ignoreCase: true); return true; } TypeCode typeCode = type.GetTypeCode(); switch (typeCode) { case TypeCode.Boolean: value = DeserializeBooleanHelper(@event.Value); break; case TypeCode.SByte: case TypeCode.Byte: case TypeCode.Int16: case TypeCode.UInt16: case TypeCode.Int32: case TypeCode.UInt32: case TypeCode.Int64: case TypeCode.UInt64: value = DeserializeIntegerHelper(typeCode, @event.Value); break; case TypeCode.Single: value = float.Parse(@event.Value, formatter.NumberFormat); break; case TypeCode.Double: value = double.Parse(@event.Value, formatter.NumberFormat); break; case TypeCode.Decimal: value = decimal.Parse(@event.Value, formatter.NumberFormat); break; case TypeCode.String: value = @event.Value; break; case TypeCode.Char: value = @event.Value[0]; break; case TypeCode.DateTime: value = DateTime.Parse(@event.Value, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind); break; default: if (expectedType == typeof(object)) { if (!@event.IsKey && attemptUnknownTypeDeserialization) { value = AttemptUnknownTypeDeserialization(@event); } else { value = @event.Value; } } else { value = typeConverter.ChangeType(@event.Value, expectedType, enumNamingConvention, typeInspector); } break; } return true; } private static bool DeserializeBooleanHelper(string value) { if (Regex.IsMatch(value, "^(true|y|yes|on)$", RegexOptions.IgnoreCase)) { return true; } if (Regex.IsMatch(value, "^(false|n|no|off)$", RegexOptions.IgnoreCase)) { return false; } throw new FormatException("The value \"" + value + "\" is not a valid YAML Boolean"); } private object DeserializeIntegerHelper(TypeCode typeCode, string value) { StringBuilderPool.BuilderWrapper builderWrapper = StringBuilderPool.Rent(); try { StringBuilder builder = builderWrapper.Builder; int i = 0; bool flag = false; ulong num = 0uL; if (value[0] == '-') { i++; flag = true; } else if (value[0] == '+') { i++; } if (value[i] == '0') { int num2; if (i == value.Length - 1) { num2 = 10; num = 0uL; } else { i++; if (value[i] == 'b') { num2 = 2; i++; } else if (value[i] == 'x') { num2 = 16; i++; } else { num2 = 8; } } for (; i < value.Length; i++) { if (value[i] != '_') { builder.Append(value[i]); } } switch (num2) { case 2: case 8: num = Convert.ToUInt64(builder.ToString(), num2); break; case 16: num = ulong.Parse(builder.ToString(), NumberStyles.HexNumber, formatter.NumberFormat); break; } } else { string[] array = value.Substring(i).Split(new char[1] { ':' }); num = 0uL; for (int j = 0; j < array.Length; j++) { num *= 60; num += ulong.Parse(array[j].Replace("_", ""), CultureInfo.InvariantCulture); } } if (!flag) { return CastInteger(num, typeCode); } long number = ((num != 9223372036854775808uL) ? checked(-(long)num) : long.MinValue); return CastInteger(number, typeCode); } finally { ((IDisposable)builderWrapper).Dispose(); } } private static object CastInteger(long number, TypeCode typeCode) { return checked(typeCode switch { TypeCode.Byte => (byte)number, TypeCode.Int16 => (short)number, TypeCode.Int32 => (int)number, TypeCode.Int64 => number, TypeCode.SByte => (sbyte)number, TypeCode.UInt16 => (ushort)number, TypeCode.UInt32 => (uint)number, TypeCode.UInt64 => (ulong)number, _ => number, }); } private static object CastInteger(ulong number, TypeCode typeCode) { return checked(typeCode switch { TypeCode.Byte => (byte)number, TypeCode.Int16 => (short)number, TypeCode.Int32 => (int)number, TypeCode.Int64 => (long)number, TypeCode.SByte => (sbyte)number, TypeCode.UInt16 => (ushort)number, TypeCode.UInt32 => (uint)number, TypeCode.UInt64 => number, _ => number, }); } private object? AttemptUnknownTypeDeserialization(YamlDotNet.Core.Events.Scalar value) { if (value.Style == ScalarStyle.SingleQuoted || value.Style == ScalarStyle.DoubleQuoted || value.Style == ScalarStyle.Folded) { return value.Value; } string v = value.Value; switch (v) { case "null": case "Null": case "NULL": case "~": case "": return null; case "true": case "True": case "TRUE": return true; case "False": case "FALSE": case "false": return false; default: if (Regex.IsMatch(v, "^0x[0-9a-fA-F]+$")) { v = v.Substring(2); if (byte.TryParse(v, NumberStyles.AllowHexSpecifier, formatter.NumberFormat, out var result)) { return result; } if (short.TryParse(v, NumberStyles.AllowHexSpecifier, formatter.NumberFormat, out var result2)) { return result2; } if (int.TryParse(v, NumberStyles.AllowHexSpecifier, formatter.NumberFormat, out var result3)) { return result3; } if (long.TryParse(v, NumberStyles.AllowHexSpecifier, formatter.NumberFormat, out var result4)) { return result4; } if (ulong.TryParse(v, NumberStyles.AllowHexSpecifier, formatter.NumberFormat, out var result5)) { return result5; } return v; } if (Regex.IsMatch(v, "^0o[0-9a-fA-F]+$")) { if (!TryAndSwallow(() => Convert.ToByte(v, 8), out object value2) && !TryAndSwallow(() => Convert.ToInt16(v, 8), out value2) && !TryAndSwallow(() => Convert.ToInt32(v, 8), out value2) && !TryAndSwallow(() => Convert.ToInt64(v, 8), out value2) && !TryAndSwallow(() => Convert.ToUInt64(v, 8), out value2)) { return v; } return value2; } if (Regex.IsMatch(v, "^[-+]?(\\.[0-9]+|[0-9]+(\\.[0-9]*)?)([eE][-+]?[0-9]+)?$")) { if (byte.TryParse(v, NumberStyles.Integer, formatter.NumberFormat, out var result6)) { return result6; } if (short.TryParse(v, NumberStyles.Integer, formatter.NumberFormat, out var result7)) { return result7; } if (int.TryParse(v, NumberStyles.Integer, formatter.NumberFormat, out var result8)) { return result8; } if (long.TryParse(v, NumberStyles.Integer, formatter.NumberFormat, out var result9)) { return result9; } if (ulong.TryParse(v, NumberStyles.Integer, formatter.NumberFormat, out var result10)) { return result10; } if (float.TryParse(v, NumberStyles.Float, formatter.NumberFormat, out var result11)) { return result11; } if (double.TryParse(v, NumberStyles.Float, formatter.NumberFormat, out var result12)) { return result12; } return v; } if (Regex.IsMatch(v, "^[-+]?(\\.inf|\\.Inf|\\.INF)$")) { if (Polyfills.StartsWith(v, '-')) { return float.NegativeInfinity; } return float.PositiveInfinity; } if (Regex.IsMatch(v, "^(\\.nan|\\.NaN|\\.NAN)$")) { return float.NaN; } return v; } } private static bool TryAndSwallow(Func attempt, out object? value) { try { value = attempt(); return true; } catch { value = null; return false; } } } internal sealed class StaticArrayNodeDeserializer : INodeDeserializer { private sealed class ArrayList : IList, ICollection, IEnumerable { private object?[] data; public bool IsFixedSize => false; public bool IsReadOnly => false; public object? this[int index] { get { return data[index]; } set { data[index] = value; } } public int Count { get; private set; } public bool IsSynchronized => false; public object SyncRoot => data; public ArrayList() { Clear(); } public int Add(object? value) { if (Count == data.Length) { Array.Resize(ref data, data.Length * 2); } data[Count] = value; return Count++; } public void Clear() { data = new object[10]; Count = 0; } bool IList.Contains(object? value) { throw new NotSupportedException(); } int IList.IndexOf(object? value) { throw new NotSupportedException(); } void IList.Insert(int index, object? value) { throw new NotSupportedException(); } void IList.Remove(object? value) { throw new NotSupportedException(); } void IList.RemoveAt(int index) { throw new NotSupportedException(); } public void CopyTo(Array array, int index) { Array.Copy(data, 0, array, index, Count); } public IEnumerator GetEnumerator() { int i = 0; while (i < Count) { yield return data[i]; int num = i + 1; i = num; } } } private readonly StaticObjectFactory factory; public StaticArrayNodeDeserializer(StaticObjectFactory factory) { this.factory = factory ?? throw new ArgumentNullException("factory"); } public bool Deserialize(IParser parser, Type expectedType, Func nestedObjectDeserializer, out object? value, ObjectDeserializer rootDeserializer) { if (!factory.IsArray(expectedType)) { value = false; return false; } Type valueType = factory.GetValueType(expectedType); ArrayList arrayList = new ArrayList(); StaticCollectionNodeDeserializer.DeserializeHelper(valueType, parser, nestedObjectDeserializer, arrayList, factory); Array array = factory.CreateArray(expectedType, arrayList.Count); arrayList.CopyTo(array, 0); value = array; return true; } } internal sealed class StaticCollectionNodeDeserializer : INodeDeserializer { private readonly StaticObjectFactory factory; public StaticCollectionNodeDeserializer(StaticObjectFactory factory) { this.factory = factory ?? throw new ArgumentNullException("factory"); } public bool Deserialize(IParser parser, Type expectedType, Func nestedObjectDeserializer, out object? value, ObjectDeserializer rootDeserializer) { if (!factory.IsList(expectedType)) { value = null; return false; } DeserializeHelper(result: (IList)(value = factory.Create(expectedType) as IList), tItem: factory.GetValueType(expectedType), parser: parser, nestedObjectDeserializer: nestedObjectDeserializer, factory: factory); return true; } internal static void DeserializeHelper(Type tItem, IParser parser, Func nestedObjectDeserializer, IList result, IObjectFactory factory) { IList result2 = result; parser.Consume(); SequenceEnd @event; while (!parser.TryConsume(out @event)) { ParsingEvent current = parser.Current; object obj = nestedObjectDeserializer(parser, tItem); if (obj is IValuePromise valuePromise) { int index = result2.Add(factory.CreatePrimitive(tItem)); valuePromise.ValueAvailable += delegate(object? v) { result2[index] = v; }; } else { result2.Add(obj); } } } } internal class StaticDictionaryNodeDeserializer : DictionaryDeserializer, INodeDeserializer { private readonly StaticObjectFactory objectFactory; public StaticDictionaryNodeDeserializer(StaticObjectFactory objectFactory, bool duplicateKeyChecking) : base(duplicateKeyChecking) { this.objectFactory = objectFactory ?? throw new ArgumentNullException("objectFactory"); } public bool Deserialize(IParser reader, Type expectedType, Func nestedObjectDeserializer, out object? value, ObjectDeserializer rootDeserializer) { if (objectFactory.IsDictionary(expectedType)) { if (!(objectFactory.Create(expectedType) is IDictionary dictionary)) { value = null; return false; } Type keyType = objectFactory.GetKeyType(expectedType); Type valueType = objectFactory.GetValueType(expectedType); value = dictionary; base.Deserialize(keyType, valueType, reader, nestedObjectDeserializer, dictionary, rootDeserializer); return true; } value = null; return false; } } internal sealed class TypeConverterNodeDeserializer : INodeDeserializer { private readonly TypeConverterCache converters; public TypeConverterNodeDeserializer(IEnumerable converters) { this.converters = new TypeConverterCache(converters); } public bool Deserialize(IParser parser, Type expectedType, Func nestedObjectDeserializer, out object? value, ObjectDeserializer rootDeserializer) { if (!converters.TryGetConverterForType(expectedType, out IYamlTypeConverter typeConverter)) { value = null; return false; } value = typeConverter.ReadYaml(parser, expectedType, rootDeserializer); return true; } } internal sealed class YamlConvertibleNodeDeserializer : INodeDeserializer { private readonly IObjectFactory objectFactory; public YamlConvertibleNodeDeserializer(IObjectFactory objectFactory) { this.objectFactory = objectFactory; } public bool Deserialize(IParser parser, Type expectedType, Func nestedObjectDeserializer, out object? value, ObjectDeserializer rootDeserializer) { Func nestedObjectDeserializer2 = nestedObjectDeserializer; IParser parser2 = parser; if (typeof(IYamlConvertible).IsAssignableFrom(expectedType)) { IYamlConvertible yamlConvertible = (IYamlConvertible)objectFactory.Create(expectedType); yamlConvertible.Read(parser2, expectedType, (Type type) => nestedObjectDeserializer2(parser2, type)); value = yamlConvertible; return true; } value = null; return false; } } internal sealed class YamlSerializableNodeDeserializer : INodeDeserializer { private readonly IObjectFactory objectFactory; public YamlSerializableNodeDeserializer(IObjectFactory objectFactory) { this.objectFactory = objectFactory; } public bool Deserialize(IParser parser, Type expectedType, Func nestedObjectDeserializer, out object? value, ObjectDeserializer rootDeserializer) { if (typeof(IYamlSerializable).IsAssignableFrom(expectedType)) { IYamlSerializable yamlSerializable = (IYamlSerializable)objectFactory.Create(expectedType); yamlSerializable.ReadYaml(parser); value = yamlSerializable; return true; } value = null; return false; } } } namespace YamlDotNet.Serialization.NamingConventions { internal sealed class CamelCaseNamingConvention : INamingConvention { public static readonly INamingConvention Instance = new CamelCaseNamingConvention(); [Obsolete("Use the Instance static field instead of creating new instances")] public CamelCaseNamingConvention() { } public string Apply(string value) { return value.ToCamelCase(); } public string Reverse(string value) { return value.ToPascalCase(); } } internal sealed class HyphenatedNamingConvention : INamingConvention { public static readonly INamingConvention Instance = new HyphenatedNamingConvention(); [Obsolete("Use the Instance static field instead of creating new instances")] public HyphenatedNamingConvention() { } public string Apply(string value) { return value.FromCamelCase("-"); } public string Reverse(string value) { return value.ToPascalCase(); } } internal sealed class LowerCaseNamingConvention : INamingConvention { public static readonly INamingConvention Instance = new LowerCaseNamingConvention(); private LowerCaseNamingConvention() { } public string Apply(string value) { return value.ToCamelCase().ToLower(CultureInfo.InvariantCulture); } public string Reverse(string value) { if (string.IsNullOrEmpty(value)) { return value; } return char.ToUpperInvariant(value[0]) + value.Substring(1); } } internal sealed class NullNamingConvention : INamingConvention { public static readonly INamingConvention Instance = new NullNamingConvention(); [Obsolete("Use the Instance static field instead of creating new instances")] public NullNamingConvention() { } public string Apply(string value) { return value; } public string Reverse(string value) { return value; } } internal sealed class PascalCaseNamingConvention : INamingConvention { public static readonly INamingConvention Instance = new PascalCaseNamingConvention(); [Obsolete("Use the Instance static field instead of creating new instances")] public PascalCaseNamingConvention() { } public string Apply(string value) { return value.ToPascalCase(); } public string Reverse(string value) { return value.ToPascalCase(); } } internal sealed class UnderscoredNamingConvention : INamingConvention { public static readonly INamingConvention Instance = new UnderscoredNamingConvention(); [Obsolete("Use the Instance static field instead of creating new instances")] public UnderscoredNamingConvention() { } public string Apply(string value) { return value.FromCamelCase("_"); } public string Reverse(string value) { return value.ToPascalCase(); } } } namespace YamlDotNet.Serialization.EventEmitters { internal abstract class ChainedEventEmitter : IEventEmitter { protected readonly IEventEmitter nextEmitter; protected ChainedEventEmitter(IEventEmitter nextEmitter) { this.nextEmitter = nextEmitter ?? throw new ArgumentNullException("nextEmitter"); } public virtual void Emit(AliasEventInfo eventInfo, IEmitter emitter) { nextEmitter.Emit(eventInfo, emitter); } public virtual void Emit(ScalarEventInfo eventInfo, IEmitter emitter) { nextEmitter.Emit(eventInfo, emitter); } public virtual void Emit(MappingStartEventInfo eventInfo, IEmitter emitter) { nextEmitter.Emit(eventInfo, emitter); } public virtual void Emit(MappingEndEventInfo eventInfo, IEmitter emitter) { nextEmitter.Emit(eventInfo, emitter); } public virtual void Emit(SequenceStartEventInfo eventInfo, IEmitter emitter) { nextEmitter.Emit(eventInfo, emitter); } public virtual void Emit(SequenceEndEventInfo eventInfo, IEmitter emitter) { nextEmitter.Emit(eventInfo, emitter); } } internal sealed class JsonEventEmitter : ChainedEventEmitter { private readonly YamlFormatter formatter; private readonly INamingConvention enumNamingConvention; private readonly ITypeInspector typeInspector; public JsonEventEmitter(IEventEmitter nextEmitter, YamlFormatter formatter, INamingConvention enumNamingConvention, ITypeInspector typeInspector) : base(nextEmitter) { this.formatter = formatter; this.enumNamingConvention = enumNamingConvention; this.typeInspector = typeInspector; } public override void Emit(AliasEventInfo eventInfo, IEmitter emitter) { eventInfo.NeedsExpansion = true; } public override void Emit(ScalarEventInfo eventInfo, IEmitter emitter) { eventInfo.IsPlainImplicit = true; eventInfo.Style = ScalarStyle.Plain; object value = eventInfo.Source.Value; if (value == null) { eventInfo.RenderedValue = "null"; } else { TypeCode typeCode = eventInfo.Source.Type.GetTypeCode(); switch (typeCode) { case TypeCode.Boolean: eventInfo.RenderedValue = formatter.FormatBoolean(value); break; case TypeCode.SByte: case TypeCode.Byte: case TypeCode.Int16: case TypeCode.UInt16: case TypeCode.Int32: case TypeCode.UInt32: case TypeCode.Int64: case TypeCode.UInt64: if (eventInfo.Source.Type.IsEnum()) { eventInfo.RenderedValue = formatter.FormatEnum(value, typeInspector, enumNamingConvention); eventInfo.Style = ((!formatter.PotentiallyQuoteEnums(value)) ? ScalarStyle.Plain : ScalarStyle.DoubleQuoted); } else { eventInfo.RenderedValue = formatter.FormatNumber(value); } break; case TypeCode.Single: { float f = (float)value; eventInfo.RenderedValue = f.ToString("G", CultureInfo.InvariantCulture); if (float.IsNaN(f) || float.IsInfinity(f)) { eventInfo.Style = ScalarStyle.DoubleQuoted; } break; } case TypeCode.Double: { double d = (double)value; eventInfo.RenderedValue = d.ToString("G", CultureInfo.InvariantCulture); if (double.IsNaN(d) || double.IsInfinity(d)) { eventInfo.Style = ScalarStyle.DoubleQuoted; } break; } case TypeCode.Decimal: eventInfo.RenderedValue = ((decimal)value).ToString(CultureInfo.InvariantCulture); break; case TypeCode.Char: case TypeCode.String: eventInfo.RenderedValue = value.ToString(); eventInfo.Style = ScalarStyle.DoubleQuoted; break; case TypeCode.DateTime: eventInfo.RenderedValue = formatter.FormatDateTime(value); break; case TypeCode.Empty: eventInfo.RenderedValue = "null"; break; default: if (eventInfo.Source.Type == typeof(TimeSpan)) { eventInfo.RenderedValue = formatter.FormatTimeSpan(value); break; } throw new NotSupportedException($"TypeCode.{typeCode} is not supported."); } } base.Emit(eventInfo, emitter); } public override void Emit(MappingStartEventInfo eventInfo, IEmitter emitter) { eventInfo.Style = MappingStyle.Flow; base.Emit(eventInfo, emitter); } public override void Emit(SequenceStartEventInfo eventInfo, IEmitter emitter) { eventInfo.Style = SequenceStyle.Flow; base.Emit(eventInfo, emitter); } } internal sealed class TypeAssigningEventEmitter : ChainedEventEmitter { private readonly IDictionary tagMappings; private readonly bool quoteNecessaryStrings; private readonly Regex? isSpecialStringValue_Regex; private static readonly string SpecialStrings_Pattern = "^(null|Null|NULL|\\~|true|True|TRUE|false|False|FALSE|[-+]?[0-9]+|0o[0-7]+|0x[0-9a-fA-F]+|[-+]?(\\.[0-9]+|[0-9]+(\\.[0-9]*)?)([eE][-+]?[0-9]+)?|[-+]?(\\.inf|\\.Inf|\\.INF)|\\.nan|\\.NaN|\\.NAN|\\s.*)$"; private static readonly string CombinedYaml1_1SpecialStrings_Pattern = "^(null|Null|NULL|\\~|true|True|TRUE|false|False|FALSE|y|Y|yes|Yes|YES|n|N|no|No|NO|on|On|ON|off|Off|OFF|[-+]?0b[0-1_]+|[-+]?0o?[0-7_]+|[-+]?(0|[1-9][0-9_]*)|[-+]?0x[0-9a-fA-F_]+|[-+]?[1-9][0-9_]*(:[0-5]?[0-9])+|[-+]?([0-9][0-9_]*)?\\.[0-9_]*([eE][-+][0-9]+)?|[-+]?[0-9][0-9_]*(:[0-5]?[0-9])+\\.[0-9_]*|[-+]?\\.(inf|Inf|INF)|\\.(nan|NaN|NAN))$"; private readonly ScalarStyle defaultScalarStyle; private readonly YamlFormatter formatter; private readonly INamingConvention enumNamingConvention; private readonly ITypeInspector typeInspector; public TypeAssigningEventEmitter(IEventEmitter nextEmitter, IDictionary tagMappings, bool quoteNecessaryStrings, bool quoteYaml1_1Strings, ScalarStyle defaultScalarStyle, YamlFormatter formatter, INamingConvention enumNamingConvention, ITypeInspector typeInspector) : base(nextEmitter) { this.defaultScalarStyle = defaultScalarStyle; this.formatter = formatter; this.tagMappings = tagMappings; this.quoteNecessaryStrings = quoteNecessaryStrings; isSpecialStringValue_Regex = new Regex(quoteYaml1_1Strings ? CombinedYaml1_1SpecialStrings_Pattern : SpecialStrings_Pattern, RegexOptions.Compiled); this.enumNamingConvention = enumNamingConvention; this.typeInspector = typeInspector; } public override void Emit(ScalarEventInfo eventInfo, IEmitter emitter) { ScalarStyle style = ScalarStyle.Plain; object value = eventInfo.Source.Value; if (value == null) { eventInfo.Tag = JsonSchema.Tags.Null; eventInfo.RenderedValue = ""; } else { TypeCode typeCode = eventInfo.Source.Type.GetTypeCode(); switch (typeCode) { case TypeCode.Boolean: eventInfo.Tag = JsonSchema.Tags.Bool; eventInfo.RenderedValue = formatter.FormatBoolean(value); break; case TypeCode.SByte: case TypeCode.Byte: case TypeCode.Int16: case TypeCode.UInt16: case TypeCode.Int32: case TypeCode.UInt32: case TypeCode.Int64: case TypeCode.UInt64: if (eventInfo.Source.Type.IsEnum) { eventInfo.Tag = FailsafeSchema.Tags.Str; eventInfo.RenderedValue = formatter.FormatEnum(value, typeInspector, enumNamingConvention); style = ((!quoteNecessaryStrings || !IsSpecialStringValue(eventInfo.RenderedValue) || !formatter.PotentiallyQuoteEnums(value)) ? defaultScalarStyle : ScalarStyle.DoubleQuoted); } else { eventInfo.Tag = JsonSchema.Tags.Int; eventInfo.RenderedValue = formatter.FormatNumber(value); } break; case TypeCode.Single: eventInfo.Tag = JsonSchema.Tags.Float; eventInfo.RenderedValue = formatter.FormatNumber((float)value); break; case TypeCode.Double: eventInfo.Tag = JsonSchema.Tags.Float; eventInfo.RenderedValue = formatter.FormatNumber((double)value); break; case TypeCode.Decimal: eventInfo.Tag = JsonSchema.Tags.Float; eventInfo.RenderedValue = formatter.FormatNumber(value); break; case TypeCode.Char: case TypeCode.String: eventInfo.Tag = FailsafeSchema.Tags.Str; eventInfo.RenderedValue = value.ToString(); style = ((!quoteNecessaryStrings || !IsSpecialStringValue(eventInfo.RenderedValue)) ? defaultScalarStyle : ScalarStyle.DoubleQuoted); break; case TypeCode.DateTime: eventInfo.Tag = DefaultSchema.Tags.Timestamp; eventInfo.RenderedValue = formatter.FormatDateTime(value); break; case TypeCode.Empty: eventInfo.Tag = JsonSchema.Tags.Null; eventInfo.RenderedValue = ""; break; default: if (eventInfo.Source.Type == typeof(TimeSpan)) { eventInfo.RenderedValue = formatter.FormatTimeSpan(value); break; } throw new NotSupportedException($"TypeCode.{typeCode} is not supported."); } } eventInfo.IsPlainImplicit = true; if (eventInfo.Style == ScalarStyle.Any) { eventInfo.Style = style; } base.Emit(eventInfo, emitter); } public override void Emit(MappingStartEventInfo eventInfo, IEmitter emitter) { AssignTypeIfNeeded(eventInfo); base.Emit(eventInfo, emitter); } public override void Emit(SequenceStartEventInfo eventInfo, IEmitter emitter) { AssignTypeIfNeeded(eventInfo); base.Emit(eventInfo, emitter); } private void AssignTypeIfNeeded(ObjectEventInfo eventInfo) { if (tagMappings.TryGetValue(eventInfo.Source.Type, out var value)) { eventInfo.Tag = value; } } private bool IsSpecialStringValue(string value) { if (value.Trim() == string.Empty) { return true; } return isSpecialStringValue_Regex?.IsMatch(value) ?? false; } } internal sealed class WriterEventEmitter : IEventEmitter { void IEventEmitter.Emit(AliasEventInfo eventInfo, IEmitter emitter) { emitter.Emit(new YamlDotNet.Core.Events.AnchorAlias(eventInfo.Alias)); } void IEventEmitter.Emit(ScalarEventInfo eventInfo, IEmitter emitter) { emitter.Emit(new YamlDotNet.Core.Events.Scalar(eventInfo.Anchor, eventInfo.Tag, eventInfo.RenderedValue, eventInfo.Style, eventInfo.IsPlainImplicit, eventInfo.IsQuotedImplicit)); } void IEventEmitter.Emit(MappingStartEventInfo eventInfo, IEmitter emitter) { emitter.Emit(new MappingStart(eventInfo.Anchor, eventInfo.Tag, eventInfo.IsImplicit, eventInfo.Style)); } void IEventEmitter.Emit(MappingEndEventInfo eventInfo, IEmitter emitter) { emitter.Emit(new MappingEnd()); } void IEventEmitter.Emit(SequenceStartEventInfo eventInfo, IEmitter emitter) { emitter.Emit(new SequenceStart(eventInfo.Anchor, eventInfo.Tag, eventInfo.IsImplicit, eventInfo.Style)); } void IEventEmitter.Emit(SequenceEndEventInfo eventInfo, IEmitter emitter) { emitter.Emit(new SequenceEnd()); } } } namespace YamlDotNet.Serialization.Converters { internal class DateTime8601Converter : IYamlTypeConverter { private readonly ScalarStyle scalarStyle; public DateTime8601Converter() : this(ScalarStyle.Any) { } public DateTime8601Converter(ScalarStyle scalarStyle) { this.scalarStyle = scalarStyle; } public bool Accepts(Type type) { return type == typeof(DateTime); } public object ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer) { string value = parser.Consume().Value; DateTime dateTime = DateTime.ParseExact(value, "O", CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind); return dateTime; } public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer) { string value2 = ((DateTime)value).ToString("O", CultureInfo.InvariantCulture); emitter.Emit(new YamlDotNet.Core.Events.Scalar(AnchorName.Empty, TagName.Empty, value2, scalarStyle, isPlainImplicit: true, isQuotedImplicit: false)); } } internal class DateTimeConverter : IYamlTypeConverter { private readonly DateTimeKind kind; private readonly IFormatProvider provider; private readonly bool doubleQuotes; private readonly string[] formats; public DateTimeConverter(DateTimeKind kind = DateTimeKind.Utc, IFormatProvider? provider = null, bool doubleQuotes = false, params string[] formats) { this.kind = ((kind == DateTimeKind.Unspecified) ? DateTimeKind.Utc : kind); this.provider = provider ?? CultureInfo.InvariantCulture; this.doubleQuotes = doubleQuotes; this.formats = formats.DefaultIfEmpty("G").ToArray(); } public bool Accepts(Type type) { return type == typeof(DateTime); } public object ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer) { string value = parser.Consume().Value; DateTimeStyles style = ((kind == DateTimeKind.Local) ? DateTimeStyles.AssumeLocal : DateTimeStyles.AssumeUniversal); DateTime dt = DateTime.ParseExact(value, formats, provider, style); dt = EnsureDateTimeKind(dt, kind); return dt; } public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer) { DateTime dateTime = (DateTime)value; string value2 = ((kind == DateTimeKind.Local) ? dateTime.ToLocalTime() : dateTime.ToUniversalTime()).ToString(formats.First(), provider); emitter.Emit(new YamlDotNet.Core.Events.Scalar(AnchorName.Empty, TagName.Empty, value2, doubleQuotes ? ScalarStyle.DoubleQuoted : ScalarStyle.Any, isPlainImplicit: true, isQuotedImplicit: false)); } private static DateTime EnsureDateTimeKind(DateTime dt, DateTimeKind kind) { if (dt.Kind == DateTimeKind.Local && kind == DateTimeKind.Utc) { return dt.ToUniversalTime(); } if (dt.Kind == DateTimeKind.Utc && kind == DateTimeKind.Local) { return dt.ToLocalTime(); } return dt; } } internal class DateTimeOffsetConverter : IYamlTypeConverter { private readonly IFormatProvider provider; private readonly ScalarStyle style; private readonly DateTimeStyles dateStyle; private readonly string[] formats; public DateTimeOffsetConverter(IFormatProvider? provider = null, ScalarStyle style = ScalarStyle.Any, DateTimeStyles dateStyle = DateTimeStyles.None, params string[] formats) { this.provider = provider ?? CultureInfo.InvariantCulture; this.style = style; this.dateStyle = dateStyle; this.formats = formats.DefaultIfEmpty("O").ToArray(); } public bool Accepts(Type type) { return type == typeof(DateTimeOffset); } public object ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer) { string value = parser.Consume().Value; DateTimeOffset dateTimeOffset = DateTimeOffset.ParseExact(value, formats, provider, dateStyle); return dateTimeOffset; } public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer) { string value2 = ((DateTimeOffset)value).ToString(formats.First(), provider); emitter.Emit(new YamlDotNet.Core.Events.Scalar(AnchorName.Empty, TagName.Empty, value2, style, isPlainImplicit: true, isQuotedImplicit: false)); } } internal class GuidConverter : IYamlTypeConverter { private readonly bool jsonCompatible; public GuidConverter(bool jsonCompatible) { this.jsonCompatible = jsonCompatible; } public bool Accepts(Type type) { return type == typeof(Guid); } public object ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer) { string value = parser.Consume().Value; return new Guid(value); } public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer) { Guid guid = (Guid)value; emitter.Emit(new YamlDotNet.Core.Events.Scalar(AnchorName.Empty, TagName.Empty, guid.ToString("D"), jsonCompatible ? ScalarStyle.DoubleQuoted : ScalarStyle.Any, isPlainImplicit: true, isQuotedImplicit: false)); } } internal class SystemTypeConverter : IYamlTypeConverter { public bool Accepts(Type type) { return typeof(Type).IsAssignableFrom(type); } public object ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer) { string value = parser.Consume().Value; return Type.GetType(value, throwOnError: true); } public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer) { Type type2 = (Type)value; emitter.Emit(new YamlDotNet.Core.Events.Scalar(AnchorName.Empty, TagName.Empty, type2.AssemblyQualifiedName, ScalarStyle.Any, isPlainImplicit: true, isQuotedImplicit: false)); } } } namespace YamlDotNet.Serialization.Callbacks { [AttributeUsage(AttributeTargets.Method)] internal sealed class OnDeserializedAttribute : Attribute { } [AttributeUsage(AttributeTargets.Method)] internal sealed class OnDeserializingAttribute : Attribute { } [AttributeUsage(AttributeTargets.Method)] internal sealed class OnSerializedAttribute : Attribute { } [AttributeUsage(AttributeTargets.Method)] internal sealed class OnSerializingAttribute : Attribute { } } namespace YamlDotNet.Serialization.BufferedDeserialization { internal interface ITypeDiscriminatingNodeDeserializerOptions { void AddTypeDiscriminator(ITypeDiscriminator discriminator); void AddKeyValueTypeDiscriminator(string discriminatorKey, IDictionary valueTypeMapping); void AddUniqueKeyTypeDiscriminator(IDictionary uniqueKeyTypeMapping); } internal class ParserBuffer : IParser { private readonly LinkedList buffer; private LinkedListNode? current; public ParsingEvent? Current => current?.Value; public ParserBuffer(IParser parserToBuffer, int maxDepth, int maxLength) { buffer = new LinkedList(); buffer.AddLast(parserToBuffer.Consume()); int num = 0; do { ParsingEvent parsingEvent = parserToBuffer.Consume(); num += parsingEvent.NestingIncrease; buffer.AddLast(parsingEvent); if (maxDepth > -1 && num > maxDepth) { throw new ArgumentOutOfRangeException("parserToBuffer", "Parser buffer exceeded max depth"); } if (maxLength > -1 && buffer.Count > maxLength) { throw new ArgumentOutOfRangeException("parserToBuffer", "Parser buffer exceeded max length"); } } while (num >= 0); current = buffer.First; } public bool MoveNext() { current = current?.Next; return current != null; } public void Reset() { current = buffer.First; } } internal class TypeDiscriminatingNodeDeserializer : INodeDeserializer { private readonly IList innerDeserializers; private readonly IList typeDiscriminators; private readonly int maxDepthToBuffer; private readonly int maxLengthToBuffer; public TypeDiscriminatingNodeDeserializer(IList innerDeserializers, IList typeDiscriminators, int maxDepthToBuffer, int maxLengthToBuffer) { this.innerDeserializers = innerDeserializers; this.typeDiscriminators = typeDiscriminators; this.maxDepthToBuffer = maxDepthToBuffer; this.maxLengthToBuffer = maxLengthToBuffer; } public bool Deserialize(IParser reader, Type expectedType, Func nestedObjectDeserializer, out object? value, ObjectDeserializer rootDeserializer) { Type expectedType2 = expectedType; if (!reader.Accept(out var _)) { value = null; return false; } IEnumerable enumerable = typeDiscriminators.Where((ITypeDiscriminator t) => t.BaseType.IsAssignableFrom(expectedType2)); if (!enumerable.Any()) { value = null; return false; } Mark start = reader.Current.Start; Type expectedType3 = expectedType2; ParserBuffer parserBuffer; try { parserBuffer = new ParserBuffer(reader, maxDepthToBuffer, maxLengthToBuffer); } catch (Exception innerException) { Mark end = reader.Current.End; throw new YamlException(in start, in end, "Failed to buffer yaml node", innerException); } try { foreach (ITypeDiscriminator item in enumerable) { parserBuffer.Reset(); if (item.TryDiscriminate(parserBuffer, out Type suggestedType)) { expectedType3 = suggestedType; break; } } } catch (Exception innerException2) { Mark end = reader.Current.End; throw new YamlException(in start, in end, "Failed to discriminate type", innerException2); } parserBuffer.Reset(); foreach (INodeDeserializer innerDeserializer in innerDeserializers) { if (innerDeserializer.Deserialize(parserBuffer, expectedType3, nestedObjectDeserializer, out value, rootDeserializer)) { return true; } } value = null; return false; } } internal class TypeDiscriminatingNodeDeserializerOptions : ITypeDiscriminatingNodeDeserializerOptions { internal readonly List discriminators = new List(); public void AddTypeDiscriminator(ITypeDiscriminator discriminator) { discriminators.Add(discriminator); } public void AddKeyValueTypeDiscriminator(string discriminatorKey, IDictionary valueTypeMapping) { discriminators.Add(new KeyValueTypeDiscriminator(typeof(T), discriminatorKey, valueTypeMapping)); } public void AddUniqueKeyTypeDiscriminator(IDictionary uniqueKeyTypeMapping) { discriminators.Add(new UniqueKeyTypeDiscriminator(typeof(T), uniqueKeyTypeMapping)); } } } namespace YamlDotNet.Serialization.BufferedDeserialization.TypeDiscriminators { internal interface ITypeDiscriminator { Type BaseType { get; } bool TryDiscriminate(IParser buffer, out Type? suggestedType); } internal class KeyValueTypeDiscriminator : ITypeDiscriminator { private readonly string targetKey; private readonly IDictionary typeMapping; public Type BaseType { get; private set; } public KeyValueTypeDiscriminator(Type baseType, string targetKey, IDictionary typeMapping) { foreach (KeyValuePair item in typeMapping) { if (!baseType.IsAssignableFrom(item.Value)) { throw new ArgumentOutOfRangeException("typeMapping", $"{item.Value} is not a assignable to {baseType}"); } } BaseType = baseType; this.targetKey = targetKey; this.typeMapping = typeMapping; } public bool TryDiscriminate(IParser parser, out Type? suggestedType) { if (parser.TryFindMappingEntry((YamlDotNet.Core.Events.Scalar scalar) => targetKey == scalar.Value, out YamlDotNet.Core.Events.Scalar _, out ParsingEvent value) && value is YamlDotNet.Core.Events.Scalar scalar2 && typeMapping.TryGetValue(scalar2.Value, out Type value2)) { suggestedType = value2; return true; } suggestedType = null; return false; } } internal class UniqueKeyTypeDiscriminator : ITypeDiscriminator { private readonly IDictionary typeMapping; public Type BaseType { get; private set; } public UniqueKeyTypeDiscriminator(Type baseType, IDictionary typeMapping) { foreach (KeyValuePair item in typeMapping) { if (!baseType.IsAssignableFrom(item.Value)) { throw new ArgumentOutOfRangeException("typeMapping", $"{item.Value} is not a assignable to {baseType}"); } } BaseType = baseType; this.typeMapping = typeMapping; } public bool TryDiscriminate(IParser parser, out Type? suggestedType) { if (parser.TryFindMappingEntry((YamlDotNet.Core.Events.Scalar scalar) => typeMapping.ContainsKey(scalar.Value), out YamlDotNet.Core.Events.Scalar key, out ParsingEvent _)) { suggestedType = typeMapping[key.Value]; return true; } suggestedType = null; return false; } } } namespace YamlDotNet.RepresentationModel { internal class DocumentLoadingState { private readonly Dictionary anchors = new Dictionary(); private readonly List nodesWithUnresolvedAliases = new List(); public void AddAnchor(YamlNode node) { if (node.Anchor.IsEmpty) { throw new ArgumentException("The specified node does not have an anchor"); } anchors[node.Anchor] = node; } public YamlNode GetNode(AnchorName anchor, Mark start, Mark end) { if (anchors.TryGetValue(anchor, out YamlNode value)) { return value; } throw new AnchorNotFoundException(in start, in end, $"The anchor '{anchor}' does not exists"); } public bool TryGetNode(AnchorName anchor, [NotNullWhen(true)] out YamlNode? node) { return anchors.TryGetValue(anchor, out node); } public void AddNodeWithUnresolvedAliases(YamlNode node) { nodesWithUnresolvedAliases.Add(node); } public void ResolveAliases() { foreach (YamlNode nodesWithUnresolvedAlias in nodesWithUnresolvedAliases) { nodesWithUnresolvedAlias.ResolveAliases(this); } } } internal class EmitterState { public HashSet EmittedAnchors { get; } = new HashSet(); } internal interface IYamlVisitor { void Visit(YamlStream stream); void Visit(YamlDocument document); void Visit(YamlScalarNode scalar); void Visit(YamlSequenceNode sequence); void Visit(YamlMappingNode mapping); } internal class LibYamlEventStream { private readonly IParser parser; public LibYamlEventStream(IParser iParser) { parser = iParser ?? throw new ArgumentNullException("iParser"); } public void WriteTo(TextWriter textWriter) { while (parser.MoveNext()) { ParsingEvent current = parser.Current; if (!(current is YamlDotNet.Core.Events.AnchorAlias anchorAlias)) { if (!(current is YamlDotNet.Core.Events.DocumentEnd documentEnd)) { if (!(current is YamlDotNet.Core.Events.DocumentStart documentStart)) { if (!(current is MappingEnd)) { if (!(current is MappingStart nodeEvent)) { if (!(current is YamlDotNet.Core.Events.Scalar scalar)) { if (!(current is SequenceEnd)) { if (!(current is SequenceStart nodeEvent2)) { if (!(current is YamlDotNet.Core.Events.StreamEnd)) { if (current is YamlDotNet.Core.Events.StreamStart) { textWriter.Write("+STR"); } } else { textWriter.Write("-STR"); } } else { textWriter.Write("+SEQ"); WriteAnchorAndTag(textWriter, nodeEvent2); } } else { textWriter.Write("-SEQ"); } } else { textWriter.Write("=VAL"); WriteAnchorAndTag(textWriter, scalar); switch (scalar.Style) { case ScalarStyle.DoubleQuoted: textWriter.Write(" \""); break; case ScalarStyle.SingleQuoted: textWriter.Write(" '"); break; case ScalarStyle.Folded: textWriter.Write(" >"); break; case ScalarStyle.Literal: textWriter.Write(" |"); break; default: textWriter.Write(" :"); break; } string value = scalar.Value; foreach (char c in value) { switch (c) { case '\b': textWriter.Write("\\b"); break; case '\t': textWriter.Write("\\t"); break; case '\n': textWriter.Write("\\n"); break; case '\r': textWriter.Write("\\r"); break; case '\\': textWriter.Write("\\\\"); break; default: textWriter.Write(c); break; } } } } else { textWriter.Write("+MAP"); WriteAnchorAndTag(textWriter, nodeEvent); } } else { textWriter.Write("-MAP"); } } else { textWriter.Write("+DOC"); if (!documentStart.IsImplicit) { textWriter.Write(" ---"); } } } else { textWriter.Write("-DOC"); if (!documentEnd.IsImplicit) { textWriter.Write(" ..."); } } } else { textWriter.Write("=ALI *"); textWriter.Write(anchorAlias.Value); } textWriter.WriteLine(); } } private static void WriteAnchorAndTag(TextWriter textWriter, NodeEvent nodeEvent) { if (!nodeEvent.Anchor.IsEmpty) { textWriter.Write(" &"); textWriter.Write(nodeEvent.Anchor); } if (!nodeEvent.Tag.IsEmpty) { textWriter.Write(" <"); textWriter.Write(nodeEvent.Tag.Value); textWriter.Write(">"); } } } internal class YamlAliasNode : YamlNode { public override YamlNodeType NodeType => YamlNodeType.Alias; internal YamlAliasNode(AnchorName anchor) { base.Anchor = anchor; } internal override void ResolveAliases(DocumentLoadingState state) { throw new NotSupportedException("Resolving an alias on an alias node does not make sense"); } internal override void Emit(IEmitter emitter, EmitterState state) { throw new NotSupportedException("A YamlAliasNode is an implementation detail and should never be saved."); } public override void Accept(IYamlVisitor visitor) { throw new NotSupportedException("A YamlAliasNode is an implementation detail and should never be visited."); } public override bool Equals(object? obj) { if (obj is YamlAliasNode yamlAliasNode && Equals(yamlAliasNode)) { return object.Equals(base.Anchor, yamlAliasNode.Anchor); } return false; } public override int GetHashCode() { return base.GetHashCode(); } internal override string ToString(RecursionLevel level) { return "*" + base.Anchor; } internal override IEnumerable SafeAllNodes(RecursionLevel level) { yield return this; } } internal class YamlDocument { private class AnchorAssigningVisitor : YamlVisitorBase { private readonly HashSet existingAnchors = new HashSet(); private readonly Dictionary visitedNodes = new Dictionary(); public void AssignAnchors(YamlDocument document) { existingAnchors.Clear(); visitedNodes.Clear(); document.Accept(this); Random random = new Random(); foreach (KeyValuePair visitedNode in visitedNodes) { if (!visitedNode.Value) { continue; } AnchorName anchorName; if (!visitedNode.Key.Anchor.IsEmpty && !existingAnchors.Contains(visitedNode.Key.Anchor)) { anchorName = visitedNode.Key.Anchor; } else { do { anchorName = new AnchorName(random.Next().ToString(CultureInfo.InvariantCulture)); } while (existingAnchors.Contains(anchorName)); } existingAnchors.Add(anchorName); visitedNode.Key.Anchor = anchorName; } } private bool VisitNodeAndFindDuplicates(YamlNode node) { if (visitedNodes.TryGetValue(node, out var value)) { if (!value) { visitedNodes[node] = true; } return !value; } visitedNodes.Add(node, value: false); return false; } public override void Visit(YamlScalarNode scalar) { VisitNodeAndFindDuplicates(scalar); } public override void Visit(YamlMappingNode mapping) { if (!VisitNodeAndFindDuplicates(mapping)) { base.Visit(mapping); } } public override void Visit(YamlSequenceNode sequence) { if (!VisitNodeAndFindDuplicates(sequence)) { base.Visit(sequence); } } } public YamlNode RootNode { get; private set; } public IEnumerable AllNodes => RootNode.AllNodes; public YamlDocument(YamlNode rootNode) { RootNode = rootNode; } public YamlDocument(string rootNode) { RootNode = new YamlScalarNode(rootNode); } internal YamlDocument(IParser parser) { DocumentLoadingState documentLoadingState = new DocumentLoadingState(); parser.Consume(); YamlDotNet.Core.Events.DocumentEnd @event; while (!parser.TryConsume(out @event)) { RootNode = YamlNode.ParseNode(parser, documentLoadingState); if (RootNode is YamlAliasNode) { throw new YamlException("A document cannot contain only an alias"); } } documentLoadingState.ResolveAliases(); if (RootNode == null) { throw new ArgumentException("Atempted to parse an empty document"); } } private void AssignAnchors() { AnchorAssigningVisitor anchorAssigningVisitor = new AnchorAssigningVisitor(); anchorAssigningVisitor.AssignAnchors(this); } internal void Save(IEmitter emitter, bool assignAnchors = true) { if (assignAnchors) { AssignAnchors(); } emitter.Emit(new YamlDotNet.Core.Events.DocumentStart()); RootNode.Save(emitter, new EmitterState()); emitter.Emit(new YamlDotNet.Core.Events.DocumentEnd(isImplicit: false)); } public void Accept(IYamlVisitor visitor) { visitor.Visit(this); } } internal sealed class YamlMappingNode : YamlNode, IEnumerable>, IEnumerable, IYamlConvertible { private readonly OrderedDictionary children = new OrderedDictionary(); public IOrderedDictionary Children => children; public MappingStyle Style { get; set; } public override YamlNodeType NodeType => YamlNodeType.Mapping; internal YamlMappingNode(IParser parser, DocumentLoadingState state) { Load(parser, state); } private void Load(IParser parser, DocumentLoadingState state) { MappingStart mappingStart = parser.Consume(); Load(mappingStart, state); Style = mappingStart.Style; bool flag = false; MappingEnd @event; while (!parser.TryConsume(out @event)) { YamlNode yamlNode = YamlNode.ParseNode(parser, state); YamlNode yamlNode2 = YamlNode.ParseNode(parser, state); if (!children.TryAdd(yamlNode, yamlNode2)) { Mark start = yamlNode.Start; Mark end = yamlNode.End; throw new YamlException(in start, in end, $"Duplicate key {yamlNode}"); } flag = flag || yamlNode is YamlAliasNode || yamlNode2 is YamlAliasNode; } if (flag) { state.AddNodeWithUnresolvedAliases(this); } } public YamlMappingNode() { } public YamlMappingNode(params KeyValuePair[] children) : this((IEnumerable>)children) { } public YamlMappingNode(IEnumerable> children) { foreach (KeyValuePair child in children) { this.children.Add(child); } } public YamlMappingNode(params YamlNode[] children) : this((IEnumerable)children) { } public YamlMappingNode(IEnumerable children) { using IEnumerator enumerator = children.GetEnumerator(); while (enumerator.MoveNext()) { YamlNode current = enumerator.Current; if (!enumerator.MoveNext()) { throw new ArgumentException("When constructing a mapping node with a sequence, the number of elements of the sequence must be even."); } Add(current, enumerator.Current); } } public void Add(YamlNode key, YamlNode value) { children.Add(key, value); } public void Add(string key, YamlNode value) { children.Add(new YamlScalarNode(key), value); } public void Add(YamlNode key, string value) { children.Add(key, new YamlScalarNode(value)); } public void Add(string key, string value) { children.Add(new YamlScalarNode(key), new YamlScalarNode(value)); } internal override void ResolveAliases(DocumentLoadingState state) { Dictionary dictionary = null; Dictionary dictionary2 = null; foreach (KeyValuePair child in children) { if (child.Key is YamlAliasNode) { if (dictionary == null) { dictionary = new Dictionary(); } dictionary.Add(child.Key, state.GetNode(child.Key.Anchor, child.Key.Start, child.Key.End)); } if (child.Value is YamlAliasNode) { if (dictionary2 == null) { dictionary2 = new Dictionary(); } dictionary2.Add(child.Key, state.GetNode(child.Value.Anchor, child.Value.Start, child.Value.End)); } } if (dictionary2 != null) { foreach (KeyValuePair item in dictionary2) { children[item.Key] = item.Value; } } if (dictionary == null) { return; } foreach (KeyValuePair item2 in dictionary) { YamlNode value = children[item2.Key]; children.Remove(item2.Key); children.Add(item2.Value, value); } } internal override void Emit(IEmitter emitter, EmitterState state) { emitter.Emit(new MappingStart(base.Anchor, base.Tag, isImplicit: true, Style)); foreach (KeyValuePair child in children) { child.Key.Save(emitter, state); child.Value.Save(emitter, state); } emitter.Emit(new MappingEnd()); } public override void Accept(IYamlVisitor visitor) { visitor.Visit(this); } public override bool Equals(object? obj) { if (!(obj is YamlMappingNode yamlMappingNode) || !object.Equals(base.Tag, yamlMappingNode.Tag) || children.Count != yamlMappingNode.children.Count) { return false; } foreach (KeyValuePair child in children) { if (!yamlMappingNode.children.TryGetValue(child.Key, out YamlNode value) || !object.Equals(child.Value, value)) { return false; } } return true; } public override int GetHashCode() { int num = base.GetHashCode(); foreach (KeyValuePair child in children) { num = YamlDotNet.Core.HashCode.CombineHashCodes(num, child.Key); num = (child.Value.Anchor.IsEmpty ? YamlDotNet.Core.HashCode.CombineHashCodes(num, child.Value) : YamlDotNet.Core.HashCode.CombineHashCodes(num, child.Value.Anchor)); } return num; } internal override IEnumerable SafeAllNodes(RecursionLevel level) { level.Increment(); yield return this; foreach (KeyValuePair child in children) { foreach (YamlNode item in child.Key.SafeAllNodes(level)) { yield return item; } foreach (YamlNode item2 in child.Value.SafeAllNodes(level)) { yield return item2; } } level.Decrement(); } internal override string ToString(RecursionLevel level) { if (!level.TryIncrement()) { return "WARNING! INFINITE RECURSION!"; } StringBuilderPool.BuilderWrapper builderWrapper = StringBuilderPool.Rent(); try { StringBuilder builder = builderWrapper.Builder; builder.Append("{ "); foreach (KeyValuePair child in children) { if (builder.Length > 2) { builder.Append(", "); } builder.Append("{ ").Append(child.Key.ToString(level)).Append(", ") .Append(child.Value.ToString(level)) .Append(" }"); } builder.Append(" }"); level.Decrement(); return builder.ToString(); } finally { ((IDisposable)builderWrapper).Dispose(); } } public IEnumerator> GetEnumerator() { return children.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } void IYamlConvertible.Read(IParser parser, Type expectedType, ObjectDeserializer nestedObjectDeserializer) { Load(parser, new DocumentLoadingState()); } void IYamlConvertible.Write(IEmitter emitter, ObjectSerializer nestedObjectSerializer) { Emit(emitter, new EmitterState()); } public static YamlMappingNode FromObject(object mapping) { if (mapping == null) { throw new ArgumentNullException("mapping"); } YamlMappingNode yamlMappingNode = new YamlMappingNode(); foreach (PropertyInfo publicProperty in mapping.GetType().GetPublicProperties()) { if (publicProperty.CanRead && publicProperty.GetGetMethod(nonPublic: false).GetParameters().Length == 0) { object value = publicProperty.GetValue(mapping, null); YamlNode yamlNode = value as YamlNode; if (yamlNode == null) { string text = Convert.ToString(value, CultureInfo.InvariantCulture); yamlNode = text ?? string.Empty; } yamlMappingNode.Add(publicProperty.Name, yamlNode); } } return yamlMappingNode; } } internal abstract class YamlNode { private const int MaximumRecursionLevel = 1000; internal const string MaximumRecursionLevelReachedToStringValue = "WARNING! INFINITE RECURSION!"; public AnchorName Anchor { get; set; } public TagName Tag { get; set; } public Mark Start { get; private set; } = Mark.Empty; public Mark End { get; private set; } = Mark.Empty; public IEnumerable AllNodes { get { RecursionLevel level = new RecursionLevel(1000); return SafeAllNodes(level); } } public abstract YamlNodeType NodeType { get; } public YamlNode this[int index] { get { if (!(this is YamlSequenceNode yamlSequenceNode)) { throw new ArgumentException($"Accessed '{NodeType}' with an invalid index: {index}. Only Sequences can be indexed by number."); } return yamlSequenceNode.Children[index]; } } public YamlNode this[YamlNode key] { get { if (!(this is YamlMappingNode yamlMappingNode)) { throw new ArgumentException($"Accessed '{NodeType}' with an invalid index: {key}. Only Mappings can be indexed by key."); } return yamlMappingNode.Children[key]; } } internal void Load(NodeEvent yamlEvent, DocumentLoadingState state) { Tag = yamlEvent.Tag; if (!yamlEvent.Anchor.IsEmpty) { Anchor = yamlEvent.Anchor; state.AddAnchor(this); } Start = yamlEvent.Start; End = yamlEvent.End; } internal static YamlNode ParseNode(IParser parser, DocumentLoadingState state) { if (parser.Accept(out var _)) { return new YamlScalarNode(parser, state); } if (parser.Accept(out var _)) { return new YamlSequenceNode(parser, state); } if (parser.Accept(out var _)) { return new YamlMappingNode(parser, state); } if (parser.TryConsume(out var event4)) { if (!state.TryGetNode(event4.Value, out YamlNode node)) { return new YamlAliasNode(event4.Value); } return node; } throw new ArgumentException("The current event is of an unsupported type.", "parser"); } internal abstract void ResolveAliases(DocumentLoadingState state); internal void Save(IEmitter emitter, EmitterState state) { if (!Anchor.IsEmpty && !state.EmittedAnchors.Add(Anchor)) { emitter.Emit(new YamlDotNet.Core.Events.AnchorAlias(Anchor)); } else { Emit(emitter, state); } } internal abstract void Emit(IEmitter emitter, EmitterState state); public abstract void Accept(IYamlVisitor visitor); public override string ToString() { RecursionLevel recursionLevel = new RecursionLevel(1000); return ToString(recursionLevel); } internal abstract string ToString(RecursionLevel level); internal abstract IEnumerable SafeAllNodes(RecursionLevel level); public static implicit operator YamlNode(string value) { return new YamlScalarNode(value); } public static implicit operator YamlNode(string[] sequence) { return new YamlSequenceNode(((IEnumerable)sequence).Select((Func)((string i) => i))); } public static explicit operator string?(YamlNode node) { if (!(node is YamlScalarNode yamlScalarNode)) { throw new ArgumentException($"Attempted to convert a '{node.NodeType}' to string. This conversion is valid only for Scalars."); } return yamlScalarNode.Value; } } internal sealed class YamlNodeIdentityEqualityComparer : IEqualityComparer { public bool Equals([AllowNull] YamlNode x, [AllowNull] YamlNode y) { return x == y; } public int GetHashCode(YamlNode obj) { return obj.GetHashCode(); } } internal enum YamlNodeType { Alias, Mapping, Scalar, Sequence } [DebuggerDisplay("{Value}")] internal sealed class YamlScalarNode : YamlNode, IYamlConvertible { private bool forceImplicitPlain; private string? value; public string? Value { get { return value; } set { if (value == null) { forceImplicitPlain = true; } else { forceImplicitPlain = false; } this.value = value; } } public ScalarStyle Style { get; set; } public override YamlNodeType NodeType => YamlNodeType.Scalar; internal YamlScalarNode(IParser parser, DocumentLoadingState state) { Load(parser, state); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void Load(IParser parser, DocumentLoadingState state) { YamlDotNet.Core.Events.Scalar scalar = parser.Consume(); Load(scalar, state); string text = scalar.Value; if (scalar.Style == ScalarStyle.Plain && base.Tag.IsEmpty) { forceImplicitPlain = text.Length switch { 0 => true, 1 => text == "~", 4 => text == "null" || text == "Null" || text == "NULL", _ => false, }; } value = text; Style = scalar.Style; } public YamlScalarNode() { } public YamlScalarNode(string? value) { Value = value; } internal override void ResolveAliases(DocumentLoadingState state) { throw new NotSupportedException("Resolving an alias on a scalar node does not make sense"); } internal override void Emit(IEmitter emitter, EmitterState state) { TagName tag = base.Tag; bool isPlainImplicit = tag.IsEmpty; if (forceImplicitPlain && Style == ScalarStyle.Plain && (Value == null || Value == "")) { tag = JsonSchema.Tags.Null; isPlainImplicit = true; } else if (tag.IsEmpty && Value == null && (Style == ScalarStyle.Plain || Style == ScalarStyle.Any)) { tag = JsonSchema.Tags.Null; isPlainImplicit = true; } emitter.Emit(new YamlDotNet.Core.Events.Scalar(base.Anchor, tag, Value ?? string.Empty, Style, isPlainImplicit, isQuotedImplicit: false)); } public override void Accept(IYamlVisitor visitor) { visitor.Visit(this); } public override bool Equals(object? obj) { if (obj is YamlScalarNode yamlScalarNode && object.Equals(base.Tag, yamlScalarNode.Tag)) { return object.Equals(Value, yamlScalarNode.Value); } return false; } public override int GetHashCode() { return YamlDotNet.Core.HashCode.CombineHashCodes(base.Tag.GetHashCode(), Value); } public static explicit operator string?(YamlScalarNode value) { return value.Value; } internal override string ToString(RecursionLevel level) { return Value ?? string.Empty; } internal override IEnumerable SafeAllNodes(RecursionLevel level) { yield return this; } void IYamlConvertible.Read(IParser parser, Type expectedType, ObjectDeserializer nestedObjectDeserializer) { Load(parser, new DocumentLoadingState()); } void IYamlConvertible.Write(IEmitter emitter, ObjectSerializer nestedObjectSerializer) { Emit(emitter, new EmitterState()); } } [DebuggerDisplay("Count = {children.Count}")] internal sealed class YamlSequenceNode : YamlNode, IEnumerable, IEnumerable, IYamlConvertible { private readonly List children = new List(); public IList Children => children; public SequenceStyle Style { get; set; } public override YamlNodeType NodeType => YamlNodeType.Sequence; internal YamlSequenceNode(IParser parser, DocumentLoadingState state) { Load(parser, state); } private void Load(IParser parser, DocumentLoadingState state) { SequenceStart sequenceStart = parser.Consume(); Load(sequenceStart, state); Style = sequenceStart.Style; bool flag = false; SequenceEnd @event; while (!parser.TryConsume(out @event)) { YamlNode yamlNode = YamlNode.ParseNode(parser, state); children.Add(yamlNode); flag = flag || yamlNode is YamlAliasNode; } if (flag) { state.AddNodeWithUnresolvedAliases(this); } } public YamlSequenceNode() { } public YamlSequenceNode(params YamlNode[] children) : this((IEnumerable)children) { } public YamlSequenceNode(IEnumerable children) { foreach (YamlNode child in children) { this.children.Add(child); } } public void Add(YamlNode child) { children.Add(child); } public void Add(string child) { children.Add(new YamlScalarNode(child)); } internal override void ResolveAliases(DocumentLoadingState state) { for (int i = 0; i < children.Count; i++) { if (children[i] is YamlAliasNode) { children[i] = state.GetNode(children[i].Anchor, children[i].Start, children[i].End); } } } internal override void Emit(IEmitter emitter, EmitterState state) { emitter.Emit(new SequenceStart(base.Anchor, base.Tag, base.Tag.IsEmpty, Style)); foreach (YamlNode child in children) { child.Save(emitter, state); } emitter.Emit(new SequenceEnd()); } public override void Accept(IYamlVisitor visitor) { visitor.Visit(this); } public override bool Equals(object? obj) { if (!(obj is YamlSequenceNode yamlSequenceNode) || !object.Equals(base.Tag, yamlSequenceNode.Tag) || children.Count != yamlSequenceNode.children.Count) { return false; } for (int i = 0; i < children.Count; i++) { if (!object.Equals(children[i], yamlSequenceNode.children[i])) { return false; } } return true; } public override int GetHashCode() { int h = 0; foreach (YamlNode child in children) { h = YamlDotNet.Core.HashCode.CombineHashCodes(h, child); } return YamlDotNet.Core.HashCode.CombineHashCodes(h, base.Tag); } internal override IEnumerable SafeAllNodes(RecursionLevel level) { level.Increment(); yield return this; foreach (YamlNode child in children) { foreach (YamlNode item in child.SafeAllNodes(level)) { yield return item; } } level.Decrement(); } internal override string ToString(RecursionLevel level) { if (!level.TryIncrement()) { return "WARNING! INFINITE RECURSION!"; } StringBuilderPool.BuilderWrapper builderWrapper = StringBuilderPool.Rent(); try { StringBuilder builder = builderWrapper.Builder; builder.Append("[ "); foreach (YamlNode child in children) { if (builder.Length > 2) { builder.Append(", "); } builder.Append(child.ToString(level)); } builder.Append(" ]"); level.Decrement(); return builder.ToString(); } finally { ((IDisposable)builderWrapper).Dispose(); } } public IEnumerator GetEnumerator() { return Children.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } void IYamlConvertible.Read(IParser parser, Type expectedType, ObjectDeserializer nestedObjectDeserializer) { Load(parser, new DocumentLoadingState()); } void IYamlConvertible.Write(IEmitter emitter, ObjectSerializer nestedObjectSerializer) { Emit(emitter, new EmitterState()); } } internal class YamlStream : IEnumerable, IEnumerable { private readonly List documents = new List(); public IList Documents => documents; public YamlStream() { } public YamlStream(params YamlDocument[] documents) : this((IEnumerable)documents) { } public YamlStream(IEnumerable documents) { foreach (YamlDocument document in documents) { this.documents.Add(document); } } public void Add(YamlDocument document) { documents.Add(document); } public void Load(TextReader input) { Load(new Parser(input)); } public void Load(IParser parser) { documents.Clear(); parser.Consume(); YamlDotNet.Core.Events.StreamEnd @event; while (!parser.TryConsume(out @event)) { YamlDocument item = new YamlDocument(parser); documents.Add(item); } } public void Save(TextWriter output) { Save(output, assignAnchors: true); } public void Save(TextWriter output, bool assignAnchors) { Save(new Emitter(output), assignAnchors); } public void Save(IEmitter emitter, bool assignAnchors) { emitter.Emit(new YamlDotNet.Core.Events.StreamStart()); foreach (YamlDocument document in documents) { document.Save(emitter, assignAnchors); } emitter.Emit(new YamlDotNet.Core.Events.StreamEnd()); } public void Accept(IYamlVisitor visitor) { visitor.Visit(this); } public IEnumerator GetEnumerator() { return documents.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } [Obsolete("Use YamlVisitorBase")] internal abstract class YamlVisitor : IYamlVisitor { protected virtual void Visit(YamlStream stream) { } protected virtual void Visited(YamlStream stream) { } protected virtual void Visit(YamlDocument document) { } protected virtual void Visited(YamlDocument document) { } protected virtual void Visit(YamlScalarNode scalar) { } protected virtual void Visited(YamlScalarNode scalar) { } protected virtual void Visit(YamlSequenceNode sequence) { } protected virtual void Visited(YamlSequenceNode sequence) { } protected virtual void Visit(YamlMappingNode mapping) { } protected virtual void Visited(YamlMappingNode mapping) { } protected virtual void VisitChildren(YamlStream stream) { foreach (YamlDocument document in stream.Documents) { document.Accept(this); } } protected virtual void VisitChildren(YamlDocument document) { if (document.RootNode != null) { document.RootNode.Accept(this); } } protected virtual void VisitChildren(YamlSequenceNode sequence) { foreach (YamlNode child in sequence.Children) { child.Accept(this); } } protected virtual void VisitChildren(YamlMappingNode mapping) { foreach (KeyValuePair child in mapping.Children) { child.Key.Accept(this); child.Value.Accept(this); } } void IYamlVisitor.Visit(YamlStream stream) { Visit(stream); VisitChildren(stream); Visited(stream); } void IYamlVisitor.Visit(YamlDocument document) { Visit(document); VisitChildren(document); Visited(document); } void IYamlVisitor.Visit(YamlScalarNode scalar) { Visit(scalar); Visited(scalar); } void IYamlVisitor.Visit(YamlSequenceNode sequence) { Visit(sequence); VisitChildren(sequence); Visited(sequence); } void IYamlVisitor.Visit(YamlMappingNode mapping) { Visit(mapping); VisitChildren(mapping); Visited(mapping); } } internal abstract class YamlVisitorBase : IYamlVisitor { public virtual void Visit(YamlStream stream) { VisitChildren(stream); } public virtual void Visit(YamlDocument document) { VisitChildren(document); } public virtual void Visit(YamlScalarNode scalar) { } public virtual void Visit(YamlSequenceNode sequence) { VisitChildren(sequence); } public virtual void Visit(YamlMappingNode mapping) { VisitChildren(mapping); } protected virtual void VisitPair(YamlNode key, YamlNode value) { key.Accept(this); value.Accept(this); } protected virtual void VisitChildren(YamlStream stream) { foreach (YamlDocument document in stream.Documents) { document.Accept(this); } } protected virtual void VisitChildren(YamlDocument document) { if (document.RootNode != null) { document.RootNode.Accept(this); } } protected virtual void VisitChildren(YamlSequenceNode sequence) { foreach (YamlNode child in sequence.Children) { child.Accept(this); } } protected virtual void VisitChildren(YamlMappingNode mapping) { foreach (KeyValuePair child in mapping.Children) { VisitPair(child.Key, child.Value); } } } } namespace YamlDotNet.Helpers { internal class DefaultFsharpHelper : IFsharpHelper { private static bool IsFsharpCore(Type t) { return t.Namespace == "Microsoft.FSharp.Core"; } public bool IsOptionType(Type t) { if (IsFsharpCore(t)) { return t.Name == "FSharpOption`1"; } return false; } public Type? GetOptionUnderlyingType(Type t) { if (!t.IsGenericType || !IsOptionType(t)) { return null; } return t.GenericTypeArguments[0]; } public object? GetValue(IObjectDescriptor objectDescriptor) { if (!IsOptionType(objectDescriptor.Type)) { throw new InvalidOperationException("Should not be called on non-Option<> type"); } if (objectDescriptor.Value == null) { return null; } return objectDescriptor.Type.GetProperty("Value").GetValue(objectDescriptor.Value); } public bool IsFsharpListType(Type t) { if (t.Namespace == "Microsoft.FSharp.Collections") { return t.Name == "FSharpList`1"; } return false; } public object? CreateFsharpListFromArray(Type t, Type itemsType, Array arr) { if (!IsFsharpListType(t)) { return null; } return t.Assembly.GetType("Microsoft.FSharp.Collections.ListModule").GetMethod("OfArray").MakeGenericMethod(itemsType) .Invoke(null, new object[1] { arr }); } } internal static class DictionaryExtensions { public static bool TryAdd(this Dictionary dictionary, T key, V value) { if (dictionary.ContainsKey(key)) { return false; } dictionary.Add(key, value); return true; } public static TValue GetOrAdd(this ConcurrentDictionary dictionary, TKey key, Func valueFactory, TArg arg) { if (dictionary == null) { throw new ArgumentNullException("dictionary"); } if (key == null) { throw new ArgumentNullException("key"); } if (valueFactory == null) { throw new ArgumentNullException("valueFactory"); } TValue value; do { if (dictionary.TryGetValue(key, out value)) { return value; } value = valueFactory(key, arg); } while (!dictionary.TryAdd(key, value)); return value; } } internal static class ExpressionExtensions { public static PropertyInfo AsProperty(this LambdaExpression propertyAccessor) { PropertyInfo propertyInfo = TryGetMemberExpression(propertyAccessor); if (propertyInfo == null) { throw new ArgumentException("Expected a lambda expression in the form: x => x.SomeProperty", "propertyAccessor"); } return propertyInfo; } [return: MaybeNull] private static TMemberInfo TryGetMemberExpression(LambdaExpression lambdaExpression) where TMemberInfo : MemberInfo { if (lambdaExpression.Parameters.Count != 1) { return null; } Expression expression = lambdaExpression.Body; if (expression is UnaryExpression unaryExpression) { if (unaryExpression.NodeType != ExpressionType.Convert) { return null; } expression = unaryExpression.Operand; } if (expression is MemberExpression memberExpression) { if (memberExpression.Expression != lambdaExpression.Parameters[0]) { return null; } return memberExpression.Member as TMemberInfo; } return null; } } internal static class FsharpHelper { public static IFsharpHelper? Instance { get; set; } public static bool IsOptionType(Type t) { return Instance?.IsOptionType(t) ?? false; } public static Type? GetOptionUnderlyingType(Type t) { return Instance?.GetOptionUnderlyingType(t); } public static object? GetValue(IObjectDescriptor objectDescriptor) { return Instance?.GetValue(objectDescriptor); } public static bool IsFsharpListType(Type t) { return Instance?.IsFsharpListType(t) ?? false; } public static object? CreateFsharpListFromArray(Type t, Type itemsType, Array arr) { return Instance?.CreateFsharpListFromArray(t, itemsType, arr); } } internal sealed class GenericCollectionToNonGenericAdapter : IList, ICollection, IEnumerable { private readonly ICollection genericCollection; public bool IsFixedSize { get { throw new NotSupportedException(); } } public bool IsReadOnly { get { throw new NotSupportedException(); } } public object? this[int index] { get { throw new NotSupportedException(); } set { ((IList)genericCollection)[index] = (T)value; } } public int Count { get { throw new NotSupportedException(); } } public bool IsSynchronized { get { throw new NotSupportedException(); } } public object SyncRoot { get { throw new NotSupportedException(); } } public GenericCollectionToNonGenericAdapter(ICollection genericCollection) { this.genericCollection = genericCollection ?? throw new ArgumentNullException("genericCollection"); } public int Add(object? value) { int count = genericCollection.Count; genericCollection.Add((T)value); return count; } public void Clear() { genericCollection.Clear(); } public bool Contains(object? value) { throw new NotSupportedException(); } public int IndexOf(object? value) { throw new NotSupportedException(); } public void Insert(int index, object? value) { throw new NotSupportedException(); } public void Remove(object? value) { throw new NotSupportedException(); } public void RemoveAt(int index) { throw new NotSupportedException(); } public void CopyTo(Array array, int index) { throw new NotSupportedException(); } public IEnumerator GetEnumerator() { return genericCollection.GetEnumerator(); } } internal sealed class GenericDictionaryToNonGenericAdapter : IDictionary, ICollection, IEnumerable where TKey : notnull { private class DictionaryEnumerator : IDictionaryEnumerator, IEnumerator { private readonly IEnumerator> enumerator; public DictionaryEntry Entry => new DictionaryEntry(Key, Value); public object Key => enumerator.Current.Key; public object? Value => enumerator.Current.Value; public object Current => Entry; public DictionaryEnumerator(IEnumerator> enumerator) { this.enumerator = enumerator; } public bool MoveNext() { return enumerator.MoveNext(); } public void Reset() { enumerator.Reset(); } } private readonly IDictionary genericDictionary; public bool IsFixedSize { get { throw new NotSupportedException(); } } public bool IsReadOnly { get { throw new NotSupportedException(); } } public ICollection Keys { get { throw new NotSupportedException(); } } public ICollection Values { get { throw new NotSupportedException(); } } public object? this[object key] { get { throw new NotSupportedException(); } set { genericDictionary[(TKey)key] = (TValue)value; } } public int Count { get { throw new NotSupportedException(); } } public bool IsSynchronized { get { throw new NotSupportedException(); } } public object SyncRoot { get { throw new NotSupportedException(); } } public GenericDictionaryToNonGenericAdapter(IDictionary genericDictionary) { this.genericDictionary = genericDictionary ?? throw new ArgumentNullException("genericDictionary"); } public void Add(object key, object? value) { throw new NotSupportedException(); } public void Clear() { throw new NotSupportedException(); } public bool Contains(object key) { throw new NotSupportedException(); } public IDictionaryEnumerator GetEnumerator() { return new DictionaryEnumerator(genericDictionary.GetEnumerator()); } public void Remove(object key) { throw new NotSupportedException(); } public void CopyTo(Array array, int index) { throw new NotSupportedException(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } internal interface IFsharpHelper { bool IsOptionType(Type t); Type? GetOptionUnderlyingType(Type t); object? GetValue(IObjectDescriptor objectDescriptor); bool IsFsharpListType(Type t); object? CreateFsharpListFromArray(Type t, Type itemsType, Array arr); } internal interface IOrderedDictionary : IDictionary, ICollection>, IEnumerable>, IEnumerable where TKey : notnull { KeyValuePair this[int index] { get; set; } void Insert(int index, TKey key, TValue value); void RemoveAt(int index); } internal class NullFsharpHelper : IFsharpHelper { public object? CreateFsharpListFromArray(Type t, Type itemsType, Array arr) { return null; } public Type? GetOptionUnderlyingType(Type t) { return null; } public object? GetValue(IObjectDescriptor objectDescriptor) { return null; } public bool IsFsharpListType(Type t) { return false; } public bool IsOptionType(Type t) { return false; } } internal static class NumberExtensions { public static bool IsPowerOfTwo(this int value) { return (value & (value - 1)) == 0; } } [Serializable] internal sealed class OrderedDictionary : IOrderedDictionary, IDictionary, ICollection>, IEnumerable>, IEnumerable where TKey : notnull { private class KeyCollection : ICollection, IEnumerable, IEnumerable { private readonly OrderedDictionary orderedDictionary; public int Count => orderedDictionary.list.Count; public bool IsReadOnly => true; public void Add(TKey item) { throw new NotSupportedException(); } public void Clear() { throw new NotSupportedException(); } public bool Contains(TKey item) { return orderedDictionary.dictionary.ContainsKey(item); } public KeyCollection(OrderedDictionary orderedDictionary) { this.orderedDictionary = orderedDictionary; } public void CopyTo(TKey[] array, int arrayIndex) { for (int i = 0; i < orderedDictionary.list.Count; i++) { array[i] = orderedDictionary.list[i + arrayIndex].Key; } } public IEnumerator GetEnumerator() { return orderedDictionary.list.Select((KeyValuePair kvp) => kvp.Key).GetEnumerator(); } public bool Remove(TKey item) { throw new NotSupportedException(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } private class ValueCollection : ICollection, IEnumerable, IEnumerable { private readonly OrderedDictionary orderedDictionary; public int Count => orderedDictionary.list.Count; public bool IsReadOnly => true; public void Add(TValue item) { throw new NotSupportedException(); } public void Clear() { throw new NotSupportedException(); } public bool Contains(TValue item) { return orderedDictionary.dictionary.ContainsValue(item); } public ValueCollection(OrderedDictionary orderedDictionary) { this.orderedDictionary = orderedDictionary; } public void CopyTo(TValue[] array, int arrayIndex) { for (int i = 0; i < orderedDictionary.list.Count; i++) { array[i] = orderedDictionary.list[i + arrayIndex].Value; } } public IEnumerator GetEnumerator() { return orderedDictionary.list.Select((KeyValuePair kvp) => kvp.Value).GetEnumerator(); } public bool Remove(TValue item) { throw new NotSupportedException(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } [NonSerialized] private Dictionary dictionary; private readonly List> list; private readonly IEqualityComparer comparer; public TValue this[TKey key] { get { return dictionary[key]; } set { TKey key2 = key; if (dictionary.ContainsKey(key2)) { int index = list.FindIndex((KeyValuePair kvp) => comparer.Equals(kvp.Key, key2)); dictionary[key2] = value; list[index] = new KeyValuePair(key2, value); } else { Add(key2, value); } } } public ICollection Keys => new KeyCollection(this); public ICollection Values => new ValueCollection(this); public int Count => dictionary.Count; public bool IsReadOnly => false; public KeyValuePair this[int index] { get { return list[index]; } set { list[index] = value; } } public OrderedDictionary() : this((IEqualityComparer)EqualityComparer.Default) { } public OrderedDictionary(IEqualityComparer comparer) { list = new List>(); dictionary = new Dictionary(comparer); this.comparer = comparer; } public void Add(KeyValuePair item) { if (!TryAdd(item)) { ThrowDuplicateKeyException(item.Key); } } public void Add(TKey key, TValue value) { if (!TryAdd(key, value)) { ThrowDuplicateKeyException(key); } } private static void ThrowDuplicateKeyException(TKey key) { throw new ArgumentException($"An item with the same key {key} has already been added."); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool TryAdd(TKey key, TValue value) { if (DictionaryExtensions.TryAdd(dictionary, key, value)) { list.Add(new KeyValuePair(key, value)); return true; } return false; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool TryAdd(KeyValuePair item) { if (DictionaryExtensions.TryAdd(dictionary, item.Key, item.Value)) { list.Add(item); return true; } return false; } public void Clear() { dictionary.Clear(); list.Clear(); } public bool Contains(KeyValuePair item) { return dictionary.Contains(item); } public bool ContainsKey(TKey key) { return dictionary.ContainsKey(key); } public void CopyTo(KeyValuePair[] array, int arrayIndex) { list.CopyTo(array, arrayIndex); } public IEnumerator> GetEnumerator() { return list.GetEnumerator(); } public void Insert(int index, TKey key, TValue value) { dictionary.Add(key, value); list.Insert(index, new KeyValuePair(key, value)); } public bool Remove(TKey key) { TKey key2 = key; if (dictionary.ContainsKey(key2)) { int index = list.FindIndex((KeyValuePair kvp) => comparer.Equals(kvp.Key, key2)); list.RemoveAt(index); if (!dictionary.Remove(key2)) { throw new InvalidOperationException(); } return true; } return false; } public bool Remove(KeyValuePair item) { return Remove(item.Key); } public void RemoveAt(int index) { TKey key = list[index].Key; dictionary.Remove(key); list.RemoveAt(index); } public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) { return dictionary.TryGetValue(key, out value); } IEnumerator IEnumerable.GetEnumerator() { return list.GetEnumerator(); } [System.Runtime.Serialization.OnDeserialized] internal void OnDeserializedMethod(StreamingContext context) { dictionary = new Dictionary(); foreach (KeyValuePair item in list) { dictionary[item.Key] = item.Value; } } } internal static class ReadOnlyCollectionExtensions { public static IReadOnlyList AsReadonlyList(this List list) { return list; } public static IReadOnlyDictionary AsReadonlyDictionary(this Dictionary dictionary) where TKey : notnull { return dictionary; } } internal static class ThrowHelper { [MethodImpl(MethodImplOptions.NoInlining)] public static void ThrowArgumentOutOfRangeException(string paramName, string message) { throw new ArgumentOutOfRangeException(paramName, message); } } } namespace YamlDotNet.Core { internal readonly struct AnchorName : IEquatable { public static readonly AnchorName Empty; private static readonly Regex AnchorPattern = new Regex("^[^\\[\\]\\{\\},]+$", RegexOptions.Compiled); private readonly string? value; public string Value => value ?? throw new InvalidOperationException("Cannot read the Value of an empty anchor"); public bool IsEmpty => value == null; public AnchorName(string value) { this.value = value ?? throw new ArgumentNullException("value"); if (!AnchorPattern.IsMatch(value)) { throw new ArgumentException("Anchor cannot be empty or contain disallowed characters: []{},\nThe value was '" + value + "'.", "value"); } } public override string ToString() { return value ?? "[empty]"; } public bool Equals(AnchorName other) { return object.Equals(value, other.value); } public override bool Equals(object? obj) { if (obj is AnchorName other) { return Equals(other); } return false; } public override int GetHashCode() { return value?.GetHashCode() ?? 0; } public static bool operator ==(AnchorName left, AnchorName right) { return left.Equals(right); } public static bool operator !=(AnchorName left, AnchorName right) { return !(left == right); } public static implicit operator AnchorName(string? value) { if (value != null) { return new AnchorName(value); } return Empty; } } internal class AnchorNotFoundException : YamlException { public AnchorNotFoundException(string message) : base(message) { } public AnchorNotFoundException(in Mark start, in Mark end, string message) : base(in start, in end, message) { } public AnchorNotFoundException(string message, Exception inner) : base(message, inner) { } } [DebuggerStepThrough] internal readonly struct CharacterAnalyzer where TBuffer : ILookAheadBuffer { public TBuffer Buffer { get; } public bool EndOfInput => Buffer.EndOfInput; public CharacterAnalyzer(TBuffer buffer) { if (buffer == null) { throw new ArgumentNullException("buffer"); } Buffer = buffer; } public char Peek(int offset) { return Buffer.Peek(offset); } public void Skip(int length) { Buffer.Skip(length); } public bool IsAlphaNumericDashOrUnderscore(int offset = 0) { char c = Buffer.Peek(offset); if ((c < '0' || c > '9') && (c < 'A' || c > 'Z') && (c < 'a' || c > 'z') && c != '_') { return c == '-'; } return true; } public bool IsAscii(int offset = 0) { return Buffer.Peek(offset) <= '\u007f'; } public bool IsPrintable(int offset = 0) { char c = Buffer.Peek(offset); switch (c) { default: if (c != '\u0085' && (c < '\u00a0' || c > '\ud7ff')) { if (c >= '\ue000') { return c <= '\ufffd'; } return false; } break; case '\t': case '\n': case '\r': case ' ': case '!': case '"': case '#': case '$': case '%': case '&': case '\'': case '(': case ')': case '*': case '+': case ',': case '-': case '.': case '/': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case ':': case ';': case '<': case '=': case '>': case '?': case '@': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '[': case '\\': case ']': case '^': case '_': case '`': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case '{': case '|': case '}': case '~': break; } return true; } public bool IsDigit(int offset = 0) { char c = Buffer.Peek(offset); if (c >= '0') { return c <= '9'; } return false; } public int AsDigit(int offset = 0) { return Buffer.Peek(offset) - 48; } public bool IsHex(int offset) { char c = Buffer.Peek(offset); if ((c < '0' || c > '9') && (c < 'A' || c > 'F')) { if (c >= 'a') { return c <= 'f'; } return false; } return true; } public int AsHex(int offset) { char c = Buffer.Peek(offset); if (c <= '9') { return c - 48; } if (c <= 'F') { return c - 65 + 10; } return c - 97 + 10; } public bool IsSpace(int offset = 0) { return Check(' ', offset); } public bool IsZero(int offset = 0) { return Check('\0', offset); } public bool IsTab(int offset = 0) { return Check('\t', offset); } public bool IsWhite(int offset = 0) { if (!IsSpace(offset)) { return IsTab(offset); } return true; } public bool IsBreak(int offset = 0) { return Check("\r\n\u0085\u2028\u2029", offset); } public bool IsCrLf(int offset = 0) { if (Check('\r', offset)) { return Check('\n', offset + 1); } return false; } public bool IsBreakOrZero(int offset = 0) { if (!IsBreak(offset)) { return IsZero(offset); } return true; } public bool IsWhiteBreakOrZero(int offset = 0) { if (!IsWhite(offset)) { return IsBreakOrZero(offset); } return true; } public bool Check(char expected, int offset = 0) { return Buffer.Peek(offset) == expected; } public bool Check(string expectedCharacters, int offset = 0) { char c = Buffer.Peek(offset); return Polyfills.Contains(expectedCharacters, c); } } internal static class Constants { public static readonly TagDirective[] DefaultTagDirectives = new TagDirective[2] { new TagDirective("!", "!"), new TagDirective("!!", "tag:yaml.org,2002:") }; public const int MajorVersion = 1; public const int MinorVersion = 3; } [DebuggerStepThrough] internal sealed class Cursor { public long Index { get; private set; } public long Line { get; private set; } public long LineOffset { get; private set; } public Cursor() { Line = 1L; } public Cursor(Cursor cursor) { Index = cursor.Index; Line = cursor.Line; LineOffset = cursor.LineOffset; } public Mark Mark() { return new Mark(Index, Line, LineOffset + 1); } public void Skip() { Index++; LineOffset++; } public void SkipLineByOffset(int offset) { Index += offset; Line++; LineOffset = 0L; } public void ForceSkipLineAfterNonBreak() { if (LineOffset != 0L) { Line++; LineOffset = 0L; } } } internal class Emitter : IEmitter { private class AnchorData { public AnchorName Anchor; public bool IsAlias; } private class TagData { public string? Handle; public string? Suffix; } private class ScalarData { public string Value = string.Empty; public bool IsMultiline; public bool IsFlowPlainAllowed; public bool IsBlockPlainAllowed; public bool IsSingleQuotedAllowed; public bool IsBlockAllowed; public bool HasSingleQuotes; public ScalarStyle Style; } private static readonly Regex UriReplacer = new Regex("[^0-9A-Za-z_\\-;?@=$~\\\\\\)\\]/:&+,\\.\\*\\(\\[!]", RegexOptions.Compiled | RegexOptions.Singleline); private static readonly string[] NewLineSeparators = new string[3] { "\r\n", "\r", "\n" }; private readonly TextWriter output; private readonly bool outputUsesUnicodeEncoding; private readonly int maxSimpleKeyLength; private readonly bool isCanonical; private readonly bool skipAnchorName; private readonly int bestIndent; private readonly int bestWidth; private EmitterState state; private readonly Stack states = new Stack(); private readonly Queue events = new Queue(); private readonly Stack indents = new Stack(); private readonly TagDirectiveCollection tagDirectives = new TagDirectiveCollection(); private int indent; private int flowLevel; private bool isMappingContext; private bool isSimpleKeyContext; private int column; private bool isWhitespace; private bool isIndentation; private readonly bool forceIndentLess; private readonly bool useUtf16SurrogatePair; private bool isDocumentEndWritten; private readonly AnchorData anchorData = new AnchorData(); private readonly TagData tagData = new TagData(); private readonly ScalarData scalarData = new ScalarData(); public Emitter(TextWriter output) : this(output, EmitterSettings.Default) { } public Emitter(TextWriter output, int bestIndent) : this(output, bestIndent, int.MaxValue) { } public Emitter(TextWriter output, int bestIndent, int bestWidth) : this(output, bestIndent, bestWidth, isCanonical: false) { } public Emitter(TextWriter output, int bestIndent, int bestWidth, bool isCanonical) : this(output, new EmitterSettings(bestIndent, bestWidth, isCanonical, 1024)) { } public Emitter(TextWriter output, EmitterSettings settings) { bestIndent = settings.BestIndent; bestWidth = settings.BestWidth; isCanonical = settings.IsCanonical; maxSimpleKeyLength = settings.MaxSimpleKeyLength; skipAnchorName = settings.SkipAnchorName; forceIndentLess = !settings.IndentSequences; useUtf16SurrogatePair = settings.UseUtf16SurrogatePairs; this.output = output; this.output.NewLine = settings.NewLine; outputUsesUnicodeEncoding = IsUnicode(output.Encoding); } public void Emit(ParsingEvent @event) { events.Enqueue(@event); while (!NeedMoreEvents()) { ParsingEvent evt = events.Peek(); try { AnalyzeEvent(evt); StateMachine(evt); } finally { events.Dequeue(); } } } private bool NeedMoreEvents() { if (events.Count == 0) { return true; } int num; switch (events.Peek().Type) { case EventType.DocumentStart: num = 1; break; case EventType.SequenceStart: num = 2; break; case EventType.MappingStart: num = 3; break; default: return false; } if (events.Count > num) { return false; } int num2 = 0; foreach (ParsingEvent @event in events) { switch (@event.Type) { case EventType.DocumentStart: case EventType.SequenceStart: case EventType.MappingStart: num2++; break; case EventType.DocumentEnd: case EventType.SequenceEnd: case EventType.MappingEnd: num2--; break; } if (num2 == 0) { return false; } } return true; } private void AnalyzeEvent(ParsingEvent evt) { anchorData.Anchor = AnchorName.Empty; tagData.Handle = null; tagData.Suffix = null; if (evt is YamlDotNet.Core.Events.AnchorAlias anchorAlias) { AnalyzeAnchor(anchorAlias.Value, isAlias: true); } else if (evt is NodeEvent nodeEvent) { if (evt is YamlDotNet.Core.Events.Scalar scalar) { AnalyzeScalar(scalar); } AnalyzeAnchor(nodeEvent.Anchor, isAlias: false); if (!nodeEvent.Tag.IsEmpty && (isCanonical || nodeEvent.IsCanonical)) { AnalyzeTag(nodeEvent.Tag); } } } private void AnalyzeAnchor(AnchorName anchor, bool isAlias) { anchorData.Anchor = anchor; anchorData.IsAlias = isAlias; } private void AnalyzeScalar(YamlDotNet.Core.Events.Scalar scalar) { string value = scalar.Value; scalarData.Value = value; if (value.Length == 0) { if (scalar.Tag == "tag:yaml.org,2002:null") { scalarData.IsMultiline = false; scalarData.IsFlowPlainAllowed = false; scalarData.IsBlockPlainAllowed = true; scalarData.IsSingleQuotedAllowed = false; scalarData.IsBlockAllowed = false; } else { scalarData.IsMultiline = false; scalarData.IsFlowPlainAllowed = false; scalarData.IsBlockPlainAllowed = false; scalarData.IsSingleQuotedAllowed = true; scalarData.IsBlockAllowed = false; } return; } bool flag = false; bool flag2 = false; if (value.StartsWith("---", StringComparison.Ordinal) || value.StartsWith("...", StringComparison.Ordinal)) { flag = true; flag2 = true; } StringLookAheadBufferPool.BufferWrapper bufferWrapper = StringLookAheadBufferPool.Rent(value); try { CharacterAnalyzer characterAnalyzer = new CharacterAnalyzer(bufferWrapper.Buffer); bool flag3 = true; bool flag4 = characterAnalyzer.IsWhiteBreakOrZero(1); bool flag5 = false; bool flag6 = false; bool flag7 = false; bool flag8 = false; bool flag9 = false; bool flag10 = false; bool flag11 = false; bool flag12 = false; bool flag13 = false; bool flag14 = false; bool flag15 = false; bool flag16 = !ValueIsRepresentableInOutputEncoding(value); bool flag17 = false; bool flag18 = false; bool flag19 = true; while (!characterAnalyzer.EndOfInput) { if (flag19) { if (characterAnalyzer.Check("#,[]{}&*!|>\"%@`'")) { flag = true; flag2 = true; flag9 = characterAnalyzer.Check('\''); flag17 |= characterAnalyzer.Check('\''); } if (characterAnalyzer.Check("?:")) { flag = true; if (flag4) { flag2 = true; } } if (characterAnalyzer.Check('-') && flag4) { flag = true; flag2 = true; } } else { if (characterAnalyzer.Check(",?[]{}")) { flag = true; } if (characterAnalyzer.Check(':')) { flag = true; if (flag4) { flag2 = true; } } if (characterAnalyzer.Check('#') && flag3) { flag = true; flag2 = true; } flag17 |= characterAnalyzer.Check('\''); } if (!flag16 && !characterAnalyzer.IsPrintable()) { flag16 = true; } if (characterAnalyzer.IsBreak()) { flag15 = true; } if (characterAnalyzer.IsSpace()) { if (flag19) { flag5 = true; } if (characterAnalyzer.Buffer.Position >= characterAnalyzer.Buffer.Length - 1) { flag7 = true; } if (flag13) { flag10 = true; flag14 = true; } flag12 = true; flag13 = false; } else if (characterAnalyzer.IsBreak()) { if (flag19) { flag6 = true; } if (characterAnalyzer.Buffer.Position >= characterAnalyzer.Buffer.Length - 1) { flag8 = true; } if (flag12) { flag11 = true; } if (flag14) { flag18 = true; } flag12 = false; flag13 = true; } else { flag12 = false; flag13 = false; flag14 = false; } flag3 = characterAnalyzer.IsWhiteBreakOrZero(); characterAnalyzer.Skip(1); if (!characterAnalyzer.EndOfInput) { flag4 = characterAnalyzer.IsWhiteBreakOrZero(1); } flag19 = false; } scalarData.IsFlowPlainAllowed = true; scalarData.IsBlockPlainAllowed = true; scalarData.IsSingleQuotedAllowed = true; scalarData.IsBlockAllowed = true; if (flag5 || flag6 || flag7 || flag8 || flag9) { scalarData.IsFlowPlainAllowed = false; scalarData.IsBlockPlainAllowed = false; } if (flag7) { scalarData.IsBlockAllowed = false; } if (flag10) { scalarData.IsFlowPlainAllowed = false; scalarData.IsBlockPlainAllowed = false; scalarData.IsSingleQuotedAllowed = false; } if (flag11 || flag16) { scalarData.IsFlowPlainAllowed = false; scalarData.IsBlockPlainAllowed = false; scalarData.IsSingleQuotedAllowed = false; } if (flag18) { scalarData.IsBlockAllowed = false; } scalarData.IsMultiline = flag15; if (flag15) { scalarData.IsFlowPlainAllowed = false; scalarData.IsBlockPlainAllowed = false; } if (flag) { scalarData.IsFlowPlainAllowed = false; } if (flag2) { scalarData.IsBlockPlainAllowed = false; } scalarData.HasSingleQuotes = flag17; } finally { ((IDisposable)bufferWrapper).Dispose(); } } private bool ValueIsRepresentableInOutputEncoding(string value) { if (outputUsesUnicodeEncoding) { return true; } try { byte[] bytes = output.Encoding.GetBytes(value); string @string = output.Encoding.GetString(bytes, 0, bytes.Length); return @string.Equals(value); } catch (EncoderFallbackException) { return false; } catch (ArgumentOutOfRangeException) { return false; } } private static bool IsUnicode(Encoding encoding) { if (!(encoding is UTF8Encoding) && !(encoding is UnicodeEncoding)) { return encoding is UTF7Encoding; } return true; } private void AnalyzeTag(TagName tag) { tagData.Handle = tag.Value; foreach (TagDirective tagDirective in tagDirectives) { if (tag.Value.StartsWith(tagDirective.Prefix, StringComparison.Ordinal)) { tagData.Handle = tagDirective.Handle; tagData.Suffix = tag.Value.Substring(tagDirective.Prefix.Length); break; } } } private void StateMachine(ParsingEvent evt) { if (evt is YamlDotNet.Core.Events.Comment comment) { EmitComment(comment); return; } switch (state) { case EmitterState.StreamStart: EmitStreamStart(evt); break; case EmitterState.FirstDocumentStart: EmitDocumentStart(evt, isFirst: true); break; case EmitterState.DocumentStart: EmitDocumentStart(evt, isFirst: false); break; case EmitterState.DocumentContent: EmitDocumentContent(evt); break; case EmitterState.DocumentEnd: EmitDocumentEnd(evt); break; case EmitterState.FlowSequenceFirstItem: EmitFlowSequenceItem(evt, isFirst: true); break; case EmitterState.FlowSequenceItem: EmitFlowSequenceItem(evt, isFirst: false); break; case EmitterState.FlowMappingFirstKey: EmitFlowMappingKey(evt, isFirst: true); break; case EmitterState.FlowMappingKey: EmitFlowMappingKey(evt, isFirst: false); break; case EmitterState.FlowMappingSimpleValue: EmitFlowMappingValue(evt, isSimple: true); break; case EmitterState.FlowMappingValue: EmitFlowMappingValue(evt, isSimple: false); break; case EmitterState.BlockSequenceFirstItem: EmitBlockSequenceItem(evt, isFirst: true); break; case EmitterState.BlockSequenceItem: EmitBlockSequenceItem(evt, isFirst: false); break; case EmitterState.BlockMappingFirstKey: EmitBlockMappingKey(evt, isFirst: true); break; case EmitterState.BlockMappingKey: EmitBlockMappingKey(evt, isFirst: false); break; case EmitterState.BlockMappingSimpleValue: EmitBlockMappingValue(evt, isSimple: true); break; case EmitterState.BlockMappingValue: EmitBlockMappingValue(evt, isSimple: false); break; case EmitterState.StreamEnd: throw new YamlException("Expected nothing after STREAM-END"); default: throw new InvalidOperationException(); } } private void EmitComment(YamlDotNet.Core.Events.Comment comment) { if (flowLevel > 0 || state == EmitterState.FlowMappingFirstKey || state == EmitterState.FlowSequenceFirstItem) { return; } string[] array = comment.Value.Split(NewLineSeparators, StringSplitOptions.None); if (comment.IsInline) { Write(" # "); Write(string.Join(" ", array)); } else { bool flag = state == EmitterState.BlockMappingFirstKey; if (flag) { IncreaseIndent(isFlow: false, isIndentless: false); } string[] array2 = array; foreach (string value in array2) { WriteIndent(); Write("# "); Write(value); WriteBreak(); } if (flag) { indent = indents.Pop(); } } isIndentation = true; } private void EmitStreamStart(ParsingEvent evt) { if (!(evt is YamlDotNet.Core.Events.StreamStart)) { throw new ArgumentException("Expected STREAM-START.", "evt"); } indent = -1; column = 0; isWhitespace = true; isIndentation = true; state = EmitterState.FirstDocumentStart; } private void EmitDocumentStart(ParsingEvent evt, bool isFirst) { if (evt is YamlDotNet.Core.Events.DocumentStart documentStart) { bool flag = documentStart.IsImplicit && isFirst && !isCanonical; TagDirectiveCollection tagDirectiveCollection = NonDefaultTagsAmong(documentStart.Tags); if (!isFirst && !isDocumentEndWritten && (documentStart.Version != null || tagDirectiveCollection.Count > 0)) { isDocumentEndWritten = false; WriteIndicator("...", needWhitespace: true, whitespace: false, indentation: false); WriteIndent(); } if (documentStart.Version != null) { AnalyzeVersionDirective(documentStart.Version); Version version = documentStart.Version.Version; flag = false; WriteIndicator("%YAML", needWhitespace: true, whitespace: false, indentation: false); WriteIndicator(string.Format(CultureInfo.InvariantCulture, "{0}.{1}", version.Major, version.Minor), needWhitespace: true, whitespace: false, indentation: false); WriteIndent(); } foreach (TagDirective item in tagDirectiveCollection) { AppendTagDirectiveTo(item, allowDuplicates: false, tagDirectives); } TagDirective[] defaultTagDirectives = Constants.DefaultTagDirectives; foreach (TagDirective value in defaultTagDirectives) { AppendTagDirectiveTo(value, allowDuplicates: true, tagDirectives); } if (tagDirectiveCollection.Count > 0) { flag = false; TagDirective[] defaultTagDirectives2 = Constants.DefaultTagDirectives; foreach (TagDirective value2 in defaultTagDirectives2) { AppendTagDirectiveTo(value2, allowDuplicates: true, tagDirectiveCollection); } foreach (TagDirective item2 in tagDirectiveCollection) { WriteIndicator("%TAG", needWhitespace: true, whitespace: false, indentation: false); WriteTagHandle(item2.Handle); WriteTagContent(item2.Prefix, needsWhitespace: true); WriteIndent(); } } if (CheckEmptyDocument()) { flag = false; } if (!flag) { WriteIndent(); WriteIndicator("---", needWhitespace: true, whitespace: false, indentation: false); if (isCanonical) { WriteIndent(); } } state = EmitterState.DocumentContent; } else { if (!(evt is YamlDotNet.Core.Events.StreamEnd)) { throw new YamlException("Expected DOCUMENT-START or STREAM-END"); } state = EmitterState.StreamEnd; } } private static TagDirectiveCollection NonDefaultTagsAmong(IEnumerable? tagCollection) { TagDirectiveCollection tagDirectiveCollection = new TagDirectiveCollection(); if (tagCollection == null) { return tagDirectiveCollection; } foreach (TagDirective item2 in tagCollection) { AppendTagDirectiveTo(item2, allowDuplicates: false, tagDirectiveCollection); } TagDirective[] defaultTagDirectives = Constants.DefaultTagDirectives; foreach (TagDirective item in defaultTagDirectives) { tagDirectiveCollection.Remove(item); } return tagDirectiveCollection; } private static void AnalyzeVersionDirective(VersionDirective versionDirective) { if (versionDirective.Version.Major != 1 || versionDirective.Version.Minor > 3) { throw new YamlException("Incompatible %YAML directive"); } } private static void AppendTagDirectiveTo(TagDirective value, bool allowDuplicates, TagDirectiveCollection tagDirectives) { if (tagDirectives.Contains(value)) { if (!allowDuplicates) { throw new YamlException("Duplicate %TAG directive."); } } else { tagDirectives.Add(value); } } private void EmitDocumentContent(ParsingEvent evt) { states.Push(EmitterState.DocumentEnd); EmitNode(evt, isMapping: false, isSimpleKey: false); } private void EmitNode(ParsingEvent evt, bool isMapping, bool isSimpleKey) { isMappingContext = isMapping; isSimpleKeyContext = isSimpleKey; switch (evt.Type) { case EventType.Alias: EmitAlias(); break; case EventType.Scalar: EmitScalar(evt); break; case EventType.SequenceStart: EmitSequenceStart(evt); break; case EventType.MappingStart: EmitMappingStart(evt); break; default: throw new YamlException($"Expected SCALAR, SEQUENCE-START, MAPPING-START, or ALIAS, got {evt.Type}"); } } private void EmitAlias() { ProcessAnchor(); state = states.Pop(); } private void EmitScalar(ParsingEvent evt) { SelectScalarStyle(evt); ProcessAnchor(); ProcessTag(); IncreaseIndent(isFlow: true, isIndentless: false); ProcessScalar(); indent = indents.Pop(); state = states.Pop(); } private void SelectScalarStyle(ParsingEvent evt) { YamlDotNet.Core.Events.Scalar scalar = (YamlDotNet.Core.Events.Scalar)evt; ScalarStyle scalarStyle = scalar.Style; bool flag = tagData.Handle == null && tagData.Suffix == null; if (flag && !scalar.IsPlainImplicit && !scalar.IsQuotedImplicit) { throw new YamlException("Neither tag nor isImplicit flags are specified."); } if (scalarStyle == ScalarStyle.Any) { scalarStyle = ((!scalarData.IsMultiline) ? ScalarStyle.Plain : ScalarStyle.Folded); } if (isCanonical) { scalarStyle = ScalarStyle.DoubleQuoted; } if (isSimpleKeyContext && scalarData.IsMultiline) { scalarStyle = ScalarStyle.DoubleQuoted; } if (scalarStyle == ScalarStyle.Plain) { if ((flowLevel != 0 && !scalarData.IsFlowPlainAllowed) || (flowLevel == 0 && !scalarData.IsBlockPlainAllowed)) { scalarStyle = ((scalarData.IsSingleQuotedAllowed && !scalarData.HasSingleQuotes) ? ScalarStyle.SingleQuoted : ScalarStyle.DoubleQuoted); } if (string.IsNullOrEmpty(scalarData.Value) && (flowLevel != 0 || isSimpleKeyContext)) { scalarStyle = ScalarStyle.SingleQuoted; } if (flag && !scalar.IsPlainImplicit) { scalarStyle = ScalarStyle.SingleQuoted; } } if (scalarStyle == ScalarStyle.SingleQuoted && !scalarData.IsSingleQuotedAllowed) { scalarStyle = ScalarStyle.DoubleQuoted; } if ((scalarStyle == ScalarStyle.Literal || scalarStyle == ScalarStyle.Folded) && (!scalarData.IsBlockAllowed || flowLevel != 0 || isSimpleKeyContext)) { scalarStyle = ScalarStyle.DoubleQuoted; } if (scalarStyle == ScalarStyle.ForcePlain) { scalarStyle = ScalarStyle.Plain; } scalarData.Style = scalarStyle; } private void ProcessScalar() { switch (scalarData.Style) { case ScalarStyle.Plain: WritePlainScalar(scalarData.Value, !isSimpleKeyContext); break; case ScalarStyle.SingleQuoted: WriteSingleQuotedScalar(scalarData.Value, !isSimpleKeyContext); break; case ScalarStyle.DoubleQuoted: WriteDoubleQuotedScalar(scalarData.Value, !isSimpleKeyContext); break; case ScalarStyle.Literal: WriteLiteralScalar(scalarData.Value); break; case ScalarStyle.Folded: WriteFoldedScalar(scalarData.Value); break; default: throw new InvalidOperationException(); } } private void WritePlainScalar(string value, bool allowBreaks) { if (!isWhitespace) { Write(' '); } bool flag = false; bool flag2 = false; for (int i = 0; i < value.Length; i++) { char c = value[i]; if (IsSpace(c)) { if (allowBreaks && !flag && column > bestWidth && i + 1 < value.Length && value[i + 1] != ' ') { WriteIndent(); } else { Write(c); } flag = true; continue; } if (IsBreak(c, out var breakChar)) { if (!flag2 && c == '\n') { WriteBreak(); } WriteBreak(breakChar); isIndentation = true; flag2 = true; continue; } if (flag2) { WriteIndent(); } Write(c); isIndentation = false; flag = false; flag2 = false; } isWhitespace = false; isIndentation = false; } private void WriteSingleQuotedScalar(string value, bool allowBreaks) { WriteIndicator("'", needWhitespace: true, whitespace: false, indentation: false); bool flag = false; bool flag2 = false; for (int i = 0; i < value.Length; i++) { char c = value[i]; if (c == ' ') { if (allowBreaks && !flag && column > bestWidth && i != 0 && i + 1 < value.Length && value[i + 1] != ' ') { WriteIndent(); } else { Write(c); } flag = true; continue; } if (IsBreak(c, out var breakChar)) { if (!flag2 && c == '\n') { WriteBreak(); } WriteBreak(breakChar); isIndentation = true; flag2 = true; continue; } if (flag2) { WriteIndent(); } if (c == '\'') { Write(c); } Write(c); isIndentation = false; flag = false; flag2 = false; } WriteIndicator("'", needWhitespace: false, whitespace: false, indentation: false); isWhitespace = false; isIndentation = false; } private void WriteDoubleQuotedScalar(string value, bool allowBreaks) { WriteIndicator("\"", needWhitespace: true, whitespace: false, indentation: false); bool flag = false; for (int i = 0; i < value.Length; i++) { char c = value[i]; if (IsPrintable(c) && !IsBreak(c, out var _)) { switch (c) { case '"': case '\\': break; case ' ': if (allowBreaks && !flag && column > bestWidth && i > 0 && i + 1 < value.Length) { WriteIndent(); if (value[i + 1] == ' ') { Write('\\'); } } else { Write(c); } flag = true; continue; default: Write(c); flag = false; continue; } } Write('\\'); switch (c) { case '\0': Write('0'); break; case '\a': Write('a'); break; case '\b': Write('b'); break; case '\t': Write('t'); break; case '\n': Write('n'); break; case '\v': Write('v'); break; case '\f': Write('f'); break; case '\r': Write('r'); break; case '\u001b': Write('e'); break; case '"': Write('"'); break; case '\\': Write('\\'); break; case '\u0085': Write('N'); break; case '\u00a0': Write('_'); break; case '\u2028': Write('L'); break; case '\u2029': Write('P'); break; default: { ushort num = c; if (num <= 255) { Write('x'); Write(num.ToString("X02", CultureInfo.InvariantCulture)); } else if (IsHighSurrogate(c)) { if (i + 1 >= value.Length || !IsLowSurrogate(value[i + 1])) { throw new SyntaxErrorException("While writing a quoted scalar, found an orphaned high surrogate."); } if (useUtf16SurrogatePair) { Write('u'); Write(num.ToString("X04", CultureInfo.InvariantCulture)); Write('\\'); Write('u'); Write(((ushort)value[i + 1]).ToString("X04", CultureInfo.InvariantCulture)); } else { Write('U'); Write(char.ConvertToUtf32(c, value[i + 1]).ToString("X08", CultureInfo.InvariantCulture)); } i++; } else { Write('u'); Write(num.ToString("X04", CultureInfo.InvariantCulture)); } break; } } flag = false; } WriteIndicator("\"", needWhitespace: false, whitespace: false, indentation: false); isWhitespace = false; isIndentation = false; } private void WriteLiteralScalar(string value) { bool flag = true; WriteIndicator("|", needWhitespace: true, whitespace: false, indentation: false); WriteBlockScalarHints(value); WriteBreak(); isIndentation = true; isWhitespace = true; for (int i = 0; i < value.Length; i++) { char c = value[i]; if (c == '\r' && i + 1 < value.Length && value[i + 1] == '\n') { continue; } if (IsBreak(c, out var breakChar)) { WriteBreak(breakChar); isIndentation = true; flag = true; continue; } if (flag) { WriteIndent(); } Write(c); isIndentation = false; flag = false; } } private void WriteFoldedScalar(string value) { bool flag = true; bool flag2 = true; WriteIndicator(">", needWhitespace: true, whitespace: false, indentation: false); WriteBlockScalarHints(value); WriteBreak(); isIndentation = true; isWhitespace = true; for (int i = 0; i < value.Length; i++) { char c = value[i]; if (IsBreak(c, out var breakChar)) { if (c == '\r' && i + 1 < value.Length && value[i + 1] == '\n') { continue; } if (!flag && !flag2 && breakChar == '\n') { int j; char breakChar2; for (j = 0; i + j < value.Length && IsBreak(value[i + j], out breakChar2); j++) { } if (i + j < value.Length && !IsBlank(value[i + j]) && !IsBreak(value[i + j], out breakChar2)) { WriteBreak(); } } WriteBreak(breakChar); isIndentation = true; flag = true; } else { if (flag) { WriteIndent(); flag2 = IsBlank(c); } if (!flag && c == ' ' && i + 1 < value.Length && value[i + 1] != ' ' && column > bestWidth) { WriteIndent(); } else { Write(c); } isIndentation = false; flag = false; } } } private static bool IsSpace(char character) { return character == ' '; } private static bool IsBreak(char character, out char breakChar) { switch (character) { case '\n': case '\r': case '\u0085': breakChar = '\n'; return true; case '\u2028': case '\u2029': breakChar = character; return true; default: breakChar = '\0'; return false; } } private static bool IsBlank(char character) { if (character != ' ') { return character == '\t'; } return true; } private static bool IsPrintable(char character) { switch (character) { default: if (character != '\u0085' && (character < '\u00a0' || character > '\ud7ff')) { if (character >= '\ue000') { return character <= '\ufffd'; } return false; } break; case '\t': case '\n': case '\r': case ' ': case '!': case '"': case '#': case '$': case '%': case '&': case '\'': case '(': case ')': case '*': case '+': case ',': case '-': case '.': case '/': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case ':': case ';': case '<': case '=': case '>': case '?': case '@': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '[': case '\\': case ']': case '^': case '_': case '`': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case '{': case '|': case '}': case '~': break; } return true; } private static bool IsHighSurrogate(char c) { if ('\ud800' <= c) { return c <= '\udbff'; } return false; } private static bool IsLowSurrogate(char c) { if ('\udc00' <= c) { return c <= '\udfff'; } return false; } private void EmitSequenceStart(ParsingEvent evt) { ProcessAnchor(); ProcessTag(); SequenceStart sequenceStart = (SequenceStart)evt; if (flowLevel != 0 || isCanonical || sequenceStart.Style == SequenceStyle.Flow || CheckEmptySequence()) { state = EmitterState.FlowSequenceFirstItem; } else { state = EmitterState.BlockSequenceFirstItem; } } private void EmitMappingStart(ParsingEvent evt) { ProcessAnchor(); ProcessTag(); MappingStart mappingStart = (MappingStart)evt; if (flowLevel != 0 || isCanonical || mappingStart.Style == MappingStyle.Flow || CheckEmptyMapping()) { state = EmitterState.FlowMappingFirstKey; } else { state = EmitterState.BlockMappingFirstKey; } } private void ProcessAnchor() { if (!anchorData.Anchor.IsEmpty && !skipAnchorName) { WriteIndicator(anchorData.IsAlias ? "*" : "&", needWhitespace: true, whitespace: false, indentation: false); WriteAnchor(anchorData.Anchor); } } private void ProcessTag() { if (tagData.Handle == null && tagData.Suffix == null) { return; } if (tagData.Handle != null) { WriteTagHandle(tagData.Handle); if (tagData.Suffix != null) { WriteTagContent(tagData.Suffix, needsWhitespace: false); } } else { WriteIndicator("!<", needWhitespace: true, whitespace: false, indentation: false); WriteTagContent(tagData.Suffix, needsWhitespace: false); WriteIndicator(">", needWhitespace: false, whitespace: false, indentation: false); } } private void EmitDocumentEnd(ParsingEvent evt) { if (evt is YamlDotNet.Core.Events.DocumentEnd documentEnd) { WriteIndent(); if (!documentEnd.IsImplicit) { WriteIndicator("...", needWhitespace: true, whitespace: false, indentation: false); WriteIndent(); isDocumentEndWritten = true; } state = EmitterState.DocumentStart; tagDirectives.Clear(); return; } throw new YamlException("Expected DOCUMENT-END."); } private void EmitFlowSequenceItem(ParsingEvent evt, bool isFirst) { if (isFirst) { WriteIndicator("[", needWhitespace: true, whitespace: true, indentation: false); IncreaseIndent(isFlow: true, isIndentless: false); flowLevel++; } if (evt is SequenceEnd) { flowLevel--; indent = indents.Pop(); if (isCanonical && !isFirst) { WriteIndicator(",", needWhitespace: false, whitespace: false, indentation: false); WriteIndent(); } WriteIndicator("]", needWhitespace: false, whitespace: false, indentation: false); state = states.Pop(); } else { if (!isFirst) { WriteIndicator(",", needWhitespace: false, whitespace: false, indentation: false); } if (isCanonical || column > bestWidth) { WriteIndent(); } states.Push(EmitterState.FlowSequenceItem); EmitNode(evt, isMapping: false, isSimpleKey: false); } } private void EmitFlowMappingKey(ParsingEvent evt, bool isFirst) { if (isFirst) { WriteIndicator("{", needWhitespace: true, whitespace: true, indentation: false); IncreaseIndent(isFlow: true, isIndentless: false); flowLevel++; } if (evt is MappingEnd) { flowLevel--; indent = indents.Pop(); if (isCanonical && !isFirst) { WriteIndicator(",", needWhitespace: false, whitespace: false, indentation: false); WriteIndent(); } WriteIndicator("}", needWhitespace: false, whitespace: false, indentation: false); state = states.Pop(); return; } if (!isFirst) { WriteIndicator(",", needWhitespace: false, whitespace: false, indentation: false); } if (isCanonical || column > bestWidth) { WriteIndent(); } if (!isCanonical && CheckSimpleKey()) { states.Push(EmitterState.FlowMappingSimpleValue); EmitNode(evt, isMapping: true, isSimpleKey: true); } else { WriteIndicator("?", needWhitespace: true, whitespace: false, indentation: false); states.Push(EmitterState.FlowMappingValue); EmitNode(evt, isMapping: true, isSimpleKey: false); } } private void EmitFlowMappingValue(ParsingEvent evt, bool isSimple) { if (isSimple) { WriteIndicator(":", needWhitespace: false, whitespace: false, indentation: false); } else { if (isCanonical || column > bestWidth) { WriteIndent(); } WriteIndicator(":", needWhitespace: true, whitespace: false, indentation: false); } states.Push(EmitterState.FlowMappingKey); EmitNode(evt, isMapping: true, isSimpleKey: false); } private void EmitBlockSequenceItem(ParsingEvent evt, bool isFirst) { if (isFirst) { IncreaseIndent(isFlow: false, isMappingContext && !isIndentation); } if (evt is SequenceEnd) { indent = indents.Pop(); state = states.Pop(); return; } WriteIndent(); WriteIndicator("-", needWhitespace: true, whitespace: false, indentation: true); states.Push(EmitterState.BlockSequenceItem); EmitNode(evt, isMapping: false, isSimpleKey: false); } private void EmitBlockMappingKey(ParsingEvent evt, bool isFirst) { if (isFirst) { IncreaseIndent(isFlow: false, isIndentless: false); } if (evt is MappingEnd) { indent = indents.Pop(); state = states.Pop(); return; } WriteIndent(); if (CheckSimpleKey()) { states.Push(EmitterState.BlockMappingSimpleValue); EmitNode(evt, isMapping: true, isSimpleKey: true); WriteIndicator(":", needWhitespace: false, whitespace: false, indentation: false); } else { WriteIndicator("?", needWhitespace: true, whitespace: false, indentation: true); states.Push(EmitterState.BlockMappingValue); EmitNode(evt, isMapping: true, isSimpleKey: false); } } private void EmitBlockMappingValue(ParsingEvent evt, bool isSimple) { if (!isSimple) { WriteIndent(); WriteIndicator(":", needWhitespace: true, whitespace: false, indentation: true); } states.Push(EmitterState.BlockMappingKey); EmitNode(evt, isMapping: true, isSimpleKey: false); } private void IncreaseIndent(bool isFlow, bool isIndentless) { indents.Push(indent); if (indent < 0) { indent = (isFlow ? bestIndent : 0); } else if (!isIndentless || !forceIndentLess) { indent += bestIndent; } } private bool CheckEmptyDocument() { int num = 0; foreach (ParsingEvent @event in events) { num++; if (num == 2) { if (@event is YamlDotNet.Core.Events.Scalar scalar) { return string.IsNullOrEmpty(scalar.Value); } break; } } return false; } private bool CheckSimpleKey() { if (events.Count < 1) { return false; } int num; switch (events.Peek().Type) { case EventType.Alias: num = AnchorNameLength(anchorData.Anchor); break; case EventType.Scalar: if (scalarData.IsMultiline) { return false; } num = AnchorNameLength(anchorData.Anchor) + SafeStringLength(tagData.Handle) + SafeStringLength(tagData.Suffix) + SafeStringLength(scalarData.Value); break; case EventType.SequenceStart: if (!CheckEmptySequence()) { return false; } num = AnchorNameLength(anchorData.Anchor) + SafeStringLength(tagData.Handle) + SafeStringLength(tagData.Suffix); break; case EventType.MappingStart: if (!CheckEmptySequence()) { return false; } num = AnchorNameLength(anchorData.Anchor) + SafeStringLength(tagData.Handle) + SafeStringLength(tagData.Suffix); break; default: return false; } return num <= maxSimpleKeyLength; } private static int AnchorNameLength(AnchorName value) { if (!value.IsEmpty) { return value.Value.Length; } return 0; } private static int SafeStringLength(string? value) { return value?.Length ?? 0; } private bool CheckEmptySequence() { return CheckEmptyStructure(); } private bool CheckEmptyMapping() { return CheckEmptyStructure(); } private bool CheckEmptyStructure() where TStart : NodeEvent where TEnd : ParsingEvent { if (events.Count < 2) { return false; } using Queue.Enumerator enumerator = events.GetEnumerator(); return enumerator.MoveNext() && enumerator.Current is TStart && enumerator.MoveNext() && enumerator.Current is TEnd; } private void WriteBlockScalarHints(string value) { StringLookAheadBufferPool.BufferWrapper bufferWrapper = StringLookAheadBufferPool.Rent(value); try { CharacterAnalyzer characterAnalyzer = new CharacterAnalyzer(bufferWrapper.Buffer); if (characterAnalyzer.IsSpace() || characterAnalyzer.IsBreak()) { int num = bestIndent; string indicator = num.ToString(CultureInfo.InvariantCulture); WriteIndicator(indicator, needWhitespace: false, whitespace: false, indentation: false); } string text = null; if (value.Length == 0 || !characterAnalyzer.IsBreak(value.Length - 1)) { text = "-"; } else if (value.Length >= 2 && characterAnalyzer.IsBreak(value.Length - 2)) { text = "+"; } if (text != null) { WriteIndicator(text, needWhitespace: false, whitespace: false, indentation: false); } } finally { ((IDisposable)bufferWrapper).Dispose(); } } private void WriteIndicator(string indicator, bool needWhitespace, bool whitespace, bool indentation) { if (needWhitespace && !isWhitespace) { Write(' '); } Write(indicator); isWhitespace = whitespace; isIndentation &= indentation; } private void WriteIndent() { int num = Math.Max(indent, 0); if (!isIndentation || column > num || (column == num && !isWhitespace)) { WriteBreak(); } while (column < num) { Write(' '); } isWhitespace = true; isIndentation = true; } private void WriteAnchor(AnchorName value) { Write(value.Value); isWhitespace = false; isIndentation = false; } private void WriteTagHandle(string value) { if (!isWhitespace) { Write(' '); } Write(value); isWhitespace = false; isIndentation = false; } private void WriteTagContent(string value, bool needsWhitespace) { if (needsWhitespace && !isWhitespace) { Write(' '); } Write(UrlEncode(value)); isWhitespace = false; isIndentation = false; } private static string UrlEncode(string text) { return UriReplacer.Replace(text, delegate(Match match) { StringBuilderPool.BuilderWrapper builderWrapper = StringBuilderPool.Rent(); try { StringBuilder builder = builderWrapper.Builder; byte[] bytes = Encoding.UTF8.GetBytes(match.Value); foreach (byte b in bytes) { builder.AppendFormat(CultureInfo.InvariantCulture, "%{0:X02}", b); } return builder.ToString(); } finally { ((IDisposable)builderWrapper).Dispose(); } }); } private void Write(char value) { output.Write(value); column++; } private void Write(string value) { output.Write(value); column += value.Length; } private void WriteBreak(char breakCharacter = '\n') { if (breakCharacter == '\n') { output.WriteLine(); } else { output.Write(breakCharacter); } column = 0; } } internal sealed class EmitterSettings { public static readonly EmitterSettings Default = new EmitterSettings(); public int BestIndent { get; } = 2; public int BestWidth { get; } = int.MaxValue; public string NewLine { get; } = Environment.NewLine; public bool IsCanonical { get; } public bool SkipAnchorName { get; private set; } public int MaxSimpleKeyLength { get; } = 1024; public bool IndentSequences { get; } public bool UseUtf16SurrogatePairs { get; } public EmitterSettings() { } public EmitterSettings(int bestIndent, int bestWidth, bool isCanonical, int maxSimpleKeyLength, bool skipAnchorName = false, bool indentSequences = false, string? newLine = null, bool useUtf16SurrogatePairs = false) { if (bestIndent < 2 || bestIndent > 9) { throw new ArgumentOutOfRangeException("bestIndent", "BestIndent must be between 2 and 9, inclusive"); } if (bestWidth <= bestIndent * 2) { throw new ArgumentOutOfRangeException("bestWidth", "BestWidth must be greater than BestIndent x 2."); } if (maxSimpleKeyLength < 0) { throw new ArgumentOutOfRangeException("maxSimpleKeyLength", "MaxSimpleKeyLength must be >= 0"); } BestIndent = bestIndent; BestWidth = bestWidth; IsCanonical = isCanonical; MaxSimpleKeyLength = maxSimpleKeyLength; SkipAnchorName = skipAnchorName; IndentSequences = indentSequences; NewLine = newLine ?? Environment.NewLine; UseUtf16SurrogatePairs = useUtf16SurrogatePairs; } public EmitterSettings WithBestIndent(int bestIndent) { return new EmitterSettings(bestIndent, BestWidth, IsCanonical, MaxSimpleKeyLength, SkipAnchorName, IndentSequences, NewLine, UseUtf16SurrogatePairs); } public EmitterSettings WithBestWidth(int bestWidth) { return new EmitterSettings(BestIndent, bestWidth, IsCanonical, MaxSimpleKeyLength, SkipAnchorName, IndentSequences, NewLine, UseUtf16SurrogatePairs); } public EmitterSettings WithMaxSimpleKeyLength(int maxSimpleKeyLength) { return new EmitterSettings(BestIndent, BestWidth, IsCanonical, maxSimpleKeyLength, SkipAnchorName, IndentSequences, NewLine, UseUtf16SurrogatePairs); } public EmitterSettings WithNewLine(string newLine) { return new EmitterSettings(BestIndent, BestWidth, IsCanonical, MaxSimpleKeyLength, SkipAnchorName, IndentSequences, newLine, UseUtf16SurrogatePairs); } public EmitterSettings Canonical() { return new EmitterSettings(BestIndent, BestWidth, isCanonical: true, MaxSimpleKeyLength, SkipAnchorName); } public EmitterSettings WithoutAnchorName() { return new EmitterSettings(BestIndent, BestWidth, IsCanonical, MaxSimpleKeyLength, skipAnchorName: true, IndentSequences, NewLine, UseUtf16SurrogatePairs); } public EmitterSettings WithIndentedSequences() { return new EmitterSettings(BestIndent, BestWidth, IsCanonical, MaxSimpleKeyLength, SkipAnchorName, indentSequences: true, NewLine, UseUtf16SurrogatePairs); } public EmitterSettings WithUtf16SurrogatePairs() { return new EmitterSettings(BestIndent, BestWidth, IsCanonical, MaxSimpleKeyLength, SkipAnchorName, IndentSequences, NewLine, useUtf16SurrogatePairs: true); } } internal enum EmitterState { StreamStart, StreamEnd, FirstDocumentStart, DocumentStart, DocumentContent, DocumentEnd, FlowSequenceFirstItem, FlowSequenceItem, FlowMappingFirstKey, FlowMappingKey, FlowMappingSimpleValue, FlowMappingValue, BlockSequenceFirstItem, BlockSequenceItem, BlockMappingFirstKey, BlockMappingKey, BlockMappingSimpleValue, BlockMappingValue } internal sealed class ForwardAnchorNotSupportedException : YamlException { public ForwardAnchorNotSupportedException(string message) : base(message) { } public ForwardAnchorNotSupportedException(in Mark start, in Mark end, string message) : base(in start, in end, message) { } public ForwardAnchorNotSupportedException(string message, Exception inner) : base(message, inner) { } } internal static class HashCode { public static int CombineHashCodes(int h1, int h2) { return ((h1 << 5) + h1) ^ h2; } public static int CombineHashCodes(int h1, object? o2) { return CombineHashCodes(h1, GetHashCode(o2)); } private static int GetHashCode(object? obj) { return obj?.GetHashCode() ?? 0; } } internal interface IEmitter { void Emit(ParsingEvent @event); } internal interface ILookAheadBuffer { bool EndOfInput { get; } char Peek(int offset); void Skip(int length); } internal sealed class InsertionQueue : IEnumerable, IEnumerable { private const int DefaultInitialCapacity = 128; private T[] items; private int readPtr; private int writePtr; private int mask; private int count; public int Count => count; public int Capacity => items.Length; public InsertionQueue(int initialCapacity = 128) { if (initialCapacity <= 0) { throw new ArgumentOutOfRangeException("initialCapacity", "The initial capacity must be a positive number."); } if (!initialCapacity.IsPowerOfTwo()) { throw new ArgumentException("The initial capacity must be a power of 2.", "initialCapacity"); } items = new T[initialCapacity]; readPtr = initialCapacity / 2; writePtr = initialCapacity / 2; mask = initialCapacity - 1; } public void Enqueue(T item) { ResizeIfNeeded(); items[writePtr] = item; writePtr = (writePtr - 1) & mask; count++; } public T Dequeue() { if (count == 0) { throw new InvalidOperationException("The queue is empty"); } T result = items[readPtr]; readPtr = (readPtr - 1) & mask; count--; return result; } public void Insert(int index, T item) { if (index > count) { throw new InvalidOperationException("Cannot insert outside of the bounds of the queue"); } ResizeIfNeeded(); CalculateInsertionParameters(mask, count, index, ref readPtr, ref writePtr, out var insertPtr, out var copyIndex, out var copyOffset, out var copyLength); if (copyLength != 0) { Array.Copy(items, copyIndex, items, copyIndex + copyOffset, copyLength); } items[insertPtr] = item; count++; } private void ResizeIfNeeded() { int num = items.Length; if (count == num) { T[] destinationArray = new T[num * 2]; int num2 = readPtr + 1; if (num2 > 0) { Array.Copy(items, 0, destinationArray, 0, num2); } writePtr += num; int num3 = num - num2; if (num3 > 0) { Array.Copy(items, readPtr + 1, destinationArray, writePtr + 1, num3); } items = destinationArray; mask = mask * 2 + 1; } } internal static void CalculateInsertionParameters(int mask, int count, int index, ref int readPtr, ref int writePtr, out int insertPtr, out int copyIndex, out int copyOffset, out int copyLength) { int num = (readPtr + 1) & mask; if (index == 0) { insertPtr = (readPtr = num); copyIndex = 0; copyOffset = 0; copyLength = 0; return; } insertPtr = (readPtr - index) & mask; if (index == count) { writePtr = (writePtr - 1) & mask; copyIndex = 0; copyOffset = 0; copyLength = 0; return; } int num2 = ((num >= insertPtr) ? (readPtr - insertPtr) : int.MaxValue); int num3 = ((writePtr <= insertPtr) ? (insertPtr - writePtr) : int.MaxValue); if (num2 <= num3) { insertPtr++; readPtr++; copyIndex = insertPtr; copyOffset = 1; copyLength = num2; } else { copyIndex = writePtr + 1; copyOffset = -1; copyLength = num3; writePtr = (writePtr - 1) & mask; } } public IEnumerator GetEnumerator() { int ptr = readPtr; for (int i = 0; i < Count; i++) { yield return items[ptr]; ptr = (ptr - 1) & mask; } } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } internal interface IParser { ParsingEvent? Current { get; } bool MoveNext(); } internal interface IScanner { Mark CurrentPosition { get; } Token? Current { get; } bool MoveNext(); bool MoveNextWithoutConsuming(); void ConsumeCurrent(); } [DebuggerStepThrough] internal sealed class LookAheadBuffer : ILookAheadBuffer { private readonly TextReader input; private readonly char[] buffer; private readonly int blockSize; private readonly int mask; private int firstIndex; private int writeOffset; private int count; private bool endOfInput; public bool EndOfInput { get { if (endOfInput) { return count == 0; } return false; } } public LookAheadBuffer(TextReader input, int capacity) { if (capacity < 1) { throw new ArgumentOutOfRangeException("capacity", "The capacity must be positive."); } if (!capacity.IsPowerOfTwo()) { throw new ArgumentException("The capacity must be a power of 2.", "capacity"); } this.input = input ?? throw new ArgumentNullException("input"); blockSize = capacity; buffer = new char[capacity * 2]; mask = capacity * 2 - 1; } private int GetIndexForOffset(int offset) { return (firstIndex + offset) & mask; } public char Peek(int offset) { if (offset >= count) { FillBuffer(); } if (offset < count) { return buffer[(firstIndex + offset) & mask]; } return '\0'; } public void Cache(int length) { if (length >= count) { FillBuffer(); } } private void FillBuffer() { if (endOfInput) { return; } int num = blockSize; do { int num2 = input.Read(buffer, writeOffset, num); if (num2 == 0) { endOfInput = true; return; } num -= num2; writeOffset += num2; count += num2; } while (num > 0); if (writeOffset == buffer.Length) { writeOffset = 0; } } public void Skip(int length) { if (length < 1 || length > blockSize) { throw new ArgumentOutOfRangeException("length", "The length must be between 1 and the number of characters in the buffer. Use the Peek() and / or Cache() methods to fill the buffer."); } firstIndex = GetIndexForOffset(length); count -= length; } } internal readonly struct Mark : IEquatable, IComparable, IComparable { public static readonly Mark Empty = new Mark(0L, 1L, 1L); public long Index { get; } public long Line { get; } public long Column { get; } public Mark(long index, long line, long column) { if (index < 0) { ThrowHelper.ThrowArgumentOutOfRangeException("index", "Index must be greater than or equal to zero."); } if (line < 1) { ThrowHelper.ThrowArgumentOutOfRangeException("line", "Line must be greater than or equal to 1."); } if (column < 1) { ThrowHelper.ThrowArgumentOutOfRangeException("column", "Column must be greater than or equal to 1."); } Index = index; Line = line; Column = column; } public override string ToString() { return $"Line: {Line}, Col: {Column}, Idx: {Index}"; } public override bool Equals(object? obj) { return Equals((Mark)(obj ?? ((object)Empty))); } public bool Equals(Mark other) { if (Index == other.Index && Line == other.Line) { return Column == other.Column; } return false; } public override int GetHashCode() { return HashCode.CombineHashCodes(Index.GetHashCode(), HashCode.CombineHashCodes(Line.GetHashCode(), Column.GetHashCode())); } public int CompareTo(object? obj) { return CompareTo((Mark)(obj ?? ((object)Empty))); } public int CompareTo(Mark other) { int num = Line.CompareTo(other.Line); if (num == 0) { num = Column.CompareTo(other.Column); } return num; } public static bool operator ==(Mark left, Mark right) { return left.Equals(right); } public static bool operator !=(Mark left, Mark right) { return !(left == right); } public static bool operator <(Mark left, Mark right) { return left.CompareTo(right) < 0; } public static bool operator <=(Mark left, Mark right) { return left.CompareTo(right) <= 0; } public static bool operator >(Mark left, Mark right) { return left.CompareTo(right) > 0; } public static bool operator >=(Mark left, Mark right) { return left.CompareTo(right) >= 0; } } internal sealed class MaximumRecursionLevelReachedException : YamlException { public MaximumRecursionLevelReachedException(string message) : base(message) { } public MaximumRecursionLevelReachedException(in Mark start, in Mark end, string message) : base(in start, in end, message) { } public MaximumRecursionLevelReachedException(string message, Exception inner) : base(message, inner) { } } internal sealed class MergingParser : IParser { private sealed class ParsingEventCollection : IEnumerable>, IEnumerable { private readonly LinkedList events; private readonly HashSet> deleted; private readonly Dictionary> references; public ParsingEventCollection() { events = new LinkedList(); deleted = new HashSet>(); references = new Dictionary>(); } public void AddAfter(LinkedListNode node, IEnumerable items) { foreach (ParsingEvent item in items) { node = events.AddAfter(node, item); } } public void Add(ParsingEvent item) { LinkedListNode node = events.AddLast(item); AddReference(item, node); } public void MarkDeleted(LinkedListNode node) { deleted.Add(node); } public bool IsDeleted(LinkedListNode node) { return deleted.Contains(node); } public void CleanMarked() { foreach (LinkedListNode item in deleted) { events.Remove(item); } } public IEnumerable> FromAnchor(AnchorName anchor) { LinkedListNode next = references[anchor].Next; return Enumerate(next); } public IEnumerator> GetEnumerator() { return Enumerate(events.First).GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } private static IEnumerable> Enumerate(LinkedListNode? node) { while (node != null) { yield return node; node = node.Next; } } private void AddReference(ParsingEvent item, LinkedListNode node) { if (item is MappingStart mappingStart) { AnchorName anchor = mappingStart.Anchor; if (!anchor.IsEmpty) { references[anchor] = node; } } } } private sealed class ParsingEventCloner : IParsingEventVisitor { private ParsingEvent? clonedEvent; public ParsingEvent Clone(ParsingEvent e) { e.Accept(this); if (clonedEvent == null) { throw new InvalidOperationException($"Could not clone event of type '{e.Type}'"); } return clonedEvent; } void IParsingEventVisitor.Visit(YamlDotNet.Core.Events.AnchorAlias e) { clonedEvent = new YamlDotNet.Core.Events.AnchorAlias(e.Value, e.Start, e.End); } void IParsingEventVisitor.Visit(YamlDotNet.Core.Events.StreamStart e) { throw new NotSupportedException(); } void IParsingEventVisitor.Visit(YamlDotNet.Core.Events.StreamEnd e) { throw new NotSupportedException(); } void IParsingEventVisitor.Visit(YamlDotNet.Core.Events.DocumentStart e) { throw new NotSupportedException(); } void IParsingEventVisitor.Visit(YamlDotNet.Core.Events.DocumentEnd e) { throw new NotSupportedException(); } void IParsingEventVisitor.Visit(YamlDotNet.Core.Events.Scalar e) { clonedEvent = new YamlDotNet.Core.Events.Scalar(AnchorName.Empty, e.Tag, e.Value, e.Style, e.IsPlainImplicit, e.IsQuotedImplicit, e.Start, e.End); } void IParsingEventVisitor.Visit(SequenceStart e) { clonedEvent = new SequenceStart(AnchorName.Empty, e.Tag, e.IsImplicit, e.Style, e.Start, e.End); } void IParsingEventVisitor.Visit(SequenceEnd e) { Mark start = e.Start; Mark end = e.End; clonedEvent = new SequenceEnd(in start, in end); } void IParsingEventVisitor.Visit(MappingStart e) { clonedEvent = new MappingStart(AnchorName.Empty, e.Tag, e.IsImplicit, e.Style, e.Start, e.End); } void IParsingEventVisitor.Visit(MappingEnd e) { Mark start = e.Start; Mark end = e.End; clonedEvent = new MappingEnd(in start, in end); } void IParsingEventVisitor.Visit(YamlDotNet.Core.Events.Comment e) { throw new NotSupportedException(); } } private readonly ParsingEventCollection events; private readonly IParser innerParser; private IEnumerator> iterator; private bool merged; public ParsingEvent? Current => iterator.Current?.Value; public MergingParser(IParser innerParser) { events = new ParsingEventCollection(); merged = false; iterator = events.GetEnumerator(); this.innerParser = innerParser; } public bool MoveNext() { if (!merged) { Merge(); events.CleanMarked(); iterator = events.GetEnumerator(); merged = true; } return iterator.MoveNext(); } private void Merge() { while (innerParser.MoveNext()) { events.Add(innerParser.Current); } foreach (LinkedListNode @event in events) { if (IsMergeToken(@event)) { events.MarkDeleted(@event); if (!HandleMerge(@event.Next)) { Mark start = @event.Value.Start; Mark end = @event.Value.End; throw new SemanticErrorException(in start, in end, "Unrecognized merge key pattern"); } } } } private bool HandleMerge(LinkedListNode? node) { if (node == null) { return false; } if (node.Value is YamlDotNet.Core.Events.AnchorAlias anchorAlias) { return HandleAnchorAlias(node, node, anchorAlias); } if (node.Value is SequenceStart) { return HandleSequence(node); } return false; } private bool HandleMergeSequence(LinkedListNode sequenceStart, LinkedListNode? node) { if (node == null) { return false; } if (node.Value is YamlDotNet.Core.Events.AnchorAlias anchorAlias) { return HandleAnchorAlias(sequenceStart, node, anchorAlias); } if (node.Value is SequenceStart) { return HandleSequence(node); } return false; } private static bool IsMergeToken(LinkedListNode node) { if (node.Value is YamlDotNet.Core.Events.Scalar scalar) { return scalar.Value == "<<"; } return false; } private bool HandleAnchorAlias(LinkedListNode node, LinkedListNode anchorNode, YamlDotNet.Core.Events.AnchorAlias anchorAlias) { IEnumerable mappingEvents = GetMappingEvents(anchorAlias.Value); events.AddAfter(node, mappingEvents); events.MarkDeleted(anchorNode); return true; } private bool HandleSequence(LinkedListNode node) { events.MarkDeleted(node); LinkedListNode linkedListNode = node; while (linkedListNode != null) { if (linkedListNode.Value is SequenceEnd) { events.MarkDeleted(linkedListNode); return true; } LinkedListNode next = linkedListNode.Next; HandleMergeSequence(node, next); linkedListNode = next; } return true; } private IEnumerable GetMappingEvents(AnchorName anchor) { ParsingEventCloner @object = new ParsingEventCloner(); int nesting = 0; return (from e in events.FromAnchor(anchor) where !events.IsDeleted(e) select e.Value).TakeWhile((ParsingEvent e) => (nesting += e.NestingIncrease) >= 0).Select(@object.Clone); } } internal class Parser : IParser { private class EventQueue { private readonly Queue highPriorityEvents = new Queue(); private readonly Queue normalPriorityEvents = new Queue(); public int Count => highPriorityEvents.Count + normalPriorityEvents.Count; public void Enqueue(ParsingEvent @event) { EventType type = @event.Type; if (type == EventType.StreamStart || type == EventType.DocumentStart) { highPriorityEvents.Enqueue(@event); } else { normalPriorityEvents.Enqueue(@event); } } public ParsingEvent Dequeue() { if (highPriorityEvents.Count <= 0) { return normalPriorityEvents.Dequeue(); } return highPriorityEvents.Dequeue(); } } private readonly Stack states = new Stack(); private readonly TagDirectiveCollection tagDirectives = new TagDirectiveCollection(); private ParserState state; private readonly IScanner scanner; private Token? currentToken; private VersionDirective? version; private readonly EventQueue pendingEvents = new EventQueue(); public ParsingEvent? Current { get; private set; } private Token? GetCurrentToken() { if (currentToken == null) { while (scanner.MoveNextWithoutConsuming()) { currentToken = scanner.Current; if (!(currentToken is YamlDotNet.Core.Tokens.Comment comment)) { break; } pendingEvents.Enqueue(new YamlDotNet.Core.Events.Comment(comment.Value, comment.IsInline, comment.Start, comment.End)); scanner.ConsumeCurrent(); } } return currentToken; } public Parser(TextReader input) : this(new Scanner(input)) { } public Parser(IScanner scanner) { this.scanner = scanner; } public bool MoveNext() { if (state == ParserState.StreamEnd) { Current = null; return false; } if (pendingEvents.Count == 0) { pendingEvents.Enqueue(StateMachine()); } Current = pendingEvents.Dequeue(); return true; } private ParsingEvent StateMachine() { return state switch { ParserState.StreamStart => ParseStreamStart(), ParserState.ImplicitDocumentStart => ParseDocumentStart(isImplicit: true), ParserState.DocumentStart => ParseDocumentStart(isImplicit: false), ParserState.DocumentContent => ParseDocumentContent(), ParserState.DocumentEnd => ParseDocumentEnd(), ParserState.BlockNode => ParseNode(isBlock: true, isIndentlessSequence: false), ParserState.BlockNodeOrIndentlessSequence => ParseNode(isBlock: true, isIndentlessSequence: true), ParserState.FlowNode => ParseNode(isBlock: false, isIndentlessSequence: false), ParserState.BlockSequenceFirstEntry => ParseBlockSequenceEntry(isFirst: true), ParserState.BlockSequenceEntry => ParseBlockSequenceEntry(isFirst: false), ParserState.IndentlessSequenceEntry => ParseIndentlessSequenceEntry(), ParserState.BlockMappingFirstKey => ParseBlockMappingKey(isFirst: true), ParserState.BlockMappingKey => ParseBlockMappingKey(isFirst: false), ParserState.BlockMappingValue => ParseBlockMappingValue(), ParserState.FlowSequenceFirstEntry => ParseFlowSequenceEntry(isFirst: true), ParserState.FlowSequenceEntry => ParseFlowSequenceEntry(isFirst: false), ParserState.FlowSequenceEntryMappingKey => ParseFlowSequenceEntryMappingKey(), ParserState.FlowSequenceEntryMappingValue => ParseFlowSequenceEntryMappingValue(), ParserState.FlowSequenceEntryMappingEnd => ParseFlowSequenceEntryMappingEnd(), ParserState.FlowMappingFirstKey => ParseFlowMappingKey(isFirst: true), ParserState.FlowMappingKey => ParseFlowMappingKey(isFirst: false), ParserState.FlowMappingValue => ParseFlowMappingValue(isEmpty: false), ParserState.FlowMappingEmptyValue => ParseFlowMappingValue(isEmpty: true), _ => throw new InvalidOperationException(), }; } private void Skip() { if (currentToken != null) { currentToken = null; scanner.ConsumeCurrent(); } } private YamlDotNet.Core.Events.StreamStart ParseStreamStart() { Token token = GetCurrentToken(); Mark start; Mark end; if (!(token is YamlDotNet.Core.Tokens.StreamStart streamStart)) { start = token?.Start ?? Mark.Empty; end = token?.End ?? Mark.Empty; throw new SemanticErrorException(in start, in end, "Did not find expected ."); } Skip(); state = ParserState.ImplicitDocumentStart; start = streamStart.Start; end = streamStart.End; return new YamlDotNet.Core.Events.StreamStart(in start, in end); } private ParsingEvent ParseDocumentStart(bool isImplicit) { if (currentToken is VersionDirective) { throw new SyntaxErrorException("While parsing a document start node, could not find document end marker before version directive."); } Token token = GetCurrentToken(); if (!isImplicit) { while (token is YamlDotNet.Core.Tokens.DocumentEnd) { Skip(); token = GetCurrentToken(); } } if (token == null) { throw new SyntaxErrorException("Reached the end of the stream while parsing a document start."); } if (token is YamlDotNet.Core.Tokens.Scalar && (state == ParserState.ImplicitDocumentStart || state == ParserState.DocumentStart)) { isImplicit = true; } if ((isImplicit && !(token is VersionDirective) && !(token is TagDirective) && !(token is YamlDotNet.Core.Tokens.DocumentStart) && !(token is YamlDotNet.Core.Tokens.StreamEnd) && !(token is YamlDotNet.Core.Tokens.DocumentEnd)) || token is BlockMappingStart) { TagDirectiveCollection tags = new TagDirectiveCollection(); ProcessDirectives(tags); states.Push(ParserState.DocumentEnd); state = ParserState.BlockNode; return new YamlDotNet.Core.Events.DocumentStart(null, tags, isImplicit: true, token.Start, token.End); } Mark start2; Mark end; if (!(token is YamlDotNet.Core.Tokens.StreamEnd) && !(token is YamlDotNet.Core.Tokens.DocumentEnd)) { Mark start = token.Start; TagDirectiveCollection tags2 = new TagDirectiveCollection(); VersionDirective versionDirective = ProcessDirectives(tags2); token = GetCurrentToken() ?? throw new SemanticErrorException("Reached the end of the stream while parsing a document start"); if (!(token is YamlDotNet.Core.Tokens.DocumentStart)) { start2 = token.Start; end = token.End; throw new SemanticErrorException(in start2, in end, "Did not find expected ."); } states.Push(ParserState.DocumentEnd); state = ParserState.DocumentContent; Mark end2 = token.End; Skip(); return new YamlDotNet.Core.Events.DocumentStart(versionDirective, tags2, isImplicit: false, start, end2); } if (token is YamlDotNet.Core.Tokens.DocumentEnd) { Skip(); } state = ParserState.StreamEnd; token = GetCurrentToken() ?? throw new SemanticErrorException("Reached the end of the stream while parsing a document start"); start2 = token.Start; end = token.End; YamlDotNet.Core.Events.StreamEnd result = new YamlDotNet.Core.Events.StreamEnd(in start2, in end); if (scanner.MoveNextWithoutConsuming()) { throw new InvalidOperationException("The scanner should contain no more tokens."); } return result; } private VersionDirective? ProcessDirectives(TagDirectiveCollection tags) { bool flag = false; VersionDirective result = null; while (true) { if (GetCurrentToken() is VersionDirective versionDirective) { if (version != null) { Mark start = versionDirective.Start; Mark end = versionDirective.End; throw new SemanticErrorException(in start, in end, "Found duplicate %YAML directive."); } if (versionDirective.Version.Major != 1 || versionDirective.Version.Minor > 3) { Mark start = versionDirective.Start; Mark end = versionDirective.End; throw new SemanticErrorException(in start, in end, "Found incompatible YAML document."); } result = (version = versionDirective); flag = true; } else { if (!(GetCurrentToken() is TagDirective tagDirective)) { break; } if (tags.Contains(tagDirective.Handle)) { Mark start = tagDirective.Start; Mark end = tagDirective.End; throw new SemanticErrorException(in start, in end, "Found duplicate %TAG directive."); } tags.Add(tagDirective); flag = true; } Skip(); } if (GetCurrentToken() is YamlDotNet.Core.Tokens.DocumentStart && (version == null || (version.Version.Major == 1 && version.Version.Minor > 1))) { if (GetCurrentToken() is YamlDotNet.Core.Tokens.DocumentStart && version == null) { version = new VersionDirective(new Version(1, 2)); } flag = true; } AddTagDirectives(tags, Constants.DefaultTagDirectives); if (flag) { tagDirectives.Clear(); } AddTagDirectives(tagDirectives, tags); return result; } private static void AddTagDirectives(TagDirectiveCollection directives, IEnumerable source) { foreach (TagDirective item in source) { if (!directives.Contains(item)) { directives.Add(item); } } } private ParsingEvent ParseDocumentContent() { if (GetCurrentToken() is VersionDirective || GetCurrentToken() is TagDirective || GetCurrentToken() is YamlDotNet.Core.Tokens.DocumentStart || GetCurrentToken() is YamlDotNet.Core.Tokens.DocumentEnd || GetCurrentToken() is YamlDotNet.Core.Tokens.StreamEnd) { state = states.Pop(); Mark position = scanner.CurrentPosition; return ProcessEmptyScalar(in position); } return ParseNode(isBlock: true, isIndentlessSequence: false); } private static YamlDotNet.Core.Events.Scalar ProcessEmptyScalar(in Mark position) { return new YamlDotNet.Core.Events.Scalar(AnchorName.Empty, TagName.Empty, string.Empty, ScalarStyle.Plain, isPlainImplicit: true, isQuotedImplicit: false, position, position); } private ParsingEvent ParseNode(bool isBlock, bool isIndentlessSequence) { Mark start; Mark end; if (GetCurrentToken() is Error error) { start = error.Start; end = error.End; throw new SemanticErrorException(in start, in end, error.Value); } Token token = GetCurrentToken() ?? throw new SemanticErrorException("Reached the end of the stream while parsing a node"); if (token is YamlDotNet.Core.Tokens.AnchorAlias anchorAlias) { state = states.Pop(); ParsingEvent result = new YamlDotNet.Core.Events.AnchorAlias(anchorAlias.Value, anchorAlias.Start, anchorAlias.End); Skip(); return result; } Mark start2 = token.Start; AnchorName anchor = AnchorName.Empty; TagName tag = TagName.Empty; Anchor anchor2 = null; Tag tag2 = null; while (true) { if (anchor.IsEmpty && token is Anchor anchor3) { anchor2 = anchor3; anchor = anchor3.Value; Skip(); } else { if (!tag.IsEmpty || !(token is Tag tag3)) { if (token is Anchor anchor4) { start = anchor4.Start; end = anchor4.End; throw new SemanticErrorException(in start, in end, "While parsing a node, found more than one anchor."); } if (token is YamlDotNet.Core.Tokens.AnchorAlias anchorAlias2) { start = anchorAlias2.Start; end = anchorAlias2.End; throw new SemanticErrorException(in start, in end, "While parsing a node, did not find expected token."); } if (!(token is Error error2)) { break; } if (tag2 != null && anchor2 != null && !anchor.IsEmpty) { return new YamlDotNet.Core.Events.Scalar(anchor, default(TagName), string.Empty, ScalarStyle.Any, isPlainImplicit: false, isQuotedImplicit: false, anchor2.Start, anchor2.End); } start = error2.Start; end = error2.End; throw new SemanticErrorException(in start, in end, error2.Value); } tag2 = tag3; if (string.IsNullOrEmpty(tag3.Handle)) { tag = new TagName(tag3.Suffix); } else { if (!tagDirectives.Contains(tag3.Handle)) { start = tag3.Start; end = tag3.End; throw new SemanticErrorException(in start, in end, "While parsing a node, found undefined tag handle."); } tag = new TagName(tagDirectives[tag3.Handle].Prefix + tag3.Suffix); } Skip(); } token = GetCurrentToken() ?? throw new SemanticErrorException("Reached the end of the stream while parsing a node"); } bool isEmpty = tag.IsEmpty; if (isIndentlessSequence && GetCurrentToken() is BlockEntry) { state = ParserState.IndentlessSequenceEntry; return new SequenceStart(anchor, tag, isEmpty, SequenceStyle.Block, start2, token.End); } if (token is YamlDotNet.Core.Tokens.Scalar scalar) { bool isPlainImplicit = false; bool isQuotedImplicit = false; if ((scalar.Style == ScalarStyle.Plain && tag.IsEmpty) || tag.IsNonSpecific) { isPlainImplicit = true; } else if (tag.IsEmpty) { isQuotedImplicit = true; } state = states.Pop(); Skip(); ParsingEvent result2 = new YamlDotNet.Core.Events.Scalar(anchor, tag, scalar.Value, scalar.Style, isPlainImplicit, isQuotedImplicit, start2, scalar.End, scalar.IsKey); if (!anchor.IsEmpty && scanner.MoveNextWithoutConsuming()) { currentToken = scanner.Current; if (currentToken is Error) { Error error3 = currentToken as Error; start = error3.Start; end = error3.End; throw new SemanticErrorException(in start, in end, error3.Value); } } if (state == ParserState.FlowMappingKey && !(scanner.Current is FlowMappingEnd) && scanner.MoveNextWithoutConsuming()) { currentToken = scanner.Current; if (currentToken != null && !(currentToken is FlowEntry) && !(currentToken is FlowMappingEnd)) { start = currentToken.Start; end = currentToken.End; throw new SemanticErrorException(in start, in end, "While parsing a flow mapping, did not find expected ',' or '}'."); } } return result2; } if (token is FlowSequenceStart flowSequenceStart) { state = ParserState.FlowSequenceFirstEntry; return new SequenceStart(anchor, tag, isEmpty, SequenceStyle.Flow, start2, flowSequenceStart.End); } if (token is FlowMappingStart flowMappingStart) { state = ParserState.FlowMappingFirstKey; return new MappingStart(anchor, tag, isEmpty, MappingStyle.Flow, start2, flowMappingStart.End); } if (isBlock) { if (token is BlockSequenceStart blockSequenceStart) { state = ParserState.BlockSequenceFirstEntry; return new SequenceStart(anchor, tag, isEmpty, SequenceStyle.Block, start2, blockSequenceStart.End); } if (token is BlockMappingStart blockMappingStart) { state = ParserState.BlockMappingFirstKey; return new MappingStart(anchor, tag, isEmpty, MappingStyle.Block, start2, blockMappingStart.End); } } if (!anchor.IsEmpty || !tag.IsEmpty) { state = states.Pop(); return new YamlDotNet.Core.Events.Scalar(anchor, tag, string.Empty, ScalarStyle.Plain, isEmpty, isQuotedImplicit: false, start2, token.End); } start = token.Start; end = token.End; throw new SemanticErrorException(in start, in end, "While parsing a node, did not find expected node content."); } private YamlDotNet.Core.Events.DocumentEnd ParseDocumentEnd() { Token token = GetCurrentToken() ?? throw new SemanticErrorException("Reached the end of the stream while parsing a document end"); bool isImplicit = true; Mark start = token.Start; Mark end = start; if (token is YamlDotNet.Core.Tokens.DocumentEnd) { end = token.End; Skip(); isImplicit = false; } else if (!(currentToken is YamlDotNet.Core.Tokens.StreamEnd) && !(currentToken is YamlDotNet.Core.Tokens.DocumentStart) && !(currentToken is FlowSequenceEnd) && !(currentToken is VersionDirective) && (!(Current is YamlDotNet.Core.Events.Scalar) || !(currentToken is Error))) { throw new SemanticErrorException(in start, in end, "Did not find expected ."); } if (version != null && version.Version.Major == 1 && version.Version.Minor > 1) { version = null; } state = ParserState.DocumentStart; return new YamlDotNet.Core.Events.DocumentEnd(isImplicit, start, end); } private ParsingEvent ParseBlockSequenceEntry(bool isFirst) { if (isFirst) { GetCurrentToken(); Skip(); } Token token = GetCurrentToken(); if (token is BlockEntry blockEntry) { Mark position = blockEntry.End; Skip(); token = GetCurrentToken(); if (!(token is BlockEntry) && !(token is BlockEnd)) { states.Push(ParserState.BlockSequenceEntry); return ParseNode(isBlock: true, isIndentlessSequence: false); } state = ParserState.BlockSequenceEntry; return ProcessEmptyScalar(in position); } Mark start; Mark end; if (token is BlockEnd blockEnd) { state = states.Pop(); start = blockEnd.Start; end = blockEnd.End; ParsingEvent result = new SequenceEnd(in start, in end); Skip(); return result; } start = token?.Start ?? Mark.Empty; end = token?.End ?? Mark.Empty; throw new SemanticErrorException(in start, in end, "While parsing a block collection, did not find expected '-' indicator."); } private ParsingEvent ParseIndentlessSequenceEntry() { Token token = GetCurrentToken(); if (token is BlockEntry blockEntry) { Mark position = blockEntry.End; Skip(); token = GetCurrentToken(); if (!(token is BlockEntry) && !(token is Key) && !(token is Value) && !(token is BlockEnd)) { states.Push(ParserState.IndentlessSequenceEntry); return ParseNode(isBlock: true, isIndentlessSequence: false); } state = ParserState.IndentlessSequenceEntry; return ProcessEmptyScalar(in position); } state = states.Pop(); Mark start = token?.Start ?? Mark.Empty; Mark end = token?.End ?? Mark.Empty; return new SequenceEnd(in start, in end); } private ParsingEvent ParseBlockMappingKey(bool isFirst) { if (isFirst) { GetCurrentToken(); Skip(); } Token token = GetCurrentToken(); if (token is Key key) { Mark position = key.End; Skip(); token = GetCurrentToken(); if (!(token is Key) && !(token is Value) && !(token is BlockEnd)) { states.Push(ParserState.BlockMappingValue); return ParseNode(isBlock: true, isIndentlessSequence: true); } state = ParserState.BlockMappingValue; return ProcessEmptyScalar(in position); } Mark position2; if (token is Value value) { Skip(); position2 = value.End; return ProcessEmptyScalar(in position2); } if (token is YamlDotNet.Core.Tokens.AnchorAlias anchorAlias) { Skip(); return new YamlDotNet.Core.Events.AnchorAlias(anchorAlias.Value, anchorAlias.Start, anchorAlias.End); } Mark end; if (token is BlockEnd blockEnd) { state = states.Pop(); position2 = blockEnd.Start; end = blockEnd.End; ParsingEvent result = new MappingEnd(in position2, in end); Skip(); return result; } if (GetCurrentToken() is Error error) { position2 = error.Start; end = error.End; throw new SyntaxErrorException(in position2, in end, error.Value); } position2 = token?.Start ?? Mark.Empty; end = token?.End ?? Mark.Empty; throw new SemanticErrorException(in position2, in end, "While parsing a block mapping, did not find expected key."); } private ParsingEvent ParseBlockMappingValue() { Token token = GetCurrentToken(); if (token is Value value) { Mark position = value.End; Skip(); token = GetCurrentToken(); if (!(token is Key) && !(token is Value) && !(token is BlockEnd)) { states.Push(ParserState.BlockMappingKey); return ParseNode(isBlock: true, isIndentlessSequence: true); } state = ParserState.BlockMappingKey; return ProcessEmptyScalar(in position); } Mark start; if (token is Error error) { start = error.Start; Mark end = error.End; throw new SemanticErrorException(in start, in end, error.Value); } state = ParserState.BlockMappingKey; start = token?.Start ?? Mark.Empty; return ProcessEmptyScalar(in start); } private ParsingEvent ParseFlowSequenceEntry(bool isFirst) { if (isFirst) { GetCurrentToken(); Skip(); } Token token = GetCurrentToken(); Mark start; Mark end; ParsingEvent result; if (!(token is FlowSequenceEnd)) { if (!isFirst) { if (!(token is FlowEntry)) { start = token?.Start ?? Mark.Empty; end = token?.End ?? Mark.Empty; throw new SemanticErrorException(in start, in end, "While parsing a flow sequence, did not find expected ',' or ']'."); } Skip(); token = GetCurrentToken(); } if (token is Key) { state = ParserState.FlowSequenceEntryMappingKey; result = new MappingStart(AnchorName.Empty, TagName.Empty, isImplicit: true, MappingStyle.Flow); Skip(); return result; } if (!(token is FlowSequenceEnd)) { states.Push(ParserState.FlowSequenceEntry); return ParseNode(isBlock: false, isIndentlessSequence: false); } } state = states.Pop(); start = token?.Start ?? Mark.Empty; end = token?.End ?? Mark.Empty; result = new SequenceEnd(in start, in end); Skip(); return result; } private ParsingEvent ParseFlowSequenceEntryMappingKey() { Token token = GetCurrentToken(); if (!(token is Value) && !(token is FlowEntry) && !(token is FlowSequenceEnd)) { states.Push(ParserState.FlowSequenceEntryMappingValue); return ParseNode(isBlock: false, isIndentlessSequence: false); } Mark position = token?.End ?? Mark.Empty; Skip(); state = ParserState.FlowSequenceEntryMappingValue; return ProcessEmptyScalar(in position); } private ParsingEvent ParseFlowSequenceEntryMappingValue() { Token token = GetCurrentToken(); if (token is Value) { Skip(); token = GetCurrentToken(); if (!(token is FlowEntry) && !(token is FlowSequenceEnd)) { states.Push(ParserState.FlowSequenceEntryMappingEnd); return ParseNode(isBlock: false, isIndentlessSequence: false); } } state = ParserState.FlowSequenceEntryMappingEnd; Mark position = token?.Start ?? Mark.Empty; return ProcessEmptyScalar(in position); } private MappingEnd ParseFlowSequenceEntryMappingEnd() { state = ParserState.FlowSequenceEntry; Token token = GetCurrentToken(); Mark start = token?.Start ?? Mark.Empty; Mark end = token?.End ?? Mark.Empty; return new MappingEnd(in start, in end); } private ParsingEvent ParseFlowMappingKey(bool isFirst) { if (isFirst) { GetCurrentToken(); Skip(); } Token token = GetCurrentToken(); Mark start; Mark end; if (!(token is FlowMappingEnd)) { if (!isFirst) { if (token is FlowEntry) { Skip(); token = GetCurrentToken(); } else if (!(token is YamlDotNet.Core.Tokens.Scalar)) { start = token?.Start ?? Mark.Empty; end = token?.End ?? Mark.Empty; throw new SemanticErrorException(in start, in end, "While parsing a flow mapping, did not find expected ',' or '}'."); } } if (token is Key) { Skip(); token = GetCurrentToken(); if (!(token is Value) && !(token is FlowEntry) && !(token is FlowMappingEnd)) { states.Push(ParserState.FlowMappingValue); return ParseNode(isBlock: false, isIndentlessSequence: false); } state = ParserState.FlowMappingValue; start = token?.Start ?? Mark.Empty; return ProcessEmptyScalar(in start); } if (token is YamlDotNet.Core.Tokens.Scalar) { states.Push(ParserState.FlowMappingValue); return ParseNode(isBlock: false, isIndentlessSequence: false); } if (!(token is FlowMappingEnd)) { states.Push(ParserState.FlowMappingEmptyValue); return ParseNode(isBlock: false, isIndentlessSequence: false); } } state = states.Pop(); Skip(); start = token?.Start ?? Mark.Empty; end = token?.End ?? Mark.Empty; return new MappingEnd(in start, in end); } private ParsingEvent ParseFlowMappingValue(bool isEmpty) { Token token = GetCurrentToken(); if (!isEmpty && token is Value) { Skip(); token = GetCurrentToken(); if (!(token is FlowEntry) && !(token is FlowMappingEnd)) { states.Push(ParserState.FlowMappingKey); return ParseNode(isBlock: false, isIndentlessSequence: false); } } state = ParserState.FlowMappingKey; if (!isEmpty && token is YamlDotNet.Core.Tokens.Scalar scalar) { Skip(); return new YamlDotNet.Core.Events.Scalar(AnchorName.Empty, TagName.Empty, scalar.Value, scalar.Style, isPlainImplicit: false, isQuotedImplicit: false, token.Start, scalar.End); } Mark position = token?.Start ?? Mark.Empty; return ProcessEmptyScalar(in position); } } internal static class ParserExtensions { public static T Consume(this IParser parser) where T : ParsingEvent { T result = parser.Require(); parser.MoveNext(); return result; } public static bool TryConsume(this IParser parser, [MaybeNullWhen(false)] out T @event) where T : ParsingEvent { if (parser.Accept(out @event)) { parser.MoveNext(); return true; } return false; } public static T Require(this IParser parser) where T : ParsingEvent { if (!parser.Accept(out var @event)) { ParsingEvent current = parser.Current; if (current == null) { throw new YamlException("Expected '" + typeof(T).Name + "', got nothing."); } Mark start = current.Start; Mark end = current.End; throw new YamlException(in start, in end, $"Expected '{typeof(T).Name}', got '{current.GetType().Name}' (at {current.Start})."); } return @event; } public static bool Accept(this IParser parser, [MaybeNullWhen(false)] out T @event) where T : ParsingEvent { if (parser.Current == null && !parser.MoveNext()) { throw new EndOfStreamException(); } if (parser.Current is T val) { @event = val; return true; } @event = null; return false; } public static void SkipThisAndNestedEvents(this IParser parser) { int num = 0; do { ParsingEvent parsingEvent = parser.Consume(); num += parsingEvent.NestingIncrease; } while (num > 0); } [Obsolete("Please use Consume() instead")] public static T Expect(this IParser parser) where T : ParsingEvent { return parser.Consume(); } [Obsolete("Please use TryConsume(out var evt) instead")] [return: MaybeNull] public static T? Allow(this IParser parser) where T : ParsingEvent { if (!parser.TryConsume(out var @event)) { return null; } return @event; } [Obsolete("Please use Accept(out var evt) instead")] [return: MaybeNull] public static T? Peek(this IParser parser) where T : ParsingEvent { if (!parser.Accept(out var @event)) { return null; } return @event; } [Obsolete("Please use TryConsume(out var evt) or Accept(out var evt) instead")] public static bool Accept(this IParser parser) where T : ParsingEvent { T @event; return parser.Accept(out @event); } public static bool TryFindMappingEntry(this IParser parser, Func selector, [MaybeNullWhen(false)] out YamlDotNet.Core.Events.Scalar? key, [MaybeNullWhen(false)] out ParsingEvent? value) { if (parser.TryConsume(out var _)) { while (parser.Current != null) { ParsingEvent current = parser.Current; if (!(current is YamlDotNet.Core.Events.Scalar scalar)) { if (current is MappingStart || current is SequenceStart) { parser.SkipThisAndNestedEvents(); } else { parser.MoveNext(); } continue; } bool flag = selector(scalar); parser.MoveNext(); if (flag) { value = parser.Current; key = scalar; return true; } parser.SkipThisAndNestedEvents(); } } key = null; value = null; return false; } } internal enum ParserState { StreamStart, StreamEnd, ImplicitDocumentStart, DocumentStart, DocumentContent, DocumentEnd, BlockNode, BlockNodeOrIndentlessSequence, FlowNode, BlockSequenceFirstEntry, BlockSequenceEntry, IndentlessSequenceEntry, BlockMappingFirstKey, BlockMappingKey, BlockMappingValue, FlowSequenceFirstEntry, FlowSequenceEntry, FlowSequenceEntryMappingKey, FlowSequenceEntryMappingValue, FlowSequenceEntryMappingEnd, FlowMappingFirstKey, FlowMappingKey, FlowMappingValue, FlowMappingEmptyValue } internal sealed class RecursionLevel { private int current; public int Maximum { get; } public RecursionLevel(int maximum) { Maximum = maximum; } public void Increment() { if (!TryIncrement()) { throw new MaximumRecursionLevelReachedException("Maximum level of recursion reached"); } } public bool TryIncrement() { if (current < Maximum) { current++; return true; } return false; } public void Decrement() { if (current == 0) { throw new InvalidOperationException("Attempted to decrement RecursionLevel to a negative value"); } current--; } } internal enum ScalarStyle { Any, Plain, SingleQuoted, DoubleQuoted, Literal, Folded, ForcePlain } internal class Scanner : IScanner { private const int MaxVersionNumberLength = 9; private static readonly SortedDictionary SimpleEscapeCodes = new SortedDictionary { { '0', '\0' }, { 'a', '\a' }, { 'b', '\b' }, { 't', '\t' }, { '\t', '\t' }, { 'n', '\n' }, { 'v', '\v' }, { 'f', '\f' }, { 'r', '\r' }, { 'e', '\u001b' }, { ' ', ' ' }, { '"', '"' }, { '\\', '\\' }, { '/', '/' }, { 'N', '\u0085' }, { '_', '\u00a0' }, { 'L', '\u2028' }, { 'P', '\u2029' } }; private readonly Stack indents = new Stack(); private readonly InsertionQueue tokens = new InsertionQueue(); private readonly Stack simpleKeys = new Stack(); private readonly CharacterAnalyzer analyzer; private readonly Cursor cursor; private bool streamStartProduced; private bool streamEndProduced; private bool plainScalarFollowedByComment; private bool flowCollectionFetched; private bool startFlowCollectionFetched; private long indent = -1L; private bool flowScalarFetched; private bool simpleKeyAllowed; private int flowLevel; private int tokensParsed; private bool tokenAvailable; private Token? previous; private Anchor? previousAnchor; private YamlDotNet.Core.Tokens.Scalar? lastScalar; private readonly int maxKeySize; private static readonly byte[] EmptyBytes = Array.Empty(); public bool SkipComments { get; private set; } public Token? Current { get; private set; } public Mark CurrentPosition => cursor.Mark(); private bool IsDocumentStart() { if (!analyzer.EndOfInput && cursor.LineOffset == 0L && analyzer.Check('-') && analyzer.Check('-', 1) && analyzer.Check('-', 2)) { return analyzer.IsWhiteBreakOrZero(3); } return false; } private bool IsDocumentEnd() { if (!analyzer.EndOfInput && cursor.LineOffset == 0L && analyzer.Check('.') && analyzer.Check('.', 1) && analyzer.Check('.', 2)) { return analyzer.IsWhiteBreakOrZero(3); } return false; } private bool IsDocumentIndicator() { if (!IsDocumentStart()) { return IsDocumentEnd(); } return true; } public Scanner(TextReader input, bool skipComments = true) : this(input, skipComments, 1024) { } public Scanner(TextReader input, bool skipComments, int maxKeySize) { analyzer = new CharacterAnalyzer(new LookAheadBuffer(input, 1024)); cursor = new Cursor(); SkipComments = skipComments; this.maxKeySize = maxKeySize; } public bool MoveNext() { if (Current != null) { ConsumeCurrent(); } return MoveNextWithoutConsuming(); } public bool MoveNextWithoutConsuming() { if (!tokenAvailable && !streamEndProduced) { FetchMoreTokens(); } if (tokens.Count > 0) { Current = tokens.Dequeue(); tokenAvailable = false; return true; } Current = null; return false; } public void ConsumeCurrent() { tokensParsed++; tokenAvailable = false; previous = Current; Current = null; } private char ReadCurrentCharacter() { char result = analyzer.Peek(0); Skip(); return result; } private char ReadLine() { if (analyzer.Check("\r\n\u0085")) { SkipLine(); return '\n'; } char result = analyzer.Peek(0); SkipLine(); return result; } private void FetchMoreTokens() { while (true) { bool flag = false; if (tokens.Count == 0) { flag = true; } else { foreach (SimpleKey simpleKey in simpleKeys) { if (simpleKey.IsPossible && simpleKey.TokenNumber == tokensParsed) { flag = true; break; } } } if (!flag) { break; } FetchNextToken(); } tokenAvailable = true; } private static bool StartsWith(StringBuilder what, char start) { if (what.Length > 0) { return what[0] == start; } return false; } private void StaleSimpleKeys() { foreach (SimpleKey simpleKey in simpleKeys) { if (simpleKey.IsPossible && (simpleKey.Line < cursor.Line || simpleKey.Index + maxKeySize < cursor.Index)) { if (simpleKey.IsRequired) { Mark mark = cursor.Mark(); tokens.Enqueue(new Error("While scanning a simple key, could not find expected ':'.", mark, mark)); } simpleKey.MarkAsImpossible(); } } } private void FetchNextToken() { if (!streamStartProduced) { FetchStreamStart(); return; } ScanToNextToken(); StaleSimpleKeys(); UnrollIndent(cursor.LineOffset); analyzer.Buffer.Cache(4); if (analyzer.Buffer.EndOfInput) { lastScalar = null; FetchStreamEnd(); } if (cursor.LineOffset == 0L && analyzer.Check('%')) { lastScalar = null; FetchDirective(); return; } if (IsDocumentStart()) { lastScalar = null; FetchDocumentIndicator(isStartToken: true); return; } if (IsDocumentEnd()) { lastScalar = null; FetchDocumentIndicator(isStartToken: false); return; } if (analyzer.Check('[')) { lastScalar = null; FetchFlowCollectionStart(isSequenceToken: true); return; } if (analyzer.Check('{')) { lastScalar = null; FetchFlowCollectionStart(isSequenceToken: false); return; } if (analyzer.Check(']')) { lastScalar = null; FetchFlowCollectionEnd(isSequenceToken: true); return; } if (analyzer.Check('}')) { lastScalar = null; FetchFlowCollectionEnd(isSequenceToken: false); return; } if (analyzer.Check(',')) { lastScalar = null; FetchFlowEntry(); return; } if (analyzer.Check('-')) { if (analyzer.IsWhiteBreakOrZero(1)) { FetchBlockEntry(); return; } if (flowLevel > 0 && analyzer.Check(",[]{}", 1)) { tokens.Enqueue(new Error("Invalid key indicator format.", cursor.Mark(), cursor.Mark())); } } if (analyzer.Check('?') && (flowLevel > 0 || analyzer.IsWhiteBreakOrZero(1)) && analyzer.IsWhiteBreakOrZero(1)) { FetchKey(); } else if (analyzer.Check(':') && (flowLevel > 0 || analyzer.IsWhiteBreakOrZero(1)) && (!simpleKeyAllowed || flowLevel <= 0) && (!flowScalarFetched || !analyzer.Check(':', 1)) && (analyzer.IsWhiteBreakOrZero(1) || analyzer.Check(',', 1) || flowScalarFetched || flowCollectionFetched || startFlowCollectionFetched)) { if (lastScalar != null) { lastScalar.IsKey = true; lastScalar = null; } FetchValue(); } else if (analyzer.Check('*')) { FetchAnchor(isAlias: true); } else if (analyzer.Check('&')) { FetchAnchor(isAlias: false); } else if (analyzer.Check('!')) { FetchTag(); } else if (analyzer.Check('|') && flowLevel == 0) { FetchBlockScalar(isLiteral: true); } else if (analyzer.Check('>') && flowLevel == 0) { FetchBlockScalar(isLiteral: false); } else if (analyzer.Check('\'')) { FetchQuotedScalar(isSingleQuoted: true); } else if (analyzer.Check('"')) { FetchQuotedScalar(isSingleQuoted: false); } else if ((!analyzer.IsWhiteBreakOrZero() && !analyzer.Check("-?:,[]{}#&*!|>'\"%@`")) || (analyzer.Check('-') && !analyzer.IsWhite(1)) || (analyzer.Check("?:") && !analyzer.IsWhiteBreakOrZero(1)) || (simpleKeyAllowed && flowLevel > 0)) { if (plainScalarFollowedByComment) { Mark mark = cursor.Mark(); tokens.Enqueue(new Error("While scanning plain scalar, found a comment between adjacent scalars.", mark, mark)); } if ((flowScalarFetched || (flowCollectionFetched && !startFlowCollectionFetched)) && analyzer.Check(':')) { Skip(); } flowScalarFetched = false; flowCollectionFetched = false; startFlowCollectionFetched = false; plainScalarFollowedByComment = false; FetchPlainScalar(); } else { if (simpleKeyAllowed && indent >= cursor.LineOffset && analyzer.IsTab()) { throw new SyntaxErrorException("While scanning a mapping, found invalid tab as indentation."); } if (!analyzer.IsWhiteBreakOrZero()) { Mark start = cursor.Mark(); Skip(); Mark end = cursor.Mark(); throw new SyntaxErrorException(in start, in end, "While scanning for the next token, found character that cannot start any token."); } Skip(); } } private bool CheckWhiteSpace() { if (!analyzer.Check(' ')) { if (flowLevel > 0 || !simpleKeyAllowed) { return analyzer.Check('\t'); } return false; } return true; } private void Skip() { cursor.Skip(); analyzer.Buffer.Skip(1); } private void SkipLine() { if (analyzer.IsCrLf()) { cursor.SkipLineByOffset(2); analyzer.Buffer.Skip(2); } else if (analyzer.IsBreak()) { cursor.SkipLineByOffset(1); analyzer.Buffer.Skip(1); } else if (!analyzer.IsZero()) { throw new InvalidOperationException("Not at a break."); } } private void ScanToNextToken() { while (true) { if (CheckWhiteSpace()) { Skip(); continue; } ProcessComment(); if (analyzer.IsBreak()) { SkipLine(); if (flowLevel == 0) { simpleKeyAllowed = true; } continue; } break; } } private void ProcessComment() { if (!analyzer.Check('#')) { return; } Mark start = cursor.Mark(); Skip(); while (analyzer.IsSpace()) { Skip(); } StringBuilderPool.BuilderWrapper builderWrapper = StringBuilderPool.Rent(); try { StringBuilder builder = builderWrapper.Builder; while (!analyzer.IsBreakOrZero()) { builder.Append(ReadCurrentCharacter()); } if (!SkipComments) { bool isInline = previous != null && previous.End.Line == start.Line && previous.End.Column != 1 && !(previous is YamlDotNet.Core.Tokens.StreamStart); tokens.Enqueue(new YamlDotNet.Core.Tokens.Comment(builder.ToString(), isInline, start, cursor.Mark())); } } finally { ((IDisposable)builderWrapper).Dispose(); } } private void FetchStreamStart() { simpleKeys.Push(new SimpleKey()); simpleKeyAllowed = true; streamStartProduced = true; Mark start = cursor.Mark(); tokens.Enqueue(new YamlDotNet.Core.Tokens.StreamStart(in start, in start)); } private void UnrollIndent(long column) { if (flowLevel == 0) { while (indent > column) { Mark start = cursor.Mark(); tokens.Enqueue(new BlockEnd(in start, in start)); indent = indents.Pop(); } } } private void FetchStreamEnd() { cursor.ForceSkipLineAfterNonBreak(); UnrollIndent(-1L); RemoveSimpleKey(); simpleKeyAllowed = false; streamEndProduced = true; Mark start = cursor.Mark(); tokens.Enqueue(new YamlDotNet.Core.Tokens.StreamEnd(in start, in start)); } private void FetchDirective() { UnrollIndent(-1L); RemoveSimpleKey(); simpleKeyAllowed = false; Token token = ScanDirective(); if (token != null) { tokens.Enqueue(token); } } private Token? ScanDirective() { Mark start = cursor.Mark(); Skip(); string text = ScanDirectiveName(in start); Token result; if (!(text == "YAML")) { if (!(text == "TAG")) { while (!analyzer.EndOfInput && !analyzer.Check('#') && !analyzer.IsBreak()) { Skip(); } return null; } result = ScanTagDirectiveValue(in start); } else { if (!(previous is YamlDotNet.Core.Tokens.DocumentStart) && !(previous is YamlDotNet.Core.Tokens.StreamStart) && !(previous is YamlDotNet.Core.Tokens.DocumentEnd)) { Mark end = cursor.Mark(); throw new SemanticErrorException(in start, in end, "While scanning a version directive, did not find preceding ."); } result = ScanVersionDirectiveValue(in start); } while (analyzer.IsWhite()) { Skip(); } ProcessComment(); if (!analyzer.IsBreakOrZero()) { Mark end = cursor.Mark(); throw new SyntaxErrorException(in start, in end, "While scanning a directive, did not find expected comment or line break."); } if (analyzer.IsBreak()) { SkipLine(); } return result; } private void FetchDocumentIndicator(bool isStartToken) { UnrollIndent(-1L); RemoveSimpleKey(); simpleKeyAllowed = false; Mark end = cursor.Mark(); Skip(); Skip(); Skip(); if (isStartToken) { InsertionQueue insertionQueue = tokens; Mark end2 = cursor.Mark(); insertionQueue.Enqueue(new YamlDotNet.Core.Tokens.DocumentStart(in end, in end2)); return; } Token token = null; while (!analyzer.EndOfInput && !analyzer.IsBreak() && !analyzer.Check('#')) { if (!analyzer.IsWhite()) { token = new Error("While scanning a document end, found invalid content after '...' marker.", end, cursor.Mark()); break; } Skip(); } tokens.Enqueue(new YamlDotNet.Core.Tokens.DocumentEnd(in end, in end)); if (token != null) { tokens.Enqueue(token); } } private void FetchFlowCollectionStart(bool isSequenceToken) { SaveSimpleKey(); IncreaseFlowLevel(); simpleKeyAllowed = true; Mark start = cursor.Mark(); Skip(); Token item = ((!isSequenceToken) ? ((Token)new FlowMappingStart(in start, in start)) : ((Token)new FlowSequenceStart(in start, in start))); tokens.Enqueue(item); startFlowCollectionFetched = true; } private void IncreaseFlowLevel() { simpleKeys.Push(new SimpleKey()); flowLevel++; } private void FetchFlowCollectionEnd(bool isSequenceToken) { RemoveSimpleKey(); DecreaseFlowLevel(); simpleKeyAllowed = false; Mark start = cursor.Mark(); Skip(); Token token = null; Token item; if (isSequenceToken) { if (analyzer.Check('#')) { token = new Error("While scanning a flow sequence end, found invalid comment after ']'.", start, start); } item = new FlowSequenceEnd(in start, in start); } else { item = new FlowMappingEnd(in start, in start); } tokens.Enqueue(item); if (token != null) { tokens.Enqueue(token); } flowCollectionFetched = true; } private void DecreaseFlowLevel() { if (flowLevel > 0) { flowLevel--; simpleKeys.Pop(); } } private void FetchFlowEntry() { RemoveSimpleKey(); simpleKeyAllowed = true; Mark start = cursor.Mark(); Skip(); Mark end = cursor.Mark(); if (analyzer.Check('#')) { tokens.Enqueue(new Error("While scanning a flow entry, found invalid comment after comma.", start, end)); } else { tokens.Enqueue(new FlowEntry(in start, in end)); } } private void FetchBlockEntry() { Mark start; if (flowLevel == 0) { if (!simpleKeyAllowed) { if (previousAnchor != null && previousAnchor.End.Line == cursor.Line) { start = previousAnchor.Start; Mark end = previousAnchor.End; throw new SemanticErrorException(in start, in end, "Anchor before sequence entry on same line is not allowed."); } Mark mark = cursor.Mark(); tokens.Enqueue(new Error("Block sequence entries are not allowed in this context.", mark, mark)); } RollIndent(cursor.LineOffset, -1, isSequence: true, cursor.Mark()); } RemoveSimpleKey(); simpleKeyAllowed = true; Mark start2 = cursor.Mark(); Skip(); InsertionQueue insertionQueue = tokens; start = cursor.Mark(); insertionQueue.Enqueue(new BlockEntry(in start2, in start)); } private void FetchKey() { if (flowLevel == 0) { if (!simpleKeyAllowed) { Mark start = cursor.Mark(); throw new SyntaxErrorException(in start, in start, "Mapping keys are not allowed in this context."); } RollIndent(cursor.LineOffset, -1, isSequence: false, cursor.Mark()); } RemoveSimpleKey(); simpleKeyAllowed = flowLevel == 0; Mark start2 = cursor.Mark(); Skip(); InsertionQueue insertionQueue = tokens; Mark end = cursor.Mark(); insertionQueue.Enqueue(new Key(in start2, in end)); } private void FetchValue() { SimpleKey simpleKey = simpleKeys.Peek(); Mark start; if (simpleKey.IsPossible) { InsertionQueue insertionQueue = tokens; int index = simpleKey.TokenNumber - tokensParsed; start = simpleKey.Mark; Mark end = simpleKey.Mark; insertionQueue.Insert(index, new Key(in start, in end)); RollIndent(simpleKey.LineOffset, simpleKey.TokenNumber, isSequence: false, simpleKey.Mark); simpleKey.MarkAsImpossible(); simpleKeyAllowed = false; } else { bool flag = flowLevel == 0; if (flag) { if (!simpleKeyAllowed) { Mark mark = cursor.Mark(); tokens.Enqueue(new Error("Mapping values are not allowed in this context.", mark, mark)); return; } RollIndent(cursor.LineOffset, -1, isSequence: false, cursor.Mark()); if (cursor.LineOffset == 0L && simpleKey.LineOffset == 0L) { InsertionQueue insertionQueue2 = tokens; int count = tokens.Count; start = simpleKey.Mark; Mark end = simpleKey.Mark; insertionQueue2.Insert(count, new Key(in start, in end)); flag = false; } } simpleKeyAllowed = flag; } Mark start2 = cursor.Mark(); Skip(); InsertionQueue insertionQueue3 = tokens; start = cursor.Mark(); insertionQueue3.Enqueue(new Value(in start2, in start)); } private void RollIndent(long column, int number, bool isSequence, Mark position) { if (flowLevel <= 0 && indent < column) { indents.Push(indent); indent = column; Token item = ((!isSequence) ? ((Token)new BlockMappingStart(in position, in position)) : ((Token)new BlockSequenceStart(in position, in position))); if (number == -1) { tokens.Enqueue(item); } else { tokens.Insert(number - tokensParsed, item); } } } private void FetchAnchor(bool isAlias) { SaveSimpleKey(); simpleKeyAllowed = false; tokens.Enqueue(ScanAnchor(isAlias)); } private Token ScanAnchor(bool isAlias) { Mark start = cursor.Mark(); Skip(); bool flag = false; if (isAlias) { SimpleKey simpleKey = simpleKeys.Peek(); flag = simpleKey.IsRequired && simpleKey.IsPossible; } StringBuilderPool.BuilderWrapper builderWrapper = StringBuilderPool.Rent(); try { StringBuilder builder = builderWrapper.Builder; while (!analyzer.IsWhiteBreakOrZero() && !analyzer.Check("[]{},") && (!flag || !analyzer.Check(':') || !analyzer.IsWhiteBreakOrZero(1))) { builder.Append(ReadCurrentCharacter()); } if (builder.Length == 0 || (!analyzer.IsWhiteBreakOrZero() && !analyzer.Check("?:,]}%@`"))) { Mark end = cursor.Mark(); throw new SyntaxErrorException(in start, in end, "While scanning an anchor or alias, found value containing disallowed: []{},"); } AnchorName value = new AnchorName(builder.ToString()); if (isAlias) { return new YamlDotNet.Core.Tokens.AnchorAlias(value, start, cursor.Mark()); } return previousAnchor = new Anchor(value, start, cursor.Mark()); } finally { ((IDisposable)builderWrapper).Dispose(); } } private void FetchTag() { SaveSimpleKey(); simpleKeyAllowed = false; tokens.Enqueue(ScanTag()); } private Tag ScanTag() { Mark start = cursor.Mark(); string text; string text2; if (analyzer.Check('<', 1)) { text = string.Empty; Skip(); Skip(); text2 = ScanTagUri(null, start); if (!analyzer.Check('>')) { Mark end = cursor.Mark(); throw new SyntaxErrorException(in start, in end, "While scanning a tag, did not find the expected '>'."); } Skip(); } else { string text3 = ScanTagHandle(isDirective: false, start); if (text3.Length > 1 && text3[0] == '!' && text3[text3.Length - 1] == '!') { text = text3; text2 = ScanTagUri(null, start); } else { text2 = ScanTagUri(text3, start); text = "!"; if (text2.Length == 0) { text2 = text; text = string.Empty; } } } if (!analyzer.IsWhiteBreakOrZero() && !analyzer.Check(',')) { Mark end = cursor.Mark(); throw new SyntaxErrorException(in start, in end, "While scanning a tag, did not find expected whitespace, comma or line break."); } return new Tag(text, text2, start, cursor.Mark()); } private void FetchBlockScalar(bool isLiteral) { SaveSimpleKey(); simpleKeyAllowed = true; tokens.Enqueue(ScanBlockScalar(isLiteral)); } private YamlDotNet.Core.Tokens.Scalar ScanBlockScalar(bool isLiteral) { StringBuilderPool.BuilderWrapper builderWrapper = StringBuilderPool.Rent(); try { StringBuilder builder = builderWrapper.Builder; StringBuilderPool.BuilderWrapper builderWrapper2 = StringBuilderPool.Rent(); try { StringBuilder builder2 = builderWrapper2.Builder; StringBuilderPool.BuilderWrapper builderWrapper3 = StringBuilderPool.Rent(); try { StringBuilder builder3 = builderWrapper3.Builder; int num = 0; int num2 = 0; long currentIndent = 0L; bool flag = false; bool? isFirstLine = null; Mark start = cursor.Mark(); Skip(); if (analyzer.Check("+-")) { num = (analyzer.Check('+') ? 1 : (-1)); Skip(); if (analyzer.IsDigit()) { if (analyzer.Check('0')) { Mark end = cursor.Mark(); throw new SyntaxErrorException(in start, in end, "While scanning a block scalar, found an indentation indicator equal to 0."); } num2 = analyzer.AsDigit(); Skip(); } } else if (analyzer.IsDigit()) { if (analyzer.Check('0')) { Mark end = cursor.Mark(); throw new SyntaxErrorException(in start, in end, "While scanning a block scalar, found an indentation indicator equal to 0."); } num2 = analyzer.AsDigit(); Skip(); if (analyzer.Check("+-")) { num = (analyzer.Check('+') ? 1 : (-1)); Skip(); } } if (analyzer.Check('#')) { Mark end = cursor.Mark(); throw new SyntaxErrorException(in start, in end, "While scanning a block scalar, found a comment without whtespace after '>' indicator."); } while (analyzer.IsWhite()) { Skip(); } ProcessComment(); if (!analyzer.IsBreakOrZero()) { Mark end = cursor.Mark(); throw new SyntaxErrorException(in start, in end, "While scanning a block scalar, did not find expected comment or line break."); } if (analyzer.IsBreak()) { SkipLine(); if (!isFirstLine.HasValue) { isFirstLine = true; } else if (isFirstLine.GetValueOrDefault()) { isFirstLine = false; } } Mark end2 = cursor.Mark(); if (num2 != 0) { currentIndent = ((indent >= 0) ? (indent + num2) : num2); } currentIndent = ScanBlockScalarBreaks(currentIndent, builder3, isLiteral, ref end2, ref isFirstLine); isFirstLine = false; while (cursor.LineOffset == currentIndent && !analyzer.IsZero() && !IsDocumentEnd()) { bool flag2 = analyzer.IsWhite(); if (!isLiteral && StartsWith(builder2, '\n') && !flag && !flag2) { if (builder3.Length == 0) { builder.Append(' '); } builder2.Length = 0; } else { builder.Append((object?)builder2); builder2.Length = 0; } builder.Append((object?)builder3); builder3.Length = 0; flag = analyzer.IsWhite(); while (!analyzer.IsBreakOrZero()) { builder.Append(ReadCurrentCharacter()); } char c = ReadLine(); if (c != 0) { builder2.Append(c); } currentIndent = ScanBlockScalarBreaks(currentIndent, builder3, isLiteral, ref end2, ref isFirstLine); } if (num != -1) { builder.Append((object?)builder2); } if (num == 1) { builder.Append((object?)builder3); } ScalarStyle style = (isLiteral ? ScalarStyle.Literal : ScalarStyle.Folded); return new YamlDotNet.Core.Tokens.Scalar(builder.ToString(), style, start, end2); } finally { ((IDisposable)builderWrapper3).Dispose(); } } finally { ((IDisposable)builderWrapper2).Dispose(); } } finally { ((IDisposable)builderWrapper).Dispose(); } } private long ScanBlockScalarBreaks(long currentIndent, StringBuilder breaks, bool isLiteral, ref Mark end, ref bool? isFirstLine) { long num = 0L; long num2 = -1L; end = cursor.Mark(); while (true) { if ((currentIndent == 0L || cursor.LineOffset < currentIndent) && analyzer.IsSpace()) { Skip(); continue; } if (cursor.LineOffset > num) { num = cursor.LineOffset; } if (!analyzer.IsBreak()) { break; } if (isFirstLine.GetValueOrDefault()) { isFirstLine = false; num2 = cursor.LineOffset; } breaks.Append(ReadLine()); end = cursor.Mark(); } if (isLiteral && isFirstLine.GetValueOrDefault()) { long num3 = cursor.LineOffset; int num4 = 0; while (!analyzer.IsBreak(num4) && analyzer.IsSpace(num4)) { num4++; num3++; } if (analyzer.IsBreak(num4) && num3 > cursor.LineOffset) { isFirstLine = false; num2 = num3; } } if (isLiteral && num2 > 1 && currentIndent < num2 - 1) { Mark end2 = cursor.Mark(); throw new SemanticErrorException(in end, in end2, "While scanning a literal block scalar, found extra spaces in first line."); } if (!isLiteral && num > cursor.LineOffset && num2 > -1) { Mark end2 = cursor.Mark(); throw new SemanticErrorException(in end, in end2, "While scanning a literal block scalar, found more spaces in lines above first content line."); } if (currentIndent == 0L && (cursor.LineOffset > 0 || indent > -1)) { currentIndent = Math.Max(num, Math.Max(indent + 1, 1L)); } return currentIndent; } private void FetchQuotedScalar(bool isSingleQuoted) { SaveSimpleKey(); simpleKeyAllowed = false; flowScalarFetched = flowLevel > 0; YamlDotNet.Core.Tokens.Scalar item = ScanFlowScalar(isSingleQuoted); tokens.Enqueue(item); lastScalar = item; if (!isSingleQuoted && analyzer.Check('#')) { Mark mark = cursor.Mark(); tokens.Enqueue(new Error("While scanning a flow sequence end, found invalid comment after double-quoted scalar.", mark, mark)); } } private YamlDotNet.Core.Tokens.Scalar ScanFlowScalar(bool isSingleQuoted) { Mark start = cursor.Mark(); Skip(); StringBuilderPool.BuilderWrapper builderWrapper = StringBuilderPool.Rent(); try { StringBuilder builder = builderWrapper.Builder; StringBuilderPool.BuilderWrapper builderWrapper2 = StringBuilderPool.Rent(); try { StringBuilder builder2 = builderWrapper2.Builder; StringBuilderPool.BuilderWrapper builderWrapper3 = StringBuilderPool.Rent(); try { StringBuilder builder3 = builderWrapper3.Builder; StringBuilderPool.BuilderWrapper builderWrapper4 = StringBuilderPool.Rent(); try { StringBuilder builder4 = builderWrapper4.Builder; bool flag = false; while (true) { if (IsDocumentIndicator()) { Mark end = cursor.Mark(); throw new SyntaxErrorException(in start, in end, "While scanning a quoted scalar, found unexpected document indicator."); } if (analyzer.IsZero()) { Mark end = cursor.Mark(); throw new SyntaxErrorException(in start, in end, "While scanning a quoted scalar, found unexpected end of stream."); } if (flag && !isSingleQuoted && indent >= cursor.LineOffset) { Mark end = cursor.Mark(); throw new SyntaxErrorException(in start, in end, "While scanning a multi-line double-quoted scalar, found wrong indentation."); } flag = false; while (!analyzer.IsWhiteBreakOrZero()) { if (isSingleQuoted && analyzer.Check('\'') && analyzer.Check('\'', 1)) { builder.Append('\''); Skip(); Skip(); continue; } if (analyzer.Check(isSingleQuoted ? '\'' : '"')) { break; } if (!isSingleQuoted && analyzer.Check('\\') && analyzer.IsBreak(1)) { Skip(); SkipLine(); flag = true; break; } if (!isSingleQuoted && analyzer.Check('\\')) { int num = 0; char c = analyzer.Peek(1); switch (c) { case 'x': num = 2; break; case 'u': num = 4; break; case 'U': num = 8; break; default: { if (SimpleEscapeCodes.TryGetValue(c, out var value)) { builder.Append(value); break; } Mark end = cursor.Mark(); throw new SyntaxErrorException(in start, in end, "While scanning a quoted scalar, found unknown escape character."); } } Skip(); Skip(); if (num <= 0) { continue; } int num2 = 0; for (int i = 0; i < num; i++) { if (!analyzer.IsHex(i)) { Mark end = cursor.Mark(); throw new SyntaxErrorException(in start, in end, "While scanning a quoted scalar, did not find expected hexadecimal number."); } num2 = (num2 << 4) + analyzer.AsHex(i); } if (num2 >= 55296 && num2 <= 57343) { for (int j = 0; j < num; j++) { Skip(); } if (analyzer.Peek(0) != '\\' || (analyzer.Peek(1) != 'u' && analyzer.Peek(1) != 'U')) { Mark end = cursor.Mark(); throw new SyntaxErrorException(in start, in end, "While scanning a quoted scalar, found invalid Unicode surrogates."); } Skip(); num = ((analyzer.Peek(0) != 'u') ? 8 : 4); Skip(); int num3 = 0; for (int k = 0; k < num; k++) { if (!analyzer.IsHex(0)) { Mark end = cursor.Mark(); throw new SyntaxErrorException(in start, in end, "While scanning a quoted scalar, did not find expected hexadecimal number."); } num3 = (num3 << 4) + analyzer.AsHex(k); } for (int l = 0; l < num; l++) { Skip(); } num2 = char.ConvertToUtf32((char)num2, (char)num3); } else { if (num2 > 1114111) { Mark end = cursor.Mark(); throw new SyntaxErrorException(in start, in end, "While scanning a quoted scalar, found invalid Unicode character escape code."); } for (int m = 0; m < num; m++) { Skip(); } } builder.Append(char.ConvertFromUtf32(num2)); } else { builder.Append(ReadCurrentCharacter()); } } if (analyzer.Check(isSingleQuoted ? '\'' : '"')) { break; } while (analyzer.IsWhite() || analyzer.IsBreak()) { if (analyzer.IsWhite()) { if (!flag) { builder2.Append(ReadCurrentCharacter()); } else { Skip(); } } else if (!flag) { builder2.Length = 0; builder3.Append(ReadLine()); flag = true; } else { builder4.Append(ReadLine()); } } if (flag) { if (StartsWith(builder3, '\n')) { if (builder4.Length == 0) { builder.Append(' '); } else { builder.Append((object?)builder4); } } else { builder.Append((object?)builder3); builder.Append((object?)builder4); } builder3.Length = 0; builder4.Length = 0; } else { builder.Append((object?)builder2); builder2.Length = 0; } } Skip(); return new YamlDotNet.Core.Tokens.Scalar(builder.ToString(), isSingleQuoted ? ScalarStyle.SingleQuoted : ScalarStyle.DoubleQuoted, start, cursor.Mark()); } finally { ((IDisposable)builderWrapper4).Dispose(); } } finally { ((IDisposable)builderWrapper3).Dispose(); } } finally { ((IDisposable)builderWrapper2).Dispose(); } } finally { ((IDisposable)builderWrapper).Dispose(); } } private void FetchPlainScalar() { SaveSimpleKey(); simpleKeyAllowed = false; bool isMultiline = false; YamlDotNet.Core.Tokens.Scalar item = (lastScalar = ScanPlainScalar(ref isMultiline)); if (isMultiline && analyzer.Check(':') && flowLevel == 0 && indent < cursor.LineOffset) { tokens.Enqueue(new Error("While scanning a multiline plain scalar, found invalid mapping.", cursor.Mark(), cursor.Mark())); } tokens.Enqueue(item); } private YamlDotNet.Core.Tokens.Scalar ScanPlainScalar(ref bool isMultiline) { StringBuilderPool.BuilderWrapper builderWrapper = StringBuilderPool.Rent(); try { StringBuilder builder = builderWrapper.Builder; StringBuilderPool.BuilderWrapper builderWrapper2 = StringBuilderPool.Rent(); try { StringBuilder builder2 = builderWrapper2.Builder; StringBuilderPool.BuilderWrapper builderWrapper3 = StringBuilderPool.Rent(); try { StringBuilder builder3 = builderWrapper3.Builder; StringBuilderPool.BuilderWrapper builderWrapper4 = StringBuilderPool.Rent(); try { StringBuilder builder4 = builderWrapper4.Builder; bool flag = false; long num = indent + 1; Mark start = cursor.Mark(); Mark end = start; SimpleKey simpleKey = simpleKeys.Peek(); while (!IsDocumentIndicator()) { if (analyzer.Check('#')) { if (indent < 0 && flowLevel == 0) { plainScalarFollowedByComment = true; } break; } bool flag2 = analyzer.Check('*') && (!simpleKey.IsPossible || !simpleKey.IsRequired); while (!analyzer.IsWhiteBreakOrZero()) { if ((analyzer.Check(':') && !flag2 && (analyzer.IsWhiteBreakOrZero(1) || (flowLevel > 0 && analyzer.Check(',', 1)))) || (flowLevel > 0 && analyzer.Check(",[]{}"))) { if (flowLevel == 0 && !simpleKey.IsPossible) { tokens.Enqueue(new Error("While scanning a plain scalar value, found invalid mapping.", cursor.Mark(), cursor.Mark())); } break; } if (flag || builder2.Length > 0) { if (flag) { if (StartsWith(builder3, '\n')) { if (builder4.Length == 0) { builder.Append(' '); } else { builder.Append((object?)builder4); } } else { builder.Append((object?)builder3); builder.Append((object?)builder4); } builder3.Length = 0; builder4.Length = 0; flag = false; } else { builder.Append((object?)builder2); builder2.Length = 0; } } if (flowLevel > 0 && cursor.LineOffset < num) { throw new InvalidOperationException(); } builder.Append(ReadCurrentCharacter()); end = cursor.Mark(); } if (!analyzer.IsWhite() && !analyzer.IsBreak()) { break; } while (analyzer.IsWhite() || analyzer.IsBreak()) { if (analyzer.IsWhite()) { if (flag && cursor.LineOffset < num && analyzer.IsTab()) { Mark end2 = cursor.Mark(); throw new SyntaxErrorException(in start, in end2, "While scanning a plain scalar, found a tab character that violate indentation."); } if (!flag) { builder2.Append(ReadCurrentCharacter()); } else { Skip(); } } else { isMultiline = true; if (!flag) { builder2.Length = 0; builder3.Append(ReadLine()); flag = true; } else { builder4.Append(ReadLine()); } } } if (flowLevel == 0 && cursor.LineOffset < num) { break; } } if (flag) { simpleKeyAllowed = true; } return new YamlDotNet.Core.Tokens.Scalar(builder.ToString(), ScalarStyle.Plain, start, end); } finally { ((IDisposable)builderWrapper4).Dispose(); } } finally { ((IDisposable)builderWrapper3).Dispose(); } } finally { ((IDisposable)builderWrapper2).Dispose(); } } finally { ((IDisposable)builderWrapper).Dispose(); } } private void RemoveSimpleKey() { SimpleKey simpleKey = simpleKeys.Peek(); if (simpleKey.IsPossible && simpleKey.IsRequired) { Mark start = simpleKey.Mark; Mark end = simpleKey.Mark; throw new SyntaxErrorException(in start, in end, "While scanning a simple key, could not find expected ':'."); } simpleKey.MarkAsImpossible(); } private string ScanDirectiveName(in Mark start) { StringBuilderPool.BuilderWrapper builderWrapper = StringBuilderPool.Rent(); try { StringBuilder builder = builderWrapper.Builder; while (analyzer.IsAlphaNumericDashOrUnderscore()) { builder.Append(ReadCurrentCharacter()); } if (builder.Length == 0) { Mark end = cursor.Mark(); throw new SyntaxErrorException(in start, in end, "While scanning a directive, could not find expected directive name."); } if (analyzer.EndOfInput) { Mark end = cursor.Mark(); throw new SyntaxErrorException(in start, in end, "While scanning a directive, found unexpected end of stream."); } if (!analyzer.IsWhiteBreakOrZero()) { Mark end = cursor.Mark(); throw new SyntaxErrorException(in start, in end, "While scanning a directive, found unexpected non-alphabetical character."); } return builder.ToString(); } finally { ((IDisposable)builderWrapper).Dispose(); } } private void SkipWhitespaces() { while (analyzer.IsWhite()) { Skip(); } } private VersionDirective ScanVersionDirectiveValue(in Mark start) { SkipWhitespaces(); int major = ScanVersionDirectiveNumber(in start); if (!analyzer.Check('.')) { Mark end = cursor.Mark(); throw new SyntaxErrorException(in start, in end, "While scanning a %YAML directive, did not find expected digit or '.' character."); } Skip(); int minor = ScanVersionDirectiveNumber(in start); return new VersionDirective(new Version(major, minor), start, start); } private TagDirective ScanTagDirectiveValue(in Mark start) { SkipWhitespaces(); string handle = ScanTagHandle(isDirective: true, start); if (!analyzer.IsWhite()) { Mark end = cursor.Mark(); throw new SyntaxErrorException(in start, in end, "While scanning a %TAG directive, did not find expected whitespace."); } SkipWhitespaces(); string prefix = ScanTagUri(null, start); if (!analyzer.IsWhiteBreakOrZero()) { Mark end = cursor.Mark(); throw new SyntaxErrorException(in start, in end, "While scanning a %TAG directive, did not find expected whitespace or line break."); } return new TagDirective(handle, prefix, start, start); } private string ScanTagUri(string? head, Mark start) { StringBuilderPool.BuilderWrapper builderWrapper = StringBuilderPool.Rent(); try { StringBuilder builder = builderWrapper.Builder; if (head != null && head.Length > 1) { builder.Append(head.Substring(1)); } while (analyzer.IsAlphaNumericDashOrUnderscore() || analyzer.Check(";/?:@&=+$.!~*'()[]%") || (analyzer.Check(',') && !analyzer.IsBreak(1))) { if (analyzer.Check('%')) { builder.Append(ScanUriEscapes(in start)); } else if (analyzer.Check('+')) { builder.Append(' '); Skip(); } else { builder.Append(ReadCurrentCharacter()); } } if (builder.Length == 0) { return string.Empty; } string text = builder.ToString(); if (Polyfills.EndsWith(text, ',')) { Mark start2 = cursor.Mark(); Mark end = cursor.Mark(); throw new SyntaxErrorException(in start2, in end, "Unexpected comma at end of tag"); } return text; } finally { ((IDisposable)builderWrapper).Dispose(); } } private string ScanUriEscapes(in Mark start) { byte[] array = EmptyBytes; int count = 0; int num = 0; do { if (!analyzer.Check('%') || !analyzer.IsHex(1) || !analyzer.IsHex(2)) { Mark end = cursor.Mark(); throw new SyntaxErrorException(in start, in end, "While scanning a tag, did not find URI escaped octet."); } int num2 = (analyzer.AsHex(1) << 4) + analyzer.AsHex(2); if (num == 0) { num = (((num2 & 0x80) == 0) ? 1 : (((num2 & 0xE0) == 192) ? 2 : (((num2 & 0xF0) == 224) ? 3 : (((num2 & 0xF8) == 240) ? 4 : 0)))); if (num == 0) { Mark end = cursor.Mark(); throw new SyntaxErrorException(in start, in end, "While scanning a tag, found an incorrect leading UTF-8 octet."); } array = new byte[num]; } else if ((num2 & 0xC0) != 128) { Mark end = cursor.Mark(); throw new SyntaxErrorException(in start, in end, "While scanning a tag, found an incorrect trailing UTF-8 octet."); } array[count++] = (byte)num2; Skip(); Skip(); Skip(); } while (--num > 0); string @string = Encoding.UTF8.GetString(array, 0, count); if (@string.Length == 0 || @string.Length > 2) { Mark end = cursor.Mark(); throw new SyntaxErrorException(in start, in end, "While scanning a tag, found an incorrect UTF-8 sequence."); } return @string; } private string ScanTagHandle(bool isDirective, Mark start) { if (!analyzer.Check('!')) { Mark end = cursor.Mark(); throw new SyntaxErrorException(in start, in end, "While scanning a tag, did not find expected '!'."); } StringBuilderPool.BuilderWrapper builderWrapper = StringBuilderPool.Rent(); try { StringBuilder builder = builderWrapper.Builder; builder.Append(ReadCurrentCharacter()); while (analyzer.IsAlphaNumericDashOrUnderscore()) { builder.Append(ReadCurrentCharacter()); } if (analyzer.Check('!')) { builder.Append(ReadCurrentCharacter()); } else if (isDirective && (builder.Length != 1 || builder[0] != '!')) { Mark end = cursor.Mark(); throw new SyntaxErrorException(in start, in end, "While scanning a tag directive, did not find expected '!'."); } return builder.ToString(); } finally { ((IDisposable)builderWrapper).Dispose(); } } private int ScanVersionDirectiveNumber(in Mark start) { int num = 0; int num2 = 0; while (analyzer.IsDigit()) { if (++num2 > 9) { Mark end = cursor.Mark(); throw new SyntaxErrorException(in start, in end, "While scanning a %YAML directive, found extremely long version number."); } num = num * 10 + analyzer.AsDigit(); Skip(); } if (num2 == 0) { Mark end = cursor.Mark(); throw new SyntaxErrorException(in start, in end, "While scanning a %YAML directive, did not find expected version number."); } return num; } private void SaveSimpleKey() { bool isRequired = flowLevel == 0 && indent == cursor.LineOffset; if (simpleKeyAllowed) { SimpleKey item = new SimpleKey(isRequired, tokensParsed + tokens.Count, cursor); RemoveSimpleKey(); simpleKeys.Pop(); simpleKeys.Push(item); } } } internal class SemanticErrorException : YamlException { public SemanticErrorException(string message) : base(message) { } public SemanticErrorException(in Mark start, in Mark end, string message) : base(in start, in end, message) { } public SemanticErrorException(string message, Exception inner) : base(message, inner) { } } internal sealed class SimpleKey { private readonly Cursor cursor; public bool IsPossible { get; private set; } public bool IsRequired { get; } public int TokenNumber { get; } public long Index => cursor.Index; public long Line => cursor.Line; public long LineOffset => cursor.LineOffset; public Mark Mark => cursor.Mark(); public void MarkAsImpossible() { IsPossible = false; } public SimpleKey() { cursor = new Cursor(); } public SimpleKey(bool isRequired, int tokenNumber, Cursor cursor) { IsPossible = true; IsRequired = isRequired; TokenNumber = tokenNumber; this.cursor = new Cursor(cursor); } } internal sealed class StringLookAheadBuffer : ILookAheadBuffer, IResettable { public string Value { get; set; } = string.Empty; public int Position { get; private set; } public int Length => Value.Length; public bool EndOfInput => IsOutside(Position); public char Peek(int offset) { int index = Position + offset; if (!IsOutside(index)) { return Value[index]; } return '\0'; } private bool IsOutside(int index) { return index >= Value.Length; } public void Skip(int length) { if (length < 0) { throw new ArgumentOutOfRangeException("length", "The length must be positive."); } Position += length; } public bool TryReset() { Position = 0; Value = string.Empty; return true; } } internal sealed class SyntaxErrorException : YamlException { public SyntaxErrorException(string message) : base(message) { } public SyntaxErrorException(in Mark start, in Mark end, string message) : base(in start, in end, message) { } public SyntaxErrorException(string message, Exception inner) : base(message, inner) { } } internal sealed class TagDirectiveCollection : KeyedCollection { public TagDirectiveCollection() { } public TagDirectiveCollection(IEnumerable tagDirectives) { foreach (TagDirective tagDirective in tagDirectives) { Add(tagDirective); } } protected override string GetKeyForItem(TagDirective item) { return item.Handle; } public new bool Contains(TagDirective directive) { return Contains(GetKeyForItem(directive)); } } internal readonly struct TagName : IEquatable { public static readonly TagName Empty; private readonly string? value; public string Value => value ?? throw new InvalidOperationException("Cannot read the Value of a non-specific tag"); public bool IsEmpty => value == null; public bool IsNonSpecific { get { if (!IsEmpty) { if (!(value == "!")) { return value == "?"; } return true; } return false; } } public bool IsLocal { get { if (!IsEmpty) { return Value[0] == '!'; } return false; } } public bool IsGlobal { get { if (!IsEmpty) { return !IsLocal; } return false; } } public TagName(string value) { this.value = value ?? throw new ArgumentNullException("value"); if (value.Length == 0) { throw new ArgumentException("Tag value must not be empty.", "value"); } if (IsGlobal && !Uri.IsWellFormedUriString(value, UriKind.RelativeOrAbsolute)) { throw new ArgumentException("Global tags must be valid URIs.", "value"); } } public override string ToString() { return value ?? "?"; } public bool Equals(TagName other) { return object.Equals(value, other.value); } public override bool Equals(object? obj) { if (obj is TagName other) { return Equals(other); } return false; } public override int GetHashCode() { return value?.GetHashCode() ?? 0; } public static bool operator ==(TagName left, TagName right) { return left.Equals(right); } public static bool operator !=(TagName left, TagName right) { return !(left == right); } public static bool operator ==(TagName left, string right) { return object.Equals(left.value, right); } public static bool operator !=(TagName left, string right) { return !(left == right); } public static implicit operator TagName(string? value) { if (value != null) { return new TagName(value); } return Empty; } } internal sealed class Version { public int Major { get; } public int Minor { get; } public Version(int major, int minor) { if (major < 0) { throw new ArgumentOutOfRangeException("major", $"{major} should be >= 0"); } Major = major; if (minor < 0) { throw new ArgumentOutOfRangeException("minor", $"{minor} should be >= 0"); } Minor = minor; } public override bool Equals(object? obj) { if (obj is Version version && Major == version.Major) { return Minor == version.Minor; } return false; } public override int GetHashCode() { return HashCode.CombineHashCodes(Major.GetHashCode(), Minor.GetHashCode()); } } internal class YamlException : Exception { public Mark Start { get; } public Mark End { get; } public YamlException(string message) : this(in Mark.Empty, in Mark.Empty, message) { } public YamlException(in Mark start, in Mark end, string message) : this(in start, in end, message, null) { } public YamlException(in Mark start, in Mark end, string message, Exception? innerException) : base(message, innerException) { Start = start; End = end; } public YamlException(string message, Exception inner) : this(in Mark.Empty, in Mark.Empty, message, inner) { } public override string ToString() { return $"({Start}) - ({End}): {Message}"; } } } namespace YamlDotNet.Core.Tokens { internal class Anchor : Token { public AnchorName Value { get; } public Anchor(AnchorName value) : this(value, Mark.Empty, Mark.Empty) { } public Anchor(AnchorName value, Mark start, Mark end) : base(in start, in end) { if (value.IsEmpty) { throw new ArgumentNullException("value"); } Value = value; } } internal sealed class AnchorAlias : Token { public AnchorName Value { get; } public AnchorAlias(AnchorName value) : this(value, Mark.Empty, Mark.Empty) { } public AnchorAlias(AnchorName value, Mark start, Mark end) : base(in start, in end) { if (value.IsEmpty) { throw new ArgumentNullException("value"); } Value = value; } } internal sealed class BlockEnd : Token { public BlockEnd() : this(in Mark.Empty, in Mark.Empty) { } public BlockEnd(in Mark start, in Mark end) : base(in start, in end) { } } internal sealed class BlockEntry : Token { public BlockEntry() : this(in Mark.Empty, in Mark.Empty) { } public BlockEntry(in Mark start, in Mark end) : base(in start, in end) { } } internal sealed class BlockMappingStart : Token { public BlockMappingStart() : this(in Mark.Empty, in Mark.Empty) { } public BlockMappingStart(in Mark start, in Mark end) : base(in start, in end) { } } internal sealed class BlockSequenceStart : Token { public BlockSequenceStart() : this(in Mark.Empty, in Mark.Empty) { } public BlockSequenceStart(in Mark start, in Mark end) : base(in start, in end) { } } internal sealed class Comment : Token { public string Value { get; } public bool IsInline { get; } public Comment(string value, bool isInline) : this(value, isInline, Mark.Empty, Mark.Empty) { } public Comment(string value, bool isInline, Mark start, Mark end) : base(in start, in end) { Value = value ?? throw new ArgumentNullException("value"); IsInline = isInline; } } internal sealed class DocumentEnd : Token { public DocumentEnd() : this(in Mark.Empty, in Mark.Empty) { } public DocumentEnd(in Mark start, in Mark end) : base(in start, in end) { } } internal sealed class DocumentStart : Token { public DocumentStart() : this(in Mark.Empty, in Mark.Empty) { } public DocumentStart(in Mark start, in Mark end) : base(in start, in end) { } } internal class Error : Token { public string Value { get; } public Error(string value, Mark start, Mark end) : base(in start, in end) { Value = value; } } internal sealed class FlowEntry : Token { public FlowEntry() : this(in Mark.Empty, in Mark.Empty) { } public FlowEntry(in Mark start, in Mark end) : base(in start, in end) { } } internal sealed class FlowMappingEnd : Token { public FlowMappingEnd() : this(in Mark.Empty, in Mark.Empty) { } public FlowMappingEnd(in Mark start, in Mark end) : base(in start, in end) { } } internal sealed class FlowMappingStart : Token { public FlowMappingStart() : this(in Mark.Empty, in Mark.Empty) { } public FlowMappingStart(in Mark start, in Mark end) : base(in start, in end) { } } internal sealed class FlowSequenceEnd : Token { public FlowSequenceEnd() : this(in Mark.Empty, in Mark.Empty) { } public FlowSequenceEnd(in Mark start, in Mark end) : base(in start, in end) { } } internal sealed class FlowSequenceStart : Token { public FlowSequenceStart() : this(in Mark.Empty, in Mark.Empty) { } public FlowSequenceStart(in Mark start, in Mark end) : base(in start, in end) { } } internal sealed class Key : Token { public Key() : this(in Mark.Empty, in Mark.Empty) { } public Key(in Mark start, in Mark end) : base(in start, in end) { } } internal sealed class Scalar : Token { public bool IsKey { get; set; } public string Value { get; } public ScalarStyle Style { get; } public Scalar(string value) : this(value, ScalarStyle.Any) { } public Scalar(string value, ScalarStyle style) : this(value, style, Mark.Empty, Mark.Empty) { } public Scalar(string value, ScalarStyle style, Mark start, Mark end) : base(in start, in end) { Value = value ?? throw new ArgumentNullException("value"); Style = style; } } internal sealed class StreamEnd : Token { public StreamEnd() : this(in Mark.Empty, in Mark.Empty) { } public StreamEnd(in Mark start, in Mark end) : base(in start, in end) { } } internal sealed class StreamStart : Token { public StreamStart() : this(in Mark.Empty, in Mark.Empty) { } public StreamStart(in Mark start, in Mark end) : base(in start, in end) { } } internal sealed class Tag : Token { public string Handle { get; } public string Suffix { get; } public Tag(string handle, string suffix) : this(handle, suffix, Mark.Empty, Mark.Empty) { } public Tag(string handle, string suffix, Mark start, Mark end) : base(in start, in end) { Handle = handle ?? throw new ArgumentNullException("handle"); Suffix = suffix ?? throw new ArgumentNullException("suffix"); } } internal class TagDirective : Token { private static readonly Regex TagHandlePattern = new Regex("^!([0-9A-Za-z_\\-]*!)?$", RegexOptions.Compiled); public string Handle { get; } public string Prefix { get; } public TagDirective(string handle, string prefix) : this(handle, prefix, Mark.Empty, Mark.Empty) { } public TagDirective(string handle, string prefix, Mark start, Mark end) : base(in start, in end) { if (string.IsNullOrEmpty(handle)) { throw new ArgumentNullException("handle", "Tag handle must not be empty."); } if (!TagHandlePattern.IsMatch(handle)) { throw new ArgumentException("Tag handle must start and end with '!' and contain alphanumerical characters only.", "handle"); } Handle = handle; if (string.IsNullOrEmpty(prefix)) { throw new ArgumentNullException("prefix", "Tag prefix must not be empty."); } Prefix = prefix; } public override bool Equals(object? obj) { if (obj is TagDirective tagDirective && Handle.Equals(tagDirective.Handle)) { return Prefix.Equals(tagDirective.Prefix); } return false; } public override int GetHashCode() { return Handle.GetHashCode() ^ Prefix.GetHashCode(); } public override string ToString() { return Handle + " => " + Prefix; } } internal abstract class Token { public Mark Start { get; } public Mark End { get; } protected Token(in Mark start, in Mark end) { Start = start; End = end; } } internal sealed class Value : Token { public Value() : this(in Mark.Empty, in Mark.Empty) { } public Value(in Mark start, in Mark end) : base(in start, in end) { } } internal sealed class VersionDirective : Token { public Version Version { get; } public VersionDirective(Version version) : this(version, Mark.Empty, Mark.Empty) { } public VersionDirective(Version version, Mark start, Mark end) : base(in start, in end) { Version = version; } public override bool Equals(object? obj) { if (obj is VersionDirective versionDirective) { return Version.Equals(versionDirective.Version); } return false; } public override int GetHashCode() { return Version.GetHashCode(); } } } namespace YamlDotNet.Core.ObjectPool { internal class DefaultObjectPool : ObjectPool where T : class { private readonly Func createFunc; private readonly Func returnFunc; private readonly int maxCapacity; private int numItems; private protected readonly ConcurrentQueue items = new ConcurrentQueue(); private protected T? fastItem; public DefaultObjectPool(IPooledObjectPolicy policy) : this(policy, Environment.ProcessorCount * 2) { } public DefaultObjectPool(IPooledObjectPolicy policy, int maximumRetained) { createFunc = policy.Create; returnFunc = policy.Return; maxCapacity = maximumRetained - 1; } public override T Get() { T result = fastItem; if (result == null || Interlocked.CompareExchange(ref fastItem, null, result) != result) { if (items.TryDequeue(out result)) { Interlocked.Decrement(ref numItems); return result; } return createFunc(); } return result; } public override void Return(T obj) { ReturnCore(obj); } private protected bool ReturnCore(T obj) { if (!returnFunc(obj)) { return false; } if (fastItem != null || Interlocked.CompareExchange(ref fastItem, obj, null) != null) { if (Interlocked.Increment(ref numItems) <= maxCapacity) { items.Enqueue(obj); return true; } Interlocked.Decrement(ref numItems); return false; } return true; } } internal class DefaultPooledObjectPolicy : IPooledObjectPolicy where T : class, new() { public T Create() { return new T(); } public bool Return(T obj) { if (obj is IResettable resettable) { return resettable.TryReset(); } return true; } } internal interface IPooledObjectPolicy where T : notnull { T Create(); bool Return(T obj); } internal interface IResettable { bool TryReset(); } internal abstract class ObjectPool where T : class { public abstract T Get(); public abstract void Return(T obj); } internal static class ObjectPool { public static ObjectPool Create(IPooledObjectPolicy? policy = null) where T : class, new() { return new DefaultObjectPool(policy ?? new DefaultPooledObjectPolicy()); } public static ObjectPool Create(int maximumRetained, IPooledObjectPolicy? policy = null) where T : class, new() { return new DefaultObjectPool(policy ?? new DefaultPooledObjectPolicy(), maximumRetained); } } [DebuggerStepThrough] internal static class StringBuilderPool { internal readonly struct BuilderWrapper : IDisposable { public readonly StringBuilder Builder; private readonly ObjectPool pool; public BuilderWrapper(StringBuilder builder, ObjectPool pool) { Builder = builder; this.pool = pool; } public override string ToString() { return Builder.ToString(); } public void Dispose() { pool.Return(Builder); } } private static readonly ObjectPool Pool = ObjectPool.Create(new StringBuilderPooledObjectPolicy { InitialCapacity = 16, MaximumRetainedCapacity = 1024 }); public static BuilderWrapper Rent() { StringBuilder builder = Pool.Get(); return new BuilderWrapper(builder, Pool); } } internal class StringBuilderPooledObjectPolicy : IPooledObjectPolicy { public int InitialCapacity { get; set; } = 100; public int MaximumRetainedCapacity { get; set; } = 4096; public StringBuilder Create() { return new StringBuilder(InitialCapacity); } public bool Return(StringBuilder obj) { if (obj.Capacity > MaximumRetainedCapacity) { return false; } obj.Clear(); return true; } } internal static class StringLookAheadBufferPool { internal readonly struct BufferWrapper : IDisposable { public readonly StringLookAheadBuffer Buffer; private readonly ObjectPool pool; public BufferWrapper(StringLookAheadBuffer buffer, ObjectPool pool) { Buffer = buffer; this.pool = pool; } public override string ToString() { return Buffer.ToString(); } public void Dispose() { pool.Return(Buffer); } } private static readonly ObjectPool Pool = ObjectPool.Create(new DefaultPooledObjectPolicy()); public static BufferWrapper Rent(string value) { StringLookAheadBuffer stringLookAheadBuffer = Pool.Get(); stringLookAheadBuffer.Value = value; return new BufferWrapper(stringLookAheadBuffer, Pool); } } } namespace YamlDotNet.Core.Events { internal sealed class AnchorAlias : ParsingEvent { internal override EventType Type => EventType.Alias; public AnchorName Value { get; } public AnchorAlias(AnchorName value, Mark start, Mark end) : base(in start, in end) { if (value.IsEmpty) { throw new YamlException(in start, in end, "Anchor value must not be empty."); } Value = value; } public AnchorAlias(AnchorName value) : this(value, Mark.Empty, Mark.Empty) { } public override string ToString() { return $"Alias [value = {Value}]"; } public override void Accept(IParsingEventVisitor visitor) { visitor.Visit(this); } } internal sealed class Comment : ParsingEvent { public string Value { get; } public bool IsInline { get; } internal override EventType Type => EventType.Comment; public Comment(string value, bool isInline) : this(value, isInline, Mark.Empty, Mark.Empty) { } public Comment(string value, bool isInline, Mark start, Mark end) : base(in start, in end) { Value = value; IsInline = isInline; } public override void Accept(IParsingEventVisitor visitor) { visitor.Visit(this); } public override string ToString() { return (IsInline ? "Inline" : "Block") + " Comment [" + Value + "]"; } } internal sealed class DocumentEnd : ParsingEvent { public override int NestingIncrease => -1; internal override EventType Type => EventType.DocumentEnd; public bool IsImplicit { get; } public DocumentEnd(bool isImplicit, Mark start, Mark end) : base(in start, in end) { IsImplicit = isImplicit; } public DocumentEnd(bool isImplicit) : this(isImplicit, Mark.Empty, Mark.Empty) { } public override string ToString() { return $"Document end [isImplicit = {IsImplicit}]"; } public override void Accept(IParsingEventVisitor visitor) { visitor.Visit(this); } } internal sealed class DocumentStart : ParsingEvent { public override int NestingIncrease => 1; internal override EventType Type => EventType.DocumentStart; public TagDirectiveCollection? Tags { get; } public VersionDirective? Version { get; } public bool IsImplicit { get; } public DocumentStart(VersionDirective? version, TagDirectiveCollection? tags, bool isImplicit, Mark start, Mark end) : base(in start, in end) { Version = version; Tags = tags; IsImplicit = isImplicit; } public DocumentStart(VersionDirective? version, TagDirectiveCollection? tags, bool isImplicit) : this(version, tags, isImplicit, Mark.Empty, Mark.Empty) { } public DocumentStart(in Mark start, in Mark end) : this(null, null, isImplicit: true, start, end) { } public DocumentStart() : this(null, null, isImplicit: true, Mark.Empty, Mark.Empty) { } public override string ToString() { return $"Document start [isImplicit = {IsImplicit}]"; } public override void Accept(IParsingEventVisitor visitor) { visitor.Visit(this); } } internal enum EventType { None, StreamStart, StreamEnd, DocumentStart, DocumentEnd, Alias, Scalar, SequenceStart, SequenceEnd, MappingStart, MappingEnd, Comment } internal interface IParsingEventVisitor { void Visit(AnchorAlias e); void Visit(StreamStart e); void Visit(StreamEnd e); void Visit(DocumentStart e); void Visit(DocumentEnd e); void Visit(Scalar e); void Visit(SequenceStart e); void Visit(SequenceEnd e); void Visit(MappingStart e); void Visit(MappingEnd e); void Visit(Comment e); } internal class MappingEnd : ParsingEvent { public override int NestingIncrease => -1; internal override EventType Type => EventType.MappingEnd; public MappingEnd(in Mark start, in Mark end) : base(in start, in end) { } public MappingEnd() : this(in Mark.Empty, in Mark.Empty) { } public override string ToString() { return "Mapping end"; } public override void Accept(IParsingEventVisitor visitor) { visitor.Visit(this); } } internal sealed class MappingStart : NodeEvent { public override int NestingIncrease => 1; internal override EventType Type => EventType.MappingStart; public bool IsImplicit { get; } public override bool IsCanonical => !IsImplicit; public MappingStyle Style { get; } public MappingStart(AnchorName anchor, TagName tag, bool isImplicit, MappingStyle style, Mark start, Mark end) : base(anchor, tag, start, end) { IsImplicit = isImplicit; Style = style; } public MappingStart(AnchorName anchor, TagName tag, bool isImplicit, MappingStyle style) : this(anchor, tag, isImplicit, style, Mark.Empty, Mark.Empty) { } public MappingStart() : this(AnchorName.Empty, TagName.Empty, isImplicit: true, MappingStyle.Any, Mark.Empty, Mark.Empty) { } public override string ToString() { return $"Mapping start [anchor = {base.Anchor}, tag = {base.Tag}, isImplicit = {IsImplicit}, style = {Style}]"; } public override void Accept(IParsingEventVisitor visitor) { visitor.Visit(this); } } internal enum MappingStyle { Any, Block, Flow } internal abstract class NodeEvent : ParsingEvent { public AnchorName Anchor { get; } public TagName Tag { get; } public abstract bool IsCanonical { get; } protected NodeEvent(AnchorName anchor, TagName tag, Mark start, Mark end) : base(in start, in end) { Anchor = anchor; Tag = tag; } protected NodeEvent(AnchorName anchor, TagName tag) : this(anchor, tag, Mark.Empty, Mark.Empty) { } } internal abstract class ParsingEvent { public virtual int NestingIncrease => 0; internal abstract EventType Type { get; } public Mark Start { get; } public Mark End { get; } public abstract void Accept(IParsingEventVisitor visitor); internal ParsingEvent(in Mark start, in Mark end) { Start = start; End = end; } } internal sealed class Scalar : NodeEvent { internal override EventType Type => EventType.Scalar; public string Value { get; } public ScalarStyle Style { get; } public bool IsPlainImplicit { get; } public bool IsQuotedImplicit { get; } public override bool IsCanonical { get { if (!IsPlainImplicit) { return !IsQuotedImplicit; } return false; } } public bool IsKey { get; } public Scalar(AnchorName anchor, TagName tag, string value, ScalarStyle style, bool isPlainImplicit, bool isQuotedImplicit, Mark start, Mark end, bool isKey = false) : base(anchor, tag, start, end) { Value = value; Style = style; IsPlainImplicit = isPlainImplicit; IsQuotedImplicit = isQuotedImplicit; IsKey = isKey; } public Scalar(AnchorName anchor, TagName tag, string value, ScalarStyle style, bool isPlainImplicit, bool isQuotedImplicit) : this(anchor, tag, value, style, isPlainImplicit, isQuotedImplicit, Mark.Empty, Mark.Empty) { } public Scalar(string value) : this(AnchorName.Empty, TagName.Empty, value, ScalarStyle.Any, isPlainImplicit: true, isQuotedImplicit: true, Mark.Empty, Mark.Empty) { } public Scalar(TagName tag, string value) : this(AnchorName.Empty, tag, value, ScalarStyle.Any, isPlainImplicit: true, isQuotedImplicit: true, Mark.Empty, Mark.Empty) { } public Scalar(AnchorName anchor, TagName tag, string value) : this(anchor, tag, value, ScalarStyle.Any, isPlainImplicit: true, isQuotedImplicit: true, Mark.Empty, Mark.Empty) { } public override string ToString() { return $"Scalar [anchor = {base.Anchor}, tag = {base.Tag}, value = {Value}, style = {Style}, isPlainImplicit = {IsPlainImplicit}, isQuotedImplicit = {IsQuotedImplicit}]"; } public override void Accept(IParsingEventVisitor visitor) { visitor.Visit(this); } } internal sealed class SequenceEnd : ParsingEvent { public override int NestingIncrease => -1; internal override EventType Type => EventType.SequenceEnd; public SequenceEnd(in Mark start, in Mark end) : base(in start, in end) { } public SequenceEnd() : this(in Mark.Empty, in Mark.Empty) { } public override string ToString() { return "Sequence end"; } public override void Accept(IParsingEventVisitor visitor) { visitor.Visit(this); } } internal sealed class SequenceStart : NodeEvent { public override int NestingIncrease => 1; internal override EventType Type => EventType.SequenceStart; public bool IsImplicit { get; } public override bool IsCanonical => !IsImplicit; public SequenceStyle Style { get; } public SequenceStart(AnchorName anchor, TagName tag, bool isImplicit, SequenceStyle style, Mark start, Mark end) : base(anchor, tag, start, end) { IsImplicit = isImplicit; Style = style; } public SequenceStart(AnchorName anchor, TagName tag, bool isImplicit, SequenceStyle style) : this(anchor, tag, isImplicit, style, Mark.Empty, Mark.Empty) { } public override string ToString() { return $"Sequence start [anchor = {base.Anchor}, tag = {base.Tag}, isImplicit = {IsImplicit}, style = {Style}]"; } public override void Accept(IParsingEventVisitor visitor) { visitor.Visit(this); } } internal enum SequenceStyle { Any, Block, Flow } internal sealed class StreamEnd : ParsingEvent { public override int NestingIncrease => -1; internal override EventType Type => EventType.StreamEnd; public StreamEnd(in Mark start, in Mark end) : base(in start, in end) { } public StreamEnd() : this(in Mark.Empty, in Mark.Empty) { } public override string ToString() { return "Stream end"; } public override void Accept(IParsingEventVisitor visitor) { visitor.Visit(this); } } internal sealed class StreamStart : ParsingEvent { public override int NestingIncrease => 1; internal override EventType Type => EventType.StreamStart; public StreamStart() : this(in Mark.Empty, in Mark.Empty) { } public StreamStart(in Mark start, in Mark end) : base(in start, in end) { } public override string ToString() { return "Stream start"; } public override void Accept(IParsingEventVisitor visitor) { visitor.Visit(this); } } } namespace System.Diagnostics.CodeAnalysis { [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, Inherited = false)] [ExcludeFromCodeCoverage] [DebuggerNonUserCode] internal sealed class AllowNullAttribute : Attribute { } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, Inherited = false)] [ExcludeFromCodeCoverage] [DebuggerNonUserCode] internal sealed class DisallowNullAttribute : Attribute { } [AttributeUsage(AttributeTargets.Method, Inherited = false)] [ExcludeFromCodeCoverage] [DebuggerNonUserCode] internal sealed class DoesNotReturnAttribute : Attribute { } [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] [ExcludeFromCodeCoverage] [DebuggerNonUserCode] internal sealed class DoesNotReturnIfAttribute : Attribute { public bool ParameterValue { get; } public DoesNotReturnIfAttribute(bool parameterValue) { ParameterValue = parameterValue; } } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, Inherited = false)] [ExcludeFromCodeCoverage] [DebuggerNonUserCode] internal sealed class MaybeNullAttribute : Attribute { } [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] [ExcludeFromCodeCoverage] [DebuggerNonUserCode] internal sealed class MaybeNullWhenAttribute : Attribute { public bool ReturnValue { get; } public MaybeNullWhenAttribute(bool returnValue) { ReturnValue = returnValue; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] [ExcludeFromCodeCoverage] [DebuggerNonUserCode] internal sealed class MemberNotNullAttribute : Attribute { public string[] Members { get; } public MemberNotNullAttribute(string member) { Members = new string[1] { member }; } public MemberNotNullAttribute(params string[] members) { Members = members; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] [ExcludeFromCodeCoverage] [DebuggerNonUserCode] internal sealed class MemberNotNullWhenAttribute : Attribute { public bool ReturnValue { get; } public string[] Members { get; } public MemberNotNullWhenAttribute(bool returnValue, string member) { ReturnValue = returnValue; Members = new string[1] { member }; } public MemberNotNullWhenAttribute(bool returnValue, params string[] members) { ReturnValue = returnValue; Members = members; } } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, Inherited = false)] [ExcludeFromCodeCoverage] [DebuggerNonUserCode] internal sealed class NotNullAttribute : Attribute { } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Parameter | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)] [ExcludeFromCodeCoverage] [DebuggerNonUserCode] internal sealed class NotNullIfNotNullAttribute : Attribute { public string ParameterName { get; } public NotNullIfNotNullAttribute(string parameterName) { ParameterName = parameterName; } } [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] [ExcludeFromCodeCoverage] [DebuggerNonUserCode] internal sealed class NotNullWhenAttribute : Attribute { public bool ReturnValue { get; } public NotNullWhenAttribute(bool returnValue) { ReturnValue = returnValue; } } }