Decompiled source of Unity Explorer Tree Snapshooter v0.0.1

UnityExplorerTreeSnapShooter.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using UnityExplorer;
using UnityExplorer.Inspectors;
using UnityExplorer.UI.Panels;
using UnityExplorerTreeSnapShooter.Models;
using UnityExplorerTreeSnapShooter.Services;
using UnityExplorerTreeSnapShooter.Services.Implementation;
using UnityExplorerTreeSnapShooter.UI;
using UniverseLib.UI;
using UniverseLib.UI.Models;
using UniverseLib.UI.Panels;
using UniverseLib.UI.Widgets;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("UnityExplorerTreeSnapshooter")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("UnityExplorerTreeSnapshooter")]
[assembly: AssemblyCopyright("Copyright © 2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("c5450fe0-edcf-483f-b9ea-4b1ef9d36da7")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace UnityExplorerTreeSnapShooter
{
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("gymmed.unity_tree_snap_shooter", "Unity Tree Snap Shooter", "0.0.1")]
	public class UnityExplorerTreeSnapShooter : BaseUnityPlugin
	{
		public const string GUID = "gymmed.unity_tree_snap_shooter";

		public const string NAME = "Unity Tree Snap Shooter";

		public const string VERSION = "0.0.1";

		public static readonly string Prefix = "[Unity-Tree-Snap-Shooter]";

		public const string EVENTS_LISTENER_GUID = "gymmed.unity_tree_snap_shooter_*";

		internal static ManualLogSource Log;

		internal void Awake()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			LogMessage("Hello world from Unity Tree Snap Shooter 0.0.1!");
			new Harmony("gymmed.unity_tree_snap_shooter").PatchAll();
		}

		internal void Update()
		{
		}

		public static void LogMessage(string message)
		{
			Log.LogMessage((object)(Prefix + " " + message));
		}

		public static string GetProjectLocation()
		{
			return Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
		}
	}
}
namespace UnityExplorerTreeSnapShooter.UI
{
	public class SnapShooterPanel : PanelBase
	{
		public static readonly string UIBaseGuid = "gymmed.unity_tree_snap_shooter.SnapShooterInspector";

		private Text _logText;

		private ISnapShooterService _snapShooterService;

		public static SnapShooterPanel Instance { get; private set; }

		public static UIBase UIBaseRegistry { get; set; }

		public override string Name => "Tree Snap Shooter";

		public override int MinWidth => 420;

		public override int MinHeight => 350;

		public override Vector2 DefaultAnchorMin => new Vector2(0.5f, 0.5f);

		public override Vector2 DefaultAnchorMax => new Vector2(0.5f, 0.5f);

		public InputFieldRef SavePath { get; private set; }

		public Text SelectionText { get; private set; }

		public override bool CanDragAndResize => true;

		public SnapShooterPanel(UIBase owner)
			: base(owner)
		{
			Instance = this;
		}

