Compare commits

..

8 Commits
4.0.6 ... 4.0.7

13 changed files with 113 additions and 112 deletions

View File

@ -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))

View File

@ -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";

View File

@ -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>();

View File

@ -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;

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}
}

View File

@ -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));

View File

@ -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();
}
}
}

View File

@ -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));
}

View File

@ -83,6 +83,7 @@ namespace UnityExplorer.UI.Widgets
displayIndex = 0;
autoExpandedIDs.Clear();
expandedInstanceIDs.Clear();
this.ScrollPool.Refresh(true, true);
}
public bool IsCellExpanded(int instanceID)

View File

@ -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" />