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.7")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.7.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.7")]
[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.7";
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.7",
MinimumRequiredVersion = "1.1.7"
};
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 __)
{
WardAccess.InvalidateWardPresenceCache();
}
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 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(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(WearNTearRemovePatch), failedRequiredPatches);
PatchRequired(harmony, typeof(WearNTearRpcRemovePatch), failedRequiredPatches);
PatchRequired(harmony, typeof(DestructibleDamagePatch), 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(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 sealed class StuWardPlacedHook : MonoBehaviour, IPlaced
{
public void OnPlaced()
{
PrivateArea component = ((Component)this).GetComponent<PrivateArea>();
if (StuWardArea.IsManaged(component))
{
WardOwnership.TryStampLocalManagedWardOwnerAccount(component);
WardOwnership.NotifyServerManagedWardPlaced(component);
ManagedWardMapStateService.NotifyLiveWardMutation(component, ManagedWardMapMutationKind.PinsOnly, "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 WardGuildIdentity
{
internal int Id { get; }
internal string Name { get; }
internal WardGuildIdentity(int id, string name)
{
Id = id;
Name = name;
}
}
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)
{
if ((Object)(object)area == (Object)null || !StuWardArea.IsManaged(area))
{
return false;
}
Player localPlayer = Player.m_localPlayer;
if ((Object)(object)localPlayer == (Object)null)
{
return false;
}
if (!WardAccess.IsDirectWardOwner(area, localPlayer))
{
return false;
}
ZNetView val = (((Object)(object)area.m_nview != (Object)null) ? area.m_nview : ((Component)area).GetComponent<ZNetView>());
if ((Object)(object)val == (Object)null || !val.IsValid() || !val.IsOwner())
{
return false;
}
ZDO zDO = val.GetZDO();
if (zDO == null)
{
return false;
}
int @int = zDO.GetInt("stuw_guild_id", 0);
string @string = zDO.GetString("stuw_guild_name", string.Empty);
if (!TryGetGuild(localPlayer, out var guild) || guild.Id == 0)
{
bool result = false;
if (@int != 0)
{
zDO.Set("stuw_guild_id", 0);
result = true;
}
if (!string.IsNullOrWhiteSpace(@string))
{
zDO.Set("stuw_guild_name", string.Empty);
result = true;
}
return result;
}
string text = guild.Name ?? string.Empty;
bool result2 = false;
if (@int != guild.Id)
{
zDO.Set("stuw_guild_id", guild.Id);
result2 = true;
}
if (!string.Equals(@string, text, StringComparison.Ordinal))
{
zDO.Set("stuw_guild_name", text);
result2 = true;
}
return result2;
}
internal static int GetWardGuildId(PrivateArea? area)
{
ZDO? wardZdo = GetWardZdo(area);
int num = ((wardZdo != null) ? wardZdo.GetInt("stuw_guild_id", 0) : 0);
if (num != 0)
{
return num;
}
if (!TryResolveWardGuildIdentity(area, out var guild))
{
return 0;
}
return guild.Id;
}
internal static string GetWardGuildName(PrivateArea? area)
{
ZDO wardZdo = GetWardZdo(area);
string text = ((wardZdo != null) ? wardZdo.GetString("stuw_guild_name", string.Empty) : null) ?? string.Empty;
if (!string.IsNullOrWhiteSpace(text))
{
return text;
}
if (TryResolveWardGuildIdentity(area, out var guild))
{
return guild.Name;
}
int num = ((wardZdo != null) ? wardZdo.GetInt("stuw_guild_id", 0) : 0);
if (num != 0 && TryGetGuildById(num, out guild))
{
return guild.Name;
}
Player localPlayer = Player.m_localPlayer;
if (num != 0 && (Object)(object)localPlayer != (Object)null && TryGetGuild(localPlayer, out guild) && guild.Id == num)
{
return guild.Name;
}
return string.Empty;
}
private static ZDO? GetWardZdo(PrivateArea? area)
{
return WardPrivateAreaSafeAccess.GetZdo(area);
}
private static bool TryResolveWardGuildIdentity(PrivateArea? area, out WardGuildIdentity guild)
{
guild = default(WardGuildIdentity);
if ((Object)(object)area == (Object)null)
{
return false;
}
long canonicalCreatorPlayerId = WardAccess.GetCanonicalCreatorPlayerId(area);
string text = WardOwnership.ResolveWardSteamAccountId(GetWardZdo(area), canonicalCreatorPlayerId, WardOwnership.GetWardSteamAccountId(area));
string wardOwnerName = GetWardOwnerName(area);
if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && TryGetSyncedGuildIdentity(canonicalCreatorPlayerId, text, wardOwnerName, out guild))
{
StampResolvedWardGuildMetadata(area, canonicalCreatorPlayerId, text, guild);
return true;
}
if (canonicalCreatorPlayerId != 0L && TryGetGuild(canonicalCreatorPlayerId, out guild))
{
StampResolvedWardGuildMetadata(area, canonicalCreatorPlayerId, WardOwnership.GetWardSteamAccountId(area), guild);
return true;
}
if (!string.IsNullOrWhiteSpace(text) && !string.IsNullOrWhiteSpace(wardOwnerName) && TryGetGuildByAccountAndName(text, wardOwnerName, out guild))
{
StampResolvedWardGuildMetadata(area, canonicalCreatorPlayerId, text, 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)
{
guild = default(WardGuildIdentity);
if (string.IsNullOrWhiteSpace(normalizedAccountId))
{
return false;
}
if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && TryGetSyncedGuildIdentity(ownerPlayerId, normalizedAccountId, ownerName, out guild))
{
return true;
}
if (ownerPlayerId != 0L && TryGetGuild(ownerPlayerId, out guild))
{
return true;
}
if (!string.IsNullOrWhiteSpace(ownerName))
{
return TryGetGuildByAccountAndName(normalizedAccountId, ownerName, 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;
}
}
return new List<WardGuildCharacterIdentity>(dictionary.Values);
}
if (!(value is IEnumerable enumerable))
{
return new List<WardGuildCharacterIdentity>();
}
foreach (object item in enumerable)
{
if (item != null)
{
if (!TryCreateCharacterIdentityFromPlayerReference(AccessTools.Property(item.GetType(), "Key")?.GetValue(item, null), out var identity2))
{
hadUnresolvedMembers = true;
}
else
{
dictionary[BuildCharacterIdentityKey(identity2.AccountId, identity2.PlayerName)] = identity2;
}
}
}
return new List<WardGuildCharacterIdentity>(dictionary.Values);
}
private static bool TryCreateCharacterIdentityFromPlayerReference(object? playerReference, out WardGuildCharacterIdentity identity)
{
identity = default(WardGuildCharacterIdentity);
if (playerReference == null || PlayerReferenceIdField == null)
{
return false;
}
try
{
string text = WardOwnership.NormalizeAccountIdValue(PlayerReferenceIdField.GetValue(playerReference)?.ToString());
string playerNameFromPlayerReference = GetPlayerNameFromPlayerReference(playerReference);
if (string.IsNullOrWhiteSpace(text) || string.IsNullOrWhiteSpace(playerNameFromPlayerReference))
{
return false;
}
identity = new WardGuildCharacterIdentity(0L, text, playerNameFromPlayerReference);
return true;
}
catch
{
return false;
}
}
private static string GetPlayerNameFromPlayerReference(object playerReference)
{
if (PlayerReferenceNameField != null)
{
string text = PlayerReferenceNameField.GetValue(playerReference)?.ToString()?.Trim() ?? string.Empty;
if (!string.IsNullOrWhiteSpace(text))
{
return text;
}
}
string text2 = playerReference.ToString()?.Trim() ?? string.Empty;
int num = text2.IndexOf(':');
if (num < 0 || num >= text2.Length - 1)
{
return string.Empty;
}
return text2.Substring(num + 1).Trim();
}
private static void InvalidateGuildCacheForAccountId(string accountId)
{
//IL_009c: Unknown result type (might be due to invalid IL or missing references)
//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
string text = WardOwnership.NormalizeAccountIdValue(accountId);
if (string.IsNullOrWhiteSpace(text))
{
return;
}
HashSet<long> hashSet = new HashSet<long>();
foreach (KeyValuePair<long, CachedPlayerPlatformIdentity> item in PlayerPlatformIdCache)
{
if (item.Value.HasPlatformId && string.Equals(item.Value.PlatformId, text, StringComparison.Ordinal))
{
hashSet.Add(item.Key);
}
}
List<PlayerInfo> list = ZNet.instance?.m_players;
if (list != null)
{
for (int i = 0; i < list.Count; i++)
{
PlayerInfo val = list[i];
if (string.Equals(WardOwnership.NormalizeAccountIdValue(((object)(PlatformUserID)(ref val.m_userInfo.m_id)).ToString()), text, StringComparison.Ordinal))
{
ZDOMan instance = ZDOMan.instance;
ZDO obj = ((instance != null) ? instance.GetZDO(val.m_characterID) : null);
long num = ((obj != null) ? obj.GetLong(ZDOVars.s_playerID, 0L) : 0);
if (num != 0L)
{
hashSet.Add(num);
}
}
}
}
Player localPlayer = Player.m_localPlayer;
if ((Object)(object)localPlayer != (Object)null && string.Equals(WardOwnership.NormalizeAccountIdValue(WardOwnership.GetPlayerAccountId(localPlayer)), text, StringComparison.Ordinal))
{
hashSet.Add(localPlayer.GetPlayerID());
}
foreach (long item2 in hashSet)
{
PlayerGuildCache.Remove(item2);
PlayerPlatformIdCache.Remove(item2);
}
}
private static void InvalidateAllGuildCaches()
{
PlayerGuildCache.Clear();
PlayerPlatformIdCache.Clear();
}
internal static string DescribeGuildObject(object? guild)
{
if (guild == null)
{
return "null";
}
try
{
string arg = (GuildNameField?.GetValue(guild) as string) ?? string.Empty;
int num = ((GuildGeneralField != null && GuildGeneralIdField != null) ? Convert.ToInt32(GuildGeneralIdField.GetValue(GuildGeneralField.GetValue(guild))) : 0);
return $"type={guild.GetType().FullName}, id={num}, name='{arg}'";
}
catch
{
return "type=" + guild.GetType().FullName;
}
}
internal static string GetPlayerPlatformId(long playerId)
{
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
if (playerId == 0L)
{
return string.Empty;
}
if (TryGetCachedPlatformId(playerId, out string platformId))
{
return platformId;
}
string playerAccountId = WardOwnership.GetPlayerAccountId(playerId);
if (!string.IsNullOrWhiteSpace(playerAccountId))
{
CachePlatformId(playerId, playerAccountId);
return playerAccountId;
}
PlayerInfo? val = FindPlayerInfo(playerId);
if (!val.HasValue || PlayerInfoUserInfoField == null || UserInfoIdField == null)
{
CachePlatformId(playerId, string.Empty);
return string.Empty;
}
try
{
object obj = val.Value;
object value = PlayerInfoUserInfoField.GetValue(obj);
if (value == null)
{
CachePlatformId(playerId, string.Empty);
retu