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.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.3.1")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.3.1.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } 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) { using MemoryStream memoryStream = new MemoryStream(); if ((object)containingAssembly == null) { containingAssembly = Assembly.GetCallingAssembly(); } string text = containingAssembly.GetManifestResourceNames().FirstOrDefault((string name) => name.EndsWith(resourceFileName, 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 { internal sealed class ConfigurationManagerAttributes { public int? Order; } [BepInPlugin("sighsorry.STUWard", "STUWard", "1.3.1")] [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 RestrictionServerMode { NotForced, ForcedOn } internal enum BoundaryBrightenMode { Off, TrustedOnly, UntrustedOnly, All } internal const string ModName = "STUWard"; internal const string ModVersion = "1.3.1"; internal const string Author = "sighsorry"; internal const string ModGuid = "sighsorry.STUWard"; internal static readonly ConfigSync ConfigSync = new ConfigSync("sighsorry.STUWard") { DisplayName = "STUWard", CurrentVersion = "1.3.1", MinimumRequiredVersion = "1.3.1" }; private Harmony _harmony; internal static ManualLogSource Log = null; internal static Plugin Instance = 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 readonly Dictionary> RestrictionModes = new Dictionary>(); 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 WardBoundaryBrightenMode = 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; bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet; ((BaseUnityPlugin)this).Config.SaveOnConfigSet = false; try { WardPluginBootstrap.InitializeCore(); WardPluginConfigBindings.BindAll(); WardPluginBootstrap.InitializeFeatures(); _harmony = new Harmony("sighsorry.STUWard"); WardPatchRegistry.ApplyAll(_harmony); CreateOrReuseWardGuiController(); ((BaseUnityPlugin)this).Config.Save(); } catch (Exception arg) { try { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } catch (Exception ex) { Log.LogWarning((object)("Failed to remove Harmony patches after STUWard startup failure: " + ex.Message)); } try { WardPluginBootstrap.Shutdown(); } catch (Exception ex2) { Log.LogWarning((object)("Failed to shut down services after STUWard startup failure: " + ex2.Message)); } Log.LogError((object)$"STUWard startup failed: {arg}"); throw; } finally { ((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet; } } private void Update() { ManagedWardRuntimeLifecycle.Update(); } private void OnDestroy() { WardPluginBootstrap.Shutdown(); Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } ((BaseUnityPlugin)this).Config.Save(); } 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 unsafe 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*)(&keyCode))/*cast due to .constrained prefix*/).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, int? configManagerOrder = null) { return Instance.BindConfig(group, name, value, description, synchronizedSetting, configManagerOrder); } 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, int? configManagerOrder = null) { //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Expected O, but got Unknown string text = (synchronizedSetting ? "Synced with server." : "Not synced with server."); string text2 = (string.IsNullOrWhiteSpace(description) ? text : (description.TrimEnd() + " " + text)); ConfigDescription val = (configManagerOrder.HasValue ? new ConfigDescription(text2, (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = configManagerOrder.Value } }) : new ConfigDescription(text2, (AcceptableValueBase)null, Array.Empty())); ConfigEntry val2 = ((BaseUnityPlugin)this).Config.Bind(group, name, value, val); if (synchronizedSetting) { ConfigSync.AddConfigEntry(val2).SynchronizedConfig = true; } return val2; } } internal static class WardPluginBootstrap { internal static void InitializeCore() { Localizer.Load(); } internal static void InitializeFeatures() { ManagedWardConfigFileService.Initialize(); WardItemPrefabPolicy.Initialize(); PrefabManager.OnVanillaPrefabsAvailable += RegisterStuWardPiece; RegisterStuWardPiece(); } internal static void Shutdown() { PrefabManager.OnVanillaPrefabsAvailable -= RegisterStuWardPiece; DoorRpcUseDoorPatch.Reset(); WardPluginConfigBindings.UnbindAll(); WardItemPrefabPolicy.Shutdown(); WardRecentPlayers.Shutdown(); ManagedWardConfigFileService.Shutdown(); GuildsCompat.TryShutdownHooks(); Localizer.Unload(); } private static void RegisterStuWardPiece() { StuWardPrefab.Register(); StuWardPrefab.ApplyRecipeSettings(); } } internal static class WardPluginConfigBindings { private static bool _handlersBound; private const int GeneralOrderStart = 700; private const int RestrictionOrderStart = 900; private const int ClientOrderStart = 300; private const int OrderStep = 10; internal static void BindAll() { UnbindAll(); BindGeneral(); BindRestrictions(); BindClient(); BindHandlers(); } internal static void UnbindAll() { if (_handlersBound) { UnbindHandler(Plugin.MaxWardRadius, HandleMaxWardRadiusChanged); UnbindHandler(Plugin.HostileCreatureStructureProtection, HandleWardPresenceConfigChanged); UnbindHandler(Plugin.DisableVanillaGuardStoneRecipe, HandleRecipeSettingsChanged); UnbindHandler(Plugin.StuWardRecipe, HandleRecipeSettingsChanged); UnbindHandler(Plugin.WardMinimapPinScale, HandleLocalWardPinConfigChanged); UnbindHandler(Plugin.WardMinimapActiveRanges, HandleLocalWardPinConfigChanged); UnbindHandler(Plugin.WardBoundaryBrightenMode, HandleLocalBoundaryBrightenModeChanged); _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.", synchronizedSetting: true, 700); Plugin.ConfigSync.AddLockingConfigEntry(Plugin.ServerConfigLocked); Plugin.MaxWardRadius = Plugin.BindConfigEntry("1 - General", "Max Ward Radius", 32f, "Maximum radius automatically assigned when a Ward is placed. Valid range: 8 to 64.", synchronizedSetting: true, 690); 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.", synchronizedSetting: true, 680); 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.", synchronizedSetting: true, 670); Plugin.HostileCreatureStructureProtection = Plugin.BindConfigEntry("1 - General", "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. UnattendedOnly uses an 8 m trusted-player range buffer, 10 s grace time, and 1 s presence refresh.", synchronizedSetting: true, 660); 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.", synchronizedSetting: true, 650); Plugin.StuWardRecipe = Plugin.BindConfigEntry("1 - General", "STUWard Recipe", "GreydwarfEye:1,BoneFragments:3,Flint:5,Wood:7", "STUWard recipe override. Format: ItemPrefab:Amount[:Recover], ...", synchronizedSetting: true, 640); } private static void BindRestrictions() { Plugin.RestrictionModes.Clear(); IReadOnlyList restrictionDefinitions = WardSettings.RestrictionDefinitions; for (int i = 0; i < restrictionDefinitions.Count; i++) { WardRestrictionDefinition wardRestrictionDefinition = restrictionDefinitions[i]; Plugin.RestrictionModes[wardRestrictionDefinition.Restriction] = BindRestrictionMode(wardRestrictionDefinition.ConfigName, wardRestrictionDefinition.ConfigDescription, 900 - i * 10); } } private static ConfigEntry BindRestrictionMode(string name, string description, int configManagerOrder) { return Plugin.BindConfigEntry("2 - Ward Restrictions", name + " Restriction", Plugin.RestrictionServerMode.ForcedOn, description + " ForcedOn preserves the server rule. NotForced lets each ward owner toggle this restriction in the ward settings UI.", synchronizedSetting: true, configManagerOrder); } 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, 300); 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, 290); 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, 280); Plugin.WardBoundaryBrightenMode = Plugin.BindConfigEntry("3 - Client", "Ward Boundary Brighten Mode", Plugin.BoundaryBrightenMode.All, "Controls which enabled ward boundaries brighten near the local player. TrustedOnly applies to wards where the player is trusted, UntrustedOnly applies to wards where the player is not trusted, All applies to every ward, and Off disables the boundary cue. Placement-conflict highlights remain enabled in every mode.", synchronizedSetting: false, 270); } private static void BindHandlers() { BindHandler(Plugin.MaxWardRadius, HandleMaxWardRadiusChanged); BindHandler(Plugin.HostileCreatureStructureProtection, HandleWardPresenceConfigChanged); BindHandler(Plugin.DisableVanillaGuardStoneRecipe, HandleRecipeSettingsChanged); BindHandler(Plugin.StuWardRecipe, HandleRecipeSettingsChanged); BindHandler(Plugin.WardMinimapPinScale, HandleLocalWardPinConfigChanged); BindHandler(Plugin.WardMinimapActiveRanges, HandleLocalWardPinConfigChanged); BindHandler(Plugin.WardBoundaryBrightenMode, HandleLocalBoundaryBrightenModeChanged); _handlersBound = true; } private static void HandleMaxWardRadiusChanged(object? _, EventArgs __) { WardSettings.HandleMaxRadiusChanged(); } private static void HandleWardPresenceConfigChanged(object? _, EventArgs __) { ManagedWardPresenceService.Invalidate(); } private static void HandleRecipeSettingsChanged(object? _, EventArgs __) { StuWardPrefab.ApplyRecipeSettings(); } private static void HandleLocalWardPinConfigChanged(object? _, EventArgs __) { WardMinimapPinsManager.HandleLocalConfigChanged(); } private static void HandleLocalBoundaryBrightenModeChanged(object? _, EventArgs __) { WardSettings.HandleLocalBoundaryBrightenModeChanged(); } 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 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 sealed class ManagedWardIndex { private sealed class SpatialWardEntry { internal PrivateArea Area { get; } internal int InstanceId { get; } internal SpatialWardEntry(PrivateArea area) { Area = area; InstanceId = ((Object)area).GetInstanceID(); } } private const float SpatialCellSize = 32f; private readonly Func _isTrackable; private readonly List _areas = new List(); private readonly HashSet _areaIds = new HashSet(); private readonly Dictionary> _spatialIndex = new Dictionary>(); private readonly Dictionary> _spatialCellsByInstanceId = new Dictionary>(); private readonly Dictionary _queryStamps = new Dictionary(); private int _queryStamp; internal int Count => _areaIds.Count; internal ManagedWardIndex(Func isTrackable) { _isTrackable = isTrackable; } internal bool Add(PrivateArea area) { int instanceID = ((Object)area).GetInstanceID(); if (!_areaIds.Add(instanceID)) { return false; } _areas.Add(area); return true; } internal bool Remove(PrivateArea area) { int instanceID = ((Object)area).GetInstanceID(); if (!_areaIds.Remove(instanceID)) { return false; } _areas.Remove(area); return true; } internal bool Contains(int instanceId) { return _areaIds.Contains(instanceId); } internal void Clear() { _areas.Clear(); _areaIds.Clear(); ClearSpatialIndex(); } internal void ClearSpatialIndex() { _spatialIndex.Clear(); _spatialCellsByInstanceId.Clear(); _queryStamps.Clear(); _queryStamp = 0; } internal void RebuildSpatialIndex() { ClearSpatialIndex(); for (int i = 0; i < _areas.Count; i++) { PrivateArea val = _areas[i]; if (_isTrackable(val)) { AddAreaToSpatialIndex(val); } } } internal void UpdateSpatialIndex(PrivateArea area, int instanceId, bool shouldContain) { RemoveAreaFromSpatialIndex(instanceId); if (shouldContain && _isTrackable(area)) { AddAreaToSpatialIndex(area); } } internal void FillCandidates(Vector3 point, float radius, List destination) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) destination.Clear(); if (_spatialIndex.Count == 0) { return; } int num = NextQueryStamp(); 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 (!_spatialIndex.TryGetValue(GetSpatialCellKey(i, j), out List value)) { continue; } for (int k = 0; k < value.Count; k++) { SpatialWardEntry spatialWardEntry = value[k]; if (!_queryStamps.TryGetValue(spatialWardEntry.InstanceId, out var value2) || value2 != num) { _queryStamps[spatialWardEntry.InstanceId] = num; destination.Add(spatialWardEntry.Area); } } } } } private void AddAreaToSpatialIndex(PrivateArea area) { //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 = new List(); _spatialIndex[spatialCellKey] = value; } value.Add(spatialWardEntry); list.Add(spatialCellKey); } } _spatialCellsByInstanceId[spatialWardEntry.InstanceId] = list; } private void RemoveAreaFromSpatialIndex(int instanceId) { _queryStamps.Remove(instanceId); if (!_spatialCellsByInstanceId.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); } } _spatialCellsByInstanceId.Remove(instanceId); } 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 int NextQueryStamp() { if (_queryStamp == int.MaxValue) { _queryStamp = 1; _queryStamps.Clear(); return _queryStamp; } _queryStamp++; return _queryStamp; } } internal static class WardPatchRegistry { private static readonly HashSet OptionalPatchTypes = new HashSet { typeof(TameableCollectorCollectorItemPatch), typeof(AzuCraftyBoxesNearbyContainersPatch) }; internal static void ApplyAll(Harmony harmony) { List list = new List(); IReadOnlyList harmonyPatchTypes = GetHarmonyPatchTypes(Assembly.GetExecutingAssembly()); for (int i = 0; i < harmonyPatchTypes.Count; i++) { if (!OptionalPatchTypes.Contains(harmonyPatchTypes[i])) { ApplyPatch(harmony, harmonyPatchTypes[i], required: true, list); } } if (list.Count != 0) { string text = "Failed to apply required patches: " + string.Join(", ", list); Plugin.Log.LogError((object)text); harmony.UnpatchSelf(); throw new InvalidOperationException(text); } for (int j = 0; j < harmonyPatchTypes.Count; j++) { if (OptionalPatchTypes.Contains(harmonyPatchTypes[j])) { ApplyPatch(harmony, harmonyPatchTypes[j], required: false, list); } } PatchOptionalCompat("GuildsCompat", delegate { GuildsCompat.TryPatch(harmony); }); PatchOptionalCompat("TargetPortalCompat", delegate { TargetPortalCompat.TryPatch(harmony); }); } private static void ApplyPatch(Harmony harmony, Type patchType, bool required, ICollection failedRequiredPatches) { try { harmony.CreateClassProcessor(patchType).Patch(); } catch (Exception ex) { if (required) { failedRequiredPatches.Add(patchType.Name); Plugin.Log.LogError((object)("Failed to patch required " + patchType.Name + ": " + ex.GetType().Name + ": " + ex.Message)); } else { Plugin.Log.LogWarning((object)("Failed to patch optional " + patchType.Name + ": " + ex.GetType().Name + ": " + ex.Message)); } } } private static IReadOnlyList GetHarmonyPatchTypes(Assembly assembly) { List list = new List(); foreach (Type loadableType in GetLoadableTypes(assembly)) { if (loadableType.IsClass && HasHarmonyPatchAttribute(loadableType)) { list.Add(loadableType); } } list.Sort((Type left, Type right) => string.Compare(left.FullName, right.FullName, StringComparison.Ordinal)); return list; } 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)); } } private static bool HasHarmonyPatchAttribute(Type type) { return type.GetCustomAttributes(typeof(HarmonyPatch), inherit: false).Length != 0; } private static IEnumerable GetLoadableTypes(Assembly assembly) { try { return assembly.GetTypes(); } catch (ReflectionTypeLoadException ex) { List list = new List(); if (ex.Types == null) { return list; } for (int i = 0; i < ex.Types.Length; i++) { Type type = ex.Types[i]; if (type != null) { list.Add(type); } } return list; } } } [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 EnsureManagedComponent(PrivateArea? area) { return EnsureManagedComponent(ManagedWardRef.FromArea(area)); } 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) { matchedByComponent = ward.EnsureManagedComponent(out var _).HasManagedComponent; } 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.NotifyWardMutation(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; 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 stuWardPiece.m_icon; } 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 piece.Piece.m_icon; } 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) { return val2; } return 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 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 bool AuthoritativeNoGuild { get; } internal CachedWardGuildIdentity(bool hasGuild, int guildId, string guildName, DateTime expiresAtUtc, bool authoritativeNoGuild) { HasGuild = hasGuild; GuildId = guildId; GuildName = guildName; ExpiresAtUtc = expiresAtUtc; AuthoritativeNoGuild = authoritativeNoGuild; } } 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 HashSet TargetPlayerIds = new HashSet(); internal readonly HashSet TargetCharacterKeys = new HashSet(StringComparer.Ordinal); internal readonly HashSet AffectedGuildIds = new HashSet(); internal bool PendingFullRefresh; internal bool PendingLiveDisplayRefresh; internal DateTime FlushAtUtc = DateTime.MinValue; } internal const string GuildIdKey = "stuw_guild_id"; internal 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 LocalGuildSyncHeartbeat = TimeSpan.FromSeconds(10.0); private static readonly Dictionary ServerSyncedGuildByPlayerId = new Dictionary(); private static readonly Dictionary ServerSyncedGuildByCharacterKey = new Dictionary(StringComparer.Ordinal); 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 static DateTime _nextLocalGuildSyncUtc = DateTime.MinValue; 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? 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? 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 bool _guildHooksRegistered; private static bool _guildHooksActive; private static bool _saveGuildPatched; internal static void ResetRuntimeState() { PlayerGuildCache.Clear(); ResetPendingWardGuildProjectionRefreshes(); ResetSyncedGuildState(); _availabilityState = AvailabilityState.Unknown; _nextAvailabilityProbeUtc = DateTime.MinValue; } internal static void EnsureRuntimeBindings() { RegisterSyncRpcs(); } 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 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 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); 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(); _syncRpcsRegistered = false; _localGuildSyncPending = true; _lastSyncedLocalPlayerId = 0L; _lastSyncedLocalGuildId = int.MinValue; _lastSyncedLocalGuildName = string.Empty; _nextLocalGuildSyncUtc = DateTime.MinValue; } 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_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0120: 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 || !IsAvailable()) { 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; DateTime utcNow = DateTime.UtcNow; bool flag = !instance.IsServer() && utcNow >= _nextLocalGuildSyncUtc; bool flag2 = _localGuildSyncPending || playerID != _lastSyncedLocalPlayerId || playerGuildIdentity.Id != _lastSyncedLocalGuildId || !string.Equals(text, _lastSyncedLocalGuildName, StringComparison.Ordinal) || flag; if (!force && !flag2) { return; } 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); } RememberLocalGuildSync(playerID, playerGuildIdentity, utcNow); 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 }); RememberLocalGuildSync(playerID, playerGuildIdentity, utcNow); } } } private static void HandleSyncPlayerGuild(long sender, ZPackage pkg) { if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer() && pkg != null && IsAvailable()) { int reportedGuildId; string text; try { reportedGuildId = pkg.ReadInt(); text = pkg.ReadString(); } catch { return; } if (text.Length <= 256) { TryApplySyncedGuildIdentity(sender, reportedGuildId); } } } private static bool TryApplySyncedGuildIdentity(long sender, int reportedGuildId) { if (!WardOwnership.TryResolveAuthoritativePlayerIdFromSender(sender, 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; } string playerName = WardOwnership.GetPlayerName(playerId); if (!TryResolveAuthoritativeGuildIdentity(playerId, text, playerName, out var guild)) { return false; } if (!GuildIdentityPolicy.CanApplyAuthoritativeGuild(reportedGuildId, guild.Id)) { InvalidateSyncedGuildIdentity(new WardGuildCharacterIdentity(playerId, text, playerName)); return false; } 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 RememberLocalGuildSync(long playerId, WardGuildIdentity guild, DateTime sentAtUtc) { _lastSyncedLocalPlayerId = playerId; _lastSyncedLocalGuildId = guild.Id; _lastSyncedLocalGuildName = guild.Name ?? string.Empty; _localGuildSyncPending = false; _nextLocalGuildSyncUtc = sentAtUtc + LocalGuildSyncHeartbeat; } internal static void ForgetServerPlayerGuildIdentity(long playerId, string accountId, string playerName) { InvalidateSyncedGuildIdentity(new WardGuildCharacterIdentity(playerId, accountId, playerName)); } internal static void InvalidateSyncedGuildIdentity(WardGuildCharacterIdentity identity) { HashSet hashSet = new HashSet(); if (identity.HasPlayerId) { hashSet.Add(identity.PlayerId); } if (identity.HasAccountAndName) { foreach (KeyValuePair item in ServerSyncedGuildByPlayerId) { if (string.Equals(item.Value.AccountId, identity.AccountId, StringComparison.Ordinal) && string.Equals(item.Value.PlayerName, identity.PlayerName, StringComparison.Ordinal)) { hashSet.Add(item.Key); } } } foreach (long item2 in hashSet) { if (ServerSyncedGuildByPlayerId.Remove(item2, out var value)) { RemoveSyncedGuildCharacterKey(value.AccountId, value.PlayerName); } PlayerGuildCache.Remove(item2); } RemoveSyncedGuildCharacterKey(identity.AccountId, identity.PlayerName); } internal static void InvalidateSyncedGuildIdentitiesForGuild(int guildId) { if (guildId == 0) { return; } List list = new List(); foreach (KeyValuePair item in ServerSyncedGuildByPlayerId) { if (item.Value.GuildId == guildId) { list.Add(new WardGuildCharacterIdentity(item.Key, item.Value.AccountId, item.Value.PlayerName)); } } foreach (WardGuildCharacterIdentity item2 in list) { InvalidateSyncedGuildIdentity(item2); } } internal static void InvalidateAllSyncedGuildIdentities() { ServerSyncedGuildByPlayerId.Clear(); ServerSyncedGuildByCharacterKey.Clear(); PlayerGuildCache.Clear(); } private static void RemoveSyncedGuildCharacterKey(string accountId, string playerName) { string text = BuildCharacterIdentityKey(accountId, playerName); if (!string.IsNullOrWhiteSpace(text)) { ServerSyncedGuildByCharacterKey.Remove(text); } } private static void NotifyGuildProjectionRefreshApplied(bool fullRefresh, HashSet? targetPlayerIds, HashSet? targetCharacterKeys, HashSet? affectedGuildIds) { HashSet recipientPeerUids = null; if (!fullRefresh) { if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return; } List peers = ZNet.instance.GetPeers(); recipientPeerUids = ((peers == null) ? new HashSet() : CollectGuildProjectionRefreshRecipients(peers, targetPlayerIds, targetCharacterKeys, affectedGuildIds)); } ManagedWardMapStateService.NotifyViewerProjectionChanged(fullRefresh, recipientPeerUids, 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; } WardGuildIdentity playerGuildIdentity = GetPlayerGuildIdentity(playerId); if (playerGuildIdentity.Id != 0) { return affectedGuildIds.Contains(playerGuildIdentity.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, accountId, playerName); if (playerId != 0L) { if (ServerSyncedGuildByPlayerId.TryGetValue(playerId, out var value2)) { previousGuild = ToWardGuildIdentity(value2); string text = BuildCharacterIdentityKey(value2.AccountId, value2.PlayerName); string b = BuildCharacterIdentityKey(value.AccountId, value.PlayerName); if (!string.Equals(text, b, StringComparison.Ordinal) && !string.IsNullOrWhiteSpace(text)) { ServerSyncedGuildByCharacterKey.Remove(text); } } if (!ServerSyncedGuildByPlayerId.TryGetValue(playerId, out value2) || value2.HasGuild != value.HasGuild || value2.GuildId != value.GuildId || !string.Equals(value2.GuildName, value.GuildName, StringComparison.Ordinal) || !string.Equals(value2.AccountId, value.AccountId, StringComparison.Ordinal) || !string.Equals(value2.PlayerName, value.PlayerName, StringComparison.Ordinal)) { ServerSyncedGuildByPlayerId[playerId] = value; result = true; } } string text2 = BuildCharacterIdentityKey(accountId, playerName); if (string.IsNullOrWhiteSpace(text2)) { return result; } if (previousGuild.Id == 0 && ServerSyncedGuildByCharacterKey.TryGetValue(text2, out var value3)) { previousGuild = ToWardGuildIdentity(value3); } if (!ServerSyncedGuildByCharacterKey.TryGetValue(text2, out var value4) || value4.HasGuild != value.HasGuild || value4.GuildId != value.GuildId || !string.Equals(value4.GuildName, value.GuildName, StringComparison.Ordinal)) { ServerSyncedGuildByCharacterKey[text2] = 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? == true) { _availabilityState = AvailabilityState.Available; _nextAvailabilityProbeUtc = DateTime.MaxValue; return true; } } catch { } _availabilityState = AvailabilityState.Unavailable; _nextAvailabilityProbeUtc = utcNow + AvailabilityProbeBackoff; return false; } internal static void ResetPendingWardGuildProjectionRefreshes() { PendingWardGuildProjectionRefresh.TargetPlayerIds.Clear(); PendingWardGuildProjectionRefresh.TargetCharacterKeys.Clear(); PendingWardGuildProjectionRefresh.AffectedGuildIds.Clear(); PendingWardGuildProjectionRefresh.PendingFullRefresh = false; PendingWardGuildProjectionRefresh.PendingLiveDisplayRefresh = false; PendingWardGuildProjectionRefresh.FlushAtUtc = DateTime.MinValue; } internal static int GetWardGuildId(PrivateArea? area) { if (TryGetStoredWardGuildIdentity(GetWardZdo(area), out var guild)) { return guild.Id; } if (!TryResolveWardGuildIdentity(area, 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, 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 num = zdo.GetLong(ZDOVars.s_creator, 0L); string wardSteamAccountId = WardOwnership.ResolveWardSteamAccountId(zdo, num); string wardOwnerNameForProjection = GetWardOwnerNameForProjection(zdo); if (!TryResolveWardGuildIdentityReadOnly(num, 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 num = zdo.GetInt("stuw_guild_id", 0); string text = zdo.GetString("stuw_guild_name", string.Empty) ?? string.Empty; if (num == 0 && string.IsNullOrWhiteSpace(text)) { return false; } guild = new WardGuildIdentity(num, text.Trim()); return true; } private static ZDO? GetWardZdo(PrivateArea? area) { return WardPrivateAreaSafeAccess.GetZdo(area); } private static bool TryResolveWardGuildIdentity(PrivateArea? area, out WardGuildIdentity guild) { guild = default(WardGuildIdentity); if ((Object)(object)area == (Object)null) { return false; } ZDO? wardZdo = GetWardZdo(area); long canonicalCreatorPlayerId = WardAccess.GetCanonicalCreatorPlayerId(area); string wardSteamAccountId = WardOwnership.ResolveWardSteamAccountId(wardZdo, canonicalCreatorPlayerId); string wardOwnerNameForProjection = GetWardOwnerNameForProjection(wardZdo); if (TryResolveWardGuildIdentityReadOnly(canonicalCreatorPlayerId, wardSteamAccountId, wardOwnerNameForProjection, treatResolvedNoGuildAsResolved: true, out guild)) { return true; } return false; } 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()) { if (TryGetSyncedGuildIdentity(ownerPlayerId, text, text2, out guild)) { if (!treatResolvedNoGuildAsResolved) { return guild.Id != 0; } return true; } if (TryResolveAuthoritativeGuildIdentity(ownerPlayerId, text, text2, out guild)) { if (!treatResolvedNoGuildAsResolved) { return guild.Id != 0; } return true; } return false; } if (ownerPlayerId != 0L && TryGetGuild(ownerPlayerId, out guild)) { return true; } if (!string.IsNullOrWhiteSpace(text) && !string.IsNullOrWhiteSpace(text2)) { return TryGetGuildByAccountAndName(text, text2, out guild); } return false; } internal static void HandleGuildSaved(object? guild) { RefreshWardGuildProjectionForGuild(guild); } internal static void RefreshAllWardGuildProjections(bool liveDisplayRefresh = false) { InvalidateAllSyncedGuildIdentities(); QueueWardGuildProjectionRefreshForAll(liveDisplayRefresh); } private static void RefreshWardGuildProjectionForGuild(object? guild) { WardGuildIdentity guild2; int num = (TryParseGuild(guild, out guild2) ? guild2.Id : 0); InvalidateSyncedGuildIdentitiesForGuild(num); bool hadUnresolvedMembers; List list = CollectGuildMemberCharacterIdentities(guild, out hadUnresolvedMembers); if (list.Count == 0 || hadUnresolvedMembers) { QueueWardGuildProjectionRefreshForAll(liveDisplayRefresh: false); return; } foreach (WardGuildCharacterIdentity item in list) { InvalidateSyncedGuildIdentity(item); RefreshWardGuildProjectionForCharacter(item, liveDisplayRefresh: false, num); } } private static void RefreshWardGuildProjectionForCharacter(WardGuildCharacterIdentity identity, bool liveDisplayRefresh = false, int affectedGuildId = 0, int previousGuildId = 0) { if (identity.HasPlayerId || identity.HasAccountAndName) { if (!string.IsNullOrWhiteSpace(identity.AccountId)) { InvalidateGuildCacheForAccountId(identity.AccountId); } QueueWardGuildProjectionRefreshForCharacter(identity, liveDisplayRefresh, affectedGuildId, previousGuildId); } } internal static void ProcessPendingWardGuildProjectionRefreshes() { PendingWardGuildProjectionRefreshState pendingWardGuildProjectionRefresh = PendingWardGuildProjectionRefresh; if ((pendingWardGuildProjectionRefresh.PendingFullRefresh || pendingWardGuildProjectionRefresh.TargetPlayerIds.Count != 0 || pendingWardGuildProjectionRefresh.TargetCharacterKeys.Count != 0 || pendingWardGuildProjectionRefresh.AffectedGuildIds.Count != 0) && !((Object)(object)ZNet.instance == (Object)null)) { if (!ZNet.instance.IsServer()) { ResetPendingWardGuildProjectionRefreshes(); } else if (!(pendingWardGuildProjectionRefresh.FlushAtUtc > DateTime.UtcNow)) { bool pendingFullRefresh = pendingWardGuildProjectionRefresh.PendingFullRefresh; bool pendingLiveDisplayRefresh = pendingWardGuildProjectionRefresh.PendingLiveDisplayRefresh; HashSet targetPlayerIds = ((pendingWardGuildProjectionRefresh.TargetPlayerIds.Count == 0) ? null : new HashSet(pendingWardGuildProjectionRefresh.TargetPlayerIds)); HashSet targetCharacterKeys = ((pendingWardGuildProjectionRefresh.TargetCharacterKeys.Count == 0) ? null : new HashSet(pendingWardGuildProjectionRefresh.TargetCharacterKeys, StringComparer.Ordinal)); HashSet affectedGuildIds = ((pendingWardGuildProjectionRefresh.AffectedGuildIds.Count == 0) ? null : new HashSet(pendingWardGuildProjectionRefresh.AffectedGuildIds)); ResetPendingWardGuildProjectionRefreshes(); RefreshWardGuildProjectionForManagedWards(targetPlayerIds, targetCharacterKeys, affectedGuildIds, pendingFullRefresh, pendingLiveDisplayRefresh); } } } private static void QueueWardGuildProjectionRefreshForAll(bool liveDisplayRefresh) { if ((Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsServer()) { if (liveDisplayRefresh) { ManagedWardMapStateService.RequestLocalDisplayRefresh(refreshImmediatelyIfVisible: true); } } else { PendingWardGuildProjectionRefresh.PendingFullRefresh = true; PendingWardGuildProjectionRefresh.TargetPlayerIds.Clear(); PendingWardGuildProjectionRefresh.TargetCharacterKeys.Clear(); UpdatePendingWardGuildProjectionRefreshWindow(liveDisplayRefresh); } } private static void QueueWardGuildProjectionRefreshForCharacter(WardGuildCharacterIdentity identity, bool liveDisplayRefresh, int affectedGuildId, int previousGuildId) { if ((Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsServer()) { if (liveDisplayRefresh) { ManagedWardMapStateService.RequestLocalDisplayRefresh(refreshImmediatelyIfVisible: true); } return; } if (!PendingWardGuildProjectionRefresh.PendingFullRefresh) { if (identity.HasPlayerId) { PendingWardGuildProjectionRefresh.TargetPlayerIds.Add(identity.PlayerId); } if (identity.HasAccountAndName) { string text = BuildCharacterIdentityKey(identity.AccountId, identity.PlayerName); if (!string.IsNullOrWhiteSpace(text)) { PendingWardGuildProjectionRefresh.TargetCharacterKeys.Add(text); } } } if (affectedGuildId != 0) { PendingWardGuildProjectionRefresh.AffectedGuildIds.Add(affectedGuildId); } if (previousGuildId != 0) { PendingWardGuildProjectionRefresh.AffectedGuildIds.Add(previousGuildId); } UpdatePendingWardGuildProjectionRefreshWindow(liveDisplayRefresh); } private static void UpdatePendingWardGuildProjectionRefreshWindow(bool liveDisplayRefresh) { if (liveDisplayRefresh) { PendingWardGuildProjectionRefresh.PendingLiveDisplayRefresh = true; } if (PendingWardGuildProjectionRefresh.FlushAtUtc == DateTime.MinValue) { PendingWardGuildProjectionRefresh.FlushAtUtc = DateTime.UtcNow + PendingWardGuildProjectionRefreshDebounce; } } private static void RefreshWardGuildProjectionForManagedWards(HashSet? targetPlayerIds, HashSet? targetCharacterKeys, HashSet? affectedGuildIds, bool fullRefresh, bool liveDisplayRefresh) { //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_007c: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || (!fullRefresh && (targetPlayerIds == null || targetPlayerIds.Count == 0) && (targetCharacterKeys == null || targetCharacterKeys.Count == 0) && (affectedGuildIds == null || affectedGuildIds.Count == 0))) { return; } if (fullRefresh) { InvalidateAllGuildCaches(); } HashSet hashSet = new HashSet(); ManagedWardRegistry.CollectCandidateIds(hashSet, targetPlayerIds, targetCharacterKeys, affectedGuildIds, fullRefresh); WardPermittedSnapshots.RefreshKnownSnapshotsForGuildIdentityChanges(targetPlayerIds, targetCharacterKeys, affectedGuildIds, fullRefresh); 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 num = val.GetLong(ZDOVars.s_creator, 0L); string wardSteamAccountId = WardOwnership.NormalizeAccountIdValue(WardOwnership.ResolveWardSteamAccountId(val, num)); ManagedWardProjectionService.RefreshProjectedMetadata(val, num, wardSteamAccountId); } if (liveDisplayRefresh) { NotifyGuildProjectionRefreshApplied(fullRefresh, targetPlayerIds, targetCharacterKeys, affectedGuildIds); } } 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) { string text = WardOwnership.NormalizeAccountIdValue(accountId); if (string.IsNullOrWhiteSpace(text)) { return; } HashSet hashSet = new HashSet(); foreach (KeyValuePair item in PlayerGuildCache) { if (string.Equals(WardOwnership.NormalizeAccountIdValue(WardOwnership.GetPlayerAccountId(item.Key)), text, StringComparison.Ordinal)) { hashSet.Add(item.Key); } } foreach (long item2 in hashSet) { PlayerGuildCache.Remove(item2); } } private static void InvalidateAllGuildCaches() { PlayerGuildCache.Clear(); } 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; } 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, guild.Id == 0); 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) { return false; } if (string.IsNullOrWhiteSpace(playerAccountId)) { CacheGuildLookup(playerId, hasGuild: false, default(WardGuildIdentity)); return false; } if (string.IsNullOrWhiteSpace(playerName)) { CacheGuildLookup(playerId, hasGuild: false, default(WardGuildIdentity)); return false; } if (!string.IsNullOrWhiteSpace(playerName) && TryGetGuildByAccountAndName(playerAccountId, playerName, out guild)) { CacheGuildLookup(playerId, hasGuild: true, guild); return true; } CacheGuildLookup(playerId, hasGuild: false, default(WardGuildIdentity)); return false; } private static bool TryGetGuildByAccountAndName(string accountId, string playerName, out WardGuildIdentity guild) { guild = default(WardGuildIdentity); string accountId2 = WardOwnership.NormalizeAccountIdValue(accountId); string playerName2 = playerName?.Trim() ?? string.Empty; if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && TryGetSyncedGuildIdentity(accountId2, playerName2, out guild)) { return guild.Id != 0; } if (TryResolveGuildByAccountAndNameFromApi(accountId2, playerName2, out guild)) { return guild.Id != 0; } return false; } internal static bool TryResolveAuthoritativeGuildIdentity(long playerId, string accountId, string playerName, out WardGuildIdentity guild) { guild = default(WardGuildIdentity); if (!IsAvailable()) { return false; } Player player = Player.GetPlayer(playerId); if ((Object)(object)player != (Object)null && TryResolveGuildByPlayerFromApi(player, out guild)) { return true; } string accountId2 = WardOwnership.NormalizeAccountIdValue(accountId); string playerName2 = playerName?.Trim() ?? string.Empty; return TryResolveGuildByAccountAndNameFromApi(accountId2, playerName2, out guild); } internal static bool TryResolveCachedAuthoritativeGuildIdentity(long playerId, string accountId, string playerName, out WardGuildIdentity guild) { guild = default(WardGuildIdentity); if (playerId == 0L) { return false; } string accountId2 = WardOwnership.NormalizeAccountIdValue(accountId); string playerName2 = playerName?.Trim() ?? string.Empty; if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && TryGetSyncedGuildIdentity(playerId, accountId2, playerName2, out guild)) { CacheGuildLookup(playerId, guild.Id != 0, guild, guild.Id == 0); return true; } if (TryGetCachedGuild(playerId, out guild)) { return true; } if (IsCachedAuthoritativeNoGuild(playerId)) { return true; } if (!TryResolveAuthoritativeGuildIdentity(playerId, accountId2, playerName2, out guild)) { return false; } CacheGuildLookup(playerId, guild.Id != 0, guild, guild.Id == 0); return true; } private static bool TryResolveGuildByPlayerFromApi(Player player, out WardGuildIdentity guild) { guild = default(WardGuildIdentity); if (GetPlayerGuildByPlayerMethod == null) { return false; } try { TryParseGuild(GetPlayerGuildByPlayerMethod.Invoke(null, new object[1] { player }), out guild); return true; } catch { return false; } } private static bool TryResolveGuildByAccountAndNameFromApi(string accountId, string playerName, out WardGuildIdentity guild) { guild = default(WardGuildIdentity); string text = WardOwnership.NormalizeAccountIdValue(accountId); string text2 = playerName?.Trim() ?? string.Empty; if (string.IsNullOrWhiteSpace(text) || string.IsNullOrWhiteSpace(text2) || GetPlayerGuildByReferenceMethod == null || PlayerReferenceFromStringMethod == null || !IsAvailable()) { return false; } GuildAccountLookupCandidates accountLookupCandidates = GuildIdentityPolicy.GetAccountLookupCandidates(text); WardGuildIdentity guild2; bool result = TryResolveGuildByReferenceId(accountLookupCandidates.PrimaryAccountId, text2, out guild2); if (guild2.Id != 0 || !accountLookupCandidates.HasFallback) { guild = guild2; return result; } if (TryResolveGuildByReferenceId(accountLookupCandidates.FallbackAccountId, text2, out var guild3)) { guild = guild3; return true; } guild = guild2; return result; } private static bool TryResolveGuildByReferenceId(string accountId, string playerName, out WardGuildIdentity guild) { guild = default(WardGuildIdentity); try { object obj = PlayerReferenceFromStringMethod.Invoke(null, new object[1] { accountId + ":" + playerName }); TryParseGuild(GetPlayerGuildByReferenceMethod.Invoke(null, new object[1] { obj }), out guild); return true; } 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 bool IsCachedAuthoritativeNoGuild(long playerId) { if (!PlayerGuildCache.TryGetValue(playerId, out var value)) { return false; } if (value.ExpiresAtUtc <= DateTime.UtcNow) { PlayerGuildCache.Remove(playerId); return false; } if (!value.HasGuild) { return value.AuthoritativeNoGuild; } return false; } private static void CacheGuildLookup(long playerId, bool hasGuild, WardGuildIdentity guild, bool authoritativeNoGuild = false) { if (playerId != 0L) { PlayerGuildCache[playerId] = new CachedWardGuildIdentity(hasGuild && guild.Id != 0, guild.Id, guild.Name ?? string.Empty, DateTime.UtcNow + GuildLookupCacheDuration, authoritativeNoGuild && !hasGuild); } } 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_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Expected O, but got Unknown EnsureHooksRegistered(); if (!_saveGuildPatched && harmony != null && !(SaveGuildMethod == null)) { 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; } } } private static void EnsureHooksRegistered() { if (_guildHooksRegistered) { _guildHooksActive = true; } else if (!(ApiType == null)) { RegisterGuildHook(RegisterOnGuildJoinedMethod, GuildJoinedDelegateType, "HandleGuildJoinedEvent"); RegisterGuildHook(RegisterOnGuildLeftMethod, GuildLeftDelegateType, "HandleGuildLeftEvent"); RegisterGuildHook(RegisterOnGuildCreatedMethod, GuildCreatedDelegateType, "HandleGuildCreatedEvent"); RegisterGuildHook(RegisterOnGuildDeletedMethod, GuildDeletedDelegateType, "HandleGuildDeletedEvent"); _guildHooksRegistered = true; _guildHooksActive = true; } } 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) { return; } try { Delegate obj = CreateGuildCallback(delegateType, handlerName); if ((object)obj != null) { registerMethod.Invoke(null, new object[1] { obj }); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Failed to register Guilds hook " + handlerName + ": " + ex.GetType().Name + ": " + ex.Message)); } } 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)) { RefreshAllWardGuildProjections(liveDisplayRefresh: true); return; } InvalidateSyncedGuildIdentity(identity); 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)) { RefreshAllWardGuildProjections(liveDisplayRefresh: true); return; } InvalidateSyncedGuildIdentity(identity); RefreshWardGuildProjectionForCharacter(identity, liveDisplayRefresh: true, TryParseGuild(guild, out var guild2) ? guild2.Id : 0); } } private static void HandleGuildCreatedEvent(object guild) { if (_guildHooksActive) { RefreshAllWardGuildProjections(liveDisplayRefresh: true); } } private static void HandleGuildDeletedEvent(object guild) { if (_guildHooksActive) { RefreshAllWardGuildProjections(liveDisplayRefresh: true); } } } internal readonly struct SyncedWardGuildIdentity { internal bool HasGuild { get; } internal int GuildId { get; } internal string GuildName { get; } internal string AccountId { get; } internal string PlayerName { get; } internal SyncedWardGuildIdentity(bool hasGuild, int guildId, string guildName, string accountId, string playerName) { HasGuild = hasGuild; GuildId = guildId; GuildName = guildName ?? string.Empty; AccountId = WardOwnership.NormalizeAccountIdValue(accountId); PlayerName = playerName?.Trim() ?? string.Empty; } } 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 { internal enum AccessDecision { NoWard, Allowed, Denied } internal readonly struct AccessResult { internal AccessDecision Decision { get; } internal bool IsDenied => Decision == AccessDecision.Denied; internal AccessResult(AccessDecision decision) { Decision = decision; } } internal readonly struct RestrictionScope : IDisposable { private readonly bool _active; private readonly WardRestrictionOptions _previousRestriction; internal RestrictionScope(WardRestrictionOptions restriction) { _active = true; _previousRestriction = _restrictionScope; _restrictionScope = restriction; _restrictionScopeDepth++; } public void Dispose() { if (_active && _restrictionScopeDepth > 0) { _restrictionScopeDepth--; if (_restrictionScopeDepth == 0) { _restrictionScope = WardRestrictionOptions.None; } else { _restrictionScope = _previousRestriction; } } } } internal readonly struct ManagedWardAllowScope : IDisposable { private readonly bool _active; internal ManagedWardAllowScope(bool active) { _active = active; if (_active) { _managedWardAllowScopeDepth++; } } public void Dispose() { if (_active && _managedWardAllowScopeDepth > 0) { _managedWardAllowScopeDepth--; } } } private const string NoAccessMessageKey = "$piece_noaccess"; private static readonly ManagedWardIndex AllWardIndex = new ManagedWardIndex((PrivateArea area) => IsTrackableManagedWard(area, requireEnabled: false)); private static readonly ManagedWardIndex EnabledWardIndex = new ManagedWardIndex((PrivateArea area) => IsTrackableManagedWard(area, requireEnabled: true)); private static readonly List SpatialQueryBuffer = new List(); [ThreadStatic] private static int _restrictionScopeDepth; [ThreadStatic] private static WardRestrictionOptions _restrictionScope; [ThreadStatic] private static int _managedWardAllowScopeDepth; private static bool _wardCacheInitialized; private static bool _managedWardSpatialIndexRequiresFullRebuild = true; private static float _managedWardSpatialIndexMaxRadius = -1f; private static int _managedWardSpatialIndexRevision; internal static bool IsManagedWardAllowScopeActive => _managedWardAllowScopeDepth > 0; internal static RestrictionScope EnterRestrictionScope(WardRestrictionOptions restriction) { return new RestrictionScope(restriction); } internal static ManagedWardAllowScope EnterManagedWardAllowScope() { return new ManagedWardAllowScope(active: true); } internal static bool TryGetRestrictionScope(out WardRestrictionOptions restriction) { restriction = _restrictionScope; if (_restrictionScopeDepth > 0) { return restriction != WardRestrictionOptions.None; } return false; } internal static void RegisterManagedWard(ManagedWardRef ward) { RefreshManagedWardState(ward); } 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 (AllWardIndex.Add(area)) { flag = true; } if (area.IsEnabled()) { if (EnabledWardIndex.Add(area)) { flag2 = true; } } else if (EnabledWardIndex.Remove(area)) { ManagedWardRuntimeContexts.ResetPresenceState(area); flag2 = true; } if (flag || flag2) { UpdateManagedWardSpatialIndexMembership(area, instanceID, flag, flag2); } if (flag2) { ManagedWardPresenceService.Invalidate(); ManagedWardPlacementPreviewService.Invalidate(); } } 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 (AllWardIndex.Remove(area)) { flag = true; } if (EnabledWardIndex.Remove(area)) { flag2 = true; } ManagedWardRuntimeContexts.ResetPresenceState(area); if (flag || flag2) { UpdateManagedWardSpatialIndexMembership(area, instanceID, flag, flag2); } if (flag2) { ManagedWardPresenceService.Invalidate(); ManagedWardPlacementPreviewService.Invalidate(); } } } internal static bool HasEnabledManagedWards() { EnsureManagedWardCacheInitialized(); return EnabledWardIndex.Count > 0; } 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(); } ManagedWardPlacementPreviewService.Invalidate(); return; } int instanceID = ((Object)area).GetInstanceID(); bool flag = AllWardIndex.Contains(instanceID); bool flag2 = EnabledWardIndex.Contains(instanceID); if (flag || flag2) { UpdateManagedWardSpatialIndexMembership(area, instanceID, flag, flag2); } } internal static void ResetManagedWardCache() { AllWardIndex.Clear(); EnabledWardIndex.Clear(); SpatialQueryBuffer.Clear(); ManagedWardPresenceService.ResetRuntimeState(); _wardCacheInitialized = false; _managedWardSpatialIndexRequiresFullRebuild = true; _managedWardSpatialIndexMaxRadius = -1f; _managedWardSpatialIndexRevision = 0; ManagedWardPlacementPreviewService.Invalidate(); } 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_0000: Unknown result type (might be due to invalid IL or missing references) return EvaluateAccessAgainstCandidates(point, radius, playerId, areas, null, flash, wardCheck); } internal static bool CheckRestrictionAccess(WardRestrictionOptions restriction, Vector3 point, float radius, long playerId, bool flash = true, bool wardCheck = false) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return !EvaluateRestrictionAccess(restriction, point, radius, playerId, flash, wardCheck).IsDenied; } internal static AccessResult EvaluateRestrictionAccess(WardRestrictionOptions restriction, 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_000a: Unknown result type (might be due to invalid IL or missing references) IReadOnlyList candidateManagedWards = GetCandidateManagedWards(point, radius, requireEnabled: true); return EvaluateRestrictionAccessAgainstCandidates(restriction, point, radius, playerId, candidateManagedWards, flash, wardCheck); } internal static AccessResult EvaluateRestrictionAccessAgainstCandidates(WardRestrictionOptions restriction, Vector3 point, float radius, long playerId, IReadOnlyList areas, bool flash = true, bool wardCheck = false) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return EvaluateAccessAgainstCandidates(point, radius, playerId, areas, restriction, flash, wardCheck); } private static AccessResult EvaluateAccessAgainstCandidates(Vector3 point, float radius, long playerId, IReadOnlyList areas, WardRestrictionOptions? restriction, bool flash, bool wardCheck) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) if (areas.Count == 0) { return new AccessResult(AccessDecision.NoWard); } ManagedWardAccessActor actor; bool flag = ManagedWardAccessEvaluator.TryCreateActorForAccessCheck(playerId, out actor); bool flag2 = false; bool flag3 = false; PrivateArea val = null; float num = float.MaxValue; foreach (PrivateArea area in areas) { if ((Object)(object)area == (Object)null || !area.IsInside(point, radius)) { continue; } flag2 = true; if ((restriction.HasValue && !WardSettings.HasRestriction(WardSettings.GetConfiguration(area), restriction.Value)) || (flag && ManagedWardAccessEvaluator.HasPlayerAccess(area, actor))) { continue; } flag3 = true; if (flash) { float num2 = Utils.DistanceXZ(((Component)area).transform.position, point); if (num2 < num) { num = num2; val = area; } } if (wardCheck && !flash) { break; } } if (!flag2) { return new AccessResult(AccessDecision.NoWard); } if (!flag3) { return new AccessResult(AccessDecision.Allowed); } if (val != null) { val.FlashShield(false); } return new AccessResult(AccessDecision.Denied); } internal static int CollectDeniedManagedWardCandidates(long playerId, IReadOnlyList areas, WardRestrictionOptions restriction, List deniedAreas) { deniedAreas.Clear(); if (playerId == 0L || areas.Count == 0) { return 0; } ManagedWardAccessActor actor = ManagedWardAccessEvaluator.CreateActor(playerId); foreach (PrivateArea area in areas) { if (!((Object)(object)area == (Object)null) && WardSettings.HasRestriction(WardSettings.GetConfiguration(area), restriction) && !ManagedWardAccessEvaluator.HasPlayerAccess(area, actor)) { 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) { if (!ShouldBlock(target, player, 0f)) { return true; } ShowNoAccessMessage(player); result = true; return false; } internal static bool TryBlockInteraction(WardRestrictionOptions restriction, Component target, Player? player, ref bool result) { if (!ShouldBlockRestriction(restriction, target, player, 0f)) { return true; } ShowNoAccessMessage(player); result = true; return false; } internal static bool TryBlockAction(Component target, Player? player, ref bool result) { if (!ShouldBlock(target, player, 0f)) { return true; } ShowNoAccessMessage(player); result = false; return false; } internal static bool TryBlockVoid(WardRestrictionOptions restriction, Component target, Player? player) { if (!ShouldBlockRestriction(restriction, target, player, 0f)) { return true; } ShowNoAccessMessage(player); 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 TryBlockItemUseAtPlayerOrHoveredTamedCreature(Player? player, ItemData? item) { if (!ShouldBlockConfiguredItemUse(player, item) && !ShouldBlockConfiguredItemUseAgainstHoveredTamedCreature(player, item)) { 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 ShouldBlockRestriction(WardRestrictionOptions restriction, Component? target, Player? player, float radius, bool flash = true) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)target == (Object)null) { return false; } return ShouldBlockRestriction(restriction, target.transform.position, radius, player, flash); } internal static bool ShouldBlockRestriction(WardRestrictionOptions restriction, Vector3 point, float radius, Player? player, bool flash = true) { //IL_0015: 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 EvaluateRestrictionAccess(restriction, point, radius, player.GetPlayerID(), flash).IsDenied; } internal static bool ShouldBlockPickup(GameObject? go, Player? player) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)go == (Object)null || !WardItemPrefabPolicy.CanAnyPickupBeBlocked()) { return false; } if (IsPlacedConsumable(go.GetComponent())) { return false; } if (WardItemPrefabPolicy.ShouldBlockPickup(go)) { return ShouldBlockRestriction(WardRestrictionOptions.Pickup, 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 (!IsPlacedConsumable(itemDrop) && WardItemPrefabPolicy.ShouldBlockPickup(itemDrop)) { return ShouldBlockRestriction(WardRestrictionOptions.Pickup, (Component?)(object)itemDrop, player, 0f); } return false; } internal static bool IsPlacedConsumable(ItemDrop? itemDrop) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Invalid comparison between Unknown and I4 if ((Object)(object)itemDrop != (Object)null && itemDrop.IsPiece()) { ItemData itemData = itemDrop.m_itemData; if (itemData == null) { return false; } return (int)(itemData.m_shared?.m_itemType).GetValueOrDefault() == 2; } 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); } } 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 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; } return HasManagedWardTrust(ward, player.GetPlayerID()); } internal static bool HasManagedWardTrust(PrivateArea? area, long playerId) { return HasManagedWardTrust(ManagedWardRef.FromArea(area), playerId); } internal static bool HasManagedWardTrust(ManagedWardRef ward, long playerId) { if ((Object)(object)ward.Area == (Object)null || playerId == 0L || !IsManagedWard(ward, requireEnabled: false)) { return false; } return ManagedWardAccessEvaluator.HasPlayerAccess(ward.Area, ManagedWardAccessEvaluator.CreateActor(playerId)); } internal static bool HasManagedWardTrust(ZDO? zdo, long playerId) { if (zdo != null && zdo.IsValid() && playerId != 0L && WardOwnership.IsManagedWardZdo(zdo)) { return ManagedWardAccessEvaluator.HasPlayerAccess(zdo, ManagedWardAccessEvaluator.CreateActor(playerId)); } return false; } 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 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, 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 bool TryGetAutomaticPlacementRadius(Player? player, Vector3 point, out float radius) { //IL_0020: 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) if ((Object)(object)player == (Object)null) { radius = 8f; return false; } long playerID = player.GetPlayerID(); int playerGuildId = GuildsCompat.GetPlayerGuildId(player); IReadOnlyList candidateManagedWards = GetCandidateManagedWards(point, WardSettings.MaxRadius, requireEnabled: false); return WardOverlapPolicy.TryGetPlacementRadius(8f, WardSettings.MaxRadius, CreateWardOverlapQuery(point, WardSettings.MaxRadius, playerID, playerGuildId, null), BuildWardOverlapAreas(candidateManagedWards, playerGuildId), out radius); } internal static long GetCanonicalCreatorPlayerId(PrivateArea? area) { long creatorPlayerId = ManagedWardRef.FromArea(area).CreatorPlayerId; if (creatorPlayerId != 0L) { return creatorPlayerId; } 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 PrivateArea? FindNearestManagedWard(Vector3 point, float radius = 0f, bool requireEnabled = true, Predicate? predicate = null) { //IL_0014: 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_0050: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) IReadOnlyList readOnlyList; if (predicate == null) { readOnlyList = GetCandidateManagedWards(point, radius, requireEnabled); } else { List list = new List(); FillCandidateManagedWards(point, radius, requireEnabled, list); readOnlyList = list; } if (readOnlyList.Count == 0) { return null; } PrivateArea result = null; float num = float.MaxValue; foreach (PrivateArea item in readOnlyList) { 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; } 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_0029: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null || item == null || !HasEnabledManagedWards() || !IsConfiguredBlockedItem(item)) { return false; } 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_0000: 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_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) IReadOnlyList candidateManagedWards = GetCandidateManagedWards(point, radius, requireEnabled: false); if (candidateManagedWards.Count == 0) { return false; } bool result = false; PrivateArea val = null; float num = float.MaxValue; 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) { continue; } WardOverlapArea area = CreateWardOverlapArea(item, guildId); if (!WardOverlapPolicy.IsForeignOverlap(query, area)) { continue; } result = true; if (flash) { float num2 = Utils.DistanceXZ(((Component)item).transform.position, point); if (num2 < num) { num = num2; val = item; } } } if ((Object)(object)val != (Object)null) { WardSettings.HighlightPlacementBlockingWard(val); ZNetView nView = WardPrivateAreaSafeAccess.GetNView(val); if ((Object)(object)nView != (Object)null && nView.IsValid()) { val.FlashShield(false); } } return result; } 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; AllWardIndex.Clear(); EnabledWardIndex.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)) { AllWardIndex.Add(val); if (val.IsEnabled()) { EnabledWardIndex.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_0014: Unknown result type (might be due to invalid IL or missing references) EnsureManagedWardSpatialIndexInitialized(); (requireEnabled ? EnabledWardIndex : AllWardIndex).FillCandidates(point, radius, destination); } private static void EnsureManagedWardSpatialIndexInitialized() { EnsureManagedWardCacheInitialized(); float maxRadius = WardSettings.MaxRadius; if (_managedWardSpatialIndexRequiresFullRebuild || !Mathf.Approximately(_managedWardSpatialIndexMaxRadius, maxRadius)) { AllWardIndex.ClearSpatialIndex(); EnabledWardIndex.ClearSpatialIndex(); SpatialQueryBuffer.Clear(); AllWardIndex.RebuildSpatialIndex(); EnabledWardIndex.RebuildSpatialIndex(); _managedWardSpatialIndexRequiresFullRebuild = false; _managedWardSpatialIndexMaxRadius = maxRadius; } } private static void UpdateManagedWardSpatialIndexMembership(PrivateArea area, int instanceId, bool updateAllWardIndex, bool updateEnabledWardIndex) { EnsureManagedWardCacheInitialized(); if (_managedWardSpatialIndexRequiresFullRebuild || !Mathf.Approximately(_managedWardSpatialIndexMaxRadius, WardSettings.MaxRadius)) { if (!_managedWardSpatialIndexRequiresFullRebuild) { _managedWardSpatialIndexRequiresFullRebuild = true; if (updateAllWardIndex) { BumpManagedWardSpatialRevision(); } } if (updateAllWardIndex) { ManagedWardPlacementPreviewService.Invalidate(); } } else { if (updateAllWardIndex) { AllWardIndex.UpdateSpatialIndex(area, instanceId, AllWardIndex.Contains(instanceId)); BumpManagedWardSpatialRevision(); ManagedWardPlacementPreviewService.Invalidate(); } if (updateEnabledWardIndex) { EnabledWardIndex.UpdateSpatialIndex(area, instanceId, EnabledWardIndex.Contains(instanceId)); } } } private static void BumpManagedWardSpatialRevision() { _managedWardSpatialIndexRevision = ((_managedWardSpatialIndexRevision == int.MaxValue) ? 1 : (_managedWardSpatialIndexRevision + 1)); } } internal sealed class WardGuiController : MonoBehaviour { private sealed class PermittedRowView { internal GameObject Root { get; } internal Text NameText { get; } internal Text StatusText { get; } internal string SearchText { get; set; } = string.Empty; internal int LastSeenGeneration { get; set; } internal PermittedRowView(GameObject root, Text nameText, Text statusText) { Root = root; NameText = nameText; StatusText = statusText; } } private sealed class RecentPlayerRowView { internal GameObject Root { get; } internal Text NameText { get; } internal Text StatusText { get; } internal Button AddButton { get; } internal string SearchText { get; set; } = string.Empty; internal int LastSeenGeneration { get; set; } internal RecentPlayerRowView(GameObject root, Text nameText, Text statusText, Button addButton) { Root = root; NameText = nameText; StatusText = statusText; AddButton = addButton; } } private sealed class StatusRowView { internal GameObject Root { get; } internal Text Text { get; } internal StatusRowView(GameObject root, Text text) { Root = root; Text = text; } } private enum WardSettingsPage { General, Restrictions } private enum RecentPlayersListState { None, Loading, Loaded, Empty, Error } private sealed class RestrictionRowView { internal GameObject Root { get; } internal Toggle Toggle { get; } internal Text Label { get; } internal Text StateText { get; } internal RestrictionRowView(GameObject root, Toggle toggle, Text label, Text stateText) { Root = root; Toggle = toggle; Label = label; StateText = stateText; } } private const float ConfigurationPushDebounceSeconds = 0.15f; private const float ConfigurationRequestTimeoutSeconds = 5f; private const float RecentPlayersRequestTimeoutSeconds = 5f; private readonly Dictionary _permittedRows = new Dictionary(); private readonly Dictionary _recentPlayerRows = new Dictionary(); private readonly Dictionary _registeredPlayerActivity = new Dictionary(); private readonly Dictionary _restrictionRows = new Dictionary(); private readonly List _permittedRowsToRemove = new List(); private readonly List _recentPlayerRowsToRemove = new List(); private PrivateArea? _currentWard; private WardConfiguration _currentConfiguration; private WardConfiguration _authoritativeConfiguration; private WardConfiguration _pendingConfiguration; private GameObject? _root; private GameObject? _panel; private GameObject? _generalPageRoot; private GameObject? _restrictionsPageRoot; private RectTransform? _permittedContent; private RectTransform? _recentPlayersContent; private RectTransform? _restrictionsContent; private Text? _ownerValueText; private Text? _guildValueText; private Toggle? _autoCloseToggle; private Toggle? _warningSoundToggle; private Toggle? _warningFlashToggle; private Toggle? _areaMarkerRotationToggle; private Button? _previousPageButton; private Button? _nextPageButton; private Transform? _buildParent; private WardSettingsPage _currentPage; private bool _visible; private bool _suppressUiEvents; private bool _configurationPushPending; private bool _closeRequested; private float _nextConfigurationPushTime; private float _pendingConfigurationRequestedAt; private int _lastPermittedRevision = int.MinValue; private int _permittedRefreshGeneration; private int _recentPlayersRefreshGeneration; private long _pendingConfigurationRequestId; private long _pendingRecentPlayersRequestId; private float _recentPlayersRequestedAt; private bool _recentPlayersRequestInProgress; private bool _hasDeferredRecentPlayersSnapshot; private WardRecentPlayersSnapshot _deferredRecentPlayersSnapshot; private StatusRowView? _emptyPermittedRow; private StatusRowView? _recentPlayersStatusRow; private string _registeredPlayersSearchQuery = string.Empty; private string _recentPlayersSearchQuery = string.Empty; private ZDOID _searchQueryWardZdoId = ZDOID.None; private RecentPlayersListState _recentPlayersListState; internal static WardGuiController? Instance { get; private set; } 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; WardRecentPlayers.SnapshotReceived += HandleRecentPlayersSnapshot; BuildGui(); } private void OnDestroy() { GUIManager.OnCustomGUIAvailable -= BuildGui; WardRecentPlayers.SnapshotReceived -= HandleRecentPlayersSnapshot; GUIManager.BlockInput(false); if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } } private void Update() { if (!_visible) { TryOpenHoveredWardUi(); return; } if (_closeRequested) { if ((Object)(object)_currentWard == (Object)null || !WardAccess.IsManagedWard(ManagedWardRef.FromArea(_currentWard), requireEnabled: false)) { CompleteCloseWardUi(); return; } if (HasPendingConfigurationRequest() && Time.unscaledTime - _pendingConfigurationRequestedAt >= 5f) { HandlePendingConfigurationRequestTimeout(); } TryFlushDeferredConfigurationAfterRequestResolution(); return; } if ((Object)(object)_root != (Object)null && !_root.activeSelf) { _root.SetActive(true); } if (Input.GetKeyDown((KeyCode)27)) { CloseWardUi(); return; } if ((Object)(object)_currentWard == (Object)null || !WardAccess.IsManagedWard(ManagedWardRef.FromArea(_currentWard), requireEnabled: false)) { CloseWardUi(); return; } Player localPlayer = Player.m_localPlayer; if (!WardAccess.CanConfigureWard(_currentWard, localPlayer) && !WardAdminDebugAccess.CanLocallyAttemptAnyWardControl(_currentWard, localPlayer)) { CloseWardUi(); return; } if (HasPendingConfigurationRequest() && Time.unscaledTime - _pendingConfigurationRequestedAt >= 5f) { HandlePendingConfigurationRequestTimeout(); } if (!HasPendingConfigurationRequest()) { RefreshAuthoritativeConfigurationFromWard(); } if (!HasPendingConfigurationRequest() && _configurationPushPending && Time.unscaledTime >= _nextConfigurationPushTime) { PushPendingConfiguration(); } if (WardPermittedSnapshots.GetRevision(_currentWard) != _lastPermittedRevision) { RefreshPermittedPlayers(force: false); RequestRecentPlayersSnapshot(); } if (_pendingRecentPlayersRequestId != 0L && Time.unscaledTime - _recentPlayersRequestedAt >= 5f) { _pendingRecentPlayersRequestId = 0L; SetRecentPlayerRowsInteractable(interactable: true); ShowRecentPlayersStatus(WardLocalization.Localize("$stuw_ui_recent_players_error", "Could not load recent players."), isError: true, RecentPlayersListState.Error); } } 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) { //IL_002f: 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_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) if (!TryGetWardZdoId(ward, out var wardZdoId) || wardZdoId != _searchQueryWardZdoId) { _registeredPlayersSearchQuery = string.Empty; _recentPlayersSearchQuery = string.Empty; _searchQueryWardZdoId = wardZdoId; } BuildGui(); if (!((Object)(object)_root == (Object)null)) { _currentWard = ward; _closeRequested = false; _configurationPushPending = false; _lastPermittedRevision = int.MinValue; _currentPage = WardSettingsPage.General; _pendingRecentPlayersRequestId = 0L; _recentPlayersRequestInProgress = false; _hasDeferredRecentPlayersSnapshot = false; _registeredPlayerActivity.Clear(); ClearPendingConfigurationRequest(); _authoritativeConfiguration = WardSettings.GetConfiguration(ward); _currentConfiguration = _authoritativeConfiguration; RefreshStaticTexts(); RefreshControls(); RefreshPermittedPlayers(force: true); SetActivePage(WardSettingsPage.General); RequestRecentPlayersSnapshot(); SetVisible(visible: true); } } internal void CloseWardUi() { _closeRequested = true; FlushPendingConfigurationPush(); TryFlushDeferredConfigurationAfterRequestResolution(); if (!_closeRequested) { return; } if (HasPendingConfigurationRequest() || _configurationPushPending) { if ((Object)(object)_root != (Object)null) { _root.SetActive(false); } GUIManager.BlockInput(false); } else { CompleteCloseWardUi(); } } private void CompleteCloseWardUi() { _currentWard = null; _closeRequested = false; _configurationPushPending = false; _lastPermittedRevision = int.MinValue; _pendingRecentPlayersRequestId = 0L; _recentPlayersRequestInProgress = false; _hasDeferredRecentPlayersSnapshot = false; _registeredPlayerActivity.Clear(); ClearPendingConfigurationRequest(); SetVisible(visible: false); } private void BuildGui() { //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Expected O, but got Unknown //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_020e: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_021b: Unknown result type (might be due to invalid IL or missing references) //IL_0222: 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_0236: Unknown result type (might be due to invalid IL or missing references) //IL_024c: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Unknown result type (might be due to invalid IL or missing references) //IL_0259: Unknown result type (might be due to invalid IL or missing references) //IL_0267: Unknown result type (might be due to invalid IL or missing references) //IL_0286: Unknown result type (might be due to invalid IL or missing references) //IL_02a6: Unknown result type (might be due to invalid IL or missing references) //IL_02b0: Expected O, but got Unknown //IL_02b7: Unknown result type (might be due to invalid IL or missing references) //IL_02e2: Unknown result type (might be due to invalid IL or missing references) //IL_02ec: Expected O, but got Unknown //IL_02fe: Unknown result type (might be due to invalid IL or missing references) //IL_0329: Unknown result type (might be due to invalid IL or missing references) //IL_0333: 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); } ClearPermittedRows(); ClearRecentPlayerRows(); _emptyPermittedRow = null; _recentPlayersStatusRow = null; _lastPermittedRevision = int.MinValue; _restrictionRows.Clear(); _generalPageRoot = null; _restrictionsPageRoot = null; _restrictionsContent = null; _recentPlayersContent = null; _previousPageButton = null; _nextPageButton = null; _buildParent = null; 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"; _generalPageRoot = CreatePageRoot("STUWardGeneralPage", panelSize); _restrictionsPageRoot = CreatePageRoot("STUWardRestrictionsPage", panelSize); CreateLabel(WardLocalization.Localize("$stuw_ui_title", "Ward Settings"), WardGuiLayoutSettings.GetTitlePosition(), 34, WardGuiLayoutSettings.GetTitleSize().x, WardGuiLayoutSettings.GetTitleSize().y, (TextAnchor)4, instance.AveriaSerifBold, instance.ValheimOrange); Vector2 ownerGuildLabelSize = WardGuiLayoutSettings.GetOwnerGuildLabelSize(); _ownerValueText = CreateLabel(string.Empty, WardGuiLayoutSettings.GetOwnerPosition(), 22, ownerGuildLabelSize.x, ownerGuildLabelSize.y, (TextAnchor)3, instance.AveriaSerifBold, instance.ValheimBeige); _guildValueText = CreateLabel(string.Empty, WardGuiLayoutSettings.GetGuildPosition(), 20, ownerGuildLabelSize.x, ownerGuildLabelSize.y, (TextAnchor)3, instance.AveriaSerif, instance.ValheimBeige); ((UnityEvent)CreateButton(WardLocalization.Localize("$stuw_ui_close", "Close"), WardGuiLayoutSettings.GetCloseButtonPosition(), 170f, 42f).onClick).AddListener(new UnityAction(CloseWardUi)); _previousPageButton = CreateButton("<", WardGuiLayoutSettings.GetPageArrowButtonPosition(), 54f, 42f); ((UnityEvent)_previousPageButton.onClick).AddListener((UnityAction)delegate { SetActivePage(WardSettingsPage.General); }); StylePageArrowButton(_previousPageButton); _nextPageButton = CreateButton(">", WardGuiLayoutSettings.GetPageArrowButtonPosition(), 54f, 42f); ((UnityEvent)_nextPageButton.onClick).AddListener((UnityAction)delegate { SetActivePage(WardSettingsPage.Restrictions); }); StylePageArrowButton(_nextPageButton); _buildParent = _generalPageRoot.transform; BuildTrustedPlayers(instance); BuildRecentPlayers(instance); _buildParent = _restrictionsPageRoot.transform; BuildTopControls(instance); BuildRestrictions(); _buildParent = null; SetActivePage(_currentPage); SetVisible(_visible); if (_visible && (Object)(object)_currentWard != (Object)null) { RefreshStaticTexts(); RefreshControls(); RefreshPermittedPlayers(force: true); if (_currentPage == WardSettingsPage.General) { RequestRecentPlayersSnapshot(); } } } private void BuildTopControls(GUIManager gui) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Expected O, but got Unknown GameObject val = new GameObject("STUWardBehaviorControls", new Type[2] { typeof(RectTransform), typeof(GridLayoutGroup) }); val.transform.SetParent(GetBuildParent(), false); Vector2 behaviorControlsGridSize = WardGuiLayoutSettings.GetBehaviorControlsGridSize(); ConfigureRect(val.GetComponent(), WardGuiLayoutSettings.GetBehaviorControlsGridPosition(), behaviorControlsGridSize.x, behaviorControlsGridSize.y); GridLayoutGroup component = val.GetComponent(); component.startCorner = (Corner)0; component.startAxis = (Axis)0; ((LayoutGroup)component).childAlignment = (TextAnchor)0; component.cellSize = WardGuiLayoutSettings.GetRestrictionCellSize(); component.spacing = WardGuiLayoutSettings.GetRestrictionCellSpacing(); ((LayoutGroup)component).padding = new RectOffset(8, 8, 8, 8); component.constraint = (Constraint)1; component.constraintCount = 2; _warningSoundToggle = CreateBehaviorToggleRow(val.transform, "WardAlertSound", WardLocalization.Localize("$stuw_ui_warning_sound", "Ward alert sound"), gui); ((UnityEvent)(object)_warningSoundToggle.onValueChanged).AddListener((UnityAction)OnWarningSoundToggleChanged); _warningFlashToggle = CreateBehaviorToggleRow(val.transform, "WardAlertVisualEffect", WardLocalization.Localize("$stuw_ui_warning_flash", "Ward alert visual effect"), gui); ((UnityEvent)(object)_warningFlashToggle.onValueChanged).AddListener((UnityAction)OnWarningFlashToggleChanged); _areaMarkerRotationToggle = CreateBehaviorToggleRow(val.transform, "WardRangeRotation", WardLocalization.Localize("$stuw_ui_area_marker_rotation", "Ward range rotation"), gui); ((UnityEvent)(object)_areaMarkerRotationToggle.onValueChanged).AddListener((UnityAction)OnAreaMarkerRotationToggleChanged); _autoCloseToggle = CreateBehaviorToggleRow(val.transform, "DoorAutoClose", WardLocalization.Localize("$stuw_ui_auto_close", "Door auto-close"), gui); ((UnityEvent)(object)_autoCloseToggle.onValueChanged).AddListener((UnityAction)OnAutoCloseToggleChanged); } private Toggle CreateBehaviorToggleRow(Transform parent, string name, string labelText, GUIManager gui) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: 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_010e: 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_012e: 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_0152: 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_0187: Unknown result type (might be due to invalid IL or missing references) Vector2 restrictionCellSize = WardGuiLayoutSettings.GetRestrictionCellSize(); GameObject val = new GameObject(name, new Type[2] { typeof(RectTransform), typeof(Image) }); val.transform.SetParent(parent, false); RectTransform component = val.GetComponent(); component.SetSizeWithCurrentAnchors((Axis)0, restrictionCellSize.x); component.SetSizeWithCurrentAnchors((Axis)1, restrictionCellSize.y); ((Graphic)val.GetComponent()).color = new Color(0f, 0f, 0f, 0.18f); Toggle result = CreateCenteredToggle(val.transform, new Vector2((0f - restrictionCellSize.x) * 0.5f + 28f, 0f), WardGuiLayoutSettings.GetBehaviorToggleSize()); GameObject val2 = new GameObject("BehaviorName", new Type[2] { typeof(RectTransform), typeof(Text) }); val2.transform.SetParent(val.transform, false); RectTransform component2 = val2.GetComponent(); component2.anchorMin = new Vector2(0.5f, 0.5f); component2.anchorMax = new Vector2(0.5f, 0.5f); component2.pivot = new Vector2(0f, 0.5f); component2.anchoredPosition = new Vector2((0f - restrictionCellSize.x) * 0.5f + 58f, 0f); component2.SetSizeWithCurrentAnchors((Axis)0, restrictionCellSize.x - 72f); component2.SetSizeWithCurrentAnchors((Axis)1, restrictionCellSize.y - 8f); Text component3 = val2.GetComponent(); gui.ApplyTextStyle(component3, gui.AveriaSerifBold, gui.ValheimBeige, 20, false); component3.text = labelText; component3.alignment = (TextAnchor)3; component3.horizontalOverflow = (HorizontalWrapMode)0; component3.verticalOverflow = (VerticalWrapMode)0; return result; } private void BuildTrustedPlayers(GUIManager gui) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: 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_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002b: 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_003f: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) Vector2 permittedListSize = WardGuiLayoutSettings.GetPermittedListSize(); Vector2 permittedListPosition = WardGuiLayoutSettings.GetPermittedListPosition(); Vector2 registeredPlayersHeaderPosition = WardGuiLayoutSettings.GetRegisteredPlayersHeaderPosition(); Vector2 playerListHeaderLabelSize = WardGuiLayoutSettings.GetPlayerListHeaderLabelSize(); CreateLabel(WardLocalization.Localize("$stuw_ui_registered_players", "Individually trusted players"), registeredPlayersHeaderPosition, 24, playerListHeaderLabelSize.x, playerListHeaderLabelSize.y, (TextAnchor)3, gui.AveriaSerifBold, gui.ValheimOrange); CreatePlayerSearchInput(WardGuiLayoutSettings.GetRegisteredPlayersSearchPosition(), _registeredPlayersSearchQuery, OnRegisteredPlayersSearchChanged, "STUWardRegisteredPlayersSearch"); _permittedContent = CreatePlayerListContent(gui, "STUWardPermittedPlayers", permittedListPosition, permittedListSize); _ = (Object)(object)_permittedContent == (Object)null; } private void BuildRecentPlayers(GUIManager gui) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_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_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: 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_0043: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) Vector2 recentPlayersListSize = WardGuiLayoutSettings.GetRecentPlayersListSize(); Vector2 playerListHeaderLabelSize = WardGuiLayoutSettings.GetPlayerListHeaderLabelSize(); CreateLabel(WardLocalization.Localize("$stuw_ui_unregistered_players", "Unregistered players"), WardGuiLayoutSettings.GetRecentPlayersHeaderPosition(), 24, playerListHeaderLabelSize.x, playerListHeaderLabelSize.y, (TextAnchor)3, gui.AveriaSerifBold, gui.ValheimOrange); CreatePlayerSearchInput(WardGuiLayoutSettings.GetRecentPlayersSearchPosition(), _recentPlayersSearchQuery, OnRecentPlayersSearchChanged, "STUWardRecentPlayersSearch"); _recentPlayersContent = CreatePlayerListContent(gui, "STUWardRecentPlayers", WardGuiLayoutSettings.GetRecentPlayersListPosition(), recentPlayersListSize); if (!((Object)(object)_recentPlayersContent == (Object)null)) { ShowRecentPlayersStatus(WardLocalization.Localize("$stuw_ui_recent_players_loading", "Loading recent players..."), isError: false, RecentPlayersListState.Loading); } } private RectTransform? CreatePlayerListContent(GUIManager gui, string objectName, Vector2 position, Vector2 size) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Expected O, but got Unknown GameObject obj = gui.CreateScrollView(_generalPageRoot.transform, false, true, 20f, 6f, gui.ValheimScrollbarHandleColorBlock, new Color(0f, 0f, 0f, 0.35f), size.x, size.y); ConfigureRect(obj.GetComponent(), position, size.x, size.y); ((Object)obj).name = objectName; Transform obj2 = obj.transform.Find("Scroll View/Viewport/Content"); RectTransform val = (RectTransform)(object)((obj2 is RectTransform) ? obj2 : null); if ((Object)(object)val == (Object)null) { Plugin.Log.LogError((object)("Failed to find the Content object for " + objectName + ".")); return null; } VerticalLayoutGroup component = ((Component)val).GetComponent(); if ((Object)(object)component == (Object)null) { Plugin.Log.LogError((object)("Failed to find the VerticalLayoutGroup for " + objectName + ".")); return null; } ((LayoutGroup)component).childAlignment = (TextAnchor)0; ((HorizontalOrVerticalLayoutGroup)component).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)component).childForceExpandWidth = true; ((HorizontalOrVerticalLayoutGroup)component).childForceExpandHeight = false; ((HorizontalOrVerticalLayoutGroup)component).spacing = 6f; ((LayoutGroup)component).padding = new RectOffset(8, 8, 8, 8); return val; } private void RequestRecentPlayersSnapshot() { if (!((Object)(object)_currentWard == (Object)null) && !((Object)(object)_recentPlayersContent == (Object)null)) { if (_recentPlayersListState != RecentPlayersListState.Loaded) { ShowRecentPlayersStatus(WardLocalization.Localize("$stuw_ui_recent_players_loading", "Loading recent players..."), isError: false, RecentPlayersListState.Loading); } BeginRecentPlayersRequest(); long num = WardRecentPlayers.RequestSnapshot(_currentWard); EndRecentPlayersRequest(num); if (num == 0L) { _pendingRecentPlayersRequestId = 0L; SetRecentPlayerRowsInteractable(interactable: true); ShowRecentPlayersStatus(WardLocalization.Localize("$stuw_ui_recent_players_error", "Could not load recent players."), isError: true, RecentPlayersListState.Error); } else { _pendingRecentPlayersRequestId = num; _recentPlayersRequestedAt = Time.unscaledTime; ApplyDeferredRecentPlayersSnapshot(num); } } } private void HandleRecentPlayersSnapshot(WardRecentPlayersSnapshot snapshot) { if (_recentPlayersRequestInProgress) { if (IsSnapshotForCurrentWard(snapshot)) { _deferredRecentPlayersSnapshot = snapshot; _hasDeferredRecentPlayersSnapshot = true; } } else { ApplyRecentPlayersSnapshot(snapshot); } } private void ApplyRecentPlayersSnapshot(WardRecentPlayersSnapshot snapshot) { if (!((Object)(object)_currentWard == (Object)null) && !((Object)(object)_recentPlayersContent == (Object)null) && snapshot.RequestId != 0L && snapshot.RequestId == _pendingRecentPlayersRequestId && IsSnapshotForCurrentWard(snapshot)) { _pendingRecentPlayersRequestId = 0L; RefreshRegisteredPlayerActivity(snapshot.RegisteredActivity); RefreshRecentPlayers(snapshot.Players); SetRecentPlayerRowsInteractable(interactable: true); RefreshPermittedPlayers(force: true); } } private void RefreshRegisteredPlayerActivity(IReadOnlyList activity) { _registeredPlayerActivity.Clear(); for (int i = 0; i < activity.Count; i++) { WardPlayerActivityEntry value = activity[i]; if (value.PlayerId != 0L) { _registeredPlayerActivity[value.PlayerId] = value; } } } private bool IsSnapshotForCurrentWard(WardRecentPlayersSnapshot snapshot) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_currentWard != (Object)null && TryGetWardZdoId(_currentWard, out var wardZdoId)) { return snapshot.WardZdoId == wardZdoId; } return false; } private void BeginRecentPlayersRequest() { _recentPlayersRequestInProgress = true; _hasDeferredRecentPlayersSnapshot = false; _deferredRecentPlayersSnapshot = default(WardRecentPlayersSnapshot); } private void EndRecentPlayersRequest(long requestId) { _recentPlayersRequestInProgress = false; if (requestId == 0L) { _hasDeferredRecentPlayersSnapshot = false; _deferredRecentPlayersSnapshot = default(WardRecentPlayersSnapshot); } } private void ApplyDeferredRecentPlayersSnapshot(long requestId) { if (_hasDeferredRecentPlayersSnapshot) { WardRecentPlayersSnapshot deferredRecentPlayersSnapshot = _deferredRecentPlayersSnapshot; _hasDeferredRecentPlayersSnapshot = false; _deferredRecentPlayersSnapshot = default(WardRecentPlayersSnapshot); if (deferredRecentPlayersSnapshot.RequestId == requestId) { ApplyRecentPlayersSnapshot(deferredRecentPlayersSnapshot); } } } private void RefreshRecentPlayers(IReadOnlyList players) { if ((Object)(object)_recentPlayersContent == (Object)null) { return; } if (players.Count == 0) { foreach (RecentPlayerRowView value3 in _recentPlayerRows.Values) { value3.Root.SetActive(false); } ShowRecentPlayersStatus(WardLocalization.Localize("$stuw_ui_no_unregistered_players", "No unregistered players seen in the last 14 days."), isError: false, RecentPlayersListState.Empty); return; } if (_recentPlayersStatusRow != null) { _recentPlayersStatusRow.Root.SetActive(false); } _recentPlayersRefreshGeneration++; for (int i = 0; i < players.Count; i++) { WardRecentPlayerEntry wardRecentPlayerEntry = players[i]; if (!_recentPlayerRows.TryGetValue(wardRecentPlayerEntry.PlayerId, out RecentPlayerRowView value)) { value = CreateRecentPlayerRow(wardRecentPlayerEntry.PlayerId); _recentPlayerRows[wardRecentPlayerEntry.PlayerId] = value; } value.LastSeenGeneration = _recentPlayersRefreshGeneration; string playerName = (string.IsNullOrWhiteSpace(wardRecentPlayerEntry.Name) ? wardRecentPlayerEntry.PlayerId.ToString() : wardRecentPlayerEntry.Name); value.NameText.text = BuildPlayerDisplayText(playerName, wardRecentPlayerEntry.GuildName, wardRecentPlayerEntry.AccountId); value.SearchText = BuildPlayerSearchText(wardRecentPlayerEntry.Name, wardRecentPlayerEntry.GuildName, wardRecentPlayerEntry.AccountId, wardRecentPlayerEntry.PlayerId); value.StatusText.text = BuildPlayerActivityStatus(wardRecentPlayerEntry.IsOnline, wardRecentPlayerEntry.LastSeenUtcTicks); value.Root.transform.SetSiblingIndex(i); } _recentPlayerRowsToRemove.Clear(); foreach (KeyValuePair recentPlayerRow in _recentPlayerRows) { if (recentPlayerRow.Value.LastSeenGeneration != _recentPlayersRefreshGeneration) { _recentPlayerRowsToRemove.Add(recentPlayerRow.Key); } } for (int j = 0; j < _recentPlayerRowsToRemove.Count; j++) { long key = _recentPlayerRowsToRemove[j]; if (_recentPlayerRows.TryGetValue(key, out RecentPlayerRowView value2)) { Object.Destroy((Object)(object)value2.Root); _recentPlayerRows.Remove(key); } } _recentPlayersListState = RecentPlayersListState.Loaded; ApplyRecentPlayersFilter(); } private void OnRecentPlayersSearchChanged(string query) { _recentPlayersSearchQuery = query ?? string.Empty; ApplyRecentPlayersFilter(); } private void ApplyRecentPlayersFilter() { if ((Object)(object)_recentPlayersContent == (Object)null || _recentPlayersListState != RecentPlayersListState.Loaded) { return; } if (_recentPlayersStatusRow != null) { _recentPlayersStatusRow.Root.SetActive(false); } string text = _recentPlayersSearchQuery.Trim(); int num = 0; foreach (RecentPlayerRowView value in _recentPlayerRows.Values) { bool flag = MatchesPlayerSearch(value.SearchText, text); value.Root.SetActive(flag); if (flag) { num++; } } if (num == 0 && text.Length > 0) { ShowRecentPlayersStatus(WardLocalization.Localize("$stuw_ui_no_matching_players", "No matching players."), isError: false, RecentPlayersListState.Loaded); } } private RecentPlayerRowView CreateRecentPlayerRow(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_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Expected O, but got Unknown Vector2 recentPlayersListSize = WardGuiLayoutSettings.GetRecentPlayersListSize(); float num = Mathf.Max(560f, recentPlayersListSize.x - 72f); GameObject val = CreatePlayerRowRoot((Transform)(object)_recentPlayersContent, "RecentPlayerRow", num); Text val2 = CreatePlayerRowText(val.transform, "PlayerName", new Vector2((0f - num) * 0.5f + 10f, 0f), num - 318f, (TextAnchor)3, GUIManager.Instance.ValheimBeige); val2.horizontalOverflow = (HorizontalWrapMode)0; Text statusText = CreatePlayerRowText(val.transform, "PlayerStatus", new Vector2(num * 0.5f - 120f - 164f, 0f), 150f, (TextAnchor)5, GUIManager.Instance.ValheimYellow); Button val3 = CreateAnchoredButton(val.transform, WardLocalization.Localize("$stuw_ui_add", "Add"), new Vector2(num * 0.5f - 60f - 4f, 0f), 120f, 32f); ((UnityEvent)val3.onClick).AddListener((UnityAction)delegate { RequestAddRecentPlayer(playerId); }); return new RecentPlayerRowView(val, val2, statusText, val3); } private static GameObject CreatePlayerRowRoot(Transform parent, string name, float rowWidth) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0040: 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) //IL_0073: 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_0095: Expected O, but got Unknown GameObject val = new GameObject(name, new Type[3] { typeof(RectTransform), typeof(Image), typeof(LayoutElement) }); val.transform.SetParent(parent, false); RectTransform component = val.GetComponent(); component.SetSizeWithCurrentAnchors((Axis)0, rowWidth); component.SetSizeWithCurrentAnchors((Axis)1, 46f); ((Graphic)val.GetComponent()).color = new Color(0f, 0f, 0f, 0.18f); LayoutElement component2 = val.GetComponent(); component2.preferredHeight = 46f; component2.preferredWidth = rowWidth; return val; } private static Text CreatePlayerRowText(Transform parent, string name, Vector2 position, float width, TextAnchor alignment, Color color) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name, new Type[2] { typeof(RectTransform), typeof(Text) }); val.transform.SetParent(parent, false); RectTransform component = val.GetComponent(); component.anchorMin = new Vector2(0.5f, 0.5f); component.anchorMax = new Vector2(0.5f, 0.5f); component.pivot = new Vector2(0f, 0.5f); component.anchoredPosition = position; component.SetSizeWithCurrentAnchors((Axis)0, width); component.SetSizeWithCurrentAnchors((Axis)1, 38f); Text component2 = val.GetComponent(); GUIManager instance = GUIManager.Instance; instance.ApplyTextStyle(component2, instance.AveriaSerifBold, color, 18, false); component2.alignment = alignment; component2.horizontalOverflow = (HorizontalWrapMode)1; component2.verticalOverflow = (VerticalWrapMode)0; return component2; } private void RequestAddRecentPlayer(long playerId) { if (!((Object)(object)_currentWard == (Object)null)) { SetRecentPlayerRowsInteractable(interactable: false); BeginRecentPlayersRequest(); long num = WardRecentPlayers.RequestAdd(_currentWard, playerId); EndRecentPlayersRequest(num); if (num == 0L) { _pendingRecentPlayersRequestId = 0L; SetRecentPlayerRowsInteractable(interactable: true); ShowRecentPlayersStatus(WardLocalization.Localize("$stuw_ui_recent_players_error", "Could not load recent players."), isError: true, RecentPlayersListState.Error); } else { _pendingRecentPlayersRequestId = num; _recentPlayersRequestedAt = Time.unscaledTime; ApplyDeferredRecentPlayersSnapshot(num); } } } private void ShowRecentPlayersStatus(string text, bool isError, RecentPlayersListState state) { //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_recentPlayersContent == (Object)null) { return; } foreach (RecentPlayerRowView value in _recentPlayerRows.Values) { value.Root.SetActive(false); } EnsureRecentPlayersStatusRow(); _recentPlayersStatusRow.Text.text = text; ((Graphic)_recentPlayersStatusRow.Text).color = (Color)(isError ? new Color(0.85f, 0.35f, 0.25f) : GUIManager.Instance.ValheimBeige); _recentPlayersStatusRow.Root.transform.SetSiblingIndex(0); _recentPlayersStatusRow.Root.SetActive(true); _recentPlayersListState = state; } private void SetRecentPlayerRowsInteractable(bool interactable) { foreach (RecentPlayerRowView value in _recentPlayerRows.Values) { ((Selectable)value.AddButton).interactable = interactable; } } private void EnsureRecentPlayersStatusRow() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: 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_0076: Unknown result type (might be due to invalid IL or missing references) if (_recentPlayersStatusRow == null && !((Object)(object)_recentPlayersContent == (Object)null)) { Vector2 recentPlayersListSize = WardGuiLayoutSettings.GetRecentPlayersListSize(); float num = Mathf.Max(560f, recentPlayersListSize.x - 72f); GameObject val = CreatePlayerRowRoot((Transform)(object)_recentPlayersContent, "RecentPlayersStatusRow", num); Text text = CreatePlayerRowText(val.transform, "Status", new Vector2((0f - num) * 0.5f + 10f, 0f), num - 24f, (TextAnchor)3, GUIManager.Instance.ValheimBeige); _recentPlayersStatusRow = new StatusRowView(val, text); } } private static string BuildPlayerActivityStatus(bool isOnline, long lastSeenUtcTicks) { if (isOnline) { return WardLocalization.Localize("$stuw_ui_online", "Online"); } if (lastSeenUtcTicks <= 0 || lastSeenUtcTicks > DateTime.MaxValue.Ticks) { return WardLocalization.Localize("$stuw_ui_last_seen_unavailable", "Last seen unavailable"); } DateTime dateTime = new DateTime(lastSeenUtcTicks, DateTimeKind.Utc); TimeSpan timeSpan = DateTime.UtcNow - dateTime; if (timeSpan < TimeSpan.Zero || timeSpan.TotalMinutes < 1.0) { return WardLocalization.Localize("$stuw_ui_last_seen_just_now", "Seen just now"); } if (timeSpan.TotalHours < 1.0) { return WardLocalization.LocalizeFormat("$stuw_ui_last_seen_minutes_ago", "Seen {0}m ago", Mathf.Max(1, Mathf.FloorToInt((float)timeSpan.TotalMinutes))); } if (timeSpan.TotalDays < 1.0) { return WardLocalization.LocalizeFormat("$stuw_ui_last_seen_hours_ago", "Seen {0}h ago", Mathf.Max(1, Mathf.FloorToInt((float)timeSpan.TotalHours))); } return WardLocalization.LocalizeFormat("$stuw_ui_last_seen_days_ago", "Seen {0}d ago", Mathf.Max(1, Mathf.FloorToInt((float)timeSpan.TotalDays))); } private static bool TryGetWardZdoId(PrivateArea ward, out ZDOID wardZdoId) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) wardZdoId = ZDOID.None; ZDO val = (((Object)(object)ward.m_nview != (Object)null && ward.m_nview.IsValid()) ? ward.m_nview.GetZDO() : null); if (val == null) { return false; } wardZdoId = val.m_uid; return wardZdoId != ZDOID.None; } private void SetVisible(bool visible) { _visible = visible; if ((Object)(object)_root != (Object)null) { _root.SetActive(visible); } GUIManager.BlockInput(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)_autoCloseToggle == (Object)null) && !((Object)(object)_warningSoundToggle == (Object)null) && !((Object)(object)_warningFlashToggle == (Object)null) && !((Object)(object)_areaMarkerRotationToggle == (Object)null)) { _suppressUiEvents = true; _autoCloseToggle.isOn = _currentConfiguration.AutoCloseEnabled; _warningSoundToggle.isOn = _currentConfiguration.WarningSoundEnabled; _warningFlashToggle.isOn = _currentConfiguration.WarningFlashEnabled; _areaMarkerRotationToggle.isOn = _currentConfiguration.AreaMarkerRotationEnabled; RefreshRestrictionRows(); _suppressUiEvents = false; } } 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(); UpdateText(_emptyPermittedRow.Text, WardLocalization.Localize("$stuw_ui_no_registered_players", "No individually trusted 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 num = 0; num < permittedPlayers.Count; num++) { KeyValuePair keyValuePair = permittedPlayers[num]; if (!_permittedRows.TryGetValue(keyValuePair.Key, out PermittedRowView value)) { value = CreatePermittedRow(keyValuePair.Key); _permittedRows[keyValuePair.Key] = value; } value.LastSeenGeneration = _permittedRefreshGeneration; GetPermittedPlayerIdentity(_currentWard, keyValuePair.Key, out string guildName, out string accountId); string playerName = (string.IsNullOrWhiteSpace(keyValuePair.Value) ? keyValuePair.Key.ToString() : keyValuePair.Value); UpdateText(value.NameText, BuildPlayerDisplayText(playerName, guildName, accountId)); value.StatusText.text = (_registeredPlayerActivity.TryGetValue(keyValuePair.Key, out var value2) ? BuildPlayerActivityStatus(value2.IsOnline, value2.LastSeenUtcTicks) : BuildPlayerActivityStatus(isOnline: false, 0L)); value.SearchText = BuildPlayerSearchText(keyValuePair.Value, guildName, accountId, keyValuePair.Key); value.Root.transform.SetSiblingIndex(num); } _permittedRowsToRemove.Clear(); foreach (KeyValuePair permittedRow in _permittedRows) { if (permittedRow.Value.LastSeenGeneration != _permittedRefreshGeneration) { _permittedRowsToRemove.Add(permittedRow.Key); } } for (int num2 = 0; num2 < _permittedRowsToRemove.Count; num2++) { long key = _permittedRowsToRemove[num2]; if (_permittedRows.TryGetValue(key, out PermittedRowView value3)) { Object.Destroy((Object)(object)value3.Root); _permittedRows.Remove(key); } } ApplyRegisteredPlayersFilter(); } private void OnRegisteredPlayersSearchChanged(string query) { _registeredPlayersSearchQuery = query ?? string.Empty; ApplyRegisteredPlayersFilter(); } private void ApplyRegisteredPlayersFilter() { if ((Object)(object)_permittedContent == (Object)null || _permittedRows.Count == 0) { return; } string text = _registeredPlayersSearchQuery.Trim(); int num = 0; foreach (PermittedRowView value in _permittedRows.Values) { bool flag = MatchesPlayerSearch(value.SearchText, text); value.Root.SetActive(flag); if (flag) { num++; } } if (_emptyPermittedRow == null) { EnsureEmptyPermittedRow(); } if (num == 0 && text.Length > 0) { UpdateText(_emptyPermittedRow.Text, WardLocalization.Localize("$stuw_ui_no_matching_players", "No matching players.")); _emptyPermittedRow.Root.transform.SetSiblingIndex(_permittedRows.Count); _emptyPermittedRow.Root.SetActive(true); } else if (_emptyPermittedRow != null) { _emptyPermittedRow.Root.SetActive(false); } } 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_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0156: 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_0180: Expected O, but got Unknown Vector2 permittedListSize = WardGuiLayoutSettings.GetPermittedListSize(); float num = Mathf.Max(560f, permittedListSize.x - 72f); GameObject val = CreatePlayerRowRoot((Transform)(object)_permittedContent, "PermittedPlayerRow", num); Vector2 registeredPlayersRemoveButtonPosition = WardGuiLayoutSettings.GetRegisteredPlayersRemoveButtonPosition(); float num2 = Mathf.Clamp(registeredPlayersRemoveButtonPosition.x, (0f - num) * 0.5f + 65f + 10f, num * 0.5f - 65f - 4f); float num3 = (0f - num) * 0.5f + 10f; float num4 = num2 - 65f - 10f - 150f; float width = Mathf.Max(220f, num4 - 12f - num3); Text val2 = CreatePlayerRowText(val.transform, "PlayerName", new Vector2(num3, 0f), width, (TextAnchor)3, GUIManager.Instance.ValheimBeige); val2.horizontalOverflow = (HorizontalWrapMode)0; Text val3 = CreatePlayerRowText(val.transform, "PlayerStatus", new Vector2(num4, 0f), 150f, (TextAnchor)5, GUIManager.Instance.ValheimYellow); val3.resizeTextForBestFit = true; val3.resizeTextMinSize = 13; val3.resizeTextMaxSize = 18; ((UnityEvent)CreateAnchoredButton(val.transform, WardLocalization.Localize("$stuw_ui_remove", "Remove"), new Vector2(num2, registeredPlayersRemoveButtonPosition.y), 130f, 32f).onClick).AddListener((UnityAction)delegate { if (!((Object)(object)_currentWard == (Object)null)) { WardSettings.RequestRemovePermitted(_currentWard, playerId); RequestRecentPlayersSnapshot(); } }); return new PermittedRowView(val, val2, val3); } private void EnsureEmptyPermittedRow() { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) if (_emptyPermittedRow == null) { Vector2 permittedListSize = WardGuiLayoutSettings.GetPermittedListSize(); float num = Mathf.Max(560f, permittedListSize.x - 72f); GameObject val = CreatePlayerRowRoot((Transform)(object)_permittedContent, "PermittedPlayerRowEmpty", num); Text text = CreatePlayerRowText(val.transform, "PlayerName", new Vector2((0f - num) * 0.5f + 10f, 0f), num - 24f, (TextAnchor)3, GUIManager.Instance.ValheimBeige); _emptyPermittedRow = new StatusRowView(val, text); } } private static void UpdateText(Text target, string text) { if (!string.Equals(target.text, text, StringComparison.Ordinal)) { target.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 ClearRecentPlayerRows() { foreach (RecentPlayerRowView value in _recentPlayerRows.Values) { Object.Destroy((Object)(object)value.Root); } _recentPlayerRows.Clear(); _recentPlayerRowsToRemove.Clear(); _recentPlayersRefreshGeneration = 0; _pendingRecentPlayersRequestId = 0L; _recentPlayersRequestInProgress = false; _hasDeferredRecentPlayersSnapshot = false; _deferredRecentPlayersSnapshot = default(WardRecentPlayersSnapshot); _recentPlayersListState = RecentPlayersListState.None; if (_recentPlayersStatusRow != null) { Object.Destroy((Object)(object)_recentPlayersStatusRow.Root); _recentPlayersStatusRow = null; } } private void BuildRestrictions() { //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_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Expected O, but got Unknown GUIManager instance = GUIManager.Instance; Vector2 restrictionListSize = WardGuiLayoutSettings.GetRestrictionListSize(); CreateLabel(WardLocalization.Localize("$stuw_ui_restrictions", "Restrictions"), WardGuiLayoutSettings.GetRestrictionsHeaderPosition(), 24, restrictionListSize.x, 40f, (TextAnchor)4, instance.AveriaSerifBold, instance.ValheimOrange); GameObject val = instance.CreateScrollView(_restrictionsPageRoot.transform, false, true, 20f, 6f, instance.ValheimScrollbarHandleColorBlock, new Color(0f, 0f, 0f, 0.35f), restrictionListSize.x, restrictionListSize.y); ConfigureRect(val.GetComponent(), WardGuiLayoutSettings.GetRestrictionListPosition(), restrictionListSize.x, restrictionListSize.y); ((Object)val).name = "STUWardRestrictions"; ref RectTransform? restrictionsContent = ref _restrictionsContent; Transform obj = val.transform.Find("Scroll View/Viewport/Content"); restrictionsContent = (RectTransform?)(object)((obj is RectTransform) ? obj : null); if ((Object)(object)_restrictionsContent == (Object)null) { return; } VerticalLayoutGroup component = ((Component)_restrictionsContent).GetComponent(); if ((Object)(object)component != (Object)null) { ((Behaviour)component).enabled = false; Object.DestroyImmediate((Object)(object)component); } GridLayoutGroup val2 = ((Component)_restrictionsContent).gameObject.AddComponent(); if ((Object)(object)val2 == (Object)null) { Plugin.Log.LogError((object)"Failed to create the ward restrictions grid layout."); return; } val2.startCorner = (Corner)0; val2.startAxis = (Axis)1; ((LayoutGroup)val2).childAlignment = (TextAnchor)0; val2.cellSize = WardGuiLayoutSettings.GetRestrictionCellSize(); val2.spacing = WardGuiLayoutSettings.GetRestrictionCellSpacing(); ((LayoutGroup)val2).padding = new RectOffset(8, 8, 8, 8); val2.constraint = (Constraint)1; val2.constraintCount = 2; IReadOnlyList restrictionDefinitions = WardSettings.RestrictionDefinitions; for (int i = 0; i < restrictionDefinitions.Count; i++) { WardRestrictionDefinition definition = restrictionDefinitions[i]; _restrictionRows[definition.Restriction] = CreateRestrictionRow(definition); } } private RestrictionRowView CreateRestrictionRow(WardRestrictionDefinition definition) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_025b: Unknown result type (might be due to invalid IL or missing references) //IL_0270: Unknown result type (might be due to invalid IL or missing references) //IL_028d: Unknown result type (might be due to invalid IL or missing references) //IL_02c4: Unknown result type (might be due to invalid IL or missing references) Vector2 restrictionCellSize = WardGuiLayoutSettings.GetRestrictionCellSize(); float x = restrictionCellSize.x; float y = restrictionCellSize.y; GameObject val = new GameObject("RestrictionRow", new Type[2] { typeof(RectTransform), typeof(Image) }); val.transform.SetParent((Transform)(object)_restrictionsContent, false); RectTransform component = val.GetComponent(); component.SetSizeWithCurrentAnchors((Axis)0, x); component.SetSizeWithCurrentAnchors((Axis)1, y); ((Graphic)val.GetComponent()).color = new Color(0f, 0f, 0f, 0.18f); Toggle val2 = CreateCenteredToggle(val.transform, new Vector2((0f - x) * 0.5f + 28f, 0f), 30f); WardRestrictionOptions restriction = definition.Restriction; ((UnityEvent)(object)val2.onValueChanged).AddListener((UnityAction)delegate(bool enabled) { OnRestrictionToggleChanged(restriction, enabled); }); GameObject val3 = new GameObject("RestrictionName", new Type[2] { typeof(RectTransform), typeof(Text) }); val3.transform.SetParent(val.transform, false); RectTransform component2 = val3.GetComponent(); component2.anchorMin = new Vector2(0.5f, 0.5f); component2.anchorMax = new Vector2(0.5f, 0.5f); component2.pivot = new Vector2(0f, 0.5f); component2.anchoredPosition = new Vector2((0f - x) * 0.5f + 58f, 0f); component2.SetSizeWithCurrentAnchors((Axis)0, x - 220f); component2.SetSizeWithCurrentAnchors((Axis)1, y - 8f); Text component3 = val3.GetComponent(); GUIManager instance = GUIManager.Instance; instance.ApplyTextStyle(component3, instance.AveriaSerifBold, instance.ValheimBeige, 20, false); component3.text = WardLocalization.Localize(definition.LocalizationToken, definition.LocalizationFallback); component3.alignment = (TextAnchor)3; component3.horizontalOverflow = (HorizontalWrapMode)0; component3.verticalOverflow = (VerticalWrapMode)0; GameObject val4 = new GameObject("RestrictionState", new Type[2] { typeof(RectTransform), typeof(Text) }); val4.transform.SetParent(val.transform, false); RectTransform component4 = val4.GetComponent(); component4.anchorMin = new Vector2(0.5f, 0.5f); component4.anchorMax = new Vector2(0.5f, 0.5f); component4.pivot = new Vector2(1f, 0.5f); component4.anchoredPosition = new Vector2(x * 0.5f - 14f, 0f); component4.SetSizeWithCurrentAnchors((Axis)0, 130f); component4.SetSizeWithCurrentAnchors((Axis)1, y - 8f); Text component5 = val4.GetComponent(); instance.ApplyTextStyle(component5, instance.AveriaSerifBold, instance.ValheimYellow, 18, false); component5.alignment = (TextAnchor)5; component5.horizontalOverflow = (HorizontalWrapMode)1; component5.verticalOverflow = (VerticalWrapMode)0; return new RestrictionRowView(val, val2, component3, component5); } private void RefreshRestrictionRows() { //IL_0093: 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) GUIManager instance = GUIManager.Instance; IReadOnlyList restrictionDefinitions = WardSettings.RestrictionDefinitions; for (int i = 0; i < restrictionDefinitions.Count; i++) { WardRestrictionDefinition wardRestrictionDefinition = restrictionDefinitions[i]; if (_restrictionRows.TryGetValue(wardRestrictionDefinition.Restriction, out RestrictionRowView value)) { bool flag = WardSettings.IsRestrictionForced(wardRestrictionDefinition.Restriction); value.Toggle.isOn = WardSettings.HasRestriction(_currentConfiguration, wardRestrictionDefinition.Restriction); ((Selectable)value.Toggle).interactable = !flag; ((Graphic)value.Label).color = (Color)(flag ? new Color(0.65f, 0.62f, 0.55f) : instance.ValheimBeige); value.StateText.text = (flag ? WardLocalization.Localize("$stuw_ui_restriction_forced", "Forced") : string.Empty); } } } private void OnRestrictionToggleChanged(WardRestrictionOptions restriction, bool enabled) { if (!_suppressUiEvents) { if (WardSettings.IsRestrictionForced(restriction)) { RefreshControls(); } else { ApplyConfigurationDraft(WardSettings.WithRestriction(_currentConfiguration, restriction, enabled)); } } } private void OnAutoCloseToggleChanged(bool enabled) { ApplyConfigurationDraft(WardSettings.WithAutoCloseEnabled(_currentConfiguration, enabled)); } private void OnWarningSoundToggleChanged(bool enabled) { ApplyConfigurationDraft(WardSettings.WithWarningSoundEnabled(_currentConfiguration, enabled)); } private void OnWarningFlashToggleChanged(bool enabled) { ApplyConfigurationDraft(WardSettings.WithWarningFlashEnabled(_currentConfiguration, enabled)); } private void OnAreaMarkerRotationToggleChanged(bool enabled) { ApplyConfigurationDraft(WardSettings.WithAreaMarkerRotationEnabled(_currentConfiguration, enabled)); } private void ApplyConfigurationDraft(WardConfiguration configuration) { if (!_suppressUiEvents) { _currentConfiguration = configuration; RefreshControls(); ScheduleConfigurationPush(); } } private void PushConfiguration() { if (!((Object)(object)_currentWard == (Object)null)) { WardConfiguration currentConfiguration = _currentConfiguration; _configurationPushPending = false; WardConfigurationRequestSubmission wardConfigurationRequestSubmission = WardSettings.RequestUpdateConfiguration(_currentWard, currentConfiguration); if (wardConfigurationRequestSubmission.IsPending) { BeginPendingConfigurationRequest(wardConfigurationRequestSubmission.RequestId, currentConfiguration); return; } WardSettings.ShowConfigurationRequestFeedback(wardConfigurationRequestSubmission.ResultCode); ApplyConfigurationResponse(0L, wardConfigurationRequestSubmission.ResultCode, wardConfigurationRequestSubmission.Configuration); } } private void ScheduleConfigurationPush() { if (!_suppressUiEvents && !((Object)(object)_currentWard == (Object)null)) { _configurationPushPending = true; _nextConfigurationPushTime = Time.unscaledTime + 0.15f; } } private void FlushPendingConfigurationPush() { if (_configurationPushPending) { PushPendingConfiguration(); } } private void PushPendingConfiguration() { if (!_suppressUiEvents && !((Object)(object)_currentWard == (Object)null) && _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) { _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 (!_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 (_configurationPushPending && (_closeRequested || Time.unscaledTime >= _nextConfigurationPushTime)) { PushPendingConfiguration(); } if (_closeRequested && !HasPendingConfigurationRequest() && !_configurationPushPending) { CompleteCloseWardUi(); } } } private GameObject CreatePageRoot(string name, Vector2 panelSize) { //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_0030: 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_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected O, but got Unknown GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) }); val.transform.SetParent(_panel.transform, false); ConfigureRect(val.GetComponent(), Vector2.zero, panelSize.x, panelSize.y); return val; } private Transform GetBuildParent() { if (!((Object)(object)_buildParent != (Object)null)) { return _panel.transform; } return _buildParent; } 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