		protected override void ConstructPanelContent()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0273: Unknown result type (might be due to invalid IL or missing references)
			if (_snapShooterService == null)
			{
				FileSnapshotSaver saver = new FileSnapshotSaver(PathsManager.Instance);
				_snapShooterService = new TreeSnapShooterService(saver);
			}
			SelectionText = UIFactory.CreateLabel(((PanelBase)this).ContentRoot, "Header", GetSelectionMessage(), (TextAnchor)4, default(Color), true, 14);
			UIFactory.CreateLabel(((PanelBase)this).ContentRoot, "SaveLabel", "Save Path:", (TextAnchor)3, default(Color), true, 14);
			SavePath = UIFactory.CreateInputField(((PanelBase)this).ContentRoot, "SavePathField", "Save to path...");
			GameObject gameObject = ((Component)SavePath.Component).gameObject;
			int? num = 25;
			int? num2 = 9999;
			UIFactory.SetLayoutElement(gameObject, (int?)null, num, num2, (int?)null, (int?)null, (int?)null, (bool?)null);
			SavePath.Text = GetDefaultSavePath();
			ButtonRef obj = UIFactory.CreateButton(((PanelBase)this).ContentRoot, "SnapshotBtn", "Snapshot Selection", (Color?)new Color(0.2f, 0.2f, 0.35f));
			GameObject gameObject2 = ((Component)obj.Component).gameObject;
			num2 = 30;
			num = 9999;
			UIFactory.SetLayoutElement(gameObject2, (int?)null, num2, num, (int?)null, (int?)null, (int?)null, (bool?)null);
			obj.OnClick = (Action)Delegate.Combine(obj.OnClick, new Action(OnSnapShoot));
			UIFactory.CreateLabel(((PanelBase)this).ContentRoot, "LogLabel", "Output:", (TextAnchor)3, default(Color), true, 14);
			GameObject val = default(GameObject);
			AutoSliderScrollbar val2 = default(AutoSliderScrollbar);
			GameObject obj2 = UIFactory.CreateScrollView(((PanelBase)this).ContentRoot, "LogScroll", ref val, ref val2, new Color(0.2f, 0.2f, 0.2f));
			num = 9999;
			num2 = 120;
			UIFactory.SetLayoutElement(obj2, (int?)null, num2, (int?)null, num, (int?)null, (int?)null, (bool?)null);
			_logText = val.AddComponent<Text>();
			_logText.font = Resources.GetBuiltinResource<Font>("Arial.ttf");
			_logText.fontSize = 12;
			((Graphic)_logText).color = Color.white;
			_logText.supportRichText = true;
			_logText.horizontalOverflow = (HorizontalWrapMode)0;
			_logText.verticalOverflow = (VerticalWrapMode)1;
			_logText.text = "Ready...";
			InspectorManager.OnInspectedTabsChanged += OnInspectorChanged;
		}

		public string GetDefaultSavePath()
		{
			string selectionName = GetSelectionName();
			string text = DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss");
			string path = "TreeSnapShooter_" + selectionName + "_" + text + ".txt";
			return Path.Combine(_snapShooterService.GetDefaultDirectory(), path);
		}

		private void OnInspectorChanged()
		{
			if (((UIModel)this).Enabled)
			{
				UpdateSelection();
			}
		}

		public override void SetActive(bool active)
		{
			((PanelBase)this).SetActive(active);
			if (active)
			{
				UpdateSelection();
			}
		}

		protected override void OnClosePanelClicked()
		{
			VisibilityManager.Instance.Toggle();
		}

		public void UpdateSelection()
		{
			if (!((Object)(object)SelectionText == (Object)null))
			{
				SelectionText.text = GetSelectionMessage();
				InputFieldRef savePath = SavePath;
				if ((Object)(object)((savePath != null) ? savePath.Component : null) != (Object)null)
				{
					SavePath.Text = GetDefaultSavePath();
				}
			}
		}

		public string GetSelectionMessage()
		{
			return "<b>Selection: " + GetSelectionName() + "</b>";
		}

		public string GetSelectionName()
		{
			GameObject inspectedGameObject = GetInspectedGameObject();
			if ((Object)(object)inspectedGameObject != (Object)null)
			{
				return ((Object)inspectedGameObject).name;
			}
			return "None";
		}

		private void OnSnapShoot()
		{
			if (SavePath == null || (Object)(object)SavePath.Component == (Object)null)
			{
				Log("ERROR: SavePath is null!");
				return;
			}
			string text = SavePath.Component.text;
			GameObject inspectedGameObject = GetInspectedGameObject();
			if ((Object)(object)inspectedGameObject != (Object)null)
			{
				try
				{
					string content = _snapShooterService.ExecuteSnapShoot(inspectedGameObject);
					string text2 = _snapShooterService.SaveSnapshot(content, ((Object)inspectedGameObject).name, text);
					Log("Successfully created snapshot: " + text2);
					return;
				}
				catch (Exception ex)
				{
					Log("Snapshot failed: " + ex.Message);
					return;
				}
			}
			Log("Target is not a GameObject!");
		}

		private void Log(string msg)
		{
			if ((Object)(object)_logText != (Object)null)
			{
				_logText.text = msg + "\n" + _logText.text;
			}
		}

		private GameObject GetInspectedGameObject()
		{
			InspectorBase activeInspector = InspectorManager.ActiveInspector;
			if (activeInspector != null)
			{
				return TryGetGameObjectFromInspector(activeInspector);
			}
			if (InspectorManager.Inspectors != null)
			{
				for (int i = 0; i < InspectorManager.Inspectors.Count; i++)
				{
					InspectorBase inspector = InspectorManager.Inspectors[i];
					GameObject val = TryGetGameObjectFromInspector(inspector);
					if ((Object)(object)val != (Object)null)
					{
						return val;
					}
				}
			}
			return null;
		}

