Decompiled source of ChuxiaDebug v1.0.6

ChuxiaDebug.dll

Decompiled 3 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using ChuxiaDebug;
using GameNetcodeStuff;
using HarmonyLib;
using TMPro;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("ChuxiaDebug")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ChuxiaDebug")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("60d2b7e4-0b76-440e-98cb-261563a44ec3")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
[BepInPlugin("ChuxiaDebug", "chuxia.ChuxiaDebug", "1.0.6")]
public class ChuxiaDebugPlugin : BaseUnityPlugin
{
	public static ConfigEntry<bool> EnableColor;

	public static ConfigEntry<string> OpenTabs;

	public void Awake()
	{
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0050: Expected O, but got Unknown
		EnableColor = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableColor", false, "Enable color.");
		OpenTabs = ((BaseUnityPlugin)this).Config.Bind<string>("General", "OpenTabs", "", "");
		Harmony val = new Harmony("chuxia.ChuxiaDebug");
		val.PatchAll(typeof(Patches));
	}
}
public static class Patches
{
	private static GameObject ChuxiaDebugMono { get; set; }

	[HarmonyPostfix]
	[HarmonyPatch(typeof(MenuManager), "Awake")]
	public static void ConnectClientToPlayerObjectPostfix(PlayerControllerB __instance)
	{
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Expected O, but got Unknown
		if ((Object)(object)ChuxiaDebugMono == (Object)null)
		{
			ChuxiaDebugMono = new GameObject("ChuxiaDebugMono");
			ChuxiaDebugMono chuxiaDebugMono = ChuxiaDebugMono.AddComponent<ChuxiaDebugMono>();
			Object.DontDestroyOnLoad((Object)(object)ChuxiaDebugMono);
		}
	}
}
namespace ChuxiaDebug;

internal class ChuxiaDebugMono : MonoBehaviour
{
	private class DebugTab
	{
		public string Name;

		public Action DrawAction;

		public bool IsClosable;

		public DebugTab(string name, Action drawAction, bool isClosable = true)
		{
			Name = name;
			DrawAction = drawAction;
			IsClosable = isClosable;
		}
	}

	private enum MemberType
	{
		Field,
		Property,
		Method
	}

	private class MemberAccessor
	{
		public string Name;

		public MemberType Type;

		public Func<object, object> Getter;

		public Action<object> MethodInvoker;

		public MethodInfo MethodInfo;

		public string TypeName { get; set; }

		public string TypeNamespace { get; set; }

		public string DeclaringName { get; set; }
	}

	private List<DebugTab> openedTabs = new List<DebugTab>();

	private int selectedTabIndex = -1;

	public static ChuxiaDebugMono Instance;

	private Dictionary<string, Action> tabFuncs = new Dictionary<string, Action>();

	private float lastFieldUpdateTime = 0f;

	private bool realtimeUpdate = true;

	private List<(MemberAccessor accessor, object value)> cachedFieldValues = new List<(MemberAccessor, object)>();

	private string searchFieldText = "";

	private Stack<object> objectStack = new Stack<object>();

	private Vector2 scrollPosition = Vector2.zero;

	private Dictionary<Type, Object> cachedObjects = new Dictionary<Type, Object>();

	private List<Type> allTypes;

	private string searchInput = "";

	private List<Type> searchResults = new List<Type>();

	private Vector2 searchScroll;

	private Vector2 tabScrollPos = Vector2.zero;

	private object pendingPushObject = null;

	private string pendingCollectionBackLabel = "";

	private static Dictionary<Type, List<MemberAccessor>> memberCache = new Dictionary<Type, List<MemberAccessor>>();

	private static bool Gui { get; set; }

	private void AddTab(string tabName)
	{
		if (!openedTabs.Any((DebugTab t) => t.Name == tabName) && tabFuncs.TryGetValue(tabName, out var value))
		{
			openedTabs.Add(new DebugTab(tabName, value));
			selectedTabIndex = openedTabs.Count - 1;
		}
	}

	public void SetCurrentObject(object obj)
	{
		objectStack.Clear();
		if (obj != null)
		{
			objectStack.Push(obj);
		}
	}

	private Object GetCachedObject(Type type)
	{
		if (!cachedObjects.TryGetValue(type, out var value) || value == (Object)null)
		{
			value = Object.FindAnyObjectByType(type);
			cachedObjects[type] = value;
		}
		return value;
	}

