using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Threading; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using JetBrains.Annotations; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using LocalizationManager; using Microsoft.CodeAnalysis; using STUWard; using ServerSync; using Splatform; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.UI; using YamlDotNet.Core; using YamlDotNet.Core.Events; using YamlDotNet.Core.ObjectPool; using YamlDotNet.Core.Tokens; using YamlDotNet.Helpers; 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("STUWard")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("sighsorry")] [assembly: AssemblyProduct("STUWard")] [assembly: AssemblyCopyright("Copyright © 2021")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("4358610B-F3F4-4843-B7AF-98B7BC60DCDE")] [assembly: AssemblyFileVersion("1.1.9")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.1.9.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; } } } namespace LocalizationManager { public static class Localizer { private static readonly string[] FileExtensions = new string[2] { ".json", ".yml" }; private static readonly Dictionary> CachedTranslations = new Dictionary>(StringComparer.OrdinalIgnoreCase); private static readonly IDeserializer Deserializer = new DeserializerBuilder().IgnoreFields().Build(); private static BaseUnityPlugin? _plugin; private static bool _registeredWithJotunn; private static bool _hookedJotunn; private static string? _lastLoggedAppliedLanguage; private static int _lastLoggedAppliedCount = -1; private static BaseUnityPlugin Plugin { get { //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Expected O, but got Unknown if ((Object)(object)_plugin != (Object)null) { return _plugin; } IEnumerable source; try { source = Assembly.GetExecutingAssembly().DefinedTypes.ToList(); } catch (ReflectionTypeLoadException ex) { source = from type in ex.Types where type != null select type.GetTypeInfo(); } _plugin = (BaseUnityPlugin)Chainloader.ManagerObject.GetComponent((Type)source.First((TypeInfo type) => type.IsClass && typeof(BaseUnityPlugin).IsAssignableFrom(type))); return _plugin; } } private static CustomLocalization CustomLocalization => LocalizationManager.Instance.GetLocalization(); public static event Action? OnLocalizationComplete; public static void Load() { _ = Plugin; LoadTranslations(); RegisterWithJotunn(); HookJotunn(); ReloadCurrentLanguageIfAvailable(); SafeCallLocalizeComplete(); } public static void Unload() { if (_hookedJotunn) { LocalizationManager.OnLocalizationAdded -= ReloadCurrentLanguageIfAvailable; _hookedJotunn = false; } _plugin = null; _registeredWithJotunn = false; _lastLoggedAppliedLanguage = null; _lastLoggedAppliedCount = -1; } public static void ReloadCurrentLanguageIfAvailable() { if (Localization.instance != null) { LoadTranslations(); RegisterWithJotunn(); ApplyCurrentLanguage(Localization.instance); } } public static void LoadLocalizationLater() { ReloadCurrentLanguageIfAvailable(); } public static void SafeCallLocalizeComplete() { Localizer.OnLocalizationComplete?.Invoke(); } public static void AddText(string key, string text) { if (!CachedTranslations.TryGetValue("English", out Dictionary value)) { value = new Dictionary(StringComparer.Ordinal); CachedTranslations["English"] = value; } value[key] = text; string text2 = "English"; string text3 = key; CustomLocalization.ClearToken(ref text2, ref text3); CustomLocalization.AddTranslation(ref text2, ref text3, text); if (Localization.instance != null) { Localization.instance.AddWord(key, text); } } private static void LoadTranslations() { if (CachedTranslations.Count > 0) { return; } HashSet availableLanguages = GetAvailableLanguages(); Dictionary dictionary = ReadMergedLanguage("English", null); if (dictionary == null || dictionary.Count == 0) { throw new InvalidOperationException("Found no English localizations in mod " + Plugin.Info.Metadata.Name + ". Expected translations/English.json or translations/English.yml."); } CachedTranslations["English"] = dictionary; foreach (string item in availableLanguages) { if (!item.Equals("English", StringComparison.OrdinalIgnoreCase)) { Dictionary dictionary2 = ReadMergedLanguage(item, dictionary); if (dictionary2 != null && dictionary2.Count > 0) { CachedTranslations[item] = dictionary2; } } } ManualLogSource log = STUWard.Plugin.Log; if (log != null) { log.LogInfo((object)("Loaded STUWard localizations: " + string.Join(", ", CachedTranslations.Select>, string>((KeyValuePair> kv) => $"{kv.Key}={kv.Value.Count}")))); } } private static void RegisterWithJotunn() { if (_registeredWithJotunn) { return; } _registeredWithJotunn = true; foreach (KeyValuePair> cachedTranslation in CachedTranslations) { cachedTranslation.Deconstruct(out var key, out var value); string text = key; Dictionary dictionary = new Dictionary(value, StringComparer.Ordinal); CustomLocalization.AddTranslation(ref text, dictionary); } ManualLogSource log = STUWard.Plugin.Log; if (log != null) { log.LogInfo((object)("Registered STUWard localizations with Jotunn: " + string.Join(", ", CachedTranslations.Keys))); } } private static void HookJotunn() { if (!_hookedJotunn) { LocalizationManager.OnLocalizationAdded += ReloadCurrentLanguageIfAvailable; _hookedJotunn = true; } } private static void ApplyCurrentLanguage(Localization localization) { string selectedLanguage = localization.GetSelectedLanguage(); Dictionary translationsForLanguage = GetTranslationsForLanguage(selectedLanguage); foreach (var (text3, text4) in translationsForLanguage) { localization.AddWord(text3, text4); } if (!string.Equals(_lastLoggedAppliedLanguage, selectedLanguage, StringComparison.Ordinal) || _lastLoggedAppliedCount != translationsForLanguage.Count) { _lastLoggedAppliedLanguage = selectedLanguage; _lastLoggedAppliedCount = translationsForLanguage.Count; ManualLogSource log = STUWard.Plugin.Log; if (log != null) { log.LogInfo((object)$"Applied STUWard localization for language '{selectedLanguage}' with {translationsForLanguage.Count} entries."); } } } private static Dictionary GetTranslationsForLanguage(string language) { if (CachedTranslations.TryGetValue(language, out Dictionary value)) { return value; } return CachedTranslations["English"]; } private static HashSet GetAvailableLanguages() { HashSet hashSet = new HashSet(StringComparer.OrdinalIgnoreCase) { "English" }; string[] manifestResourceNames = typeof(Localizer).Assembly.GetManifestResourceNames(); foreach (string text in manifestResourceNames) { string[] fileExtensions = FileExtensions; foreach (string text2 in fileExtensions) { _ = "translations." + text2; if (!text.Contains(".translations.", StringComparison.OrdinalIgnoreCase) || !text.EndsWith(text2, StringComparison.OrdinalIgnoreCase)) { continue; } int num = text.LastIndexOf(".translations.", StringComparison.OrdinalIgnoreCase); if (num >= 0) { int num2 = num + ".translations.".Length; int num3 = text.Length - num2 - text2.Length; if (num3 > 0) { hashSet.Add(text.Substring(num2, num3)); } } } } foreach (string item in from path in Directory.GetFiles(Paths.PluginPath, Plugin.Info.Metadata.Name + ".*", SearchOption.AllDirectories) where FileExtensions.Contains(Path.GetExtension(path), StringComparer.OrdinalIgnoreCase) select path) { string[] array = Path.GetFileNameWithoutExtension(item).Split('.'); if (array.Length >= 2 && !string.IsNullOrWhiteSpace(array[1])) { hashSet.Add(array[1]); } } return hashSet; } private static Dictionary? ReadMergedLanguage(string language, IReadOnlyDictionary? englishFallback) { Dictionary dictionary = new Dictionary(StringComparer.Ordinal); if (englishFallback != null) { MergeInto(dictionary, englishFallback); } Dictionary dictionary2 = ReadEmbeddedLanguage(language); if (dictionary2 != null) { MergeInto(dictionary, dictionary2); } Dictionary dictionary3 = ReadExternalLanguage(language); if (dictionary3 != null) { MergeInto(dictionary, dictionary3); } if (dictionary.Count != 0) { return dictionary; } return null; } private static Dictionary? ReadEmbeddedLanguage(string language) { string[] fileExtensions = FileExtensions; foreach (string text in fileExtensions) { byte[] array = ReadEmbeddedFileBytes("translations." + language + text, typeof(Localizer).Assembly); if (array != null) { return DeserializeTranslations(Encoding.UTF8.GetString(array)); } } return null; } private static Dictionary? ReadExternalLanguage(string language) { string text = FindExternalLanguageFile(language); if (text != null) { return DeserializeTranslations(File.ReadAllText(text, Encoding.UTF8)); } return null; } private static string? FindExternalLanguageFile(string language) { string[] fileExtensions = FileExtensions; foreach (string text in fileExtensions) { string searchPattern = Plugin.Info.Metadata.Name + "." + language + text; string text2 = Directory.GetFiles(Paths.PluginPath, searchPattern, SearchOption.AllDirectories).FirstOrDefault(); if (!string.IsNullOrWhiteSpace(text2)) { return text2; } } return null; } private static Dictionary DeserializeTranslations(string rawText) { return Deserializer.Deserialize>(rawText) ?? new Dictionary(StringComparer.Ordinal); } private static void MergeInto(IDictionary target, IReadOnlyDictionary source) { foreach (KeyValuePair item in source) { item.Deconstruct(out var key, out var value); string key2 = key; string value2 = value; target[key2] = value2; } } 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 name) => name.EndsWith(resourceFileName2, StringComparison.OrdinalIgnoreCase)); if (text == null) { return 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 STUWard { [BepInPlugin("sighsorry.STUWard", "STUWard", "1.1.9")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { internal enum Toggle { Off, On } internal enum PickupBlockRule { BlockAllExceptWhitelist, AllowAllExceptBlacklist } internal enum HostileCreatureStructureProtectionMode { Off, UnattendedOnly, Always } internal enum DiagnosticLogMode { Off, Failures, Verbose } internal const string ModName = "STUWard"; internal const string ModVersion = "1.1.9"; internal const string Author = "sighsorry"; internal const string ModGuid = "sighsorry.STUWard"; internal static readonly ConfigSync ConfigSync = new ConfigSync("sighsorry.STUWard") { DisplayName = "STUWard", CurrentVersion = "1.1.9", MinimumRequiredVersion = "1.1.9" }; private Harmony _harmony; internal static ManualLogSource Log = null; internal static Plugin Instance = null; internal static WardGuiController WardGui = null; internal static ConfigEntry ServerConfigLocked = null; internal static ConfigEntry MaxWardsPerSteamId = null; internal static ConfigEntry MaxWardRadius = null; internal static ConfigEntry PickupBlockMode = null; internal static ConfigEntry HostileCreatureStructureProtection = null; internal static ConfigEntry UnattendedWardTrustedPlayerRangeBuffer = null; internal static ConfigEntry UnattendedWardTrustedPresenceGraceSeconds = null; internal static ConfigEntry UnattendedWardPresenceRefreshInterval = null; internal static ConfigEntry DisableVanillaGuardStoneRecipe = null; internal static ConfigEntry StuWardRecipe = null; internal static ConfigEntry WardSettingsShortcut = null; internal static ConfigEntry WardMinimapPinScale = null; internal static ConfigEntry WardMinimapActiveRanges = null; internal static ConfigEntry WardDiagnosticLogging = null; private void Awake() { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; WardPluginBootstrap.InitializeCore(); bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet; ((BaseUnityPlugin)this).Config.SaveOnConfigSet = false; try { WardPluginConfigBindings.BindAll(); WardPluginBootstrap.InitializeFeatures(); _harmony = new Harmony("sighsorry.STUWard"); WardPatchRegistry.ApplyAll(_harmony); WardGui = CreateOrReuseWardGuiController(); ((BaseUnityPlugin)this).Config.Save(); } finally { ((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet; } } private void Update() { WardPluginBootstrap.Update(); } private void OnDestroy() { WardPluginBootstrap.Shutdown(); Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } ((BaseUnityPlugin)this).Config.Save(); } internal static bool IsBlockedItem(string prefabName) { return WardItemPrefabPolicy.IsBlockedItem(prefabName); } internal static bool HasBlockedItems() { return WardItemPrefabPolicy.HasBlockedItems(); } internal static bool IsWardSettingsShortcutDown() { //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_0014: 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_0025: Unknown result type (might be due to invalid IL or missing references) if (WardSettingsShortcut != null) { KeyboardShortcut value = WardSettingsShortcut.Value; if ((int)((KeyboardShortcut)(ref value)).MainKey != 0) { value = WardSettingsShortcut.Value; return ((KeyboardShortcut)(ref value)).IsDown(); } } return false; } internal static bool HasWardSettingsShortcutBinding() { //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_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Invalid comparison between Unknown and I4 if (WardSettingsShortcut != null) { KeyboardShortcut value = WardSettingsShortcut.Value; return (int)((KeyboardShortcut)(ref value)).MainKey > 0; } return false; } internal static string GetWardSettingsShortcutLabel() { //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_0014: 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_00a0: 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_00a7: 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: Invalid comparison between Unknown and I4 //IL_00e2: 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) if (WardSettingsShortcut != null) { KeyboardShortcut value = WardSettingsShortcut.Value; if ((int)((KeyboardShortcut)(ref value)).MainKey != 0) { KeyboardShortcut value2 = WardSettingsShortcut.Value; List list = new List(); AddModifierLabel(list, ((KeyboardShortcut)(ref value2)).Modifiers, (KeyCode)306, (KeyCode)305, "Ctrl"); AddModifierLabel(list, ((KeyboardShortcut)(ref value2)).Modifiers, (KeyCode)308, (KeyCode)307, "Alt"); AddModifierLabel(list, ((KeyboardShortcut)(ref value2)).Modifiers, (KeyCode)304, (KeyCode)303, "Shift"); foreach (KeyCode modifier in ((KeyboardShortcut)(ref value2)).Modifiers) { if (modifier - 303 > 5) { list.Add(GetKeyLabel(modifier)); } } list.Add(GetKeyLabel(((KeyboardShortcut)(ref value2)).MainKey)); return string.Join("+", list); } } return WardLocalization.Localize("$stuw_shortcut_unbound", "Unbound"); } private static void AddModifierLabel(List parts, IEnumerable modifiers, KeyCode left, KeyCode right, string label) { //IL_000a: 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_0011: 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) foreach (KeyCode modifier in modifiers) { if (modifier == left || modifier == right) { parts.Add(label); break; } } } 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 switch (keyCode - 48) { default: switch (keyCode - 303) { case 4: case 5: return "Alt"; case 2: case 3: return "Ctrl"; case 0: case 1: return "Shift"; default: return ((object)(KeyCode)(ref keyCode)).ToString(); } case 0: return "0"; case 1: return "1"; case 2: return "2"; case 3: return "3"; case 4: return "4"; case 5: return "5"; case 6: return "6"; case 7: return "7"; case 8: return "8"; case 9: return "9"; } } internal static ConfigEntry BindConfigEntry(string group, string name, T value, string description, bool synchronizedSetting = true) { return Instance.BindConfig(group, name, value, description, synchronizedSetting); } internal static bool ShouldLogWardDiagnosticFailures() { if (WardDiagnosticLogging != null) { return WardDiagnosticLogging.Value != DiagnosticLogMode.Off; } return false; } internal static bool ShouldLogWardDiagnosticVerbose() { if (WardDiagnosticLogging != null) { return WardDiagnosticLogging.Value == DiagnosticLogMode.Verbose; } return false; } internal static void LogWardDiagnosticFailure(string context, string message) { if (ShouldLogWardDiagnosticFailures() && Log != null) { Log.LogWarning((object)("[WardDiag:" + context + "] " + message)); } } internal static void LogWardDiagnosticVerbose(string context, string message) { if (ShouldLogWardDiagnosticVerbose() && Log != null) { Log.LogInfo((object)("[WardDiag:" + context + "] " + message)); } } private static WardGuiController CreateOrReuseWardGuiController() { //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_0023: Expected O, but got Unknown if ((Object)(object)WardGuiController.Instance != (Object)null) { return WardGuiController.Instance; } GameObject val = new GameObject("STUWard.WardGui"); Object.DontDestroyOnLoad((Object)val); return val.AddComponent(); } private ConfigEntry BindConfig(string group, string name, T value, string description, bool synchronizedSetting = true) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown string text = (synchronizedSetting ? "Synced with server." : "Not synced with server."); string text2 = (string.IsNullOrWhiteSpace(description) ? text : (description.TrimEnd() + " " + text)); ConfigEntry val = ((BaseUnityPlugin)this).Config.Bind(group, name, value, new ConfigDescription(text2, (AcceptableValueBase)null, Array.Empty())); if (synchronizedSetting) { ConfigSync.AddConfigEntry(val).SynchronizedConfig = true; } return val; } } internal static class WardPluginBootstrap { internal static void InitializeCore() { Localizer.Load(); } internal static void InitializeFeatures() { WardGuiLayoutSettings.Bind(); ManagedWardConfigFileService.Initialize(); WardItemPrefabPolicy.Initialize(); WardOwnership.Initialize(); PrefabManager.OnVanillaPrefabsAvailable += RegisterStuWardPiece; RegisterStuWardPiece(); } internal static void Update() { ManagedWardRuntimeLifecycle.Update(); } internal static void Shutdown() { PrefabManager.OnVanillaPrefabsAvailable -= RegisterStuWardPiece; WardPluginConfigBindings.UnbindAll(); WardItemPrefabPolicy.Shutdown(); ManagedWardConfigFileService.Shutdown(); GuildsCompat.TryShutdownHooks(); Localizer.Unload(); } internal static void ApplyRecipeSettings() { StuWardPrefab.ApplyRecipeSettings(); } private static void RegisterStuWardPiece() { StuWardPrefab.Register(); ApplyRecipeSettings(); } } internal static class WardPluginConfigBindings { private static bool _handlersBound; internal static void BindAll() { UnbindAll(); BindGeneral(); BindClient(); BindDebug(); BindHandlers(); } internal static void UnbindAll() { if (_handlersBound) { UnbindHandler(Plugin.MaxWardRadius, HandleMaxWardRadiusChanged); UnbindHandler(Plugin.MaxWardsPerSteamId, HandleMaxWardLimitChanged); UnbindHandler(Plugin.HostileCreatureStructureProtection, HandleWardPresenceConfigChanged); UnbindHandler(Plugin.UnattendedWardTrustedPlayerRangeBuffer, HandleWardPresenceConfigChanged); UnbindHandler(Plugin.UnattendedWardTrustedPresenceGraceSeconds, HandleWardPresenceConfigChanged); UnbindHandler(Plugin.UnattendedWardPresenceRefreshInterval, HandleWardPresenceConfigChanged); UnbindHandler(Plugin.DisableVanillaGuardStoneRecipe, HandleRecipeSettingsChanged); UnbindHandler(Plugin.StuWardRecipe, HandleRecipeSettingsChanged); UnbindHandler(Plugin.WardMinimapPinScale, HandleLocalWardPinConfigChanged); UnbindHandler(Plugin.WardMinimapActiveRanges, HandleLocalWardPinConfigChanged); _handlersBound = false; } } private static void BindGeneral() { Plugin.ServerConfigLocked = Plugin.BindConfigEntry("1 - General", "Lock Configuration", Plugin.Toggle.On, "If on, the configuration is locked and can be changed by server admins only."); Plugin.ConfigSync.AddLockingConfigEntry(Plugin.ServerConfigLocked); Plugin.MaxWardsPerSteamId = Plugin.BindConfigEntry("1 - General", "Max Wards Per Steam ID", 3, "Maximum number of managed Wards allowed per Steam/platform account. Set to -1 for unlimited."); Plugin.MaxWardRadius = Plugin.BindConfigEntry("1 - General", "Max Ward Radius", 32f, "Maximum configurable Ward radius. Valid range: 8 to 64."); Plugin.PickupBlockMode = Plugin.BindConfigEntry("1 - General", "Pickup Block Mode", Plugin.PickupBlockRule.BlockAllExceptWhitelist, "Pickup rule inside a foreign enabled ward. BlockAllExceptWhitelist blocks every item pickup except pickup_whitelist. AllowAllExceptBlacklist allows item pickup except pickup_blacklist."); Plugin.HostileCreatureStructureProtection = Plugin.BindConfigEntry("2 - Unattended Protection", "Hostile Creature Structure Protection Mode", Plugin.HostileCreatureStructureProtectionMode.UnattendedOnly, "Controls whether building pieces inside an enabled ward ignore damage from MonsterAI-controlled attackers. Off disables this extra protection. UnattendedOnly protects while no trusted player is nearby. Always protects regardless of trusted player presence."); Plugin.UnattendedWardTrustedPlayerRangeBuffer = Plugin.BindConfigEntry("2 - Unattended Protection", "Unattended Ward Trusted Player Range Buffer", 16f, "Additional distance beyond the ward radius used when checking for nearby trusted players before hostile-creature structure protection turns off."); Plugin.UnattendedWardTrustedPresenceGraceSeconds = Plugin.BindConfigEntry("2 - Unattended Protection", "Unattended Ward Trusted Presence Grace Seconds", 10f, "How long a ward keeps counting as attended after the last nearby trusted player leaves."); Plugin.UnattendedWardPresenceRefreshInterval = Plugin.BindConfigEntry("2 - Unattended Protection", "Unattended Ward Presence Refresh Interval", 1f, "How often nearby trusted-player attendance is recalculated for unattended hostile-creature structure protection."); Plugin.DisableVanillaGuardStoneRecipe = Plugin.BindConfigEntry("1 - General", "Disable Vanilla Guard Stone Recipe", Plugin.Toggle.On, "If on, the vanilla guard_stone build recipe is removed from the Hammer piece table while STUWard remains available."); Plugin.StuWardRecipe = Plugin.BindConfigEntry("1 - General", "STUWard Recipe", "GreydwarfEye:1,BoneFragments:3,Flint:5,Wood:7", "STUWard recipe override. Format: ItemPrefab:Amount[:Recover], ..."); } private static void BindClient() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) Plugin.WardSettingsShortcut = Plugin.BindConfigEntry("3 - Client", "Ward Settings Shortcut", new KeyboardShortcut((KeyCode)101, (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }), "Shortcut used to open the ward settings UI while looking at your ward. Example values: LeftAlt + E, F7", synchronizedSetting: false); Plugin.WardMinimapPinScale = Plugin.BindConfigEntry("3 - Client", "Ward Minimap Pin Scale", 1, "0 disables ward icon pins. 1 is the default icon size. 100 means x100 icon size.", synchronizedSetting: false); Plugin.WardMinimapActiveRanges = Plugin.BindConfigEntry("3 - Client", "Ward Minimap Active Ranges", Plugin.Toggle.On, "If on, enabled managed wards also show their active radius on the minimap and map.", synchronizedSetting: false); } private static void BindDebug() { Plugin.WardDiagnosticLogging = Plugin.BindConfigEntry("4 - Debug", "Ward Diagnostic Logging", Plugin.DiagnosticLogMode.Off, "Local-only scalar diagnostic logging for ward ownership/toggle flows. Use Failures for rejection paths only, or Verbose for request and state tracing. Enable separately on each client/server instance you want logs from.", synchronizedSetting: false); } private static void BindHandlers() { BindHandler(Plugin.MaxWardRadius, HandleMaxWardRadiusChanged); BindHandler(Plugin.MaxWardsPerSteamId, HandleMaxWardLimitChanged); BindHandler(Plugin.HostileCreatureStructureProtection, HandleWardPresenceConfigChanged); BindHandler(Plugin.UnattendedWardTrustedPlayerRangeBuffer, HandleWardPresenceConfigChanged); BindHandler(Plugin.UnattendedWardTrustedPresenceGraceSeconds, HandleWardPresenceConfigChanged); BindHandler(Plugin.UnattendedWardPresenceRefreshInterval, HandleWardPresenceConfigChanged); BindHandler(Plugin.DisableVanillaGuardStoneRecipe, HandleRecipeSettingsChanged); BindHandler(Plugin.StuWardRecipe, HandleRecipeSettingsChanged); BindHandler(Plugin.WardMinimapPinScale, HandleLocalWardPinConfigChanged); BindHandler(Plugin.WardMinimapActiveRanges, HandleLocalWardPinConfigChanged); _handlersBound = true; } private static void HandleMaxWardRadiusChanged(object? _, EventArgs __) { WardSettings.HandleMaxRadiusChanged(); } private static void HandleMaxWardLimitChanged(object? _, EventArgs __) { WardOwnership.HandleWardLimitPolicyChanged(); } private static void HandleWardPresenceConfigChanged(object? _, EventArgs __) { ManagedWardRuntimeInvalidationService.PublishPresencePolicyChanged("ward presence config changed"); } private static void HandleRecipeSettingsChanged(object? _, EventArgs __) { WardPluginBootstrap.ApplyRecipeSettings(); } private static void HandleLocalWardPinConfigChanged(object? _, EventArgs __) { WardMinimapPinsManager.HandleLocalConfigChanged(); } private static void BindHandler(ConfigEntry? entry, EventHandler handler) { if (entry != null) { entry.SettingChanged += handler; } } private static void UnbindHandler(ConfigEntry? entry, EventHandler handler) { if (entry != null) { entry.SettingChanged -= handler; } } } internal readonly struct ManagedWardRef { internal PrivateArea? Area { get; } internal ZNetView? NView { get; } internal ZDO? Zdo { get; } internal StuWardArea? Component { get; } internal bool HasArea => (Object)(object)Area != (Object)null; internal bool HasManagedComponent => (Object)(object)Component != (Object)null; internal bool IsManagedZdo => WardOwnership.IsManagedWardZdo(Zdo); internal bool IsManaged { get { if (!HasManagedComponent) { return IsManagedZdo; } return true; } } internal bool IsPlacementGhost { get { if ((Object)(object)Area != (Object)null) { return Player.IsPlacementGhost(((Component)Area).gameObject); } return false; } } internal bool HasValidNetworkIdentity { get { if ((Object)(object)NView != (Object)null && NView.IsValid()) { return Zdo != null; } return false; } } internal bool IsOwner { get { if ((Object)(object)NView != (Object)null && NView.IsValid()) { return NView.IsOwner(); } return false; } } internal long CreatorPlayerId { get { ZDO? zdo = Zdo; if (zdo == null) { return 0L; } return zdo.GetLong(ZDOVars.s_creator, 0L); } } private ManagedWardRef(PrivateArea? area, ZNetView? nview, ZDO? zdo, StuWardArea? component) { Area = area; NView = nview; Zdo = zdo; Component = component; } internal static ManagedWardRef FromArea(PrivateArea? area) { return FromArea(area, null); } internal static ManagedWardRef FromArea(PrivateArea? area, ZDO? knownZdo) { ZNetView nView = WardPrivateAreaSafeAccess.GetNView(area); ZDO zdo = ((knownZdo != null && knownZdo.IsValid()) ? knownZdo : WardPrivateAreaSafeAccess.GetZdo(nView)); return new ManagedWardRef(area, nView, zdo, ((Object)(object)area != (Object)null) ? ((Component)area).GetComponent() : null); } internal ManagedWardRef EnsureManagedComponent(out bool added) { added = false; if ((Object)(object)Area == (Object)null || HasManagedComponent || !IsManagedZdo || IsPlacementGhost) { return this; } ((Component)Area).gameObject.AddComponent(); added = true; return FromArea(Area, Zdo); } } internal static class WardPatchRegistry { internal static void ApplyAll(Harmony harmony) { List list = new List(); PatchWardCore(harmony, list); PatchInteractions(harmony, list); PatchBuildAndDamage(harmony, list); PatchItemAndCombat(harmony); PatchCompat(harmony); if (list.Count == 0) { return; } string text = "Failed to apply required patches: " + string.Join(", ", list); Plugin.Log.LogError((object)text); throw new InvalidOperationException(text); } private static void PatchWardCore(Harmony harmony, ICollection failedRequiredPatches) { PatchRequired(harmony, typeof(PrivateAreaAwakePatch), failedRequiredPatches); PatchRequired(harmony, typeof(PrivateAreaOnDestroyPatch), failedRequiredPatches); PatchRequired(harmony, typeof(PrivateAreaUpdateStatusPatch), failedRequiredPatches); PatchRequired(harmony, typeof(PrivateAreaSetupPatch), failedRequiredPatches); PatchRequired(harmony, typeof(ZNetSceneCreateObjectManagedWardPatch), failedRequiredPatches); PatchOptional(harmony, typeof(PrivateAreaShowAreaMarkerPatch)); PatchOptional(harmony, typeof(PrivateAreaGetHoverTextPatch)); PatchOptional(harmony, typeof(PrivateAreaHideMarkerPatch)); PatchOptional(harmony, typeof(PrivateAreaHaveLocalAccessManagedPatch)); PatchOptional(harmony, typeof(PrivateAreaCheckAccessManagedPatch)); PatchOptional(harmony, typeof(PrivateAreaInteractAdminDebugPatch)); PatchRequired(harmony, typeof(PrivateAreaRpcTogglePermittedManagedPatch), failedRequiredPatches); PatchRequired(harmony, typeof(PrivateAreaRpcToggleEnabledAdminDebugPatch), failedRequiredPatches); PatchOptional(harmony, typeof(PrivateAreaRpcFlashShieldVolumePatch)); PatchOptional(harmony, typeof(PrivateAreaAddPermittedSnapshotPatch)); PatchOptional(harmony, typeof(PrivateAreaRemovePermittedSnapshotPatch)); PatchOptional(harmony, typeof(PrivateAreaSetEnabledWardMinimapVisibilityPatch)); PatchOptional(harmony, typeof(CircleProjectorCreateSegmentsPatch)); PatchOptional(harmony, typeof(DoorRpcUseDoorPatch)); PatchOptional(harmony, typeof(ZNetAwakeWardOwnershipPatch)); PatchOptional(harmony, typeof(ZNetRpcPeerInfoWardOwnershipPatch)); PatchOptional(harmony, typeof(ZNetRpcCharacterIdWardOwnershipPatch)); PatchOptional(harmony, typeof(ZNetDisconnectWardOwnershipPatch)); PatchOptional(harmony, typeof(PlayerStartWardOwnershipPatch)); PatchOptional(harmony, typeof(PlayerOnDeathWardUiPatch)); PatchOptional(harmony, typeof(PlayerOnRespawnWardUiPatch)); PatchOptional(harmony, typeof(PlayerUpdateWardAdminDebugPatch)); PatchOptional(harmony, typeof(MinimapSetMapModeWardPinsPatch)); PatchOptional(harmony, typeof(PlayerUpdateWardPinsPatch)); PatchOptional(harmony, typeof(ObjectDBAwakePatch)); PatchOptional(harmony, typeof(ObjectDBCopyOtherDbPatch)); } private static void PatchInteractions(Harmony harmony, ICollection failedRequiredPatches) { PatchRequired(harmony, typeof(DirectInteractionPatches), failedRequiredPatches); PatchOptional(harmony, typeof(ContainerCheckAccessManagedPatch)); PatchRequired(harmony, typeof(UseItemInteractionPatches), failedRequiredPatches); PatchOptional(harmony, typeof(StationUsePatches)); PatchOptional(harmony, typeof(ProcessingInteractionPatches)); PatchOptional(harmony, typeof(TeleportWorldTeleportPatch)); PatchOptional(harmony, typeof(TeleportWorldTriggerPatch)); PatchRequired(harmony, typeof(ItemDropPickupPatch), failedRequiredPatches); PatchRequired(harmony, typeof(HumanoidPickupPatch), failedRequiredPatches); } private static void PatchBuildAndDamage(Harmony harmony, ICollection failedRequiredPatches) { PatchRequired(harmony, typeof(PlayerTryPlacePiecePatch), failedRequiredPatches); PatchOptional(harmony, typeof(PlayerSetupPlacementGhostPatch)); PatchOptional(harmony, typeof(PlayerUpdatePlacementGhostPatch)); PatchRequired(harmony, typeof(PlayerPlacePiecePatch), failedRequiredPatches); PatchRequired(harmony, typeof(PlayerCheckCanRemovePiecePatch), failedRequiredPatches); PatchRequired(harmony, typeof(PlayerRemovePiecePatch), failedRequiredPatches); PatchOptional(harmony, typeof(PlayerRepairPatch)); PatchRequired(harmony, typeof(ZNetSceneDestroyPatch), failedRequiredPatches); PatchOptional(harmony, typeof(AttackSpawnOnHitTerrainPatch)); PatchOptional(harmony, typeof(TerrainOpAwakePatch)); PatchRequired(harmony, typeof(WearNTearDamagePatch), failedRequiredPatches); PatchRequired(harmony, typeof(WearNTearRpcDamagePatch), failedRequiredPatches); PatchRequired(harmony, typeof(WearNTearRemovePatch), failedRequiredPatches); PatchRequired(harmony, typeof(WearNTearRpcRemovePatch), failedRequiredPatches); PatchRequired(harmony, typeof(DestructibleDamagePatch), failedRequiredPatches); PatchRequired(harmony, typeof(DestructibleRpcDamagePatch), failedRequiredPatches); PatchRequired(harmony, typeof(TreeBaseDamagePatch), failedRequiredPatches); PatchRequired(harmony, typeof(TreeBaseRpcDamagePatch), failedRequiredPatches); } private static void PatchItemAndCombat(Harmony harmony) { PatchOptional(harmony, typeof(PlayerUseHotbarItemPatch)); PatchOptional(harmony, typeof(HumanoidUseItemPatch)); PatchOptional(harmony, typeof(HumanoidUpdateEquipmentPatch)); PatchOptional(harmony, typeof(HumanoidEquipItemPatch)); PatchOptional(harmony, typeof(HumanoidStartAttackPatch)); PatchOptional(harmony, typeof(AttackStartBlockedItemTargetPatch)); PatchOptional(harmony, typeof(InventoryGuiOnRightClickItemPatch)); PatchOptional(harmony, typeof(TameableCollectorCollectorItemPatch)); PatchOptional(harmony, typeof(AzuCraftyBoxesNearbyContainersPatch)); PatchOptional(harmony, typeof(FeastRpcTryEatPatch)); PatchOptional(harmony, typeof(PlayerAutoPickupPatch)); PatchOptional(harmony, typeof(TerminalAwakeWardReportCommandPatch)); PatchOptional(harmony, typeof(TerminalTryRunCommandWardReportPatch)); } private static void PatchCompat(Harmony harmony) { Harmony harmony2 = harmony; PatchOptionalCompat("GuildsCompat", delegate { GuildsCompat.TryPatch(harmony2); }); PatchOptionalCompat("TargetPortalCompat", delegate { TargetPortalCompat.TryPatch(harmony2); }); } private static void PatchRequired(Harmony harmony, Type patchType, ICollection failedRequiredPatches) { try { harmony.CreateClassProcessor(patchType).Patch(); } catch (Exception ex) { failedRequiredPatches.Add(patchType.Name); Plugin.Log.LogError((object)("Failed to patch required " + patchType.Name + ": " + ex.GetType().Name + ": " + ex.Message)); } } private static void PatchOptional(Harmony harmony, Type patchType) { try { harmony.CreateClassProcessor(patchType).Patch(); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Failed to patch optional " + patchType.Name + ": " + ex.GetType().Name + ": " + ex.Message)); } } private static void PatchOptionalCompat(string name, Action patchAction) { try { patchAction(); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Failed to patch " + name + ": " + ex.GetType().Name + ": " + ex.Message)); } } } [DisallowMultipleComponent] internal sealed class StuWardArea : MonoBehaviour { internal const string PrefabName = "piece_stuward"; internal const string BasePrefabName = "guard_stone"; internal const string DisplayName = "$stuw_piece_name"; internal const string Description = "$stuw_piece_desc"; internal static bool IsManaged(PrivateArea? area) { if ((Object)(object)area != (Object)null) { return (Object)(object)((Component)area).GetComponent() != (Object)null; } return false; } } internal static class ManagedWardIdentity { internal static bool IsManaged(PrivateArea? area) { bool matchedByComponent; bool matchedByZdo; return TryResolve(ManagedWardRef.FromArea(area), repairComponent: false, out matchedByComponent, out matchedByZdo); } internal static bool EnsureManagedComponent(PrivateArea? area) { return EnsureManagedComponent(ManagedWardRef.FromArea(area)); } internal static bool EnsureManagedComponent(PrivateArea? area, ZDO? zdo) { return EnsureManagedComponent(ManagedWardRef.FromArea(area, zdo)); } internal static bool EnsureManagedComponent(ManagedWardRef ward) { bool matchedByComponent; bool matchedByZdo; return TryResolve(ward, repairComponent: true, out matchedByComponent, out matchedByZdo) && matchedByComponent; } internal static bool TryResolve(PrivateArea? area, ZDO? zdo, bool repairComponent, out bool matchedByComponent, out bool matchedByZdo) { return TryResolve(ManagedWardRef.FromArea(area, zdo), repairComponent, out matchedByComponent, out matchedByZdo); } internal static bool TryResolve(ManagedWardRef ward, bool repairComponent, out bool matchedByComponent, out bool matchedByZdo) { matchedByComponent = ward.HasManagedComponent; matchedByZdo = ward.IsManagedZdo; if (!ward.HasArea) { return matchedByZdo; } if ((!matchedByComponent & matchedByZdo) && repairComponent) { bool added; ManagedWardRef managedWardRef = ward.EnsureManagedComponent(out added); matchedByComponent = managedWardRef.HasManagedComponent; if (added) { Plugin.LogWardDiagnosticVerbose("Placement.Identity", "Restored missing StuWardArea component from managed ward ZDO identity. " + WardDiagnosticInfo.DescribeWard(managedWardRef.Area)); } } return matchedByComponent | matchedByZdo; } } internal sealed class StuWardPlacedHook : MonoBehaviour, IPlaced { public void OnPlaced() { PrivateArea component = ((Component)this).GetComponent(); ManagedWardRef ward = ManagedWardRef.FromArea(component); if (ManagedWardIdentity.EnsureManagedComponent(ward)) { WardOwnership.TryStampLocalManagedWardOwnerAccount(ward); WardOwnership.NotifyServerManagedWardPlaced(ward); ManagedWardMapStateService.NotifyLiveWardMutation(component, ManagedWardMapMutationKind.IndexAndPins, "local managed ward placed"); Plugin.LogWardDiagnosticVerbose("Placement.OnPlaced", "IPlaced.OnPlaced hit for managed ward. " + WardDiagnosticInfo.DescribeWard(component)); } } } internal static class StuWardPrefab { private static bool _registered; private static GameObject? _stuWardPrefab; private static GameObject? _vanillaGuardStonePrefab; private static int _vanillaGuardStoneIndex = -1; private static Requirement[]? _defaultStuWardRequirements; private static string? _lastLoggedPieceIconState; internal static void Register() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0047: 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: Expected O, but got Unknown //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Expected O, but got Unknown if (_registered || PieceManager.Instance.GetPiece("piece_stuward") != null) { _registered = true; } else { if ((Object)(object)PrefabManager.Instance.GetPrefab("guard_stone") == (Object)null) { return; } PieceConfig val = new PieceConfig { PieceTable = "Hammer", Name = "$stuw_piece_name", Description = "$stuw_piece_desc" }; CustomPiece val2 = new CustomPiece("piece_stuward", "guard_stone", val); GameObject piecePrefab = val2.PiecePrefab; Piece piece = val2.Piece; PrivateArea val3 = (((Object)(object)piecePrefab != (Object)null) ? piecePrefab.GetComponent() : null); if ((Object)(object)piecePrefab == (Object)null || (Object)(object)piece == (Object)null || (Object)(object)val3 == (Object)null) { Plugin.Log.LogWarning((object)"Failed to create STUWard clone prefab from guard_stone."); return; } if ((Object)(object)piecePrefab.GetComponent() == (Object)null) { piecePrefab.AddComponent(); } if ((Object)(object)piecePrefab.GetComponent() == (Object)null) { piecePrefab.AddComponent(); } piece.m_name = "$stuw_piece_name"; piece.m_description = "$stuw_piece_desc"; piece.m_resources = CloneRequirements(piece.m_resources); val3.m_name = "$stuw_piece_name"; val3.m_radius = 8f; if ((Object)(object)val3.m_areaMarker != (Object)null) { val3.m_areaMarker.m_radius = 8f; } _stuWardPrefab = piecePrefab; _defaultStuWardRequirements = CloneRequirements(piece.m_resources); PieceManager.Instance.AddPiece(val2); _registered = PieceManager.Instance.GetPiece("piece_stuward") != null; if (_registered) { Plugin.Log.LogInfo((object)"Registered STUWard clone piece."); } } } internal static void ApplyRecipeSettings() { ApplyVanillaGuardStoneRecipeSetting(); ApplyStuWardRecipeSetting(); } internal static Sprite? GetPieceIcon() { Piece stuWardPiece = GetStuWardPiece(); if ((Object)(object)stuWardPiece != (Object)null && (Object)(object)stuWardPiece.m_icon != (Object)null) { return LogPieceIconResolution(stuWardPiece.m_icon, "stuWardPrefab piece icon '" + ((Object)stuWardPiece.m_icon).name + "'"); } CustomPiece piece = PieceManager.Instance.GetPiece("piece_stuward"); if ((Object)(object)((piece != null) ? piece.Piece : null) != (Object)null && (Object)(object)piece.Piece.m_icon != (Object)null) { return LogPieceIconResolution(piece.Piece.m_icon, "registered piece icon '" + ((Object)piece.Piece.m_icon).name + "'"); } GameObject val = ((piece != null) ? piece.PiecePrefab : null) ?? PrefabManager.Instance.GetPrefab("piece_stuward") ?? PrefabManager.Instance.GetPrefab("guard_stone"); Sprite val2 = ((!((Object)(object)val != (Object)null)) ? null : val.GetComponent()?.m_icon); if ((Object)(object)val2 != (Object)null) { string text = (((Object)(object)val != (Object)null) ? ((Object)val).name : "null"); return LogPieceIconResolution(val2, "prefab '" + text + "' piece icon '" + ((Object)val2).name + "'"); } return LogMissingPieceIcon(string.Format("stuWardPrefabPresent={0}, registeredPiecePresent={1}, registeredPiecePrefabPresent={2}, fallbackPrefab='{3}'", (Object)(object)_stuWardPrefab != (Object)null, (Object)(object)((piece != null) ? piece.Piece : null) != (Object)null, (Object)(object)((piece != null) ? piece.PiecePrefab : null) != (Object)null, ((val != null) ? ((Object)val).name : null) ?? "null")); } internal static Requirement[] GetCurrentStuWardRequirements() { return CloneRequirements(GetStuWardPiece()?.m_resources); } private static Piece? GetStuWardPiece() { Piece val = (((Object)(object)_stuWardPrefab != (Object)null) ? _stuWardPrefab.GetComponent() : null); if ((Object)(object)val != (Object)null) { return val; } CustomPiece piece = PieceManager.Instance.GetPiece("piece_stuward"); if (piece == null) { return null; } return piece.Piece; } private static Sprite LogPieceIconResolution(Sprite icon, string source) { string text = "resolved:" + source; if (_lastLoggedPieceIconState != text) { _lastLoggedPieceIconState = text; Plugin.LogWardDiagnosticVerbose("WardPins.Icon", "Resolved piece_stuward icon from " + source + "."); } return icon; } private static Sprite? LogMissingPieceIcon(string context) { string text = "missing:" + context; if (_lastLoggedPieceIconState != text) { _lastLoggedPieceIconState = text; Plugin.LogWardDiagnosticFailure("WardPins.Icon", "Failed to resolve piece_stuward icon. " + context); } return null; } internal static void ApplyVanillaGuardStoneRecipeSetting() { PieceTable? hammerPieceTable = GetHammerPieceTable(); List list = hammerPieceTable?.m_pieces; GameObject prefab = PrefabManager.Instance.GetPrefab("guard_stone"); if ((Object)(object)hammerPieceTable == (Object)null || list == null || (Object)(object)prefab == (Object)null) { return; } if (_vanillaGuardStonePrefab == null) { _vanillaGuardStonePrefab = prefab; } List matchingGuardStoneIndexes = GetMatchingGuardStoneIndexes(list, prefab); if (_vanillaGuardStoneIndex < 0 && matchingGuardStoneIndexes.Count > 0) { _vanillaGuardStoneIndex = matchingGuardStoneIndexes[0]; } if (Plugin.DisableVanillaGuardStoneRecipe != null && Plugin.DisableVanillaGuardStoneRecipe.Value == Plugin.Toggle.On) { for (int num = matchingGuardStoneIndexes.Count - 1; num >= 0; num--) { list.RemoveAt(matchingGuardStoneIndexes[num]); } } else if (matchingGuardStoneIndexes.Count == 0 && (Object)(object)_vanillaGuardStonePrefab != (Object)null) { int index = ((_vanillaGuardStoneIndex >= 0) ? Mathf.Clamp(_vanillaGuardStoneIndex, 0, list.Count) : list.Count); list.Insert(index, _vanillaGuardStonePrefab); } Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { localPlayer.UpdateAvailablePiecesList(); } } private static void ApplyStuWardRecipeSetting() { Piece val = (((Object)(object)_stuWardPrefab != (Object)null) ? _stuWardPrefab.GetComponent() : null); if ((Object)(object)val == (Object)null) { return; } string text = Plugin.StuWardRecipe?.Value?.Trim() ?? string.Empty; Requirement[] requirements; if (string.IsNullOrWhiteSpace(text)) { if (_defaultStuWardRequirements != null) { val.m_resources = CloneRequirements(_defaultStuWardRequirements); Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { localPlayer.UpdateAvailablePiecesList(); } } } else if (!TryParseRequirements(text, out requirements)) { Plugin.Log.LogWarning((object)("Invalid STUWard recipe override '" + text + "'. Keeping previous recipe.")); } else { val.m_resources = requirements; Player localPlayer2 = Player.m_localPlayer; if (localPlayer2 != null) { localPlayer2.UpdateAvailablePiecesList(); } } } private static PieceTable? GetHammerPieceTable() { GameObject prefab = PrefabManager.Instance.GetPrefab("Hammer"); return (((Object)(object)prefab != (Object)null) ? prefab.GetComponent() : null)?.m_itemData?.m_shared?.m_buildPieces; } private static List GetMatchingGuardStoneIndexes(List pieces, GameObject guardStonePrefab) { List list = new List(); for (int i = 0; i < pieces.Count; i++) { GameObject val = pieces[i]; if (!((Object)(object)val == (Object)null) && ((Object)(object)val == (Object)(object)guardStonePrefab || ((Object)val).name == "guard_stone")) { list.Add(i); } } return list; } private static Requirement[] CloneRequirements(Requirement[]? source) { //IL_0020: 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: 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_0049: 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_0062: Expected O, but got Unknown if (source == null || source.Length == 0) { return Array.Empty(); } Requirement[] array = (Requirement[])(object)new Requirement[source.Length]; for (int i = 0; i < source.Length; i++) { Requirement val = source[i]; array[i] = new Requirement { m_resItem = val.m_resItem, m_amount = val.m_amount, m_extraAmountOnlyOneIngredient = val.m_extraAmountOnlyOneIngredient, m_amountPerLevel = val.m_amountPerLevel, m_recover = val.m_recover }; } return array; } private static bool TryParseRequirements(string value, out Requirement[] requirements) { //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Expected O, but got Unknown requirements = Array.Empty(); string[] array = value.Split(new char[4] { ',', ';', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); if (array.Length == 0) { return false; } List list = new List(array.Length); string[] array2 = array; for (int i = 0; i < array2.Length; i++) { string[] array3 = array2[i].Split(':'); int num = array3.Length; if ((num < 2 || num > 3) ? true : false) { return false; } string text = array3[0].Trim(); if (string.IsNullOrWhiteSpace(text) || !int.TryParse(array3[1], out var result) || result <= 0) { return false; } GameObject val = ResolveItemPrefab(text); ItemDrop val2 = (((Object)(object)val != (Object)null) ? val.GetComponent() : null); if ((Object)(object)val2 == (Object)null) { Plugin.Log.LogWarning((object)("Unable to resolve STUWard recipe item prefab '" + text + "'.")); return false; } bool result2 = true; if (array3.Length == 3 && !TryParseBool(array3[2], out result2)) { return false; } list.Add(new Requirement { m_resItem = val2, m_amount = result, m_amountPerLevel = 1, m_recover = result2 }); } requirements = list.ToArray(); return true; } private static GameObject? ResolveItemPrefab(string prefabName) { if (string.IsNullOrWhiteSpace(prefabName)) { return null; } ObjectDB instance = ObjectDB.instance; GameObject val = ((instance != null) ? instance.GetItemPrefab(prefabName) : null); if ((Object)(object)val != (Object)null) { return val; } return PrefabManager.Instance.GetPrefab(prefabName); } private static bool TryParseBool(string value, out bool result) { switch (value.Trim().ToLowerInvariant()) { case "1": case "yes": case "on": case "true": result = true; return true; case "0": case "off": case "no": case "false": result = false; return true; default: result = false; return false; } } } [HarmonyPatch(typeof(ObjectDB), "Awake")] internal static class ObjectDBAwakePatch { private static void Postfix() { Localizer.ReloadCurrentLanguageIfAvailable(); StuWardPrefab.ApplyRecipeSettings(); } } [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] internal static class ObjectDBCopyOtherDbPatch { private static void Postfix() { Localizer.ReloadCurrentLanguageIfAvailable(); StuWardPrefab.ApplyRecipeSettings(); } } internal readonly struct CachedWardGuildIdentity { internal bool HasGuild { get; } internal int GuildId { get; } internal string GuildName { get; } internal DateTime ExpiresAtUtc { get; } internal CachedWardGuildIdentity(bool hasGuild, int guildId, string guildName, DateTime expiresAtUtc) { HasGuild = hasGuild; GuildId = guildId; GuildName = guildName; ExpiresAtUtc = expiresAtUtc; } } internal readonly struct CachedPlayerPlatformIdentity { internal bool HasPlatformId { get; } internal string PlatformId { get; } internal DateTime ExpiresAtUtc { get; } internal CachedPlayerPlatformIdentity(bool hasPlatformId, string platformId, DateTime expiresAtUtc) { HasPlatformId = hasPlatformId; PlatformId = platformId; ExpiresAtUtc = expiresAtUtc; } } internal readonly struct WardGuildCharacterIdentity { internal long PlayerId { get; } internal string AccountId { get; } internal string PlayerName { get; } internal bool HasPlayerId => PlayerId != 0; internal bool HasAccountAndName { get { if (!string.IsNullOrWhiteSpace(AccountId)) { return !string.IsNullOrWhiteSpace(PlayerName); } return false; } } internal WardGuildCharacterIdentity(long playerId, string accountId, string playerName) { PlayerId = playerId; AccountId = WardOwnership.NormalizeAccountIdValue(accountId); PlayerName = playerName?.Trim() ?? string.Empty; } } internal static class GuildsCompat { private enum AvailabilityState { Unknown, Available, Unavailable } private sealed class PendingWardGuildProjectionRefreshState { internal readonly Dictionary TargetIdentitiesByPlayerId = new Dictionary(); internal readonly Dictionary TargetIdentitiesByCharacterKey = new Dictionary(StringComparer.Ordinal); internal readonly HashSet AffectedGuildIds = new HashSet(); internal bool PendingFullRefresh; internal bool PendingLiveDisplayRefresh; internal string PendingLiveDisplayReason = string.Empty; internal DateTime FlushAtUtc = DateTime.MinValue; } private const string GuildIdKey = "stuw_guild_id"; private const string GuildNameKey = "stuw_guild_name"; private static readonly TimeSpan GuildLookupCacheDuration = TimeSpan.FromSeconds(30.0); private const string SyncPlayerGuildRpc = "STUWard_SyncPlayerGuild"; private static readonly TimeSpan PendingPlayerGuildSyncLifetime = TimeSpan.FromSeconds(15.0); private static readonly Dictionary ServerSyncedGuildByPlayerId = new Dictionary(); private static readonly Dictionary ServerSyncedGuildByCharacterKey = new Dictionary(StringComparer.Ordinal); private static readonly Dictionary PendingPlayerGuildSyncsBySender = new Dictionary(); private static bool _syncRpcsRegistered; private static bool _localGuildSyncPending = true; private static long _lastSyncedLocalPlayerId; private static int _lastSyncedLocalGuildId = int.MinValue; private static string _lastSyncedLocalGuildName = string.Empty; private const string GuildsPluginGuid = "org.bepinex.plugins.guilds"; private static readonly TimeSpan AvailabilityProbeBackoff = TimeSpan.FromSeconds(2.0); private static readonly Assembly? GuildsAssembly = GetPluginAssembly("org.bepinex.plugins.guilds"); private static readonly Type? ApiType = GuildsAssembly?.GetType("Guilds.API"); private static readonly Type? GuildType = GuildsAssembly?.GetType("Guilds.Guild"); private static readonly Type? GuildGeneralType = GuildsAssembly?.GetType("Guilds.GuildGeneral"); private static readonly Type? PlayerReferenceType = GuildsAssembly?.GetType("Guilds.PlayerReference"); private static readonly Type? GuildJoinedDelegateType = ApiType?.GetNestedType("GuildJoined", BindingFlags.Public | BindingFlags.NonPublic); private static readonly Type? GuildLeftDelegateType = ApiType?.GetNestedType("GuildLeft", BindingFlags.Public | BindingFlags.NonPublic); private static readonly Type? GuildCreatedDelegateType = ApiType?.GetNestedType("GuildCreated", BindingFlags.Public | BindingFlags.NonPublic); private static readonly Type? GuildDeletedDelegateType = ApiType?.GetNestedType("GuildDeleted", BindingFlags.Public | BindingFlags.NonPublic); private static readonly MethodInfo? IsLoadedMethod = ((ApiType != null) ? AccessTools.Method(ApiType, "IsLoaded", (Type[])null, (Type[])null) : null); private static readonly MethodInfo? GetPlayerGuildByPlayerMethod = ((ApiType != null) ? AccessTools.Method(ApiType, "GetPlayerGuild", new Type[1] { typeof(Player) }, (Type[])null) : null); private static readonly MethodInfo? GetPlayerGuildByReferenceMethod = ((ApiType != null && PlayerReferenceType != null) ? AccessTools.Method(ApiType, "GetPlayerGuild", new Type[1] { PlayerReferenceType }, (Type[])null) : null); private static readonly MethodInfo? GetGuildsMethod = ((ApiType != null) ? AccessTools.Method(ApiType, "GetGuilds", Type.EmptyTypes, (Type[])null) : null); private static readonly MethodInfo? GetGuildByIdMethod = ((ApiType != null) ? AccessTools.Method(ApiType, "GetGuild", new Type[1] { typeof(int) }, (Type[])null) : null); private static readonly MethodInfo? PlayerReferenceFromStringMethod = ((PlayerReferenceType != null) ? AccessTools.Method(PlayerReferenceType, "fromString", new Type[1] { typeof(string) }, (Type[])null) : null); private static readonly MethodInfo? RegisterOnGuildJoinedMethod = ((ApiType != null && GuildJoinedDelegateType != null) ? AccessTools.Method(ApiType, "RegisterOnGuildJoined", new Type[1] { GuildJoinedDelegateType }, (Type[])null) : null); private static readonly MethodInfo? RegisterOnGuildLeftMethod = ((ApiType != null && GuildLeftDelegateType != null) ? AccessTools.Method(ApiType, "RegisterOnGuildLeft", new Type[1] { GuildLeftDelegateType }, (Type[])null) : null); private static readonly MethodInfo? RegisterOnGuildCreatedMethod = ((ApiType != null && GuildCreatedDelegateType != null) ? AccessTools.Method(ApiType, "RegisterOnGuildCreated", new Type[1] { GuildCreatedDelegateType }, (Type[])null) : null); private static readonly MethodInfo? RegisterOnGuildDeletedMethod = ((ApiType != null && GuildDeletedDelegateType != null) ? AccessTools.Method(ApiType, "RegisterOnGuildDeleted", new Type[1] { GuildDeletedDelegateType }, (Type[])null) : null); private static readonly MethodInfo? SaveGuildMethod = ((ApiType != null && GuildType != null) ? AccessTools.Method(ApiType, "SaveGuild", new Type[1] { GuildType }, (Type[])null) : null); private static readonly FieldInfo? PlayerInfoUserInfoField = AccessTools.Field(typeof(PlayerInfo), "m_userInfo"); private static readonly FieldInfo? UserInfoIdField = ((PlayerInfoUserInfoField?.FieldType != null) ? AccessTools.Field(PlayerInfoUserInfoField.FieldType, "m_id") : null); private static readonly FieldInfo? GuildNameField = ((GuildType != null) ? AccessTools.Field(GuildType, "Name") : null); private static readonly FieldInfo? GuildGeneralField = ((GuildType != null) ? AccessTools.Field(GuildType, "General") : null); private static readonly FieldInfo? GuildGeneralIdField = ((GuildGeneralType != null) ? AccessTools.Field(GuildGeneralType, "id") : null); private static readonly FieldInfo? GuildMembersField = ((GuildType != null) ? AccessTools.Field(GuildType, "Members") : null); private static readonly FieldInfo? PlayerReferenceIdField = ((PlayerReferenceType != null) ? AccessTools.Field(PlayerReferenceType, "id") : null); private static readonly FieldInfo? PlayerReferenceNameField = ((PlayerReferenceType != null) ? (AccessTools.Field(PlayerReferenceType, "name") ?? AccessTools.Field(PlayerReferenceType, "Name")) : null); private static readonly bool HasGuildsApiSurface = ApiType != null && IsLoadedMethod != null; private static AvailabilityState _availabilityState = AvailabilityState.Unknown; private static DateTime _nextAvailabilityProbeUtc = DateTime.MinValue; private static readonly TimeSpan PendingWardGuildProjectionRefreshDebounce = TimeSpan.FromMilliseconds(250.0); private static readonly PendingWardGuildProjectionRefreshState PendingWardGuildProjectionRefresh = new PendingWardGuildProjectionRefreshState(); private static readonly Dictionary PlayerGuildCache = new Dictionary(); private static readonly Dictionary PlayerPlatformIdCache = new Dictionary(); private static bool _guildHooksRegistered; private static bool _guildHooksActive; private static bool _saveGuildPatched; internal static void ResetRuntimeState() { PlayerGuildCache.Clear(); PlayerPlatformIdCache.Clear(); ResetPendingWardGuildProjectionRefreshes(); ResetSyncedGuildState(); _availabilityState = AvailabilityState.Unknown; _nextAvailabilityProbeUtc = DateTime.MinValue; } internal static void EnsureRuntimeBindings() { RegisterSyncRpcs(); } internal static void OnZNetAwake() { ResetRuntimeState(); EnsureRuntimeBindings(); } internal static WardGuildIdentity GetPlayerGuildIdentity(Player? player) { if (!TryGetGuild(player, out var guild)) { return default(WardGuildIdentity); } return guild; } internal static WardGuildIdentity GetPlayerGuildIdentity(long playerId) { if (!TryGetGuild(playerId, out var guild)) { return default(WardGuildIdentity); } return guild; } internal static WardGuildIdentity GetWardGuildIdentity(PrivateArea? area) { return new WardGuildIdentity(GetWardGuildId(area), GetWardGuildName(area)); } internal static WardGuildIdentity GetWardGuildIdentity(ZDO? zdo) { return new WardGuildIdentity(GetWardGuildId(zdo), GetWardGuildName(zdo)); } internal static int GetPlayerGuildId(Player? player) { if (!TryGetGuild(player, out var guild)) { return 0; } return guild.Id; } internal static int GetPlayerGuildId(long playerId) { if (!TryGetGuild(playerId, out var guild)) { return 0; } return guild.Id; } internal static string GetPlayerGuildName(long playerId) { if (!TryGetGuild(playerId, out var guild)) { return string.Empty; } return guild.Name; } internal static int GetWardGuildId(ZDO? zdo) { if (zdo == null) { return 0; } return zdo.GetInt("stuw_guild_id", 0); } internal static string GetWardGuildName(ZDO? zdo) { return ((zdo != null) ? zdo.GetString("stuw_guild_name", string.Empty) : null) ?? string.Empty; } internal static string BuildCharacterIdentityKey(string accountId, string playerName) { string text = WardOwnership.NormalizeAccountIdValue(accountId); string text2 = playerName?.Trim() ?? string.Empty; if (string.IsNullOrWhiteSpace(text) || string.IsNullOrWhiteSpace(text2)) { return string.Empty; } return text + "\n" + text2; } internal static void Update() { SyncLocalPlayerGuildIfNeeded(force: false); ProcessPendingPlayerGuildSyncs(); ProcessPendingWardGuildProjectionRefreshes(); } internal static void OnLocalPlayerStarted(Player? player) { if (!((Object)(object)player == (Object)null) && !((Object)(object)player != (Object)(object)Player.m_localPlayer)) { _localGuildSyncPending = true; SyncLocalPlayerGuildIfNeeded(force: true); } } internal static void ResetSyncedGuildState() { ServerSyncedGuildByPlayerId.Clear(); ServerSyncedGuildByCharacterKey.Clear(); PendingPlayerGuildSyncsBySender.Clear(); _syncRpcsRegistered = false; _localGuildSyncPending = true; _lastSyncedLocalPlayerId = 0L; _lastSyncedLocalGuildId = int.MinValue; _lastSyncedLocalGuildName = string.Empty; } internal static bool TryGetSyncedGuildIdentity(long playerId, string accountId, string playerName, out WardGuildIdentity guild) { guild = default(WardGuildIdentity); if (playerId != 0L && ServerSyncedGuildByPlayerId.TryGetValue(playerId, out var value)) { guild = (value.HasGuild ? new WardGuildIdentity(value.GuildId, value.GuildName) : default(WardGuildIdentity)); return true; } string text = BuildCharacterIdentityKey(accountId, playerName); if (string.IsNullOrWhiteSpace(text) || !ServerSyncedGuildByCharacterKey.TryGetValue(text, out var value2)) { return false; } guild = (value2.HasGuild ? new WardGuildIdentity(value2.GuildId, value2.GuildName) : default(WardGuildIdentity)); return true; } internal static bool TryGetSyncedGuildIdentity(string accountId, string playerName, out WardGuildIdentity guild) { return TryGetSyncedGuildIdentity(0L, accountId, playerName, out guild); } private static void RegisterSyncRpcs() { ZRoutedRpc instance = ZRoutedRpc.instance; if (!_syncRpcsRegistered && instance != null) { instance.Register("STUWard_SyncPlayerGuild", (Action)HandleSyncPlayerGuild); _syncRpcsRegistered = true; } } private static void SyncLocalPlayerGuildIfNeeded(bool force) { //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Expected O, but got Unknown Player localPlayer = Player.m_localPlayer; ZNet instance = ZNet.instance; if ((Object)(object)localPlayer == (Object)null || (Object)(object)instance == (Object)null) { return; } long playerID = localPlayer.GetPlayerID(); string playerAccountId = WardOwnership.GetPlayerAccountId(localPlayer); if (playerID == 0L || string.IsNullOrWhiteSpace(playerAccountId)) { return; } WardGuildIdentity playerGuildIdentity = GetPlayerGuildIdentity(localPlayer); string text = playerGuildIdentity.Name ?? string.Empty; bool flag = _localGuildSyncPending || playerID != _lastSyncedLocalPlayerId || playerGuildIdentity.Id != _lastSyncedLocalGuildId || !string.Equals(text, _lastSyncedLocalGuildName, StringComparison.Ordinal); if (!force && !flag) { return; } _lastSyncedLocalPlayerId = playerID; _lastSyncedLocalGuildId = playerGuildIdentity.Id; _lastSyncedLocalGuildName = text; _localGuildSyncPending = false; if (instance.IsServer()) { if (UpsertSyncedGuildIdentity(playerID, playerAccountId, localPlayer.GetPlayerName(), playerGuildIdentity, out var previousGuild)) { RefreshWardGuildProjectionForCharacter(new WardGuildCharacterIdentity(playerID, playerAccountId, localPlayer.GetPlayerName()), liveDisplayRefresh: true, playerGuildIdentity.Id, previousGuild.Id); } return; } ZRoutedRpc instance2 = ZRoutedRpc.instance; if (instance2 != null) { long serverPeerID = instance2.GetServerPeerID(); if (serverPeerID != 0L) { ZPackage val = new ZPackage(); val.Write(playerGuildIdentity.Id); val.Write(text); instance2.InvokeRoutedRPC(serverPeerID, "STUWard_SyncPlayerGuild", new object[1] { val }); } } } private static void HandleSyncPlayerGuild(long sender, ZPackage pkg) { if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer()) { int guildId = pkg.ReadInt(); string guildName = pkg.ReadString(); if (!TryApplySyncedGuildIdentity(sender, guildId, guildName)) { PendingPlayerGuildSyncsBySender[sender] = new PendingPlayerGuildSync(sender, guildId, guildName, DateTime.UtcNow); } } } private static void ProcessPendingPlayerGuildSyncs() { if (PendingPlayerGuildSyncsBySender.Count == 0 || (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return; } List list = null; List list2 = null; DateTime utcNow = DateTime.UtcNow; foreach (KeyValuePair item in PendingPlayerGuildSyncsBySender) { if (utcNow - item.Value.FirstSeenUtc > PendingPlayerGuildSyncLifetime) { if (list == null) { list = new List(); } list.Add(item.Key); } else if (TryApplySyncedGuildIdentity(item.Value.SenderUid, item.Value.GuildId, item.Value.GuildName)) { if (list2 == null) { list2 = new List(); } list2.Add(item.Key); } } if (list != null) { foreach (long item2 in list) { PendingPlayerGuildSyncsBySender.Remove(item2); } } if (list2 == null) { return; } foreach (long item3 in list2) { PendingPlayerGuildSyncsBySender.Remove(item3); } } private static bool TryApplySyncedGuildIdentity(long sender, int guildId, string guildName) { if (!WardOwnership.TryResolveAuthoritativePlayerIdFromSender(sender, "GuildsCompat.Sync", out var playerId)) { return false; } string text = WardOwnership.GetAuthoritativeAccountIdFromSender(sender, playerId); if (string.IsNullOrWhiteSpace(text)) { text = WardOwnership.GetPlayerAccountId(playerId); } if (string.IsNullOrWhiteSpace(text)) { return false; } WardGuildIdentity guild = ((guildId != 0) ? new WardGuildIdentity(guildId, guildName) : default(WardGuildIdentity)); string playerName = WardOwnership.GetPlayerName(playerId); if (UpsertSyncedGuildIdentity(playerId, text, playerName, guild, out var previousGuild)) { WardOwnership.RefreshServerPlayerAccountIdForResolvedPlayer(playerId, text); RefreshWardGuildProjectionForCharacter(new WardGuildCharacterIdentity(playerId, text, playerName), liveDisplayRefresh: true, guild.Id, previousGuild.Id); } return true; } private static void NotifyGuildProjectionRefreshApplied(string reason, bool fullRefresh, HashSet? targetPlayerIds, HashSet? targetCharacterKeys, HashSet? affectedGuildIds) { string reason2 = (string.IsNullOrWhiteSpace(reason) ? "guild projection refreshed" : reason); HashSet hashSet = null; if (!fullRefresh) { if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return; } List peers = ZNet.instance.GetPeers(); if (peers == null) { return; } hashSet = CollectGuildProjectionRefreshRecipients(peers, targetPlayerIds, targetCharacterKeys, affectedGuildIds); if (hashSet.Count == 0) { return; } } ManagedWardMapStateService.NotifyViewerProjectionChanged(reason2, fullRefresh, hashSet, refreshImmediatelyIfVisible: true); } private static HashSet CollectGuildProjectionRefreshRecipients(List peers, HashSet? targetPlayerIds, HashSet? targetCharacterKeys, HashSet? affectedGuildIds) { HashSet hashSet = new HashSet(); for (int i = 0; i < peers.Count; i++) { ZNetPeer val = peers[i]; if (val != null && val.m_uid != 0L) { long playerIdFromSender = WardOwnership.GetPlayerIdFromSender(val.m_uid); string authoritativeAccountIdFromSender = WardOwnership.GetAuthoritativeAccountIdFromSender(val.m_uid, playerIdFromSender); string playerName = ((playerIdFromSender != 0L) ? WardOwnership.GetPlayerName(playerIdFromSender) : string.Empty); if (ShouldReceiveGuildProjectionRefresh(playerIdFromSender, authoritativeAccountIdFromSender, playerName, targetPlayerIds, targetCharacterKeys, affectedGuildIds)) { hashSet.Add(val.m_uid); } } } return hashSet; } private static bool ShouldReceiveGuildProjectionRefresh(long playerId, string accountId, string playerName, HashSet? targetPlayerIds, HashSet? targetCharacterKeys, HashSet? affectedGuildIds) { if (playerId != 0L && WardAdminDebugAccess.IsPlayerAdminDebugController(playerId)) { return true; } if (targetPlayerIds != null && targetPlayerIds.Count > 0 && playerId != 0L && targetPlayerIds.Contains(playerId)) { return true; } if (targetCharacterKeys != null && targetCharacterKeys.Count > 0) { string text = BuildCharacterIdentityKey(accountId, playerName); if (!string.IsNullOrWhiteSpace(text) && targetCharacterKeys.Contains(text)) { return true; } } if (affectedGuildIds == null || affectedGuildIds.Count == 0) { return false; } if (TryGetSyncedGuildIdentity(playerId, accountId, playerName, out var guild) && guild.Id != 0) { return affectedGuildIds.Contains(guild.Id); } return false; } private static bool UpsertSyncedGuildIdentity(long playerId, string accountId, string playerName, WardGuildIdentity guild, out WardGuildIdentity previousGuild) { previousGuild = default(WardGuildIdentity); bool result = false; SyncedWardGuildIdentity value = new SyncedWardGuildIdentity(guild.Id != 0, guild.Id, guild.Name); if (playerId != 0L) { if (ServerSyncedGuildByPlayerId.TryGetValue(playerId, out var value2)) { previousGuild = ToWardGuildIdentity(value2); } if (!ServerSyncedGuildByPlayerId.TryGetValue(playerId, out value2) || value2.HasGuild != value.HasGuild || value2.GuildId != value.GuildId || !string.Equals(value2.GuildName, value.GuildName, StringComparison.Ordinal)) { ServerSyncedGuildByPlayerId[playerId] = value; result = true; } } string text = BuildCharacterIdentityKey(accountId, playerName); if (string.IsNullOrWhiteSpace(text)) { return result; } if (previousGuild.Id == 0 && ServerSyncedGuildByCharacterKey.TryGetValue(text, out var value3)) { previousGuild = ToWardGuildIdentity(value3); } if (!ServerSyncedGuildByCharacterKey.TryGetValue(text, out var value4) || value4.HasGuild != value.HasGuild || value4.GuildId != value.GuildId || !string.Equals(value4.GuildName, value.GuildName, StringComparison.Ordinal)) { ServerSyncedGuildByCharacterKey[text] = value; result = true; } return result; } private static WardGuildIdentity ToWardGuildIdentity(SyncedWardGuildIdentity syncedGuild) { if (!syncedGuild.HasGuild) { return default(WardGuildIdentity); } return new WardGuildIdentity(syncedGuild.GuildId, syncedGuild.GuildName); } private static Assembly? GetPluginAssembly(string pluginGuid) { if (!Chainloader.PluginInfos.TryGetValue(pluginGuid, out var value)) { return null; } return ((object)value.Instance)?.GetType().Assembly; } internal static bool IsAvailable() { if (!HasGuildsApiSurface) { return false; } if (_availabilityState == AvailabilityState.Available) { return true; } DateTime utcNow = DateTime.UtcNow; if (_availabilityState == AvailabilityState.Unavailable && utcNow < _nextAvailabilityProbeUtc) { return false; } try { if ((IsLoadedMethod.Invoke(null, Array.Empty()) as bool?).GetValueOrDefault()) { _availabilityState = AvailabilityState.Available; _nextAvailabilityProbeUtc = DateTime.MaxValue; return true; } } catch { } _availabilityState = AvailabilityState.Unavailable; _nextAvailabilityProbeUtc = utcNow + AvailabilityProbeBackoff; return false; } internal static void ResetPendingWardGuildProjectionRefreshes() { PendingWardGuildProjectionRefresh.TargetIdentitiesByPlayerId.Clear(); PendingWardGuildProjectionRefresh.TargetIdentitiesByCharacterKey.Clear(); PendingWardGuildProjectionRefresh.AffectedGuildIds.Clear(); PendingWardGuildProjectionRefresh.PendingFullRefresh = false; PendingWardGuildProjectionRefresh.PendingLiveDisplayRefresh = false; PendingWardGuildProjectionRefresh.PendingLiveDisplayReason = string.Empty; PendingWardGuildProjectionRefresh.FlushAtUtc = DateTime.MinValue; } internal static bool TryStampLocalWardGuildMetadata(PrivateArea? area) { return TryStampLocalWardGuildMetadata(ManagedWardRef.FromArea(area)); } internal static bool TryStampLocalWardGuildMetadata(ManagedWardRef ward) { if ((Object)(object)ward.Area == (Object)null || !ManagedWardIdentity.EnsureManagedComponent(ward)) { return false; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return false; } if (!WardAccess.IsDirectWardOwner(ward, localPlayer.GetPlayerID())) { return false; } if (!ward.HasValidNetworkIdentity || !ward.IsOwner) { return false; } ZDO zdo = ward.Zdo; if (zdo == null) { return false; } WardGuildIdentity guild; WardGuildIdentity guild2 = ((TryGetGuild(localPlayer, out guild) && guild.Id != 0) ? new WardGuildIdentity(guild.Id, guild.Name ?? string.Empty) : default(WardGuildIdentity)); ManagedWardProjection projection = ManagedWardProjectionService.ResolveExplicitProjection(localPlayer.GetPlayerID(), WardOwnership.GetPlayerAccountId(localPlayer), guild2); return ManagedWardMetadataMutationService.ApplyOwnedLocalProjection(zdo, projection, ManagedWardMapMutationKind.IndexAndPins, "local ward guild metadata stamp", forceSendWhenMetadataChanged: false).ProjectionResult.GuildChanged; } internal static int GetWardGuildId(PrivateArea? area) { if (TryGetStoredWardGuildIdentity(GetWardZdo(area), out var guild)) { return guild.Id; } if (!TryResolveWardGuildIdentity(area, allowMetadataStamp: false, out var guild2)) { return 0; } return guild2.Id; } internal static string GetWardGuildName(PrivateArea? area) { if (TryGetStoredWardGuildIdentity(GetWardZdo(area), out var guild) && !string.IsNullOrWhiteSpace(guild.Name)) { return guild.Name; } if (TryResolveWardGuildIdentity(area, allowMetadataStamp: false, out var guild2)) { return guild2.Name; } int id = guild.Id; if (id != 0 && TryGetGuildById(id, out guild2)) { return guild2.Name; } Player localPlayer = Player.m_localPlayer; if (id != 0 && (Object)(object)localPlayer != (Object)null && TryGetGuild(localPlayer, out guild2) && guild2.Id == id) { return guild2.Name; } return string.Empty; } internal static WardGuildIdentity ResolveWardGuildIdentityReadOnly(ZDO? zdo) { if (TryGetStoredWardGuildIdentity(zdo, out var guild) && guild.Id != 0) { return guild; } if (zdo == null) { return default(WardGuildIdentity); } long @long = zdo.GetLong(ZDOVars.s_creator, 0L); string wardSteamAccountId = WardOwnership.ResolveWardSteamAccountId(zdo, @long, WardOwnership.GetWardSteamAccountId(zdo)); string wardOwnerNameForProjection = GetWardOwnerNameForProjection(zdo); if (!TryResolveWardGuildIdentityReadOnly(@long, wardSteamAccountId, wardOwnerNameForProjection, treatResolvedNoGuildAsResolved: false, out var guild2)) { return default(WardGuildIdentity); } return guild2; } private static bool TryGetStoredWardGuildIdentity(ZDO? zdo, out WardGuildIdentity guild) { guild = default(WardGuildIdentity); if (zdo == null) { return false; } int @int = zdo.GetInt("stuw_guild_id", 0); string text = zdo.GetString("stuw_guild_name", string.Empty) ?? string.Empty; if (@int == 0 && string.IsNullOrWhiteSpace(text)) { return false; } guild = new WardGuildIdentity(@int, text.Trim()); return true; } private static ZDO? GetWardZdo(PrivateArea? area) { return WardPrivateAreaSafeAccess.GetZdo(area); } private static bool TryResolveWardGuildIdentity(PrivateArea? area, bool allowMetadataStamp, out WardGuildIdentity guild) { guild = default(WardGuildIdentity); if ((Object)(object)area == (Object)null) { return false; } long canonicalCreatorPlayerId = WardAccess.GetCanonicalCreatorPlayerId(area); string wardSteamAccountId = WardOwnership.ResolveWardSteamAccountId(GetWardZdo(area), canonicalCreatorPlayerId, WardOwnership.GetWardSteamAccountId(area)); string wardOwnerName = GetWardOwnerName(area); if (TryResolveWardGuildIdentityReadOnly(canonicalCreatorPlayerId, wardSteamAccountId, wardOwnerName, treatResolvedNoGuildAsResolved: true, out guild)) { if (allowMetadataStamp) { StampResolvedWardGuildMetadata(area, canonicalCreatorPlayerId, wardSteamAccountId, guild); } return true; } return false; } private static string GetWardOwnerName(PrivateArea? area) { if ((Object)(object)area == (Object)null) { return string.Empty; } string creatorName = WardPrivateAreaSafeAccess.GetCreatorName(area); if (!string.IsNullOrWhiteSpace(creatorName)) { return creatorName.Trim(); } return GetWardOwnerNameForProjection(GetWardZdo(area)); } internal static string GetWardOwnerNameForProjection(ZDO? zdo) { return WardPrivateAreaSafeAccess.GetCreatorName(zdo); } internal static bool TryResolveProjectedGuildIdentity(long ownerPlayerId, string normalizedAccountId, string ownerName, out WardGuildIdentity guild) { return TryResolveWardGuildIdentityReadOnly(ownerPlayerId, normalizedAccountId, ownerName, treatResolvedNoGuildAsResolved: true, out guild); } private static bool TryResolveWardGuildIdentityReadOnly(long ownerPlayerId, string wardSteamAccountId, string ownerName, bool treatResolvedNoGuildAsResolved, out WardGuildIdentity guild) { guild = default(WardGuildIdentity); string text = WardOwnership.NormalizeAccountIdValue(wardSteamAccountId); string text2 = ownerName?.Trim() ?? string.Empty; if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && TryGetSyncedGuildIdentity(ownerPlayerId, text, text2, out guild)) { if (!treatResolvedNoGuildAsResolved) { return guild.Id != 0; } return true; } if (ownerPlayerId != 0L && TryGetGuild(ownerPlayerId, out guild)) { return true; } if (!string.IsNullOrWhiteSpace(text) && !string.IsNullOrWhiteSpace(text2)) { return TryGetGuildByAccountAndName(text, text2, out guild); } return false; } private static void StampResolvedWardGuildMetadata(PrivateArea? area, long ownerPlayerId, string wardSteamAccountId, WardGuildIdentity guild) { if (guild.Id != 0 && !((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer()) { ZDO wardZdo = GetWardZdo(area); if (wardZdo != null) { ManagedWardMetadataMutationService.ApplyExplicitProjection(wardZdo, ManagedWardProjectionService.ResolveExplicitProjection(ownerPlayerId, wardSteamAccountId, guild), ManagedWardMapMutationKind.IndexAndPins, "resolved ward guild metadata"); } } } internal static void HandleGuildSaved(object? guild) { Plugin.LogWardDiagnosticVerbose("GuildsCompat.Refresh", "Queued guild save refresh for guild=" + DescribeGuildObject(guild) + "."); RefreshWardGuildProjectionForGuild(guild); } internal static void RefreshAllWardGuildProjections(bool liveDisplayRefresh = false) { Plugin.LogWardDiagnosticVerbose("GuildsCompat.Refresh", "Queued full ward guild projection refresh."); QueueWardGuildProjectionRefreshForAll(liveDisplayRefresh, "full guild projection refresh"); } private static void RefreshWardGuildProjectionForGuild(object? guild) { WardGuildIdentity guild2; int affectedGuildId = (TryParseGuild(guild, out guild2) ? guild2.Id : 0); bool hadUnresolvedMembers; List list = CollectGuildMemberCharacterIdentities(guild, out hadUnresolvedMembers); if (list.Count == 0 || hadUnresolvedMembers) { Plugin.LogWardDiagnosticFailure("GuildsCompat.Refresh", "Could not extract complete guild member character identities from guild=" + DescribeGuildObject(guild) + ". Falling back to full ward guild refresh."); QueueWardGuildProjectionRefreshForAll(liveDisplayRefresh: false, "full guild projection refresh"); return; } Plugin.LogWardDiagnosticVerbose("GuildsCompat.Refresh", $"Queued ward guild projection refresh for {list.Count} guild member character(s) from guild={DescribeGuildObject(guild)}."); foreach (WardGuildCharacterIdentity item in list) { RefreshWardGuildProjectionForCharacter(item, liveDisplayRefresh: false, affectedGuildId); } } private static void RefreshWardGuildProjectionForCharacter(WardGuildCharacterIdentity identity, bool liveDisplayRefresh = false, int affectedGuildId = 0, int previousGuildId = 0) { if (identity.HasPlayerId || identity.HasAccountAndName) { Plugin.LogWardDiagnosticVerbose("GuildsCompat.Refresh", $"Queued ward guild projection refresh for character playerId={identity.PlayerId}, accountId='{identity.AccountId}', playerName='{identity.PlayerName}'."); if (!string.IsNullOrWhiteSpace(identity.AccountId)) { InvalidateGuildCacheForAccountId(identity.AccountId); } QueueWardGuildProjectionRefreshForCharacter(identity, liveDisplayRefresh, $"guild projection refresh for playerId={identity.PlayerId}, accountId='{identity.AccountId}'", affectedGuildId, previousGuildId); } } internal static void ProcessPendingWardGuildProjectionRefreshes() { if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer()) { PendingWardGuildProjectionRefreshState pendingWardGuildProjectionRefresh = PendingWardGuildProjectionRefresh; if ((pendingWardGuildProjectionRefresh.PendingFullRefresh || pendingWardGuildProjectionRefresh.TargetIdentitiesByPlayerId.Count != 0 || pendingWardGuildProjectionRefresh.TargetIdentitiesByCharacterKey.Count != 0 || pendingWardGuildProjectionRefresh.AffectedGuildIds.Count != 0) && !(pendingWardGuildProjectionRefresh.FlushAtUtc > DateTime.UtcNow)) { bool pendingFullRefresh = pendingWardGuildProjectionRefresh.PendingFullRefresh; bool pendingLiveDisplayRefresh = pendingWardGuildProjectionRefresh.PendingLiveDisplayRefresh; string liveDisplayReason = (string.IsNullOrWhiteSpace(pendingWardGuildProjectionRefresh.PendingLiveDisplayReason) ? "guild projection refreshed" : pendingWardGuildProjectionRefresh.PendingLiveDisplayReason); HashSet targetPlayerIds = ((pendingWardGuildProjectionRefresh.TargetIdentitiesByPlayerId.Count == 0) ? null : new HashSet(pendingWardGuildProjectionRefresh.TargetIdentitiesByPlayerId.Keys)); HashSet targetCharacterKeys = ((pendingWardGuildProjectionRefresh.TargetIdentitiesByCharacterKey.Count == 0) ? null : new HashSet(pendingWardGuildProjectionRefresh.TargetIdentitiesByCharacterKey.Keys, StringComparer.Ordinal)); HashSet affectedGuildIds = ((pendingWardGuildProjectionRefresh.AffectedGuildIds.Count == 0) ? null : new HashSet(pendingWardGuildProjectionRefresh.AffectedGuildIds)); ResetPendingWardGuildProjectionRefreshes(); RefreshWardGuildProjectionForManagedWards(targetPlayerIds, targetCharacterKeys, affectedGuildIds, pendingFullRefresh, pendingLiveDisplayRefresh, liveDisplayReason); } } } private static void QueueWardGuildProjectionRefreshForAll(bool liveDisplayRefresh, string liveDisplayReason) { PendingWardGuildProjectionRefresh.PendingFullRefresh = true; PendingWardGuildProjectionRefresh.TargetIdentitiesByPlayerId.Clear(); PendingWardGuildProjectionRefresh.TargetIdentitiesByCharacterKey.Clear(); UpdatePendingWardGuildProjectionRefreshWindow(liveDisplayRefresh, liveDisplayReason); } private static void QueueWardGuildProjectionRefreshForCharacter(WardGuildCharacterIdentity identity, bool liveDisplayRefresh, string liveDisplayReason, int affectedGuildId, int previousGuildId) { if (!PendingWardGuildProjectionRefresh.PendingFullRefresh) { if (identity.HasPlayerId) { PendingWardGuildProjectionRefresh.TargetIdentitiesByPlayerId[identity.PlayerId] = MergeQueuedWardGuildCharacterIdentity(PendingWardGuildProjectionRefresh.TargetIdentitiesByPlayerId.TryGetValue(identity.PlayerId, out var value) ? value : default(WardGuildCharacterIdentity), identity); } if (identity.HasAccountAndName) { string text = BuildCharacterIdentityKey(identity.AccountId, identity.PlayerName); if (!string.IsNullOrWhiteSpace(text)) { PendingWardGuildProjectionRefresh.TargetIdentitiesByCharacterKey[text] = MergeQueuedWardGuildCharacterIdentity(PendingWardGuildProjectionRefresh.TargetIdentitiesByCharacterKey.TryGetValue(text, out var value2) ? value2 : default(WardGuildCharacterIdentity), identity); } } } if (affectedGuildId != 0) { PendingWardGuildProjectionRefresh.AffectedGuildIds.Add(affectedGuildId); } if (previousGuildId != 0) { PendingWardGuildProjectionRefresh.AffectedGuildIds.Add(previousGuildId); } UpdatePendingWardGuildProjectionRefreshWindow(liveDisplayRefresh, liveDisplayReason); } private static void UpdatePendingWardGuildProjectionRefreshWindow(bool liveDisplayRefresh, string liveDisplayReason) { if (liveDisplayRefresh) { PendingWardGuildProjectionRefresh.PendingLiveDisplayRefresh = true; } if (string.IsNullOrWhiteSpace(PendingWardGuildProjectionRefresh.PendingLiveDisplayReason)) { PendingWardGuildProjectionRefresh.PendingLiveDisplayReason = (string.IsNullOrWhiteSpace(liveDisplayReason) ? "guild projection refreshed" : liveDisplayReason); } if (PendingWardGuildProjectionRefresh.FlushAtUtc == DateTime.MinValue) { PendingWardGuildProjectionRefresh.FlushAtUtc = DateTime.UtcNow + PendingWardGuildProjectionRefreshDebounce; } } private static WardGuildCharacterIdentity MergeQueuedWardGuildCharacterIdentity(WardGuildCharacterIdentity existingIdentity, WardGuildCharacterIdentity incomingIdentity) { long playerId = (existingIdentity.HasPlayerId ? existingIdentity.PlayerId : incomingIdentity.PlayerId); string accountId = ((!string.IsNullOrWhiteSpace(existingIdentity.AccountId)) ? existingIdentity.AccountId : incomingIdentity.AccountId); string playerName = ((!string.IsNullOrWhiteSpace(existingIdentity.PlayerName)) ? existingIdentity.PlayerName : incomingIdentity.PlayerName); return new WardGuildCharacterIdentity(playerId, accountId, playerName); } private static bool RefreshWardGuildProjectionForManagedWards(HashSet? targetPlayerIds, HashSet? targetCharacterKeys, HashSet? affectedGuildIds, bool fullRefresh, bool liveDisplayRefresh, string liveDisplayReason) { //IL_006a: 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_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return false; } if (!fullRefresh && (targetPlayerIds == null || targetPlayerIds.Count == 0) && (targetCharacterKeys == null || targetCharacterKeys.Count == 0) && (affectedGuildIds == null || affectedGuildIds.Count == 0)) { return false; } if (fullRefresh) { InvalidateAllGuildCaches(); } HashSet hashSet = new HashSet(); int num = ManagedWardRegistry.CollectCandidateIds(hashSet, targetPlayerIds, targetCharacterKeys, affectedGuildIds, fullRefresh); int num2 = 0; int num3 = 0; foreach (ZDOID item in hashSet) { ZDOMan instance = ZDOMan.instance; ZDO val = ((instance != null) ? instance.GetZDO(item) : null); if (val == null || !WardOwnership.IsManagedWardZdo(val)) { ManagedWardRegistry.RemoveEntry(item); continue; } long @long = val.GetLong(ZDOVars.s_creator, 0L); num3++; string wardSteamAccountId = WardOwnership.NormalizeAccountIdValue(WardOwnership.ResolveWardSteamAccountId(val, @long, WardOwnership.GetWardSteamAccountId(val))); if (ManagedWardMetadataMutationService.RefreshProjectedMetadata(val, @long, wardSteamAccountId, ManagedWardMapMutationKind.IndexOnly, "guild projection refreshed").ProjectionResult.AnyChanged) { num2++; } } if (num2 > 0 && liveDisplayRefresh) { NotifyGuildProjectionRefreshApplied(liveDisplayReason, fullRefresh, targetPlayerIds, targetCharacterKeys, affectedGuildIds); } Plugin.LogWardDiagnosticVerbose("GuildsCompat.Refresh", string.Format("Scanned {0} managed ward(s) for guild projection refresh out of {1} registry candidate(s) and {2} indexed ward(s){3}{4}{5}{6}, changed={7}.", num3, num, ManagedWardRegistry.GetIndexedCount(), fullRefresh ? " on full refresh" : string.Empty, (!fullRefresh && targetPlayerIds != null && targetPlayerIds.Count > 0) ? $" targeting {targetPlayerIds.Count} playerId(s)" : string.Empty, (!fullRefresh && targetCharacterKeys != null && targetCharacterKeys.Count > 0) ? $" and {targetCharacterKeys.Count} account/name identities" : string.Empty, (!fullRefresh && affectedGuildIds != null && affectedGuildIds.Count > 0) ? $" across {affectedGuildIds.Count} affected guild(s)" : string.Empty, num2)); return num2 > 0; } private static List CollectGuildMemberCharacterIdentities(object? guild, out bool hadUnresolvedMembers) { Dictionary dictionary = new Dictionary(StringComparer.Ordinal); hadUnresolvedMembers = false; if (guild == null || GuildMembersField == null) { return new List(); } object value = GuildMembersField.GetValue(guild); if (value is IDictionary dictionary2) { foreach (object key in dictionary2.Keys) { if (!TryCreateCharacterIdentityFromPlayerReference(key, out var identity)) { hadUnresolvedMembers = true; } else { dictionary[BuildCharacterIdentityKey(identity.AccountId, identity.PlayerName)] = identity; } } return new List(dictionary.Values); } if (!(value is IEnumerable enumerable)) { return new List(); } foreach (object item in enumerable) { if (item != null) { if (!TryCreateCharacterIdentityFromPlayerReference(AccessTools.Property(item.GetType(), "Key")?.GetValue(item, null), out var identity2)) { hadUnresolvedMembers = true; } else { dictionary[BuildCharacterIdentityKey(identity2.AccountId, identity2.PlayerName)] = identity2; } } } return new List(dictionary.Values); } private static bool TryCreateCharacterIdentityFromPlayerReference(object? playerReference, out WardGuildCharacterIdentity identity) { identity = default(WardGuildCharacterIdentity); if (playerReference == null || PlayerReferenceIdField == null) { return false; } try { string text = WardOwnership.NormalizeAccountIdValue(PlayerReferenceIdField.GetValue(playerReference)?.ToString()); string playerNameFromPlayerReference = GetPlayerNameFromPlayerReference(playerReference); if (string.IsNullOrWhiteSpace(text) || string.IsNullOrWhiteSpace(playerNameFromPlayerReference)) { return false; } identity = new WardGuildCharacterIdentity(0L, text, playerNameFromPlayerReference); return true; } catch { return false; } } private static string GetPlayerNameFromPlayerReference(object playerReference) { if (PlayerReferenceNameField != null) { string text = PlayerReferenceNameField.GetValue(playerReference)?.ToString()?.Trim() ?? string.Empty; if (!string.IsNullOrWhiteSpace(text)) { return text; } } string text2 = playerReference.ToString()?.Trim() ?? string.Empty; int num = text2.IndexOf(':'); if (num < 0 || num >= text2.Length - 1) { return string.Empty; } return text2.Substring(num + 1).Trim(); } private static void InvalidateGuildCacheForAccountId(string accountId) { //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) string text = WardOwnership.NormalizeAccountIdValue(accountId); if (string.IsNullOrWhiteSpace(text)) { return; } HashSet hashSet = new HashSet(); foreach (KeyValuePair item in PlayerPlatformIdCache) { if (item.Value.HasPlatformId && string.Equals(item.Value.PlatformId, text, StringComparison.Ordinal)) { hashSet.Add(item.Key); } } List list = ZNet.instance?.m_players; if (list != null) { for (int i = 0; i < list.Count; i++) { PlayerInfo val = list[i]; if (string.Equals(WardOwnership.NormalizeAccountIdValue(((object)(PlatformUserID)(ref val.m_userInfo.m_id)).ToString()), text, StringComparison.Ordinal)) { ZDOMan instance = ZDOMan.instance; ZDO obj = ((instance != null) ? instance.GetZDO(val.m_characterID) : null); long num = ((obj != null) ? obj.GetLong(ZDOVars.s_playerID, 0L) : 0); if (num != 0L) { hashSet.Add(num); } } } } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null && string.Equals(WardOwnership.NormalizeAccountIdValue(WardOwnership.GetPlayerAccountId(localPlayer)), text, StringComparison.Ordinal)) { hashSet.Add(localPlayer.GetPlayerID()); } foreach (long item2 in hashSet) { PlayerGuildCache.Remove(item2); PlayerPlatformIdCache.Remove(item2); } } private static void InvalidateAllGuildCaches() { PlayerGuildCache.Clear(); PlayerPlatformIdCache.Clear(); } internal static string DescribeGuildObject(object? guild) { if (guild == null) { return "null"; } try { string arg = (GuildNameField?.GetValue(guild) as string) ?? string.Empty; int num = ((GuildGeneralField != null && GuildGeneralIdField != null) ? Convert.ToInt32(GuildGeneralIdField.GetValue(GuildGeneralField.GetValue(guild))) : 0); return $"type={guild.GetType().FullName}, id={num}, name='{arg}'"; } catch { return "type=" + guild.GetType().FullName; } } internal static string GetPlayerPlatformId(long playerId) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) if (playerId == 0L) { return string.Empty; } if (TryGetCachedPlatformId(playerId, out string platformId)) { return platformId; } string playerAccountId = WardOwnership.GetPlayerAccountId(playerId); if (!string.IsNullOrWhiteSpace(playerAccountId)) { CachePlatformId(playerId, playerAccountId); return playerAccountId; } PlayerInfo? val = FindPlayerInfo(playerId); if (!val.HasValue || PlayerInfoUserInfoField == null || UserInfoIdField == null) { CachePlatformId(playerId, string.Empty); return string.Empty; } try { object obj = val.Value; object value = PlayerInfoUserInfoField.GetValue(obj); if (value == null) { CachePlatformId(playerId, string.Empty); return string.Empty; } string text = UserInfoIdField.GetValue(value)?.ToString() ?? string.Empty; CachePlatformId(playerId, text); return text; } catch { CachePlatformId(playerId, string.Empty); return string.Empty; } } private static bool TryGetGuild(Player? player, out WardGuildIdentity guild) { guild = default(WardGuildIdentity); if ((Object)(object)player == (Object)null) { return false; } long playerID = player.GetPlayerID(); if (TryGetCachedGuild(playerID, out guild)) { return true; } if (IsCachedNoGuild(playerID)) { return false; } if (IsAvailable() && GetPlayerGuildByPlayerMethod != null) { try { if (TryParseGuild(GetPlayerGuildByPlayerMethod.Invoke(null, new object[1] { player }), out guild)) { CacheGuildLookup(playerID, hasGuild: true, guild); return true; } } catch { } } string playerAccountId = WardOwnership.GetPlayerAccountId(player); string playerName = player.GetPlayerName(); if (!string.IsNullOrWhiteSpace(playerAccountId) && !string.IsNullOrWhiteSpace(playerName) && TryGetGuildByAccountAndName(playerAccountId, playerName, out guild)) { CacheGuildLookup(playerID, hasGuild: true, guild); return true; } Plugin.LogWardDiagnosticVerbose("GuildsCompat.Lookup", $"Failed local guild lookup. playerId={playerID}, playerName='{playerName}', accountId='{playerAccountId}', apiAvailable={IsAvailable()}, hasPlayerLookup={GetPlayerGuildByPlayerMethod != null}, hasReferenceLookup={GetPlayerGuildByReferenceMethod != null && PlayerReferenceFromStringMethod != null}"); CacheGuildLookup(playerID, hasGuild: false, default(WardGuildIdentity)); return false; } private static bool TryGetGuild(long playerId, out WardGuildIdentity guild) { guild = default(WardGuildIdentity); if (playerId == 0L) { return false; } string playerAccountId = WardOwnership.GetPlayerAccountId(playerId); string playerName = WardOwnership.GetPlayerName(playerId); if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && TryGetSyncedGuildIdentity(playerId, playerAccountId, playerName, out guild)) { CacheGuildLookup(playerId, guild.Id != 0, guild); return guild.Id != 0; } if (TryGetCachedGuild(playerId, out guild)) { return true; } if (IsCachedNoGuild(playerId)) { return false; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null && localPlayer.GetPlayerID() == playerId) { return TryGetGuild(localPlayer, out guild); } if (!IsAvailable() || GetPlayerGuildByReferenceMethod == null || PlayerReferenceFromStringMethod == null) { Plugin.LogWardDiagnosticVerbose("GuildsCompat.Lookup", $"Failed remote guild lookup because Guilds API reference lookup is unavailable. playerId={playerId}, playerName='{WardOwnership.GetPlayerName(playerId)}', accountId='{WardOwnership.GetPlayerAccountId(playerId)}', apiAvailable={IsAvailable()}, hasReferenceLookup={GetPlayerGuildByReferenceMethod != null && PlayerReferenceFromStringMethod != null}"); return false; } string playerPlatformId = GetPlayerPlatformId(playerId); if (string.IsNullOrWhiteSpace(playerPlatformId)) { string playerAccountId2 = WardOwnership.GetPlayerAccountId(playerId); Plugin.LogWardDiagnosticVerbose("GuildsCompat.Lookup", $"Failed remote guild lookup because live player platform id is unavailable. playerId={playerId}, playerName='{WardOwnership.GetPlayerName(playerId)}', fallbackAccountId='{playerAccountId2}'"); CacheGuildLookup(playerId, hasGuild: false, default(WardGuildIdentity)); return false; } if (string.IsNullOrWhiteSpace(playerName)) { Plugin.LogWardDiagnosticVerbose("GuildsCompat.Lookup", $"Failed remote guild lookup because player name is unavailable. playerId={playerId}, accountId='{playerPlatformId}'"); CacheGuildLookup(playerId, hasGuild: false, default(WardGuildIdentity)); return false; } if (!string.IsNullOrWhiteSpace(playerName) && TryGetGuildByAccountAndName(playerPlatformId, playerName, out guild)) { CacheGuildLookup(playerId, hasGuild: true, guild); return true; } Plugin.LogWardDiagnosticVerbose("GuildsCompat.Lookup", $"Failed remote guild lookup after account/name lookup. playerId={playerId}, playerName='{playerName}', accountId='{playerPlatformId}'"); CacheGuildLookup(playerId, hasGuild: false, default(WardGuildIdentity)); return false; } private static bool TryGetGuildByAccountAndName(string accountId, string playerName, out WardGuildIdentity guild) { guild = default(WardGuildIdentity); string text = WardOwnership.NormalizeAccountIdValue(accountId); string text2 = playerName?.Trim() ?? string.Empty; if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && TryGetSyncedGuildIdentity(text, text2, out guild)) { return guild.Id != 0; } if (string.IsNullOrWhiteSpace(text) || string.IsNullOrWhiteSpace(text2) || GetPlayerGuildByReferenceMethod == null || PlayerReferenceFromStringMethod == null || !IsAvailable()) { return false; } try { object obj = PlayerReferenceFromStringMethod.Invoke(null, new object[1] { text + ":" + text2 }); return TryParseGuild(GetPlayerGuildByReferenceMethod.Invoke(null, new object[1] { obj }), out guild); } catch { return false; } } private static bool TryGetGuildById(int guildId, out WardGuildIdentity guild) { guild = default(WardGuildIdentity); if (guildId == 0 || GetGuildByIdMethod == null || !IsAvailable()) { return false; } try { return TryParseGuild(GetGuildByIdMethod.Invoke(null, new object[1] { guildId }), out guild); } catch { return false; } } private static bool TryGetCachedGuild(long playerId, out WardGuildIdentity guild) { guild = default(WardGuildIdentity); if (!PlayerGuildCache.TryGetValue(playerId, out var value)) { return false; } if (value.ExpiresAtUtc <= DateTime.UtcNow) { PlayerGuildCache.Remove(playerId); return false; } if (!value.HasGuild || value.GuildId == 0) { return false; } guild = new WardGuildIdentity(value.GuildId, value.GuildName); return true; } private static bool IsCachedNoGuild(long playerId) { if (!PlayerGuildCache.TryGetValue(playerId, out var value)) { return false; } if (value.ExpiresAtUtc <= DateTime.UtcNow) { PlayerGuildCache.Remove(playerId); return false; } return !value.HasGuild; } private static void CacheGuildLookup(long playerId, bool hasGuild, WardGuildIdentity guild) { if (playerId != 0L) { PlayerGuildCache[playerId] = new CachedWardGuildIdentity(hasGuild && guild.Id != 0, guild.Id, guild.Name ?? string.Empty, DateTime.UtcNow + GuildLookupCacheDuration); } } private static bool TryGetCachedPlatformId(long playerId, out string platformId) { platformId = string.Empty; if (!PlayerPlatformIdCache.TryGetValue(playerId, out var value)) { return false; } if (value.ExpiresAtUtc <= DateTime.UtcNow) { PlayerPlatformIdCache.Remove(playerId); return false; } if (!value.HasPlatformId) { return true; } platformId = value.PlatformId; return true; } private static void CachePlatformId(long playerId, string platformId) { if (playerId != 0L) { bool flag = !string.IsNullOrWhiteSpace(platformId); PlayerPlatformIdCache[playerId] = new CachedPlayerPlatformIdentity(flag, flag ? platformId : string.Empty, DateTime.UtcNow + GuildLookupCacheDuration); } } private static PlayerInfo? FindPlayerInfo(long playerId) { //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_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_0059: Unknown result type (might be due to invalid IL or missing references) List list = ZNet.instance?.m_players; if (list == null) { return null; } for (int i = 0; i < list.Count; i++) { PlayerInfo val = list[i]; ZDOMan instance = ZDOMan.instance; ZDO obj = ((instance != null) ? instance.GetZDO(val.m_characterID) : null); if (((obj != null) ? obj.GetLong(ZDOVars.s_playerID, 0L) : 0) == playerId) { return val; } } return null; } private static bool TryParseGuild(object? guildObject, out WardGuildIdentity guild) { guild = default(WardGuildIdentity); if (guildObject == null || GuildNameField == null || GuildGeneralField == null || GuildGeneralIdField == null) { return false; } try { object value = GuildGeneralField.GetValue(guildObject); int num = ((value != null) ? Convert.ToInt32(GuildGeneralIdField.GetValue(value)) : 0); if (num == 0) { return false; } string name = (GuildNameField.GetValue(guildObject) as string) ?? string.Empty; guild = new WardGuildIdentity(num, name); return true; } catch { return false; } } internal static void TryPatch(Harmony harmony) { //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Expected O, but got Unknown EnsureHooksRegistered(); if (_saveGuildPatched || harmony == null || SaveGuildMethod == null) { if (SaveGuildMethod == null) { Plugin.LogWardDiagnosticFailure("GuildsCompat.Patch", "Skipped SaveGuild postfix patch because SaveGuildMethod could not be resolved."); } return; } MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(GuildsSaveGuildPatch), "Postfix", (Type[])null, (Type[])null); if (!(methodInfo == null)) { harmony.Patch((MethodBase)SaveGuildMethod, (HarmonyMethod)null, new HarmonyMethod(methodInfo), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _saveGuildPatched = true; Plugin.LogWardDiagnosticVerbose("GuildsCompat.Patch", "Patched Guilds.API.SaveGuild postfix for ward guild projection refresh."); } } private static void EnsureHooksRegistered() { if (_guildHooksRegistered) { _guildHooksActive = true; return; } if (ApiType == null) { Plugin.LogWardDiagnosticFailure("GuildsCompat.Patch", "Skipped guild event hook registration because Guilds API type could not be resolved."); return; } RegisterGuildHook(RegisterOnGuildJoinedMethod, GuildJoinedDelegateType, "HandleGuildJoinedEvent"); RegisterGuildHook(RegisterOnGuildLeftMethod, GuildLeftDelegateType, "HandleGuildLeftEvent"); RegisterGuildHook(RegisterOnGuildCreatedMethod, GuildCreatedDelegateType, "HandleGuildCreatedEvent"); RegisterGuildHook(RegisterOnGuildDeletedMethod, GuildDeletedDelegateType, "HandleGuildDeletedEvent"); _guildHooksRegistered = true; _guildHooksActive = true; Plugin.LogWardDiagnosticVerbose("GuildsCompat.Patch", "Registered Guilds API event hooks for joined/left/created/deleted."); } internal static void TryShutdownHooks() { _guildHooksActive = false; _saveGuildPatched = false; } internal static bool IsGuildHooksActive() { return _guildHooksActive; } private static void RegisterGuildHook(MethodInfo? registerMethod, Type? delegateType, string handlerName) { if (registerMethod == null || delegateType == null) { Plugin.LogWardDiagnosticFailure("GuildsCompat.Patch", "Skipped guild hook registration for handler '" + handlerName + "' because the register method or delegate type was unresolved."); return; } Delegate @delegate = CreateGuildCallback(delegateType, handlerName); if ((object)@delegate == null) { Plugin.LogWardDiagnosticFailure("GuildsCompat.Patch", "Failed to create guild callback delegate for handler '" + handlerName + "'."); return; } registerMethod.Invoke(null, new object[1] { @delegate }); Plugin.LogWardDiagnosticVerbose("GuildsCompat.Patch", "Registered guild hook '" + registerMethod.Name + "' -> '" + handlerName + "'."); } private static Delegate? CreateGuildCallback(Type delegateType, string handlerName) { MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(GuildsCompat), handlerName, (Type[])null, (Type[])null); MethodInfo method = delegateType.GetMethod("Invoke"); if (methodInfo == null || method == null) { return null; } ParameterInfo[] parameters = method.GetParameters(); ParameterExpression[] array = new ParameterExpression[parameters.Length]; Expression[] array2 = new Expression[parameters.Length]; for (int i = 0; i < parameters.Length; i++) { array2[i] = Expression.Convert(array[i] = Expression.Parameter(parameters[i].ParameterType, parameters[i].Name), typeof(object)); } MethodCallExpression body = Expression.Call(methodInfo, array2); return Expression.Lambda(delegateType, body, array).Compile(); } private static void HandleGuildJoinedEvent(object guild, object playerReference) { if (_guildHooksActive) { if (!TryCreateCharacterIdentityFromPlayerReference(playerReference, out var identity)) { Plugin.LogWardDiagnosticFailure("GuildsCompat.Event", "Received GuildJoined event with an unresolved player reference. Falling back to full ward guild refresh, guild=" + DescribeGuildObject(guild) + "."); RefreshAllWardGuildProjections(liveDisplayRefresh: true); return; } Plugin.LogWardDiagnosticVerbose("GuildsCompat.Event", "Received GuildJoined event for accountId='" + identity.AccountId + "', playerName='" + identity.PlayerName + "', guild=" + DescribeGuildObject(guild) + "."); RefreshWardGuildProjectionForCharacter(identity, liveDisplayRefresh: true, TryParseGuild(guild, out var guild2) ? guild2.Id : 0); } } private static void HandleGuildLeftEvent(object guild, object playerReference) { if (_guildHooksActive) { if (!TryCreateCharacterIdentityFromPlayerReference(playerReference, out var identity)) { Plugin.LogWardDiagnosticFailure("GuildsCompat.Event", "Received GuildLeft event with an unresolved player reference. Falling back to full ward guild refresh, guild=" + DescribeGuildObject(guild) + "."); RefreshAllWardGuildProjections(liveDisplayRefresh: true); return; } Plugin.LogWardDiagnosticVerbose("GuildsCompat.Event", "Received GuildLeft event for accountId='" + identity.AccountId + "', playerName='" + identity.PlayerName + "', guild=" + DescribeGuildObject(guild) + "."); RefreshWardGuildProjectionForCharacter(identity, liveDisplayRefresh: true, TryParseGuild(guild, out var guild2) ? guild2.Id : 0); } } private static void HandleGuildCreatedEvent(object guild) { if (_guildHooksActive) { Plugin.LogWardDiagnosticVerbose("GuildsCompat.Event", "Received GuildCreated event, guild=" + DescribeGuildObject(guild) + ". Refreshing all ward guild projections."); RefreshAllWardGuildProjections(liveDisplayRefresh: true); } } private static void HandleGuildDeletedEvent(object guild) { if (_guildHooksActive) { Plugin.LogWardDiagnosticVerbose("GuildsCompat.Event", "Received GuildDeleted event, guild=" + DescribeGuildObject(guild) + ". Refreshing all ward guild projections."); RefreshAllWardGuildProjections(liveDisplayRefresh: true); } } } internal readonly struct SyncedWardGuildIdentity { internal bool HasGuild { get; } internal int GuildId { get; } internal string GuildName { get; } internal SyncedWardGuildIdentity(bool hasGuild, int guildId, string guildName) { HasGuild = hasGuild; GuildId = guildId; GuildName = guildName ?? string.Empty; } } internal readonly struct PendingPlayerGuildSync { internal long SenderUid { get; } internal int GuildId { get; } internal string GuildName { get; } internal DateTime FirstSeenUtc { get; } internal PendingPlayerGuildSync(long senderUid, int guildId, string guildName, DateTime firstSeenUtc) { SenderUid = senderUid; GuildId = guildId; GuildName = guildName ?? string.Empty; FirstSeenUtc = firstSeenUtc; } } internal static class ManagedWardPlacementPreviewService { private sealed class PlacementPreviewOverlapState { internal int CandidateInstanceId; internal Vector3 Point; internal long PlayerId; internal int GuildId; internal int SpatialRevision = -1; internal bool BlocksPlacement; internal bool HasValue; } private static readonly PlacementPreviewOverlapState OverlapCache = new PlacementPreviewOverlapState(); internal static bool ShouldShowAsInvalid(Player? player, Component? candidate, Vector3 point) { //IL_00a6: 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) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) if (!WardAccess.IsManagedWardPlacementCandidate(candidate) || (Object)(object)candidate == (Object)null) { return false; } long num = (((Object)(object)player != (Object)null) ? player.GetPlayerID() : 0); int num2 = (((Object)(object)player != (Object)null) ? GuildsCompat.GetPlayerGuildId(player) : 0); int instanceID = ((Object)candidate).GetInstanceID(); int managedWardSpatialIndexRevision = WardAccess.GetManagedWardSpatialIndexRevision(); if (OverlapCache.HasValue && OverlapCache.CandidateInstanceId == instanceID && OverlapCache.PlayerId == num && OverlapCache.GuildId == num2 && OverlapCache.SpatialRevision == managedWardSpatialIndexRevision && PointsMatch(OverlapCache.Point, point)) { return OverlapCache.BlocksPlacement; } bool flag = WardAccess.WouldBlockManagedWardPlacement(player, candidate, point, flash: false); OverlapCache.CandidateInstanceId = instanceID; OverlapCache.Point = point; OverlapCache.PlayerId = num; OverlapCache.GuildId = num2; OverlapCache.SpatialRevision = managedWardSpatialIndexRevision; OverlapCache.BlocksPlacement = flag; OverlapCache.HasValue = true; return flag; } internal static void Invalidate() { OverlapCache.HasValue = false; } private static bool PointsMatch(Vector3 left, Vector3 right) { //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_0013: 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) if (Mathf.Approximately(left.x, right.x)) { return Mathf.Approximately(left.z, right.z); } return false; } } internal static class WardAccess { private sealed class SpatialWardEntry { internal PrivateArea Area { get; } internal int InstanceId { get; } internal SpatialWardEntry(PrivateArea area) { Area = area; InstanceId = ((Object)area).GetInstanceID(); } } internal enum AccessDecision { NoWard, Allowed, Denied } internal readonly struct AccessResult { internal AccessDecision Decision { get; } internal bool IsDenied => Decision == AccessDecision.Denied; internal bool IsCoveredAndAllowed => Decision == AccessDecision.Allowed; internal AccessResult(AccessDecision decision) { Decision = decision; } } private const string NoAccessMessageKey = "$piece_noaccess"; private const float SpatialCellSize = 32f; private static readonly List ManagedWards = new List(); private static readonly List EnabledManagedWards = new List(); private static readonly HashSet ManagedWardIds = new HashSet(); private static readonly HashSet EnabledManagedWardIds = new HashSet(); private static readonly Dictionary> ManagedWardSpatialIndex = new Dictionary>(); private static readonly Dictionary> EnabledManagedWardSpatialIndex = new Dictionary>(); private static readonly Dictionary> ManagedWardSpatialCellsByInstanceId = new Dictionary>(); private static readonly Dictionary> EnabledManagedWardSpatialCellsByInstanceId = new Dictionary>(); private static readonly Dictionary SpatialQueryStamps = new Dictionary(); private static readonly List SpatialQueryBuffer = new List(); private static bool _wardCacheInitialized; private static bool _managedWardSpatialIndexRequiresFullRebuild = true; private static float _managedWardSpatialIndexMaxRadius = -1f; private static int _managedWardSpatialIndexRevision; private static int _spatialQueryStamp; internal static void RegisterManagedWard(PrivateArea? area) { RegisterManagedWard(ManagedWardRef.FromArea(area)); } internal static void RegisterManagedWard(ManagedWardRef ward) { RefreshManagedWardState(ward); } internal static void RefreshManagedWardState(PrivateArea? area) { RefreshManagedWardState(ManagedWardRef.FromArea(area)); } internal static void RefreshManagedWardState(ManagedWardRef ward) { PrivateArea area = ward.Area; if ((Object)(object)area == (Object)null) { return; } EnsureManagedWardCacheInitialized(); if (!IsTrackableManagedWard(ward, requireEnabled: false)) { UnregisterManagedWard(ward); return; } int instanceID = ((Object)area).GetInstanceID(); bool flag = false; bool flag2 = false; if (ManagedWardIds.Add(instanceID)) { ManagedWards.Add(area); flag = true; } if (area.IsEnabled()) { if (EnabledManagedWardIds.Add(instanceID)) { EnabledManagedWards.Add(area); flag2 = true; } } else if (EnabledManagedWardIds.Remove(instanceID)) { EnabledManagedWards.Remove(area); ManagedWardRuntimeContexts.ResetPresenceState(area); flag2 = true; } if (flag || flag2) { UpdateManagedWardSpatialIndexMembership(area, instanceID, flag, flag2); } if (flag2) { ManagedWardRuntimeInvalidationService.PublishWardEnabledChanged(ward, "managed ward enabled membership changed"); } } internal static void UnregisterManagedWard(PrivateArea? area) { UnregisterManagedWard(ManagedWardRef.FromArea(area)); } internal static void UnregisterManagedWard(ManagedWardRef ward) { PrivateArea area = ward.Area; if (!((Object)(object)area == (Object)null)) { int instanceID = ((Object)area).GetInstanceID(); bool flag = false; bool flag2 = false; if (ManagedWardIds.Remove(instanceID)) { ManagedWards.Remove(area); flag = true; } if (EnabledManagedWardIds.Remove(instanceID)) { EnabledManagedWards.Remove(area); flag2 = true; } ManagedWardRuntimeContexts.ResetPresenceState(area); if (flag || flag2) { UpdateManagedWardSpatialIndexMembership(area, instanceID, flag, flag2); } if (flag2) { ManagedWardRuntimeInvalidationService.PublishWardEnabledChanged(ward, "managed ward unregistered"); } } } internal static bool HasEnabledManagedWards() { EnsureManagedWardCacheInitialized(); return EnabledManagedWardIds.Count > 0; } internal static void InvalidateWardPresenceCache() { ManagedWardRuntimeInvalidationService.PublishPresencePolicyChanged("ward presence cache invalidated"); } internal static void InvalidateManagedWardSpatialIndex() { if (_managedWardSpatialIndexRequiresFullRebuild) { ManagedWardRuntimeInvalidationService.PublishSpatialIndexChanged("managed ward spatial index rebuild already pending"); return; } _managedWardSpatialIndexRequiresFullRebuild = true; BumpManagedWardSpatialRevision(); ManagedWardRuntimeInvalidationService.PublishSpatialIndexChanged("managed ward spatial index invalidated"); } internal static void RefreshManagedWardSpatialIndexEntry(PrivateArea? area) { RefreshManagedWardSpatialIndexEntry(ManagedWardRef.FromArea(area)); } internal static void RefreshManagedWardSpatialIndexEntry(ManagedWardRef ward) { PrivateArea area = ward.Area; if ((Object)(object)area == (Object)null) { return; } EnsureManagedWardCacheInitialized(); if (_managedWardSpatialIndexRequiresFullRebuild || !Mathf.Approximately(_managedWardSpatialIndexMaxRadius, WardSettings.MaxRadius)) { if (!_managedWardSpatialIndexRequiresFullRebuild) { _managedWardSpatialIndexRequiresFullRebuild = true; BumpManagedWardSpatialRevision(); } ManagedWardRuntimeInvalidationService.PublishSpatialIndexChanged("managed ward spatial index requires rebuild"); return; } int instanceID = ((Object)area).GetInstanceID(); bool flag = ManagedWardIds.Contains(instanceID); bool flag2 = EnabledManagedWardIds.Contains(instanceID); if (flag || flag2) { UpdateManagedWardSpatialIndexMembership(area, instanceID, flag, flag2); } } internal static void ResetManagedWardCache() { ManagedWards.Clear(); EnabledManagedWards.Clear(); ManagedWardIds.Clear(); EnabledManagedWardIds.Clear(); ManagedWardSpatialIndex.Clear(); EnabledManagedWardSpatialIndex.Clear(); ManagedWardSpatialCellsByInstanceId.Clear(); EnabledManagedWardSpatialCellsByInstanceId.Clear(); SpatialQueryStamps.Clear(); SpatialQueryBuffer.Clear(); ManagedWardRuntimeInvalidationService.ResetPresence(); _wardCacheInitialized = false; _managedWardSpatialIndexRequiresFullRebuild = true; _managedWardSpatialIndexMaxRadius = -1f; _managedWardSpatialIndexRevision = 0; _spatialQueryStamp = 0; ManagedWardRuntimeInvalidationService.PublishSpatialIndexChanged("managed ward cache reset"); } internal static void UpdateTrustedPlayerPresenceSweep() { ManagedWardPresenceService.Update(); } internal static IReadOnlyList GetManagedWards(bool requireEnabled) { EnsureManagedWardCacheInitialized(); if (!requireEnabled) { return ManagedWards; } return EnabledManagedWards; } internal static bool CheckAccess(Vector3 point, float radius, long playerId, bool flash = true, bool wardCheck = false) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return !EvaluateAccess(point, radius, playerId, flash, wardCheck).IsDenied; } internal static AccessResult EvaluateAccess(Vector3 point, float radius, long playerId, bool flash = true, bool wardCheck = false) { //IL_0000: 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) IReadOnlyList candidateManagedWards = GetCandidateManagedWards(point, radius, requireEnabled: true); return EvaluateAccessAgainstCandidates(point, radius, playerId, candidateManagedWards, flash, wardCheck); } internal static AccessResult EvaluateAccessAgainstCandidates(Vector3 point, float radius, long playerId, IReadOnlyList areas, bool flash = true, bool wardCheck = false) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) if (areas.Count == 0) { return new AccessResult(AccessDecision.NoWard); } bool includeDiagnosticData = Plugin.ShouldLogWardDiagnosticVerbose(); ManagedWardAccessActor actor; bool flag = ManagedWardAccessEvaluator.TryCreateActorForAccessCheck(playerId, out actor); bool flag2 = false; bool flag3 = false; List list = null; foreach (PrivateArea area in areas) { if ((Object)(object)area == (Object)null || !area.IsInside(point, radius)) { continue; } flag2 = true; if (flag && ManagedWardAccessEvaluator.HasPlayerAccess(area, actor, includeDiagnosticData)) { continue; } flag3 = true; if (flash) { if (list == null) { list = new List(); } list.Add(area); } if (wardCheck) { break; } } if (!flag2) { return new AccessResult(AccessDecision.NoWard); } if (!flag3) { return new AccessResult(AccessDecision.Allowed); } if (list != null) { foreach (PrivateArea item in list) { item.FlashShield(false); } } return new AccessResult(AccessDecision.Denied); } internal static int CollectDeniedManagedWardCandidates(long playerId, IReadOnlyList areas, List deniedAreas) { deniedAreas.Clear(); if (playerId == 0L || areas.Count == 0) { return 0; } bool includeDiagnosticData = Plugin.ShouldLogWardDiagnosticVerbose(); ManagedWardAccessActor actor = ManagedWardAccessEvaluator.CreateActor(playerId); foreach (PrivateArea area in areas) { if (!((Object)(object)area == (Object)null) && !ManagedWardAccessEvaluator.HasPlayerAccess(area, actor, includeDiagnosticData)) { deniedAreas.Add(area); } } return deniedAreas.Count; } internal static bool IsInsideAnyManagedWard(Vector3 point, float radius, IReadOnlyList areas) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < areas.Count; i++) { PrivateArea val = areas[i]; if ((Object)(object)val != (Object)null && val.IsInside(point, radius)) { return true; } } return false; } internal static bool TryBlockInteraction(Component target, Player? player, ref bool result) { bool flag = ShouldBlock(target, player, 0f); LogLocalInteractionAttemptVerbose("Interaction", target, player, flag); if (!flag) { return true; } ShowNoAccessMessage(player); result = true; return false; } internal static bool TryBlockAction(Component target, Player? player, ref bool result) { bool flag = ShouldBlock(target, player, 0f); LogLocalInteractionAttemptVerbose("Action", target, player, flag); if (!flag) { return true; } ShowNoAccessMessage(player); result = false; return false; } internal static bool TryBlockVoid(Component target, Player? player) { bool flag = ShouldBlock(target, player, 0f); LogLocalInteractionAttemptVerbose("Void", target, player, flag); if (!flag) { return true; } ShowNoAccessMessage(player); return false; } internal static bool TryBlockPlacement(Player? player, Vector3 point, float radius, ref bool result) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if (!ShouldBlock(point, radius, player)) { return true; } ShowNoAccessMessage(player); result = false; return false; } internal static bool TryBlockPlacement(Player? player, Vector3 point, float radius) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if (!ShouldBlock(point, radius, player)) { return true; } ShowNoAccessMessage(player); return false; } internal static bool TryBlockItemUse(Player? player, ItemData? item, ref bool result) { if (!ShouldBlockConfiguredItemUse(player, item)) { return true; } ShowBlockedItemMessage(player); result = false; return false; } internal static bool TryBlockItemUse(Player? player, ItemData? item) { if (!ShouldBlockConfiguredItemUse(player, item)) { return true; } ShowBlockedItemMessage(player); return false; } internal static bool TryBlockItemUse(Player? player, ItemData? item, Vector3 targetPoint) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) if (!ShouldBlockConfiguredItemUse(player, item, targetPoint)) { return true; } ShowBlockedItemMessage(player); return false; } internal static bool TryForceUnequipBlockedItems(Player? player) { //IL_0087: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer) { return false; } if (!HasEnabledManagedWards()) { return false; } Inventory inventory = ((Humanoid)player).GetInventory(); if (inventory == null) { return false; } List inventory2 = inventory.m_inventory; if (inventory2 == null || inventory2.Count == 0) { return false; } bool flag = false; for (int i = 0; i < inventory2.Count; i++) { ItemData val = inventory2[i]; if (val != null && val.m_equipped && IsConfiguredBlockedItem(val)) { flag = true; break; } } if (!flag) { return false; } if (!ShouldBlock(((Component)player).transform.position, 0f, player, flash: false)) { return false; } bool flag2 = false; for (int j = 0; j < inventory2.Count; j++) { ItemData val2 = inventory2[j]; if (val2 != null && val2.m_equipped && IsConfiguredBlockedItem(val2)) { ((Humanoid)player).UnequipItem(val2, false); flag2 = true; } } if (flag2) { ShowBlockedItemMessage(player); } return flag2; } internal static bool TryBlockAttack(Player? player, ref bool result) { return TryBlockAttack(player, (player != null) ? ((Humanoid)player).GetCurrentWeapon() : null, ref result); } internal static bool TryBlockAttack(Player? player, ItemData? item, ref bool result) { if (!ShouldBlockConfiguredItemUse(player, item) && !ShouldBlockConfiguredItemUseAgainstHoveredTamedCreature(player, item)) { return true; } if (!TryForceUnequipBlockedItems(player)) { ShowBlockedItemMessage(player); } result = false; return false; } internal static bool ShouldBlock(Component? target, Player? player, float radius, bool flash = true) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)target == (Object)null) { return false; } return ShouldBlock(target.transform.position, radius, player, flash); } internal static bool ShouldBlock(Vector3 point, float radius, Player? player, bool flash = true) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null) { return false; } if (!HasEnabledManagedWards()) { return false; } return EvaluateAccess(point, radius, player.GetPlayerID(), flash).IsDenied; } internal static bool ShouldBlockPickup(GameObject? go, Player? player) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)go == (Object)null || !WardItemPrefabPolicy.CanAnyPickupBeBlocked()) { return false; } if (WardItemPrefabPolicy.ShouldBlockPickup(go)) { return ShouldBlock(go.transform.position, 0f, player); } return false; } internal static bool ShouldBlockPickup(ItemDrop? itemDrop, Player? player) { if ((Object)(object)itemDrop == (Object)null || !WardItemPrefabPolicy.CanAnyPickupBeBlocked()) { return false; } if (WardItemPrefabPolicy.ShouldBlockPickup(itemDrop)) { return ShouldBlock((Component?)(object)itemDrop, player, 0f); } return false; } internal static void ShowNoAccessMessage(Player? player) { if (!((Object)(object)player == (Object)null) && !((Object)(object)player != (Object)(object)Player.m_localPlayer)) { ((Character)player).Message((MessageType)2, "$piece_noaccess", 0, (Sprite)null); } } private static void LogLocalInteractionAttemptVerbose(string context, Component? target, Player? player, bool blocked) { //IL_0071: Unknown result type (might be due to invalid IL or missing references) if (Plugin.ShouldLogWardDiagnosticVerbose() && !((Object)(object)target == (Object)null) && !((Object)(object)player == (Object)null)) { long playerID = player.GetPlayerID(); Plugin.LogWardDiagnosticVerbose("Access." + context, $"Evaluated local interaction before server handling. blocked={blocked}, targetType={((object)target).GetType().Name}, targetName='{((Object)target).name}', playerId={playerID}, playerName='{player.GetPlayerName()}', position={target.transform.position}"); } } internal static void ShowBlockedItemMessage(Player? player) { if (!((Object)(object)player == (Object)null) && !((Object)(object)player != (Object)(object)Player.m_localPlayer)) { ((Character)player).Message((MessageType)2, WardLocalization.Localize("$stuw_msg_blocked_item", "A ward prevents using this item here."), 0, (Sprite)null); } } internal static void ShowProtectedBuildingDamageMessage(Player? player) { if (!((Object)(object)player == (Object)null) && !((Object)(object)player != (Object)(object)Player.m_localPlayer)) { ((Character)player).Message((MessageType)2, WardLocalization.Localize("$stuw_msg_building_damage_protected", "An active Ward prevents damaging protected structures."), 0, (Sprite)null); } } internal static void ShowWardOverlapMessage(Player? player) { if (!((Object)(object)player == (Object)null) && !((Object)(object)player != (Object)(object)Player.m_localPlayer)) { ((Character)player).Message((MessageType)2, WardLocalization.Localize("$stuw_msg_overlap", "Another Ward is too close."), 0, (Sprite)null); } } internal static void ShowWardLimitMessage(Player? player, int limit) { if (!((Object)(object)player == (Object)null) && !((Object)(object)player != (Object)(object)Player.m_localPlayer)) { string text = WardLocalization.LocalizeFormat("$stuw_msg_limit_with_max", "Ward limit reached (max {0})", limit); ((Character)player).Message((MessageType)2, text, 0, (Sprite)null); } } internal static Player? GetPlayer(Humanoid? humanoid) { return (Player?)(object)((humanoid is Player) ? humanoid : null); } internal static Player? GetPlayer(Collider? collider) { if ((Object)(object)collider == (Object)null) { return null; } return ((Component)collider).GetComponentInParent(); } internal static float GetTerrainRadius(GameObject? prefab) { if ((Object)(object)prefab == (Object)null) { return 0f; } TerrainModifier component = prefab.GetComponent(); if ((Object)(object)component != (Object)null) { return component.GetRadius(); } TerrainOp component2 = prefab.GetComponent(); if (!((Object)(object)component2 != (Object)null)) { return 0f; } return component2.GetRadius(); } internal static bool IsRelevantWard(PrivateArea? area) { return IsManagedWard(area, requireEnabled: true); } internal static bool IsManagedWard(PrivateArea? area, bool requireEnabled) { return IsManagedWard(ManagedWardRef.FromArea(area), requireEnabled); } internal static bool IsManagedWard(ManagedWardRef ward, bool requireEnabled) { return IsTrackableManagedWard(ward, requireEnabled); } internal static bool CanConfigureWard(PrivateArea? area, Player? player) { return CanConfigureWard(ManagedWardRef.FromArea(area), player); } internal static bool CanConfigureWard(ManagedWardRef ward, Player? player) { if ((Object)(object)ward.Area == (Object)null || (Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer || !IsManagedWard(ward, requireEnabled: false)) { return false; } if (!IsDirectWardOwner(ward, player.GetPlayerID())) { return WardAdminDebugAccess.CanLocallyControlAnyWard(ward.Area, player); } return true; } internal static bool CanControlManagedWard(PrivateArea? area, long playerId) { return CanControlManagedWard(ManagedWardRef.FromArea(area), playerId); } internal static bool CanControlManagedWard(ManagedWardRef ward, long playerId) { if ((Object)(object)ward.Area == (Object)null || playerId == 0L || !IsManagedWard(ward, requireEnabled: false)) { return false; } if (!IsDirectWardOwner(ward, playerId)) { return WardAdminDebugAccess.IsPlayerAdminDebugController(playerId); } return true; } internal static bool IsDirectWardOwner(PrivateArea? area, Player? player) { if ((Object)(object)area != (Object)null && (Object)(object)player != (Object)null) { return IsDirectWardOwner(area, player.GetPlayerID()); } return false; } internal static bool IsDirectWardOwner(PrivateArea? area, long playerId) { return IsDirectWardOwner(ManagedWardRef.FromArea(area), playerId); } internal static bool IsDirectWardOwner(ManagedWardRef ward, long playerId) { if ((Object)(object)ward.Area == (Object)null || playerId == 0L || !IsManagedWard(ward, requireEnabled: false)) { return false; } return GetCanonicalCreatorPlayerId(ward.Area) == playerId; } internal static bool IsPlayerInWardGuild(Player? player, PrivateArea? area) { return IsPlayerGuildMatchingWardGuild(GuildsCompat.GetPlayerGuildIdentity(player), GuildsCompat.GetWardGuildIdentity(area)); } internal static bool IsPlayerIdInWardGuild(long playerId, PrivateArea? area) { if (playerId == 0L) { return false; } return IsPlayerGuildMatchingWardGuild(GuildsCompat.GetPlayerGuildIdentity(playerId), GuildsCompat.GetWardGuildIdentity(area)); } internal static bool IsPlayerIdInWardGuild(long playerId, ZDO? zdo) { if (playerId == 0L) { return false; } return IsPlayerGuildMatchingWardGuild(GuildsCompat.GetPlayerGuildIdentity(playerId), GuildsCompat.GetWardGuildIdentity(zdo)); } internal static bool IsPlayerGuildMatchingWardGuild(WardGuildIdentity playerGuild, WardGuildIdentity wardGuild) { return ManagedWardAccessEvaluator.HasMatchingGuild(playerGuild, wardGuild); } internal static bool ShouldBlockHostileCreatureDamageToBuilding(Vector3 point) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return ManagedWardPresenceService.ShouldBlockHostileCreatureDamageToBuilding(point); } internal static bool TryBlockManagedWardPlacement(Player? player, Component? candidate, Vector3 point, ref bool result) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) if (!IsManagedWardPlacementCandidate(candidate)) { return true; } if (!WouldBlockManagedWardPlacement(player, candidate, point, flash: true)) { return true; } ShowWardOverlapMessage(player); result = false; return false; } internal static bool TryBlockManagedWardPlacement(Player? player, Component? candidate, Vector3 point) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) if (!IsManagedWardPlacementCandidate(candidate)) { return true; } if (!WouldBlockManagedWardPlacement(player, candidate, point, flash: true)) { return true; } ShowWardOverlapMessage(player); return false; } internal static float GetMaxNonOverlappingRadius(PrivateArea? area) { return GetMaxNonOverlappingRadius(area, WardSettings.MaxRadius); } internal static float GetMaxNonOverlappingRadius(PrivateArea? area, float fallbackRadius) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) long canonicalCreatorPlayerId = GetCanonicalCreatorPlayerId(area); int guildId = (GuildsCompat.IsAvailable() ? GuildsCompat.GetWardGuildId(area) : 0); if (!((Object)(object)area == (Object)null)) { return GetMaxNonOverlappingRadius(((Component)area).transform.position, canonicalCreatorPlayerId, guildId, area, fallbackRadius); } return fallbackRadius; } internal static float GetMaxNonOverlappingRadius(Vector3 point, long ownerCreatorPlayerId, int guildId, PrivateArea? ignoredWard, float fallbackRadius) { //IL_0000: 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) IReadOnlyList candidateManagedWards = GetCandidateManagedWards(point, fallbackRadius, requireEnabled: false); if (candidateManagedWards.Count == 0) { return fallbackRadius; } return WardOverlapPolicy.GetMaxNonOverlappingRadius(fallbackRadius, CreateWardOverlapQuery(point, fallbackRadius, ownerCreatorPlayerId, guildId, ignoredWard), BuildWardOverlapAreas(candidateManagedWards, guildId)); } internal static long GetCanonicalCreatorPlayerId(PrivateArea? area) { long wardCreatorId = GetWardCreatorId(area); if (wardCreatorId != 0L) { return wardCreatorId; } Piece val = (((Object)(object)area?.m_piece != (Object)null) ? area.m_piece : ((area != null) ? ((Component)area).GetComponent() : null)); if (!((Object)(object)val != (Object)null)) { return 0L; } return val.GetCreator(); } internal static long GetWardCreatorId(PrivateArea? area) { return ManagedWardRef.FromArea(area).CreatorPlayerId; } internal static PrivateArea? FindNearestManagedWard(Vector3 point, float radius = 0f, bool requireEnabled = true, Predicate? predicate = null) { //IL_0000: 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_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) IReadOnlyList candidateManagedWards = GetCandidateManagedWards(point, radius, requireEnabled); if (candidateManagedWards.Count == 0) { return null; } PrivateArea result = null; float num = float.MaxValue; foreach (PrivateArea item in candidateManagedWards) { if (!((Object)(object)item == (Object)null) && item.IsInside(point, radius) && (predicate == null || predicate(item))) { float num2 = Utils.DistanceXZ(((Component)item).transform.position, point); if (!(num2 >= num)) { num = num2; result = item; } } } return result; } internal static bool HasPlayerAccessToManagedWardZdo(ZDO? zdo, long playerId) { return ManagedWardAccessEvaluator.HasPlayerAccessToManagedWardZdo(zdo, playerId); } internal static bool HasPlayerAccessToManagedWardZdo(ZDO? zdo, long playerId, WardGuildIdentity playerGuild) { return ManagedWardAccessEvaluator.HasPlayerAccessToManagedWardZdo(zdo, playerId, playerGuild); } internal static bool HasPlayerAccessToManagedWardIndexEntry(WardMinimapVisibilityIndexedEntry entry, long playerId, WardGuildIdentity playerGuild) { return ManagedWardAccessEvaluator.HasPlayerAccessToManagedWardIndexEntry(entry, playerId, playerGuild); } internal static bool HasMatchingGuild(WardGuildIdentity playerGuild, WardGuildIdentity wardGuild) { return ManagedWardAccessEvaluator.HasMatchingGuild(playerGuild, wardGuild); } private static bool ShouldBlockConfiguredItemUse(Player? player, ItemData? item) { return ShouldBlockConfiguredItemUse(player, item, null); } private static bool ShouldBlockConfiguredItemUse(Player? player, ItemData? item, Vector3? targetPoint) { //IL_0027: 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) if ((Object)(object)player == (Object)null || item == null) { return false; } if (!HasEnabledManagedWards()) { return false; } if (!IsConfiguredBlockedItem(item)) { return false; } if (ShouldBlock(((Component)player).transform.position, 0f, player)) { return true; } if (targetPoint.HasValue) { return ShouldBlock(targetPoint.Value, 0f, player); } return false; } private static bool ShouldBlockConfiguredItemUseAgainstHoveredTamedCreature(Player? player, ItemData? item) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) if (TryGetHoveredTamedCreaturePoint(player, out var targetPoint)) { return ShouldBlockConfiguredItemUse(player, item, targetPoint); } return false; } private static bool IsConfiguredBlockedItem(ItemData? item) { if (item == null) { return false; } return WardItemPrefabPolicy.IsBlockedItem(item); } private static bool TryGetHoveredTamedCreaturePoint(Player? player, out Vector3 targetPoint) { //IL_0001: 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_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) targetPoint = default(Vector3); if ((Object)(object)player == (Object)null) { return false; } Character hoveringCreature = player.m_hoveringCreature; if ((Object)(object)hoveringCreature != (Object)null && hoveringCreature.IsTamed()) { targetPoint = ((Component)hoveringCreature).transform.position; return true; } try { Character val = null; GameObject val2 = null; player.FindHoverObject(ref val2, ref val); if ((Object)(object)val == (Object)null || !val.IsTamed()) { return false; } targetPoint = ((Component)val).transform.position; return true; } catch { return false; } } internal static bool WouldBlockManagedWardPlacement(Player? player, Component? candidate, Vector3 point, bool flash) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null) { return false; } if (!StuWardArea.IsManaged(((Object)(object)candidate != (Object)null) ? (candidate.GetComponent() ?? candidate.GetComponentInParent()) : null)) { return false; } float radius = 8f; return OverlapsForeignManagedWard(point, radius, player.GetPlayerID(), GuildsCompat.GetPlayerGuildId(player), null, flash); } private static bool OverlapsForeignManagedWard(Vector3 point, float radius, long ownerCreatorPlayerId, int guildId, PrivateArea? ignoredWard, bool flash) { //IL_000d: 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) List list = (flash ? new List() : null); IReadOnlyList candidateManagedWards = GetCandidateManagedWards(point, radius, requireEnabled: false); if (candidateManagedWards.Count == 0) { return false; } bool flag = false; WardOverlapQuery query = CreateWardOverlapQuery(point, radius, ownerCreatorPlayerId, guildId, ignoredWard); foreach (PrivateArea item in candidateManagedWards) { if (!((Object)(object)item == (Object)null) && !((Object)(object)item == (Object)(object)ignoredWard)) { WardOverlapArea area = CreateWardOverlapArea(item, guildId); if (!WardOverlapPolicy.SharesTrustedWardGroup(area, query) && WardOverlapPolicy.Overlaps(query, area)) { flag = true; list?.Add(item); } } } if (!flag || list == null) { return flag; } foreach (PrivateArea item2 in list) { ZNetView nView = WardPrivateAreaSafeAccess.GetNView(item2); if (!((Object)(object)nView == (Object)null) && nView.IsValid()) { item2.FlashShield(false); } } return true; } private static WardOverlapQuery CreateWardOverlapQuery(Vector3 point, float radius, long ownerCreatorPlayerId, int guildId, PrivateArea? ignoredWard) { //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) return new WardOverlapQuery(point.x, point.z, radius, ownerCreatorPlayerId, guildId, ((Object)(object)ignoredWard != (Object)null) ? ((Object)ignoredWard).GetInstanceID() : 0); } private static List BuildWardOverlapAreas(IReadOnlyList areas, int queryGuildId) { List list = new List(areas.Count); for (int i = 0; i < areas.Count; i++) { PrivateArea val = areas[i]; if ((Object)(object)val != (Object)null) { list.Add(CreateWardOverlapArea(val, queryGuildId)); } } return list; } private static WardOverlapArea CreateWardOverlapArea(PrivateArea area, int queryGuildId) { //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_0012: 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) Vector3 position = ((Component)area).transform.position; return new WardOverlapArea(((Object)area).GetInstanceID(), position.x, position.z, WardSettings.GetStoredRadiusOrMin(area), GetCanonicalCreatorPlayerId(area), (queryGuildId != 0 && GuildsCompat.IsAvailable()) ? GuildsCompat.GetWardGuildId(area) : 0); } internal static int GetManagedWardSpatialIndexRevision() { return _managedWardSpatialIndexRevision; } internal static bool IsManagedWardPlacementCandidate(Component? candidate) { return StuWardArea.IsManaged(((Object)(object)candidate != (Object)null) ? (candidate.GetComponent() ?? candidate.GetComponentInParent()) : null); } private static void EnsureManagedWardCacheInitialized() { if (_wardCacheInitialized) { return; } _wardCacheInitialized = true; ManagedWards.Clear(); EnabledManagedWards.Clear(); ManagedWardIds.Clear(); EnabledManagedWardIds.Clear(); List allAreas = PrivateArea.m_allAreas; if (allAreas == null) { return; } for (int i = 0; i < allAreas.Count; i++) { PrivateArea val = allAreas[i]; if (IsTrackableManagedWard(val, requireEnabled: false)) { int instanceID = ((Object)val).GetInstanceID(); ManagedWardIds.Add(instanceID); ManagedWards.Add(val); if (val.IsEnabled()) { EnabledManagedWardIds.Add(instanceID); EnabledManagedWards.Add(val); } } } _managedWardSpatialIndexRequiresFullRebuild = true; } private static bool IsTrackableManagedWard(PrivateArea? area, bool requireEnabled) { return IsTrackableManagedWard(ManagedWardRef.FromArea(area), requireEnabled); } private static bool IsTrackableManagedWard(ManagedWardRef ward, bool requireEnabled) { PrivateArea area = ward.Area; if ((Object)(object)area == (Object)null || ward.IsPlacementGhost || !ManagedWardIdentity.EnsureManagedComponent(ward)) { return false; } if (requireEnabled && !area.IsEnabled()) { return false; } return ward.HasValidNetworkIdentity; } internal static IReadOnlyList GetCandidateManagedWards(Vector3 point, float radius, bool requireEnabled) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) FillCandidateManagedWards(point, radius, requireEnabled, SpatialQueryBuffer); return SpatialQueryBuffer; } internal static void FillCandidateManagedWards(Vector3 point, float radius, bool requireEnabled, List destination) { //IL_0036: 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_0051: 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) EnsureManagedWardSpatialIndexInitialized(); destination.Clear(); Dictionary> dictionary = (requireEnabled ? EnabledManagedWardSpatialIndex : ManagedWardSpatialIndex); if (dictionary.Count == 0) { return; } int num = NextSpatialQueryStamp(); float num2 = Mathf.Max(0f, radius); int spatialCellCoordinate = GetSpatialCellCoordinate(point.x - num2); int spatialCellCoordinate2 = GetSpatialCellCoordinate(point.x + num2); int spatialCellCoordinate3 = GetSpatialCellCoordinate(point.z - num2); int spatialCellCoordinate4 = GetSpatialCellCoordinate(point.z + num2); for (int i = spatialCellCoordinate; i <= spatialCellCoordinate2; i++) { for (int j = spatialCellCoordinate3; j <= spatialCellCoordinate4; j++) { if (!dictionary.TryGetValue(GetSpatialCellKey(i, j), out var value)) { continue; } for (int k = 0; k < value.Count; k++) { SpatialWardEntry spatialWardEntry = value[k]; if (!SpatialQueryStamps.TryGetValue(spatialWardEntry.InstanceId, out var value2) || value2 != num) { SpatialQueryStamps[spatialWardEntry.InstanceId] = num; destination.Add(spatialWardEntry.Area); } } } } } private static void EnsureManagedWardSpatialIndexInitialized() { EnsureManagedWardCacheInitialized(); float maxRadius = WardSettings.MaxRadius; if (_managedWardSpatialIndexRequiresFullRebuild || !Mathf.Approximately(_managedWardSpatialIndexMaxRadius, maxRadius)) { ManagedWardSpatialIndex.Clear(); EnabledManagedWardSpatialIndex.Clear(); ManagedWardSpatialCellsByInstanceId.Clear(); EnabledManagedWardSpatialCellsByInstanceId.Clear(); SpatialQueryStamps.Clear(); SpatialQueryBuffer.Clear(); BuildManagedWardSpatialIndex(ManagedWards, ManagedWardSpatialIndex, ManagedWardSpatialCellsByInstanceId, requireEnabled: false); BuildManagedWardSpatialIndex(EnabledManagedWards, EnabledManagedWardSpatialIndex, EnabledManagedWardSpatialCellsByInstanceId, requireEnabled: true); _managedWardSpatialIndexRequiresFullRebuild = false; _managedWardSpatialIndexMaxRadius = maxRadius; } } private static void BuildManagedWardSpatialIndex(IReadOnlyList areas, Dictionary> spatialIndex, Dictionary> occupiedCellsByInstanceId, bool requireEnabled) { for (int i = 0; i < areas.Count; i++) { PrivateArea area = areas[i]; if (IsTrackableManagedWard(area, requireEnabled)) { AddAreaToSpatialIndex(area, spatialIndex, occupiedCellsByInstanceId); } } } private static void UpdateManagedWardSpatialIndexMembership(PrivateArea area, int instanceId, bool managedMembershipChanged, bool enabledMembershipChanged) { EnsureManagedWardCacheInitialized(); if (_managedWardSpatialIndexRequiresFullRebuild || !Mathf.Approximately(_managedWardSpatialIndexMaxRadius, WardSettings.MaxRadius)) { if (!_managedWardSpatialIndexRequiresFullRebuild) { _managedWardSpatialIndexRequiresFullRebuild = true; if (managedMembershipChanged) { BumpManagedWardSpatialRevision(); } } if (managedMembershipChanged) { ManagedWardRuntimeInvalidationService.PublishSpatialIndexChanged("managed ward spatial index deferred rebuild"); } } else { if (managedMembershipChanged) { UpdateAreaInSpatialIndex(area, instanceId, ManagedWardIds.Contains(instanceId), ManagedWardSpatialIndex, ManagedWardSpatialCellsByInstanceId, requireEnabled: false); BumpManagedWardSpatialRevision(); ManagedWardRuntimeInvalidationService.PublishSpatialIndexChanged("managed ward spatial index membership changed"); } if (enabledMembershipChanged) { UpdateAreaInSpatialIndex(area, instanceId, EnabledManagedWardIds.Contains(instanceId), EnabledManagedWardSpatialIndex, EnabledManagedWardSpatialCellsByInstanceId, requireEnabled: true); } } } private static void UpdateAreaInSpatialIndex(PrivateArea area, int instanceId, bool shouldContain, Dictionary> spatialIndex, Dictionary> occupiedCellsByInstanceId, bool requireEnabled) { RemoveAreaFromSpatialIndex(instanceId, spatialIndex, occupiedCellsByInstanceId); if (shouldContain && IsTrackableManagedWard(area, requireEnabled)) { AddAreaToSpatialIndex(area, spatialIndex, occupiedCellsByInstanceId); } } private static void AddAreaToSpatialIndex(PrivateArea area, Dictionary> spatialIndex, Dictionary> occupiedCellsByInstanceId) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_001f: 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_003c: Unknown result type (might be due to invalid IL or missing references) Vector3 position = ((Component)area).transform.position; float radius = WardSettings.GetRadius(area); SpatialWardEntry spatialWardEntry = new SpatialWardEntry(area); List list = new List(); int spatialCellCoordinate = GetSpatialCellCoordinate(position.x - radius); int spatialCellCoordinate2 = GetSpatialCellCoordinate(position.x + radius); int spatialCellCoordinate3 = GetSpatialCellCoordinate(position.z - radius); int spatialCellCoordinate4 = GetSpatialCellCoordinate(position.z + radius); for (int i = spatialCellCoordinate; i <= spatialCellCoordinate2; i++) { for (int j = spatialCellCoordinate3; j <= spatialCellCoordinate4; j++) { long spatialCellKey = GetSpatialCellKey(i, j); if (!spatialIndex.TryGetValue(spatialCellKey, out List value)) { value = (spatialIndex[spatialCellKey] = new List()); } value.Add(spatialWardEntry); list.Add(spatialCellKey); } } occupiedCellsByInstanceId[spatialWardEntry.InstanceId] = list; } private static void RemoveAreaFromSpatialIndex(int instanceId, Dictionary> spatialIndex, Dictionary> occupiedCellsByInstanceId) { if (!occupiedCellsByInstanceId.TryGetValue(instanceId, out List value)) { return; } for (int i = 0; i < value.Count; i++) { long key = value[i]; if (!spatialIndex.TryGetValue(key, out List value2)) { continue; } for (int num = value2.Count - 1; num >= 0; num--) { if (value2[num].InstanceId == instanceId) { value2.RemoveAt(num); } } if (value2.Count == 0) { spatialIndex.Remove(key); } } occupiedCellsByInstanceId.Remove(instanceId); } private static void BumpManagedWardSpatialRevision() { _managedWardSpatialIndexRevision = ((_managedWardSpatialIndexRevision == int.MaxValue) ? 1 : (_managedWardSpatialIndexRevision + 1)); } private static int GetSpatialCellCoordinate(float coordinate) { return Mathf.FloorToInt(coordinate / 32f); } private static long GetSpatialCellKey(int cellX, int cellZ) { return ((long)cellX << 32) ^ (uint)cellZ; } private static int NextSpatialQueryStamp() { if (_spatialQueryStamp == int.MaxValue) { _spatialQueryStamp = 1; SpatialQueryStamps.Clear(); return _spatialQueryStamp; } _spatialQueryStamp++; return _spatialQueryStamp; } } internal sealed class WardGuiController : MonoBehaviour { private sealed class PermittedRowView { internal GameObject Root { get; } internal Text NameText { get; } internal int LastSeenGeneration { get; set; } internal PermittedRowView(GameObject root, Text nameText) { Root = root; NameText = nameText; } } private sealed class SliderCommitHandler : MonoBehaviour, IEndDragHandler, IEventSystemHandler, IPointerUpHandler { internal Action? OnCommit { get; set; } public void OnEndDrag(PointerEventData eventData) { OnCommit?.Invoke(); } public void OnPointerUp(PointerEventData eventData) { OnCommit?.Invoke(); } } [CompilerGenerated] private sealed class d__52 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Door door; public float delay; public WardGuiController <>4__this; private int 5__2; object? IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object? IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__52(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown //IL_00c9: Unknown result type (might be due to invalid IL or missing references) int num = <>1__state; WardGuiController wardGuiController = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; 5__2 = ((Object)door).GetInstanceID(); <>2__current = (object)new WaitForSeconds(delay); <>1__state = 1; return true; case 1: { <>1__state = -1; wardGuiController._doorCloseCoroutines.Remove(5__2); if ((Object)(object)door == (Object)null || door.m_canNotBeClosed) { return false; } ZNetView val = (((Object)(object)door.m_nview != (Object)null) ? door.m_nview : ((Component)door).GetComponent()); if ((Object)(object)val == (Object)null || !val.IsValid()) { return false; } if (!WardSettings.TryGetAutoCloseDoorDelay(((Component)door).transform.position, out var _)) { return false; } ZDO zDO = val.GetZDO(); if (zDO == null || zDO.GetInt(ZDOVars.s_state, 0) == 0) { return false; } val.InvokeRPC("UseDoor", new object[1] { true }); 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 ConfigurationPushDebounceSeconds = 0.15f; private const float ConfigurationRequestTimeoutSeconds = 5f; private readonly Dictionary _doorCloseCoroutines = new Dictionary(); private readonly Dictionary _permittedRows = new Dictionary(); private readonly List _permittedRowsToRemove = new List(); private PrivateArea? _currentWard; private WardConfiguration _currentConfiguration; private WardConfiguration _authoritativeConfiguration; private WardConfiguration _pendingConfiguration; private GameObject? _root; private GameObject? _hintRoot; private GameObject? _panel; private RectTransform? _permittedContent; private Text? _ownerValueText; private Text? _guildValueText; private Text? _shortcutHintText; private Text? _areaMarkerSpeedValueText; private Text? _areaMarkerAlphaValueText; private Text? _radiusValueText; private Text? _delayValueText; private Slider? _areaMarkerSpeedSlider; private Slider? _areaMarkerAlphaSlider; private Slider? _autoCloseDelaySlider; private Slider? _radiusSlider; private Toggle? _warningSoundToggle; private Toggle? _warningFlashToggle; private Image? _radiusLimitMarker; private bool _visible; private bool _suppressUiEvents; private bool _configurationCommitPending; private bool _configurationPushPending; private bool _layoutRebuildPending; private float _nextConfigurationPushTime; private float _pendingConfigurationRequestedAt; private int _lastPermittedRevision = int.MinValue; private int _permittedRefreshGeneration; private long _pendingConfigurationRequestId; private PermittedRowView? _emptyPermittedRow; internal static WardGuiController? Instance { get; private set; } internal bool IsVisible => _visible; private void Awake() { if ((Object)(object)Instance != (Object)null && (Object)(object)Instance != (Object)(object)this) { Object.Destroy((Object)(object)this); return; } Instance = this; Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); GUIManager.OnCustomGUIAvailable += BuildGui; BuildGui(); } private void OnDestroy() { GUIManager.OnCustomGUIAvailable -= BuildGui; GUIManager.BlockInput(false); _doorCloseCoroutines.Clear(); if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } } private void Update() { if (_layoutRebuildPending && !IsTextInputFocused()) { _layoutRebuildPending = false; RebuildLayout(); } if (!_visible) { SetShortcutHintVisible(visible: false); TryOpenHoveredWardUi(); return; } SetShortcutHintVisible(visible: false); if (Input.GetKeyDown((KeyCode)27)) { CloseWardUi(); return; } if ((Object)(object)_currentWard == (Object)null || !WardAccess.IsManagedWard(ManagedWardRef.FromArea(_currentWard), requireEnabled: false)) { CloseWardUi(); return; } if (HasPendingConfigurationRequest() && Time.unscaledTime - _pendingConfigurationRequestedAt >= 5f) { HandlePendingConfigurationRequestTimeout(); } if (!HasPendingConfigurationRequest()) { RefreshAuthoritativeConfigurationFromWard(); } if (!HasPendingConfigurationRequest() && (_configurationCommitPending || _configurationPushPending) && Time.unscaledTime >= _nextConfigurationPushTime) { CommitPendingConfiguration(); } if (WardPermittedSnapshots.GetRevision(_currentWard) != _lastPermittedRevision) { RefreshPermittedPlayers(force: false); } } internal bool TryOpenHoveredWardUi() { if (!Plugin.IsWardSettingsShortcutDown()) { return false; } Player localPlayer = Player.m_localPlayer; GameObject val = (((Object)(object)localPlayer != (Object)null) ? localPlayer.m_hovering : null); if ((Object)(object)val == (Object)null) { return false; } ManagedWardRef ward = ManagedWardRef.FromArea(val.GetComponentInParent()); if (!WardAccess.CanConfigureWard(ward, localPlayer) && !WardAdminDebugAccess.CanLocallyAttemptAnyWardControl(ward.Area, localPlayer)) { return false; } OpenWardUi(ward.Area); return true; } internal void OpenWardUi(PrivateArea ward) { BuildGui(); if (!((Object)(object)_root == (Object)null)) { _currentWard = ward; _configurationCommitPending = false; _configurationPushPending = false; _lastPermittedRevision = int.MinValue; ClearPendingConfigurationRequest(); _authoritativeConfiguration = WardSettings.GetConfiguration(ward); _currentConfiguration = _authoritativeConfiguration; RefreshStaticTexts(); RefreshControls(); RefreshPermittedPlayers(force: true); SetVisible(visible: true); } } internal void CloseWardUi() { FlushPendingConfigurationPush(); _currentWard = null; _configurationCommitPending = false; _configurationPushPending = false; _lastPermittedRevision = int.MinValue; ClearPendingConfigurationRequest(); SetVisible(visible: false); } internal void ScheduleDoorAutoClose(Door door) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)door == (Object)null || door.m_canNotBeClosed) { return; } if (!WardSettings.TryGetAutoCloseDoorDelay(((Component)door).transform.position, out var delay)) { CancelDoorAutoClose(door); return; } int instanceID = ((Object)door).GetInstanceID(); if (_doorCloseCoroutines.TryGetValue(instanceID, out Coroutine value)) { ((MonoBehaviour)this).StopCoroutine(value); } _doorCloseCoroutines[instanceID] = ((MonoBehaviour)this).StartCoroutine(CloseDoorAfterDelay(door, delay)); } internal void CancelDoorAutoClose(Door door) { if (!((Object)(object)door == (Object)null)) { int instanceID = ((Object)door).GetInstanceID(); if (_doorCloseCoroutines.TryGetValue(instanceID, out Coroutine value)) { ((MonoBehaviour)this).StopCoroutine(value); _doorCloseCoroutines.Remove(instanceID); } } } [IteratorStateMachine(typeof(d__52))] private IEnumerator CloseDoorAfterDelay(Door door, float delay) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__52(0) { <>4__this = this, door = door, delay = delay }; } private void BuildGui() { //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Expected O, but got Unknown //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: 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_013c: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_021d: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_022f: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_025a: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Unknown result type (might be due to invalid IL or missing references) //IL_0285: Unknown result type (might be due to invalid IL or missing references) //IL_029b: Unknown result type (might be due to invalid IL or missing references) //IL_02b4: Unknown result type (might be due to invalid IL or missing references) //IL_02d3: Unknown result type (might be due to invalid IL or missing references) //IL_02f3: Unknown result type (might be due to invalid IL or missing references) //IL_02fd: Expected O, but got Unknown //IL_030d: Unknown result type (might be due to invalid IL or missing references) //IL_0326: Unknown result type (might be due to invalid IL or missing references) //IL_0333: Unknown result type (might be due to invalid IL or missing references) //IL_038a: Unknown result type (might be due to invalid IL or missing references) //IL_03a0: Unknown result type (might be due to invalid IL or missing references) //IL_03b9: Unknown result type (might be due to invalid IL or missing references) //IL_03d8: Unknown result type (might be due to invalid IL or missing references) //IL_03f1: Unknown result type (might be due to invalid IL or missing references) //IL_03fe: Unknown result type (might be due to invalid IL or missing references) //IL_0441: Unknown result type (might be due to invalid IL or missing references) //IL_045a: Unknown result type (might be due to invalid IL or missing references) //IL_0479: Unknown result type (might be due to invalid IL or missing references) //IL_0492: Unknown result type (might be due to invalid IL or missing references) //IL_049f: Unknown result type (might be due to invalid IL or missing references) //IL_04e2: Unknown result type (might be due to invalid IL or missing references) //IL_04fb: Unknown result type (might be due to invalid IL or missing references) //IL_051a: Unknown result type (might be due to invalid IL or missing references) //IL_0533: Unknown result type (might be due to invalid IL or missing references) //IL_0540: Unknown result type (might be due to invalid IL or missing references) //IL_0583: Unknown result type (might be due to invalid IL or missing references) //IL_059c: Unknown result type (might be due to invalid IL or missing references) //IL_05bb: Unknown result type (might be due to invalid IL or missing references) //IL_05d4: Unknown result type (might be due to invalid IL or missing references) //IL_05ef: Unknown result type (might be due to invalid IL or missing references) //IL_0608: Unknown result type (might be due to invalid IL or missing references) //IL_0615: Unknown result type (might be due to invalid IL or missing references) //IL_065b: Unknown result type (might be due to invalid IL or missing references) //IL_0674: Unknown result type (might be due to invalid IL or missing references) //IL_0681: Unknown result type (might be due to invalid IL or missing references) //IL_06c7: Unknown result type (might be due to invalid IL or missing references) //IL_06cb: Unknown result type (might be due to invalid IL or missing references) //IL_06de: Unknown result type (might be due to invalid IL or missing references) //IL_0702: Unknown result type (might be due to invalid IL or missing references) //IL_071b: Unknown result type (might be due to invalid IL or missing references) //IL_0720: Unknown result type (might be due to invalid IL or missing references) //IL_0726: Unknown result type (might be due to invalid IL or missing references) //IL_073a: Unknown result type (might be due to invalid IL or missing references) //IL_073c: Unknown result type (might be due to invalid IL or missing references) //IL_0742: Unknown result type (might be due to invalid IL or missing references) //IL_07cc: Unknown result type (might be due to invalid IL or missing references) //IL_07d6: Expected O, but got Unknown if ((Object)(object)GUIManager.CustomGUIFront == (Object)null) { return; } Localizer.ReloadCurrentLanguageIfAvailable(); if ((Object)(object)_root != (Object)null) { Object.Destroy((Object)(object)_root); } if ((Object)(object)_hintRoot != (Object)null) { Object.Destroy((Object)(object)_hintRoot); } ClearPermittedRows(); _emptyPermittedRow = null; _lastPermittedRevision = int.MinValue; GUIManager instance = GUIManager.Instance; Vector2 panelSize = WardGuiLayoutSettings.GetPanelSize(); _root = new GameObject("STUWardGUIRoot", new Type[2] { typeof(RectTransform), typeof(Image) }); _root.transform.SetParent(GUIManager.CustomGUIFront.transform, false); RectTransform component = _root.GetComponent(); component.anchorMin = Vector2.zero; component.anchorMax = Vector2.one; component.offsetMin = Vector2.zero; component.offsetMax = Vector2.zero; component.anchoredPosition = Vector2.zero; Image component2 = _root.GetComponent(); ((Graphic)component2).color = new Color(0f, 0f, 0f, 0.6f); ((Graphic)component2).raycastTarget = true; _panel = instance.CreateWoodpanel(_root.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), WardGuiLayoutSettings.GetPanelOffset(), panelSize.x, panelSize.y, false); ((Object)_panel).name = "STUWardPanel"; GameObject val = instance.CreateText(string.Empty, GUIManager.CustomGUIFront.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, -150f), instance.AveriaSerifBold, 18, instance.ValheimBeige, true, Color.black, 460f, 84f, false); ((Object)val).name = "STUWardShortcutHint"; _hintRoot = val; _shortcutHintText = val.GetComponent(); if ((Object)(object)_shortcutHintText != (Object)null) { _shortcutHintText.alignment = (TextAnchor)4; } SetShortcutHintVisible(visible: false); Vector2 permittedListSize = WardGuiLayoutSettings.GetPermittedListSize(); Vector2 permittedListPosition = WardGuiLayoutSettings.GetPermittedListPosition(); Vector2 registeredPlayersHeaderPosition = WardGuiLayoutSettings.GetRegisteredPlayersHeaderPosition(); CreateLabel(WardLocalization.Localize("$stuw_ui_title", "Ward Settings"), WardGuiLayoutSettings.GetTitlePosition(), 34, 560f, 56f, (TextAnchor)4, instance.AveriaSerifBold, instance.ValheimOrange); _ownerValueText = CreateLabel(string.Empty, WardGuiLayoutSettings.GetOwnerPosition(), 22, 800f, 36f, (TextAnchor)3, instance.AveriaSerifBold, instance.ValheimBeige); _guildValueText = CreateLabel(string.Empty, WardGuiLayoutSettings.GetGuildPosition(), 20, 800f, 32f, (TextAnchor)3, instance.AveriaSerif, instance.ValheimBeige); ((UnityEvent)CreateButton(WardLocalization.Localize("$stuw_ui_close", "Close"), WardGuiLayoutSettings.GetCloseButtonPosition(), 170f, 42f).onClick).AddListener(new UnityAction(CloseWardUi)); CreateLabel(WardLocalization.Localize("$stuw_ui_radius", "Ward radius"), WardGuiLayoutSettings.GetRadiusLabelPosition(), 21, 240f, 36f, (TextAnchor)3, instance.AveriaSerifBold, instance.ValheimBeige); _radiusSlider = CreateSlider(WardGuiLayoutSettings.GetRadiusSliderPosition(), 520f, 8f, WardSettings.MaxRadius, wholeNumbers: true, commitOnRelease: true); ((UnityEvent)(object)_radiusSlider.onValueChanged).AddListener((UnityAction)OnRadiusSliderChanged); _radiusLimitMarker = CreateSliderLimitMarker(_radiusSlider, new Color(0.82f, 0.22f, 0.18f, 0.95f)); _radiusValueText = CreateLabel(string.Empty, WardGuiLayoutSettings.GetRadiusValuePosition(), 21, 120f, 36f, (TextAnchor)4, instance.AveriaSerifBold, instance.ValheimYellow); CreateLabel(WardLocalization.Localize("$stuw_ui_range_speed", "Range speed"), WardGuiLayoutSettings.GetAreaMarkerSpeedLabelPosition(), 21, 240f, 36f, (TextAnchor)3, instance.AveriaSerifBold, instance.ValheimBeige); _areaMarkerSpeedSlider = CreateSlider(WardGuiLayoutSettings.GetAreaMarkerSpeedSliderPosition(), 520f, 0f, 1f, wholeNumbers: false, commitOnRelease: true); ((UnityEvent)(object)_areaMarkerSpeedSlider.onValueChanged).AddListener((UnityAction)OnAreaMarkerSpeedSliderChanged); _areaMarkerSpeedValueText = CreateLabel(string.Empty, WardGuiLayoutSettings.GetAreaMarkerSpeedValuePosition(), 21, 120f, 36f, (TextAnchor)4, instance.AveriaSerifBold, instance.ValheimYellow); CreateLabel(WardLocalization.Localize("$stuw_ui_range_brightness", "Range brightness"), WardGuiLayoutSettings.GetAreaMarkerAlphaLabelPosition(), 21, 240f, 36f, (TextAnchor)3, instance.AveriaSerifBold, instance.ValheimBeige); _areaMarkerAlphaSlider = CreateSlider(WardGuiLayoutSettings.GetAreaMarkerAlphaSliderPosition(), 520f, 0f, 1f, wholeNumbers: false, commitOnRelease: true); ((UnityEvent)(object)_areaMarkerAlphaSlider.onValueChanged).AddListener((UnityAction)OnAreaMarkerAlphaSliderChanged); _areaMarkerAlphaValueText = CreateLabel(string.Empty, WardGuiLayoutSettings.GetAreaMarkerAlphaValuePosition(), 21, 120f, 36f, (TextAnchor)4, instance.AveriaSerifBold, instance.ValheimYellow); CreateLabel(WardLocalization.Localize("$stuw_ui_door_close_delay", "Door close delay"), WardGuiLayoutSettings.GetAutoCloseDelayLabelPosition(), 21, 240f, 36f, (TextAnchor)3, instance.AveriaSerifBold, instance.ValheimBeige); _autoCloseDelaySlider = CreateSlider(WardGuiLayoutSettings.GetAutoCloseDelaySliderPosition(), 520f, 0f, 10f, wholeNumbers: true, commitOnRelease: true); ((UnityEvent)(object)_autoCloseDelaySlider.onValueChanged).AddListener((UnityAction)OnAutoCloseDelaySliderChanged); _delayValueText = CreateLabel(string.Empty, WardGuiLayoutSettings.GetAutoCloseDelayValuePosition(), 21, 120f, 36f, (TextAnchor)4, instance.AveriaSerifBold, instance.ValheimYellow); CreateLabel(WardLocalization.Localize("$stuw_ui_warning_effects", "Warning effects"), WardGuiLayoutSettings.GetWarningEffectsLabelPosition(), 21, 240f, 36f, (TextAnchor)3, instance.AveriaSerifBold, instance.ValheimBeige); CreateLabel(WardLocalization.Localize("$stuw_ui_warning_sound", "Sound"), WardGuiLayoutSettings.GetWarningSoundLabelPosition(), 21, 120f, 36f, (TextAnchor)3, instance.AveriaSerifBold, instance.ValheimBeige); _warningSoundToggle = CreateToggle(WardGuiLayoutSettings.GetWarningSoundTogglePosition(), GetSliderHandleHeight(_radiusSlider)); ((UnityEvent)(object)_warningSoundToggle.onValueChanged).AddListener((UnityAction)OnWarningSoundToggleChanged); CreateLabel(WardLocalization.Localize("$stuw_ui_warning_flash", "Flash"), WardGuiLayoutSettings.GetWarningFlashLabelPosition(), 21, 120f, 36f, (TextAnchor)3, instance.AveriaSerifBold, instance.ValheimBeige); _warningFlashToggle = CreateToggle(WardGuiLayoutSettings.GetWarningFlashTogglePosition(), GetSliderHandleHeight(_radiusSlider)); ((UnityEvent)(object)_warningFlashToggle.onValueChanged).AddListener((UnityAction)OnWarningFlashToggleChanged); CreateLabel(WardLocalization.Localize("$stuw_ui_registered_players", "Registered players"), registeredPlayersHeaderPosition, 24, permittedListSize.x, 40f, (TextAnchor)4, instance.AveriaSerifBold, instance.ValheimOrange); GameObject val2 = instance.CreateScrollView(_panel.transform, false, true, 20f, 6f, instance.ValheimScrollbarHandleColorBlock, new Color(0f, 0f, 0f, 0.35f), permittedListSize.x, permittedListSize.y); ConfigureRect(val2.GetComponent(), permittedListPosition, permittedListSize.x, permittedListSize.y); ((Object)val2).name = "STUWardPermittedPlayers"; ref RectTransform? permittedContent = ref _permittedContent; Transform obj = val2.transform.Find("Scroll View/Viewport/Content"); permittedContent = (RectTransform?)(object)((obj is RectTransform) ? obj : null); if ((Object)(object)_permittedContent != (Object)null) { VerticalLayoutGroup component3 = ((Component)_permittedContent).GetComponent(); if ((Object)(object)component3 != (Object)null) { ((LayoutGroup)component3).childAlignment = (TextAnchor)0; ((HorizontalOrVerticalLayoutGroup)component3).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)component3).childForceExpandWidth = true; ((HorizontalOrVerticalLayoutGroup)component3).childForceExpandHeight = false; ((HorizontalOrVerticalLayoutGroup)component3).spacing = 6f; ((LayoutGroup)component3).padding = new RectOffset(8, 8, 8, 8); } } SetVisible(_visible); if (_visible && (Object)(object)_currentWard != (Object)null) { RefreshStaticTexts(); RefreshControls(); RefreshPermittedPlayers(force: true); } } internal void RebuildLayout() { BuildGui(); } internal void ScheduleLayoutRebuild() { _layoutRebuildPending = true; } private void SetVisible(bool visible) { _visible = visible; if ((Object)(object)_root != (Object)null) { _root.SetActive(visible); } if (visible) { SetShortcutHintVisible(visible: false); } GUIManager.BlockInput(visible); } private void SetShortcutHintVisible(bool visible) { if ((Object)(object)_hintRoot != (Object)null) { _hintRoot.SetActive(visible); } } private void RefreshStaticTexts() { if (!((Object)(object)_currentWard == (Object)null) && !((Object)(object)_ownerValueText == (Object)null) && !((Object)(object)_guildValueText == (Object)null)) { _ownerValueText.text = WardLocalization.LocalizeFormat("$stuw_ui_owner", "Owner: {0}", WardPrivateAreaSafeAccess.GetCreatorName(_currentWard)); string wardGuildName = GuildsCompat.GetWardGuildName(_currentWard); _guildValueText.text = WardLocalization.LocalizeFormat("$stuw_ui_guild", "Guild: {0}", string.IsNullOrWhiteSpace(wardGuildName) ? "-" : wardGuildName); } } private void RefreshControls() { if (!((Object)(object)_areaMarkerSpeedSlider == (Object)null) && !((Object)(object)_areaMarkerSpeedValueText == (Object)null) && !((Object)(object)_areaMarkerAlphaSlider == (Object)null) && !((Object)(object)_areaMarkerAlphaValueText == (Object)null) && !((Object)(object)_autoCloseDelaySlider == (Object)null) && !((Object)(object)_radiusSlider == (Object)null) && !((Object)(object)_radiusValueText == (Object)null) && !((Object)(object)_delayValueText == (Object)null) && !((Object)(object)_warningSoundToggle == (Object)null) && !((Object)(object)_warningFlashToggle == (Object)null)) { float maxRadius = (((Object)(object)_currentWard != (Object)null) ? WardSettings.GetMaxNonOverlappingRadius(_currentWard) : WardSettings.MaxRadius); float num = Mathf.Clamp(_currentConfiguration.Radius, 8f, WardSettings.MaxRadius); _suppressUiEvents = true; _areaMarkerSpeedSlider.value = _currentConfiguration.AreaMarkerSpeedMultiplier; _areaMarkerAlphaSlider.value = _currentConfiguration.AreaMarkerAlpha; _autoCloseDelaySlider.value = _currentConfiguration.AutoCloseDelay; _warningSoundToggle.isOn = _currentConfiguration.WarningSoundEnabled; _warningFlashToggle.isOn = _currentConfiguration.WarningFlashEnabled; _radiusSlider.maxValue = WardSettings.MaxRadius; _radiusSlider.value = num; _areaMarkerSpeedValueText.text = $"{Mathf.RoundToInt(_currentConfiguration.AreaMarkerSpeedMultiplier * 100f)}%"; _areaMarkerAlphaValueText.text = $"{Mathf.RoundToInt(_currentConfiguration.AreaMarkerAlpha * 100f)}%"; _radiusValueText.text = WardLocalization.LocalizeFormat("$stuw_ui_radius_value", "{0} m", Mathf.RoundToInt(num)); _delayValueText.text = (Mathf.Approximately(_currentConfiguration.AutoCloseDelay, 0f) ? WardLocalization.Localize("$stuw_ui_off", "Off") : WardLocalization.LocalizeFormat("$stuw_ui_delay_value", "{0} s", Mathf.RoundToInt(_currentConfiguration.AutoCloseDelay))); _suppressUiEvents = false; UpdateRadiusLimitMarker(maxRadius); UpdateRadiusValueVisuals(maxRadius); } } private void RefreshPermittedPlayers(bool force) { if ((Object)(object)_currentWard == (Object)null || (Object)(object)_permittedContent == (Object)null) { return; } int revision = WardPermittedSnapshots.GetRevision(_currentWard); if (!force && revision == _lastPermittedRevision) { return; } _lastPermittedRevision = revision; List> permittedPlayers = WardPrivateAreaSafeAccess.GetPermittedPlayers(_currentWard); if (permittedPlayers.Count == 0) { ClearPermittedRows(); EnsureEmptyPermittedRow(); UpdatePermittedRowText(_emptyPermittedRow, WardLocalization.Localize("$stuw_ui_no_registered_players", "No registered players.")); _emptyPermittedRow.Root.SetActive(true); _emptyPermittedRow.Root.transform.SetSiblingIndex(0); return; } if (_emptyPermittedRow != null) { _emptyPermittedRow.Root.SetActive(false); } permittedPlayers.Sort((KeyValuePair left, KeyValuePair right) => string.Compare(left.Value, right.Value, StringComparison.OrdinalIgnoreCase)); _permittedRefreshGeneration++; for (int i = 0; i < permittedPlayers.Count; i++) { KeyValuePair keyValuePair = permittedPlayers[i]; if (!_permittedRows.TryGetValue(keyValuePair.Key, out PermittedRowView value)) { value = CreatePermittedRow(keyValuePair.Key); _permittedRows[keyValuePair.Key] = value; } value.LastSeenGeneration = _permittedRefreshGeneration; UpdatePermittedRowText(value, BuildPermittedPlayerDisplayText(_currentWard, keyValuePair.Key, keyValuePair.Value)); value.Root.transform.SetSiblingIndex(i); value.Root.SetActive(true); } _permittedRowsToRemove.Clear(); foreach (KeyValuePair permittedRow in _permittedRows) { if (permittedRow.Value.LastSeenGeneration != _permittedRefreshGeneration) { _permittedRowsToRemove.Add(permittedRow.Key); } } for (int j = 0; j < _permittedRowsToRemove.Count; j++) { long key = _permittedRowsToRemove[j]; if (_permittedRows.TryGetValue(key, out PermittedRowView value2)) { Object.Destroy((Object)(object)value2.Root); _permittedRows.Remove(key); } } } private PermittedRowView CreatePermittedRow(long playerId) { //IL_0014: 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_001f: 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_0077: Expected O, but got Unknown //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //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_0123: 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) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_015e: 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) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_0274: Unknown result type (might be due to invalid IL or missing references) //IL_027b: 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_02a2: Expected O, but got Unknown Vector2 permittedListSize = WardGuiLayoutSettings.GetPermittedListSize(); float num = Mathf.Max(560f, permittedListSize.x - 72f); float num2 = 46f; float num3 = 130f; GameObject val = new GameObject("PermittedPlayerRow", new Type[3] { typeof(RectTransform), typeof(Image), typeof(LayoutElement) }); val.transform.SetParent((Transform)(object)_permittedContent, false); RectTransform component = val.GetComponent(); component.SetSizeWithCurrentAnchors((Axis)0, num); component.SetSizeWithCurrentAnchors((Axis)1, num2); ((Graphic)val.GetComponent()).color = new Color(0f, 0f, 0f, 0.18f); LayoutElement component2 = val.GetComponent(); component2.preferredHeight = num2; component2.preferredWidth = num; GameObject val2 = new GameObject("PlayerName", new Type[3] { typeof(RectTransform), typeof(Text), typeof(LayoutElement) }); val2.transform.SetParent(val.transform, false); RectTransform component3 = val2.GetComponent(); component3.anchorMin = new Vector2(0.5f, 0.5f); component3.anchorMax = new Vector2(0.5f, 0.5f); component3.pivot = new Vector2(0f, 0.5f); float num4 = 10f; Vector2 registeredPlayersRemoveButtonPosition = WardGuiLayoutSettings.GetRegisteredPlayersRemoveButtonPosition(); float num5 = Mathf.Clamp(registeredPlayersRemoveButtonPosition.x, (0f - num) * 0.5f + num3 * 0.5f + 10f, num * 0.5f - num3 * 0.5f - 4f); float num6 = num5 - num3 * 0.5f - 12f; float num7 = Mathf.Max(340f, num6 - ((0f - num) * 0.5f + num4)); component3.anchoredPosition = new Vector2((0f - num) * 0.5f + num4, 0f); component3.SetSizeWithCurrentAnchors((Axis)0, num7); component3.SetSizeWithCurrentAnchors((Axis)1, num2 - 8f); Text component4 = val2.GetComponent(); GUIManager instance = GUIManager.Instance; instance.ApplyTextStyle(component4, instance.AveriaSerifBold, instance.ValheimBeige, 18, false); component4.text = string.Empty; component4.alignment = (TextAnchor)3; component4.horizontalOverflow = (HorizontalWrapMode)1; component4.verticalOverflow = (VerticalWrapMode)0; ((UnityEvent)CreateAnchoredButton(val.transform, WardLocalization.Localize("$stuw_ui_remove", "Remove"), new Vector2(num5, registeredPlayersRemoveButtonPosition.y), num3, 32f).onClick).AddListener((UnityAction)delegate { if (!((Object)(object)_currentWard == (Object)null)) { WardSettings.RequestRemovePermitted(_currentWard, playerId); } }); return new PermittedRowView(val, component4); } private void EnsureEmptyPermittedRow() { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown //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_0064: 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_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0131: 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_0164: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) if (_emptyPermittedRow == null) { GameObject val = new GameObject("PermittedPlayerRowEmpty", new Type[3] { typeof(RectTransform), typeof(Image), typeof(LayoutElement) }); val.transform.SetParent((Transform)(object)_permittedContent, false); RectTransform component = val.GetComponent(); Vector2 permittedListSize = WardGuiLayoutSettings.GetPermittedListSize(); float num = Mathf.Max(560f, permittedListSize.x - 72f); float num2 = 46f; component.SetSizeWithCurrentAnchors((Axis)0, num); component.SetSizeWithCurrentAnchors((Axis)1, num2); ((Graphic)val.GetComponent()).color = new Color(0f, 0f, 0f, 0.18f); LayoutElement component2 = val.GetComponent(); component2.preferredHeight = num2; component2.preferredWidth = num; GameObject val2 = new GameObject("PlayerName", new Type[3] { typeof(RectTransform), typeof(Text), typeof(LayoutElement) }); val2.transform.SetParent(val.transform, false); RectTransform component3 = val2.GetComponent(); component3.anchorMin = new Vector2(0.5f, 0.5f); component3.anchorMax = new Vector2(0.5f, 0.5f); component3.pivot = new Vector2(0f, 0.5f); component3.anchoredPosition = new Vector2((0f - num) * 0.5f + 10f, 0f); component3.SetSizeWithCurrentAnchors((Axis)0, num - 24f); component3.SetSizeWithCurrentAnchors((Axis)1, num2 - 8f); Text component4 = val2.GetComponent(); GUIManager instance = GUIManager.Instance; instance.ApplyTextStyle(component4, instance.AveriaSerifBold, instance.ValheimBeige, 18, false); component4.alignment = (TextAnchor)3; component4.horizontalOverflow = (HorizontalWrapMode)1; component4.verticalOverflow = (VerticalWrapMode)0; _emptyPermittedRow = new PermittedRowView(val, component4); } } private void UpdatePermittedRowText(PermittedRowView row, string text) { if (!string.Equals(row.NameText.text, text, StringComparison.Ordinal)) { row.NameText.text = text; } } private void ClearPermittedRows() { foreach (PermittedRowView value in _permittedRows.Values) { Object.Destroy((Object)(object)value.Root); } _permittedRows.Clear(); _permittedRowsToRemove.Clear(); _permittedRefreshGeneration = 0; if (_emptyPermittedRow != null) { Object.Destroy((Object)(object)_emptyPermittedRow.Root); _emptyPermittedRow = null; } } private void OnAreaMarkerSpeedSliderChanged(float value) { if (!_suppressUiEvents) { _currentConfiguration = new WardConfiguration(_currentConfiguration.ShowAreaMarker, Mathf.Clamp(value, 0f, 1f), _currentConfiguration.AreaMarkerAlpha, _currentConfiguration.Radius, _currentConfiguration.AutoCloseDelay, _currentConfiguration.WarningSoundEnabled, _currentConfiguration.WarningFlashEnabled); RefreshControls(); ScheduleConfigurationCommit(); } } private void OnAreaMarkerAlphaSliderChanged(float value) { if (!_suppressUiEvents) { _currentConfiguration = new WardConfiguration(_currentConfiguration.ShowAreaMarker, _currentConfiguration.AreaMarkerSpeedMultiplier, Mathf.Clamp(value, 0f, 1f), _currentConfiguration.Radius, _currentConfiguration.AutoCloseDelay, _currentConfiguration.WarningSoundEnabled, _currentConfiguration.WarningFlashEnabled); RefreshControls(); ScheduleConfigurationCommit(); } } private void OnRadiusSliderChanged(float value) { if (!_suppressUiEvents) { _currentConfiguration = new WardConfiguration(_currentConfiguration.ShowAreaMarker, _currentConfiguration.AreaMarkerSpeedMultiplier, _currentConfiguration.AreaMarkerAlpha, Mathf.Clamp(value, 8f, WardSettings.MaxRadius), _currentConfiguration.AutoCloseDelay, _currentConfiguration.WarningSoundEnabled, _currentConfiguration.WarningFlashEnabled); ScheduleConfigurationCommit(); UpdateRadiusTexts(); } } private void OnAutoCloseDelaySliderChanged(float value) { if (!_suppressUiEvents) { _currentConfiguration = new WardConfiguration(_currentConfiguration.ShowAreaMarker, _currentConfiguration.AreaMarkerSpeedMultiplier, _currentConfiguration.AreaMarkerAlpha, _currentConfiguration.Radius, Mathf.Clamp(value, 0f, 10f), _currentConfiguration.WarningSoundEnabled, _currentConfiguration.WarningFlashEnabled); RefreshControls(); ScheduleConfigurationCommit(); } } private void OnWarningSoundToggleChanged(bool enabled) { if (!_suppressUiEvents) { _currentConfiguration = WardSettings.WithWarningSoundEnabled(_currentConfiguration, enabled); RefreshControls(); ScheduleConfigurationPush(); } } private void OnWarningFlashToggleChanged(bool enabled) { if (!_suppressUiEvents) { _currentConfiguration = WardSettings.WithWarningFlashEnabled(_currentConfiguration, enabled); RefreshControls(); ScheduleConfigurationPush(); } } private void PushConfiguration() { if (!((Object)(object)_currentWard == (Object)null)) { WardConfiguration currentConfiguration = _currentConfiguration; _configurationCommitPending = false; _configurationPushPending = false; WardConfigurationRequestSubmission wardConfigurationRequestSubmission = WardSettings.RequestUpdateConfiguration(_currentWard, currentConfiguration); if (wardConfigurationRequestSubmission.IsPending) { BeginPendingConfigurationRequest(wardConfigurationRequestSubmission.RequestId, currentConfiguration); return; } WardSettings.ShowConfigurationRequestFeedback(wardConfigurationRequestSubmission.ResultCode, wardConfigurationRequestSubmission.ShowOverlapMessage); ApplyConfigurationResponse(0L, wardConfigurationRequestSubmission.ResultCode, wardConfigurationRequestSubmission.Configuration); } } private void ScheduleConfigurationCommit() { if (!_suppressUiEvents && !((Object)(object)_currentWard == (Object)null)) { _configurationCommitPending = true; _configurationPushPending = false; _nextConfigurationPushTime = float.PositiveInfinity; } } private void ScheduleConfigurationPush() { if (!_suppressUiEvents && !((Object)(object)_currentWard == (Object)null)) { _configurationPushPending = true; _nextConfigurationPushTime = Time.unscaledTime + 0.15f; } } private void FlushPendingConfigurationPush() { if (_configurationCommitPending || _configurationPushPending) { CommitPendingConfiguration(); } } private void CommitPendingConfiguration() { if (!_suppressUiEvents && !((Object)(object)_currentWard == (Object)null) && (_configurationCommitPending || _configurationPushPending) && !HasPendingConfigurationRequest()) { PushConfiguration(); } } internal void HandleWardConfigurationResponse(PrivateArea ward, long requestId, WardConfigurationRequestResultCode resultCode, WardConfiguration configuration) { if (!((Object)(object)_currentWard == (Object)null) && !((Object)(object)ward != (Object)(object)_currentWard)) { ApplyConfigurationResponse(requestId, resultCode, configuration); } } private bool HasPendingConfigurationRequest() { return _pendingConfigurationRequestId != 0; } private void BeginPendingConfigurationRequest(long requestId, WardConfiguration submittedConfiguration) { _pendingConfigurationRequestId = requestId; _pendingConfiguration = submittedConfiguration; _pendingConfigurationRequestedAt = Time.unscaledTime; } private void ClearPendingConfigurationRequest() { _pendingConfigurationRequestId = 0L; _pendingConfiguration = default(WardConfiguration); _pendingConfigurationRequestedAt = 0f; } private void ApplyConfigurationResponse(long requestId, WardConfigurationRequestResultCode resultCode, WardConfiguration configuration) { bool flag = HasPendingConfigurationRequest(); if (requestId == 0L || (flag && requestId == _pendingConfigurationRequestId)) { bool flag2 = flag && !WardSettings.ConfigurationsMatch(_currentConfiguration, _pendingConfiguration); _authoritativeConfiguration = configuration; if (flag) { ClearPendingConfigurationRequest(); } bool flag3 = (uint)(resultCode - 2) <= 2u; if (flag3 || !flag2) { _currentConfiguration = configuration; } if (flag3) { _configurationCommitPending = false; _configurationPushPending = false; } RefreshControls(); TryFlushDeferredConfigurationAfterRequestResolution(); } } private void RefreshAuthoritativeConfigurationFromWard() { if ((Object)(object)_currentWard == (Object)null) { return; } WardConfiguration configuration = WardSettings.GetConfiguration(_currentWard); if (!WardSettings.ConfigurationsMatch(_authoritativeConfiguration, configuration)) { _authoritativeConfiguration = configuration; if (!_configurationCommitPending && !_configurationPushPending && !WardSettings.ConfigurationsMatch(_currentConfiguration, configuration)) { _currentConfiguration = configuration; RefreshControls(); } } } private void HandlePendingConfigurationRequestTimeout() { if (!((Object)(object)_currentWard == (Object)null) && HasPendingConfigurationRequest()) { Plugin.Log.LogWarning((object)$"Timed out waiting for ward configuration response for ward instanceId={((Object)_currentWard).GetInstanceID()} requestId={_pendingConfigurationRequestId}."); bool num = !WardSettings.ConfigurationsMatch(_currentConfiguration, _pendingConfiguration); _authoritativeConfiguration = WardSettings.GetConfiguration(_currentWard); ClearPendingConfigurationRequest(); if (!num) { _currentConfiguration = _authoritativeConfiguration; RefreshControls(); } TryFlushDeferredConfigurationAfterRequestResolution(); } } private void TryFlushDeferredConfigurationAfterRequestResolution() { if (!HasPendingConfigurationRequest()) { if (_configurationCommitPending) { CommitPendingConfiguration(); } else if (_configurationPushPending && Time.unscaledTime >= _nextConfigurationPushTime) { CommitPendingConfiguration(); } } } private void UpdateRadiusTexts() { if (!((Object)(object)_radiusValueText == (Object)null)) { float maxRadius = (((Object)(object)_currentWard != (Object)null) ? WardSettings.GetMaxNonOverlappingRadius(_currentWard) : WardSettings.MaxRadius); _radiusValueText.text = WardLocalization.LocalizeFormat("$stuw_ui_radius_value", "{0} m", Mathf.RoundToInt(_currentConfiguration.Radius)); UpdateRadiusLimitMarker(maxRadius); UpdateRadiusValueVisuals(maxRadius); } } private Button CreateButton(string text, Vector2 position, float width, float height) { //IL_001b: 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) return GUIManager.Instance.CreateButton(text, _panel.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), position, width, height).GetComponent