		private GameObject TryGetGameObjectFromInspector(InspectorBase inspector)
		{
			if (inspector == null)
			{
				return null;
			}
			object target = inspector.Target;
			if (target == null || target.ToString() == "null")
			{
				return null;
			}
			GameObject val = (GameObject)((target is GameObject) ? target : null);
			if (val != null)
			{
				return val;
			}
			Component val2 = (Component)((target is Component) ? target : null);
			if (val2 != null && (Object)(object)val2.gameObject != (Object)null)
			{
				return val2.gameObject;
			}
			return null;
		}

		public override void Destroy()
		{
			((PanelBase)this).Destroy();
			InspectorManager.OnInspectedTabsChanged -= OnInspectorChanged;
		}
	}
}
namespace UnityExplorerTreeSnapShooter.Services
{
	public interface IComponentStateReader
	{
		List<ComponentSnapshot> ReadComponents(GameObject gameObject, IReferenceTracker tracker);

		List<GameObjectSnapshot> ReadAllGameObjects(List<SnapshotNode> hierarchyNodes, int selectedInstanceId, IReferenceTracker tracker);
	}
	public interface IHierarchyBuilder
	{
		void BuildHierarchy(Transform root, IReferenceTracker tracker);

		List<SnapshotNode> GetHierarchyNodes();

		List<SnapshotNode> BuildParentChain(Transform transform, IReferenceTracker tracker);
	}
	public interface IPathsManager
	{
		string GetSnapshotsDirectory();
	}
	public interface IReferenceTracker
	{
		void AddToSelection(int instanceId);

		bool IsInSelection(int instanceId);

		bool IsInSelection(Object obj);

		void Clear();
	}
	public interface ISnapShooterService
	{
		string ExecuteSnapShoot(GameObject root);

		string SaveSnapshot(string content, string gameObjectName);

		string SaveSnapshot(string content, string gameObjectName, string userProvidedPath);

		string GetDefaultDirectory();
	}
	public interface ISnapshotFormatter
	{
		string Format(SnapshotResult snapshot);
	}
	public interface ISnapshotSaver
	{
		string Save(string content, string gameObjectName);

		string Save(string content, string gameObjectName, string userProvidedPath);

		string GetDefaultDirectory();
	}
	public interface IVisibilityManager
	{
		bool IsVisible { get; }

		void Initialize(UIBase uiBase);

		void Toggle();

		void SetVisible(bool visible);
	}
	public class TreeSnapShooterService : ISnapShooterService
	{
		private readonly IReferenceTracker _referenceTracker;

		private readonly IHierarchyBuilder _hierarchyBuilder;

		private readonly IComponentStateReader _componentReader;

		private readonly ISnapshotFormatter _formatter;

		private readonly ISnapshotSaver _saver;

		public TreeSnapShooterService(ISnapshotSaver saver)
		{
			_referenceTracker = new ReferenceTracker();
			_hierarchyBuilder = new HierarchyBuilder();
			_componentReader = new ComponentStateReader(_referenceTracker);
			_formatter = new PlainTextSnapshotFormatter();
			_saver = saver;
		}

		public string ExecuteSnapShoot(GameObject root)
		{
			_referenceTracker.Clear();
			SnapshotResult snapshotResult = new SnapshotResult
			{
				RootName = ((Object)root).name,
				RootInstanceId = ((Object)root).GetInstanceID(),
				GeneratedAt = DateTime.Now
			};
			_hierarchyBuilder.BuildHierarchy(root.transform, _referenceTracker);
			snapshotResult.Hierarchy = _hierarchyBuilder.GetHierarchyNodes();
			snapshotResult.ParentChain = _hierarchyBuilder.BuildParentChain(root.transform, _referenceTracker);
			snapshotResult.Components = _componentReader.ReadComponents(root, _referenceTracker);
			snapshotResult.GameObjectSnapshots = _componentReader.ReadAllGameObjects(snapshotResult.Hierarchy, ((Object)root).GetInstanceID(), _referenceTracker);
			return _formatter.Format(snapshotResult);
		}

