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.1.9
STUWard.dll
Decompiled a day 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.EventSystems; using UnityEngine.Events; using UnityEngine.UI; using YamlDotNet.Core; using YamlDotNet.Core.Events; using YamlDotNet.Core.ObjectPool; using YamlDotNet.Core.Tokens; using YamlDotNet.Helpers; using YamlDotNet.Serialization; using YamlDotNet.Serialization.BufferedDeserialization; using YamlDotNet.Serialization.BufferedDeserialization.TypeDiscriminators; using YamlDotNet.Serialization.Callbacks; using YamlDotNet.Serialization.Converters; using YamlDotNet.Serialization.EventEmitters; using YamlDotNet.Serialization.NamingConventions; using YamlDotNet.Serialization.NodeDeserializers; using YamlDotNet.Serialization.NodeTypeResolvers; using YamlDotNet.Serialization.ObjectFactories; using YamlDotNet.Serialization.ObjectGraphTraversalStrategies; using YamlDotNet.Serialization.ObjectGraphVisitors; using YamlDotNet.Serialization.Schemas; using YamlDotNet.Serialization.TypeInspectors; using YamlDotNet.Serialization.TypeResolvers; using YamlDotNet.Serialization.Utilities; using YamlDotNet.Serialization.ValueDeserializers; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("STUWard")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("sighsorry")] [assembly: AssemblyProduct("STUWard")] [assembly: AssemblyCopyright("Copyright © 2021")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("4358610B-F3F4-4843-B7AF-98B7BC60DCDE")] [assembly: AssemblyFileVersion("1.1.9")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.1.9.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace LocalizationManager { public static class Localizer { private static readonly string[] FileExtensions = new string[2] { ".json", ".yml" }; private static readonly Dictionary<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) { string resourceFileName2 = resourceFileName; using MemoryStream memoryStream = new MemoryStream(); if ((object)containingAssembly == null) { containingAssembly = Assembly.GetCallingAssembly(); } string text = containingAssembly.GetManifestResourceNames().FirstOrDefault((string name) => name.EndsWith(resourceFileName2, StringComparison.OrdinalIgnoreCase)); if (text == null) { return null; } containingAssembly.GetManifestResourceStream(text)?.CopyTo(memoryStream); return (memoryStream.Length == 0L) ? null : memoryStream.ToArray(); } } public static class LocalizationManagerVersion { public const string Version = "1.4.1"; } } namespace STUWard { [BepInPlugin("sighsorry.STUWard", "STUWard", "1.1.9")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { internal enum Toggle { Off, On } internal enum PickupBlockRule { BlockAllExceptWhitelist, AllowAllExceptBlacklist } internal enum HostileCreatureStructureProtectionMode { Off, UnattendedOnly, Always } internal enum DiagnosticLogMode { Off, Failures, Verbose } internal const string ModName = "STUWard"; internal const string ModVersion = "1.1.9"; internal const string Author = "sighsorry"; internal const string ModGuid = "sighsorry.STUWard"; internal static readonly ConfigSync ConfigSync = new ConfigSync("sighsorry.STUWard") { DisplayName = "STUWard", CurrentVersion = "1.1.9", MinimumRequiredVersion = "1.1.9" }; private Harmony _harmony; internal static ManualLogSource Log = null; internal static Plugin Instance = null; internal static WardGuiController WardGui = null; internal static ConfigEntry<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 ConfigEntry<float> UnattendedWardTrustedPlayerRangeBuffer = null; internal static ConfigEntry<float> UnattendedWardTrustedPresenceGraceSeconds = null; internal static ConfigEntry<float> UnattendedWardPresenceRefreshInterval = null; 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<DiagnosticLogMode> WardDiagnosticLogging = null; private void Awake() { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; WardPluginBootstrap.InitializeCore(); bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet; ((BaseUnityPlugin)this).Config.SaveOnConfigSet = false; try { WardPluginConfigBindings.BindAll(); WardPluginBootstrap.InitializeFeatures(); _harmony = new Harmony("sighsorry.STUWard"); WardPatchRegistry.ApplyAll(_harmony); WardGui = CreateOrReuseWardGuiController(); ((BaseUnityPlugin)this).Config.Save(); } finally { ((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet; } } private void Update() { WardPluginBootstrap.Update(); } private void OnDestroy() { WardPluginBootstrap.Shutdown(); Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } ((BaseUnityPlugin)this).Config.Save(); } internal static bool IsBlockedItem(string prefabName) { return WardItemPrefabPolicy.IsBlockedItem(prefabName); } internal static bool HasBlockedItems() { return WardItemPrefabPolicy.HasBlockedItems(); } internal static bool IsWardSettingsShortcutDown() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) if (WardSettingsShortcut != null) { KeyboardShortcut value = WardSettingsShortcut.Value; if ((int)((KeyboardShortcut)(ref value)).MainKey != 0) { value = WardSettingsShortcut.Value; return ((KeyboardShortcut)(ref value)).IsDown(); } } return false; } internal static bool HasWardSettingsShortcutBinding() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Invalid comparison between Unknown and I4 if (WardSettingsShortcut != null) { KeyboardShortcut value = WardSettingsShortcut.Value; return (int)((KeyboardShortcut)(ref value)).MainKey > 0; } return false; } internal static string GetWardSettingsShortcutLabel() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Invalid comparison between Unknown and I4 //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) if (WardSettingsShortcut != null) { KeyboardShortcut value = WardSettingsShortcut.Value; if ((int)((KeyboardShortcut)(ref value)).MainKey != 0) { KeyboardShortcut value2 = WardSettingsShortcut.Value; List<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 static string GetKeyLabel(KeyCode keyCode) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected I4, but got Unknown //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Expected I4, but got Unknown switch (keyCode - 48) { default: switch (keyCode - 303) { case 4: case 5: return "Alt"; case 2: case 3: return "Ctrl"; case 0: case 1: return "Shift"; default: return ((object)(KeyCode)(ref keyCode)).ToString(); } case 0: return "0"; case 1: return "1"; case 2: return "2"; case 3: return "3"; case 4: return "4"; case 5: return "5"; case 6: return "6"; case 7: return "7"; case 8: return "8"; case 9: return "9"; } } internal static ConfigEntry<T> BindConfigEntry<T>(string group, string name, T value, string description, bool synchronizedSetting = true) { return Instance.BindConfig(group, name, value, description, synchronizedSetting); } internal static bool ShouldLogWardDiagnosticFailures() { if (WardDiagnosticLogging != null) { return WardDiagnosticLogging.Value != DiagnosticLogMode.Off; } return false; } internal static bool ShouldLogWardDiagnosticVerbose() { if (WardDiagnosticLogging != null) { return WardDiagnosticLogging.Value == DiagnosticLogMode.Verbose; } return false; } internal static void LogWardDiagnosticFailure(string context, string message) { if (ShouldLogWardDiagnosticFailures() && Log != null) { Log.LogWarning((object)("[WardDiag:" + context + "] " + message)); } } internal static void LogWardDiagnosticVerbose(string context, string message) { if (ShouldLogWardDiagnosticVerbose() && Log != null) { Log.LogInfo((object)("[WardDiag:" + context + "] " + message)); } } private static WardGuiController CreateOrReuseWardGuiController() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown if ((Object)(object)WardGuiController.Instance != (Object)null) { return WardGuiController.Instance; } GameObject val = new GameObject("STUWard.WardGui"); Object.DontDestroyOnLoad((Object)val); return val.AddComponent<WardGuiController>(); } private ConfigEntry<T> BindConfig<T>(string group, string name, T value, string description, bool synchronizedSetting = true) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown string text = (synchronizedSetting ? "Synced with server." : "Not synced with server."); string text2 = (string.IsNullOrWhiteSpace(description) ? text : (description.TrimEnd() + " " + text)); ConfigEntry<T> val = ((BaseUnityPlugin)this).Config.Bind<T>(group, name, value, new ConfigDescription(text2, (AcceptableValueBase)null, Array.Empty<object>())); if (synchronizedSetting) { ConfigSync.AddConfigEntry<T>(val).SynchronizedConfig = true; } return val; } } internal static class WardPluginBootstrap { internal static void InitializeCore() { Localizer.Load(); } internal static void InitializeFeatures() { WardGuiLayoutSettings.Bind(); ManagedWardConfigFileService.Initialize(); WardItemPrefabPolicy.Initialize(); WardOwnership.Initialize(); PrefabManager.OnVanillaPrefabsAvailable += RegisterStuWardPiece; RegisterStuWardPiece(); } internal static void Update() { ManagedWardRuntimeLifecycle.Update(); } internal static void Shutdown() { PrefabManager.OnVanillaPrefabsAvailable -= RegisterStuWardPiece; WardPluginConfigBindings.UnbindAll(); WardItemPrefabPolicy.Shutdown(); ManagedWardConfigFileService.Shutdown(); GuildsCompat.TryShutdownHooks(); Localizer.Unload(); } internal static void ApplyRecipeSettings() { StuWardPrefab.ApplyRecipeSettings(); } private static void RegisterStuWardPiece() { StuWardPrefab.Register(); ApplyRecipeSettings(); } } internal static class WardPluginConfigBindings { private static bool _handlersBound; internal static void BindAll() { UnbindAll(); BindGeneral(); BindClient(); BindDebug(); BindHandlers(); } internal static void UnbindAll() { if (_handlersBound) { UnbindHandler<float>(Plugin.MaxWardRadius, HandleMaxWardRadiusChanged); UnbindHandler<int>(Plugin.MaxWardsPerSteamId, HandleMaxWardLimitChanged); UnbindHandler<Plugin.HostileCreatureStructureProtectionMode>(Plugin.HostileCreatureStructureProtection, HandleWardPresenceConfigChanged); UnbindHandler<float>(Plugin.UnattendedWardTrustedPlayerRangeBuffer, HandleWardPresenceConfigChanged); UnbindHandler<float>(Plugin.UnattendedWardTrustedPresenceGraceSeconds, HandleWardPresenceConfigChanged); UnbindHandler<float>(Plugin.UnattendedWardPresenceRefreshInterval, HandleWardPresenceConfigChanged); UnbindHandler<Plugin.Toggle>(Plugin.DisableVanillaGuardStoneRecipe, HandleRecipeSettingsChanged); UnbindHandler<string>(Plugin.StuWardRecipe, HandleRecipeSettingsChanged); UnbindHandler<int>(Plugin.WardMinimapPinScale, HandleLocalWardPinConfigChanged); UnbindHandler<Plugin.Toggle>(Plugin.WardMinimapActiveRanges, HandleLocalWardPinConfigChanged); _handlersBound = false; } } private static void BindGeneral() { Plugin.ServerConfigLocked = Plugin.BindConfigEntry("1 - General", "Lock Configuration", Plugin.Toggle.On, "If on, the configuration is locked and can be changed by server admins only."); Plugin.ConfigSync.AddLockingConfigEntry<Plugin.Toggle>(Plugin.ServerConfigLocked); Plugin.MaxWardsPerSteamId = Plugin.BindConfigEntry("1 - General", "Max Wards Per Steam ID", 3, "Maximum number of managed Wards allowed per Steam/platform account. Set to -1 for unlimited."); Plugin.MaxWardRadius = Plugin.BindConfigEntry("1 - General", "Max Ward Radius", 32f, "Maximum configurable Ward radius. Valid range: 8 to 64."); Plugin.PickupBlockMode = Plugin.BindConfigEntry("1 - General", "Pickup Block Mode", Plugin.PickupBlockRule.BlockAllExceptWhitelist, "Pickup rule inside a foreign enabled ward. BlockAllExceptWhitelist blocks every item pickup except pickup_whitelist. AllowAllExceptBlacklist allows item pickup except pickup_blacklist."); Plugin.HostileCreatureStructureProtection = Plugin.BindConfigEntry("2 - Unattended Protection", "Hostile Creature Structure Protection Mode", Plugin.HostileCreatureStructureProtectionMode.UnattendedOnly, "Controls whether building pieces inside an enabled ward ignore damage from MonsterAI-controlled attackers. Off disables this extra protection. UnattendedOnly protects while no trusted player is nearby. Always protects regardless of trusted player presence."); Plugin.UnattendedWardTrustedPlayerRangeBuffer = Plugin.BindConfigEntry("2 - Unattended Protection", "Unattended Ward Trusted Player Range Buffer", 16f, "Additional distance beyond the ward radius used when checking for nearby trusted players before hostile-creature structure protection turns off."); Plugin.UnattendedWardTrustedPresenceGraceSeconds = Plugin.BindConfigEntry("2 - Unattended Protection", "Unattended Ward Trusted Presence Grace Seconds", 10f, "How long a ward keeps counting as attended after the last nearby trusted player leaves."); Plugin.UnattendedWardPresenceRefreshInterval = Plugin.BindConfigEntry("2 - Unattended Protection", "Unattended Ward Presence Refresh Interval", 1f, "How often nearby trusted-player attendance is recalculated for unattended hostile-creature structure protection."); Plugin.DisableVanillaGuardStoneRecipe = Plugin.BindConfigEntry("1 - General", "Disable Vanilla Guard Stone Recipe", Plugin.Toggle.On, "If on, the vanilla guard_stone build recipe is removed from the Hammer piece table while STUWard remains available."); Plugin.StuWardRecipe = Plugin.BindConfigEntry("1 - General", "STUWard Recipe", "GreydwarfEye:1,BoneFragments:3,Flint:5,Wood:7", "STUWard recipe override. Format: ItemPrefab:Amount[:Recover], ..."); } private static void BindClient() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) Plugin.WardSettingsShortcut = Plugin.BindConfigEntry<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); Plugin.WardMinimapPinScale = Plugin.BindConfigEntry("3 - Client", "Ward Minimap Pin Scale", 1, "0 disables ward icon pins. 1 is the default icon size. 100 means x100 icon size.", synchronizedSetting: false); Plugin.WardMinimapActiveRanges = Plugin.BindConfigEntry("3 - Client", "Ward Minimap Active Ranges", Plugin.Toggle.On, "If on, enabled managed wards also show their active radius on the minimap and map.", synchronizedSetting: false); } private static void BindDebug() { Plugin.WardDiagnosticLogging = Plugin.BindConfigEntry("4 - Debug", "Ward Diagnostic Logging", Plugin.DiagnosticLogMode.Off, "Local-only scalar diagnostic logging for ward ownership/toggle flows. Use Failures for rejection paths only, or Verbose for request and state tracing. Enable separately on each client/server instance you want logs from.", synchronizedSetting: false); } private static void BindHandlers() { BindHandler<float>(Plugin.MaxWardRadius, HandleMaxWardRadiusChanged); BindHandler<int>(Plugin.MaxWardsPerSteamId, HandleMaxWardLimitChanged); BindHandler<Plugin.HostileCreatureStructureProtectionMode>(Plugin.HostileCreatureStructureProtection, HandleWardPresenceConfigChanged); BindHandler<float>(Plugin.UnattendedWardTrustedPlayerRangeBuffer, HandleWardPresenceConfigChanged); BindHandler<float>(Plugin.UnattendedWardTrustedPresenceGraceSeconds, HandleWardPresenceConfigChanged); BindHandler<float>(Plugin.UnattendedWardPresenceRefreshInterval, HandleWardPresenceConfigChanged); BindHandler<Plugin.Toggle>(Plugin.DisableVanillaGuardStoneRecipe, HandleRecipeSettingsChanged); BindHandler<string>(Plugin.StuWardRecipe, HandleRecipeSettingsChanged); BindHandler<int>(Plugin.WardMinimapPinScale, HandleLocalWardPinConfigChanged); BindHandler<Plugin.Toggle>(Plugin.WardMinimapActiveRanges, HandleLocalWardPinConfigChanged); _handlersBound = true; } private static void HandleMaxWardRadiusChanged(object? _, EventArgs __) { WardSettings.HandleMaxRadiusChanged(); } private static void HandleMaxWardLimitChanged(object? _, EventArgs __) { WardOwnership.HandleWardLimitPolicyChanged(); } private static void HandleWardPresenceConfigChanged(object? _, EventArgs __) { ManagedWardRuntimeInvalidationService.PublishPresencePolicyChanged("ward presence config changed"); } private static void HandleRecipeSettingsChanged(object? _, EventArgs __) { WardPluginBootstrap.ApplyRecipeSettings(); } private static void HandleLocalWardPinConfigChanged(object? _, EventArgs __) { WardMinimapPinsManager.HandleLocalConfigChanged(); } private static void BindHandler<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 IsManaged { get { if (!HasManagedComponent) { return IsManagedZdo; } return true; } } internal bool IsPlacementGhost { get { if ((Object)(object)Area != (Object)null) { return Player.IsPlacementGhost(((Component)Area).gameObject); } return false; } } internal bool HasValidNetworkIdentity { get { if ((Object)(object)NView != (Object)null && NView.IsValid()) { return Zdo != null; } return false; } } internal bool IsOwner { get { if ((Object)(object)NView != (Object)null && NView.IsValid()) { return NView.IsOwner(); } return false; } } internal long CreatorPlayerId { get { ZDO? zdo = Zdo; if (zdo == null) { return 0L; } return zdo.GetLong(ZDOVars.s_creator, 0L); } } private ManagedWardRef(PrivateArea? area, ZNetView? nview, ZDO? zdo, StuWardArea? component) { Area = area; NView = nview; Zdo = zdo; Component = component; } internal static ManagedWardRef FromArea(PrivateArea? area) { return FromArea(area, null); } internal static ManagedWardRef FromArea(PrivateArea? area, ZDO? knownZdo) { ZNetView nView = WardPrivateAreaSafeAccess.GetNView(area); ZDO zdo = ((knownZdo != null && knownZdo.IsValid()) ? knownZdo : WardPrivateAreaSafeAccess.GetZdo(nView)); return new ManagedWardRef(area, nView, zdo, ((Object)(object)area != (Object)null) ? ((Component)area).GetComponent<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 static class WardPatchRegistry { internal static void ApplyAll(Harmony harmony) { List<string> list = new List<string>(); PatchWardCore(harmony, list); PatchInteractions(harmony, list); PatchBuildAndDamage(harmony, list); PatchItemAndCombat(harmony); PatchCompat(harmony); if (list.Count == 0) { return; } string text = "Failed to apply required patches: " + string.Join(", ", list); Plugin.Log.LogError((object)text); throw new InvalidOperationException(text); } private static void PatchWardCore(Harmony harmony, ICollection<string> failedRequiredPatches) { PatchRequired(harmony, typeof(PrivateAreaAwakePatch), failedRequiredPatches); PatchRequired(harmony, typeof(PrivateAreaOnDestroyPatch), failedRequiredPatches); PatchRequired(harmony, typeof(PrivateAreaUpdateStatusPatch), failedRequiredPatches); PatchRequired(harmony, typeof(PrivateAreaSetupPatch), failedRequiredPatches); PatchRequired(harmony, typeof(ZNetSceneCreateObjectManagedWardPatch), failedRequiredPatches); PatchOptional(harmony, typeof(PrivateAreaShowAreaMarkerPatch)); PatchOptional(harmony, typeof(PrivateAreaGetHoverTextPatch)); PatchOptional(harmony, typeof(PrivateAreaHideMarkerPatch)); PatchOptional(harmony, typeof(PrivateAreaHaveLocalAccessManagedPatch)); PatchOptional(harmony, typeof(PrivateAreaCheckAccessManagedPatch)); PatchOptional(harmony, typeof(PrivateAreaInteractAdminDebugPatch)); PatchRequired(harmony, typeof(PrivateAreaRpcTogglePermittedManagedPatch), failedRequiredPatches); PatchRequired(harmony, typeof(PrivateAreaRpcToggleEnabledAdminDebugPatch), failedRequiredPatches); PatchOptional(harmony, typeof(PrivateAreaRpcFlashShieldVolumePatch)); PatchOptional(harmony, typeof(PrivateAreaAddPermittedSnapshotPatch)); PatchOptional(harmony, typeof(PrivateAreaRemovePermittedSnapshotPatch)); PatchOptional(harmony, typeof(PrivateAreaSetEnabledWardMinimapVisibilityPatch)); PatchOptional(harmony, typeof(CircleProjectorCreateSegmentsPatch)); PatchOptional(harmony, typeof(DoorRpcUseDoorPatch)); PatchOptional(harmony, typeof(ZNetAwakeWardOwnershipPatch)); PatchOptional(harmony, typeof(ZNetRpcPeerInfoWardOwnershipPatch)); PatchOptional(harmony, typeof(ZNetRpcCharacterIdWardOwnershipPatch)); PatchOptional(harmony, typeof(ZNetDisconnectWardOwnershipPatch)); PatchOptional(harmony, typeof(PlayerStartWardOwnershipPatch)); PatchOptional(harmony, typeof(PlayerOnDeathWardUiPatch)); PatchOptional(harmony, typeof(PlayerOnRespawnWardUiPatch)); PatchOptional(harmony, typeof(PlayerUpdateWardAdminDebugPatch)); PatchOptional(harmony, typeof(MinimapSetMapModeWardPinsPatch)); PatchOptional(harmony, typeof(PlayerUpdateWardPinsPatch)); PatchOptional(harmony, typeof(ObjectDBAwakePatch)); PatchOptional(harmony, typeof(ObjectDBCopyOtherDbPatch)); } private static void PatchInteractions(Harmony harmony, ICollection<string> failedRequiredPatches) { PatchRequired(harmony, typeof(DirectInteractionPatches), failedRequiredPatches); PatchOptional(harmony, typeof(ContainerCheckAccessManagedPatch)); PatchRequired(harmony, typeof(UseItemInteractionPatches), failedRequiredPatches); PatchOptional(harmony, typeof(StationUsePatches)); PatchOptional(harmony, typeof(ProcessingInteractionPatches)); PatchOptional(harmony, typeof(TeleportWorldTeleportPatch)); PatchOptional(harmony, typeof(TeleportWorldTriggerPatch)); PatchRequired(harmony, typeof(ItemDropPickupPatch), failedRequiredPatches); PatchRequired(harmony, typeof(HumanoidPickupPatch), failedRequiredPatches); } private static void PatchBuildAndDamage(Harmony harmony, ICollection<string> failedRequiredPatches) { PatchRequired(harmony, typeof(PlayerTryPlacePiecePatch), failedRequiredPatches); PatchOptional(harmony, typeof(PlayerSetupPlacementGhostPatch)); PatchOptional(harmony, typeof(PlayerUpdatePlacementGhostPatch)); PatchRequired(harmony, typeof(PlayerPlacePiecePatch), failedRequiredPatches); PatchRequired(harmony, typeof(PlayerCheckCanRemovePiecePatch), failedRequiredPatches); PatchRequired(harmony, typeof(PlayerRemovePiecePatch), failedRequiredPatches); PatchOptional(harmony, typeof(PlayerRepairPatch)); PatchRequired(harmony, typeof(ZNetSceneDestroyPatch), failedRequiredPatches); PatchOptional(harmony, typeof(AttackSpawnOnHitTerrainPatch)); PatchOptional(harmony, typeof(TerrainOpAwakePatch)); PatchRequired(harmony, typeof(WearNTearDamagePatch), failedRequiredPatches); PatchRequired(harmony, typeof(WearNTearRpcDamagePatch), failedRequiredPatches); PatchRequired(harmony, typeof(WearNTearRemovePatch), failedRequiredPatches); PatchRequired(harmony, typeof(WearNTearRpcRemovePatch), failedRequiredPatches); PatchRequired(harmony, typeof(DestructibleDamagePatch), failedRequiredPatches); PatchRequired(harmony, typeof(DestructibleRpcDamagePatch), failedRequiredPatches); PatchRequired(harmony, typeof(TreeBaseDamagePatch), failedRequiredPatches); PatchRequired(harmony, typeof(TreeBaseRpcDamagePatch), failedRequiredPatches); } private static void PatchItemAndCombat(Harmony harmony) { PatchOptional(harmony, typeof(PlayerUseHotbarItemPatch)); PatchOptional(harmony, typeof(HumanoidUseItemPatch)); PatchOptional(harmony, typeof(HumanoidUpdateEquipmentPatch)); PatchOptional(harmony, typeof(HumanoidEquipItemPatch)); PatchOptional(harmony, typeof(HumanoidStartAttackPatch)); PatchOptional(harmony, typeof(AttackStartBlockedItemTargetPatch)); PatchOptional(harmony, typeof(InventoryGuiOnRightClickItemPatch)); PatchOptional(harmony, typeof(TameableCollectorCollectorItemPatch)); PatchOptional(harmony, typeof(AzuCraftyBoxesNearbyContainersPatch)); PatchOptional(harmony, typeof(FeastRpcTryEatPatch)); PatchOptional(harmony, typeof(PlayerAutoPickupPatch)); PatchOptional(harmony, typeof(TerminalAwakeWardReportCommandPatch)); PatchOptional(harmony, typeof(TerminalTryRunCommandWardReportPatch)); } private static void PatchCompat(Harmony harmony) { Harmony harmony2 = harmony; PatchOptionalCompat("GuildsCompat", delegate { GuildsCompat.TryPatch(harmony2); }); PatchOptionalCompat("TargetPortalCompat", delegate { TargetPortalCompat.TryPatch(harmony2); }); } private static void PatchRequired(Harmony harmony, Type patchType, ICollection<string> failedRequiredPatches) { try { harmony.CreateClassProcessor(patchType).Patch(); } catch (Exception ex) { failedRequiredPatches.Add(patchType.Name); Plugin.Log.LogError((object)("Failed to patch required " + patchType.Name + ": " + ex.GetType().Name + ": " + ex.Message)); } } private static void PatchOptional(Harmony harmony, Type patchType) { try { harmony.CreateClassProcessor(patchType).Patch(); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Failed to patch optional " + patchType.Name + ": " + ex.GetType().Name + ": " + ex.Message)); } } private static void PatchOptionalCompat(string name, Action patchAction) { try { patchAction(); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Failed to patch " + name + ": " + ex.GetType().Name + ": " + ex.Message)); } } } [DisallowMultipleComponent] internal sealed class StuWardArea : MonoBehaviour { internal const string PrefabName = "piece_stuward"; internal const string BasePrefabName = "guard_stone"; internal const string DisplayName = "$stuw_piece_name"; internal const string Description = "$stuw_piece_desc"; internal static bool IsManaged(PrivateArea? area) { if ((Object)(object)area != (Object)null) { return (Object)(object)((Component)area).GetComponent<StuWardArea>() != (Object)null; } return false; } } internal static class ManagedWardIdentity { internal static bool IsManaged(PrivateArea? area) { bool matchedByComponent; bool matchedByZdo; return TryResolve(ManagedWardRef.FromArea(area), repairComponent: false, out matchedByComponent, out matchedByZdo); } internal static bool EnsureManagedComponent(PrivateArea? area) { return EnsureManagedComponent(ManagedWardRef.FromArea(area)); } internal static bool EnsureManagedComponent(PrivateArea? area, ZDO? zdo) { return EnsureManagedComponent(ManagedWardRef.FromArea(area, zdo)); } internal static bool EnsureManagedComponent(ManagedWardRef ward) { bool matchedByComponent; bool matchedByZdo; return TryResolve(ward, repairComponent: true, out matchedByComponent, out matchedByZdo) && matchedByComponent; } internal static bool TryResolve(PrivateArea? area, ZDO? zdo, bool repairComponent, out bool matchedByComponent, out bool matchedByZdo) { return TryResolve(ManagedWardRef.FromArea(area, zdo), repairComponent, out matchedByComponent, out matchedByZdo); } internal static bool TryResolve(ManagedWardRef ward, bool repairComponent, out bool matchedByComponent, out bool matchedByZdo) { matchedByComponent = ward.HasManagedComponent; matchedByZdo = ward.IsManagedZdo; if (!ward.HasArea) { return matchedByZdo; } if ((!matchedByComponent & matchedByZdo) && repairComponent) { bool added; ManagedWardRef managedWardRef = ward.EnsureManagedComponent(out added); matchedByComponent = managedWardRef.HasManagedComponent; if (added) { Plugin.LogWardDiagnosticVerbose("Placement.Identity", "Restored missing StuWardArea component from managed ward ZDO identity. " + WardDiagnosticInfo.DescribeWard(managedWardRef.Area)); } } return matchedByComponent | matchedByZdo; } } internal sealed class StuWardPlacedHook : MonoBehaviour, IPlaced { public void OnPlaced() { PrivateArea component = ((Component)this).GetComponent<PrivateArea>(); ManagedWardRef ward = ManagedWardRef.FromArea(component); if (ManagedWardIdentity.EnsureManagedComponent(ward)) { WardOwnership.TryStampLocalManagedWardOwnerAccount(ward); WardOwnership.NotifyServerManagedWardPlaced(ward); ManagedWardMapStateService.NotifyLiveWardMutation(component, ManagedWardMapMutationKind.IndexAndPins, "local managed ward placed"); Plugin.LogWardDiagnosticVerbose("Placement.OnPlaced", "IPlaced.OnPlaced hit for managed ward. " + WardDiagnosticInfo.DescribeWard(component)); } } } internal static class StuWardPrefab { private static bool _registered; private static GameObject? _stuWardPrefab; private static GameObject? _vanillaGuardStonePrefab; private static int _vanillaGuardStoneIndex = -1; private static Requirement[]? _defaultStuWardRequirements; private static string? _lastLoggedPieceIconState; internal static void Register() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Expected O, but got Unknown //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Expected O, but got Unknown if (_registered || PieceManager.Instance.GetPiece("piece_stuward") != null) { _registered = true; } else { if ((Object)(object)PrefabManager.Instance.GetPrefab("guard_stone") == (Object)null) { return; } PieceConfig val = new PieceConfig { PieceTable = "Hammer", Name = "$stuw_piece_name", Description = "$stuw_piece_desc" }; CustomPiece val2 = new CustomPiece("piece_stuward", "guard_stone", val); GameObject piecePrefab = val2.PiecePrefab; Piece piece = val2.Piece; PrivateArea val3 = (((Object)(object)piecePrefab != (Object)null) ? piecePrefab.GetComponent<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 LogPieceIconResolution(stuWardPiece.m_icon, "stuWardPrefab piece icon '" + ((Object)stuWardPiece.m_icon).name + "'"); } CustomPiece piece = PieceManager.Instance.GetPiece("piece_stuward"); if ((Object)(object)((piece != null) ? piece.Piece : null) != (Object)null && (Object)(object)piece.Piece.m_icon != (Object)null) { return LogPieceIconResolution(piece.Piece.m_icon, "registered piece icon '" + ((Object)piece.Piece.m_icon).name + "'"); } GameObject val = ((piece != null) ? piece.PiecePrefab : null) ?? PrefabManager.Instance.GetPrefab("piece_stuward") ?? PrefabManager.Instance.GetPrefab("guard_stone"); Sprite val2 = ((!((Object)(object)val != (Object)null)) ? null : val.GetComponent<Piece>()?.m_icon); if ((Object)(object)val2 != (Object)null) { string text = (((Object)(object)val != (Object)null) ? ((Object)val).name : "null"); return LogPieceIconResolution(val2, "prefab '" + text + "' piece icon '" + ((Object)val2).name + "'"); } return LogMissingPieceIcon(string.Format("stuWardPrefabPresent={0}, registeredPiecePresent={1}, registeredPiecePrefabPresent={2}, fallbackPrefab='{3}'", (Object)(object)_stuWardPrefab != (Object)null, (Object)(object)((piece != null) ? piece.Piece : null) != (Object)null, (Object)(object)((piece != null) ? piece.PiecePrefab : null) != (Object)null, ((val != null) ? ((Object)val).name : null) ?? "null")); } internal static Requirement[] GetCurrentStuWardRequirements() { return CloneRequirements(GetStuWardPiece()?.m_resources); } private static Piece? GetStuWardPiece() { Piece val = (((Object)(object)_stuWardPrefab != (Object)null) ? _stuWardPrefab.GetComponent<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 Sprite LogPieceIconResolution(Sprite icon, string source) { string text = "resolved:" + source; if (_lastLoggedPieceIconState != text) { _lastLoggedPieceIconState = text; Plugin.LogWardDiagnosticVerbose("WardPins.Icon", "Resolved piece_stuward icon from " + source + "."); } return icon; } private static Sprite? LogMissingPieceIcon(string context) { string text = "missing:" + context; if (_lastLoggedPieceIconState != text) { _lastLoggedPieceIconState = text; Plugin.LogWardDiagnosticFailure("WardPins.Icon", "Failed to resolve piece_stuward icon. " + context); } return null; } internal static void ApplyVanillaGuardStoneRecipeSetting() { PieceTable? hammerPieceTable = GetHammerPieceTable(); List<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 CachedWardGuildIdentity(bool hasGuild, int guildId, string guildName, DateTime expiresAtUtc) { HasGuild = hasGuild; GuildId = guildId; GuildName = guildName; ExpiresAtUtc = expiresAtUtc; } } internal readonly struct CachedPlayerPlatformIdentity { internal bool HasPlatformId { get; } internal string PlatformId { get; } internal DateTime ExpiresAtUtc { get; } internal CachedPlayerPlatformIdentity(bool hasPlatformId, string platformId, DateTime expiresAtUtc) { HasPlatformId = hasPlatformId; PlatformId = platformId; ExpiresAtUtc = expiresAtUtc; } } internal readonly struct WardGuildCharacterIdentity { internal long PlayerId { get; } internal string AccountId { get; } internal string PlayerName { get; } internal bool HasPlayerId => PlayerId != 0; internal bool HasAccountAndName { get { if (!string.IsNullOrWhiteSpace(AccountId)) { return !string.IsNullOrWhiteSpace(PlayerName); } return false; } } internal WardGuildCharacterIdentity(long playerId, string accountId, string playerName) { PlayerId = playerId; AccountId = WardOwnership.NormalizeAccountIdValue(accountId); PlayerName = playerName?.Trim() ?? string.Empty; } } internal static class GuildsCompat { private enum AvailabilityState { Unknown, Available, Unavailable } private sealed class PendingWardGuildProjectionRefreshState { internal readonly Dictionary<long, WardGuildCharacterIdentity> TargetIdentitiesByPlayerId = new Dictionary<long, WardGuildCharacterIdentity>(); internal readonly Dictionary<string, WardGuildCharacterIdentity> TargetIdentitiesByCharacterKey = new Dictionary<string, WardGuildCharacterIdentity>(StringComparer.Ordinal); internal readonly HashSet<int> AffectedGuildIds = new HashSet<int>(); internal bool PendingFullRefresh; internal bool PendingLiveDisplayRefresh; internal string PendingLiveDisplayReason = string.Empty; internal DateTime FlushAtUtc = DateTime.MinValue; } private const string GuildIdKey = "stuw_guild_id"; private const string GuildNameKey = "stuw_guild_name"; private static readonly TimeSpan GuildLookupCacheDuration = TimeSpan.FromSeconds(30.0); private const string SyncPlayerGuildRpc = "STUWard_SyncPlayerGuild"; private static readonly TimeSpan PendingPlayerGuildSyncLifetime = TimeSpan.FromSeconds(15.0); private static readonly Dictionary<long, SyncedWardGuildIdentity> ServerSyncedGuildByPlayerId = new Dictionary<long, SyncedWardGuildIdentity>(); private static readonly Dictionary<string, SyncedWardGuildIdentity> ServerSyncedGuildByCharacterKey = new Dictionary<string, SyncedWardGuildIdentity>(StringComparer.Ordinal); private static readonly Dictionary<long, PendingPlayerGuildSync> PendingPlayerGuildSyncsBySender = new Dictionary<long, PendingPlayerGuildSync>(); private static bool _syncRpcsRegistered; private static bool _localGuildSyncPending = true; private static long _lastSyncedLocalPlayerId; private static int _lastSyncedLocalGuildId = int.MinValue; private static string _lastSyncedLocalGuildName = string.Empty; private const string GuildsPluginGuid = "org.bepinex.plugins.guilds"; private static readonly TimeSpan AvailabilityProbeBackoff = TimeSpan.FromSeconds(2.0); private static readonly Assembly? GuildsAssembly = GetPluginAssembly("org.bepinex.plugins.guilds"); private static readonly Type? ApiType = GuildsAssembly?.GetType("Guilds.API"); private static readonly Type? GuildType = GuildsAssembly?.GetType("Guilds.Guild"); private static readonly Type? GuildGeneralType = GuildsAssembly?.GetType("Guilds.GuildGeneral"); private static readonly Type? PlayerReferenceType = GuildsAssembly?.GetType("Guilds.PlayerReference"); private static readonly Type? GuildJoinedDelegateType = ApiType?.GetNestedType("GuildJoined", BindingFlags.Public | BindingFlags.NonPublic); private static readonly Type? GuildLeftDelegateType = ApiType?.GetNestedType("GuildLeft", BindingFlags.Public | BindingFlags.NonPublic); private static readonly Type? GuildCreatedDelegateType = ApiType?.GetNestedType("GuildCreated", BindingFlags.Public | BindingFlags.NonPublic); private static readonly Type? GuildDeletedDelegateType = ApiType?.GetNestedType("GuildDeleted", BindingFlags.Public | BindingFlags.NonPublic); private static readonly MethodInfo? IsLoadedMethod = ((ApiType != null) ? AccessTools.Method(ApiType, "IsLoaded", (Type[])null, (Type[])null) : null); private static readonly MethodInfo? GetPlayerGuildByPlayerMethod = ((ApiType != null) ? AccessTools.Method(ApiType, "GetPlayerGuild", new Type[1] { typeof(Player) }, (Type[])null) : null); private static readonly MethodInfo? GetPlayerGuildByReferenceMethod = ((ApiType != null && PlayerReferenceType != null) ? AccessTools.Method(ApiType, "GetPlayerGuild", new Type[1] { PlayerReferenceType }, (Type[])null) : null); private static readonly MethodInfo? GetGuildsMethod = ((ApiType != null) ? AccessTools.Method(ApiType, "GetGuilds", Type.EmptyTypes, (Type[])null) : null); private static readonly MethodInfo? GetGuildByIdMethod = ((ApiType != null) ? AccessTools.Method(ApiType, "GetGuild", new Type[1] { typeof(int) }, (Type[])null) : null); private static readonly MethodInfo? PlayerReferenceFromStringMethod = ((PlayerReferenceType != null) ? AccessTools.Method(PlayerReferenceType, "fromString", new Type[1] { typeof(string) }, (Type[])null) : null); private static readonly MethodInfo? RegisterOnGuildJoinedMethod = ((ApiType != null && GuildJoinedDelegateType != null) ? AccessTools.Method(ApiType, "RegisterOnGuildJoined", new Type[1] { GuildJoinedDelegateType }, (Type[])null) : null); private static readonly MethodInfo? RegisterOnGuildLeftMethod = ((ApiType != null && GuildLeftDelegateType != null) ? AccessTools.Method(ApiType, "RegisterOnGuildLeft", new Type[1] { GuildLeftDelegateType }, (Type[])null) : null); private static readonly MethodInfo? RegisterOnGuildCreatedMethod = ((ApiType != null && GuildCreatedDelegateType != null) ? AccessTools.Method(ApiType, "RegisterOnGuildCreated", new Type[1] { GuildCreatedDelegateType }, (Type[])null) : null); private static readonly MethodInfo? RegisterOnGuildDeletedMethod = ((ApiType != null && GuildDeletedDelegateType != null) ? AccessTools.Method(ApiType, "RegisterOnGuildDeleted", new Type[1] { GuildDeletedDelegateType }, (Type[])null) : null); private static readonly MethodInfo? SaveGuildMethod = ((ApiType != null && GuildType != null) ? AccessTools.Method(ApiType, "SaveGuild", new Type[1] { GuildType }, (Type[])null) : null); private static readonly FieldInfo? PlayerInfoUserInfoField = AccessTools.Field(typeof(PlayerInfo), "m_userInfo"); private static readonly FieldInfo? UserInfoIdField = ((PlayerInfoUserInfoField?.FieldType != null) ? AccessTools.Field(PlayerInfoUserInfoField.FieldType, "m_id") : null); private static readonly FieldInfo? GuildNameField = ((GuildType != null) ? AccessTools.Field(GuildType, "Name") : null); private static readonly FieldInfo? GuildGeneralField = ((GuildType != null) ? AccessTools.Field(GuildType, "General") : null); private static readonly FieldInfo? GuildGeneralIdField = ((GuildGeneralType != null) ? AccessTools.Field(GuildGeneralType, "id") : null); private static readonly FieldInfo? GuildMembersField = ((GuildType != null) ? AccessTools.Field(GuildType, "Members") : null); private static readonly FieldInfo? PlayerReferenceIdField = ((PlayerReferenceType != null) ? AccessTools.Field(PlayerReferenceType, "id") : null); private static readonly FieldInfo? PlayerReferenceNameField = ((PlayerReferenceType != null) ? (AccessTools.Field(PlayerReferenceType, "name") ?? AccessTools.Field(PlayerReferenceType, "Name")) : null); private static readonly bool HasGuildsApiSurface = ApiType != null && IsLoadedMethod != null; private static AvailabilityState _availabilityState = AvailabilityState.Unknown; private static DateTime _nextAvailabilityProbeUtc = DateTime.MinValue; private static readonly TimeSpan PendingWardGuildProjectionRefreshDebounce = TimeSpan.FromMilliseconds(250.0); private static readonly PendingWardGuildProjectionRefreshState PendingWardGuildProjectionRefresh = new PendingWardGuildProjectionRefreshState(); private static readonly Dictionary<long, CachedWardGuildIdentity> PlayerGuildCache = new Dictionary<long, CachedWardGuildIdentity>(); private static readonly Dictionary<long, CachedPlayerPlatformIdentity> PlayerPlatformIdCache = new Dictionary<long, CachedPlayerPlatformIdentity>(); private static bool _guildHooksRegistered; private static bool _guildHooksActive; private static bool _saveGuildPatched; internal static void ResetRuntimeState() { PlayerGuildCache.Clear(); PlayerPlatformIdCache.Clear(); ResetPendingWardGuildProjectionRefreshes(); ResetSyncedGuildState(); _availabilityState = AvailabilityState.Unknown; _nextAvailabilityProbeUtc = DateTime.MinValue; } internal static void EnsureRuntimeBindings() { RegisterSyncRpcs(); } internal static void OnZNetAwake() { ResetRuntimeState(); EnsureRuntimeBindings(); } internal static WardGuildIdentity GetPlayerGuildIdentity(Player? player) { if (!TryGetGuild(player, out var guild)) { return default(WardGuildIdentity); } return guild; } internal static WardGuildIdentity GetPlayerGuildIdentity(long playerId) { if (!TryGetGuild(playerId, out var guild)) { return default(WardGuildIdentity); } return guild; } internal static WardGuildIdentity GetWardGuildIdentity(PrivateArea? area) { return new WardGuildIdentity(GetWardGuildId(area), GetWardGuildName(area)); } internal static WardGuildIdentity GetWardGuildIdentity(ZDO? zdo) { return new WardGuildIdentity(GetWardGuildId(zdo), GetWardGuildName(zdo)); } internal static int GetPlayerGuildId(Player? player) { if (!TryGetGuild(player, out var guild)) { return 0; } return guild.Id; } internal static int GetPlayerGuildId(long playerId) { if (!TryGetGuild(playerId, out var guild)) { return 0; } return guild.Id; } internal static string GetPlayerGuildName(long playerId) { if (!TryGetGuild(playerId, out var guild)) { return string.Empty; } return guild.Name; } internal static int GetWardGuildId(ZDO? zdo) { if (zdo == null) { return 0; } return zdo.GetInt("stuw_guild_id", 0); } internal static string GetWardGuildName(ZDO? zdo) { return ((zdo != null) ? zdo.GetString("stuw_guild_name", string.Empty) : null) ?? string.Empty; } internal static string BuildCharacterIdentityKey(string accountId, string playerName) { string text = WardOwnership.NormalizeAccountIdValue(accountId); string text2 = playerName?.Trim() ?? string.Empty; if (string.IsNullOrWhiteSpace(text) || string.IsNullOrWhiteSpace(text2)) { return string.Empty; } return text + "\n" + text2; } internal static void Update() { SyncLocalPlayerGuildIfNeeded(force: false); ProcessPendingPlayerGuildSyncs(); ProcessPendingWardGuildProjectionRefreshes(); } internal static void OnLocalPlayerStarted(Player? player) { if (!((Object)(object)player == (Object)null) && !((Object)(object)player != (Object)(object)Player.m_localPlayer)) { _localGuildSyncPending = true; SyncLocalPlayerGuildIfNeeded(force: true); } } internal static void ResetSyncedGuildState() { ServerSyncedGuildByPlayerId.Clear(); ServerSyncedGuildByCharacterKey.Clear(); PendingPlayerGuildSyncsBySender.Clear(); _syncRpcsRegistered = false; _localGuildSyncPending = true; _lastSyncedLocalPlayerId = 0L; _lastSyncedLocalGuildId = int.MinValue; _lastSyncedLocalGuildName = string.Empty; } internal static bool TryGetSyncedGuildIdentity(long playerId, string accountId, string playerName, out WardGuildIdentity guild) { guild = default(WardGuildIdentity); if (playerId != 0L && ServerSyncedGuildByPlayerId.TryGetValue(playerId, out var value)) { guild = (value.HasGuild ? new WardGuildIdentity(value.GuildId, value.GuildName) : default(WardGuildIdentity)); return true; } string text = BuildCharacterIdentityKey(accountId, playerName); if (string.IsNullOrWhiteSpace(text) || !ServerSyncedGuildByCharacterKey.TryGetValue(text, out var value2)) { return false; } guild = (value2.HasGuild ? new WardGuildIdentity(value2.GuildId, value2.GuildName) : default(WardGuildIdentity)); return true; } internal static bool TryGetSyncedGuildIdentity(string accountId, string playerName, out WardGuildIdentity guild) { return TryGetSyncedGuildIdentity(0L, accountId, playerName, out guild); } private static void RegisterSyncRpcs() { ZRoutedRpc instance = ZRoutedRpc.instance; if (!_syncRpcsRegistered && instance != null) { instance.Register<ZPackage>("STUWard_SyncPlayerGuild", (Action<long, ZPackage>)HandleSyncPlayerGuild); _syncRpcsRegistered = true; } } private static void SyncLocalPlayerGuildIfNeeded(bool force) { //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Expected O, but got Unknown Player localPlayer = Player.m_localPlayer; ZNet instance = ZNet.instance; if ((Object)(object)localPlayer == (Object)null || (Object)(object)instance == (Object)null) { return; } long playerID = localPlayer.GetPlayerID(); string playerAccountId = WardOwnership.GetPlayerAccountId(localPlayer); if (playerID == 0L || string.IsNullOrWhiteSpace(playerAccountId)) { return; } WardGuildIdentity playerGuildIdentity = GetPlayerGuildIdentity(localPlayer); string text = playerGuildIdentity.Name ?? string.Empty; bool flag = _localGuildSyncPending || playerID != _lastSyncedLocalPlayerId || playerGuildIdentity.Id != _lastSyncedLocalGuildId || !string.Equals(text, _lastSyncedLocalGuildName, StringComparison.Ordinal); if (!force && !flag) { return; } _lastSyncedLocalPlayerId = playerID; _lastSyncedLocalGuildId = playerGuildIdentity.Id; _lastSyncedLocalGuildName = text; _localGuildSyncPending = false; if (instance.IsServer()) { if (UpsertSyncedGuildIdentity(playerID, playerAccountId, localPlayer.GetPlayerName(), playerGuildIdentity, out var previousGuild)) { RefreshWardGuildProjectionForCharacter(new WardGuildCharacterIdentity(playerID, playerAccountId, localPlayer.GetPlayerName()), liveDisplayRefresh: true, playerGuildIdentity.Id, previousGuild.Id); } return; } ZRoutedRpc instance2 = ZRoutedRpc.instance; if (instance2 != null) { long serverPeerID = instance2.GetServerPeerID(); if (serverPeerID != 0L) { ZPackage val = new ZPackage(); val.Write(playerGuildIdentity.Id); val.Write(text); instance2.InvokeRoutedRPC(serverPeerID, "STUWard_SyncPlayerGuild", new object[1] { val }); } } } private static void HandleSyncPlayerGuild(long sender, ZPackage pkg) { if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer()) { int guildId = pkg.ReadInt(); string guildName = pkg.ReadString(); if (!TryApplySyncedGuildIdentity(sender, guildId, guildName)) { PendingPlayerGuildSyncsBySender[sender] = new PendingPlayerGuildSync(sender, guildId, guildName, DateTime.UtcNow); } } } private static void ProcessPendingPlayerGuildSyncs() { if (PendingPlayerGuildSyncsBySender.Count == 0 || (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return; } List<long> list = null; List<long> list2 = null; DateTime utcNow = DateTime.UtcNow; foreach (KeyValuePair<long, PendingPlayerGuildSync> item in PendingPlayerGuildSyncsBySender) { if (utcNow - item.Value.FirstSeenUtc > PendingPlayerGuildSyncLifetime) { if (list == null) { list = new List<long>(); } list.Add(item.Key); } else if (TryApplySyncedGuildIdentity(item.Value.SenderUid, item.Value.GuildId, item.Value.GuildName)) { if (list2 == null) { list2 = new List<long>(); } list2.Add(item.Key); } } if (list != null) { foreach (long item2 in list) { PendingPlayerGuildSyncsBySender.Remove(item2); } } if (list2 == null) { return; } foreach (long item3 in list2) { PendingPlayerGuildSyncsBySender.Remove(item3); } } private static bool TryApplySyncedGuildIdentity(long sender, int guildId, string guildName) { if (!WardOwnership.TryResolveAuthoritativePlayerIdFromSender(sender, "GuildsCompat.Sync", out var playerId)) { return false; } string text = WardOwnership.GetAuthoritativeAccountIdFromSender(sender, playerId); if (string.IsNullOrWhiteSpace(text)) { text = WardOwnership.GetPlayerAccountId(playerId); } if (string.IsNullOrWhiteSpace(text)) { return false; } WardGuildIdentity guild = ((guildId != 0) ? new WardGuildIdentity(guildId, guildName) : default(WardGuildIdentity)); string playerName = WardOwnership.GetPlayerName(playerId); if (UpsertSyncedGuildIdentity(playerId, text, playerName, guild, out var previousGuild)) { WardOwnership.RefreshServerPlayerAccountIdForResolvedPlayer(playerId, text); RefreshWardGuildProjectionForCharacter(new WardGuildCharacterIdentity(playerId, text, playerName), liveDisplayRefresh: true, guild.Id, previousGuild.Id); } return true; } private static void NotifyGuildProjectionRefreshApplied(string reason, bool fullRefresh, HashSet<long>? targetPlayerIds, HashSet<string>? targetCharacterKeys, HashSet<int>? affectedGuildIds) { string reason2 = (string.IsNullOrWhiteSpace(reason) ? "guild projection refreshed" : reason); HashSet<long> hashSet = null; if (!fullRefresh) { if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return; } List<ZNetPeer> peers = ZNet.instance.GetPeers(); if (peers == null) { return; } hashSet = CollectGuildProjectionRefreshRecipients(peers, targetPlayerIds, targetCharacterKeys, affectedGuildIds); if (hashSet.Count == 0) { return; } } ManagedWardMapStateService.NotifyViewerProjectionChanged(reason2, fullRefresh, hashSet, refreshImmediatelyIfVisible: true); } private static HashSet<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; } if (TryGetSyncedGuildIdentity(playerId, accountId, playerName, out var guild) && guild.Id != 0) { return affectedGuildIds.Contains(guild.Id); } return false; } private static bool UpsertSyncedGuildIdentity(long playerId, string accountId, string playerName, WardGuildIdentity guild, out WardGuildIdentity previousGuild) { previousGuild = default(WardGuildIdentity); bool result = false; SyncedWardGuildIdentity value = new SyncedWardGuildIdentity(guild.Id != 0, guild.Id, guild.Name); if (playerId != 0L) { if (ServerSyncedGuildByPlayerId.TryGetValue(playerId, out var value2)) { previousGuild = ToWardGuildIdentity(value2); } if (!ServerSyncedGuildByPlayerId.TryGetValue(playerId, out value2) || value2.HasGuild != value.HasGuild || value2.GuildId != value.GuildId || !string.Equals(value2.GuildName, value.GuildName, StringComparison.Ordinal)) { ServerSyncedGuildByPlayerId[playerId] = value; result = true; } } string text = BuildCharacterIdentityKey(accountId, playerName); if (string.IsNullOrWhiteSpace(text)) { return result; } if (previousGuild.Id == 0 && ServerSyncedGuildByCharacterKey.TryGetValue(text, out var value3)) { previousGuild = ToWardGuildIdentity(value3); } if (!ServerSyncedGuildByCharacterKey.TryGetValue(text, out var value4) || value4.HasGuild != value.HasGuild || value4.GuildId != value.GuildId || !string.Equals(value4.GuildName, value.GuildName, StringComparison.Ordinal)) { ServerSyncedGuildByCharacterKey[text] = value; result = true; } return result; } private static WardGuildIdentity ToWardGuildIdentity(SyncedWardGuildIdentity syncedGuild) { if (!syncedGuild.HasGuild) { return default(WardGuildIdentity); } return new WardGuildIdentity(syncedGuild.GuildId, syncedGuild.GuildName); } private static Assembly? GetPluginAssembly(string pluginGuid) { if (!Chainloader.PluginInfos.TryGetValue(pluginGuid, out var value)) { return null; } return ((object)value.Instance)?.GetType().Assembly; } internal static bool IsAvailable() { if (!HasGuildsApiSurface) { return false; } if (_availabilityState == AvailabilityState.Available) { return true; } DateTime utcNow = DateTime.UtcNow; if (_availabilityState == AvailabilityState.Unavailable && utcNow < _nextAvailabilityProbeUtc) { return false; } try { if ((IsLoadedMethod.Invoke(null, Array.Empty<object>()) as bool?).GetValueOrDefault()) { _availabilityState = AvailabilityState.Available; _nextAvailabilityProbeUtc = DateTime.MaxValue; return true; } } catch { } _availabilityState = AvailabilityState.Unavailable; _nextAvailabilityProbeUtc = utcNow + AvailabilityProbeBackoff; return false; } internal static void ResetPendingWardGuildProjectionRefreshes() { PendingWardGuildProjectionRefresh.TargetIdentitiesByPlayerId.Clear(); PendingWardGuildProjectionRefresh.TargetIdentitiesByCharacterKey.Clear(); PendingWardGuildProjectionRefresh.AffectedGuildIds.Clear(); PendingWardGuildProjectionRefresh.PendingFullRefresh = false; PendingWardGuildProjectionRefresh.PendingLiveDisplayRefresh = false; PendingWardGuildProjectionRefresh.PendingLiveDisplayReason = string.Empty; PendingWardGuildProjectionRefresh.FlushAtUtc = DateTime.MinValue; } internal static bool TryStampLocalWardGuildMetadata(PrivateArea? area) { return TryStampLocalWardGuildMetadata(ManagedWardRef.FromArea(area)); } internal static bool TryStampLocalWardGuildMetadata(ManagedWardRef ward) { if ((Object)(object)ward.Area == (Object)null || !ManagedWardIdentity.EnsureManagedComponent(ward)) { return false; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return false; } if (!WardAccess.IsDirectWardOwner(ward, localPlayer.GetPlayerID())) { return false; } if (!ward.HasValidNetworkIdentity || !ward.IsOwner) { return false; } ZDO zdo = ward.Zdo; if (zdo == null) { return false; } WardGuildIdentity guild; WardGuildIdentity guild2 = ((TryGetGuild(localPlayer, out guild) && guild.Id != 0) ? new WardGuildIdentity(guild.Id, guild.Name ?? string.Empty) : default(WardGuildIdentity)); ManagedWardProjection projection = ManagedWardProjectionService.ResolveExplicitProjection(localPlayer.GetPlayerID(), WardOwnership.GetPlayerAccountId(localPlayer), guild2); return ManagedWardMetadataMutationService.ApplyOwnedLocalProjection(zdo, projection, ManagedWardMapMutationKind.IndexAndPins, "local ward guild metadata stamp", forceSendWhenMetadataChanged: false).ProjectionResult.GuildChanged; } internal static int GetWardGuildId(PrivateArea? area) { if (TryGetStoredWardGuildIdentity(GetWardZdo(area), out var guild)) { return guild.Id; } if (!TryResolveWardGuildIdentity(area, allowMetadataStamp: false, out var guild2)) { return 0; } return guild2.Id; } internal static string GetWardGuildName(PrivateArea? area) { if (TryGetStoredWardGuildIdentity(GetWardZdo(area), out var guild) && !string.IsNullOrWhiteSpace(guild.Name)) { return guild.Name; } if (TryResolveWardGuildIdentity(area, allowMetadataStamp: false, out var guild2)) { return guild2.Name; } int id = guild.Id; if (id != 0 && TryGetGuildById(id, out guild2)) { return guild2.Name; } Player localPlayer = Player.m_localPlayer; if (id != 0 && (Object)(object)localPlayer != (Object)null && TryGetGuild(localPlayer, out guild2) && guild2.Id == id) { return guild2.Name; } return string.Empty; } internal static WardGuildIdentity ResolveWardGuildIdentityReadOnly(ZDO? zdo) { if (TryGetStoredWardGuildIdentity(zdo, out var guild) && guild.Id != 0) { return guild; } if (zdo == null) { return default(WardGuildIdentity); } long @long = zdo.GetLong(ZDOVars.s_creator, 0L); string wardSteamAccountId = WardOwnership.ResolveWardSteamAccountId(zdo, @long, WardOwnership.GetWardSteamAccountId(zdo)); string wardOwnerNameForProjection = GetWardOwnerNameForProjection(zdo); if (!TryResolveWardGuildIdentityReadOnly(@long, wardSteamAccountId, wardOwnerNameForProjection, treatResolvedNoGuildAsResolved: false, out var guild2)) { return default(WardGuildIdentity); } return guild2; } private static bool TryGetStoredWardGuildIdentity(ZDO? zdo, out WardGuildIdentity guild) { guild = default(WardGuildIdentity); if (zdo == null) { return false; } int @int = zdo.GetInt("stuw_guild_id", 0); string text = zdo.GetString("stuw_guild_name", string.Empty) ?? string.Empty; if (@int == 0 && string.IsNullOrWhiteSpace(text)) { return false; } guild = new WardGuildIdentity(@int, text.Trim()); return true; } private static ZDO? GetWardZdo(PrivateArea? area) { return WardPrivateAreaSafeAccess.GetZdo(area); } private static bool TryResolveWardGuildIdentity(PrivateArea? area, bool allowMetadataStamp, out WardGuildIdentity guild) { guild = default(WardGuildIdentity); if ((Object)(object)area == (Object)null) { return false; } long canonicalCreatorPlayerId = WardAccess.GetCanonicalCreatorPlayerId(area); string wardSteamAccountId = WardOwnership.ResolveWardSteamAccountId(GetWardZdo(area), canonicalCreatorPlayerId, WardOwnership.GetWardSteamAccountId(area)); string wardOwnerName = GetWardOwnerName(area); if (TryResolveWardGuildIdentityReadOnly(canonicalCreatorPlayerId, wardSteamAccountId, wardOwnerName, treatResolvedNoGuildAsResolved: true, out guild)) { if (allowMetadataStamp) { StampResolvedWardGuildMetadata(area, canonicalCreatorPlayerId, wardSteamAccountId, guild); } return true; } return false; } private static string GetWardOwnerName(PrivateArea? area) { if ((Object)(object)area == (Object)null) { return string.Empty; } string creatorName = WardPrivateAreaSafeAccess.GetCreatorName(area); if (!string.IsNullOrWhiteSpace(creatorName)) { return creatorName.Trim(); } return GetWardOwnerNameForProjection(GetWardZdo(area)); } internal static string GetWardOwnerNameForProjection(ZDO? zdo) { return WardPrivateAreaSafeAccess.GetCreatorName(zdo); } internal static bool TryResolveProjectedGuildIdentity(long ownerPlayerId, string normalizedAccountId, string ownerName, out WardGuildIdentity guild) { return TryResolveWardGuildIdentityReadOnly(ownerPlayerId, normalizedAccountId, ownerName, treatResolvedNoGuildAsResolved: true, out guild); } private static bool TryResolveWardGuildIdentityReadOnly(long ownerPlayerId, string wardSteamAccountId, string ownerName, bool treatResolvedNoGuildAsResolved, out WardGuildIdentity guild) { guild = default(WardGuildIdentity); string text = WardOwnership.NormalizeAccountIdValue(wardSteamAccountId); string text2 = ownerName?.Trim() ?? string.Empty; if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && TryGetSyncedGuildIdentity(ownerPlayerId, text, text2, out guild)) { if (!treatResolvedNoGuildAsResolved) { return guild.Id != 0; } return true; } if (ownerPlayerId != 0L && TryGetGuild(ownerPlayerId, out guild)) { return true; } if (!string.IsNullOrWhiteSpace(text) && !string.IsNullOrWhiteSpace(text2)) { return TryGetGuildByAccountAndName(text, text2, out guild); } return false; } private static void StampResolvedWardGuildMetadata(PrivateArea? area, long ownerPlayerId, string wardSteamAccountId, WardGuildIdentity guild) { if (guild.Id != 0 && !((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer()) { ZDO wardZdo = GetWardZdo(area); if (wardZdo != null) { ManagedWardMetadataMutationService.ApplyExplicitProjection(wardZdo, ManagedWardProjectionService.ResolveExplicitProjection(ownerPlayerId, wardSteamAccountId, guild), ManagedWardMapMutationKind.IndexAndPins, "resolved ward guild metadata"); } } } internal static void HandleGuildSaved(object? guild) { Plugin.LogWardDiagnosticVerbose("GuildsCompat.Refresh", "Queued guild save refresh for guild=" + DescribeGuildObject(guild) + "."); RefreshWardGuildProjectionForGuild(guild); } internal static void RefreshAllWardGuildProjections(bool liveDisplayRefresh = false) { Plugin.LogWardDiagnosticVerbose("GuildsCompat.Refresh", "Queued full ward guild projection refresh."); QueueWardGuildProjectionRefreshForAll(liveDisplayRefresh, "full guild projection refresh"); } private static void RefreshWardGuildProjectionForGuild(object? guild) { WardGuildIdentity guild2; int affectedGuildId = (TryParseGuild(guild, out guild2) ? guild2.Id : 0); bool hadUnresolvedMembers; List<WardGuildCharacterIdentity> list = CollectGuildMemberCharacterIdentities(guild, out hadUnresolvedMembers); if (list.Count == 0 || hadUnresolvedMembers) { Plugin.LogWardDiagnosticFailure("GuildsCompat.Refresh", "Could not extract complete guild member character identities from guild=" + DescribeGuildObject(guild) + ". Falling back to full ward guild refresh."); QueueWardGuildProjectionRefreshForAll(liveDisplayRefresh: false, "full guild projection refresh"); return; } Plugin.LogWardDiagnosticVerbose("GuildsCompat.Refresh", $"Queued ward guild projection refresh for {list.Count} guild member character(s) from guild={DescribeGuildObject(guild)}."); foreach (WardGuildCharacterIdentity item in list) { RefreshWardGuildProjectionForCharacter(item, liveDisplayRefresh: false, affectedGuildId); } } private static void RefreshWardGuildProjectionForCharacter(WardGuildCharacterIdentity identity, bool liveDisplayRefresh = false, int affectedGuildId = 0, int previousGuildId = 0) { if (identity.HasPlayerId || identity.HasAccountAndName) { Plugin.LogWardDiagnosticVerbose("GuildsCompat.Refresh", $"Queued ward guild projection refresh for character playerId={identity.PlayerId}, accountId='{identity.AccountId}', playerName='{identity.PlayerName}'."); if (!string.IsNullOrWhiteSpace(identity.AccountId)) { InvalidateGuildCacheForAccountId(identity.AccountId); } QueueWardGuildProjectionRefreshForCharacter(identity, liveDisplayRefresh, $"guild projection refresh for playerId={identity.PlayerId}, accountId='{identity.AccountId}'", affectedGuildId, previousGuildId); } } internal static void ProcessPendingWardGuildProjectionRefreshes() { if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer()) { PendingWardGuildProjectionRefreshState pendingWardGuildProjectionRefresh = PendingWardGuildProjectionRefresh; if ((pendingWardGuildProjectionRefresh.PendingFullRefresh || pendingWardGuildProjectionRefresh.TargetIdentitiesByPlayerId.Count != 0 || pendingWardGuildProjectionRefresh.TargetIdentitiesByCharacterKey.Count != 0 || pendingWardGuildProjectionRefresh.AffectedGuildIds.Count != 0) && !(pendingWardGuildProjectionRefresh.FlushAtUtc > DateTime.UtcNow)) { bool pendingFullRefresh = pendingWardGuildProjectionRefresh.PendingFullRefresh; bool pendingLiveDisplayRefresh = pendingWardGuildProjectionRefresh.PendingLiveDisplayRefresh; string liveDisplayReason = (string.IsNullOrWhiteSpace(pendingWardGuildProjectionRefresh.PendingLiveDisplayReason) ? "guild projection refreshed" : pendingWardGuildProjectionRefresh.PendingLiveDisplayReason); HashSet<long> targetPlayerIds = ((pendingWardGuildProjectionRefresh.TargetIdentitiesByPlayerId.Count == 0) ? null : new HashSet<long>(pendingWardGuildProjectionRefresh.TargetIdentitiesByPlayerId.Keys)); HashSet<string> targetCharacterKeys = ((pendingWardGuildProjectionRefresh.TargetIdentitiesByCharacterKey.Count == 0) ? null : new HashSet<string>(pendingWardGuildProjectionRefresh.TargetIdentitiesByCharacterKey.Keys, StringComparer.Ordinal)); HashSet<int> affectedGuildIds = ((pendingWardGuildProjectionRefresh.AffectedGuildIds.Count == 0) ? null : new HashSet<int>(pendingWardGuildProjectionRefresh.AffectedGuildIds)); ResetPendingWardGuildProjectionRefreshes(); RefreshWardGuildProjectionForManagedWards(targetPlayerIds, targetCharacterKeys, affectedGuildIds, pendingFullRefresh, pendingLiveDisplayRefresh, liveDisplayReason); } } } private static void QueueWardGuildProjectionRefreshForAll(bool liveDisplayRefresh, string liveDisplayReason) { PendingWardGuildProjectionRefresh.PendingFullRefresh = true; PendingWardGuildProjectionRefresh.TargetIdentitiesByPlayerId.Clear(); PendingWardGuildProjectionRefresh.TargetIdentitiesByCharacterKey.Clear(); UpdatePendingWardGuildProjectionRefreshWindow(liveDisplayRefresh, liveDisplayReason); } private static void QueueWardGuildProjectionRefreshForCharacter(WardGuildCharacterIdentity identity, bool liveDisplayRefresh, string liveDisplayReason, int affectedGuildId, int previousGuildId) { if (!PendingWardGuildProjectionRefresh.PendingFullRefresh) { if (identity.HasPlayerId) { PendingWardGuildProjectionRefresh.TargetIdentitiesByPlayerId[identity.PlayerId] = MergeQueuedWardGuildCharacterIdentity(PendingWardGuildProjectionRefresh.TargetIdentitiesByPlayerId.TryGetValue(identity.PlayerId, out var value) ? value : default(WardGuildCharacterIdentity), identity); } if (identity.HasAccountAndName) { string text = BuildCharacterIdentityKey(identity.AccountId, identity.PlayerName); if (!string.IsNullOrWhiteSpace(text)) { PendingWardGuildProjectionRefresh.TargetIdentitiesByCharacterKey[text] = MergeQueuedWardGuildCharacterIdentity(PendingWardGuildProjectionRefresh.TargetIdentitiesByCharacterKey.TryGetValue(text, out var value2) ? value2 : default(WardGuildCharacterIdentity), identity); } } } if (affectedGuildId != 0) { PendingWardGuildProjectionRefresh.AffectedGuildIds.Add(affectedGuildId); } if (previousGuildId != 0) { PendingWardGuildProjectionRefresh.AffectedGuildIds.Add(previousGuildId); } UpdatePendingWardGuildProjectionRefreshWindow(liveDisplayRefresh, liveDisplayReason); } private static void UpdatePendingWardGuildProjectionRefreshWindow(bool liveDisplayRefresh, string liveDisplayReason) { if (liveDisplayRefresh) { PendingWardGuildProjectionRefresh.PendingLiveDisplayRefresh = true; } if (string.IsNullOrWhiteSpace(PendingWardGuildProjectionRefresh.PendingLiveDisplayReason)) { PendingWardGuildProjectionRefresh.PendingLiveDisplayReason = (string.IsNullOrWhiteSpace(liveDisplayReason) ? "guild projection refreshed" : liveDisplayReason); } if (PendingWardGuildProjectionRefresh.FlushAtUtc == DateTime.MinValue) { PendingWardGuildProjectionRefresh.FlushAtUtc = DateTime.UtcNow + PendingWardGuildProjectionRefreshDebounce; } } private static WardGuildCharacterIdentity MergeQueuedWardGuildCharacterIdentity(WardGuildCharacterIdentity existingIdentity, WardGuildCharacterIdentity incomingIdentity) { long playerId = (existingIdentity.HasPlayerId ? existingIdentity.PlayerId : incomingIdentity.PlayerId); string accountId = ((!string.IsNullOrWhiteSpace(existingIdentity.AccountId)) ? existingIdentity.AccountId : incomingIdentity.AccountId); string playerName = ((!string.IsNullOrWhiteSpace(existingIdentity.PlayerName)) ? existingIdentity.PlayerName : incomingIdentity.PlayerName); return new WardGuildCharacterIdentity(playerId, accountId, playerName); } private static bool RefreshWardGuildProjectionForManagedWards(HashSet<long>? targetPlayerIds, HashSet<string>? targetCharacterKeys, HashSet<int>? affectedGuildIds, bool fullRefresh, bool liveDisplayRefresh, string liveDisplayReason) { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return false; } if (!fullRefresh && (targetPlayerIds == null || targetPlayerIds.Count == 0) && (targetCharacterKeys == null || targetCharacterKeys.Count == 0) && (affectedGuildIds == null || affectedGuildIds.Count == 0)) { return false; } if (fullRefresh) { InvalidateAllGuildCaches(); } HashSet<ZDOID> hashSet = new HashSet<ZDOID>(); int num = ManagedWardRegistry.CollectCandidateIds(hashSet, targetPlayerIds, targetCharacterKeys, affectedGuildIds, fullRefresh); int num2 = 0; int num3 = 0; foreach (ZDOID item in hashSet) { ZDOMan instance = ZDOMan.instance; ZDO val = ((instance != null) ? instance.GetZDO(item) : null); if (val == null || !WardOwnership.IsManagedWardZdo(val)) { ManagedWardRegistry.RemoveEntry(item); continue; } long @long = val.GetLong(ZDOVars.s_creator, 0L); num3++; string wardSteamAccountId = WardOwnership.NormalizeAccountIdValue(WardOwnership.ResolveWardSteamAccountId(val, @long, WardOwnership.GetWardSteamAccountId(val))); if (ManagedWardMetadataMutationService.RefreshProjectedMetadata(val, @long, wardSteamAccountId, ManagedWardMapMutationKind.IndexOnly, "guild projection refreshed").ProjectionResult.AnyChanged) { num2++; } } if (num2 > 0 && liveDisplayRefresh) { NotifyGuildProjectionRefreshApplied(liveDisplayReason, fullRefresh, targetPlayerIds, targetCharacterKeys, affectedGuildIds); } Plugin.LogWardDiagnosticVerbose("GuildsCompat.Refresh", string.Format("Scanned {0} managed ward(s) for guild projection refresh out of {1} registry candidate(s) and {2} indexed ward(s){3}{4}{5}{6}, changed={7}.", num3, num, ManagedWardRegistry.GetIndexedCount(), fullRefresh ? " on full refresh" : string.Empty, (!fullRefresh && targetPlayerIds != null && targetPlayerIds.Count > 0) ? $" targeting {targetPlayerIds.Count} playerId(s)" : string.Empty, (!fullRefresh && targetCharacterKeys != null && targetCharacterKeys.Count > 0) ? $" and {targetCharacterKeys.Count} account/name identities" : string.Empty, (!fullRefresh && affectedGuildIds != null && affectedGuildIds.Count > 0) ? $" across {affectedGuildIds.Count} affected guild(s)" : string.Empty, num2)); return num2 > 0; } private static List<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;