Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of STU Ward v1.3.1
STUWard.dll
Decompiled 19 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Security; using System.Security.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<string, Dictionary<string, string>> CachedTranslations = new Dictionary<string, Dictionary<string, string>>(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<TypeInfo> 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<string, string> value)) { value = new Dictionary<string, string>(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<string> availableLanguages = GetAvailableLanguages(); Dictionary<string, string> 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<string, string> 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<KeyValuePair<string, Dictionary<string, string>>, string>((KeyValuePair<string, Dictionary<string, string>> kv) => $"{kv.Key}={kv.Value.Count}")))); } } private static void RegisterWithJotunn() { if (_registeredWithJotunn) { return; } _registeredWithJotunn = true; foreach (KeyValuePair<string, Dictionary<string, string>> cachedTranslation in CachedTranslations) { cachedTranslation.Deconstruct(out var key, out var value); string text = key; Dictionary<string, string> dictionary = new Dictionary<string, string>(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<string, string> 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<string, string> GetTranslationsForLanguage(string language) { if (CachedTranslations.TryGetValue(language, out Dictionary<string, string> value)) { return value; } return CachedTranslations["English"]; } private static HashSet<string> GetAvailableLanguages() { HashSet<string> hashSet = new HashSet<string>(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<string>(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<string, string>? ReadMergedLanguage(string language, IReadOnlyDictionary<string, string>? englishFallback) { Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.Ordinal); if (englishFallback != null) { MergeInto(dictionary, englishFallback); } Dictionary<string, string> dictionary2 = ReadEmbeddedLanguage(language); if (dictionary2 != null) { MergeInto(dictionary, dictionary2); } Dictionary<string, string> dictionary3 = ReadExternalLanguage(language); if (dictionary3 != null) { MergeInto(dictionary, dictionary3); } if (dictionary.Count != 0) { return dictionary; } return null; } private static Dictionary<string, string>? 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<string, string>? 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<string, string> DeserializeTranslations(string rawText) { return Deserializer.Deserialize<Dictionary<string, string>>(rawText) ?? new Dictionary<string, string>(StringComparer.Ordinal); } private static void MergeInto(IDictionary<string, string> target, IReadOnlyDictionary<string, string> source) { foreach (KeyValuePair<string, string> 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<Toggle> ServerConfigLocked = null; internal static ConfigEntry<int> MaxWardsPerSteamId = null; internal static ConfigEntry<float> MaxWardRadius = null; internal static ConfigEntry<PickupBlockRule> PickupBlockMode = null; internal static ConfigEntry<HostileCreatureStructureProtectionMode> HostileCreatureStructureProtection = null; internal static readonly Dictionary<WardRestrictionOptions, ConfigEntry<RestrictionServerMode>> RestrictionModes = new Dictionary<WardRestrictionOptions, ConfigEntry<RestrictionServerMode>>(); internal static ConfigEntry<Toggle> DisableVanillaGuardStoneRecipe = null; internal static ConfigEntry<string> StuWardRecipe = null; internal static ConfigEntry<KeyboardShortcut> WardSettingsShortcut = null; internal static ConfigEntry<int> WardMinimapPinScale = null; internal static ConfigEntry<Toggle> WardMinimapActiveRanges = null; internal static ConfigEntry<BoundaryBrightenMode> 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<string> list = new List<string>(); 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<string> parts, IEnumerable<KeyCode> 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<T> BindConfigEntry<T>(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<WardGuiController>(); } private ConfigEntry<T> BindConfig<T>(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<object>())); ConfigEntry<T> val2 = ((BaseUnityPlugin)this).Config.Bind<T>(group, name, value, val); if (synchronizedSetting) { ConfigSync.AddConfigEntry<T>(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<float>(Plugin.MaxWardRadius, HandleMaxWardRadiusChanged); UnbindHandler<Plugin.HostileCreatureStructureProtectionMode>(Plugin.HostileCreatureStructureProtection, HandleWardPresenceConfigChanged); UnbindHandler<Plugin.Toggle>(Plugin.DisableVanillaGuardStoneRecipe, HandleRecipeSettingsChanged); UnbindHandler<string>(Plugin.StuWardRecipe, HandleRecipeSettingsChanged); UnbindHandler<int>(Plugin.WardMinimapPinScale, HandleLocalWardPinConfigChanged); UnbindHandler<Plugin.Toggle>(Plugin.WardMinimapActiveRanges, HandleLocalWardPinConfigChanged); UnbindHandler<Plugin.BoundaryBrightenMode>(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.Toggle>(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<WardRestrictionDefinition> 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<Plugin.RestrictionServerMode> 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<KeyboardShortcut>("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<float>(Plugin.MaxWardRadius, HandleMaxWardRadiusChanged); BindHandler<Plugin.HostileCreatureStructureProtectionMode>(Plugin.HostileCreatureStructureProtection, HandleWardPresenceConfigChanged); BindHandler<Plugin.Toggle>(Plugin.DisableVanillaGuardStoneRecipe, HandleRecipeSettingsChanged); BindHandler<string>(Plugin.StuWardRecipe, HandleRecipeSettingsChanged); BindHandler<int>(Plugin.WardMinimapPinScale, HandleLocalWardPinConfigChanged); BindHandler<Plugin.Toggle>(Plugin.WardMinimapActiveRanges, HandleLocalWardPinConfigChanged); BindHandler<Plugin.BoundaryBrightenMode>(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<T>(ConfigEntry<T>? entry, EventHandler handler) { if (entry != null) { entry.SettingChanged += handler; } } private static void UnbindHandler<T>(ConfigEntry<T>? 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<StuWardArea>() : null); } internal ManagedWardRef EnsureManagedComponent(out bool added) { added = false; if ((Object)(object)Area == (Object)null || HasManagedComponent || !IsManagedZdo || IsPlacementGhost) { return this; } ((Component)Area).gameObject.AddComponent<StuWardArea>(); 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<PrivateArea, bool> _isTrackable; private readonly List<PrivateArea> _areas = new List<PrivateArea>(); private readonly HashSet<int> _areaIds = new HashSet<int>(); private readonly Dictionary<long, List<SpatialWardEntry>> _spatialIndex = new Dictionary<long, List<SpatialWardEntry>>(); private readonly Dictionary<int, List<long>> _spatialCellsByInstanceId = new Dictionary<int, List<long>>(); private readonly Dictionary<int, int> _queryStamps = new Dictionary<int, int>(); private int _queryStamp; internal int Count => _areaIds.Count; internal ManagedWardIndex(Func<PrivateArea, bool> 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<PrivateArea> 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<SpatialWardEntry> 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<long> list = new List<long>(); 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<SpatialWardEntry> value)) { value = new List<SpatialWardEntry>(); _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<long> value)) { return; } for (int i = 0; i < value.Count; i++) { long key = value[i]; if (!_spatialIndex.TryGetValue(key, out List<SpatialWardEntry> 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<Type> OptionalPatchTypes = new HashSet<Type> { typeof(TameableCollectorCollectorItemPatch), typeof(AzuCraftyBoxesNearbyContainersPatch) }; internal static void ApplyAll(Harmony harmony) { List<string> list = new List<string>(); IReadOnlyList<Type> 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<string> 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<Type> GetHarmonyPatchTypes(Assembly assembly) { List<Type> list = new List<Type>(); 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<Type> GetLoadableTypes(Assembly assembly) { try { return assembly.GetTypes(); } catch (ReflectionTypeLoadException ex) { List<Type> list = new List<Type>(); 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<StuWardArea>() != (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<PrivateArea>(); 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<PrivateArea>() : 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<StuWardArea>() == (Object)null) { piecePrefab.AddComponent<StuWardArea>(); } if ((Object)(object)piecePrefab.GetComponent<StuWardPlacedHook>() == (Object)null) { piecePrefab.AddComponent<StuWardPlacedHook>(); } 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<Piece>()?.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<Piece>() : 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<GameObject> 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<int> 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<Piece>() : 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<ItemDrop>() : null)?.m_itemData?.m_shared?.m_buildPieces; } private static List<int> GetMatchingGuardStoneIndexes(List<GameObject> pieces, GameObject guardStonePrefab) { List<int> list = new List<int>(); 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>(); } 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<Requirement>(); string[] array = value.Split(new char[4] { ',', ';', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); if (array.Length == 0) { return false; } List<Requirement> list = new List<Requirement>(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<ItemDrop>() : 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<long> TargetPlayerIds = new HashSet<long>(); internal readonly HashSet<string> TargetCharacterKeys = new HashSet<string>(StringComparer.Ordinal); internal readonly HashSet<int> AffectedGuildIds = new HashSet<int>(); 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<long, SyncedWardGuildIdentity> ServerSyncedGuildByPlayerId = new Dictionary<long, SyncedWardGuildIdentity>(); private static readonly Dictionary<string, SyncedWardGuildIdentity> ServerSyncedGuildByCharacterKey = new Dictionary<string, SyncedWardGuildIdentity>(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<long, CachedWardGuildIdentity> PlayerGuildCache = new Dictionary<long, CachedWardGuildIdentity>(); 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<ZPackage>("STUWard_SyncPlayerGuild", (Action<long, ZPackage>)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<long> hashSet = new HashSet<long>(); if (identity.HasPlayerId) { hashSet.Add(identity.PlayerId); } if (identity.HasAccountAndName) { foreach (KeyValuePair<long, SyncedWardGuildIdentity> 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<WardGuildCharacterIdentity> list = new List<WardGuildCharacterIdentity>(); foreach (KeyValuePair<long, SyncedWardGuildIdentity> 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<long>? targetPlayerIds, HashSet<string>? targetCharacterKeys, HashSet<int>? affectedGuildIds) { HashSet<long> recipientPeerUids = null; if (!fullRefresh) { if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return; } List<ZNetPeer> peers = ZNet.instance.GetPeers(); recipientPeerUids = ((peers == null) ? new HashSet<long>() : CollectGuildProjectionRefreshRecipients(peers, targetPlayerIds, targetCharacterKeys, affectedGuildIds)); } ManagedWardMapStateService.NotifyViewerProjectionChanged(fullRefresh, recipientPeerUids, refreshImmediatelyIfVisible: true); } private static HashSet<long> CollectGuildProjectionRefreshRecipients(List<ZNetPeer> peers, HashSet<long>? targetPlayerIds, HashSet<string>? targetCharacterKeys, HashSet<int>? affectedGuildIds) { HashSet<long> hashSet = new HashSet<long>(); 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<long>? targetPlayerIds, HashSet<string>? targetCharacterKeys, HashSet<int>? 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<object>()) 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<WardGuildCharacterIdentity> 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<long> targetPlayerIds = ((pendingWardGuildProjectionRefresh.TargetPlayerIds.Count == 0) ? null : new HashSet<long>(pendingWardGuildProjectionRefresh.TargetPlayerIds)); HashSet<string> targetCharacterKeys = ((pendingWardGuildProjectionRefresh.TargetCharacterKeys.Count == 0) ? null : new HashSet<string>(pendingWardGuildProjectionRefresh.TargetCharacterKeys, StringComparer.Ordinal)); HashSet<int> affectedGuildIds = ((pendingWardGuildProjectionRefresh.AffectedGuildIds.Count == 0) ? null : new HashSet<int>(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<long>? targetPlayerIds, HashSet<string>? targetCharacterKeys, HashSet<int>? 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<ZDOID> hashSet = new HashSet<ZDOID>(); 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<WardGuildCharacterIdentity> CollectGuildMemberCharacterIdentities(object? guild, out bool hadUnresolvedMembers) { Dictionary<string, WardGuildCharacterIdentity> dictionary = new Dictionary<string, WardGuildCharacterIdentity>(StringComparer.Ordinal); hadUnresolvedMembers = false; if (guild == null || GuildMembersField == null) { return new List<WardGuildCharacterIdentity>(); } 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<WardGuildCharacterIdentity>(dictionary.Values); } if (!(value is IEnumerable enumerable)) { return new List<WardGuildCharacterIdentity>(); } 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<WardGuildCharacterIdentity>(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<long> hashSet = new HashSet<long>(); foreach (KeyValuePair<long, CachedWardGuildIdentity> 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(ac