		public string SaveSnapshot(string content, string gameObjectName)
		{
			return _saver.Save(content, gameObjectName);
		}

		public string SaveSnapshot(string content, string gameObjectName, string userProvidedPath)
		{
			return _saver.Save(content, gameObjectName, userProvidedPath);
		}

		public string GetDefaultDirectory()
		{
			return _saver.GetDefaultDirectory();
		}
	}
}
namespace UnityExplorerTreeSnapShooter.Services.Implementation
{
	public class ComponentStateReader : IComponentStateReader
	{
		private readonly IReferenceTracker _tracker;

		public ComponentStateReader(IReferenceTracker tracker)
		{
			_tracker = tracker;
		}

		public List<ComponentSnapshot> ReadComponents(GameObject gameObject, IReferenceTracker tracker)
		{
			List<ComponentSnapshot> list = new List<ComponentSnapshot>();
			Component[] components = gameObject.GetComponents<Component>();
			foreach (Component val in components)
			{
				if (!((Object)(object)val == (Object)null))
				{
					ComponentSnapshot item = new ComponentSnapshot
					{
						TypeName = ((object)val).GetType().Name,
						InstanceId = ((Object)val).GetInstanceID(),
						Members = ReadMembers(val, tracker)
					};
					list.Add(item);
				}
			}
			return list;
		}

		public List<GameObjectSnapshot> ReadAllGameObjects(List<SnapshotNode> hierarchyNodes, int selectedInstanceId, IReferenceTracker tracker)
		{
			List<GameObjectSnapshot> list = new List<GameObjectSnapshot>();
			HashSet<int> hashSet = new HashSet<int>();
			foreach (SnapshotNode hierarchyNode in hierarchyNodes)
			{
				GameObject gameObjectByInstanceId = GetGameObjectByInstanceId(hierarchyNode.InstanceId);
				if ((Object)(object)gameObjectByInstanceId == (Object)null)
				{
					continue;
				}
				bool isSelected = hierarchyNode.InstanceId == selectedInstanceId;
				GameObjectSnapshot gameObjectSnapshot = new GameObjectSnapshot
				{
					Name = ((Object)gameObjectByInstanceId).name,
					InstanceId = hierarchyNode.InstanceId,
					IsSelected = isSelected,
					Components = new List<ComponentSnapshot>()
				};
				if (hashSet.Contains(hierarchyNode.InstanceId))
				{
					gameObjectSnapshot.IsDuplicate = true;
					list.Add(gameObjectSnapshot);
					continue;
				}
				hashSet.Add(hierarchyNode.InstanceId);
				Component[] components = gameObjectByInstanceId.GetComponents<Component>();
				foreach (Component val in components)
				{
					if (!((Object)(object)val == (Object)null))
					{
						int instanceID = ((Object)val).GetInstanceID();
						ComponentSnapshot item = new ComponentSnapshot
						{
							TypeName = ((object)val).GetType().Name,
							InstanceId = instanceID,
							Members = ReadMembers(val, tracker)
						};
						gameObjectSnapshot.Components.Add(item);
					}
				}
				list.Add(gameObjectSnapshot);
			}
			return list;
		}

		private GameObject GetGameObjectByInstanceId(int instanceId)
		{
			GameObject[] array = Object.FindObjectsOfType<GameObject>();
			foreach (GameObject val in array)
			{
				if (((Object)val).GetInstanceID() == instanceId)
				{
					return val;
				}
			}
			return null;
		}

		private List<MemberSnapshot> ReadMembers(Component component, IReferenceTracker tracker)
		{
			List<MemberSnapshot> list = new List<MemberSnapshot>();
			Type type = ((object)component).GetType();
			BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
			FieldInfo[] fields = type.GetFields(bindingAttr);
			foreach (FieldInfo fieldInfo in fields)
			{
				try
				{
					object value = fieldInfo.GetValue(component);
					MemberSnapshot item = CreateMemberSnapshot("field", fieldInfo.Name, value, fieldInfo.FieldType, tracker);
					list.Add(item);
				}
				catch
				{
					list.Add(new MemberSnapshot
					{
						MemberType = "field",
						MemberName = fieldInfo.Name,
						FormattedValue = "[Error reading value]"
					});
				}
			}
			PropertyInfo[] properties = type.GetProperties(bindingAttr);
			foreach (PropertyInfo propertyInfo in properties)
			{
				try
				{
					if (propertyInfo.GetIndexParameters().Length == 0)
					{
						object value2 = propertyInfo.GetValue(component, null);
						MemberSnapshot item2 = CreateMemberSnapshot("property", propertyInfo.Name, value2, propertyInfo.PropertyType, tracker);
						list.Add(item2);
					}
				}
				catch
				{
					list.Add(new MemberSnapshot
					{
						MemberType = "property",
						MemberName = propertyInfo.Name,
						FormattedValue = "[Error reading value]"
					});
				}
			}
			return list;
		}

