using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.Json;
using HarmonyLib;
using Il2CppTMPro;
using MelonLoader;
using MelonLoader.Preferences;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(PickupTabOverlay), "Pickup Tab Overlay", "0.1.27", "kp0hyc", null)]
[assembly: MelonGame("Valko Game Studios", "Labyrinthine")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("PickupTabOverlay")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("PickupTabOverlay")]
[assembly: AssemblyTitle("PickupTabOverlay")]
[assembly: AssemblyVersion("1.0.0.0")]
public class PickupTabOverlay : MelonMod
{
private readonly struct TmpOverlayModel
{
public readonly string Text;
public readonly float Width;
public readonly float Height;
public readonly int StyleKey;
public TmpOverlayModel(string text, float width, float height, int styleKey)
{
Text = text;
Width = width;
Height = height;
StyleKey = styleKey;
}
}
private readonly struct ObjectiveTextStyle
{
public static readonly ObjectiveTextStyle Fallback = new ObjectiveTextStyle(hasLiveStyle: false, "fallback", 30, 28, 24, null, null, null, null, null);
public readonly bool HasLiveStyle;
public readonly string Source;
public readonly int HeaderFontSize;
public readonly int RowFontSize;
public readonly int FooterFontSize;
public readonly object Color;
public readonly object MutedColor;
public readonly object Font;
public readonly object FontSharedMaterial;
public readonly object SourceText;
public int StyleKey => (((((((HeaderFontSize * 397) ^ RowFontSize) * 397) ^ FooterFontSize) * 397) ^ ((Font != null) ? RuntimeHelpers.GetHashCode(Font) : 0)) * 397) ^ ((FontSharedMaterial != null) ? RuntimeHelpers.GetHashCode(FontSharedMaterial) : 0);
public ObjectiveTextStyle(bool hasLiveStyle, string source, int headerFontSize, int rowFontSize, int footerFontSize, object color, object mutedColor, object font, object fontSharedMaterial, object sourceText)
{
HasLiveStyle = hasLiveStyle;
Source = source;
HeaderFontSize = headerFontSize;
RowFontSize = rowFontSize;
FooterFontSize = footerFontSize;
Color = color;
MutedColor = mutedColor;
Font = font;
FontSharedMaterial = fontSharedMaterial;
SourceText = sourceText;
}
public static ObjectiveTextStyle FromConfig(int headerFontSize, int rowFontSize, int footerFontSize, object color)
{
return new ObjectiveTextStyle(hasLiveStyle: false, "config", headerFontSize, rowFontSize, footerFontSize, color, CopyColorWithAlpha(color, 0.82f), null, null, null);
}
}
private readonly struct PickupEntry
{
public readonly int Id;
public readonly string Name;
public readonly int Count;
public readonly bool LeftHand;
public readonly bool RightHand;
public PickupEntry(int id, string name, int count, bool leftHand, bool rightHand)
{
Id = id;
Name = name;
Count = count;
LeftHand = leftHand;
RightHand = rightHand;
}
}
private readonly struct CollectibleEntry
{
public readonly string Label;
public readonly int Amount;
public CollectibleEntry(string label, int amount)
{
Label = label;
Amount = amount;
}
}
private readonly struct UnlockEntry
{
public readonly string Category;
public readonly string Name;
public readonly int Id;
public readonly string ItemClass;
public readonly int Count;
public UnlockEntry(string category, string name, int id, string itemClass, int count)
{
Category = category;
Name = name;
Id = id;
ItemClass = itemClass;
Count = count;
}
public UnlockEntry WithCount(int count)
{
return new UnlockEntry(Category, Name, Id, ItemClass, count);
}
}
private readonly struct ShandadaItemInfo
{
public readonly string Name;
public readonly string ItemClass;
public ShandadaItemInfo(string name, string itemClass)
{
Name = name;
ItemClass = itemClass;
}
}
private const string HarmonyId = "kp0hyc.pickuptaboverlay";
private const string PrefCategoryName = "PickupTabOverlay";
private const int MinimumReadableRowFontSize = 18;
private const int MinimumReadableFooterFontSize = 16;
private static readonly List<PickupEntry> s_entries = new List<PickupEntry>();
private static readonly Dictionary<string, int> s_collectiblesFound = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
private static readonly HashSet<int> s_countedCollectibles = new HashSet<int>();
private static readonly List<UnlockEntry> s_unlockEntries = new List<UnlockEntry>();
private static readonly Dictionary<string, int> s_unlockEntryIndexes = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
private static readonly HashSet<int> s_countedUnlockPickups = new HashSet<int>();
private static readonly HashSet<int> s_undiscoveredCosmeticItemIds = new HashSet<int>();
private static readonly Dictionary<int, string> s_customizationNameCache = new Dictionary<int, string>();
private static readonly Dictionary<int, string> s_customizationClassCache = new Dictionary<int, string>();
private static readonly Dictionary<int, ShandadaItemInfo> s_shandadaItems = new Dictionary<int, ShandadaItemInfo>();
private static MelonPreferences_Entry<bool> s_enabled;
private static MelonPreferences_Entry<int> s_panelWidth;
private static MelonPreferences_Entry<bool> s_showIds;
private static MelonPreferences_Entry<bool> s_showHandLabels;
private static MelonPreferences_Entry<bool> s_showEmptyMessage;
private static MelonPreferences_Entry<bool> s_showCollectibles;
private static MelonPreferences_Entry<bool> s_showUnlockPickups;
private static MelonPreferences_Entry<bool> s_debugLogging;
private static MelonPreferences_Entry<bool> s_legacyDebugLogging;
private static MelonPreferences_Entry<bool> s_useTextMeshProOverlay;
private static MelonPreferences_Entry<bool> s_useObjectiveTextStyle;
private static MelonPreferences_Entry<int> s_objectiveTextScalePercent;
private static MelonPreferences_Entry<int> s_headerFontSize;
private static MelonPreferences_Entry<int> s_rowFontSize;
private static MelonPreferences_Entry<int> s_footerFontSize;
private static MelonPreferences_Entry<int> s_maxVisibleItems;
private static DateTime s_nextRefreshUtc = DateTime.MinValue;
private static DateTime s_nextWarningUtc = DateTime.MinValue;
private static DateTime s_nextObjectiveStyleRefreshUtc = DateTime.MinValue;
private static DateTime s_nextTmpOverlayRetryUtc = DateTime.MinValue;
private static DateTime s_nextTmpDiagnosticsUtc = DateTime.MinValue;
private static ObjectiveTextStyle s_objectiveTextStyle = ObjectiveTextStyle.Fallback;
private static string s_lastLoggedObjectiveStyleSignature;
private static string s_lastLoggedRendererSignature;
private static string s_lastLoggedTmpSourceSignature;
private static string s_lastLoggedTmpDiagnosticsSignature;
private static string s_lastLoggedTmpLayoutSignature;
private static string s_lastLoggedDirectTmpFailure;
private static bool s_tmpOverlayReady;
private static bool s_tmpOverlayFailed;
private static bool s_tmpOverlayVisible;
private static bool s_loggedTmpOverlayReady;
private static bool s_tmpOverlayUsesDirectUi;
private static bool s_shandadaItemsLoaded;
private static string s_tmpLastText;
private static int s_tmpLastStyleKey;
private static float s_tmpLastWidth;
private static float s_tmpLastHeight;
private static Type s_rectType;
private static Type s_colorType;
private static Type s_vector2Type;
private static Type s_guiType;
private static Type s_screenType;
private static Type s_inputType;
private static Type s_keyCodeType;
private static Type s_labyrinthineInputManagerType;
private static Type s_inputButtonType;
private static Type s_playerNetworkSyncType;
private static Type s_gameManagerType;
private static Type s_objectType;
private static Type s_rndPlayerInventoryType;
private static Type s_rndCollectibleType;
private static Type s_customizationPickupType;
private static Type s_customCaseItemUnlockType;
private static Type s_customizationManagerType;
private static Type s_localisationManagerType;
private static Type s_objectiveUiType;
private static Type s_tmpTextType;
private static Type s_tmpFontAssetType;
private static Type s_canvasType;
private static Type s_componentType;
private static Type s_gameObjectType;
private static Type s_transformType;
private static Type s_rectTransformType;
private static Type s_resourcesType;
private static Type s_textMeshProUguiType;
private static Type s_renderModeType;
private static Type s_textAlignmentOptionsType;
private static Type s_textOverflowModesType;
private static ConstructorInfo s_rectCtor;
private static ConstructorInfo s_colorCtor;
private static ConstructorInfo s_vector2Ctor;
private static ConstructorInfo s_gameObjectCtor;
private static ConstructorInfo s_gameObjectWithComponentsCtor;
private static MethodInfo s_guiLabel;
private static MethodInfo s_inputGetKey;
private static MethodInfo s_gameGetButton;
private static MethodInfo s_findObjectsOfTypeMethod;
private static MethodInfo s_componentGetComponentInParentMethod;
private static MethodInfo s_gameObjectGetComponentMethod;
private static MethodInfo s_gameObjectAddComponentMethod;
private static MethodInfo s_gameObjectSetActiveMethod;
private static MethodInfo s_transformSetParentMethod;
private static MethodInfo s_transformSetAsLastSiblingMethod;
private static MethodInfo s_objectInstantiateMethod;
private static MethodInfo s_objectDestroyMethod;
private static MethodInfo s_objectDontDestroyOnLoadMethod;
private static MethodInfo s_resourcesFindObjectsOfTypeAllMethod;
private static PropertyInfo s_guiColorProperty;
private static PropertyInfo s_screenWidthProperty;
private static PropertyInfo s_screenHeightProperty;
private static PropertyInfo s_guiSkinProperty;
private static PropertyInfo s_guiSkinLabelProperty;
private static PropertyInfo s_styleFontSizeProperty;
private static PropertyInfo s_styleNormalProperty;
private static PropertyInfo s_styleStateTextColorProperty;
private static object s_keyCodeTab;
private static object s_showTabMenuButton;
private static object s_tmpOverlayRoot;
private static object s_tmpOverlayTextObject;
private static object s_tmpOverlayText;
private static object s_tmpOverlayRectTransform;
private static object s_larkeSansFont;
private static bool s_reflectionReady;
public override void OnInitializeMelon()
{
MelonPreferences_Category obj = MelonPreferences.CreateCategory("PickupTabOverlay");
s_enabled = obj.CreateEntry<bool>("Enabled", true, "Show local pickup inventory while the tab menu is open.", (string)null, false, false, (ValueValidator)null, (string)null);
s_panelWidth = obj.CreateEntry<int>("PanelWidth", 320, "Pickup panel width in pixels.", (string)null, false, false, (ValueValidator)null, (string)null);
s_showIds = obj.CreateEntry<bool>("ShowItemIDs", true, "Show random-case item IDs next to pickup names.", (string)null, false, false, (ValueValidator)null, (string)null);
s_showHandLabels = obj.CreateEntry<bool>("ShowHandLabels", true, "Mark currently selected left/right hand pickup items.", (string)null, false, false, (ValueValidator)null, (string)null);
s_showEmptyMessage = obj.CreateEntry<bool>("ShowEmptyMessage", true, "Show a small message when no pickups are held.", (string)null, false, false, (ValueValidator)null, (string)null);
s_showCollectibles = obj.CreateEntry<bool>("ShowCollectibles", true, "Show random-case collectibles picked up during the current run.", (string)null, false, false, (ValueValidator)null, (string)null);
s_showUnlockPickups = obj.CreateEntry<bool>("ShowUnlockPickups", true, "Show cosmetic, blueprint, and stamp pickups during the current run.", (string)null, false, false, (ValueValidator)null, (string)null);
s_legacyDebugLogging = obj.CreateEntry<bool>("DebugLogging", false, "Legacy pickup overlay diagnostics flag.", (string)null, false, false, (ValueValidator)null, (string)null);
s_debugLogging = obj.CreateEntry<bool>("VerboseLogs", false, "Log pickup overlay diagnostics for troubleshooting.", (string)null, false, false, (ValueValidator)null, (string)null);
s_useTextMeshProOverlay = obj.CreateEntry<bool>("UseTextMeshProOverlay", true, "Draw the pickup panel using TextMeshPro instead of IMGUI.", (string)null, false, false, (ValueValidator)null, (string)null);
s_useObjectiveTextStyle = obj.CreateEntry<bool>("UseObjectiveTextStyle", true, "Use the game's live objective text size and color when available.", (string)null, false, false, (ValueValidator)null, (string)null);
s_objectiveTextScalePercent = obj.CreateEntry<int>("ObjectiveTextScalePercent", 100, "Multiplier for objective-derived pickup overlay text size.", (string)null, false, false, (ValueValidator)null, (string)null);
s_headerFontSize = obj.CreateEntry<int>("HeaderFontSize", 30, "Pickup panel header font size.", (string)null, false, false, (ValueValidator)null, (string)null);
s_rowFontSize = obj.CreateEntry<int>("RowFontSize", 28, "Pickup panel row font size.", (string)null, false, false, (ValueValidator)null, (string)null);
s_footerFontSize = obj.CreateEntry<int>("FooterFontSize", 24, "Pickup panel footer font size.", (string)null, false, false, (ValueValidator)null, (string)null);
s_maxVisibleItems = obj.CreateEntry<int>("MaxVisibleItems", 12, "Maximum pickup rows to show before collapsing the rest.", (string)null, false, false, (ValueValidator)null, (string)null);
TryPatchCollectiblePickup();
TryPatchCustomizationPickup();
TryPatchCustomCaseItemUnlock();
LogDebug("PickupTabOverlay initialized.");
}
public override void OnSceneWasLoaded(int buildIndex, string sceneName)
{
DestroyTmpOverlay();
s_entries.Clear();
s_collectiblesFound.Clear();
s_countedCollectibles.Clear();
s_unlockEntries.Clear();
s_unlockEntryIndexes.Clear();
s_countedUnlockPickups.Clear();
s_undiscoveredCosmeticItemIds.Clear();
s_nextRefreshUtc = DateTime.MinValue;
s_nextObjectiveStyleRefreshUtc = DateTime.MinValue;
s_objectiveTextStyle = ObjectiveTextStyle.Fallback;
s_lastLoggedObjectiveStyleSignature = null;
s_lastLoggedRendererSignature = null;
s_lastLoggedTmpSourceSignature = null;
s_lastLoggedTmpDiagnosticsSignature = null;
s_lastLoggedTmpLayoutSignature = null;
s_lastLoggedDirectTmpFailure = null;
s_nextTmpDiagnosticsUtc = DateTime.MinValue;
}
private static void TryPatchCollectiblePickup()
{
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_005d: Expected O, but got Unknown
try
{
MethodInfo methodInfo = GetRndCollectibleType()?.GetMethod("Pickup", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (methodInfo == null)
{
MelonLogger.Warning("Could not find RndCollectible.Pickup; random collectibles will not be tracked.");
return;
}
new Harmony("kp0hyc.pickuptaboverlay").Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(PickupTabOverlay).GetMethod("RndCollectiblePickupPrefix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
LogDebug("Patched RndCollectible.Pickup for collectible tracking.");
}
catch (Exception ex)
{
MelonLogger.Warning("Could not patch RndCollectible.Pickup: " + ex.GetType().Name + " " + ex.Message);
}
}
private static void TryPatchCustomizationPickup()
{
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_005d: Expected O, but got Unknown
try
{
MethodInfo methodInfo = GetCustomizationPickupType()?.GetMethod("Pickup", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (methodInfo == null)
{
MelonLogger.Warning("Could not find CustomizationPickup.Pickup; cosmetic pickups will not be tracked.");
return;
}
new Harmony("kp0hyc.pickuptaboverlay").Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(PickupTabOverlay).GetMethod("CustomizationPickupPrefix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
LogDebug("Patched CustomizationPickup.Pickup for cosmetic tracking.");
}
catch (Exception ex)
{
MelonLogger.Warning("Could not patch CustomizationPickup.Pickup: " + ex.GetType().Name + " " + ex.Message);
}
}
private static void TryPatchCustomCaseItemUnlock()
{
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_005d: Expected O, but got Unknown
try
{
MethodInfo methodInfo = GetCustomCaseItemUnlockType()?.GetMethod("Pickup", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (methodInfo == null)
{
MelonLogger.Warning("Could not find CustomCaseItemUnlock.Pickup; blueprint/stamp pickups will not be tracked.");
return;
}
new Harmony("kp0hyc.pickuptaboverlay").Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(PickupTabOverlay).GetMethod("CustomCaseItemUnlockPrefix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
LogDebug("Patched CustomCaseItemUnlock.Pickup for blueprint/stamp tracking.");
}
catch (Exception ex)
{
MelonLogger.Warning("Could not patch CustomCaseItemUnlock.Pickup: " + ex.GetType().Name + " " + ex.Message);
}
}
private static void RndCollectiblePickupPrefix(object __instance)
{
try
{
if (__instance == null)
{
return;
}
int hashCode = RuntimeHelpers.GetHashCode(__instance);
if (!s_countedCollectibles.Contains(hashCode) && TryClassifyCollectible(__instance, out var label, out var amount))
{
s_countedCollectibles.Add(hashCode);
if (!s_collectiblesFound.TryGetValue(label, out var value))
{
value = 0;
}
s_collectiblesFound[label] = value + amount;
}
}
catch (Exception ex)
{
LogWarning("collectible pickup tracking failed: " + ex.GetType().Name + " " + ex.Message);
}
}
private static void CustomizationPickupPrefix(object __instance)
{
try
{
if (__instance == null)
{
return;
}
int hashCode = RuntimeHelpers.GetHashCode(__instance);
if (!s_countedUnlockPickups.Contains(hashCode) && TryConvertInt(GetFieldOrProp(__instance, "ItemID") ?? GetFieldOrProp(__instance, "itemID"), out var result))
{
s_countedUnlockPickups.Add(hashCode);
bool flag = IsCustomizationItemAlreadyUnlocked(result);
if (!flag)
{
s_undiscoveredCosmeticItemIds.Add(result);
}
string text = (s_undiscoveredCosmeticItemIds.Contains(result) ? "Undiscovered item" : ResolveCustomizationName(result));
if (string.IsNullOrWhiteSpace(text))
{
text = CleanPickupObjectName(__instance, "Cosmetic");
}
string text2 = ResolveCustomizationClass(result);
AddUnlockEntry("Cosmetic", text, result, text2);
LogDebug("Cosmetic pickup itemID=" + result + " alreadyUnlocked=" + flag + " class=" + (text2 ?? "{unknown}") + " name=" + text);
}
}
catch (Exception ex)
{
LogWarning("cosmetic pickup tracking failed: " + ex.GetType().Name + " " + ex.Message);
}
}
private static void CustomCaseItemUnlockPrefix(object __instance)
{
try
{
if (__instance == null)
{
return;
}
int hashCode = RuntimeHelpers.GetHashCode(__instance);
if (!s_countedUnlockPickups.Contains(hashCode))
{
bool flag = false;
bool flag2 = false;
if (TryConvertBool(GetFieldOrProp(__instance, "unlockMazeType"), out var result) && result)
{
object fieldOrProp = GetFieldOrProp(__instance, "mazeType");
AddUnlockEntry("Map Blueprint", "Picked up", -1);
LogDebug("Map blueprint pickup mazeType=" + FormatEnumValue(fieldOrProp, "Map"));
flag = true;
flag2 = true;
}
if (TryConvertBool(GetFieldOrProp(__instance, "unlockMonsterType"), out var result2) && result2)
{
object fieldOrProp2 = GetFieldOrProp(__instance, "monsterType");
LogDebug("Unexpected monster blueprint pickup monsterType=" + FormatEnumValue(fieldOrProp2, "Monster"));
flag = true;
}
if (TryConvertBool(GetFieldOrProp(__instance, "unlockContractType"), out var result3) && result3)
{
object fieldOrProp3 = GetFieldOrProp(__instance, "contractType");
AddUnlockEntry("Stamps", "Collected", -1);
LogDebug("Stamp pickup contractType=" + FormatEnumValue(fieldOrProp3, "Contract"));
flag = true;
flag2 = true;
}
if (!flag)
{
AddUnlockEntry("Blueprint", CleanPickupObjectName(__instance, "Custom Case Unlock"), -1);
flag2 = true;
LogDebug("Unknown custom-case unlock pickup name=" + CleanPickupObjectName(__instance, "Custom Case Unlock"));
}
else if (!flag2)
{
LogDebug("Custom-case unlock pickup had no visible overlay row.");
}
s_countedUnlockPickups.Add(hashCode);
}
}
catch (Exception ex)
{
LogWarning("blueprint/stamp pickup tracking failed: " + ex.GetType().Name + " " + ex.Message);
}
}
private static bool TryClassifyCollectible(object collectible, out string label, out int amount)
{
label = null;
if (!TryConvertInt(GetFieldOrProp(collectible, "amount"), out amount) || amount <= 0)
{
amount = 1;
}
object fieldOrProp = GetFieldOrProp(collectible, "collectibleType");
string text = ((fieldOrProp == null) ? string.Empty : fieldOrProp.ToString());
string collectibleObjectName = GetCollectibleObjectName(collectible);
string text2 = (text + " " + collectibleObjectName + " " + (GetFieldOrProp(collectible, "pickupMessage") ?? string.Empty)).ToLowerInvariant();
if (text2.Contains("ticket"))
{
label = "Tickets";
return true;
}
if (text.IndexOf("Reroll", StringComparison.OrdinalIgnoreCase) >= 0 || text2.Contains("reroll"))
{
label = "Reroll Coins";
return true;
}
return false;
}
private static string GetCollectibleObjectName(object collectible)
{
string text = GetFieldOrProp(GetFieldOrProp(collectible, "gameObject") ?? collectible, "name") as string;
if (!string.IsNullOrWhiteSpace(text))
{
return text;
}
return string.Empty;
}
private static void AddUnlockEntry(string category, string name, int id, string itemClass = null)
{
if (string.IsNullOrWhiteSpace(category))
{
category = "Unlock";
}
if (string.IsNullOrWhiteSpace(name))
{
name = "Unknown";
}
name = CleanUnityName(name);
itemClass = FormatItemClass(itemClass);
string key = category + "|" + id + "|" + itemClass + "|" + name;
if (s_unlockEntryIndexes.TryGetValue(key, out var value) && value >= 0 && value < s_unlockEntries.Count)
{
s_unlockEntries[value] = s_unlockEntries[value].WithCount(s_unlockEntries[value].Count + 1);
return;
}
s_unlockEntryIndexes[key] = s_unlockEntries.Count;
s_unlockEntries.Add(new UnlockEntry(category, name, id, itemClass, 1));
}
private static string ResolveCustomizationName(int itemId)
{
if (s_customizationNameCache.TryGetValue(itemId, out var value))
{
return value;
}
string text = null;
if (TryGetShandadaItemInfo(itemId, out var info) && !string.IsNullOrWhiteSpace(info.Name))
{
text = info.Name;
}
object obj = TryGetCustomizationItem(itemId);
if (obj != null && string.IsNullOrWhiteSpace(text))
{
text = GetFieldOrProp(obj, "Name") as string;
if (string.IsNullOrWhiteSpace(text))
{
text = GetLocalisation(GetFieldOrProp(obj, "LocalisationKey") as string, null);
}
}
if (!string.IsNullOrWhiteSpace(text))
{
s_customizationNameCache[itemId] = text;
return text;
}
return null;
}
private static object TryGetCustomizationItem(int itemId)
{
try
{
object customizationCollection = GetCustomizationCollection();
if (customizationCollection == null || itemId < 0 || itemId > 65535)
{
return null;
}
MethodInfo methodInfo = customizationCollection.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "TryGetItem" && m.GetParameters().Length == 2);
if (methodInfo == null)
{
return null;
}
object[] array = new object[2]
{
(ushort)itemId,
null
};
if (TryConvertBool(methodInfo.Invoke(customizationCollection, array), out var result) && result)
{
return array[1];
}
}
catch
{
}
return null;
}
private static string ResolveCustomizationClass(int itemId)
{
if (s_customizationClassCache.TryGetValue(itemId, out var value))
{
return value;
}
string text = null;
if (TryGetShandadaItemInfo(itemId, out var info))
{
text = info.ItemClass;
}
if (string.IsNullOrWhiteSpace(text))
{
object obj = TryGetCustomizationItem(itemId);
text = (GetFieldOrProp(obj, "ItemRarity") ?? GetFieldOrProp(obj, "itemRarity"))?.ToString();
}
text = FormatItemClass(text);
if (!string.IsNullOrWhiteSpace(text))
{
s_customizationClassCache[itemId] = text;
}
return text;
}
private static bool TryGetShandadaItemInfo(int itemId, out ShandadaItemInfo info)
{
EnsureShandadaItemsLoaded();
return s_shandadaItems.TryGetValue(itemId, out info);
}
private static void EnsureShandadaItemsLoaded()
{
if (s_shandadaItemsLoaded)
{
return;
}
s_shandadaItemsLoaded = true;
try
{
Assembly assembly = typeof(PickupTabOverlay).Assembly;
string text = assembly.GetManifestResourceNames().FirstOrDefault((string name) => name.EndsWith("shandada_game_item_id_map.json", StringComparison.OrdinalIgnoreCase));
if (string.IsNullOrWhiteSpace(text))
{
LogDebug("Embedded Shandadapanda item map was not found.");
return;
}
using Stream stream = assembly.GetManifestResourceStream(text);
if (stream == null)
{
return;
}
using JsonDocument jsonDocument = JsonDocument.Parse(stream);
if (!jsonDocument.RootElement.TryGetProperty("gameToWebsite", out var value) || value.ValueKind != JsonValueKind.Array)
{
return;
}
foreach (JsonElement item in value.EnumerateArray())
{
if (TryGetJsonInt(item, "gameItemId", out var value2) && value2 >= 0)
{
string jsonString = GetJsonString(item, "websiteName");
string text2 = GetJsonString(item, "class") ?? GetJsonString(item, "websiteMapClass") ?? GetJsonString(item, "websiteEvent");
if (!string.IsNullOrWhiteSpace(jsonString) || !string.IsNullOrWhiteSpace(text2))
{
s_shandadaItems[value2] = new ShandadaItemInfo(jsonString, text2);
}
}
}
LogDebug("Loaded " + s_shandadaItems.Count + " Shandadapanda item names.");
}
catch (Exception ex)
{
LogWarning("Shandadapanda item map load failed: " + ex.GetType().Name + " " + ex.Message);
}
}
private static bool TryGetJsonInt(JsonElement element, string name, out int value)
{
value = 0;
if (!element.TryGetProperty(name, out var value2))
{
return false;
}
if (value2.ValueKind == JsonValueKind.Number)
{
return value2.TryGetInt32(out value);
}
if (value2.ValueKind == JsonValueKind.String)
{
return int.TryParse(value2.GetString(), out value);
}
return false;
}
private static string GetJsonString(JsonElement element, string name)
{
if (!element.TryGetProperty(name, out var value) || value.ValueKind != JsonValueKind.String)
{
return null;
}
return value.GetString();
}
private static string FormatItemClass(string itemClass)
{
if (string.IsNullOrWhiteSpace(itemClass))
{
return null;
}
itemClass = itemClass.Trim();
int num = itemClass.LastIndexOf('.');
if (num >= 0 && num + 1 < itemClass.Length)
{
itemClass = itemClass.Substring(num + 1);
}
itemClass = CleanUnityName(itemClass).Trim();
if (!string.IsNullOrWhiteSpace(itemClass))
{
return itemClass.ToLowerInvariant();
}
return null;
}
private static object GetCustomizationCollection()
{
object customizationManager = GetCustomizationManager();
return GetFieldOrProp(customizationManager, "Collection") ?? GetFieldOrProp(customizationManager, "collection");
}
private static object GetCustomizationManager()
{
Type customizationManagerType = GetCustomizationManagerType();
return GetStaticFieldOrProp(customizationManagerType, "Instance") ?? FindFirstObjectOfType(customizationManagerType);
}
private static bool IsCustomizationItemAlreadyUnlocked(int itemId)
{
if (itemId < 0 || itemId > 65535)
{
return false;
}
if (TryIsCustomizationItemUnlocked(GetCurrentCustomizationSave(), itemId, out var unlocked))
{
return unlocked;
}
if (TryUnlockedItemsListContains(GetFieldOrProp(GetCustomizationManager(), "UnlockedItems"), itemId, out unlocked))
{
return unlocked;
}
LogDebug("Could not determine cosmetic unlock state for itemID=" + itemId + "; hiding name.");
return false;
}
private static bool TryIsCustomizationItemUnlocked(object customizationSave, int itemId, out bool unlocked)
{
unlocked = false;
if (customizationSave == null || itemId < 0 || itemId > 65535)
{
return false;
}
try
{
return TryConvertBool(customizationSave.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "IsItemUnlocked" && m.GetParameters().Length == 1)?.Invoke(customizationSave, new object[1] { (ushort)itemId }), out unlocked);
}
catch
{
unlocked = false;
return false;
}
}
private static bool TryUnlockedItemsListContains(object list, int itemId, out bool unlocked)
{
unlocked = false;
if (list == null)
{
return false;
}
foreach (object item in EnumerateItems(list))
{
if (TryConvertInt(item, out var result) && result == itemId)
{
unlocked = true;
return true;
}
}
return true;
}
private static object GetCurrentCustomizationSave()
{
return GetFieldOrProp(GetCustomizationManager(), "CustomizationSave");
}
private static object LoadCustomizationSave()
{
try
{
return (FindType("CharacterCustomization.CustomizationSave")?.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "Load" && m.GetParameters().Length == 0))?.Invoke(null, Array.Empty<object>());
}
catch
{
return null;
}
}
private static string GetLocalisation(string key, string defaultValue)
{
if (string.IsNullOrWhiteSpace(key))
{
return defaultValue;
}
try
{
string text = (GetLocalisationManagerType()?.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "GetLocalisation" && m.GetParameters().Length == 2))?.Invoke(null, new object[2] { key, defaultValue }) as string;
return string.IsNullOrWhiteSpace(text) ? defaultValue : text;
}
catch
{
return defaultValue;
}
}
private static string FormatEnumValue(object value, string fallback)
{
if (value == null)
{
return fallback;
}
string text = value.ToString();
if (string.IsNullOrWhiteSpace(text))
{
return fallback;
}
return CleanUnityName(text);
}
private static string CleanPickupObjectName(object pickup, string fallback)
{
string text = GetFieldOrProp(GetFieldOrProp(pickup, "gameObject") ?? pickup, "name") as string;
if (string.IsNullOrWhiteSpace(text))
{
return fallback;
}
string text2 = CleanUnityName(text);
if (text2.StartsWith("CPickup - ", StringComparison.OrdinalIgnoreCase))
{
text2 = text2.Substring("CPickup - ".Length).Trim();
}
if (!string.IsNullOrWhiteSpace(text2))
{
return text2;
}
return fallback;
}
public override void OnUpdate()
{
if (s_enabled == null || !s_enabled.Value)
{
SetTmpOverlayVisible(visible: false);
return;
}
DateTime utcNow = DateTime.UtcNow;
if (utcNow >= s_nextRefreshUtc)
{
s_nextRefreshUtc = utcNow.AddMilliseconds(250.0);
try
{
RefreshPickupEntries();
}
catch (Exception ex)
{
LogWarning("pickup refresh failed: " + ex.GetType().Name + " " + ex.Message);
}
}
try
{
UpdateTmpOverlay();
}
catch (Exception ex2)
{
ResetTmpOverlayState(failed: false);
LogWarning("TextMeshPro pickup overlay update failed: " + ex2.GetType().Name + " " + ex2.Message);
}
}
public override void OnGUI()
{
if (s_enabled == null || !s_enabled.Value || !EnsureReflection() || !IsTabMenuPressed() || (!HasAnyDisplayedPickup() && (s_showEmptyMessage == null || !s_showEmptyMessage.Value)) || (IsTextMeshProOverlayEnabled() && s_tmpOverlayReady))
{
return;
}
try
{
DrawPickupPanel();
}
catch (Exception ex)
{
LogWarning("pickup overlay draw failed: " + ex.GetType().Name + " " + ex.Message);
}
}
private static void RefreshPickupEntries()
{
s_entries.Clear();
}
private static void DrawPickupPanel()
{
int val = Clamp((s_maxVisibleItems == null) ? 12 : s_maxVisibleItems.Value, 1, 40);
ObjectiveTextStyle textStyle = ResolveTextStyle();
LogOverlayRenderer("IMGUI fallback", GetFallbackRendererReason() + " " + DescribeTextStyleForLog(textStyle));
List<CollectibleEntry> collectibleRows = GetCollectibleRows();
List<UnlockEntry> unlockRows = GetUnlockRows();
float width = ResolveOverlayWidth(unlockRows);
int num = Math.Min(s_entries.Count, val);
float singleRowHeight = GetSingleRowHeight(textStyle.RowFontSize);
float num2 = ((s_entries.Count > num) ? Math.Max(20f, (float)textStyle.FooterFontSize + 8f) : 0f);
float num3 = collectibleRows.Sum((CollectibleEntry row) => EstimateDisplayRowHeight(row.Label + ": " + row.Amount, textStyle.RowFontSize, width));
float num4 = unlockRows.Sum((UnlockEntry row) => EstimateDisplayRowHeight(FormatUnlockEntry(row), textStyle.RowFontSize, width));
float num5 = ((!HasAnyDisplayedPickup()) ? singleRowHeight : 0f);
float num6 = num3 + num4 + (float)num * singleRowHeight + num2 + num5 + 8f;
float num7 = 34f;
float x = Math.Max(12f, (float)ScreenWidth() - width - num7);
float num8 = Math.Max(12f, (float)ScreenHeight() - num6 - num7);
foreach (CollectibleEntry item in collectibleRows)
{
string text = item.Label + ": " + item.Amount;
float num9 = EstimateDisplayRowHeight(text, textStyle.RowFontSize, width);
LabelShadowed(x, num8, width, num9, text, textStyle.RowFontSize, textStyle.Color);
num8 += num9;
}
foreach (UnlockEntry item2 in unlockRows)
{
string text2 = FormatUnlockEntry(item2);
float num10 = EstimateDisplayRowHeight(text2, textStyle.RowFontSize, width);
LabelShadowed(x, num8, width, num10, text2, textStyle.RowFontSize, textStyle.Color);
num8 += num10;
}
if (!HasAnyDisplayedPickup())
{
LabelShadowed(x, num8, width, singleRowHeight, "No pickups", textStyle.RowFontSize, textStyle.MutedColor);
return;
}
for (int num11 = 0; num11 < num; num11++)
{
PickupEntry entry = s_entries[num11];
LabelShadowed(x, num8, width, singleRowHeight, FormatEntry(entry), textStyle.RowFontSize, textStyle.Color);
num8 += singleRowHeight;
}
if (s_entries.Count > num)
{
int num12 = s_entries.Count - num;
LabelShadowed(x, num8, width, num2, "+ " + num12 + " more", textStyle.FooterFontSize, textStyle.MutedColor);
}
}
private static void UpdateTmpOverlay()
{
if (!IsTextMeshProOverlayEnabled())
{
SetTmpOverlayVisible(visible: false);
}
else
{
if (!EnsureReflection())
{
return;
}
if (!IsTabMenuPressed() || (!HasAnyDisplayedPickup() && (s_showEmptyMessage == null || !s_showEmptyMessage.Value)))
{
SetTmpOverlayVisible(visible: false);
return;
}
ObjectiveTextStyle objectiveTextStyle = ResolveTextStyle();
TmpOverlayModel model = BuildTmpOverlayModel(objectiveTextStyle);
if (EnsureTmpOverlay())
{
LogOverlayRenderer(s_tmpOverlayUsesDirectUi ? "TextMeshPro direct UI" : "TextMeshPro cloned UI", DescribeTextStyleForLog(objectiveTextStyle));
ApplyTmpTextStyle(objectiveTextStyle);
ApplyTmpLayout(model.Width, model.Height);
ApplyTmpText(model.Text, model.StyleKey);
LogTmpLayoutDiagnostics(objectiveTextStyle, model);
SetTmpOverlayVisible(visible: true);
}
}
}
private static bool IsTextMeshProOverlayEnabled()
{
if (s_useTextMeshProOverlay != null)
{
return s_useTextMeshProOverlay.Value;
}
return true;
}
private static TmpOverlayModel BuildTmpOverlayModel(ObjectiveTextStyle textStyle)
{
int val = Clamp((s_maxVisibleItems == null) ? 12 : s_maxVisibleItems.Value, 1, 40);
List<CollectibleEntry> collectibleRows = GetCollectibleRows();
List<UnlockEntry> unlockRows = GetUnlockRows();
float width = ResolveOverlayWidth(unlockRows);
int num = Math.Min(s_entries.Count, val);
float singleRowHeight = GetSingleRowHeight(textStyle.RowFontSize);
float num2 = ((s_entries.Count > num) ? Math.Max(20f, (float)textStyle.FooterFontSize + 8f) : 0f);
float num3 = ((!HasAnyDisplayedPickup()) ? singleRowHeight : 0f) + (float)num * singleRowHeight + num2 + 10f;
StringBuilder stringBuilder = new StringBuilder();
foreach (CollectibleEntry item in collectibleRows)
{
string text = item.Label + ": " + item.Amount;
num3 += EstimateDisplayRowHeight(text, textStyle.RowFontSize, width);
AppendTmpLine(stringBuilder, text, textStyle.RowFontSize, muted: false);
}
foreach (UnlockEntry item2 in unlockRows)
{
string text2 = FormatUnlockEntry(item2);
num3 += EstimateDisplayRowHeight(text2, textStyle.RowFontSize, width);
AppendTmpLine(stringBuilder, text2, textStyle.RowFontSize, muted: false);
}
if (!HasAnyDisplayedPickup())
{
AppendTmpLine(stringBuilder, "No pickups", textStyle.RowFontSize, muted: true);
}
else
{
for (int i = 0; i < num; i++)
{
AppendTmpLine(stringBuilder, FormatEntry(s_entries[i]), textStyle.RowFontSize, muted: false);
}
}
if (s_entries.Count > num)
{
AppendTmpLine(stringBuilder, "+ " + (s_entries.Count - num) + " more", textStyle.FooterFontSize, muted: true);
}
return new TmpOverlayModel(stringBuilder.ToString().TrimEnd('\n'), width, num3, textStyle.StyleKey);
}
private static float ResolveOverlayWidth(List<UnlockEntry> unlockRows)
{
int num = Clamp((s_panelWidth == null) ? 320 : s_panelWidth.Value, 220, 900);
int value = (unlockRows.Any((UnlockEntry row) => string.Equals(row.Category, "Cosmetic", StringComparison.OrdinalIgnoreCase)) ? Math.Max(num, 680) : num);
int val = Math.Max(220, ScreenWidth() - 80);
return Clamp(value, 220, Math.Min(900, val));
}
private static float GetSingleRowHeight(int fontSize)
{
return Math.Max(30f, (float)fontSize + 10f);
}
private static float EstimateDisplayRowHeight(string text, int fontSize, float width)
{
int num = EstimateWrappedLineCount(text, fontSize, width);
return Math.Max(GetSingleRowHeight(fontSize), (float)num * ((float)fontSize + 8f) + 4f);
}
private static int EstimateWrappedLineCount(string text, int fontSize, float width)
{
if (string.IsNullOrWhiteSpace(text))
{
return 1;
}
float num = Math.Max(80f, width - 8f);
float num2 = Math.Max(7f, (float)fontSize * 0.54f);
int num3 = Math.Max(8, (int)Math.Floor(num / num2));
int num4 = 1;
int num5 = 0;
string[] array = text.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
foreach (string text2 in array)
{
int num6 = Math.Max(1, text2.Length);
if (num5 == 0)
{
num4 += Math.Max(0, (num6 - 1) / num3);
num5 = num6 % num3;
if (num5 == 0)
{
num5 = num3;
}
continue;
}
if (num5 + 1 + num6 <= num3)
{
num5 += 1 + num6;
continue;
}
num4++;
num4 += Math.Max(0, (num6 - 1) / num3);
num5 = num6 % num3;
if (num5 == 0)
{
num5 = num3;
}
}
return Math.Max(1, num4);
}
private static void AppendTmpLine(StringBuilder builder, string text, int fontSize, bool muted)
{
if (builder.Length > 0)
{
builder.Append('\n');
}
builder.Append(text ?? string.Empty);
}
private static string EscapeTmpRichText(string text)
{
if (string.IsNullOrEmpty(text))
{
return string.Empty;
}
return text.Replace("<", "<").Replace(">", ">");
}
private static bool EnsureTmpOverlay()
{
if (s_tmpOverlayReady && s_tmpOverlayRoot != null && s_tmpOverlayText != null && s_tmpOverlayRectTransform != null)
{
return true;
}
if (s_tmpOverlayFailed && DateTime.UtcNow < s_nextTmpOverlayRetryUtc)
{
return false;
}
try
{
if (TryCreateDirectTmpOverlay(out var failureReason))
{
return true;
}
LogDirectTmpFailure(failureReason);
if (s_gameObjectType == null || s_rectTransformType == null || s_canvasType == null || s_textMeshProUguiType == null || s_textAlignmentOptionsType == null || s_vector2Ctor == null || s_objectInstantiateMethod == null)
{
LogTmpOverlayDiagnostics("required Unity/TMP types or methods are missing");
return MarkTmpOverlayFailed("required Unity/TMP types are not available");
}
if (!TryFindTmpOverlaySource(out var sourceText))
{
LogTmpOverlayDiagnostics("source search found no usable active TMP source");
s_nextTmpOverlayRetryUtc = DateTime.UtcNow.AddMilliseconds(500.0);
return false;
}
string text = DescribeTmpTextSource(sourceText);
if (!string.Equals(s_lastLoggedTmpSourceSignature, text, StringComparison.Ordinal))
{
s_lastLoggedTmpSourceSignature = text;
LogDebug("TextMeshPro pickup overlay source " + text + ".");
}
object fieldOrProp = GetFieldOrProp(sourceText, "gameObject");
object fieldOrProp2 = GetFieldOrProp(GetComponentInParent(sourceText, s_canvasType), "transform");
if (fieldOrProp == null || fieldOrProp2 == null)
{
return MarkTmpOverlayFailed("objective TextMeshPro source has no canvas parent");
}
s_tmpOverlayRoot = CloneGameObject(fieldOrProp, fieldOrProp2);
s_tmpOverlayTextObject = s_tmpOverlayRoot;
s_tmpOverlayText = GetComponent(s_tmpOverlayTextObject, s_textMeshProUguiType);
s_tmpOverlayRectTransform = GetComponent(s_tmpOverlayTextObject, s_rectTransformType);
if (s_tmpOverlayText == null || s_tmpOverlayRectTransform == null)
{
return MarkTmpOverlayFailed("could not clone TextMeshProUGUI component");
}
SetFieldOrProp(s_tmpOverlayRoot, "name", "kp0hyc PickupTabOverlay Text");
object fieldOrProp3 = GetFieldOrProp(s_tmpOverlayTextObject, "transform");
s_transformSetAsLastSiblingMethod?.Invoke(fieldOrProp3, Array.Empty<object>());
SetRectTransformAnchors(s_tmpOverlayRectTransform, 1f, 0f, 1f, 0f, 1f, 0f);
SetFieldOrProp(s_tmpOverlayText, "alignment", Enum.Parse(s_textAlignmentOptionsType, "BottomRight"));
SetFieldOrProp(s_tmpOverlayText, "richText", false);
SetFieldOrProp(s_tmpOverlayText, "enableAutoSizing", false);
SetFieldOrProp(s_tmpOverlayText, "enableWordWrapping", true);
if (s_textOverflowModesType != null)
{
SetFieldOrProp(s_tmpOverlayText, "overflowMode", Enum.Parse(s_textOverflowModesType, "Overflow"));
}
SetFieldOrProp(s_tmpOverlayText, "raycastTarget", false);
s_tmpOverlayReady = true;
s_tmpOverlayFailed = false;
s_tmpOverlayVisible = true;
s_tmpOverlayUsesDirectUi = false;
SetTmpOverlayVisible(visible: false);
if (!s_loggedTmpOverlayReady)
{
s_loggedTmpOverlayReady = true;
LogDebug("TextMeshPro pickup overlay created by cloning source UI.");
}
return true;
}
catch (Exception ex)
{
ResetTmpOverlayState(failed: true);
LogWarning("TextMeshPro pickup overlay creation failed: " + ex.GetType().Name + " " + ex.Message);
return false;
}
}
private static bool TryCreateDirectTmpOverlay(out string failureReason)
{
//IL_0076: Unknown result type (might be due to invalid IL or missing references)
//IL_007c: Expected O, but got Unknown
//IL_009f: Unknown result type (might be due to invalid IL or missing references)
//IL_00a5: Expected O, but got Unknown
//IL_010e: Unknown result type (might be due to invalid IL or missing references)
//IL_0123: Unknown result type (might be due to invalid IL or missing references)
//IL_0138: Unknown result type (might be due to invalid IL or missing references)
//IL_014d: Unknown result type (might be due to invalid IL or missing references)
//IL_0163: Unknown result type (might be due to invalid IL or missing references)
//IL_0179: Unknown result type (might be due to invalid IL or missing references)
//IL_018f: Unknown result type (might be due to invalid IL or missing references)
//IL_019b: 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)
failureReason = null;
GameObject val = null;
GameObject val2 = null;
try
{
if ((object)s_textMeshProUguiType == null)
{
s_textMeshProUguiType = typeof(TextMeshProUGUI);
}
if ((object)s_textAlignmentOptionsType == null)
{
s_textAlignmentOptionsType = typeof(TextAlignmentOptions);
}
if ((object)s_textOverflowModesType == null)
{
s_textOverflowModesType = typeof(TextOverflowModes);
}
RectTransform val3 = ResolveTmpOverlayParentTransform(GameObject.Find("Global/Global Canvas/Player_UI/Tab Menu"));
if ((Object)(object)val3 == (Object)null)
{
failureReason = "game Tab Menu/Player_UI RectTransform is not available";
return false;
}
val = new GameObject("kp0hyc PickupTabOverlay Root");
val.transform.SetParent((Transform)(object)val3, false);
RectTransform val4 = val.GetComponent<RectTransform>() ?? val.AddComponent<RectTransform>();
val2 = new GameObject("kp0hyc PickupTabOverlay Text");
val2.transform.SetParent(val.transform, false);
RectTransform val5 = val2.GetComponent<RectTransform>() ?? val2.AddComponent<RectTransform>();
TextMeshProUGUI val6 = val2.AddComponent<TextMeshProUGUI>();
if ((Object)(object)val6 == (Object)null || (Object)(object)val4 == (Object)null || (Object)(object)val5 == (Object)null)
{
failureReason = "created direct GameObjects but TextMeshProUGUI/RectTransform was null";
Object.Destroy((Object)(object)val);
return false;
}
val4.anchorMin = new Vector2(1f, 0f);
val4.anchorMax = new Vector2(1f, 0f);
val4.pivot = new Vector2(1f, 0f);
val4.anchoredPosition = new Vector2(-34f, 34f);
val5.anchorMin = new Vector2(0f, 0f);
val5.anchorMax = new Vector2(1f, 1f);
val5.pivot = new Vector2(1f, 0f);
val5.offsetMin = Vector2.zero;
val5.offsetMax = Vector2.zero;
SetFieldOrProp(val6, "alignment", (object)(TextAlignmentOptions)1028);
SetFieldOrProp(val6, "richText", false);
SetFieldOrProp(val6, "enableAutoSizing", false);
SetFieldOrProp(val6, "enableWordWrapping", true);
SetFieldOrProp(val6, "overflowMode", (object)(TextOverflowModes)0);
SetFieldOrProp(val6, "raycastTarget", false);
SetFieldOrProp(val6, "text", string.Empty);
SetFieldOrProp(val6, "fontSize", (float)Clamp((s_rowFontSize == null) ? 18 : s_rowFontSize.Value, 18, 72));
SetFieldOrProp(val6, "color", ObjectiveColor());
object obj = FindTmpFontByName("Larke Sans Regular SDF");
if (obj != null)
{
SetFieldOrProp(val6, "font", obj);
}
s_tmpOverlayRoot = val;
s_tmpOverlayTextObject = val2;
s_tmpOverlayText = val6;
s_tmpOverlayRectTransform = val4;
s_tmpOverlayReady = true;
s_tmpOverlayFailed = false;
s_tmpOverlayVisible = true;
s_tmpOverlayUsesDirectUi = true;
SetTmpOverlayVisible(visible: false);
if (!s_loggedTmpOverlayReady)
{
s_loggedTmpOverlayReady = true;
LogDebug("TextMeshPro pickup overlay created with TellMeCosmetics-style direct UI setup.");
}
return true;
}
catch (Exception ex)
{
failureReason = ex.GetType().Name + " " + ex.Message;
try
{
if ((Object)(object)val != (Object)null)
{
Object.Destroy((Object)(object)val);
}
}
catch
{
}
return false;
}
}
private static RectTransform ResolveTmpOverlayParentTransform(GameObject tabMenu)
{
RectTransform val = (((Object)(object)tabMenu == (Object)null) ? null : tabMenu.GetComponent<RectTransform>());
if ((Object)(object)val != (Object)null)
{
return val;
}
GameObject val2 = GameObject.Find("Global/Global Canvas/Player_UI");
RectTransform val3 = (((Object)(object)val2 == (Object)null) ? null : val2.GetComponent<RectTransform>());
if ((Object)(object)val3 != (Object)null)
{
return val3;
}
GameObject val4 = GameObject.Find("Global/Global Canvas");
RectTransform val5 = (((Object)(object)val4 == (Object)null) ? null : val4.GetComponent<RectTransform>());
if ((Object)(object)val5 != (Object)null)
{
return val5;
}
return null;
}
private static void LogDirectTmpFailure(string failureReason)
{
if (string.IsNullOrWhiteSpace(failureReason))
{
failureReason = "unknown";
}
if (!string.Equals(s_lastLoggedDirectTmpFailure, failureReason, StringComparison.Ordinal))
{
s_lastLoggedDirectTmpFailure = failureReason;
LogDebug("Direct TextMeshPro pickup overlay failed: " + failureReason);
}
}
private static bool TryFindTmpOverlaySource(out object sourceText)
{
sourceText = null;
if (IsUsableTmpOverlaySource(s_objectiveTextStyle.SourceText))
{
sourceText = s_objectiveTextStyle.SourceText;
return true;
}
if (TryGetObjectiveTextStyleFromObjectiveUi(out var style) && IsUsableTmpOverlaySource(style.SourceText))
{
s_objectiveTextStyle = style;
sourceText = style.SourceText;
return true;
}
if (TryGetObjectiveTextStyleFromTmpScan(out var style2) && IsUsableTmpOverlaySource(style2.SourceText))
{
s_objectiveTextStyle = style2;
sourceText = style2.SourceText;
return true;
}
return false;
}
private static void LogTmpOverlayDiagnostics(string reason)
{
if (!IsDebugLoggingEnabled())
{
return;
}
DateTime utcNow = DateTime.UtcNow;
if (!(utcNow < s_nextTmpDiagnosticsUtc))
{
string text = BuildTmpOverlayDiagnostics(reason);
if (string.Equals(s_lastLoggedTmpDiagnosticsSignature, text, StringComparison.Ordinal))
{
s_nextTmpDiagnosticsUtc = utcNow.AddSeconds(5.0);
return;
}
s_lastLoggedTmpDiagnosticsSignature = text;
s_nextTmpDiagnosticsUtc = utcNow.AddSeconds(2.0);
LogDebug(text);
}
}
private static void LogTmpLayoutDiagnostics(ObjectiveTextStyle textStyle, TmpOverlayModel model)
{
if (IsDebugLoggingEnabled())
{
object rectTransform = ((s_tmpOverlayTextObject == null) ? null : GetComponent(s_tmpOverlayTextObject, s_rectTransformType));
object componentInParent = GetComponentInParent(s_tmpOverlayText, s_canvasType);
string b = (s_tmpOverlayUsesDirectUi ? "direct" : "cloned") + "|" + model.Width.ToString("0.#") + "|" + model.Height.ToString("0.#") + "|" + textStyle.RowFontSize + "|" + DescribeRectTransform(s_tmpOverlayRectTransform) + "|" + DescribeRectTransform(rectTransform) + "|" + GetCanvasScaleFactor(s_tmpOverlayText).ToString("0.##");
if (!string.Equals(s_lastLoggedTmpLayoutSignature, b, StringComparison.Ordinal))
{
s_lastLoggedTmpLayoutSignature = b;
LogDebug("TMP pickup layout renderer=" + (s_tmpOverlayUsesDirectUi ? "direct" : "cloned") + " screen=" + ScreenWidth() + "x" + ScreenHeight() + " model=" + model.Width.ToString("0.#") + "x" + model.Height.ToString("0.#") + " root={" + DescribeRectTransform(s_tmpOverlayRectTransform) + "} text={" + DescribeRectTransform(rectTransform) + "} rootScale=" + DescribeVector(GetFieldOrProp(GetFieldOrProp(s_tmpOverlayRoot, "transform"), "lossyScale")) + " textScale=" + DescribeVector(GetFieldOrProp(GetFieldOrProp(s_tmpOverlayTextObject, "transform"), "lossyScale")) + " canvasScale=" + GetCanvasScaleFactor(s_tmpOverlayText).ToString("0.##") + " canvas='" + TruncateForLog(GetUnityObjectName(componentInParent), 60) + "' " + DescribeTextStyleForLog(textStyle));
}
}
}
private static string BuildTmpOverlayDiagnostics(string reason)
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append("TMP diagnostics reason=");
stringBuilder.Append(reason);
stringBuilder.Append(" types={");
stringBuilder.Append("GameObject=").Append(TypeNameForLog(s_gameObjectType));
stringBuilder.Append(", RectTransform=").Append(TypeNameForLog(s_rectTransformType));
stringBuilder.Append(", Canvas=").Append(TypeNameForLog(s_canvasType));
stringBuilder.Append(", TMP_Text=").Append(TypeNameForLog(s_tmpTextType));
stringBuilder.Append(", TextMeshProUGUI=").Append(TypeNameForLog(s_textMeshProUguiType));
stringBuilder.Append(", TextAlignmentOptions=").Append(TypeNameForLog(s_textAlignmentOptionsType));
stringBuilder.Append(", TextOverflowModes=").Append(TypeNameForLog(s_textOverflowModesType));
stringBuilder.Append("} methods={");
stringBuilder.Append("FindObjectsOfType=").Append(s_findObjectsOfTypeMethod != null);
stringBuilder.Append(", GetComponentInParent=").Append(s_componentGetComponentInParentMethod != null);
stringBuilder.Append(", GetComponent=").Append(s_gameObjectGetComponentMethod != null);
stringBuilder.Append(", AddComponent=").Append(s_gameObjectAddComponentMethod != null);
stringBuilder.Append(", Instantiate=").Append(s_objectInstantiateMethod != null);
stringBuilder.Append(", SetActive=").Append(s_gameObjectSetActiveMethod != null);
stringBuilder.Append("}");
AppendObjectiveUiDiagnostics(stringBuilder);
AppendTmpScanDiagnostics(stringBuilder, s_textMeshProUguiType, "TextMeshProUGUI");
if (s_tmpTextType != null && (object)s_tmpTextType != s_textMeshProUguiType)
{
AppendTmpScanDiagnostics(stringBuilder, s_tmpTextType, "TMP_Text");
}
return stringBuilder.ToString();
}
private static void AppendObjectiveUiDiagnostics(StringBuilder builder)
{
int num = 0;
int num2 = 0;
int num3 = 0;
List<string> list = new List<string>();
try
{
foreach (object item in FindObjectsOfType(GetObjectiveUiType()))
{
num++;
if (IsActiveInHierarchy(item))
{
num2++;
}
object fieldOrProp = GetFieldOrProp(item, "displayText");
if (fieldOrProp != null)
{
num3++;
if (list.Count < 2)
{
list.Add(DescribeTmpTextSource(fieldOrProp));
}
}
else if (list.Count < 2)
{
list.Add("objectiveUi='" + TruncateForLog(GetUnityObjectName(item), 50) + "' displayText=null");
}
}
}
catch (Exception ex)
{
list.Add("error=" + ex.GetType().Name + ":" + ex.Message);
}
builder.Append(" objectiveUI={total=").Append(num).Append(", active=")
.Append(num2)
.Append(", withDisplayText=")
.Append(num3)
.Append(", samples=[")
.Append(string.Join("; ", list))
.Append("]}");
}
private static void AppendTmpScanDiagnostics(StringBuilder builder, Type type, string label)
{
if (type == null)
{
builder.Append(" ").Append(label).Append("={type=null}");
return;
}
int num = 0;
int num2 = 0;
int num3 = 0;
int num4 = 0;
int num5 = 0;
int num6 = 0;
List<string> list = new List<string>();
try
{
foreach (object item in FindObjectsOfType(type))
{
num++;
bool flag = IsActiveInHierarchy(item);
if (flag)
{
num2++;
}
if (IsPickupTmpOverlayObject(item))
{
num5++;
continue;
}
if (!TryConvertFloat(GetFieldOrProp(item, "fontSize"), out var result) || result <= 1f)
{
num4++;
if (list.Count < 4)
{
list.Add("noFontSize {" + DescribeTmpTextSource(item) + "}");
}
continue;
}
if (GetComponentInParent(item, s_canvasType) == null)
{
num6++;
if (list.Count < 4)
{
list.Add("noCanvas {" + DescribeTmpTextSource(item) + "}");
}
continue;
}
num3++;
if (list.Count < 4)
{
list.Add("usable active=" + flag + " {" + DescribeTmpTextSource(item) + "}");
}
}
}
catch (Exception ex)
{
list.Add("error=" + ex.GetType().Name + ":" + ex.Message);
}
builder.Append(" ").Append(label).Append("={total=")
.Append(num)
.Append(", active=")
.Append(num2)
.Append(", usable=")
.Append(num3)
.Append(", ownOverlay=")
.Append(num5)
.Append(", noFontSize=")
.Append(num4)
.Append(", noCanvas=")
.Append(num6)
.Append(", samples=[")
.Append(string.Join("; ", list))
.Append("]}");
}
private static bool IsUsableTmpOverlaySource(object sourceText)
{
if (sourceText == null || !IsActiveInHierarchy(sourceText))
{
return false;
}
if (GetFieldOrProp(sourceText, "gameObject") == null)
{
return false;
}
return GetComponentInParent(sourceText, s_canvasType) != null;
}
private static bool MarkTmpOverlayFailed(string reason)
{
ResetTmpOverlayState(failed: true);
LogWarning("TextMeshPro pickup overlay unavailable: " + reason);
return false;
}
private static void ApplyTmpTextStyle(ObjectiveTextStyle textStyle)
{
if (s_tmpOverlayText != null)
{
if (textStyle.Font != null)
{
SetFieldOrProp(s_tmpOverlayText, "font", textStyle.Font);
}
if (textStyle.FontSharedMaterial != null)
{
SetFieldOrProp(s_tmpOverlayText, "fontSharedMaterial", textStyle.FontSharedMaterial);
}
SetFieldOrProp(s_tmpOverlayText, "fontSize", (float)textStyle.RowFontSize);
SetFieldOrProp(s_tmpOverlayText, "color", textStyle.Color ?? ObjectiveColor());
}
}
private static void ApplyTmpLayout(float width, float height)
{
if (s_tmpOverlayRectTransform != null && (!(Math.Abs(width - s_tmpLastWidth) < 0.1f) || !(Math.Abs(height - s_tmpLastHeight) < 0.1f)))
{
s_tmpLastWidth = width;
s_tmpLastHeight = height;
SetFieldOrProp(s_tmpOverlayRectTransform, "sizeDelta", Vector2(width, height));
SetFieldOrProp(s_tmpOverlayRectTransform, "anchoredPosition", Vector2(-34f, 34f));
}
}
private static void ApplyTmpText(string text, int styleKey)
{
if (s_tmpOverlayText != null && (!string.Equals(s_tmpLastText, text, StringComparison.Ordinal) || s_tmpLastStyleKey != styleKey))
{
s_tmpLastText = text;
s_tmpLastStyleKey = styleKey;
SetFieldOrProp(s_tmpOverlayText, "text", text);
}
}
private static void SetTmpOverlayVisible(bool visible)
{
if (s_tmpOverlayRoot == null || s_gameObjectSetActiveMethod == null || s_tmpOverlayVisible == visible)
{
return;
}
try
{
s_gameObjectSetActiveMethod.Invoke(s_tmpOverlayRoot, new object[1] { visible });
s_tmpOverlayVisible = visible;
}
catch
{
ResetTmpOverlayState(failed: false);
}
}
private static void DestroyTmpOverlay()
{
if (s_tmpOverlayRoot != null && s_objectDestroyMethod != null)
{
try
{
s_objectDestroyMethod.Invoke(null, new object[1] { s_tmpOverlayRoot });
}
catch
{
}
}
ResetTmpOverlayState(failed: false);
}
private static void ResetTmpOverlayState(bool failed)
{
s_tmpOverlayRoot = null;
s_tmpOverlayTextObject = null;
s_tmpOverlayText = null;
s_tmpOverlayRectTransform = null;
s_tmpOverlayReady = false;
s_tmpOverlayVisible = false;
s_tmpOverlayFailed = failed;
s_tmpOverlayUsesDirectUi = false;
s_nextTmpOverlayRetryUtc = (failed ? DateTime.UtcNow.AddSeconds(5.0) : DateTime.MinValue);
s_loggedTmpOverlayReady = false;
s_tmpLastText = null;
s_tmpLastStyleKey = 0;
s_tmpLastWidth = 0f;
s_tmpLastHeight = 0f;
}
private static object CreateGameObject(string name, params Type[] components)
{
if (s_gameObjectWithComponentsCtor != null)
{
return s_gameObjectWithComponentsCtor.Invoke(new object[2] { name, components });
}
object obj = s_gameObjectCtor.Invoke(new object[1] { name });
foreach (Type type in components)
{
s_gameObjectAddComponentMethod?.Invoke(obj, new object[1] { type });
}
return obj;
}
private static object CloneGameObject(object sourceGameObject, object parentTransform)
{
if (sourceGameObject == null || parentTransform == null || s_objectInstantiateMethod == null)
{
return null;
}
return s_objectInstantiateMethod.Invoke(null, new object[3] { sourceGameObject, parentTransform, false });
}
private static object GetComponent(object gameObject, Type componentType)
{
if (gameObject == null || componentType == null || s_gameObjectGetComponentMethod == null)
{
return null;
}
try
{
return s_gameObjectGetComponentMethod.Invoke(gameObject, new object[1] { componentType });
}
catch
{
return null;
}
}
private static void SetRectTransformAnchors(object rectTransform, float anchorMinX, float anchorMinY, float anchorMaxX, float anchorMaxY, float pivotX, float pivotY)
{
SetFieldOrProp(rectTransform, "anchorMin", Vector2(anchorMinX, anchorMinY));
SetFieldOrProp(rectTransform, "anchorMax", Vector2(anchorMaxX, anchorMaxY));
SetFieldOrProp(rectTransform, "pivot", Vector2(pivotX, pivotY));
}
private static ObjectiveTextStyle ResolveTextStyle()
{
if (s_useObjectiveTextStyle != null && s_useObjectiveTextStyle.Value)
{
TryRefreshObjectiveTextStyle();
}
if (s_objectiveTextStyle.HasLiveStyle)
{
return s_objectiveTextStyle;
}
return ObjectiveTextStyle.FromConfig(Clamp((s_headerFontSize == null) ? 20 : s_headerFontSize.Value, 20, 76), Clamp((s_rowFontSize == null) ? 18 : s_rowFontSize.Value, 18, 72), Clamp((s_footerFontSize == null) ? 16 : s_footerFontSize.Value, 16, 68), ObjectiveColor());
}
private static void TryRefreshObjectiveTextStyle()
{
DateTime utcNow = DateTime.UtcNow;
if (utcNow < s_nextObjectiveStyleRefreshUtc)
{
return;
}
s_nextObjectiveStyleRefreshUtc = utcNow.AddSeconds((!s_objectiveTextStyle.HasLiveStyle) ? 1 : 2);
try
{
if (TryGetObjectiveTextStyleFromObjectiveUi(out var style) || TryGetObjectiveTextStyleFromTmpScan(out style))
{
s_objectiveTextStyle = style;
string text = DescribeTextStyleForLog(style);
if (!string.Equals(s_lastLoggedObjectiveStyleSignature, text, StringComparison.Ordinal))
{
s_lastLoggedObjectiveStyleSignature = text;
LogDebug("Objective text style " + text);
}
}
}
catch (Exception ex)
{
LogWarning("objective text style refresh failed: " + ex.GetType().Name + " " + ex.Message);
}
}
private static bool TryGetObjectiveTextStyleFromObjectiveUi(out ObjectiveTextStyle style)
{
style = ObjectiveTextStyle.Fallback;
Type objectiveUiType = GetObjectiveUiType();
if (objectiveUiType == null)
{
return false;
}
foreach (object item in FindObjectsOfType(objectiveUiType))
{
if (item != null && IsActiveInHierarchy(item) && TryGetTextStyleFromTmpText(GetFieldOrProp(item, "displayText"), "ObjectiveUI", out style))
{
return true;
}
}
return false;
}
private static bool TryGetObjectiveTextStyleFromTmpScan(out ObjectiveTextStyle style)
{
style = ObjectiveTextStyle.Fallback;
Type type = GetTextMeshProUguiType() ?? GetTmpTextType();
if (type == null)
{
return false;
}
ObjectiveTextStyle objectiveTextStyle = ObjectiveTextStyle.Fallback;
int num = int.MinValue;
foreach (object item in FindObjectsOfType(type))
{
if (item != null && IsActiveInHierarchy(item) && !IsPickupTmpOverlayObject(item) && TryGetTextStyleFromTmpText(item, "TMP scan", out var style2))
{
int num2 = ScoreTmpTextCandidate(item, style2.RowFontSize);
if (num2 > num)
{
num = num2;
objectiveTextStyle = style2;
}
}
}
if (!objectiveTextStyle.HasLiveStyle)
{
return false;
}
style = objectiveTextStyle;
return true;
}
private static int ScoreTmpTextCandidate(object tmpText, int rowFontSize)
{
int num = rowFontSize;
if (TryConvertFloat(GetFieldOrProp(tmpText, "fontSize"), out var result))
{
num += (int)Math.Round(result * 10f);
}
string text = GetFieldOrProp(tmpText, "text") as string;
if (!string.IsNullOrWhiteSpace(text))
{
if (text.Length > 3)
{
num += 100;
}
if (text == text.ToUpperInvariant())
{
num += 200;
}
if (text.IndexOf("Pickups", StringComparison.OrdinalIgnoreCase) >= 0)
{
num -= 500;
}
}
string text2 = (GetFieldOrProp(GetFieldOrProp(tmpText, "gameObject"), "name") as string) ?? string.Empty;
if (text2.IndexOf("objective", StringComparison.OrdinalIgnoreCase) >= 0)
{
num += 10000;
}
if (text2.IndexOf("mission", StringComparison.OrdinalIgnoreCase) >= 0 || text2.IndexOf("task", StringComparison.OrdinalIgnoreCase) >= 0 || text2.IndexOf("quest", StringComparison.OrdinalIgnoreCase) >= 0)
{
num += 2000;
}
if (text2.IndexOf("map", StringComparison.OrdinalIgnoreCase) >= 0 || text2.IndexOf("seed", StringComparison.OrdinalIgnoreCase) >= 0 || text2.IndexOf("monster", StringComparison.OrdinalIgnoreCase) >= 0 || text2.IndexOf("pickup", StringComparison.OrdinalIgnoreCase) >= 0)
{
num -= 1000;
}
return num;
}
private static bool TryGetTextStyleFromTmpText(object tmpText, string source, out ObjectiveTextStyle style)
{
style = ObjectiveTextStyle.Fallback;
if (tmpText == null)
{
return false;
}
if (!TryConvertFloat(GetFieldOrProp(tmpText, "fontSize"), out var result) || result <= 1f)
{
return false;
}
int num = Clamp((s_objectiveTextScalePercent == null) ? 100 : s_objectiveTextScalePercent.Value, 50, 200);
int val = Clamp((s_rowFontSize == null) ? 18 : s_rowFontSize.Value, 18, 72);
int val2 = Clamp((s_headerFontSize == null) ? 20 : s_headerFontSize.Value, 20, 76);
int val3 = Clamp((s_footerFontSize == null) ? 16 : s_footerFontSize.Value, 16, 68);
int num2 = Clamp(Math.Max((int)Math.Round(result * (float)num / 100f), val), 18, 84);
int headerFontSize = Clamp(Math.Max(num2 + 2, val2), 20, 88);
int footerFontSize = Clamp(Math.Max(num2 - 4, val3), 16, 76);
object color = NormalizeTextColor(GetFieldOrProp(tmpText, "color"));
object fieldOrProp = GetFieldOrProp(tmpText, "font");
object fieldOrProp2 = GetFieldOrProp(tmpText, "fontSharedMaterial");
style = new ObjectiveTextStyle(hasLiveStyle: true, source, headerFontSize, num2, footerFontSize, color, CopyColorWithAlpha(color, 0.82f), fieldOrProp, fieldOrProp2, tmpText);
return true;
}
private static float GetCanvasScaleFactor(object component)
{
try
{
Type canvasType = GetCanvasType();
if (canvasType == null)
{
return 1f;
}
object componentInParent = GetComponentInParent(component, canvasType);
if (componentInParent == null)
{
return 1f;
}
float result;
return (TryConvertFloat(GetFieldOrProp(componentInParent, "scaleFactor"), out result) && result > 0f) ? Clamp(result, 0.5f, 4f) : 1f;
}
catch
{
return 1f;
}
}
private static object GetComponentInParent(object component, Type requestedType)
{
if (component == null || requestedType == null || s_componentGetComponentInParentMethod == null)
{
return null;
}
try
{
return s_componentGetComponentInParentMethod.Invoke(component, new object[1] { requestedType });
}
catch
{
return null;
}
}
private static IEnumerable<object> FindObjectsOfType(Type type)
{
if (type == null || s_findObjectsOfTypeMethod == null)
{
yield break;
}
object list = null;
try
{
list = s_findObjectsOfTypeMethod.Invoke(null, new object[1] { type });
}
catch
{
}
foreach (object item in EnumerateItems(list))
{
if (item != null)
{
yield return item;
}
}
}
private static IEnumerable<object> FindResourceObjectsOfType(Type type)
{
if (type == null || s_resourcesFindObjectsOfTypeAllMethod == null)
{
yield break;
}
object list = null;
try
{
list = s_resourcesFindObjectsOfTypeAllMethod.Invoke(null, new object[1] { type });
}
catch
{
}
foreach (object item in EnumerateItems(list))
{
if (item != null)
{
yield return item;
}
}
}
private static object FindTmpFontByName(string name)
{
if (string.IsNullOrWhiteSpace(name))
{
return null;
}
if (s_larkeSansFont != null && string.Equals(GetFieldOrProp(s_larkeSansFont, "name")?.ToString(), name, StringComparison.OrdinalIgnoreCase))
{
return s_larkeSansFont;
}
foreach (object item in FindResourceObjectsOfType(s_tmpFontAssetType))
{
if (string.Equals(GetFieldOrProp(item, "name")?.ToString(), name, StringComparison.OrdinalIgnoreCase))
{
s_larkeSansFont = item;
return item;
}
}
return null;
}
private static bool HasAnyDisplayedPickup()
{
if (s_entries.Count <= 0 && GetCollectibleRows().Count <= 0)
{
return GetUnlockRows().Count > 0;
}
return true;
}
private static List<CollectibleEntry> GetCollectibleRows()
{
List<CollectibleEntry> list = new List<CollectibleEntry>();
if (s_showCollectibles == null || !s_showCollectibles.Value)
{
return list;
}
AddCollectibleRow(list, "Tickets");
AddCollectibleRow(list, "Reroll Coins");
return list;
}
private static void AddCollectibleRow(List<CollectibleEntry> rows, string label)
{
if (s_collectiblesFound.TryGetValue(label, out var value) && value > 0)
{
rows.Add(new CollectibleEntry(label, value));
}
}
private static List<UnlockEntry> GetUnlockRows()
{
if (s_showUnlockPickups == null || !s_showUnlockPickups.Value)
{
return new List<UnlockEntry>();
}
return s_unlockEntries.ToList();
}
private static string FormatEntry(PickupEntry entry)
{
string text = entry.Name;
if (entry.Count > 1)
{
text = text + " x" + entry.Count;
}
if (s_showIds != null && s_showIds.Value && entry.Id >= 0)
{
text = text + " #" + entry.Id;
}
if (s_showHandLabels != null && s_showHandLabels.Value)
{
if (entry.LeftHand && entry.RightHand)
{
text += " L/R";
}
else if (entry.LeftHand)
{
text += " L";
}
else if (entry.RightHand)
{
text += " R";
}
}
return text;
}
private static string FormatUnlockEntry(UnlockEntry entry)
{
if (string.Equals(entry.Category, "Stamps", StringComparison.OrdinalIgnoreCase))
{
return "Stamps: " + entry.Count;
}
string text = entry.Category + ": " + entry.Name;
if (entry.Id >= 0)
{
text = text + " #" + entry.Id;
}
if (string.Equals(entry.Category, "Cosmetic", StringComparison.OrdinalIgnoreCase) && !string.IsNullOrWhiteSpace(entry.ItemClass))
{
text = text + " (" + entry.ItemClass + ")";
}
if (entry.Count > 1)
{
text = text + " x" + entry.Count;
}
return text;
}
private static object GetLocalRndPlayerInventory()
{
object fieldOrProp = GetFieldOrProp(GetStaticFieldOrProp(GetPlayerNetworkSyncType(), "instance"), "RndPlayerInventory");
if (fieldOrProp != null)
{
return fieldOrProp;
}
fieldOrProp = GetFieldOrProp(GetFieldOrProp(GetStaticFieldOrProp(GetGameManagerType(), "instance"), "mainPlayer"), "RndPlayerInventory");
if (fieldOrProp != null)
{
return fieldOrProp;
}
return FindOwnedRndPlayerInventory();
}
private static object FindOwnedRndPlayerInventory()
{
try
{
if (!EnsureReflection() || s_findObjectsOfTypeMethod == null)
{
return null;
}
Type rndPlayerInventoryType = GetRndPlayerInventoryType();
if (rndPlayerInventoryType == null)
{
return null;
}
object? list = s_findObjectsOfTypeMethod.Invoke(null, new object[1] { rndPlayerInventoryType });
object obj = null;
foreach (object item in EnumerateItems(list))
{
if (item != null)
{
obj = obj ?? item;
if (TryConvertBool(GetFieldOrProp(GetFieldOrProp(item, "playerNetworkSync"), "isOwned"), out var result) && result)
{
return item;
}
}
}
return obj;
}
catch
{
return null;
}
}
private static int GetHandItemId(string propertyName)
{
try
{
if (TryConvertInt(GetFieldOrProp(GetStaticFieldOrProp(FindType("InventoryController"), "Instance"), propertyName), out var result))
{
return result;
}
}
catch
{
}
return -1;
}
private static bool TryGetItemId(object item, out int id)
{
if (TryConvertInt(GetFieldOrProp(item, "SerializedID"), out id))
{
return true;
}
return TryConvertInt(GetFieldOrProp(item, "ID"), out id);
}
private static string GetItemDisplayName(object item)
{
try
{
string text = item.GetType().GetMethod("GetItemName", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.Invoke(item, Array.Empty<object>()) as string;
if (!string.IsNullOrWhiteSpace(text))
{
return text;
}
}
catch
{
}
string text2 = GetFieldOrProp(item, "name") as string;
if (!string.IsNullOrWhiteSpace(text2))
{
return CleanUnityName(text2);
}
text2 = GetFieldOrProp(item, "nameLocalisationKey") as string;
if (!string.IsNullOrWhiteSpace(text2))
{
return text2;
}
return null;
}
private static string CleanUnityName(string name)
{
if (string.IsNullOrWhiteSpace(name))
{
return name;
}
string text = name.Trim();
if (text.EndsWith("(Clone)", StringComparison.OrdinalIgnoreCase))
{
text = text.Substring(0, text.Length - 7).Trim();
}
if (text.StartsWith("SO_", StringComparison.OrdinalIgnoreCase))
{
text = text.Substring(3);
}
return text.Replace('_', ' ');
}
private static bool IsTabMenuPressed()
{
if (IsTabMenuObjectActive())
{
return true;
}
try
{
if (s_gameGetButton != null && s_showTabMenuButton != null && TryConvertBool(s_gameGetButton.Invoke(null, new object[1] { s_showTabMenuButton }), out var result))
{
return result;
}
}
catch
{
}
try
{
if (s_inputGetKey != null && s_keyCodeTab != null && TryConvertBool(s_inputGetKey.Invoke(null, new object[1] { s_keyCodeTab }), out var result2))
{
return result2;
}
}
catch
{
}
return false;
}
private static bool IsTabMenuObjectActive()
{
try
{
if (IsActiveInHierarchy(GetFieldOrProp(GetStaticFieldOrProp(FindType("UI_Controller"), "instance"), "tabMenu")))
{
return true;
}
GameObject val = GameObject.Find("Global/Global Canvas/Player_UI/Tab Menu");
return (Object)(object)val != (Object)null && val.activeInHierarchy;
}
catch
{
return false;
}
}
private static bool IsActiveInHierarchy(object obj)
{
if (obj == null)
{
return false;
}
bool result;
return TryConvertBool(GetFieldOrProp(GetFieldOrProp(obj, "gameObject") ?? obj, "activeInHierarchy"), out result) && result;
}
private static bool EnsureReflection()
{
if (s_reflectionReady)
{
return true;
}
try
{
s_rectType = FindType("UnityEngine.Rect");
s_colorType = FindType("UnityEngine.Color");
s_vector2Type = FindType("UnityEngine.Vector2");
s_guiType = FindType("UnityEngine.GUI");
s_screenType = FindType("UnityEngine.Screen");
s_inputType = FindType("UnityEngine.Input");
s_keyCodeType = FindType("UnityEngine.KeyCode");
s_objectType = FindType("UnityEngine.Object");
s_componentType = FindType("UnityEngine.Component");
s_gameObjectType = FindType("UnityEngine.GameObject");
s_transformType = FindType("UnityEngine.Transform");
s_rectTransformType = FindType("UnityEngine.RectTransform");
s_objectiveUiType = FindType("Objectives.ObjectiveUI");
s_tmpTextType = FindTmpType("TMP_Text");
s_tmpFontAssetType = FindTmpType("TMP_FontAsset");
s_textMeshProUguiType = FindTmpType("TextMeshProUGUI");
s_canvasType = FindType("UnityEngine.Canvas");
s_renderModeType = FindType("UnityEngine.RenderMode");
s_resourcesType = FindType("UnityEngine.Resources");
s_textAlignmentOptionsType = FindTmpType("TextAlignmentOptions");
s_textOverflowModesType = FindTmpType("TextOverflowModes");
s_labyrinthineInputManagerType = FindType("LabyrinthineInputManager");
s_inputButtonType = FindType("InputButton");
if (s_rectType == null || s_colorType == null || s_guiType == null)
{
return LogReflectionNotReady();
}
s_rectCtor = s_rectType.GetConstructor(new Type[4]
{
typeof(float),
typeof(float),
typeof(float),
typeof(float)
});
s_colorCtor = s_colorType.GetConstructor(new Type[4]
{
typeof(float),
typeof(float),
typeof(float),
typeof(float)
});
s_vector2Ctor = s_vector2Type?.GetConstructor(new Type[2]
{
typeof(float),
typeof(float)
});
s_gameObjectCtor = s_gameObjectType?.GetConstructor(new Type[1] { typeof(string) });
s_gameObjectWithComponentsCtor = s_gameObjectType?.GetConstructor(new Type[2]
{
typeof(string),
typeof(Type[])
});
s_guiColorProperty = s_guiType.GetProperty("color", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
s_screenWidthProperty = s_screenType?.GetProperty("width", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
s_screenHeightProperty = s_screenType?.GetProperty("height", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
s_guiSkinProperty = s_guiType.GetProperty("skin", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
s_guiLabel = s_guiType.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "Label" && m.GetParameters().Length == 2 && m.GetParameters()[0].ParameterType == s_rectType && m.GetParameters()[1].ParameterType == typeof(string));
s_inputGetKey = s_inputType?.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "GetKey" && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == s_keyCodeType);
if (s_keyCodeType != null)
{
s_keyCodeTab = Enum.Parse(s_keyCodeType, "Tab");
}
if (s_labyrinthineInputManagerType != null && s_inputButtonType != null)
{
s_gameGetButton = s_labyrinthineInputManagerType.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "GetButton" && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == s_inputButtonType);
s_showTabMenuButton = Enum.Parse(s_inputButtonType, "ShowTabMenu");
}
s_findObjectsOfTypeMethod = s_objectType?.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "FindObjectsOfType" && !m.ContainsGenericParameters && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == typeof(Type));
s_componentGetComponentInParentMethod = s_componentType?.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "GetComponentInParent" && !m.ContainsGenericParameters && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == typeof(Type));
s_gameObjectGetComponentMethod = s_gameObjectType?.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "GetComponent" && !m.ContainsGenericParameters && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == typeof(Type));
s_gameObjectAddComponentMethod = s_gameObjectType?.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "AddComponent" && !m.ContainsGenericParameters && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == typeof(Type));
s_gameObjectSetActiveMethod = s_gameObjectType?.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "SetActive" && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == typeof(bool));
s_transformSetParentMethod = s_transformType?.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "SetParent" && m.GetParameters().Length == 2 && m.GetParameters()[1].ParameterType == typeof(bool));
s_transformSetAsLastSiblingMethod = s_transformType?.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "SetAsLastSibling" && m.GetParameters().Length == 0);
s_objectInstantiateMethod = s_objectType?.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "Instantiate" && !m.ContainsGenericParameters && m.GetParameters().Length == 3 && m.GetParameters()[1].ParameterType == s_transformType && m.GetParameters()[2].ParameterType == typeof(bool));
s_objectDestroyMethod = s_objectType?.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "Destroy" && m.GetParameters().Length == 1);
s_objectDontDestroyOnLoadMethod = s_objectType?.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "DontDestroyOnLoad" && m.GetParameters().Length == 1);
s_resourcesFindObjectsOfTypeAllMethod = s_resourcesType?.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "FindObjectsOfTypeAll" && !m.ContainsGenericParameters && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == typeof(Type));
if (s_rectCtor == null || s_colorCtor == null || s_guiLabel == null)
{
return LogReflectionNotReady();
}
InitLabelSkinAccessors();
s_reflectionReady = true;
return true;
}
catch (Exception ex)
{
LogWarning("Unity reflection init failed: " + ex.GetType().Name + " " + ex.Message);
return false;
}
}
private static void InitLabelSkinAccessors()
{
try
{
object obj = s_guiSkinProperty?.GetValue(null);
PropertyInfo propertyInfo = ((s_guiSkinLabelProperty == null && obj != null) ? obj.GetType().GetProperty("label", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) : s_guiSkinLabelProperty);
if (propertyInfo != null)
{
s_guiSkinLabelProperty = propertyInfo;
}
object obj2 = s_guiSkinLabelProperty?.GetValue(obj);
if (obj2 != null)
{
Type type = obj2.GetType();
s_styleFontSizeProperty = type.GetProperty("fontSize", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
s_styleNormalProperty = type.GetProperty("normal", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
s_styleStateTextColorProperty = (s_styleNormalProperty?.GetValue(obj2))?.GetType().GetProperty("textColor", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
}
}
catch
{
}
}
private static bool LogReflectionNotReady()
{
LogWarning("Unity IMGUI reflection is not ready yet.");
return false;
}
private static void LabelShadowed(float x, float y, float width, float height, string text, int fontSize, object color)
{
Label(x + 1f, y + 1f, width, height, text, Color(0f, 0f, 0f, 0.7f), fontSize);
Label(x, y, width, height, text, color, fontSize);
}
private static object ObjectiveColor()
{
return Color(1f, 1f, 1f, 1f);
}
private static object MutedObjectiveColor()
{
return Color(1f, 1f, 1f, 0.82f);
}
private static object NormalizeTextColor(object color)
{
if (TryReadColor(color, out var r, out var g, out var b, out var a))
{
return Color(Clamp01(r), Clamp01(g), Clamp01(b), Clamp01((a <= 0f) ? 1f : a));
}
return ObjectiveColor();
}
private static object CopyColorWithAlpha(object color, float alpha)
{
if (TryReadColor(color, out var r, out var g, out var b, out var _))
{
return Color(Clamp01(r), Clamp01(g), Clamp01(b), Clamp01(alpha));
}
return Color(1f, 1f, 1f, Clamp01(alpha));
}
private static bool TryReadColor(object color, out float r, out float g, out float b, out float a)
{
r = 1f;
g = 1f;
b = 1f;
a = 1f;
if (color == null)
{
return false;
}
if (TryConvertFloat(GetFieldOrProp(color, "r"), out r) && TryConvertFloat(GetFieldOrProp(color, "g"), out g) && TryConvertFloat(GetFieldOrProp(color, "b"), out b))
{
return TryConvertFloat(GetFieldOrProp(color, "a"), out a);
}
return false;
}
private static void Label(float x, float y, float width, float height, string text, object color, int fontSize)
{
SetGuiColor(color);
object oldFontSize = null;
object oldTextColor = null;
object skinLabelStyle = GetSkinLabelStyle();
object obj = ((skinLabelStyle == null) ? null : s_styleNormalProperty?.GetValue(skinLabelStyle));
try
{
if (skinLabelStyle != null && s_styleFontSizeProperty != null)
{
oldFontSize = s_styleFontSizeProperty.GetValue(skinLabelStyle);
}
if (obj != null && s_styleStateTextColorProperty != null)
{
oldTextColor = s_styleStateTextColorProperty.GetValue(obj);
}
SetLabelFontSize(skinLabelStyle, fontSize);
SetLabelTextColor(obj, color);
s_guiLabel.Invoke(null, new object[2]
{
Rect(x, y, width, height),
text
});
}
finally
{
RestoreLabelStyle(skinLabelStyle, obj, oldFontSize, oldTextColor);
SetGuiColor(Color(1f, 1f, 1f, 1f));
}
}
private static object GetSkinLabelStyle()
{
try
{
object obj = s_guiSkinProperty?.GetValue(null);
return (obj == null) ? null : s_guiSkinLabelProperty?.GetValue(obj);
}
catch
{
return null;
}
}
private static void SetLabelFontSize(object style, int fontSize)
{
try
{
s_styleFontSizeProperty?.SetValue(style, fontSize);
}
catch
{
}
}
private static void SetLabelTextColor(object normal, object color)
{
try
{
s_styleStateTextColorProperty?.SetValue(normal, color);
}
catch
{
}
}
private static void RestoreLabelStyle(object style, object normal, object oldFontSize, object oldTextColor)
{
try
{
if (style != null && oldFontSize != null)
{
s_styleFontSizeProperty?.SetValue(style, oldFontSize);
}
if (normal != null && oldTextColor != null)
{
s_styleStateTextColorProperty?.SetValue(normal, oldTextColor);
}
}
catch
{
}
}
private static object Rect(float x, float y, float width, float height)
{
return s_rectCtor.Invoke(new object[4] { x, y, width, height });
}
private static object Color(float r, float g, float b, float a)
{
return s_colorCtor.Invoke(new object[4] { r, g, b, a });
}
private static object Vector2(float x, float y)
{
return s_vector2Ctor.Invoke(new object[2] { x, y });
}
private static void SetGuiColor(object color)
{
try
{
s_guiColorProperty?.SetValue(null, color);
}
catch
{
}
}
private static int ScreenWidth()
{
try
{
return (s_screenWidthProperty == null) ? 1920 : Convert.ToInt32(s_screenWidthProperty.GetValue(null));
}
catch
{
return 1920;
}
}
private static int ScreenHeight()
{
try
{
return (s_screenHeightProperty == null) ? 1080 : Convert.ToInt32(s_screenHeightProperty.GetValue(null));
}
catch
{
return 1080;
}
}
private static Type GetPlayerNetworkSyncType()
{
if (s_playerNetworkSyncType == null)
{
s_playerNetworkSyncType = FindType("PlayerNetworkSync");
}
return s_playerNetworkSyncType;
}
private static Type GetGameManagerType()
{
if (s_gameManagerType == null)
{
s_gameManagerType = FindType("GameManager");
}
return s_gameManagerType;
}
private static Type GetRndPlayerInventoryType()
{
if (s_rndPlayerInventoryType == null)
{
s_rndPlayerInventoryType = FindType("ValkoGames.Labyrinthine.Cases.Inventory.RndPlayerInventory");
}
return s_rndPlayerInventoryType;
}
private static Type GetRndCollectibleType()
{
if (s_rndCollectibleType == null)
{
s_rndCollectibleType = FindType("ValkoGames.Labyrinthine.Cases.Interactions.RndCollectible");
}
return s_rndCollectibleType;
}
private static Type GetCustomizationPickupType()
{
if (s_customizationPickupType == null)
{
s_customizationPickupType = FindType("CharacterCustomization.CustomizationPickup");
}
return s_customizationPickupType;
}
private static Type GetCustomCaseItemUnlockType()
{
if (s_customCaseItemUnlockType == null)
{
s_customCaseItemUnlockType = FindType("ValkoGames.Labyrinthine.Cases.Custom.CustomCaseItemUnlock");
}
return s_customCaseItemUnlockType;
}
private static Type GetCustomizationManagerType()
{
if (s_customizationManagerType == null)
{
s_customizationManagerType = FindType("CharacterCustomization.CustomizationManager");
}
return s_customizationManagerType;
}
private static Type GetLocalisationManagerType()
{
if (s_localisationManagerType == null)
{
s_localisationManagerType = FindType("Localisation.LocalisationManager") ?? FindType("LocalisationManager");
}
return s_localisationManagerType;
}
private static Type GetObjectiveUiType()
{
if (s_objectiveUiType == null)
{
s_objectiveUiType = FindType("Objectives.ObjectiveUI");
}
return s_objectiveUiType;
}
private static Type GetTmpTextType()
{
if (s_tmpTextType == null)
{
s_tmpTextType = FindTmpType("TMP_Text");
}
return s_tmpTextType;
}
private static Type GetTextMeshProUguiType()
{
if (s_textMeshProUguiType == null)
{
s_textMeshProUguiType = FindTmpType("TextMeshProUGUI");
}
return s_textMeshProUguiType;
}
private static Type GetCanvasType()
{
if (s_canvasType == null)
{
s_canvasType = FindType("UnityEngine.Canvas");
}
return s_canvasType;
}
private static Type FindTmpType(string typeName)
{
return FindType("Il2CppTMPro." + typeName) ?? FindType("TMPro." + typeName);
}
private static Type FindType(string fullName)
{
string il2cppName = (fullName.StartsWith("Il2Cpp.", StringComparison.Ordinal) ? fullName : ("Il2Cpp." + fullName));
string shortName = (fullName.Contains(".") ? fullName.Substring(fullName.LastIndexOf('.') + 1) : fullName);
Type type = Type.GetType(fullName) ?? Type.GetType(il2cppName);
if (type != null)
{
return type;
}
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly assembly in assemblies)
{
Type type2 = assembly.GetType(fullName, throwOnError: false) ?? assembly.GetType(il2cppName, throwOnError: false);
if (type2 != null)
{
return type2;
}
}
assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly assembly2 in assemblies)
{
Type[] source;
try
{
source = assembly2.GetTypes();
}
catch (ReflectionTypeLoadException ex)
{
source = ex.Types.Where((Type t) => t != null).ToArray();
}
catch
{
continue;
}
Type type3 = source.FirstOrDefault((Type t) => t.Name == shortName || t.FullName == fullName || t.FullName == il2cppName);
if (type3 != null)
{
return type3;
}
}
return null;
}
private static object GetStaticFieldOrProp(Type type, string name)
{
if (type == null)
{
return null;
}
try
{
PropertyInfo property = type.GetProperty(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
if (property != null)
{
return property.GetValue(null);
}
}
catch
{
}
try
{
return type.GetField(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(null);
}
catch
{
return null;
}
}
private static object GetFieldOrProp(object obj, string name)
{
if (obj == null)
{
return null;
}
Type type = obj.GetType();
try
{
PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (property != null)
{
return property.GetValue(obj);
}
}
catch
{
}
try
{
return type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(obj);
}
catch
{
return null;
}
}
private static bool SetFieldOrProp(object obj, string name, object value)
{
if (obj == null)
{
return false;
}
Type type = obj.GetType();
try
{
PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (property != null && property.CanWrite)
{
property.SetValue(obj, value);
return true;
}
}
catch
{
}
try
{
FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (field != null)
{
field.SetValue(obj, value);
return true;
}
}
catch
{
}
return false;
}
private static object FindFirstObjectOfType(Type type)
{
if (type == null)
{
return null;
}
try
{
foreach (object item in EnumerateItems(((s_objectType ?? FindType("UnityEngine.Object"))?.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "FindObjectsOfType" && !m.ContainsGenericParameters && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == typeof(Type)))?.Invoke(null, new object[1] { type })))
{
if (item != null)
{
return item;
}
}
}
catch
{
}
return null;
}
private static void ForEachListItem(object list, Action<object> action)
{
foreach (object item in EnumerateItems(list))
{
action(item);
}
}
private static IEnumerable<object> EnumerateItems(object list)
{
if (list == null)
{
yield break;
}
if (list is Array array)
{
foreach (object item in array)
{
yield return item;
}
yield break;
}
if (list is IEnumerable enumerable)
{
foreach (object item2 in enumerable)
{
yield return item2;
}
yield break;
}
if (!TryConvertInt(GetFieldOrProp(list, "Count"), out var count))
{
TryConvertInt(GetFieldOrProp(list, "Length"), out count);
}
if (count <= 0)
{
yield break;
}
MethodInfo getItem = list.GetType().GetMethod("get_Item", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (getItem == null)
{
yield break;
}
for (int i = 0; i < count; i++)
{
object obj = null;
try
{
obj = getItem.Invoke(list, new object[1] { i });
}
catch
{
}
if (obj != null)
{
yield return obj;
}
}
}
private static bool TryConvertInt(object value, out int result)
{
try
{
if (value == null)
{
result = 0;
return false;
}
result = Convert.ToInt32(value);
return true;
}
catch
{
result = 0;
return false;
}
}
private static bool TryConvertFloat(object value, out float result)
{
try
{
if (value == null)
{
result = 0f;
return false;
}
result = Convert.ToSingle(value);
return true;
}
catch
{
result = 0f;
return false;
}
}
private static bool TryConvertBool(object value, out bool result)
{
try
{
if (value == null)
{
result = false;
return false;
}
result = Convert.ToBoolean(value);
return true;
}
catch
{
result = false;
return false;
}
}
private static void LogOverlayRenderer(string renderer, string details)
{
string b = renderer + "|" + details;
if (!string.Equals(s_lastLoggedRendererSignature, b, StringComparison.Ordinal))
{
s_lastLoggedRendererSignature = b;
LogDebug("Pickup overlay renderer=" + renderer + " " + details);
}
}
private static string GetFallbackRendererReason()
{
if (!IsTextMeshProOverlayEnabled())
{
return "reason=TextMeshPro disabled";
}
if (s_tmpOverlayFailed)
{
return "reason=TextMeshPro unavailable/retrying";
}
if (!s_tmpOverlayReady)
{
return "reason=TextMeshPro not ready";
}
return "reason=TextMeshPro ready";
}
private static string DescribeTextStyleForLog(ObjectiveTextStyle style)
{
string text = (string.IsNullOrWhiteSpace(style.Source) ? "unknown" : style.Source);
return "styleSource=" + text + " headerFont=" + style.HeaderFontSize + " rowFont=" + style.RowFontSize + " footerFont=" + style.FooterFontSize + " tmpSource={" + DescribeTmpTextSource(style.SourceText) + "}";
}
private static string DescribeTmpTextSource(object tmpText)
{
if (tmpText == null)
{
return "none";
}
try
{
string text = GetUnityObjectName(GetFieldOrProp(tmpText, "gameObject")) ?? GetUnityObjectName(tmpText) ?? tmpText.GetType().Name;
string text2 = GetFieldOrProp(tmpText, "text") as string;
float result;
string text3 = (TryConvertFloat(GetFieldOrProp(tmpText, "fontSize"), out result) ? result.ToString("0.##") : "?");
string text4 = GetCanvasScaleFactor(tmpText).ToString("0.##");
return "name='" + TruncateForLog(text, 60) + "' fontSize=" + text3 + " canvasScale=" + text4 + " text='" + TruncateForLog(text2, 60) + "'";
}
catch
{
return tmpText.GetType().Name;
}
}
private static string DescribeRectTransform(object rectTransform)
{
if (rectTransform == null)
{
return "none";
}
try
{
object fieldOrProp = GetFieldOrProp(rectTransform, "rect");
return "name='" + TruncateForLog(GetUnityObjectName(rectTransform), 50) + "' anchorMin=" + DescribeVector(GetFieldOrProp(rectTransform, "anchorMin")) + " anchorMax=" + DescribeVector(GetFieldOrProp(rectTransform, "anchorMax")) + " pivot=" + DescribeVector(GetFieldOrProp(rectTransform, "pivot")) + " anchoredPosition=" + DescribeVector(GetFieldOrProp(rectTransform, "anchoredPosition")) + " sizeDelta=" + DescribeVector(GetFieldOrProp(rectTransform, "sizeDelta")) + " rect=" + DescribeRect(fieldOrProp);
}
catch
{
return rectTransform.GetType().Name;
}
}
private static string DescribeRect(object rect)
{
if (rect == null)
{
return "none";
}
float result;
string obj = (TryConvertFloat(GetFieldOrProp(rect, "width"), out result) ? result.ToString("0.#") : "?");
float result2;
string text = (TryConvertFloat(GetFieldOrProp(rect, "height"), out result2) ? result2.ToString("0.#") : "?");
return obj + "x" + text;
}
private static string DescribeVector(object vector)
{
if (vector == null)
{
return "none";
}
float result;
bool num = TryConvertFloat(GetFieldOrProp(vector, "x"), out result);
float result2;
bool flag = TryConvertFloat(GetFieldOrProp(vector, "y"), out result2);
float result3;
bool flag2 = TryConvertFloat(GetFieldOrProp(vector, "z"), out result3);
if (!num && !flag && !flag2)
{
return vector.ToString();
}
if (!flag2)
{
return "(" + result.ToString("0.###") + "," + result2.ToString("0.###") + ")";
}
return "(" + result.ToString("0.###") + "," + result2.ToString("0.###") + "," + result3.ToString("0.###") + ")";
}
private static bool IsPickupTmpOverlayObject(object tmpText)
{
if (tmpText == null)
{
return false;
}
if (tmpText == s_tmpOverlayText)
{
return true;
}
object fieldOrProp = GetFieldOrProp(tmpText, "gameObject");
if (fieldOrProp == s_tmpOverlayTextObject || fieldOrProp == s_tmpOverlayRoot)
{
return true;
}
return (GetUnityObjectName(fieldOrProp) ?? string.Empty).IndexOf("kp0hyc PickupTabOverlay", StringComparison.OrdinalIgnoreCase) >= 0;
}
private static string GetUnityObjectName(object obj)
{
if (obj == null)
{
return null;
}
try
{
string text = GetFieldOrProp(obj, "name") as string;
if (!string.IsNullOrWhiteSpace(text))
{
return text.Trim();
}
object fieldOrProp = GetFieldOrProp(obj, "gameObject");
if (fieldOrProp != null && fieldOrProp != obj)
{
text = GetFieldOrProp(fieldOrProp, "name") as string;
if (!string.IsNullOrWhiteSpace(text))
{
return text.Trim();
}
}
}
catch
{
}
return null;
}
private static string TruncateForLog(string text, int maxLength)
{
if (string.IsNullOrWhiteSpace(text))
{
return string.Empty;
}
string text2 = text.Replace("\r", " ").Replace("\n", " ").Trim();
if (text2.Length <= maxLength)
{
return text2;
}
return text2.Substring(0, Math.Max(0, maxLength - 3)) + "...";
}
private static string TypeNameForLog(Type type)
{
object obj;
if (!(type == null))
{
obj = type.FullName;
if (obj == null)
{
return type.Name;
}
}
else
{
obj = "null";
}
return (string)obj;
}
private static int Clamp(int value, int min, int max)
{
if (value < min)
{
return min;
}
if (value <= max)
{
return value;
}
return max;
}
private static float Clamp(float value, float min, float max)
{
if (value < min)
{
return min;
}
if (!(value > max))
{
return value;
}
return max;
}
private static float Clamp01(float value)
{
if (value < 0f)
{
return 0f;
}
if (!(value > 1f))
{
return value;
}
return 1f;
}
private static void LogWarning(string message)
{
if (!(DateTime.UtcNow < s_nextWarningUtc))
{
s_nextWarningUtc = DateTime.UtcNow.AddSeconds(10.0);
MelonLogger.Warning(message);
}
}
private static void LogDebug(string message)
{
if (IsDebugLoggingEnabled())
{
MelonLogger.Msg("[Debug] " + message);
}
}
private static bool IsDebugLoggingEnabled()
{
if (s_debugLogging == null || !s_debugLogging.Value)
{
if (s_legacyDebugLogging != null)
{
return s_legacyDebugLogging.Value;
}
return false;
}
return true;
}
}