mirror of
https://github.com/GrahamKracker/UnityExplorer.git
synced 2025-07-03 20:12:33 +08:00
Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
a46acba265 | |||
5515b2eae4 | |||
9992029e28 | |||
14105785f0 | |||
365269b0dd | |||
0b973393d1 | |||
701d4431ae | |||
bfa73bcb55 |
@ -44,15 +44,15 @@ namespace UnityExplorer
|
||||
|
||||
public static bool Il2CppTypeNotNull(Type type, out IntPtr il2cppPtr)
|
||||
{
|
||||
if (cppClassPointers.TryGetValue(type.AssemblyQualifiedName, out il2cppPtr))
|
||||
return il2cppPtr != IntPtr.Zero;
|
||||
|
||||
il2cppPtr = (IntPtr)typeof(Il2CppClassPointerStore<>)
|
||||
if (!cppClassPointers.TryGetValue(type.AssemblyQualifiedName, out il2cppPtr))
|
||||
{
|
||||
il2cppPtr = (IntPtr)typeof(Il2CppClassPointerStore<>)
|
||||
.MakeGenericType(new Type[] { type })
|
||||
.GetField("NativeClassPtr", BF.Public | BF.Static)
|
||||
.GetValue(null);
|
||||
|
||||
cppClassPointers.Add(type.AssemblyQualifiedName, il2cppPtr);
|
||||
cppClassPointers.Add(type.AssemblyQualifiedName, il2cppPtr);
|
||||
}
|
||||
|
||||
return il2cppPtr != IntPtr.Zero;
|
||||
}
|
||||
@ -242,11 +242,11 @@ namespace UnityExplorer
|
||||
else if (castTo == typeof(string))
|
||||
return UnboxString(obj);
|
||||
|
||||
// Casting from il2cpp object to il2cpp object...
|
||||
|
||||
if (!Il2CppTypeNotNull(castTo, out IntPtr castToPtr))
|
||||
return obj;
|
||||
|
||||
// Casting from il2cpp object to il2cpp object...
|
||||
|
||||
IntPtr castFromPtr = il2cpp_object_get_class(cppObj.Pointer);
|
||||
|
||||
if (!il2cpp_class_is_assignable_from(castToPtr, castFromPtr))
|
||||
|
@ -20,7 +20,7 @@ namespace UnityExplorer
|
||||
public static class ExplorerCore
|
||||
{
|
||||
public const string NAME = "UnityExplorer";
|
||||
public const string VERSION = "4.0.6";
|
||||
public const string VERSION = "4.0.7";
|
||||
public const string AUTHOR = "Sinai";
|
||||
public const string GUID = "com.sinai.unityexplorer";
|
||||
|
||||
|
Binary file not shown.
@ -63,7 +63,7 @@ namespace UnityExplorer.UI.Inspectors
|
||||
addCompInput.Text = "";
|
||||
|
||||
TransformTree.Clear();
|
||||
ComponentList.Clear();
|
||||
UpdateComponents();
|
||||
}
|
||||
|
||||
public override void CloseInspector()
|
||||
@ -112,6 +112,9 @@ namespace UnityExplorer.UI.Inspectors
|
||||
|
||||
private IEnumerable<GameObject> GetTransformEntries()
|
||||
{
|
||||
if (!GOTarget)
|
||||
return Enumerable.Empty<GameObject>();
|
||||
|
||||
cachedChildren.Clear();
|
||||
for (int i = 0; i < GOTarget.transform.childCount; i++)
|
||||
cachedChildren.Add(GOTarget.transform.GetChild(i).gameObject);
|
||||
@ -124,10 +127,21 @@ namespace UnityExplorer.UI.Inspectors
|
||||
private readonly List<bool> behaviourEnabledStates = new List<bool>();
|
||||
|
||||
// ComponentList.GetRootEntriesMethod
|
||||
private List<Component> GetComponentEntries() => componentEntries;
|
||||
private List<Component> GetComponentEntries() => GOTarget ? componentEntries : Enumerable.Empty<Component>().ToList();
|
||||
|
||||
public void UpdateComponents()
|
||||
{
|
||||
if (!GOTarget)
|
||||
{
|
||||
componentEntries.Clear();
|
||||
compInstanceIDs.Clear();
|
||||
behaviourEntries.Clear();
|
||||
behaviourEnabledStates.Clear();
|
||||
ComponentList.RefreshData();
|
||||
ComponentList.ScrollPool.Refresh(true, true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if we actually need to refresh the component cells or not.
|
||||
var comps = GOTarget.GetComponents<Component>();
|
||||
var behaviours = GOTarget.GetComponents<Behaviour>();
|
||||
|
@ -21,7 +21,8 @@ namespace UnityExplorer.UI.Inspectors
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
this.currentEntries.Clear();
|
||||
RefreshData();
|
||||
ScrollPool.Refresh(true, true);
|
||||
}
|
||||
|
||||
private bool CheckShouldDisplay(Component _, string __) => true;
|
||||
|
@ -1,19 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityExplorer.UI.Models
|
||||
{
|
||||
public interface IPooledObject
|
||||
{
|
||||
GameObject UIRoot { get; set; }
|
||||
|
||||
GameObject CreateContent(GameObject parent);
|
||||
|
||||
float DefaultHeight { get; }
|
||||
|
||||
//GameObject CreatePrototype();
|
||||
}
|
||||
}
|
@ -39,7 +39,7 @@ namespace UnityExplorer.UI.ObjectExplorer
|
||||
|
||||
private GameObject refreshRow;
|
||||
private Dropdown sceneDropdown;
|
||||
private readonly Dictionary<int, Dropdown.OptionData> sceneToDropdownOption = new Dictionary<int, Dropdown.OptionData>();
|
||||
private readonly Dictionary<Scene, Dropdown.OptionData> sceneToDropdownOption = new Dictionary<Scene, Dropdown.OptionData>();
|
||||
|
||||
private IEnumerable<GameObject> GetRootEntries() => SceneHandler.CurrentRootObjects;
|
||||
|
||||
@ -70,7 +70,7 @@ namespace UnityExplorer.UI.ObjectExplorer
|
||||
var go = transform.gameObject;
|
||||
if (SceneHandler.SelectedScene != go.scene)
|
||||
{
|
||||
int idx = sceneDropdown.options.IndexOf(sceneToDropdownOption[go.scene.handle]);
|
||||
int idx = sceneDropdown.options.IndexOf(sceneToDropdownOption[go.scene]);
|
||||
sceneDropdown.value = idx;
|
||||
}
|
||||
|
||||
@ -91,12 +91,12 @@ namespace UnityExplorer.UI.ObjectExplorer
|
||||
|
||||
private void SceneHandler_OnInspectedSceneChanged(Scene scene)
|
||||
{
|
||||
if (!sceneToDropdownOption.ContainsKey(scene.handle))
|
||||
if (!sceneToDropdownOption.ContainsKey(scene))
|
||||
PopulateSceneDropdown();
|
||||
|
||||
if (sceneToDropdownOption.ContainsKey(scene.handle))
|
||||
if (sceneToDropdownOption.ContainsKey(scene))
|
||||
{
|
||||
var opt = sceneToDropdownOption[scene.handle];
|
||||
var opt = sceneToDropdownOption[scene];
|
||||
int idx = sceneDropdown.options.IndexOf(opt);
|
||||
if (sceneDropdown.value != idx)
|
||||
sceneDropdown.value = idx;
|
||||
@ -134,7 +134,7 @@ namespace UnityExplorer.UI.ObjectExplorer
|
||||
|
||||
var option = new Dropdown.OptionData(name);
|
||||
sceneDropdown.options.Add(option);
|
||||
sceneToDropdownOption.Add(scene.handle, option);
|
||||
sceneToDropdownOption.Add(scene, option);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ namespace UnityExplorer.UI.ObjectExplorer
|
||||
get => m_selectedScene;
|
||||
internal set
|
||||
{
|
||||
if (m_selectedScene != null && m_selectedScene?.handle == value?.handle)
|
||||
if (m_selectedScene != null && m_selectedScene == value)
|
||||
return;
|
||||
m_selectedScene = value;
|
||||
OnInspectedSceneChanged?.Invoke((Scene)m_selectedScene);
|
||||
@ -37,6 +37,7 @@ namespace UnityExplorer.UI.ObjectExplorer
|
||||
/// </summary>
|
||||
public static ReadOnlyCollection<Scene> LoadedScenes => new ReadOnlyCollection<Scene>(allLoadedScenes);
|
||||
private static readonly List<Scene> allLoadedScenes = new List<Scene>();
|
||||
private static HashSet<Scene> previousLoadedScenes;
|
||||
|
||||
/// <summary>
|
||||
/// The names of all scenes in the build settings, if they could be retrieved.
|
||||
@ -82,7 +83,7 @@ namespace UnityExplorer.UI.ObjectExplorer
|
||||
}
|
||||
private static GameObject dontDestroyObject;
|
||||
|
||||
public static bool InspectingAssetScene => !SelectedScene?.IsValid() ?? false;
|
||||
public static bool InspectingAssetScene => SelectedScene.HasValue && SelectedScene.Value == default;
|
||||
|
||||
internal static void Init()
|
||||
{
|
||||
@ -110,17 +111,9 @@ namespace UnityExplorer.UI.ObjectExplorer
|
||||
|
||||
internal static void Update()
|
||||
{
|
||||
int curHandle = SelectedScene?.handle ?? -1;
|
||||
// DontDestroyOnLoad always exists, so default to true if our curHandle is that handle.
|
||||
// otherwise we will check while iterating.
|
||||
bool inspectedExists = curHandle == DontDestroyHandle || curHandle == 0;
|
||||
|
||||
// Quick sanity check if the loaded scenes changed
|
||||
bool anyChange = LoadedSceneCount != allLoadedScenes.Count;
|
||||
// otherwise keep a lookup table of the previous handles to check if the list changed at all.
|
||||
HashSet<int> previousHandles = null;
|
||||
if (!anyChange)
|
||||
previousHandles = new HashSet<int>(allLoadedScenes.Select(it => it.handle));
|
||||
// check if the loaded scenes changed. always confirm DontDestroy / HideAndDontSave
|
||||
int confirmedCount = 2;
|
||||
bool inspectedExists = SelectedScene == DontDestroyScene || (SelectedScene.HasValue && SelectedScene.Value == default);
|
||||
|
||||
allLoadedScenes.Clear();
|
||||
|
||||
@ -130,20 +123,22 @@ namespace UnityExplorer.UI.ObjectExplorer
|
||||
if (scene == default || !scene.isLoaded)
|
||||
continue;
|
||||
|
||||
// If no changes yet, ensure the previous list contained this handle.
|
||||
if (!anyChange && !previousHandles.Contains(scene.handle))
|
||||
anyChange = true;
|
||||
// If no changes yet, ensure the previous list contained the scene
|
||||
if (previousLoadedScenes != null && previousLoadedScenes.Contains(scene))
|
||||
confirmedCount++;
|
||||
|
||||
// If we have not yet confirmed inspectedExists, check if this scene is our currently inspected one.
|
||||
if (curHandle != -1 && !inspectedExists && scene.handle == curHandle)
|
||||
if (!inspectedExists && scene == SelectedScene)
|
||||
inspectedExists = true;
|
||||
|
||||
allLoadedScenes.Add(scene);
|
||||
}
|
||||
|
||||
// Always add the DontDestroyOnLoad scene and the "none" scene.
|
||||
bool anyChange = confirmedCount != allLoadedScenes.Count;
|
||||
|
||||
allLoadedScenes.Add(DontDestroyScene);
|
||||
allLoadedScenes.Add(default);
|
||||
previousLoadedScenes = new HashSet<Scene>(allLoadedScenes);
|
||||
|
||||
// Default to first scene if none selected or previous selection no longer exists.
|
||||
if (!inspectedExists)
|
||||
@ -163,14 +158,14 @@ namespace UnityExplorer.UI.ObjectExplorer
|
||||
else
|
||||
{
|
||||
var allObjects = RuntimeProvider.Instance.FindObjectsOfTypeAll(typeof(GameObject));
|
||||
var list = new List<GameObject>();
|
||||
var objects = new List<GameObject>();
|
||||
foreach (var obj in allObjects)
|
||||
{
|
||||
var go = obj.TryCast<GameObject>();
|
||||
if (go.transform.parent == null && !go.scene.IsValid())
|
||||
list.Add(go);
|
||||
objects.Add(go);
|
||||
}
|
||||
rootObjects = list.ToArray();
|
||||
rootObjects = objects.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,9 +4,16 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityExplorer.UI.Models
|
||||
namespace UnityExplorer.UI
|
||||
{
|
||||
// Abstract non-generic class, handles the pool dictionary and interfacing with the generic pools.
|
||||
public interface IPooledObject
|
||||
{
|
||||
GameObject UIRoot { get; set; }
|
||||
float DefaultHeight { get; }
|
||||
|
||||
GameObject CreateContent(GameObject parent);
|
||||
}
|
||||
|
||||
public abstract class Pool
|
||||
{
|
||||
protected static readonly Dictionary<Type, Pool> pools = new Dictionary<Type, Pool>();
|
||||
@ -39,7 +46,6 @@ namespace UnityExplorer.UI.Models
|
||||
protected abstract void TryReturn(IPooledObject obj);
|
||||
}
|
||||
|
||||
// Each generic implementation has its own pool, business logic is here
|
||||
public class Pool<T> : Pool where T : IPooledObject
|
||||
{
|
||||
public static Pool<T> GetPool() => (Pool<T>)GetPool(typeof(T));
|
@ -6,31 +6,6 @@ using UnityEngine;
|
||||
|
||||
namespace UnityExplorer.UI.Widgets
|
||||
{
|
||||
public struct DataViewInfo
|
||||
{
|
||||
// static
|
||||
public static DataViewInfo None => s_default;
|
||||
private static DataViewInfo s_default = default;
|
||||
|
||||
public static implicit operator float(DataViewInfo it) => it.height;
|
||||
|
||||
// instance
|
||||
public int dataIndex, normalizedSpread;
|
||||
public float height, startPosition;
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
var other = (DataViewInfo)obj;
|
||||
|
||||
return this.dataIndex == other.dataIndex
|
||||
&& this.height == other.height
|
||||
&& this.startPosition == other.startPosition
|
||||
&& this.normalizedSpread == other.normalizedSpread;
|
||||
}
|
||||
|
||||
public override int GetHashCode() => base.GetHashCode();
|
||||
}
|
||||
|
||||
public class DataHeightCache<T> where T : ICell
|
||||
{
|
||||
private ScrollPool<T> ScrollPool { get; }
|
||||
@ -93,11 +68,10 @@ namespace UnityExplorer.UI.Widgets
|
||||
int expectedMax = expectedMin + cache.normalizedSpread - 1;
|
||||
if (rangeIndex < expectedMin || rangeIndex > expectedMax)
|
||||
{
|
||||
RecalculateStartPositions(Math.Max(dataIndex, expectedMax));
|
||||
RecalculateStartPositions(ScrollPool.DataSource.ItemCount - 1);
|
||||
|
||||
rangeIndex = GetRangeFloorOfPosition(desiredHeight);
|
||||
dataIndex = rangeCache[rangeIndex];
|
||||
//cache = heightCache[dataIndex];
|
||||
}
|
||||
|
||||
return dataIndex;
|
||||
@ -125,17 +99,11 @@ namespace UnityExplorer.UI.Widgets
|
||||
/// <summary>Append a data index to the cache with the provided height value.</summary>
|
||||
public void Add(float value)
|
||||
{
|
||||
value = (float)Math.Floor(value);
|
||||
value = Math.Max(DefaultHeight, value);
|
||||
|
||||
int spread = GetRangeSpread(totalHeight, value);
|
||||
|
||||
heightCache.Add(new DataViewInfo()
|
||||
{
|
||||
height = value,
|
||||
startPosition = TotalHeight,
|
||||
normalizedSpread = spread,
|
||||
});
|
||||
heightCache.Add(new DataViewInfo(heightCache.Count, value, totalHeight, spread));
|
||||
|
||||
int dataIdx = heightCache.Count - 1;
|
||||
for (int i = 0; i < spread; i++)
|
||||
@ -203,31 +171,31 @@ namespace UnityExplorer.UI.Widgets
|
||||
int spread = GetRangeSpread(cache.startPosition, height);
|
||||
|
||||
// If the previous item in the range cache is not the previous data index, there is a gap.
|
||||
if (dataIndex > 0 && rangeCache[rangeIndex - 1] != (dataIndex - 1))
|
||||
if (rangeCache[rangeIndex] != dataIndex)
|
||||
{
|
||||
// Recalculate start positions up to this index. The gap could be anywhere before here.
|
||||
RecalculateStartPositions(dataIndex + 1);
|
||||
RecalculateStartPositions(ScrollPool.DataSource.ItemCount - 1);
|
||||
// Get the range index and spread again after rebuilding
|
||||
rangeIndex = GetRangeCeilingOfPosition(cache.startPosition);
|
||||
spread = GetRangeSpread(cache.startPosition, height);
|
||||
}
|
||||
|
||||
if (rangeCache.Count <= rangeIndex || rangeCache[rangeIndex] != dataIndex)
|
||||
throw new Exception("ScrollPool data height cache is corrupt or invalid, rebuild failed!");
|
||||
if (rangeCache[rangeIndex] != dataIndex)
|
||||
throw new IndexOutOfRangeException($"Trying to set dataIndex {dataIndex} at rangeIndex {rangeIndex}, but cache is corrupt or invalid!");
|
||||
|
||||
if (spread != cache.normalizedSpread)
|
||||
{
|
||||
int spreadDiff = spread - cache.normalizedSpread;
|
||||
cache.normalizedSpread = spread;
|
||||
|
||||
SetSpread(dataIndex, rangeIndex, spreadDiff);
|
||||
UpdateSpread(dataIndex, rangeIndex, spreadDiff);
|
||||
}
|
||||
|
||||
// set the struct back to the array (TODO necessary?)
|
||||
// set the struct back to the array
|
||||
heightCache[dataIndex] = cache;
|
||||
}
|
||||
|
||||
private void SetSpread(int dataIndex, int rangeIndex, int spreadDiff)
|
||||
private void UpdateSpread(int dataIndex, int rangeIndex, int spreadDiff)
|
||||
{
|
||||
if (spreadDiff > 0)
|
||||
{
|
||||
@ -244,8 +212,6 @@ namespace UnityExplorer.UI.Widgets
|
||||
rangeCache.RemoveAt(rangeIndex);
|
||||
spreadDiff++;
|
||||
}
|
||||
//for (int i = 0; i < -spreadDiff; i++)
|
||||
// rangeCache.RemoveAt(rangeIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@ -254,24 +220,60 @@ namespace UnityExplorer.UI.Widgets
|
||||
if (heightCache.Count <= 1)
|
||||
return;
|
||||
|
||||
rangeCache.Clear();
|
||||
|
||||
DataViewInfo cache;
|
||||
DataViewInfo prev = DataViewInfo.None;
|
||||
for (int i = 0; i <= toIndex && i < heightCache.Count; i++)
|
||||
for (int idx = 0; idx <= toIndex && idx < heightCache.Count; idx++)
|
||||
{
|
||||
cache = heightCache[i];
|
||||
cache = heightCache[idx];
|
||||
|
||||
if (prev != DataViewInfo.None)
|
||||
if (!prev.Equals(DataViewInfo.None))
|
||||
cache.startPosition = prev.startPosition + prev.height;
|
||||
else
|
||||
cache.startPosition = 0;
|
||||
|
||||
var origSpread = cache.normalizedSpread;
|
||||
cache.normalizedSpread = GetRangeSpread(cache.startPosition, cache.height);
|
||||
if (cache.normalizedSpread != origSpread)
|
||||
SetSpread(i, GetRangeCeilingOfPosition(cache.startPosition), cache.normalizedSpread - origSpread);
|
||||
for (int i = 0; i < cache.normalizedSpread; i++)
|
||||
rangeCache.Add(cache.dataIndex);
|
||||
|
||||
heightCache[idx] = cache;
|
||||
|
||||
prev = cache;
|
||||
}
|
||||
}
|
||||
|
||||
public struct DataViewInfo
|
||||
{
|
||||
// static
|
||||
public static DataViewInfo None => s_default;
|
||||
private static DataViewInfo s_default = default;
|
||||
|
||||
public static implicit operator float(DataViewInfo it) => it.height;
|
||||
|
||||
public DataViewInfo(int index, float height, float startPos, int spread)
|
||||
{
|
||||
this.dataIndex = index;
|
||||
this.height = height;
|
||||
this.startPosition = startPos;
|
||||
this.normalizedSpread = spread;
|
||||
}
|
||||
|
||||
// instance
|
||||
public int dataIndex, normalizedSpread;
|
||||
public float height, startPosition;
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
var other = (DataViewInfo)obj;
|
||||
|
||||
return this.dataIndex == other.dataIndex
|
||||
&& this.height == other.height
|
||||
&& this.startPosition == other.startPosition
|
||||
&& this.normalizedSpread == other.normalizedSpread;
|
||||
}
|
||||
|
||||
public override int GetHashCode() => base.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -142,7 +142,9 @@ namespace UnityExplorer.UI.Widgets
|
||||
RefreshCells(true, true);
|
||||
|
||||
// Slide to the normalized position of the index
|
||||
float normalized = HeightCache[index].startPosition / HeightCache.TotalHeight;
|
||||
var cache = HeightCache[index];
|
||||
float normalized = (cache.startPosition + (cache.height * 0.5f)) / HeightCache.TotalHeight;
|
||||
|
||||
RuntimeProvider.Instance.StartCoroutine(ForceDelayedJump(index, normalized, onJumped));
|
||||
}
|
||||
|
||||
|
@ -83,6 +83,7 @@ namespace UnityExplorer.UI.Widgets
|
||||
displayIndex = 0;
|
||||
autoExpandedIDs.Clear();
|
||||
expandedInstanceIDs.Clear();
|
||||
this.ScrollPool.Refresh(true, true);
|
||||
}
|
||||
|
||||
public bool IsCellExpanded(int instanceID)
|
||||
|
@ -290,8 +290,7 @@
|
||||
<Compile Include="UI\Inspectors\ReflectionInspector.cs" />
|
||||
<Compile Include="UI\CacheObject\IValues\InteractiveValueStruct.cs" />
|
||||
<Compile Include="UI\Models\InputFieldRef.cs" />
|
||||
<Compile Include="UI\Models\ObjectPool\IPooledObject.cs" />
|
||||
<Compile Include="UI\Models\ObjectPool\Pool.cs" />
|
||||
<Compile Include="UI\Pool.cs" />
|
||||
<Compile Include="UI\Panels\LogPanel.cs" />
|
||||
<Compile Include="UI\Panels\CSConsolePanel.cs" />
|
||||
<Compile Include="Core\Utility\IOUtility.cs" />
|
||||
|
Reference in New Issue
Block a user