		private MemberSnapshot CreateMemberSnapshot(string memberType, string memberName, object value, Type valueType, IReferenceTracker tracker)
		{
			MemberSnapshot memberSnapshot = new MemberSnapshot
			{
				MemberType = memberType,
				MemberName = memberName,
				ValueType = (valueType?.Name ?? "null")
			};
			if (value == null)
			{
				memberSnapshot.FormattedValue = "null";
				return memberSnapshot;
			}
			Object val = (Object)((value is Object) ? value : null);
			if (val != null)
			{
				if (val == (Object)null)
				{
					memberSnapshot.FormattedValue = "null";
					return memberSnapshot;
				}
				int instanceID = val.GetInstanceID();
				memberSnapshot.ReferencedInstanceId = instanceID;
				if (tracker.IsInSelection(instanceID))
				{
					memberSnapshot.FormattedValue = $"[InstanceID: {instanceID}] {val.name} ({valueType.Name})";
					memberSnapshot.IsOutsideReference = false;
				}
				else
				{
					memberSnapshot.FormattedValue = $"[OUTSIDE_REFERENCE: InstanceID={instanceID}, Type={valueType.Name}] {val.name}";
					memberSnapshot.IsOutsideReference = true;
				}
				return memberSnapshot;
			}
			memberSnapshot.FormattedValue = FormatPrimitiveValue(value);
			return memberSnapshot;
		}

		private string FormatPrimitiveValue(object value)
		{
			if (value is string text)
			{
				return "\"" + text + "\"";
			}
			if (value.GetType().IsPrimitive || value.GetType().IsEnum)
			{
				return value.ToString();
			}
			if (value is Array array)
			{
				return $"Array[{array.Length}]";
			}
			if (value is IEnumerable enumerable && !(value is string))
			{
				int num = 0;
				foreach (object item in enumerable)
				{
					_ = item;
					num++;
				}
				return $"IEnumerable[{num}]";
			}
			return $"({value.GetType().Name}) {value}";
		}
	}
	public class FileSnapshotSaver : ISnapshotSaver
	{
		private readonly string _snapshotsDirectory;

		public FileSnapshotSaver(IPathsManager pathsManager)
		{
			_snapshotsDirectory = pathsManager.GetSnapshotsDirectory();
		}

		public string Save(string content, string gameObjectName)
		{
			return Save(content, gameObjectName, null);
		}

		public string Save(string content, string gameObjectName, string userProvidedPath)
		{
			string text = DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss");
			string text2;
			string path;
			if (!string.IsNullOrEmpty(userProvidedPath))
			{
				if (userProvidedPath.EndsWith(".txt") || userProvidedPath.EndsWith(".json"))
				{
					text2 = Path.GetDirectoryName(userProvidedPath);
					path = Path.GetFileName(userProvidedPath);
				}
				else
				{
					text2 = userProvidedPath;
					path = "TreeSnapShooter_" + gameObjectName + "_" + text + ".txt";
				}
			}
			else
			{
				text2 = _snapshotsDirectory;
				path = "TreeSnapShooter_" + gameObjectName + "_" + text + ".txt";
			}
			string text3 = Path.Combine(text2, path);
			try
			{
				EnsureDirectoryExists(text2);
				File.WriteAllText(text3, content);
				return text3;
			}
			catch (Exception ex)
			{
				UnityExplorerTreeSnapShooter.LogMessage("Error saving snapshot: " + ex.Message);
				throw;
			}
		}

		private void EnsureDirectoryExists(string path)
		{
			if (!Directory.Exists(path))
			{
				Directory.CreateDirectory(path);
			}
		}