	private T GetCachedObject<T>() where T : Object
	{
		Type typeFromHandle = typeof(T);
		if (!cachedObjects.TryGetValue(typeFromHandle, out var value) || value == (Object)null)
		{
			value = (Object)(object)Object.FindAnyObjectByType<T>();
			cachedObjects[typeFromHandle] = value;
		}
		return (T)(object)value;
	}

	private void Awake()
	{
		allTypes = (from t in AppDomain.CurrentDomain.GetAssemblies().SelectMany(delegate(Assembly assembly)
			{
				try
				{
					return assembly.GetTypes();
				}
				catch
				{
					return Array.Empty<Type>();
				}
			})
			where t.IsClass && !t.IsAbstract && typeof(Object).IsAssignableFrom(t)
			select t).ToList();
		tabFuncs = new Dictionary<string, Action>();
		tabFuncs["RoundManager"] = delegate
		{
			DrawSingleObjectTab(RoundManager.Instance);
		};
		tabFuncs["GameNetworkManager"] = delegate
		{
			DrawSingleObjectTab(GameNetworkManager.Instance);
		};
		tabFuncs["HUDManager"] = delegate
		{
			DrawSingleObjectTab(HUDManager.Instance);
		};
		tabFuncs["ShipBuildModeManager"] = delegate
		{
			DrawSingleObjectTab(ShipBuildModeManager.Instance);
		};
		tabFuncs["SoundManager"] = delegate
		{
			DrawSingleObjectTab(SoundManager.Instance);
		};
		tabFuncs["MenuManager"] = delegate
		{
			DrawSingleObjectTab(GetCachedObject<MenuManager>());
		};
		tabFuncs["QuickMenuManager"] = delegate
		{
			DrawSingleObjectTab(GetCachedObject<QuickMenuManager>());
		};
		tabFuncs["StartOfRound"] = delegate
		{
			DrawSingleObjectTab(StartOfRound.Instance);
		};
		tabFuncs["TimeOfDay"] = delegate
		{
			DrawSingleObjectTab(TimeOfDay.Instance);
		};
		tabFuncs["StartMatchLever"] = delegate
		{
			DrawSingleObjectTab(GetCachedObject<StartMatchLever>());
		};
		tabFuncs["Terminal"] = delegate
		{
			DrawSingleObjectTab(GetCachedObject<Terminal>());
		};
		tabFuncs["MapScreen"] = delegate
		{
			DrawSingleObjectTab(StartOfRound.Instance?.mapScreen);
		};
		openedTabs.Add(new DebugTab("Default", DrawDefaultTab, isClosable: false));
		openedTabs.Add(new DebugTab("Search", DrawSearchTab, isClosable: false));
		string[] array = ChuxiaDebugPlugin.OpenTabs?.Value?.Split(new char[1] { ',' });
		if (array != null)
		{
			string[] array2 = array;
			foreach (string tabName in array2)
			{
				if (tabFuncs.TryGetValue(tabName, out var value))
				{
					openedTabs.Add(new DebugTab(tabName, value));
					continue;
				}
				Type type = allTypes.FirstOrDefault((Type t) => t.Name == tabName);
				if (!(type != null))
				{
					continue;
				}
				Object instance = GetCachedObject(type);
				if (instance != (Object)null)
				{
					openedTabs.Add(new DebugTab(tabName, delegate
					{
						DrawSingleObjectTab(instance);
					}));
				}
			}
		}
		selectedTabIndex = 0;
		Instance = this;
	}

	private void UpdateSavedOpenTabs()
	{
		IEnumerable<string> values = from t in openedTabs
			where t.IsClosable
			select t.Name;
		ChuxiaDebugPlugin.OpenTabs.Value = string.Join(",", values);
	}

