Decompiled source of PeakAdminToolkit v1.0.1
BepInEx/plugins/PeakAdminToolkit/PeakAdminToolkit.dll
Decompiled 3 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Peak; using PeakAdminToolkit.Core; using PeakAdminToolkit.Items; using PeakAdminToolkit.Players; using PeakAdminToolkit.Self; using PeakAdminToolkit.UI; using PeakAdminToolkit.World; using UnityEngine; using UnityEngine.SceneManagement; [assembly: AssemblyDescription("PEAK item catalog and administration toolkit")] [assembly: AssemblyFileVersion("1.0.1.0")] [assembly: ComVisible(false)] [assembly: AssemblyProduct("PEAK Admin Toolkit")] [assembly: CompilationRelaxations(8)] [assembly: AssemblyTitle("PEAK Admin Toolkit")] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("1.0.1.0")] namespace PeakAdminToolkit { [BepInPlugin("com.oldip.peakadmintoolkit", "PEAK Admin Toolkit", "1.0.1")] public sealed class Plugin : BaseUnityPlugin { public const string Guid = "com.oldip.peakadmintoolkit"; public const string Name = "PEAK Admin Toolkit"; public const string Version = "1.0.1"; private ToolkitConfig config; private Compatibility compatibility; private PeakApi api; private MainWindow window; private SelfTools selfTools; private HornFuelHud hornFuelHud; private DroppedItemHistory droppedItems; private DroppedItemCapture droppedItemCapture; private bool hasFocus = true; private double nextLanguagePoll; private bool guiFailureReported; private bool WindowIsOpen { get { if (window != null) { return window.IsOpen; } return false; } } private void Awake() { config = new ToolkitConfig(((BaseUnityPlugin)this).Config); compatibility = new Compatibility(() => WindowIsOpen, ((BaseUnityPlugin)this).Logger); api = new PeakApi(compatibility, new ItemDescriptions(delegate(string message) { ((BaseUnityPlugin)this).Logger.LogWarning((object)message); }), delegate(string message) { ((BaseUnityPlugin)this).Logger.LogInfo((object)message); }); selfTools = new SelfTools(new SelfApi(), delegate(string message) { ((BaseUnityPlugin)this).Logger.LogWarning((object)message); }, () => WindowIsOpen || !hasFocus || !config.Enabled.Value); droppedItems = new DroppedItemHistory(); window = new MainWindow(config, api, selfTools, droppedItems, delegate(string message) { ((BaseUnityPlugin)this).Logger.LogWarning((object)message); }); droppedItemCapture = new DroppedItemCapture(droppedItems, delegate(string message) { ((BaseUnityPlugin)this).Logger.LogWarning((object)message); }); hornFuelHud = new HornFuelHud(null, delegate(string message) { ((BaseUnityPlugin)this).Logger.LogWarning((object)message); }, () => ((Behaviour)this).isActiveAndEnabled && config.Enabled.Value); SceneManager.sceneLoaded += OnSceneLoaded; SceneManager.sceneUnloaded += OnSceneUnloaded; ((BaseUnityPlugin)this).Logger.LogInfo((object)("PEAK Admin Toolkit 1.0.1 loaded. Window hooks: " + compatibility.WindowHooksReady)); } private void Update() { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) if (config == null || window == null) { return; } if (!config.Enabled.Value) { window.Close(); selfTools.Reset(); return; } selfTools.Poll(); if ((int)config.ToggleKey.Value != 0 && Input.GetKeyDown(config.ToggleKey.Value)) { if (WindowIsOpen) { window.Close(); } else if (api.CanOpenWindow) { window.Open(); } } if (Time.unscaledTimeAsDouble >= nextLanguagePoll) { nextLanguagePoll = Time.unscaledTimeAsDouble + 1.0; window.RefreshLanguage(api.ReadLanguage()); } } private void OnGUI() { if (window == null) { return; } try { window.Draw(); } catch (Exception ex) { window.Close(); if (!guiFailureReported) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Admin window closed after a UI error: " + ex.Message)); } guiFailureReported = true; } } private void OnApplicationFocus(bool hasFocus) { this.hasFocus = hasFocus; if (!hasFocus && window != null) { window.Close(); } } private void OnDisable() { if (selfTools != null) { selfTools.Reset(); } if (window != null) { window.Close(); } } private void OnSceneUnloaded(Scene scene) { if (selfTools != null) { selfTools.Reset(); } if (droppedItems != null) { droppedItems.Clear(); } } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { if (selfTools != null) { selfTools.Reset(); } if (droppedItems != null) { droppedItems.Clear(); } if (window != null) { window.Close(); window.InvalidateItemCatalog(); } } private void OnDestroy() { SceneManager.sceneLoaded -= OnSceneLoaded; SceneManager.sceneUnloaded -= OnSceneUnloaded; if (selfTools != null) { selfTools.Dispose(); } if (hornFuelHud != null) { hornFuelHud.Dispose(); } if (droppedItemCapture != null) { droppedItemCapture.Dispose(); } if (window != null) { window.Dispose(); } if (compatibility != null) { compatibility.Dispose(); } window = null; api = null; compatibility = null; selfTools = null; hornFuelHud = null; } } } namespace PeakAdminToolkit.Core { internal sealed class ToolkitConfig { public readonly ConfigEntry<bool> Enabled; public readonly ConfigEntry<KeyCode> ToggleKey; public readonly ConfigEntry<string> Language; public ToolkitConfig(ConfigFile file) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Expected O, but got Unknown //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Expected O, but got Unknown Enabled = file.Bind<bool>("General", "Enabled", true, new ConfigDescription("Enable the toolkit. Disabling closes the window, resets self tools and stops the horn HUD correction. / 停用时关闭窗口并恢复自身工具 / 停用時關閉視窗並恢復自身工具", (AcceptableValueBase)null, new object[0])); ToggleKey = file.Bind<KeyCode>("Interface", "ToggleKey", (KeyCode)289, new ConfigDescription("Open or close the window. None disables the shortcut. / 窗口快捷键 / 視窗快捷鍵", (AcceptableValueBase)null, new object[0])); Language = file.Bind<string>("Interface", "Language", "Auto", new ConfigDescription("UI language. Auto follows PEAK; unsupported languages use English. / 界面语言 / 介面語言", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[4] { "Auto", "en", "zh-CN", "zh-TW" }), new object[0])); } } internal sealed class Localization { private static readonly Dictionary<string, string> English = Read("en"); private static readonly Dictionary<string, string> Simplified = Read("zh-CN"); private static readonly Dictionary<string, string> Traditional = Read("zh-TW"); public string Language { get; private set; } public static IEnumerable<string> Keys => English.Keys; public Localization() { Language = "en"; } public static string Resolve(string preference, string gameLanguage) { switch (preference) { case "en": case "zh-CN": case "zh-TW": return preference; default: if (gameLanguage == "SimplifiedChinese") { return "zh-CN"; } if (gameLanguage == "TraditionalChinese") { return "zh-TW"; } return "en"; } } public void Update(string preference, string gameLanguage) { Language = Resolve(preference, gameLanguage); } public string Text(string key) { Dictionary<string, string> dictionary = ((Language == "zh-CN") ? Simplified : ((Language == "zh-TW") ? Traditional : English)); if (dictionary.TryGetValue(key, out var value) || English.TryGetValue(key, out value)) { return value; } return key; } public string Format(string key, params object[] values) { try { return string.Format(Text(key), values); } catch (FormatException) { if (English.TryGetValue(key, out var value)) { try { return string.Format(value, values); } catch (FormatException) { } } return key; } } private static Dictionary<string, string> Read(string language) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Invalid comparison between Unknown and I4 Dictionary<string, string> dictionary = new Dictionary<string, string>(); foreach (JProperty item in EmbeddedJson.Read("Locales." + language + ".json").Properties()) { if ((int)item.Value.Type == 8) { string value = (string)item.Value; if (!string.IsNullOrWhiteSpace(value)) { dictionary[item.Name] = value; } } } return dictionary; } } internal static class EmbeddedJson { public static JObject Read(string name, Action<string> warning = null) { //IL_005f: Expected O, but got Unknown //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Expected O, but got Unknown //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown using Stream stream = typeof(EmbeddedJson).Assembly.GetManifestResourceStream("PeakAdminToolkit." + name); if (stream == null) { warning?.Invoke("Missing embedded data: " + name); return new JObject(); } try { using StreamReader streamReader = new StreamReader(stream); return JObject.Parse(streamReader.ReadToEnd()); } catch (JsonException ex) { JsonException ex2 = ex; warning?.Invoke("Invalid embedded data " + name + ": " + ((Exception)(object)ex2).Message); return new JObject(); } } } internal sealed class Compatibility : IDisposable { private readonly Harmony harmony; private readonly ManualLogSource log; private readonly FieldInfo languageField; private readonly FieldInfo guiInstance; private readonly PropertyInfo cursorProperty; private static Func<bool> windowOpen; private bool reportedLanguageFailure; public bool WindowHooksReady { get; private set; } public Compatibility(Func<bool> isWindowOpen, ManualLogSource logger) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Expected O, but got Unknown log = logger; harmony = new Harmony("com.oldip.peakadmintoolkit"); Type type = FindGameType("LocalizedText"); Type type2 = FindGameType("GUIManager"); if (type != null) { languageField = type.GetField("CURRENT_LANGUAGE", BindingFlags.Static | BindingFlags.Public); } if (type2 != null) { guiInstance = type2.GetField("instance", BindingFlags.Static | BindingFlags.Public); cursorProperty = type2.GetProperty("windowShowingCursor", BindingFlags.Instance | BindingFlags.Public); } PropertyInfo propertyInfo = ((type2 == null) ? null : type2.GetProperty("windowBlockingInput", BindingFlags.Instance | BindingFlags.Public)); if (!IsBooleanGetter(propertyInfo) || !IsBooleanGetter(cursorProperty) || guiInstance == null) { log.LogWarning((object)"Window unavailable: PEAK input/cursor API is incompatible. Expected GUIManager.windowBlockingInput and windowShowingCursor."); return; } windowOpen = isWindowOpen; try { HarmonyMethod val = new HarmonyMethod(typeof(Compatibility).GetMethod("IncludeToolkitWindow", BindingFlags.Static | BindingFlags.NonPublic)); harmony.Patch((MethodBase)propertyInfo.GetGetMethod(), (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)cursorProperty.GetGetMethod(), (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); WindowHooksReady = true; } catch (Exception ex) { Dispose(); log.LogWarning((object)("Window unavailable: input hooks could not be installed. " + ex.Message)); } } private static Type FindGameType(string name) { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { if (assembly.GetName().Name == "Assembly-CSharp") { return assembly.GetType(name, throwOnError: false); } } return null; } private static bool IsBooleanGetter(PropertyInfo property) { if (property != null && property.PropertyType == typeof(bool)) { return property.GetGetMethod() != null; } return false; } private static void IncludeToolkitWindow(ref bool __result) { __result = __result || (windowOpen != null && windowOpen()); } public string ReadGameLanguage() { try { object obj = ((languageField == null) ? null : languageField.GetValue(null)); if (obj != null) { return obj.ToString(); } } catch (Exception ex) { if (!reportedLanguageFailure) { log.LogWarning((object)("PEAK language read failed: " + ex.Message)); } } if (!reportedLanguageFailure) { log.LogWarning((object)"PEAK language unavailable; Auto uses English. An explicit UI language still works."); } reportedLanguageFailure = true; return null; } public bool GameWantsCursor() { if (guiInstance == null || cursorProperty == null) { return false; } try { object value = guiInstance.GetValue(null); Object val = (Object)((value is Object) ? value : null); if (val == (Object)null) { return false; } return (bool)cursorProperty.GetValue(value, null); } catch (Exception) { return false; } } public void Dispose() { WindowHooksReady = false; windowOpen = null; harmony.UnpatchSelf(); } } internal sealed class PeakApi { private readonly Compatibility compatibility; private readonly ItemCatalogApi catalog; private readonly ItemSpawnApi spawning = new ItemSpawnApi(); public bool CanOpenWindow => compatibility.WindowHooksReady; public bool CanSpawnItems => spawning.CanSpawnItems; public PeakApi(Compatibility compatibility, ItemDescriptions descriptions = null, Action<string> diagnosticLog = null) { this.compatibility = compatibility; catalog = new ItemCatalogApi(descriptions, diagnosticLog); } public string ReadLanguage() { return compatibility.ReadGameLanguage(); } public bool GameWantsCursor() { return compatibility.GameWantsCursor(); } public List<ItemCatalogEntry> ReadItemCatalog(bool includeSpecial = false) { return catalog.ReadItemCatalog(includeSpecial); } public bool SpawnItem(ItemCatalogEntry entry, bool includeSpecial = false) { return spawning.SpawnItem(entry, includeSpecial); } public bool MatchesItem(string query, ItemCatalogEntry item) { if (item != null) { return ItemSearch.Matches(query, item.CurrentName, item.EnglishName, item.SimplifiedName, item.TraditionalName); } return false; } } } namespace PeakAdminToolkit.Items { internal static class ItemApiAccess { internal const BindingFlags StaticFlags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy; internal const BindingFlags InstanceFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy; internal static bool IsValidToSpawn(object item) { if (TryIsValidToSpawn(item, out var valid, out var _)) { return valid; } return false; } internal static bool TryIsValidToSpawn(object item, out bool valid, out string reason) { valid = false; reason = null; if (item == null) { reason = "item unavailable"; return false; } try { MethodInfo method = item.GetType().GetMethod("IsValidToSpawn", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy, null, Type.EmptyTypes, null); if (method == null) { reason = "IsValidToSpawn missing"; return false; } if (method.ReturnType != typeof(bool)) { reason = "IsValidToSpawn must return Boolean"; return false; } valid = (bool)method.Invoke(item, null); return true; } catch (Exception ex) { TargetInvocationException ex2 = ex as TargetInvocationException; reason = ((ex2 != null && ex2.InnerException != null) ? ex2.InnerException : ex).GetType().Name; return false; } } internal static string InvokeStringMethod(object target, string name) { MethodInfo method = target.GetType().GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy, null, Type.EmptyTypes, null); if (method == null || method.ReturnType != typeof(string)) { return string.Empty; } try { return (method.Invoke(target, null) as string) ?? string.Empty; } catch (Exception) { return string.Empty; } } internal static bool ReadStaticBoolean(Type type, string name) { object obj = ReadStaticMember(type, name); if (obj is bool) { return (bool)obj; } return false; } internal static object ReadMember(object target, string name) { if (target == null) { return null; } Type type = target.GetType(); PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy); if (property != null && property.GetIndexParameters().Length == 0) { try { return property.GetValue(target, null); } catch (Exception) { return null; } } FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy); if (!(field == null)) { return field.GetValue(target); } return null; } internal static object ReadStaticMember(Type type, string name) { if (type == null) { return null; } PropertyInfo property = type.GetProperty(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy); if (property != null && property.GetIndexParameters().Length == 0) { try { return property.GetValue(null, null); } catch (Exception) { return null; } } FieldInfo field = type.GetField(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy); if (!(field == null)) { return field.GetValue(null); } return null; } internal static Type FindGameType(string name) { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { if (!(assembly.GetName().Name != "Assembly-CSharp")) { return assembly.GetType(name, throwOnError: false); } } return null; } internal static Type FindLoadedType(string name) { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { Type type = assembly.GetType(name, throwOnError: false); if (type != null) { return type; } } return null; } internal static bool HasStaticBooleanMember(Type type, string name) { if (type == null) { return false; } PropertyInfo property = type.GetProperty(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy); if (property != null && property.PropertyType == typeof(bool) && property.GetIndexParameters().Length == 0) { MethodInfo getMethod = property.GetGetMethod(nonPublic: true); if (getMethod != null && getMethod.IsStatic) { return true; } } FieldInfo field = type.GetField(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy); if (field != null && field.FieldType == typeof(bool)) { return field.IsStatic; } return false; } } internal sealed class ItemValidityDiagnostics { private readonly Action<string> log; private readonly HashSet<string> seen = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private readonly List<string> details = new List<string>(); private int validCount; private int invalidCount; private int unknownCount; public ItemValidityDiagnostics(Action<string> log) { this.log = log; } public void Record(string spawnName, bool evaluated, bool valid, string reason) { if (SpecialItems.Classify(spawnName) != SpecialItemKind.None && seen.Add(spawnName)) { if (!evaluated) { unknownCount++; details.Add("unknown: " + spawnName + " (" + reason + ")"); } else if (valid) { validCount++; } else { invalidCount++; details.Add("false: " + spawnName); } } } public void Write(string failure = null) { try { log("[ItemValidity] status=" + ((failure == null) ? "complete" : ("incomplete reason=" + failure)) + " registered=" + seen.Count + " true=" + validCount + " false=" + invalidCount + " unknown=" + unknownCount); foreach (string detail in details) { log("[ItemValidity] " + detail); } } catch (Exception) { } } } internal sealed class HornFuelHud : IDisposable { private const BindingFlags Members = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; private static HornFuelHud current; private readonly Harmony harmony = new Harmony("com.oldip.peakadmintoolkit.hornfuelhud"); private readonly Func<string, Type> resolve; private readonly Action<string> log; private readonly Func<bool> enabled; private bool disposed; private string frameFailure; internal bool Available { get; private set; } internal HornFuelHud(Func<string, Type> resolve, Action<string> log, Func<bool> enabled) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Expected O, but got Unknown this.resolve = resolve ?? new Func<string, Type>(FindGameType); this.log = log; this.enabled = enabled; try { Type type = this.resolve("GUIManager"); if (type == null || this.resolve("Character") == null || this.resolve("MagicBugle") == null) { throw new MissingMemberException("Horn HUD game types"); } MethodInfo method = type.GetMethod("UpdateItems", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); if (method == null || method.ReturnType != typeof(void)) { throw new MissingMethodException("GUIManager", "UpdateItems"); } harmony.Patch((MethodBase)method, (HarmonyMethod)null, new HarmonyMethod(typeof(HornFuelHud).GetMethod("Postfix", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); current = this; Available = true; } catch (Exception ex) { Fail(ex); } } private static void Postfix(object __instance) { HornFuelHud hornFuelHud = current; if (hornFuelHud == null || !hornFuelHud.Available || (hornFuelHud.enabled != null && !hornFuelHud.enabled())) { return; } try { Apply(__instance, hornFuelHud.resolve); hornFuelHud.frameFailure = null; } catch (Exception innerException) { while (innerException is TargetInvocationException && innerException.InnerException != null) { innerException = innerException.InnerException; } string text = innerException.GetType().Name + ": " + innerException.Message; if (hornFuelHud.frameFailure != text && hornFuelHud.log != null) { hornFuelHud.log("Horn HUD frame skipped: " + text); } hornFuelHud.frameFailure = text; } } internal static void Apply(object gui, Func<string, Type> resolve) { if (gui == null || resolve == null) { return; } Type type = resolve("Character"); Type type2 = resolve("MagicBugle"); if (type == null || type2 == null) { return; } object obj = ReadStatic(type, "localCharacter"); if (obj == null || !object.ReferenceEquals(obj, ReadStatic(type, "observedCharacter"))) { return; } object obj2 = Read(Read(obj, "data"), "currentItem"); if (obj2 == null) { return; } MethodInfo method = obj2.GetType().GetMethod("GetComponent", new Type[1] { typeof(Type) }); if (method == null) { return; } object obj3 = method.Invoke(obj2, new object[1] { type2 }); if (obj3 == null) { return; } object obj4 = Read(Read(Read(obj, "refs"), "items"), "currentSelectedSlot"); if (obj4 == null || !Convert.ToBoolean(Read(obj4, "IsSome"))) { return; } int num = Convert.ToInt32(Read(obj4, "Value")); if (!(Read(gui, "items") is Array array) || num < 0 || num >= array.Length) { return; } object value = array.GetValue(num); object obj5 = Read(value, "fuelBar"); object obj6 = Read(value, "fuelBarFill"); if (obj5 == null || obj6 == null) { return; } float num2 = Convert.ToSingle(Read(obj3, "totalTootTime")); float num3 = Convert.ToSingle(Read(obj3, "currentFuel")); if (!(num2 <= 0f) && !float.IsNaN(num2) && !float.IsNaN(num3)) { PropertyInfo property = obj6.GetType().GetProperty("fillAmount", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); MethodInfo method2 = obj5.GetType().GetMethod("SetActive", new Type[1] { typeof(bool) }); if (!(property == null) && property.CanWrite && !(method2 == null)) { float num4 = Math.Max(0f, Math.Min(1f, num3 / num2)); method2.Invoke(obj5, new object[1] { true }); property.SetValue(obj6, num4, null); } } } private static object Read(object target, string name) { if (target == null) { return null; } Type type = target.GetType(); FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { return field.GetValue(target); } PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (!(property == null)) { return property.GetValue(target, null); } return null; } private static object ReadStatic(Type type, string name) { FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { return field.GetValue(null); } PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (!(property == null)) { return property.GetValue(null, null); } return null; } private static Type FindGameType(string name) { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { if (assembly.GetName().Name == "Assembly-CSharp") { return assembly.GetType(name, throwOnError: false); } } return null; } private void Fail(Exception ex) { while (ex is TargetInvocationException && ex.InnerException != null) { ex = ex.InnerException; } Available = false; if (object.ReferenceEquals(current, this)) { current = null; } try { harmony.UnpatchSelf(); } catch { } if (log != null) { log("Horn fuel HUD unavailable: " + ex.Message); } } public void Dispose() { if (!disposed) { disposed = true; Available = false; if (object.ReferenceEquals(current, this)) { current = null; } harmony.UnpatchSelf(); } } } internal sealed class ItemCatalogApi { private readonly ItemDescriptions descriptions; private readonly Action<string> diagnosticLog; public ItemCatalogApi(ItemDescriptions descriptions, Action<string> diagnosticLog = null) { this.descriptions = descriptions; this.diagnosticLog = diagnosticLog; } public List<ItemCatalogEntry> ReadItemCatalog(bool includeSpecial = false) { ItemValidityDiagnostics itemValidityDiagnostics = ((includeSpecial && diagnosticLog != null) ? new ItemValidityDiagnostics(diagnosticLog) : null); try { return ReadCatalog(includeSpecial, itemValidityDiagnostics); } catch (Exception ex) { itemValidityDiagnostics?.Write("catalog read failed: " + ex.GetType().Name); return new List<ItemCatalogEntry>(); } } private List<ItemCatalogEntry> ReadCatalog(bool includeSpecial, ItemValidityDiagnostics diagnostics) { List<ItemCatalogEntry> list = new List<ItemCatalogEntry>(); Type type = ItemApiAccess.FindGameType("ItemDatabase"); if (type == null) { diagnostics?.Write("ItemDatabase type unavailable"); return list; } object target = ItemApiAccess.ReadStaticMember(type, "Instance"); object obj = ItemApiAccess.ReadMember(target, "itemLookup"); if (!(obj is IDictionary dictionary)) { diagnostics?.Write("ItemDatabase lookup unavailable"); return list; } HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); foreach (DictionaryEntry item in dictionary) { try { ItemCatalogEntry itemCatalogEntry = CreateCatalogEntry(item.Value, item.Key as string, includeSpecial, diagnostics); if (itemCatalogEntry != null && hashSet.Add(itemCatalogEntry.SpawnName)) { list.Add(itemCatalogEntry); } } catch (Exception ex) { diagnostics?.Record(item.Key as string, evaluated: false, valid: false, "candidate read failed: " + ex.GetType().Name); } } list.Sort(delegate(ItemCatalogEntry left, ItemCatalogEntry right) { int num = StringComparer.CurrentCultureIgnoreCase.Compare(left.CurrentName, right.CurrentName); return (num == 0) ? StringComparer.OrdinalIgnoreCase.Compare(left.SpawnName, right.SpawnName) : num; }); diagnostics?.Write(); return list; } private ItemCatalogEntry CreateCatalogEntry(object item, string registeredName, bool includeSpecial, ItemValidityDiagnostics diagnostics) { string spawnName = GetSpawnName(item); if (string.IsNullOrEmpty(spawnName)) { diagnostics?.Record(registeredName, evaluated: false, valid: false, "prefab or name unavailable"); return null; } bool valid; string reason; bool flag = ItemApiAccess.TryIsValidToSpawn(item, out valid, out reason); diagnostics?.Record(spawnName, flag, valid, reason); bool duplicatePrefab = ItemApiAccess.ReadMember(item, "isSecretlyOtherItemPrefab") != null; if (!flag) { return null; } bool flag2 = valid || ItemManualSpawnPolicy.AllowsSoloOverride(item, spawnName); if (!ItemVisibility.ShouldShow(spawnName, registered: true, flag2, duplicatePrefab, includeSpecial)) { return null; } string text = ItemApiAccess.InvokeStringMethod(item, "GetName"); if (string.IsNullOrWhiteSpace(text)) { text = spawnName; } string localizedItemKey = GetLocalizedItemKey(item, "GetNameIndex"); string text2 = GetLocalizedText(localizedItemKey, "English"); string localizedText = GetLocalizedText(localizedItemKey, "SimplifiedChinese"); string localizedText2 = GetLocalizedText(localizedItemKey, "TraditionalChinese"); if (string.IsNullOrWhiteSpace(text2)) { text2 = spawnName; } object obj = ItemApiAccess.ReadMember(item, "UIData"); string text3 = (ItemApiAccess.ReadMember(obj, "itemName") as string) ?? spawnName; object obj2 = ItemApiAccess.ReadMember(item, "itemTags"); string nativeTags = ((obj2 == null) ? string.Empty : obj2.ToString()); string localizedItemKey2 = GetLocalizedItemKey(item, "GetDescriptionIndex"); SpecialItemKind specialItemKind = SpecialItems.Classify(spawnName); if (specialItemKind != SpecialItemKind.None) { Localization localization = new Localization(); localization.Update("en", null); Localization localization2 = new Localization(); localization2.Update("zh-CN", null); Localization localization3 = new Localization(); localization3.Update("zh-TW", null); ItemCategory itemCategory = ItemCategory.Other; ConsumableKind kinds = ConsumableKind.None; if (specialItemKind == SpecialItemKind.MultiplayerItems) { itemCategory |= ItemClassification.Categories(text3, nativeTags); kinds = ItemClassification.Kinds(text3, nativeTags); } string text4 = SpecialItems.DisplayName(spawnName, localization); string text5 = SpecialItems.DisplayName(spawnName, localization2); string text6 = SpecialItems.DisplayName(spawnName, localization3); string text7 = SpecialItems.Description(spawnName, localization); string text8 = SpecialItems.Description(spawnName, localization2); string text9 = SpecialItems.Description(spawnName, localization3); if (string.IsNullOrEmpty(text7)) { text7 = ReadDescription(localizedItemKey2, "en", text3, text2, spawnName); } if (string.IsNullOrEmpty(text8)) { text8 = ReadDescription(localizedItemKey2, "zh-CN", text3, text2, spawnName); } if (string.IsNullOrEmpty(text9)) { text9 = ReadDescription(localizedItemKey2, "zh-TW", text3, text2, spawnName); } return new ItemCatalogEntry(spawnName, text.Trim(), string.IsNullOrEmpty(text4) ? text2.Trim() : text4, string.IsNullOrEmpty(text5) ? localizedText : text5, string.IsNullOrEmpty(text6) ? localizedText2 : text6, ReadItemIcon(obj), itemCategory, kinds, text7, text8, text9, valid, flag2); } return new ItemCatalogEntry(spawnName, text.Trim(), text2.Trim(), localizedText, localizedText2, ReadItemIcon(obj), ItemClassification.Categories(text3, nativeTags), ItemClassification.Kinds(text3, nativeTags), ReadDescription(localizedItemKey2, "en", text3, text2, spawnName), ReadDescription(localizedItemKey2, "zh-CN", text3, text2, spawnName), ReadDescription(localizedItemKey2, "zh-TW", text3, text2, spawnName)); } private string ReadDescription(string key, string language, params string[] names) { string text = ((descriptions == null) ? string.Empty : descriptions.Get(language, names)); if (!string.IsNullOrEmpty(text)) { return text; } return GetLocalizedText(key, (language == "zh-TW") ? "TraditionalChinese" : ((language == "zh-CN") ? "SimplifiedChinese" : "English")); } private static Texture2D ReadItemIcon(object uiData) { if (uiData == null) { return null; } MethodInfo method = uiData.GetType().GetMethod("GetIcon", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy, null, Type.EmptyTypes, null); if (method != null && method.ReturnType == typeof(Texture2D)) { try { object? obj = method.Invoke(uiData, null); Texture2D val = (Texture2D)((obj is Texture2D) ? obj : null); if ((Object)(object)val != (Object)null) { return val; } } catch (Exception) { } } object obj2 = ItemApiAccess.ReadMember(uiData, "icon"); return (Texture2D)((obj2 is Texture2D) ? obj2 : null); } private static string GetSpawnName(object item) { object obj = ItemApiAccess.ReadMember(item, "name"); string text = obj as string; if (!string.IsNullOrWhiteSpace(text)) { return text.Replace("(Clone)", string.Empty).Trim(); } return string.Empty; } private static string GetLocalizedItemKey(object item, string methodName) { object target = ItemApiAccess.ReadMember(item, "UIData"); string text = ItemApiAccess.ReadMember(target, "itemName") as string; if (string.IsNullOrWhiteSpace(text)) { return string.Empty; } Type type = ItemApiAccess.FindGameType("LocalizedText"); if (type == null) { return string.Empty; } MethodInfo method = type.GetMethod(methodName, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy, null, new Type[1] { typeof(string) }, null); if (method == null) { return string.Empty; } try { return (method.Invoke(null, new object[1] { text }) as string) ?? string.Empty; } catch (Exception) { return string.Empty; } } private static string GetLocalizedText(string key, string language) { if (string.IsNullOrWhiteSpace(key)) { return string.Empty; } Type type = ItemApiAccess.FindGameType("LocalizedText"); if (type == null) { return string.Empty; } FieldInfo field = type.GetField("CURRENT_LANGUAGE", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy); if (field == null || !field.FieldType.IsEnum) { return string.Empty; } MethodInfo method = type.GetMethod("GetText", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy, null, new Type[2] { typeof(string), field.FieldType }, null); if (method == null) { return string.Empty; } try { object obj = Enum.Parse(field.FieldType, language); return (method.Invoke(null, new object[2] { key, obj }) as string) ?? string.Empty; } catch (Exception) { return string.Empty; } } } internal sealed class ItemSpawnApi { public bool CanSpawnItems { get { try { object localCharacterItems = GetLocalCharacterItems(); return IsInRoom() && HasSpawnCapability(localCharacterItems); } catch (Exception) { return false; } } } public bool SpawnItem(ItemCatalogEntry entry, bool includeSpecial = false) { try { return RequestSpawn(entry, includeSpecial); } catch (Exception) { return false; } } private bool RequestSpawn(ItemCatalogEntry entry, bool includeSpecial) { if (entry == null || !entry.CanSpawnManually || !CanSpawnItems) { return false; } if (!TryGetDatabaseItem(entry.SpawnName, out var item)) { return false; } if (!ItemApiAccess.TryIsValidToSpawn(item, out var valid, out var _)) { return false; } bool flag = valid || ItemManualSpawnPolicy.AllowsSoloOverride(item, entry.SpawnName); if (!flag) { return false; } bool duplicatePrefab = ItemApiAccess.ReadMember(item, "isSecretlyOtherItemPrefab") != null; if (!ItemVisibility.ShouldShow(entry.SpawnName, registered: true, flag, duplicatePrefab, includeSpecial)) { return false; } object localCharacterItems = GetLocalCharacterItems(); if (localCharacterItems == null) { return false; } MethodInfo methodInfo = FindSpawnMethod(localCharacterItems.GetType()); if (methodInfo == null) { return false; } try { methodInfo.Invoke(localCharacterItems, new object[1] { entry.SpawnName }); return true; } catch (Exception) { return false; } } private static bool HasSpawnCapability(object characterItems) { if (characterItems == null) { return false; } Type type = ItemApiAccess.FindLoadedType("Photon.Pun.PhotonNetwork"); if (!ItemApiAccess.HasStaticBooleanMember(type, "InRoom")) { return false; } Type type2 = ItemApiAccess.FindGameType("ItemDatabase"); Type type3 = ItemApiAccess.FindGameType("Item"); if (type2 == null || type3 == null || ItemApiAccess.ReadStaticMember(type2, "Instance") == null) { return false; } if (FindTryGetItemMethod(type2, type3) == null || FindSpawnMethod(characterItems.GetType()) == null) { return false; } MethodInfo method = type3.GetMethod("IsValidToSpawn", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy, null, Type.EmptyTypes, null); if (method != null) { return method.ReturnType == typeof(bool); } return false; } private static bool TryGetDatabaseItem(string spawnName, out object item) { item = null; Type type = ItemApiAccess.FindGameType("ItemDatabase"); Type type2 = ItemApiAccess.FindGameType("Item"); if (type == null || type2 == null) { return false; } MethodInfo methodInfo = FindTryGetItemMethod(type, type2); if (methodInfo == null) { return false; } object[] array = new object[2] { spawnName, null }; try { if (!(bool)methodInfo.Invoke(null, array)) { return false; } item = array[1]; return item != null; } catch (Exception) { return false; } } private static MethodInfo FindTryGetItemMethod(Type databaseType, Type itemType) { MethodInfo[] methods = databaseType.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy); foreach (MethodInfo methodInfo in methods) { if (!(methodInfo.Name != "TryGetItem") && !(methodInfo.ReturnType != typeof(bool))) { ParameterInfo[] parameters = methodInfo.GetParameters(); if (parameters.Length == 2 && parameters[0].ParameterType == typeof(string) && parameters[1].ParameterType.IsByRef && parameters[1].ParameterType.GetElementType() == itemType) { return methodInfo; } } } return null; } private static bool IsInRoom() { Type type = ItemApiAccess.FindLoadedType("Photon.Pun.PhotonNetwork"); return ItemVisibility.CanRequestSpawn(ItemApiAccess.ReadStaticBoolean(type, "InRoom")); } private static object GetLocalCharacterItems() { Type type = ItemApiAccess.FindGameType("Character"); object target = ItemApiAccess.ReadStaticMember(type, "localCharacter"); object target2 = ItemApiAccess.ReadMember(target, "refs"); return ItemApiAccess.ReadMember(target2, "items"); } private static MethodInfo FindSpawnMethod(Type type) { MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy); foreach (MethodInfo methodInfo in methods) { if (!(methodInfo.Name != "SpawnItemInHand") && !(methodInfo.ReturnType != typeof(void))) { ParameterInfo[] parameters = methodInfo.GetParameters(); if (parameters.Length == 1 && parameters[0].ParameterType == typeof(string)) { return methodInfo; } } } return null; } } internal static class ItemManualSpawnPolicy { internal static bool AllowsSoloOverride(object item, string spawnName) { if (item == null || SpecialItems.Classify(spawnName) != SpecialItemKind.MultiplayerItems) { return false; } try { Type type = ItemApiAccess.FindLoadedType("Photon.Pun.PhotonNetwork"); if (!ItemApiAccess.HasStaticBooleanMember(type, "OfflineMode") || !ItemApiAccess.HasStaticBooleanMember(type, "InRoom")) { return false; } bool flag = ItemApiAccess.ReadStaticBoolean(type, "OfflineMode"); if (!flag && ItemApiAccess.ReadStaticBoolean(type, "InRoom")) { object target = ItemApiAccess.ReadStaticMember(type, "CurrentRoom"); object obj = ItemApiAccess.ReadMember(target, "PlayerCount"); flag = obj is int && (int)obj == 1; } if (!flag) { return false; } Type type2 = ItemApiAccess.FindGameType("LootData"); MethodInfo method = item.GetType().GetMethod("GetComponent", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy, null, new Type[1] { typeof(Type) }, null); if (type2 == null || method == null) { return false; } object obj2 = method.Invoke(item, new object[1] { type2 }); if (obj2 == null) { return false; } object obj3 = ItemApiAccess.ReadMember(obj2, "banInSolo"); object obj4 = ItemApiAccess.ReadMember(obj2, "excludeBasedOnCustomRunSetting"); if (!(obj3 is bool) || !(bool)obj3 || !(obj4 is bool) || (bool)obj4) { return false; } FieldInfo field = type2.GetField("useOtherItemForSpawningValidity", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy); if (field == null || field.GetValue(obj2) != null) { return false; } Type type3 = ItemApiAccess.FindGameType("RunSettings"); if (type3 == null) { return false; } MethodInfo method2 = type3.GetMethod("IsItemEnabled", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy, null, new Type[1] { typeof(string) }, null); MethodInfo method3 = type3.GetMethod("IsItemEnabled", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy, null, new Type[1] { typeof(ushort) }, null); object obj5 = ItemApiAccess.ReadMember(item, "itemID"); if (method2 == null || method3 == null || method2.ReturnType != typeof(bool) || method3.ReturnType != typeof(bool) || !(obj5 is ushort)) { return false; } return (bool)method2.Invoke(null, new object[1] { spawnName }) && (bool)method3.Invoke(null, new object[1] { obj5 }); } catch (Exception) { return false; } } } internal sealed class ItemCatalogEntry { public readonly string SpawnName; public readonly string CurrentName; public readonly string EnglishName; public readonly string SimplifiedName; public readonly string TraditionalName; public readonly Texture2D Icon; public readonly ItemCategory Categories; public readonly ConsumableKind Kinds; public readonly bool ValidToSpawn; public readonly bool CanSpawnManually; private readonly string englishDescription; private readonly string simplifiedDescription; private readonly string traditionalDescription; public string DisplayName(string language) { string text = language switch { "en" => EnglishName, "zh-CN" => SimplifiedName, "zh-TW" => TraditionalName, _ => CurrentName, }; if (!string.IsNullOrWhiteSpace(text)) { return text; } return CurrentName; } public string DisplayDescription(string language) { string text = ((language == "zh-TW") ? traditionalDescription : ((language == "zh-CN") ? simplifiedDescription : englishDescription)); if (!string.IsNullOrWhiteSpace(text)) { return text.Trim(); } return string.Empty; } public ItemCatalogEntry(string spawnName, string currentName, string englishName, string simplifiedName, string traditionalName, Texture2D icon, ItemCategory categories, ConsumableKind kinds, string englishDescription = null, string simplifiedDescription = null, string traditionalDescription = null, bool validToSpawn = true, bool? canSpawnManually = null) { SpawnName = spawnName; CurrentName = currentName; EnglishName = englishName; SimplifiedName = simplifiedName; TraditionalName = traditionalName; Icon = icon; Categories = categories; Kinds = kinds; ValidToSpawn = validToSpawn; CanSpawnManually = canSpawnManually ?? validToSpawn; this.englishDescription = englishDescription; this.simplifiedDescription = simplifiedDescription; this.traditionalDescription = traditionalDescription; } } [Flags] internal enum ItemCategory { None = 0, Mystical = 1, Consumable = 2, Deployable = 4, Equipment = 8, Other = 0x10 } [Flags] internal enum ConsumableKind { None = 0, Food = 1, Healing = 2, Recovery = 4, Buff = 8, Revive = 0x10 } internal static class ItemClassification { private static readonly Dictionary<string, ItemCategory> Known = BuildCategories(); public static ItemCategory Categories(string uiName, string nativeTags) { ItemCategory value; bool flag = Known.TryGetValue((uiName ?? string.Empty).Trim(), out value); if (HasTag(nativeTags, "Mystical") || HasTag(nativeTags, "ScoutAmulet") || HasTag(nativeTags, "GoldenIdol") || HasTag(nativeTags, "BookOfBones")) { value |= ItemCategory.Mystical; } if (!flag && IsFoodTag(nativeTags)) { value |= ItemCategory.Consumable; } if (value != ItemCategory.None) { return value; } return ItemCategory.Other; } public static ConsumableKind Kinds(string uiName, string nativeTags) { if ((Categories(uiName, nativeTags) & ItemCategory.Consumable) == 0) { return ConsumableKind.None; } ConsumableKind consumableKind = ConsumableKind.None; switch ((uiName ?? string.Empty).Trim().ToLowerInvariant()) { case "medicinal root": case "medicinalroot": consumableKind = ConsumableKind.Food | ConsumableKind.Healing | ConsumableKind.Recovery; break; case "napberry": consumableKind = ConsumableKind.Food | ConsumableKind.Healing | ConsumableKind.Recovery; break; case "froglegs": consumableKind = ConsumableKind.Food; break; case "mandrake": consumableKind = ConsumableKind.Food | ConsumableKind.Recovery; break; case "bandages": consumableKind = ConsumableKind.Healing; break; case "first aid kit": case "firstaidkit": case "cure-all": case "remedy fungus": consumableKind = ConsumableKind.Healing | ConsumableKind.Recovery; break; case "antidote": case "heat pack": consumableKind = ConsumableKind.Recovery; break; case "sunscreen": consumableKind = ConsumableKind.Buff; break; case "energy drink": case "sports drink": consumableKind = ConsumableKind.Buff; break; case "fortified milk": case "fortifiedmilk": consumableKind = ConsumableKind.Healing | ConsumableKind.Buff; break; case "scout effigy": case "scouteffigy": consumableKind = ConsumableKind.Revive; break; } if (IsFoodTag(nativeTags)) { consumableKind |= ConsumableKind.Food; } return consumableKind; } public static bool Matches(ItemCategory categories, ConsumableKind kinds, ItemCategory category, ConsumableKind kind) { if (category == ItemCategory.None || (categories & category) != ItemCategory.None) { if (kind != ConsumableKind.None) { return (kinds & kind) != 0; } return true; } return false; } public static ConsumableKind[] AvailableKinds(IEnumerable<ItemCatalogEntry> catalog) { ConsumableKind consumableKind = ConsumableKind.None; foreach (ItemCatalogEntry item in catalog) { if ((item.Categories & ItemCategory.Consumable) != ItemCategory.None) { consumableKind |= item.Kinds; } } List<ConsumableKind> list = new List<ConsumableKind>(); list.Add(ConsumableKind.None); List<ConsumableKind> list2 = list; ConsumableKind[] array = new ConsumableKind[5] { ConsumableKind.Food, ConsumableKind.Healing, ConsumableKind.Recovery, ConsumableKind.Buff, ConsumableKind.Revive }; foreach (ConsumableKind consumableKind2 in array) { if ((consumableKind & consumableKind2) != ConsumableKind.None) { list2.Add(consumableKind2); } } return list2.ToArray(); } private static bool IsFoodTag(string tags) { if (!HasTag(tags, "PackagedFood") && !HasTag(tags, "Berry") && !HasTag(tags, "Mushroom") && !HasTag(tags, "GourmandRequirement")) { return HasTag(tags, "Bird"); } return true; } private static bool HasTag(string tags, string expected) { string[] array = (tags ?? string.Empty).Split(new char[1] { ',' }); foreach (string text in array) { if (string.Equals(text.Trim(), expected, StringComparison.Ordinal)) { return true; } } return false; } private static Dictionary<string, ItemCategory> BuildCategories() { Dictionary<string, ItemCategory> dictionary = new Dictionary<string, ItemCategory>(StringComparer.OrdinalIgnoreCase); Add(dictionary, ItemCategory.Mystical, "AMULET_CLONE|AMULET_DOUBLEJUMP|AMULET_HEALING|AMULET_INFINITESTAM|Ancient Idol|anti-rope cannon|anti-rope spool|Bugle of Friendship|Cursed Skull|Faerie Lantern|RitualDagger|Scout Effigy|ScoutEffigy|Scoutmaster's Bugle|SCOUTMASTERSOUL|ScoutsHonor|Strange Gem|THEBOOKOFBONES|VOIDLAUNCHER|Warp Compass|Warp Fungus"); Add(dictionary, ItemCategory.Consumable, "Airline Food|Aloe Vera|Antidote|Balloon|Balloon Bunch|Bandages|Big Egg|Big Lollipop|Bird|Black Clusterberry|Blue Berrynana|Blue Shroomberry|Brown Berrynana|Bugle Shroom|Button Shroom|Cactus|Chubby Shroom|Cluster Shroom|Coconut|Coconut Half|Cure-All|EARLYWORM|Egg|Energy Drink|First Aid Kit|FirstAidKit|Fortified Milk|FortifiedMilk|FrogLegs|Gold Prickleberry|Granola Bar|Green Clusterberry|Green Crispberry|Green Kingberry|Green Shroomberry|Heat Pack|Honeycomb|Hot Dog|Mandrake|Marshmallow|Medicinal Root|MedicinalRoot|Napberry|Orange Winterberry|Pandora's Lunchbox|Pink Berrynana|Purple Kingberry|Purple Shroomberry|Red Clusterberry|Red Crispberry|Red Prickleberry|Red Shroomberry|Remedy Fungus|Scorchberry|Scout Cookies|Scout Effigy|ScoutEffigy|Small Egg|Sports Drink|Sunscreen|Tick|Trail Mix|Yellow Berrynana|Yellow Clusterberry|Yellow Crispberry|Yellow Kingberry|Yellow Shroomberry|Yellow Winterberry"); Add(dictionary, ItemCategory.Deployable, "Magic Bean"); Add(dictionary, ItemCategory.Deployable, "anti-rope cannon|anti-rope spool|Bounce Fungus|Chain Launcher|Checkpoint Flag|Cloud Fungus|Piton|Portable Stove|rope cannon|rope spool|Scout Cannon|Shelf Fungus|VOIDLAUNCHER"); Add(dictionary, ItemCategory.Equipment, "Backpack|Binoculars|Bugle|Candlestick|Compass|Fannypack|Flare|Glider|Guidebook|Jetpack|Lantern|Megaphone|Parasol|Pirate's Compass|Rescue Claw|Rocketpack|Torch"); Add(dictionary, ItemCategory.Other, "Beehive|Berrynana Peel|Bing Bong|Blowgun|Conch|Dynamite|Frisbee|Frog|Scorpion|Scroll|SNOWBALL|Stick|Stone|Torn Page"); return dictionary; } private static void Add(Dictionary<string, ItemCategory> map, ItemCategory category, string names) { string[] array = names.Split(new char[1] { '|' }); foreach (string key in array) { map.TryGetValue(key, out var value); map[key] = value | category; } } } internal static class ChineseScript { public static string ToSimplified(string value) { return Convert(value, "zh-CN", 33554432u); } public static string ToTraditional(string value) { return Convert(value, "zh-TW", 67108864u); } private static string Convert(string value, string locale, uint flags) { if (string.IsNullOrEmpty(value) || Environment.OSVersion.Platform != PlatformID.Win32NT) { return value; } try { int num = LCMapStringEx(locale, flags, value, -1, null, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); if (num == 0) { return value; } StringBuilder stringBuilder = new StringBuilder(num); return (LCMapStringEx(locale, flags, value, -1, stringBuilder, num, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero) == 0) ? value : stringBuilder.ToString(); } catch (DllNotFoundException) { return value; } catch (EntryPointNotFoundException) { return value; } } [DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)] private static extern int LCMapStringEx(string locale, uint flags, string source, int sourceLength, StringBuilder destination, int destinationLength, IntPtr version, IntPtr reserved, IntPtr sortHandle); } internal sealed class ItemDescriptions { private readonly Dictionary<string, string> english; private readonly Dictionary<string, string> simplified; public ItemDescriptions(Action<string> warning = null) { english = Read("peak-item-tooltip.descriptions.json", warning); simplified = Read("peak-item-tooltip.descriptions.zh-CN.json", warning); } public string Get(string language, params string[] names) { string text = Find((language == "zh-CN" || language == "zh-TW") ? simplified : english, names); if (!(language == "zh-TW")) { return text; } return ChineseScript.ToTraditional(text); } private static string Find(Dictionary<string, string> table, string[] names) { foreach (string text in names) { if (!string.IsNullOrWhiteSpace(text) && table.TryGetValue(text.Trim(), out var value)) { return value; } } return string.Empty; } private static Dictionary<string, string> Read(string fileName, Action<string> warning) { //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Invalid comparison between Unknown and I4 Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); JToken obj = EmbeddedJson.Read("Descriptions." + fileName, warning)["items"]; JObject val = (JObject)(object)((obj is JObject) ? obj : null); if (val == null) { return dictionary; } foreach (JProperty item in val.Properties()) { JToken value = item.Value; JObject val2 = (JObject)(object)((value is JObject) ? value : null); JToken val3 = ((val2 == null) ? null : val2["description"]); if (val3 != null && (int)val3.Type == 8) { string text = (string)val3; if (!string.IsNullOrWhiteSpace(text)) { dictionary[item.Name.Trim()] = text.Trim(); } } } return dictionary; } } internal static class ItemSearch { public static bool Matches(string query, string currentName, string englishName, string simplifiedName, string traditionalName) { string text = Normalize(query); if (text.Length == 0) { return true; } string[] array = new string[4] { currentName ?? string.Empty, englishName ?? string.Empty, simplifiedName ?? string.Empty, traditionalName ?? string.Empty }; string[] array2 = array; foreach (string value in array2) { if (Contains(value, text)) { return true; } } bool flag = false; string[] array3 = array; foreach (string value2 in array3) { if (Contains(value2, "glider") || Contains(value2, "滑翔翼")) { flag = true; break; } } if (flag) { if (!Contains("傘 umbrella", text)) { return Contains("umbrella", text); } return true; } return false; } private static bool Contains(string value, string query) { return Normalize(value).IndexOf(query, StringComparison.OrdinalIgnoreCase) >= 0; } private static string Normalize(string value) { if (string.IsNullOrEmpty(value)) { return string.Empty; } StringBuilder stringBuilder = new StringBuilder(value.Length); foreach (char c in value) { if (!char.IsWhiteSpace(c)) { stringBuilder.Append(char.ToLowerInvariant(c)); } } return ChineseScript.ToSimplified(stringBuilder.ToString()); } } internal static class ItemVisibility { private static readonly HashSet<string> HiddenPrefabs = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "ClimbingChalk", "Climbing Chalk", "Clusterberry_UNUSED", "FireWood", "GuidebookPage_13_FirstTeams", "Megaphone", "Mushroom Glow", "Weird Shroom", "Stone", "Skull", "Warpsketball", "Basketball", "Cheat Compass", "Cheat Compass 1", "BingBong_Prop Variant", "Binoculars_Prop", "Bugle_Prop Variant", "GuidebookPage", "Lollipop_Prop", "Mandrake_Hidden", "Parasol_Roots Variant", "Parachute", "AUTOPARACHUTE", "ScoutCookies_Vanilla", "Warp Compass", "RescueHook_Infinite", "ScoutmasterSoul" }; public static bool ShouldShow(string spawnName, bool registered, bool canSpawn, bool duplicatePrefab, bool includeSpecial = false) { if (string.IsNullOrWhiteSpace(spawnName) || !registered || duplicatePrefab) { return false; } SpecialItemKind specialItemKind = SpecialItems.Classify(spawnName); if (specialItemKind == SpecialItemKind.MultiplayerItems) { if (!canSpawn) { return includeSpecial; } return true; } if (!canSpawn) { return false; } if (specialItemKind != SpecialItemKind.None) { return includeSpecial; } string text = NormalizePrefabName(spawnName); if (!HiddenPrefabs.Contains(text) && !text.StartsWith("C_", StringComparison.OrdinalIgnoreCase) && !text.StartsWith("GuidebookPage", StringComparison.OrdinalIgnoreCase) && !text.StartsWith("Basketball", StringComparison.OrdinalIgnoreCase) && text.IndexOf("_Prop", StringComparison.OrdinalIgnoreCase) < 0 && !text.StartsWith("Cheat ", StringComparison.OrdinalIgnoreCase) && !text.EndsWith("_UNUSED", StringComparison.OrdinalIgnoreCase) && !text.EndsWith("_TEMP", StringComparison.OrdinalIgnoreCase)) { return !text.EndsWith("_Hidden", StringComparison.OrdinalIgnoreCase); } return false; } public static bool CanRequestSpawn(bool inRoom) { return inRoom; } private static string NormalizePrefabName(string value) { return (value ?? string.Empty).Replace("(Clone)", string.Empty).Trim(); } } internal enum SpecialItemKind { None, SpecialVariants, UnusedItems, MultiplayerItems, LobbyToys, MiscellaneousItems } internal static class SpecialItems { private static readonly HashSet<string> Chess = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "C_King B", "C_King W", "C_Queen B", "C_Queen W", "C_Rook B", "C_Rook W", "C_Bishop B", "C_Bishop W", "C_Knight B", "C_Knight W", "C_Pawn B", "C_Pawn W" }; private static readonly HashSet<string> LobbyProps = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "Binoculars_Prop", "Lollipop_Prop", "Bugle_Prop Variant", "BingBong_Prop Variant", "Passport" }; private static readonly HashSet<string> Multiplayer = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "Fannypack", "Cursed Skull", "Bugle_Magic", "ScoutEffigy", "HealingDart Variant", "RitualDagger" }; private static readonly HashSet<string> Miscellaneous = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "GuidebookPage", "GuidebookPageScroll Variant", "GuidebookPage_0_Intro", "GuidebookPage_10_Sleepy", "GuidebookPage_11_Awake", "GuidebookPage_12_Crashout", "GuidebookPage_13_FirstTeams", "GuidebookPage_1_Mushrooms", "GuidebookPage_2_Campfire", "GuidebookPage_3_Revival", "GuidebookPage_4_Poison", "GuidebookPage_5_Zombies", "GuidebookPage_6_BodyHeat", "GuidebookPage_7_BurningSun", "GuidebookPage_8_Magma", "GuidebookPage_9_Gloom" }; public static SpecialItemKind Classify(string spawnName) { string text = Normalize(spawnName); if (EqualsName(text, "RescueHook_Infinite") || EqualsName(text, "ScoutCookies_Vanilla")) { return SpecialItemKind.SpecialVariants; } if (EqualsName(text, "Parachute")) { return SpecialItemKind.UnusedItems; } if (LobbyProps.Contains(text) || Chess.Contains(text) || EqualsName(text, "Basketball") || EqualsName(text, "Warpsketball")) { return SpecialItemKind.LobbyToys; } if (Miscellaneous.Contains(text)) { return SpecialItemKind.MiscellaneousItems; } if (Multiplayer.Contains(text)) { return SpecialItemKind.MultiplayerItems; } return SpecialItemKind.None; } public static SpecialItemKind[] AvailableKinds(IEnumerable<ItemCatalogEntry> catalog) { HashSet<SpecialItemKind> hashSet = new HashSet<SpecialItemKind>(); foreach (ItemCatalogEntry item2 in catalog) { hashSet.Add(Classify(item2.SpawnName)); } List<SpecialItemKind> list = new List<SpecialItemKind>(); list.Add(SpecialItemKind.None); List<SpecialItemKind> list2 = list; SpecialItemKind[] array = new SpecialItemKind[5] { SpecialItemKind.SpecialVariants, SpecialItemKind.UnusedItems, SpecialItemKind.MultiplayerItems, SpecialItemKind.LobbyToys, SpecialItemKind.MiscellaneousItems }; foreach (SpecialItemKind item in array) { if (hashSet.Contains(item)) { list2.Add(item); } } return list2.ToArray(); } public static string DisplayName(string spawnName, Localization loc) { string text = Normalize(spawnName); if (EqualsName(text, "RescueHook_Infinite")) { return loc.Text("InfiniteHookName"); } if (EqualsName(text, "ScoutCookies_Vanilla")) { return loc.Text("VanillaCookiesName"); } if (EqualsName(text, "Parachute")) { return loc.Text("ParachuteName"); } if (EqualsName(text, "Basketball")) { return loc.Text("BasketballName"); } if (EqualsName(text, "Warpsketball")) { return loc.Text("WarpsketballName"); } if (EqualsName(text, "GuidebookPageScroll Variant")) { return loc.Text("ScrollName"); } if (EqualsName(text, "Binoculars_Prop")) { return loc.Text("LobbyBinocularsName"); } if (EqualsName(text, "Lollipop_Prop")) { return loc.Text("LobbyLollipopName"); } if (EqualsName(text, "Bugle_Prop Variant")) { return loc.Text("LobbyBugleName"); } if (EqualsName(text, "BingBong_Prop Variant")) { return loc.Text("LobbyBingBongName"); } if (EqualsName(text, "Passport")) { return loc.Text("LobbyPassportName"); } if (EqualsName(text, "Cursed Skull")) { return loc.Text("CursedSkullName"); } if (EqualsName(text, "Bugle_Magic")) { return loc.Text("FriendshipBugleName"); } if (EqualsName(text, "ScoutEffigy")) { return loc.Text("ScoutEffigyName"); } if (EqualsName(text, "HealingDart Variant")) { return loc.Text("BlowgunName"); } if (EqualsName(text, "RitualDagger")) { return loc.Text("RitualDaggerName"); } if (EqualsName(text, "Fannypack")) { return loc.Text("FannypackName"); } if (!Chess.Contains(text)) { return string.Empty; } string text2 = text.Substring(2).Split(' ', '_')[0].ToLowerInvariant(); string key = (text.EndsWith(" B", StringComparison.OrdinalIgnoreCase) ? "ChessBlack" : "ChessWhite"); return loc.Format(key, loc.Text("Chess_" + text2)); } public static string Description(string spawnName, Localization loc) { string text = Normalize(spawnName); if (EqualsName(text, "RescueHook_Infinite")) { return loc.Text("InfiniteHookDescription"); } if (EqualsName(text, "ScoutCookies_Vanilla")) { return loc.Text("VanillaCookiesDescription"); } if (EqualsName(text, "Parachute")) { return loc.Text("ParachuteDescription"); } if (EqualsName(text, "Basketball")) { return loc.Text("BasketballDescription"); } if (EqualsName(text, "Warpsketball")) { return loc.Text("WarpsketballDescription"); } if (!Chess.Contains(text)) { return string.Empty; } return loc.Text("ChessDescription"); } private static bool EqualsName(string name, string expected) { return string.Equals(name, expected, StringComparison.OrdinalIgnoreCase); } private static string Normalize(string name) { return (name ?? string.Empty).Replace("(Clone)", string.Empty).Trim(); } } } namespace PeakAdminToolkit.UI { internal sealed class SpecialItemFilter { private ItemCategory category; public bool Enabled { get; private set; } public SpecialItemKind SelectedKind { get; private set; } public void SetCategory(ItemCategory value) { if (category != value) { Reset(); } category = value; } public void SetEnabled(bool value) { Enabled = value && category == ItemCategory.Other; SelectedKind = SpecialItemKind.None; } public void SelectKind(SpecialItemKind kind) { SelectedKind = (Enabled ? kind : SpecialItemKind.None); } public void Reset() { Enabled = false; SelectedKind = SpecialItemKind.None; } public bool Matches(ItemCatalogEntry item) { SpecialItemKind specialItemKind = SpecialItems.Classify(item.SpawnName); if (specialItemKind != SpecialItemKind.None && (specialItemKind != SpecialItemKind.MultiplayerItems || !item.CanSpawnManually) && (!Enabled || category != ItemCategory.Other)) { return false; } if (SelectedKind != SpecialItemKind.None) { return SelectedKind == specialItemKind; } return true; } } internal sealed class CursorLease { private bool acquired; private CursorLockMode previousLock; private bool previousVisibility; public void Acquire() { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) if (!acquired) { previousLock = Cursor.lockState; previousVisibility = Cursor.visible; acquired = true; } Cursor.lockState = (CursorLockMode)0; Cursor.visible = true; } public void Release(bool anotherWindowNeedsCursor) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) if (acquired) { acquired = false; if (!anotherWindowNeedsCursor) { Cursor.lockState = previousLock; Cursor.visible = previousVisibility; } } } } internal static class WindowBounds { private const float ScreenMargin = 16f; public static float ScaleFor(float screenWidth, float screenHeight) { if (screenWidth <= 0f || screenHeight <= 0f) { return 1f; } return Mathf.Min(screenWidth / 1920f, screenHeight / 1080f); } public static Rect Centered(float screenWidth, float screenHeight) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) float num = ScaleFor(screenWidth, screenHeight); return Clamp(new Rect((screenWidth / num - 1200f) / 2f, (screenHeight / num - 800f) / 2f, 1200f, 800f), screenWidth / num, screenHeight / num); } public static Rect Clamp(Rect window, float screenWidth, float screenHeight) { //IL_009e: Unknown result type (might be due to invalid IL or missing references) ((Rect)(ref window)).width = Mathf.Min(((Rect)(ref window)).width, Mathf.Max(1f, screenWidth - 16f)); ((Rect)(ref window)).height = Mathf.Min(((Rect)(ref window)).height, Mathf.Max(1f, screenHeight - 16f)); ((Rect)(ref window)).x = Mathf.Clamp(((Rect)(ref window)).x, 0f, Mathf.Max(0f, screenWidth - ((Rect)(ref window)).width)); ((Rect)(ref window)).y = Mathf.Clamp(((Rect)(ref window)).y, 0f, Mathf.Max(0f, screenHeight - ((Rect)(ref window)).height)); return window; } } internal static class ItemGridLayout { private const float Gap = 8f; private const float MinWidth = 140f; private const float Height = 142f; public static int Columns(float width) { return Math.Max(1, (int)((width + 8f) / 148f)); } public static Rect CardRect(int index, float width) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) int num = Columns(width); float num2 = (width - 8f * (float)(num - 1)) / (float)num; return new Rect((float)(index % num) * (num2 + 8f), (float)(index / num) * 150f, num2, 142f); } public static float ContentHeight(int count, float width) { if (count != 0) { return (float)((count - 1) / Columns(width) + 1) * 150f - 8f; } return 0f; } public static float ContentWidth(float viewportWidth) { return Math.Max(1f, viewportWidth - 24f); } public static Rect StatusRect(Rect card, float measuredHeight) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) float num = ((measuredHeight > 0f) ? Math.Max(28f, (float)Math.Ceiling(measuredHeight) + 4f) : 0f); return new Rect(((Rect)(ref card)).x + 8f, ((Rect)(ref card)).y + 92f - num, ((Rect)(ref card)).width - 16f, num); } public static Rect IconRect(Rect card, float statusHeight) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) float num = ((statusHeight > 0f) ? Math.Min(80f, 80f - statusHeight) : 80f); return new Rect(((Rect)(ref card)).x + (((Rect)(ref card)).width - num) / 2f, ((Rect)(ref card)).y + 8f, num, num); } public static int HitTest(Rect viewport, Vector2 scroll, Vector2 pointer, int count) { //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) float num = ContentWidth(((Rect)(ref viewport)).width); if (pointer.x < ((Rect)(ref viewport)).x || pointer.x >= ((Rect)(ref viewport)).x + num || pointer.y < ((Rect)(ref viewport)).y || pointer.y >= ((Rect)(ref viewport)).y + ((Rect)(ref viewport)).height) { return -1; } float num2 = pointer.x - ((Rect)(ref viewport)).x + scroll.x; float num3 = pointer.y - ((Rect)(ref viewport)).y + scroll.y; for (int i = 0; i < count; i++) { Rect val = CardRect(i, num); if (num2 >= ((Rect)(ref val)).x && num2 < ((Rect)(ref val)).x + ((Rect)(ref val)).width && num3 >= ((Rect)(ref val)).y && num3 < ((Rect)(ref val)).y + ((Rect)(ref val)).height) { return i; } } return -1; } } internal sealed class Theme : IDisposable { private bool ready; private Font font; private Texture2D windowBackground; private Texture2D panelBackground; private Texture2D buttonBackground; private Texture2D buttonHoverBackground; private Texture2D buttonActiveBackground; private Texture2D buttonSelectedHoverBackground; public GUIStyle Window { get; private set; } public GUIStyle Heading { get; private set; } public GUIStyle Body { get; private set; } public GUIStyle Small { get; private set; } public GUIStyle Button { get; private set; } public GUIStyle Toggle { get; private set; } public GUIStyle Card { get; private set; } public GUIStyle CardName { get; private set; } public GUIStyle Tooltip { get; private set; } public GUIStyle TextField { get; private set; } public void Ensure() { //IL_0059: 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_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Expected O, but got Unknown //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Expected O, but got Unknown //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Expected O, but got Unknown //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Expected O, but got Unknown //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Expected O, but got Unknown //IL_0264: Unknown result type (might be due to invalid IL or missing references) //IL_0279: Unknown result type (might be due to invalid IL or missing references) //IL_0280: Expected O, but got Unknown //IL_0357: Unknown result type (might be due to invalid IL or missing references) //IL_035e: Expected O, but got Unknown //IL_0394: Unknown result type (might be due to invalid IL or missing references) //IL_03a5: Unknown result type (might be due to invalid IL or missing references) //IL_03ac: Expected O, but got Unknown //IL_03ba: Unknown result type (might be due to invalid IL or missing references) //IL_03c4: Expected O, but got Unknown //IL_03c6: Unknown result type (might be due to invalid IL or missing references) //IL_03d0: Expected O, but got Unknown //IL_03de: Unknown result type (might be due to invalid IL or missing references) //IL_03e5: Expected O, but got Unknown //IL_0400: Unknown result type (might be due to invalid IL or missing references) //IL_040a: Expected O, but got Unknown //IL_0424: Unknown result type (might be due to invalid IL or missing references) //IL_042b: Expected O, but got Unknown //IL_0448: Unknown result type (might be due to invalid IL or missing references) //IL_0452: Expected O, but got Unknown //IL_0473: Unknown result type (might be due to invalid IL or missing references) //IL_0488: Unknown result type (might be due to invalid IL or missing references) //IL_048f: Expected O, but got Unknown //IL_04b6: Unknown result type (might be due to invalid IL or missing references) //IL_04c0: Expected O, but got Unknown //IL_04f2: Unknown result type (might be due to invalid IL or missing references) if (!ready) { font = Font.CreateDynamicFontFromOSFont(new string[4] { "Microsoft JhengHei", "Microsoft YaHei", "Arial Unicode MS", "Arial" }, 20); windowBackground = CreateTexture(new Color(0.075f, 0.09f, 0.105f, 0.98f)); panelBackground = CreateTexture(new Color(0.12f, 0.15f, 0.17f, 0.99f)); buttonBackground = CreateTexture(new Color(0.22f, 0.27f, 0.3f, 1f)); buttonHoverBackground = CreateTexture(new Color(0.3f, 0.39f, 0.43f, 1f)); buttonActiveBackground = CreateTexture(new Color(0.1f, 0.39f, 0.36f, 1f)); buttonSelectedHoverBackground = CreateTexture(new Color(0.15f, 0.5f, 0.45f, 1f)); GUIStyle val = new GUIStyle(GUI.skin.box); val.fontSize = 18; val.fontStyle = (FontStyle)1; val.alignment = (TextAnchor)1; val.padding = new RectOffset(16, 16, 16, 16); val.contentOffset = Vector2.zero; Window = val; SetBackground(Window, windowBackground); SetTextColor(Window, new Color(0.96f, 0.98f, 1f, 1f)); GUIStyle val2 = new GUIStyle(GUI.skin.label); val2.wordWrap = true; val2.richText = true; val2.fontSize = 20; Body = val2; SetTextColor(Body, new Color(0.94f, 0.96f, 0.98f, 1f)); GUIStyle val3 = new GUIStyle(Body); val3.fontSize = 26; val3.fontStyle = (FontStyle)1; val3.wordWrap = false; val3.alignment = (TextAnchor)3; Heading = val3; GUIStyle val4 = new GUIStyle(GUI.skin.label); val4.fontSize = 16; val4.wordWrap = true; val4.richText = true; Small = val4; SetTextColor(Small, new Color(0.82f, 0.87f, 0.9f, 1f)); GUIStyle val5 = new GUIStyle(GUI.skin.button); val5.fixedHeight = 38f; val5.fontSize = 18; Button = val5; SetButtonState(Button.normal, buttonBackground); SetButtonState(Button.hover, buttonHoverBackground); SetButtonState(Button.focused, buttonHoverBackground); SetButtonState(Button.active, buttonActiveBackground); SetButtonState(Button.onNormal, buttonActiveBackground); SetButtonState(Button.onHover, buttonSelectedHoverBackground); SetButtonState(Button.onFocused, buttonSelectedHoverBackground); SetButtonState(Button.onActive, buttonActiveBackground); GUIStyle val6 = new GUIStyle(GUI.skin.toggle); val6.fontSize = 18; val6.fixedHeight = 32f; Toggle = val6; SetTextColor(Toggle, new Color(0.94f, 0.96f, 0.98f, 1f)); GUIStyle val7 = new GUIStyle(Button); val7.fixedHeight = 0f; val7.margin = new RectOffset(); val7.padding = new RectOffset(); Card = val7; GUIStyle val8 = new GUIStyle(Body); val8.fontSize = 18; val8.richText = false; val8.alignment = (TextAnchor)4; val8.padding = new RectOffset(); val8.clipping = (TextClipping)1; CardName = val8; GUIStyle val9 = new GUIStyle(GUI.skin.textField); val9.fontSize = 20; val9.fixedHeight = 42f; val9.padding = new RectOffset(10, 10, 7, 7); TextField = val9; SetTextColor(TextField, new Color(0.96f, 0.98f, 1f, 1f)); GUIStyle val10 = new GUIStyle(GUI.skin.box); val10.alignment = (TextAnchor)0; val10.wordWrap = true; val10.richText = true; val10.fontSize = 16; val10.padding = new RectOffset(8, 8, 6, 6); Tooltip = val10; SetBackground(Tooltip, panelBackground); SetTextColor(Tooltip, new Color(0.94f, 0.96f, 0.98f, 1f)); if ((Object)(object)font != (Object)null) { GUIStyle window = Window; GUIStyle heading = Heading; GUIStyle body = Body; GUIStyle small = Small; GUIStyle button = Button; GUIStyle toggle = Toggle; GUIStyle card = Card; GUIStyle cardName = CardName; GUIStyle tooltip = Tooltip; Font val11 = (TextField.font = font); Font val13 = (tooltip.font = val11); Font val15 = (cardName.font = val13); Font val17 = (card.font = val15); Font val19 = (toggle.font = val17); Font val21 = (button.font = val19); Font val23 = (small.font = val21); Font val25 = (body.font = val23); Font val27 = (heading.font = val25); window.font = val27; } ready = true; } } private static Texture2D CreateTexture(Color color) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Expected O, but got Unknown //IL_0015: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(1, 1, (TextureFormat)4, false); ((Object)val).hideFlags = (HideFlags)61; val.SetPixel(0, 0, color); val.Apply(); return val; } private static void SetBackground(GUIStyle style, Texture2D texture) { style.normal.background = texture; style.hover.background = texture; style.active.background = texture; style.focused.background = texture; style.onNormal.background = texture; style.onHover.background = texture; style.onActive.background = texture; style.onFocused.background = texture; } private static void SetTextColor(GUIStyle style, Color color) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) style.normal.textColor = color; style.hover.textColor = color; style.active.textColor = color; style.focused.textColor = color; style.onNormal.textColor = color; style.onHover.textColor = color; style.onActive.textColor = color; style.onFocused.textColor = color; } private static void SetButtonState(GUIStyleState state, Texture2D background) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) state.background = background; state.textColor = new Color(0.97f, 0.98f, 1f, 1f); } private static void DestroyTexture(Texture2D texture) { if ((Object)(object)texture != (Object)null) { Object.Destroy((Object)(object)texture); } } public void Dispose() { Window = null; Heading = null; Body = null; Small = null; Button = null; Card = null; CardName = null; Tooltip = null; TextField = null; if ((Object)(object)font != (Object)null) { Object.Destroy((Object)(object)font); } font = null; DestroyTexture(windowBackground); DestroyTexture(panelBackground); DestroyTexture(buttonBackground); DestroyTexture(buttonHoverBackground); DestroyTexture(buttonActiveBackground); DestroyTexture(buttonSelectedHoverBackground); windowBackground = null; panelBackground = null; buttonBackground = null; buttonHoverBackground = null; buttonActiveBackground = null; buttonSelectedHoverBackground = null; ready = false; } } internal sealed class Toast { private string message; private double expires; public void Show(string text, double now, double duration) { message = text; expires = now + duration; } public string Current(double now) { if (!(now < expires)) { return null; } return message; } public void Clear() { message = null; } } internal sealed class Tooltip { private string target; private string content; private double started; public string Observe(string id, string text, double now) { if (string.IsNullOrEmpty(id) || string.IsNullOrEmpty(text)) { Clear(); return null; } if (target != id || content != text) { target = id; content = text; started = now; } if (!(now - started >= 1.0)) { return null; } return content; } public void Clear() { target = null; content = null; } public static Rect Bounds(Vector2 pointer, float width, float height, float windowWidth, float windowHeight) { //IL_009f: Unknown result type (might be due to invalid IL or missing references) width = Mathf.Min(width, windowWidth - 24f); height = Mathf.Min(height, windowHeight - 24f); float num = pointer.x + 14f; float num2 = pointer.y + 14f; if (num + width > windowWidth - 12f) { num = pointer.x - width - 14f; } if (num2 + height > windowHeight - 12f) { num2 = pointer.y - height - 14f; } return new Rect(Mathf.Clamp(num, 12f, windowWidth - width - 12f), Mathf.Clamp(num2, 12f, windowHeight - height - 12f), width, height); } } internal static class ItemTooltip { public static string Format(ItemCatalogEntry item, Localization localization) { List<string> list = new List<string>(); foreach (ItemCategory value in Enum.GetValues(typeof(ItemCategory))) { if (value != ItemCategory.None && (item.Categories & value) != ItemCategory.None) { list.Add(localization.Text(value.ToString())); } } foreach (ConsumableKind value2 in Enum.GetValues(typeof(ConsumableKind))) { if (value2 != ConsumableKind.None && (item.Kinds & value2) != ConsumableKind.None) { list.Add(localization.Text(value2.ToString())); } } SpecialItemKind specialItemKind = SpecialItems.Classify(item.SpawnName); if (specialItemKind != SpecialItemKind.None) { list.Add(localization.Text(specialItemKind.ToString())); } string text = item.DisplayName(localization.Language) + "\n" + localization.Format("ItemCategory", string.Join(" · ", list.ToArray())); if (!item.CanSpawnManually) { string text2 = text; text = text2 + "\n" + localization.Text("ItemUnavailable") + "\n" + localization.Text("ItemUnavailableReason"); } else if (!item.ValidToSpawn) { string text3 = text; text = text3 + "\n" + localization.Text("SoloManualSpawn") + "\n" + localization.Text("SoloManualSpawnReason"); } string text4 = item.DisplayDescription(localization.Language); if (!string.IsNullOrEmpty(text4)) { return text + "\n\n" + text4; } return text; } } internal sealed class MainWindow : IDisposable { private const int WindowId = 5259604; private static readonly ItemCategory[] Categories = new ItemCategory[6] { ItemCategory.None, ItemCategory.Mystical, ItemCategory.Consumable, ItemCategory.Deployable, ItemCategory.Equipment, ItemCategory.Other }; private ConsumableKind[] availableKinds = new ConsumableKind[1]; private readonly ToolkitConfig config; private readonly PeakApi api; private readonly SelfTools selfTools; private readonly SelfToolsPanel selfPanel = new SelfToolsPanel(); private readonly WorldPanel worldPanel = new WorldPanel(); private readonly PlayerPanel playerPanel; private readonly RoomRoleReader roomRole = new RoomRoleReader(); private readonly Localization localization = new Localization(); private readonly CursorLease cursor = new CursorLease(); private readonly Theme theme = new Theme(); private readonly Toast toast = new Toast(); private readonly Tooltip tooltip = new Tooltip(); private readonly SpecialItemFilter specialFilter = new SpecialItemFilter(); private readonly List<ItemCatalogEntry> catalog = new List<ItemCatalogEntry>(); private readonly List<ItemCatalogEntry> visibleItems = new List<ItemCatalogEntry>(); private Rect windowRect; private float uiScale = 1f; private int screenWidth; private int screenHeight; private bool open; private bool catalogLoaded; private bool languageUnavailable; private int activeTab = 1; private int categoryIndex; private int kindIndex; private string itemQuery = string.Empty; private Vector2 itemScroll = Vector2.zero; private string lastGameLanguage; private string lastPreference; public bool IsOpen => open; public MainWindow(ToolkitConfig config, PeakApi api, SelfTools selfTools, DroppedItemHistory history, Action<string> log) { //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) playerPanel = new PlayerPanel(history, log); this.config = config; this.api = api; this.selfTools = selfTools; lastPreference = config.Language.Value; localization.Update(lastPreference, null); } public void Open() { if (!open && api.CanOpenWindow) { specialFilter.Reset(); specialFilter.SetCategory(Categories[categoryIndex]); open = true; CenterOnScreen(); InvalidateItemCatalog(); cursor.Acquire(); toast.Clear(); tooltip.Clear(); } } public void Close() { if (open) { open = false; specialFilter.Reset(); cursor.Release(api.GameWantsCursor()); toast.Clear(); tooltip.Clear(); } } public void InvalidateItemCatalog() { tooltip.Clear(); catalogLoaded = false; catalog.Clear(); visibleItems.Clear(); } public void RefreshLanguage(string gameLanguage) { bool flag = !string.Equals(gameLanguage, lastGameLanguage, StringComparison.Ordinal); languageUnavailable = string.IsNullOrEmpty(gameLanguage) && config.Language.Value == "Auto"; if (!(gameLanguage == lastGameLanguage) || !(config.Language.Value == lastPreference)) { lastGameLanguage = gameLanguage; lastPreference = config.Language.Value; localization.Update(lastPreference, gameLanguage); tooltip.Clear(); if (flag && catalogLoaded) { RefreshItemCatalog(); } } } public void Draw() { //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) if (!open) { return; } if (screenWidth != Screen.width || screenHeight != Screen.height) { CenterOnScreen(); } theme.Ensure(); Matrix4x4 matrix = GUI.matrix; try { GUI.matrix = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(uiScale, uiScale, 1f)); windowRect = GUI.Window(5259604, windowRect, new WindowFunction(DrawContents), string.Empty, theme.Window); windowRect = WindowBounds.Clamp(windowRect, (float)screenWidth / uiScale, (float)screenHeight / uiScale); } finally { GUI.matrix = matrix; } } private void DrawContents(int id) { //IL_02e3: Unknown result type (might be due to invalid IL or missing references) //IL_02f2: Unknown result type (might be due to invalid IL or missing references) //IL_02f8: Invalid comparison between Unknown and I4 //IL_0366: Unknown result type (might be due to invalid IL or missing references) //IL_0372: Expected O, but got Unknown //IL_0379: Unknown result type (might be due to invalid IL or missing references) //IL_0398: Unknown result type (might be due to invalid IL or missing references) GUILayout.BeginVertical((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandHeight(true) }); GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(42f) }); GUILayout.Label(localization.Text("Heading"), theme.Heading, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label(localization.Text("Foundation"), theme.Small, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(150f) }); GUILayout.FlexibleSpace(); int num = GUILayout.SelectionGrid(activeTab, new string[5] { localization.Text("Overview"), localization.Text("Items"), localization.Text("SelfTools"), localization.Text("Players"), localization.Text("World") }, 5, theme.Button, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(640f) }); if (num != activeTab) { activeTab = num; specialFilter.Reset(); InvalidateItemCatalog(); } GUILayout.EndHorizontal(); GUILayout.Space(10f); ItemCatalogEntry itemCatalogEntry = null; if (activeTab == 1) { itemCatalogEntry = DrawItems(); } else if (activeTab == 2) { selfPanel.Draw(selfTools, theme, localization, toast); } else if (activeTab == 3) { playerPanel.Draw(theme, localization, toast); } else if (activeTab == 4) { worldPanel.Draw(theme, localization, toast); } else { DrawOverview(); GUILayout.FlexibleSpace(); } GUILayout.Label(toast.Current(Time.unscaledTimeAsDouble) ?? string.Empty, theme.Small, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(26f) }); GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label(localization.Text("CloseHelp"), theme.Small, (GUILayoutOption[])(object)new GUILayoutOption[0]); if (GUILayout.Button(localization.Text("Close"), theme.Button, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) })) { Close(); } GUILayout.EndHorizontal(); GUILayout.EndVertical(); GUI.DragWindow(new Rect(12f, 12f, ((Rect)(ref windowRect)).width - 680f, 42f)); if ((int)Event.current.type == 7) { string text = null; if (open && itemCatalogEntry != null) { text = ItemTooltip.Format(itemCatalogEntry, localization); } string text2 = tooltip.Observe((text == null) ? null : itemCatalogEntry.SpawnName, text, Time.unscaledTimeAsDouble); if (!string.IsNullOrEmpty(text2)) { float num2 = Mathf.Min(380f, ((Rect)(ref windowRect)).width - 24f); float height = theme.Tooltip.CalcHeight(new GUIContent(text2), num2); GUI.Box(Tooltip.Bounds(Event.current.mousePosition, num2, height, ((Rect)(ref windowRect)).width, ((Rect)(ref windowRect)).height), text2, theme.Tooltip); } } } private void DrawOverview() { //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Expected O, but got Unknown //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Expected O, but got Unknown //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Expected O, but got Unknown //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Expected O, but got Unknown GUILayout.Label(localization.Text("Scope"), theme.Body, (GUILayoutOption[])(object)new GUILayoutOption[0]); string key = roomRole.Read() switch { RoomRole.OutsideRoom => "RoomRoleOutside", RoomRole.Client => "RoomRoleClient", RoomRole.Host => "RoomRoleHost", _ => "RoomRoleUnavailable", }; GUILayout.Label(localization.Format("RoomRoleLabel", localization.Text(key)), theme.Body, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Space(16f); GUILayout.Label(localization.Text("Language"), theme.Body, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUIContent[] array = (GUIContent[])(object)new GUIContent[4] { new GUIContent(localization.Text("Auto")), new GUIContent(localization.Text("English")), new GUIContent(localization.Text("SimplifiedChinese")), new GUIContent(localization.Text("TraditionalChinese")) }; int num = ((config.Language.Value == "en") ? 1 : ((config.Language.Value == "zh-CN") ? 2 : ((config.Language.Value == "zh-TW") ? 3 : 0))); int num2 = GUILayout.SelectionGrid(num, array, 4, theme.Button, (GUILayoutOption[])(object)new GUILayoutOption[0]); if (num2 != num) { config.Language.Value = num2 switch { 3 => "zh-TW", 2 => "zh-CN", 1 => "en", _ => "Auto", }; RefreshLanguage(lastGameLanguage); toast.Show(localization.Text("Saved"), Time.unscaledTimeAsDouble, 2.0); } GUILayout.Label(localization.Text("AutoHelp"), theme.Small, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label(localization.Format("ActiveLanguage", LanguageName()), theme.Small, (GUILayoutOption[])(object)new GUILayoutOption[0]); if (languageUnavailable) { GUILayout.Label(localization.Text("LanguageUnavailable"), theme.Small, (GUILayoutOption[])(object)new GUILayoutOption[0]); } } private ItemCatalogEntry DrawItems() { //IL_040c: Unknown result type (might be due to invalid IL or missing references) //IL_0411: Unknown result type (might be due to invalid IL or missing references) //IL_0435: Unknown result type (might be due to invalid IL or missing references) //IL_0438: Unknown result type (might be due to invalid IL or missing references) //IL_0455: Unknown result type (might be due to invalid IL or missing references) //IL_045c: Unknown result type (might be due to invalid IL or missing references) //IL_0461: Unknown result type (might be due to invalid IL or missing references) //IL_0463: Unknown result type (might be due to invalid IL or missing references) //IL_0466: Unknown result type (might be due to invalid IL or missing references) //IL_047e: Unknown result type (might be due to invalid IL or missing references) //IL_0480: Unknown result type (might be due to invalid IL or missing references) //IL_04a3: Unknown result type (might be due to invalid IL or missing references) //IL_04f7: Unknown result type (might be due to invalid IL or missing references) //IL_04fc: Unknown result type (might be due to invalid IL or missing references) //IL_06c6: Unknown result type (might be due to invalid IL or missing references) //IL_06cc: Invalid comparison between Unknown and I4 //IL_06d1: Unknown result type (might be due to invalid IL or missing references) //IL_06d4: Unknown result type (might be due to invalid IL or missing references) //IL_06de: Unknown result type (might be due to invalid IL or missing references) //IL_0530: Unknown result type (might be due to invalid IL or missing references) //IL_05bc: Unknown result type (might be due to invalid IL or missing references) //IL_05fb: Unknown result type (might be due to invalid IL or missing references) //IL_05ff: Unknown result type (might be due to invalid IL or missing references) //IL_0604: Unknown result type (might be due to invalid IL or missing references) //IL_0606: Unknown result type (might be due to invalid IL or missing references) //IL_060f: Unknown result type (might be due to invalid IL or missing references) //IL_0614: Unknown result type (might be due to invalid IL or missing references) //IL_0625: Unknown result type (might be due to invalid IL or missing references) //IL_0683: Unknown result type (might be due to invalid IL or missing references) //IL_0643: Unknown result type (might be due to invalid IL or missing references) if (!catalogLoaded) { RefreshItemCatalog(); } GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label(localization.Text("SearchItems"), theme.Body, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(180f) }); string text = GUILayout.TextField(itemQuery, theme.TextField, (GUILayoutOption[])(object)new GUILayoutOption[0]); if (text != itemQuery) { itemQuery = text; ApplyFilter(); } if (GUILayout.Button(localization.Text("RefreshItems"), theme.Button, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) })) { RefreshItemCatalog(); } GUILayout.EndHorizontal(); GUILayout.Space(6f); string[] array = new strin