		public string GetDefaultDirectory()
		{
			return _snapshotsDirectory;
		}
	}
	public class HierarchyBuilder : IHierarchyBuilder
	{
		private readonly List<SnapshotNode> _nodes = new List<SnapshotNode>();

		public void BuildHierarchy(Transform root, IReferenceTracker tracker)
		{
			_nodes.Clear();
			BuildNode(root, 0, tracker);
		}

		private void BuildNode(Transform transform, int depth, IReferenceTracker tracker)
		{
			GameObject gameObject = ((Component)transform).gameObject;
			int instanceID = ((Object)gameObject).GetInstanceID();
			tracker.AddToSelection(instanceID);
			SnapshotNode item = new SnapshotNode
			{
				Name = ((Object)gameObject).name,
				InstanceId = instanceID,
				TypeName = typeof(GameObject).Name,
				Depth = depth,
				IsActive = gameObject.activeInHierarchy
			};
			_nodes.Add(item);
			for (int i = 0; i < transform.childCount; i++)
			{
				Transform child = transform.GetChild(i);
				BuildNode(child, depth + 1, tracker);
			}
		}

		public List<SnapshotNode> GetHierarchyNodes()
		{
			return new List<SnapshotNode>(_nodes);
		}

		public List<SnapshotNode> BuildParentChain(Transform transform, IReferenceTracker tracker)
		{
			List<SnapshotNode> list = new List<SnapshotNode>();
			List<Transform> list2 = new List<Transform>();
			Transform parent = transform.parent;
			while ((Object)(object)parent != (Object)null)
			{
				list2.Add(parent);
				parent = parent.parent;
			}
			list2.Reverse();
			for (int i = 0; i < list2.Count; i++)
			{
				GameObject gameObject = ((Component)list2[i]).gameObject;
				int instanceID = ((Object)gameObject).GetInstanceID();
				tracker.AddToSelection(instanceID);
				SnapshotNode item = new SnapshotNode
				{
					Name = ((Object)gameObject).name,
					InstanceId = instanceID,
					TypeName = typeof(GameObject).Name,
					Depth = i,
					IsActive = gameObject.activeInHierarchy
				};
				list.Add(item);
			}
			return list;
		}
	}
	public class PathsManager : IPathsManager
	{
		private static PathsManager _instance;

		private readonly string _snapshotsDirectory;

		public static PathsManager Instance => _instance ?? (_instance = new PathsManager());

		private PathsManager()
		{
			string projectLocation = UnityExplorerTreeSnapShooter.GetProjectLocation();
			_snapshotsDirectory = Path.Combine(projectLocation, "Snapshots");
			EnsureDirectoryExists(_snapshotsDirectory);
		}

		private void EnsureDirectoryExists(string path)
		{
			try
			{
				if (!Directory.Exists(path))
				{
					Directory.CreateDirectory(path);
					UnityExplorerTreeSnapShooter.LogMessage("Created directory: " + path);
				}
			}
			catch (Exception ex)
			{
				UnityExplorerTreeSnapShooter.LogMessage("Error creating directory " + path + ": " + ex.Message);
			}
		}

		public string GetSnapshotsDirectory()
		{
			return _snapshotsDirectory;
		}
	}
	public class PlainTextSnapshotFormatter : ISnapshotFormatter
	{
		private readonly StringBuilder _output = new StringBuilder();

		public string Format(SnapshotResult snapshot)
		{
			_output.Clear();
			AddHeader(snapshot);
			AddParentHierarchy(snapshot.ParentChain);
			AddHierarchy(snapshot.Hierarchy);
			AddComponents(snapshot.Components);
			AddGameObjectReflection(snapshot.GameObjectSnapshots);
			return _output.ToString();
		}

		private void AddHeader(SnapshotResult snapshot)
		{
			AppendLine("========================================");
			AppendLine("TREE SNAPSHOT - " + snapshot.RootName);
			AppendLine($"Root Instance ID: {snapshot.RootInstanceId}");
			AppendLine($"Generated: {snapshot.GeneratedAt:yyyy-MM-dd HH:mm:ss}");
			AppendLine("========================================");
			AppendLine("");
		}