	private void DrawDefaultTab()
	{
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0044: Unknown result type (might be due to invalid IL or missing references)
		ChuxiaDebugPlugin.EnableColor.Value = GUILayout.Toggle(ChuxiaDebugPlugin.EnableColor.Value, "EnableColor", Array.Empty<GUILayoutOption>());
		scrollPosition = GUILayout.BeginScrollView(scrollPosition, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(500f) });
		foreach (KeyValuePair<string, Action> kvp in tabFuncs)
		{
			if (!openedTabs.Any((DebugTab t) => t.Name == kvp.Key) && GUILayout.Button(kvp.Key ?? "", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) }))
			{
				openedTabs.Add(new DebugTab(kvp.Key, kvp.Value));
				selectedTabIndex = openedTabs.Count - 1;
				UpdateSavedOpenTabs();
				break;
			}
		}
		GUILayout.EndScrollView();
	}

	private void DrawSearchTab()
	{
		//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0110: Unknown result type (might be due to invalid IL or missing references)
		//IL_0115: Unknown result type (might be due to invalid IL or missing references)
		GUILayout.Label("Search Type:", Array.Empty<GUILayoutOption>());
		GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
		searchInput = GUILayout.TextField(searchInput, Array.Empty<GUILayoutOption>());
		if (GUILayout.Button("Search", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(100f) }))
		{
			if (!string.IsNullOrWhiteSpace(searchInput))
			{
				string lowerInput = searchInput.ToLowerInvariant();
				searchResults = (from t in allTypes
					where t.Name.ToLowerInvariant().Contains(lowerInput)
					orderby t.Name
					select t).ToList();
			}
			else
			{
				searchResults.Clear();
			}
		}
		GUILayout.EndHorizontal();
		if (searchResults.Count == 0)
		{
			return;
		}
		searchScroll = GUILayout.BeginScrollView(searchScroll, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(500f) });
		foreach (Type searchResult in searchResults)
		{
			Object[] array = Object.FindObjectsByType(searchResult, (FindObjectsSortMode)1);
			foreach (Object item in array)
			{
				if (GUILayout.Button(searchResult.Name, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(25f) }))
				{
					openedTabs.Add(new DebugTab(searchResult.Name, delegate
					{
						DrawSingleObjectTab(item);
					}));
					selectedTabIndex = openedTabs.Count - 1;
					UpdateSavedOpenTabs();
				}
			}
		}
		GUILayout.EndScrollView();
	}

	public static void String(string text, GUIStyle style, float yPos)
	{
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0014: Expected O, but got Unknown
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		float num = Screen.width;
		Vector2 val = style.CalcSize(new GUIContent(text));
		float num2 = (num - val.x) / 2f;
		GUI.Label(new Rect(num2, yPos, val.x, val.y), text, style);
	}

	public void Update()
	{
		if (UnityInput.Current.GetKeyDown((KeyCode)291))
		{
			Gui = !Gui;
			if (Cursor.visible && !Gui)
			{
				Cursor.visible = false;
				Cursor.lockState = (CursorLockMode)1;
			}
		}
		if (!Cursor.visible && Gui)
		{
			Cursor.visible = true;
			Cursor.lockState = (CursorLockMode)0;
		}
	}

	public void OnGUI()
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0043: Unknown result type (might be due to invalid IL or missing references)
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: Expected O, but got Unknown
		Scene activeScene = SceneManager.GetActiveScene();
		Color backgroundColor = default(Color);
		((Color)(ref backgroundColor))..ctor(0.09019608f, 0.09019608f, 0.09019608f, 1f);
		GUI.backgroundColor = backgroundColor;
		GUI.contentColor = Color.white;
		GUIStyle val = new GUIStyle(GUI.skin.label);
		val.normal.textColor = Color.white;
		val.fontStyle = (FontStyle)1;
		GUIStyle style = val;
		if (!Gui)
		{
			String("ChuxiaDebug Press F10", style, 10f);
		}
		else
		{
			ShowMenu();
		}
	}

	private void DrawDebugWindow(int windowId)
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		//IL_006a: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			GUILayout.BeginVertical(Array.Empty<GUILayoutOption>());
			try
			{
				tabScrollPos = GUILayout.BeginScrollView(tabScrollPos, (GUILayoutOption[])(object)new GUILayoutOption[2]
				{
					GUILayout.Height(40f),
					GUILayout.ExpandWidth(true)
				});
				try
				{
					GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
					try
					{
						for (int i = 0; i < openedTabs.Count; i++)
						{
							DebugTab debugTab = openedTabs[i];
							GUI.backgroundColor = ((i == selectedTabIndex) ? Color.green : Color.white);
							if (GUILayout.Button(debugTab.Name, (GUILayoutOption[])(object)new GUILayoutOption[2]
							{
								GUILayout.Width(150f),
								GUILayout.Height(30f)
							}))
							{
								selectedTabIndex = i;
								scrollPosition = Vector2.zero;
								searchFieldText = "";
								objectStack.Clear();
								cachedFieldValues.Clear();
							}
							GUI.backgroundColor = Color.white;
							if (debugTab.IsClosable && GUILayout.Button("x", (GUILayoutOption[])(object)new GUILayoutOption[2]
							{
								GUILayout.Width(20f),
								GUILayout.Height(30f)
							}))
							{
								openedTabs.RemoveAt(i);
								if (selectedTabIndex >= i)
								{
									selectedTabIndex = Mathf.Max(0, selectedTabIndex - 1);
								}
								UpdateSavedOpenTabs();
								break;
							}
						}
					}
					finally
					{
						GUILayout.EndHorizontal();
					}
				}
				finally
				{
					GUILayout.EndScrollView();
				}
				GUILayout.Space(10f);
				if (selectedTabIndex >= 0 && selectedTabIndex < openedTabs.Count)
				{
					openedTabs[selectedTabIndex].DrawAction?.Invoke();
				}
			}
			finally
			{
				GUILayout.EndVertical();
			}
			GUI.DragWindow();
		}
		catch (Exception arg)
		{
			Debug.LogError((object)$"ChuxiaDebug: Error in DrawDebugWindow. GUI may be broken.\n{arg}");
		}
	}

	public void ShowMenu()
	{
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_0040: Expected O, but got Unknown
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		float num = (float)(Screen.width - 1500) / 2f;
		GUI.Window(0, new Rect(num, 10f, 1500f, 600f), new WindowFunction(DrawDebugWindow), "ChuxiaDebug");
	}

	public void DrawSingleObjectTab(object obj)
	{
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		if (obj != null)
		{
			if (objectStack.Count == 0)
			{
				objectStack.Push(obj);
				scrollPosition = Vector2.zero;
				searchFieldText = "";
			}
			DrawObjectFields();
		}
	}

	private void PushOrExpandObject(object obj, string fallbackLabel = "Back")
	{
		//IL_009f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		if (obj is IEnumerable source && !(obj is string))
		{
			Debug.Log((object)203);
			List<object> item = source.Cast<object>().ToList();
			objectStack.Clear();
			cachedFieldValues.Clear();
			objectStack.Push(item);
			pendingCollectionBackLabel = fallbackLabel;
			scrollPosition = Vector2.zero;
			searchFieldText = "";
		}
		else
		{
			Debug.Log((object)218);
			objectStack.Push(obj);
			scrollPosition = Vector2.zero;
			searchFieldText = "";
		}
	}

	public void DrawObjectListTab<T>(IEnumerable<T> items, Func<T, string> getName, string backButtonLabel)
	{
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0102: Unknown result type (might be due to invalid IL or missing references)
		//IL_0092: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		if (objectStack.Count == 0)
		{
			scrollPosition = GUILayout.BeginScrollView(scrollPosition, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(500f) });
			foreach (T item in items)
			{
				string text = getName(item);
				if (GUILayout.Button(text, Array.Empty<GUILayoutOption>()))
				{
					objectStack.Clear();
					cachedFieldValues.Clear();
					objectStack.Push(item);
					scrollPosition = Vector2.zero;
					searchFieldText = "";
				}
			}
			GUILayout.EndScrollView();
		}
		else if (GUILayout.Button("← " + backButtonLabel, Array.Empty<GUILayoutOption>()))
		{
			objectStack.Clear();
			cachedFieldValues.Clear();
			scrollPosition = Vector2.zero;
			searchFieldText = "";
		}
		else
		{
			DrawObjectFields();
		}
	}

	public void PlayerTab()
	{
		DrawObjectListTab(StartOfRound.Instance.allPlayerScripts, (PlayerControllerB player) => player.playerUsername, "Back To allPlayerScripts");
	}

	public void ItemListTab()
	{
		DrawObjectListTab(StartOfRound.Instance.allItemsList.itemsList, (Item item) => item.itemName, "Back To ItemList");
	}

	private string ObjectToName(object obj)
	{
		if (obj == null && ChuxiaDebugPlugin.EnableColor.Value)
		{
			return "<color=grey>null</color>";
		}
		if (obj == null)
		{
			return "null";
		}
		if (obj is IList list && list != null)
		{
			return $"[{list.Count}] ";
		}
		if (obj is ICollection collection && collection != null)
		{
			return $"[{collection.Count}] ";
		}
		if (obj is IDictionary dictionary && dictionary != null)
		{
			return $"[{dictionary.Count}] ";
		}
		PlayerControllerB val = (PlayerControllerB)((obj is PlayerControllerB) ? obj : null);
		if (val != null)
		{
			return $"{val.playerUsername}({val.playerClientId})";
		}
		UnlockableItem val2 = (UnlockableItem)((obj is UnlockableItem) ? obj : null);
		if (val2 != null)
		{
			return val2.unlockableName ?? "";
		}
		GrabbableObject val3 = (GrabbableObject)((obj is GrabbableObject) ? obj : null);
		if (val3 != null)
		{
			return val3?.itemProperties.itemName ?? "";
		}
		WeatherEffect val4 = (WeatherEffect)((obj is WeatherEffect) ? obj : null);
		if (val4 != null)
		{
			return val4.name ?? "";
		}
		TextMeshProUGUI val5 = (TextMeshProUGUI)((obj is TextMeshProUGUI) ? obj : null);
		if (val5 != null)
		{
			return ((val5 != null) ? ((TMP_Text)val5).text : null) ?? "null";
		}
		Slider val6 = (Slider)((obj is Slider) ? obj : null);
		if (val6 != null)
		{
			return $"{((val6 != null) ? new float?(val6.value) : null):F2}";
		}
		GameObject val7 = (GameObject)((obj is GameObject) ? obj : null);
		if (val7 != null)
		{
			return "\"" + ((val7 != null) ? ((Object)val7).name : null) + "\" ";
		}
		if (obj is string && ChuxiaDebugPlugin.EnableColor.Value)
		{
			return $"<color=#C57160>\"{obj}\"</color>";
		}
		if (obj is string)
		{
			return $"\"{obj}\"";
		}
		if ((obj is bool || obj is bool) && ChuxiaDebugPlugin.EnableColor.Value)
		{
			return $"<color=#3599D0>{obj}</color>";
		}
		if (obj is bool || obj is bool)
		{
			return $"{obj}";
		}
		Object val8 = (Object)((obj is Object) ? obj : null);
		if (val8 != null)
		{
			if (val8 == (Object)null)
			{
				return "null";
			}
			return "\"" + ((val8 != null) ? val8.name : null) + "\"";
		}
		return obj?.ToString() ?? "null";
	}

	private void DrawObjectFields()
	{
		//IL_0466: Unknown result type (might be due to invalid IL or missing references)
		//IL_046b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0475: Expected O, but got Unknown
		//IL_0159: Unknown result type (might be due to invalid IL or missing references)
		//IL_016a: Unknown result type (might be due to invalid IL or missing references)
		//IL_017b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0222: Unknown result type (might be due to invalid IL or missing references)
		//IL_0227: Unknown result type (might be due to invalid IL or missing references)
		//IL_03aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_03c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_03c7: Unknown result type (might be due to invalid IL or missing references)
		if (objectStack.Count == 0 || objectStack.Peek() == null)
		{
			return;
		}
		object obj = objectStack.Peek();
		Object val = (Object)((obj is Object) ? obj : null);
		if (val != null && val == (Object)null)
		{
			objectStack.Pop();
			objectStack.Push(null);
			return;
		}
		if (obj is IList items && !(obj is string))
		{
			DrawObjectListTab(items, (object o) => ObjectToName(o) ?? "null", pendingCollectionBackLabel);
			return;
		}
		Type type = obj.GetType();
		List<MemberAccessor> memberAccessors = GetMemberAccessors(type);
		if ((realtimeUpdate && Time.unscaledTime - lastFieldUpdateTime > 0.1f) || cachedFieldValues.Count == 0)
		{
			cachedFieldValues.Clear();
			foreach (MemberAccessor item in memberAccessors)
			{
				object obj2 = null;
				try
				{
					obj2 = ((item.Type == MemberType.Method) ? "<Func>" : item.Getter(obj));
					Transform val2 = (Transform)((obj2 is Transform) ? obj2 : null);
					if (val2 != null)
					{
						obj2 = $"({val2.position.x:F2}, {val2.position.y:F2}, {val2.position.z:F2})";
					}
				}
				catch
				{
					obj2 = "<Fail>";
				}
				cachedFieldValues.Add((item, obj2));
			}
			lastFieldUpdateTime = Time.unscaledTime;
		}
		GUILayout.Space(10f);
		if (objectStack.Count > 1 && GUILayout.Button("← Back", Array.Empty<GUILayoutOption>()))
		{
			objectStack.Pop();
			scrollPosition = Vector2.zero;
			searchFieldText = "";
			return;
		}
		GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
		GUILayout.Label(ObjectToName(obj) ?? "", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) });
		realtimeUpdate = GUILayout.Toggle(realtimeUpdate, "Auto-Update", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(100f) });
		GUILayout.EndHorizontal();
		GUILayout.Space(5f);
		GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
		GUILayout.Label("Search: ", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) });
		string text = GUILayout.TextField(searchFieldText, Array.Empty<GUILayoutOption>());
		GUILayout.EndHorizontal();
		if (text != searchFieldText)
		{
			searchFieldText = text;
		}
		List<(MemberAccessor, object)> list = cachedFieldValues.Where(((MemberAccessor accessor, object value) kv) => string.IsNullOrEmpty(searchFieldText) || kv.accessor.Name.IndexOf(searchFieldText, StringComparison.OrdinalIgnoreCase) >= 0).ToList();
		int count = list.Count;
		int num = Mathf.CeilToInt(16.666666f);
		int num2 = Mathf.Clamp(Mathf.FloorToInt(scrollPosition.y / 30f), 0, Math.Max(0, count - 1));
		int num3 = Mathf.Clamp(num2 + num + 2, 0, count);
		scrollPosition.y = Mathf.Clamp(scrollPosition.y, 0f, Mathf.Max(0f, (float)count * 30f - 500f));
		scrollPosition = GUILayout.BeginScrollView(scrollPosition, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(500f) });
		GUILayout.BeginVertical(GUIStyle.op_Implicit("box"), Array.Empty<GUILayoutOption>());
		if (count == 0)
		{
			GUILayout.Label("No Fields", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) });
		}
		else
		{
			GUILayout.Space((float)num2 * 30f);
			for (int i = num2; i < num3; i++)
			{
				var (memberAccessor, obj4) = list[i];
				GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) });
				GUIStyle val3 = new GUIStyle(GUI.skin.label)
				{
					wordWrap = false
				};
				if (ChuxiaDebugPlugin.EnableColor.Value)
				{
					string text2 = "";
					switch (memberAccessor.Type)
					{
					case MemberType.Field:
						text2 = "#3C8372";
						break;
					case MemberType.Property:
						text2 = "#673688";
						break;
					case MemberType.Method:
						text2 = "#884404";
						break;
					}
					val3.richText = true;
					string text3 = "<color=#27C890>" + memberAccessor.DeclaringName + "<color=white>.</color></color><color=" + text2 + ">" + memberAccessor.Name + "</color>";
					GUILayout.Label(text3, val3, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(400f) });
				}
				else
				{
					GUILayout.Label(memberAccessor.DeclaringName + "." + memberAccessor.Name, val3, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(400f) });
				}
				string text4 = ObjectToName(obj4) ?? "NULL";
				text4 = ((!ChuxiaDebugPlugin.EnableColor.Value) ? (text4 + " (" + memberAccessor.TypeNamespace + "." + memberAccessor.TypeName + ")") : (text4 + " (<color=grey>" + memberAccessor.TypeNamespace + "</color>.<color=#179932>" + memberAccessor.TypeName + "</color>)"));
				GUILayout.Label(text4.Replace("\n", "\\n"), val3, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
				if (memberAccessor.Type != MemberType.Method && GUILayout.Button("Copy", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) }))
				{
					GUIUtility.systemCopyBuffer = obj4?.ToString() ?? "";
				}
				if (memberAccessor.Type == MemberType.Method)
				{
					if (GUILayout.Button("Invoke", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) }))
					{
						try
						{
							memberAccessor.MethodInvoker?.Invoke(obj);
							Debug.Log((object)("调用方法成功: " + memberAccessor.Name));
						}
						catch (Exception arg)
						{
							Debug.LogError((object)$"调用方法失败: {memberAccessor.Name}, 异常: {arg}");
						}
					}
					GUILayout.Space(60f);
				}
				else if (obj4 != null && obj4 != obj)
				{
					if (GUILayout.Button("Inject", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) }))
					{
						pendingPushObject = obj4;
						pendingCollectionBackLabel = "Back To " + ObjectToName(obj);
					}
				}
				else
				{
					GUILayout.Space(60f);
				}
				GUILayout.EndHorizontal();
			}
			float num4 = Mathf.Max(0f, (float)(count - num3) * 30f);
			GUILayout.Space(Mathf.Max(0f, num4));
		}
		GUILayout.EndVertical();
		GUILayout.EndScrollView();
		if (pendingPushObject != null)
		{
			PushOrExpandObject(pendingPushObject, pendingCollectionBackLabel);
			pendingPushObject = null;
		}
	}

	public void DrawObjectListTab(IList items, Func<object, string> getName, string backButtonLabel)
	{
		//IL_007f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		//IL_009c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
		if (objectStack.Count == 0 || !(objectStack.Peek() is IList))
		{
			return;
		}
		if (GUILayout.Button("← " + backButtonLabel, Array.Empty<GUILayoutOption>()))
		{
			objectStack.Clear();
			cachedFieldValues.Clear();
			scrollPosition = Vector2.zero;
			searchFieldText = "";
			return;
		}
		scrollPosition = GUILayout.BeginScrollView(scrollPosition, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(500f) });
		for (int i = 0; i < items.Count; i++)
		{
			object obj = items[i];
			string text = $"[{i}] {getName(obj)}";
			if (GUILayout.Button(text, Array.Empty<GUILayoutOption>()))
			{
				objectStack.Push(obj);
				cachedFieldValues.Clear();
				scrollPosition = Vector2.zero;
				searchFieldText = "";
				break;
			}
		}
		GUILayout.EndScrollView();
	}

	private List<MemberAccessor> GetMemberAccessors(Type type)
	{
		if (memberCache.TryGetValue(type, out var value))
		{
			return value;
		}
		List<MemberAccessor> list = new List<MemberAccessor>();
		BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
		FieldInfo[] fields = type.GetFields(bindingAttr);
		foreach (FieldInfo fieldInfo in fields)
		{
			Func<object, object> getter = CreateGetter(fieldInfo);
			list.Add(new MemberAccessor
			{
				Name = fieldInfo.Name,
				Type = MemberType.Field,
				TypeNamespace = fieldInfo.FieldType.Namespace,
				TypeName = fieldInfo.FieldType.Name,
				DeclaringName = fieldInfo.DeclaringType.Name,
				Getter = getter,
				MethodInvoker = null
			});
		}
		PropertyInfo[] properties = type.GetProperties(bindingAttr);
		foreach (PropertyInfo propertyInfo in properties)
		{
			if (propertyInfo.CanRead && propertyInfo.GetIndexParameters().Length == 0)
			{
				Func<object, object> getter2 = CreateGetter(propertyInfo);
				list.Add(new MemberAccessor
				{
					Name = propertyInfo.Name,
					Type = MemberType.Property,
					TypeNamespace = propertyInfo.DeclaringType.Namespace,
					TypeName = propertyInfo.DeclaringType.Name,
					DeclaringName = propertyInfo.DeclaringType.Name,
					Getter = getter2,
					MethodInvoker = null
				});
			}
		}
		memberCache[type] = list;
		return list;
	}

	private Func<object, object> CreateGetter(FieldInfo field)
	{
		ParameterExpression parameterExpression = Expression.Parameter(typeof(object), "instance");
		MemberExpression expression = Expression.Field(Expression.Convert(parameterExpression, field.DeclaringType), field);
		UnaryExpression body = Expression.Convert(expression, typeof(object));
		return Expression.Lambda<Func<object, object>>(body, new ParameterExpression[1] { parameterExpression }).Compile();
	}

	private Func<object, object> CreateGetter(PropertyInfo prop)
	{
		ParameterExpression parameterExpression = Expression.Parameter(typeof(object), "instance");
		MemberExpression expression = Expression.Property(Expression.Convert(parameterExpression, prop.DeclaringType), prop);
		UnaryExpression body = Expression.Convert(expression, typeof(object));
		return Expression.Lambda<Func<object, object>>(body, new ParameterExpression[1] { parameterExpression }).Compile();
	}

	private Action<object> CreateMethodInvoker(MethodInfo method)
	{
		ParameterExpression parameterExpression = Expression.Parameter(typeof(object), "instance");
		MethodCallExpression body = Expression.Call(Expression.Convert(parameterExpression, method.DeclaringType), method);
		return Expression.Lambda<Action<object>>(body, new ParameterExpression[1] { parameterExpression }).Compile();
	}
}