		private void AddParentHierarchy(List<SnapshotNode> parentChain)
		{
			AppendLine("=== PARENT HIERARCHY ===");
			AppendLine("");
			if (parentChain.Count == 0)
			{
				AppendLine("  (No parents - already at root)");
			}
			else
			{
				foreach (SnapshotNode item in parentChain)
				{
					string text = new string(' ', item.Depth * 2);
					string text2 = (item.IsActive ? "" : " [INACTIVE]");
					AppendLine($"{text}{item.Name} (InstanceID: {item.InstanceId}){text2}");
				}
			}
			AppendLine("");
		}

		private void AddHierarchy(List<SnapshotNode> hierarchy)
		{
			AppendLine("=== CHILDREN HIERARCHY ===");
			AppendLine("");
			foreach (SnapshotNode item in hierarchy)
			{
				string text = new string(' ', item.Depth * 2);
				string text2 = (item.IsActive ? "" : " [INACTIVE]");
				AppendLine($"{text}[{item.Depth}] {item.Name} (InstanceID: {item.InstanceId}){text2}");
			}
		}

		private void AddComponents(List<ComponentSnapshot> components)
		{
			AppendLine("");
			AppendLine("=== COMPONENTS ===");
			AppendLine("");
			foreach (ComponentSnapshot component in components)
			{
				AppendLine($"  {component.TypeName} (InstanceID: {component.InstanceId})");
			}
			AddComponentDetails(components);
		}

		private void AddComponentDetails(List<ComponentSnapshot> components)
		{
			AppendLine("");
			AppendLine("=== UNITYEXPLORER DISCOVERED STATE (REFLECTION) ===");
			AppendLine("");
			foreach (ComponentSnapshot component in components)
			{
				AppendLine($"--- {component.TypeName} (InstanceID: {component.InstanceId}) ---");
				foreach (MemberSnapshot member in component.Members)
				{
					string text = "  ";
					AppendLine(text + member.MemberType + " " + member.MemberName + ": " + member.FormattedValue);
				}
				AppendLine("");
			}
		}

		private void AddGameObjectReflection(List<GameObjectSnapshot> gameObjectSnapshots)
		{
			AppendLine("");
			AppendLine("=== GAME OBJECT REFLECTION (ALL CHILDREN) ===");
			AppendLine("");
			foreach (GameObjectSnapshot gameObjectSnapshot in gameObjectSnapshots)
			{
				string text = (gameObjectSnapshot.IsSelected ? " [SELECTED]" : "");
				string text2 = (gameObjectSnapshot.IsDuplicate ? " [DUPLICATE - skipped]" : "");
				AppendLine($"--- {gameObjectSnapshot.Name} (InstanceID: {gameObjectSnapshot.InstanceId}){text}{text2} ---");
				if (gameObjectSnapshot.IsDuplicate || gameObjectSnapshot.Components.Count == 0)
				{
					AppendLine("");
					continue;
				}
				foreach (ComponentSnapshot component in gameObjectSnapshot.Components)
				{
					AppendLine($"  {component.TypeName} (InstanceID: {component.InstanceId}):");
					foreach (MemberSnapshot member in component.Members)
					{
						string text3 = "    ";
						AppendLine(text3 + member.MemberType + " " + member.MemberName + ": " + member.FormattedValue);
					}
					AppendLine("");
				}
				AppendLine("");
			}
		}

		private void AppendLine(string line)
		{
			_output.AppendLine(line);
		}
	}
	public class ReferenceTracker : IReferenceTracker
	{
		private readonly HashSet<int> _selectionInstanceIds = new HashSet<int>();

		public void AddToSelection(int instanceId)
		{
			_selectionInstanceIds.Add(instanceId);
		}

		public bool IsInSelection(int instanceId)
		{
			return _selectionInstanceIds.Contains(instanceId);
		}

		public bool IsInSelection(Object obj)
		{
			if (obj == (Object)null)
			{
				return false;
			}
			return _selectionInstanceIds.Contains(obj.GetInstanceID());
		}

		public void Clear()
		{
			_selectionInstanceIds.Clear();
		}
	}
	public class VisibilityManager : IVisibilityManager
	{
		private static VisibilityManager _instance;

		private UIBase _uiBase;

		public static VisibilityManager Instance => _instance ?? (_instance = new VisibilityManager());

		public bool IsVisible { get; private set; }

		private VisibilityManager()
		{
		}

		public void Initialize(UIBase uiBase)
		{
			_uiBase = uiBase;
		}

		public void Toggle()
		{
			SetVisible(!IsVisible);
		}

		public void SetVisible(bool visible)
		{
			if (IsVisible == visible)
			{
				return;
			}
			IsVisible = visible;
			if (_uiBase != null)
			{
				_uiBase.Enabled = visible;
			}
			if (!visible)
			{
				EventSystem current = EventSystem.current;
				if (current != null)
				{
					current.SetSelectedGameObject((GameObject)null);
				}
			}
		}
	}
}
namespace UnityExplorerTreeSnapShooter.Patches
{
	[HarmonyPatch(typeof(InspectorPanel), "ConstructPanelContent")]
	public static class Patch_InspectorPanel_ConstructPanelContent
	{
		private static SnapShooterPanel _snapShooterPanel;

		private static void Postfix(InspectorPanel __instance)
		{
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			if (_snapShooterPanel == null)
			{
				if (SnapShooterPanel.UIBaseRegistry == null)
				{
					SnapShooterPanel.UIBaseRegistry = UniversalUI.RegisterUI(SnapShooterPanel.UIBaseGuid, (Action)null);
				}
				SnapShooterPanel.UIBaseRegistry.Enabled = false;
				VisibilityManager.Instance.Initialize(SnapShooterPanel.UIBaseRegistry);
				_snapShooterPanel = new SnapShooterPanel(SnapShooterPanel.UIBaseRegistry);
			}
			ButtonRef obj = UIFactory.CreateButton(((Component)((PanelBase)__instance).TitleBar.transform.Find("CloseHolder")).gameObject, "SnapshotBtn", "Snapshot", (Color?)new Color(0.2f, 0.2f, 0.35f));
			GameObject gameObject = ((Component)obj.Component).gameObject;
			int? num = 25;
			UIFactory.SetLayoutElement(gameObject, (int?)80, num, (int?)null, (int?)null, (int?)null, (int?)null, (bool?)null);
			((Component)obj.Component).transform.SetSiblingIndex(0);
			obj.OnClick = (Action)Delegate.Combine(obj.OnClick, (Action)delegate
			{
				VisibilityManager.Instance.Toggle();
			});
			UnityExplorerTreeSnapShooter.LogMessage("[TreeSnapShooter] Snapshoot button added to Inspector panel!");
		}
	}
}
namespace UnityExplorerTreeSnapShooter.Models
{
	public class SnapshotNode
	{
		public string Name { get; set; }

		public int InstanceId { get; set; }

		public string TypeName { get; set; }

		public List<SnapshotNode> Children { get; set; } = new List<SnapshotNode>();


		public int Depth { get; set; }

		public bool IsActive { get; set; }

		public bool IsOutsideReference { get; set; }
	}
	public class ComponentSnapshot
	{
		public string TypeName { get; set; }

		public int InstanceId { get; set; }

		public List<MemberSnapshot> Members { get; set; } = new List<MemberSnapshot>();

	}
	public class GameObjectSnapshot
	{
		public string Name { get; set; }

		public int InstanceId { get; set; }

		public bool IsSelected { get; set; }

		public bool IsDuplicate { get; set; }

		public List<ComponentSnapshot> Components { get; set; } = new List<ComponentSnapshot>();

	}
	public class MemberSnapshot
	{
		public string MemberType { get; set; }

		public string MemberName { get; set; }

		public string ValueType { get; set; }

		public string FormattedValue { get; set; }

		public int? ReferencedInstanceId { get; set; }

		public bool IsOutsideReference { get; set; }
	}
	public class SnapshotResult
	{
		public string RootName { get; set; }

		public int RootInstanceId { get; set; }

		public DateTime GeneratedAt { get; set; }

		public List<SnapshotNode> ParentChain { get; set; } = new List<SnapshotNode>();


		public List<SnapshotNode> Hierarchy { get; set; } = new List<SnapshotNode>();


		public List<ComponentSnapshot> Components { get; set; } = new List<ComponentSnapshot>();


		public List<GameObjectSnapshot> GameObjectSnapshots { get; set; } = new List<GameObjectSnapshot>();

	}
}