update runtime monitors

This commit is contained in:
Mikhail 2024-03-10 04:56:29 +08:00
parent 7f2d1cee73
commit 69e2c926e8
13 changed files with 304 additions and 32 deletions

View File

@ -12,6 +12,7 @@ namespace DCFApixels.DragonECS
public abstract bool IsEmpty { get; } public abstract bool IsEmpty { get; }
public abstract void SetRaw(EcsWorld world); public abstract void SetRaw(EcsWorld world);
public abstract EcsWorld GetRaw(); public abstract EcsWorld GetRaw();
public abstract EcsWorld GetCurrentWorldRaw();
} }
[Serializable] [Serializable]
public abstract class EcsWorldProvider<TWorld> : EcsWorldProviderBase where TWorld : EcsWorld public abstract class EcsWorldProvider<TWorld> : EcsWorldProviderBase where TWorld : EcsWorld
@ -78,6 +79,10 @@ namespace DCFApixels.DragonECS
{ {
return Get(); return Get();
} }
public sealed override EcsWorld GetCurrentWorldRaw()
{
return _world;
}
public TWorld Get() public TWorld Get()
{ {
if (_world == null || _world.IsDestroyed) if (_world == null || _world.IsDestroyed)

View File

@ -23,6 +23,9 @@ namespace DCFApixels.DragonECS.Unity.Editors
EcsWorld world = Target.GetRaw(); EcsWorld world = Target.GetRaw();
GUILayout.Box($"{world.GetMeta().Name} ( {world.id} )", style, GUILayout.ExpandWidth(true)); GUILayout.Box($"{world.GetMeta().Name} ( {world.id} )", style, GUILayout.ExpandWidth(true));
} }
EcsGUI.Layout.DrawWorldBaseInfo(Target.GetCurrentWorldRaw());
base.OnInspectorGUI(); base.OnInspectorGUI();
GUILayout.Space(10); GUILayout.Space(10);

View File

@ -1,23 +1,33 @@
namespace DCFApixels.DragonECS using DCFApixels.DragonECS.Unity.Internal;
namespace DCFApixels.DragonECS
{ {
public sealed class DebugModule : IEcsModule public sealed class DebugModule : IEcsModule
{ {
public const string DEBUG_LAYER = nameof(DEBUG_LAYER); public const string DEBUG_LAYER = nameof(DEBUG_LAYER);
public EcsWorld[] _worlds; public EcsWorld[] _worlds;
public DebugModule(params EcsWorld[] worlds) public DebugModule(params EcsWorld[] worlds)
{ {
_worlds = worlds; _worlds = worlds;
} }
void IEcsModule.Import(EcsPipeline.Builder b) void IEcsModule.Import(EcsPipeline.Builder b)
{ {
UnityDebugService.Activate();
b.Layers.Insert(EcsConsts.POST_END_LAYER, DEBUG_LAYER); b.Layers.Insert(EcsConsts.POST_END_LAYER, DEBUG_LAYER);
//b.Add(new PipelineDebugSystem(), DEBUG_LAYER); b.Add(new PipelineMonitorSystem(), DEBUG_LAYER);
foreach (var world in _worlds) foreach (var world in _worlds)
{ {
//b.Add(new WorldDebugSystem(world), DEBUG_LAYER); b.Add(new WorldMonitorSystem(world), DEBUG_LAYER);
} }
} }
} }
public static class DebugModuleExt
{
public static EcsPipeline.Builder AddUnityDebug(this EcsPipeline.Builder self, params EcsWorld[] worlds)
{
self.AddModule(new DebugModule(worlds));
return self;
}
}
} }

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b1105324b07e39d449acceb24bdd7eb3
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,20 @@
#if UNITY_EDITOR
using DCFApixels.DragonECS.Unity.Internal;
using UnityEditor;
namespace DCFApixels.DragonECS.Unity.Editors
{
[CustomEditor(typeof(EntityMonitor))]
internal class EntityMonitorEditor : Editor
{
private EntityMonitor Target => (EntityMonitor)target;
public override void OnInspectorGUI()
{
bool isAlive = Target.Entity.TryUnpack(out int id, out short gen, out EcsWorld world);
EcsGUI.Layout.EntityBar(isAlive ? EcsGUI.EntityStatus.Alive : EcsGUI.EntityStatus.NotAlive, id, gen, world.id);
EcsGUI.Layout.DrawRuntimeComponents(Target.Entity, false);
}
}
}
#endif

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c5457dbe0f53566419d37e0ee9d9c13f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,18 @@
#if UNITY_EDITOR
using DCFApixels.DragonECS.Unity.Internal;
using UnityEditor;
namespace DCFApixels.DragonECS.Unity.Editors
{
[CustomEditor(typeof(WorldMonitor))]
internal class WorldMonitorEditor : Editor
{
private WorldMonitor Target => (WorldMonitor)target;
public override void OnInspectorGUI()
{
EcsGUI.Layout.DrawWorldBaseInfo(Target.World);
}
}
}
#endif

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7aadf8c836c97694186e4b3aeb01fcce
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,31 +1,19 @@
using UnityEngine; using UnityEngine;
namespace DCFApixels.DragonECS namespace DCFApixels.DragonECS.Unity.Internal
{ {
[MetaTags(MetaTags.HIDDEN), MetaColor(MetaColor.Gray)] [MetaTags(MetaTags.HIDDEN)]
public class EntityMonitor : MonoBehaviour, IEcsProcess [MetaColor(MetaColor.Gray)]
public class EntityMonitor : MonoBehaviour
{ {
private entlong _entity; private entlong _entity;
private int _entityID; public entlong Entity
private short _gen;
private EcsWorld _world;
public EcsWorld World
{ {
get { return _world; } get { return _entity; }
} }
public int EntityID public void Set(entlong entity)
{
get { return _entityID; }
}
public EntityMonitor(entlong entity)
{ {
_entity = entity; _entity = entity;
if (_entity.TryUnpack(out _entityID, out _gen, out _world))
{
}
} }
} }
} }

View File

@ -1,9 +1,42 @@
using UnityEngine; using DCFApixels.DragonECS.Unity.Editors;
using UnityEngine;
namespace DCFApixels.DragonECS namespace DCFApixels.DragonECS.Unity.Internal
{ {
[MetaTags(MetaTags.HIDDEN), MetaColor(MetaColor.Gray)] [MetaTags(MetaTags.HIDDEN)]
public class PipelineMonitor : MonoBehaviour, IEcsProcess [MetaColor(MetaColor.Gray)]
public class PipelineMonitor : MonoBehaviour
{ {
private EcsPipeline _pipeline;
public EcsPipeline Pipeline
{
get { return _pipeline; }
}
public void Set(EcsPipeline pipeline)
{
_pipeline = pipeline;
}
}
[MetaTags(MetaTags.HIDDEN)]
[MetaColor(MetaColor.Gray)]
public class PipelineMonitorSystem : IEcsInit, IEcsPipelineMember, IEcsDestroy
{
private PipelineMonitor _monitor;
public EcsPipeline Pipeline { get; set; }
public void Init()
{
TypeMeta meta = typeof(EcsPipeline).ToMeta();
_monitor = new GameObject($"{UnityEditorUtility.TransformToUpperName(meta.Name)}").AddComponent<PipelineMonitor>();
UnityEngine.Object.DontDestroyOnLoad(_monitor);
_monitor.Set(Pipeline);
_monitor.gameObject.SetActive(false);
}
public void Destroy()
{
UnityEngine.Object.Destroy(_monitor);
}
} }
} }

View File

@ -1,9 +1,108 @@
using UnityEngine; using DCFApixels.DragonECS.Unity.Editors;
using System;
using UnityEngine;
namespace DCFApixels.DragonECS namespace DCFApixels.DragonECS.Unity.Internal
{ {
[MetaTags(MetaTags.HIDDEN), MetaColor(MetaColor.Gray)] [MetaTags(MetaTags.HIDDEN)]
public class WorldMonitor : MonoBehaviour, IEcsProcess [MetaColor(MetaColor.Gray)]
public class WorldMonitor : MonoBehaviour
{ {
private EcsWorld _world;
public EcsWorld World
{
get { return _world; }
}
public void Set(EcsWorld world)
{
_world = world;
}
}
[MetaTags(MetaTags.HIDDEN)]
[MetaColor(MetaColor.Gray)]
public class WorldMonitorSystem : IEcsInit, IEcsWorldEventListener, IEcsEntityEventListener
{
private EcsWorld _world;
private WorldMonitor _monitor;
private Transform _entityMonitorsPoolRoot;
private EntityMonitor[] _entityMonitors;
public EcsWorld World
{
get { return _world; }
}
public WorldMonitorSystem(EcsWorld world)
{
_world = world;
_entityMonitors = new EntityMonitor[_world.Capacity];
_world.AddListener(entityEventListener: this);
_world.AddListener(worldEventListener: this);
}
public void Init()
{
TypeMeta meta = _world.GetMeta();
_monitor = new GameObject($"{UnityEditorUtility.TransformToUpperName(meta.Name)} ( {_world.id} )").AddComponent<WorldMonitor>();
UnityEngine.Object.DontDestroyOnLoad(_monitor);
_monitor.Set(_world);
_monitor.gameObject.SetActive(false);
_entityMonitorsPoolRoot = new GameObject("__POOL").transform;
_entityMonitorsPoolRoot.SetParent(_monitor.transform);
foreach (var e in _world.Entities)
{
InitNewEntity(e, false);
}
}
void IEcsWorldEventListener.OnWorldResize(int newSize)
{
Array.Resize(ref _entityMonitors, newSize);
}
void IEcsWorldEventListener.OnReleaseDelEntityBuffer(ReadOnlySpan<int> buffer) { }
void IEcsWorldEventListener.OnWorldDestroy()
{
UnityEngine.Object.Destroy(_monitor);
UnityEngine.Object.Destroy(_entityMonitorsPoolRoot);
_monitor = null;
_entityMonitorsPoolRoot = null;
}
void IEcsEntityEventListener.OnNewEntity(int entityID)
{
InitNewEntity(entityID, true);
}
private void InitNewEntity(int entityID, bool check)
{
if(_monitor == null) { return; }
ref var _entityMonitorRef = ref _entityMonitors[entityID];
if (_entityMonitorRef == null)
{
_entityMonitorRef = new GameObject($"ENTITY ( {entityID} )").AddComponent<EntityMonitor>();
}
if (check && _entityMonitorRef.Entity.IsAlive)
{
throw new Exception();
}
_entityMonitorRef.Set(_world.GetEntityLong(entityID));
_entityMonitorRef.transform.SetParent(_monitor.transform);
}
void IEcsEntityEventListener.OnDelEntity(int entityID)
{
if(_monitor == null) { return; }
ref var _entityMonitorRef = ref _entityMonitors[entityID];
if (_entityMonitorRef != null)
{
if (_entityMonitorRef.Entity.IsAlive)
{
throw new Exception();
}
_entityMonitorRef.transform.SetParent(_entityMonitorsPoolRoot.transform);
_entityMonitorRef.Set(_world.GetEntityLong(entityID));
}
}
} }
} }

View File

@ -1,4 +1,5 @@
#if UNITY_EDITOR #if UNITY_EDITOR
using Codice.Client.Common.GameUI;
using DCFApixels.DragonECS.Unity.Internal; using DCFApixels.DragonECS.Unity.Internal;
using System; using System;
using System.Reflection; using System.Reflection;
@ -23,6 +24,20 @@ namespace DCFApixels.DragonECS.Unity.Editors
} }
} }
public struct ContentColorScope : IDisposable
{
private readonly Color _oldColor;
public ContentColorScope(Color color)
{
_oldColor = GUI.contentColor;
GUI.contentColor = color;
}
public void Dispose()
{
GUI.contentColor = _oldColor;
}
}
internal readonly static Color GrayColor = new Color32(100, 100, 100, 255); internal readonly static Color GrayColor = new Color32(100, 100, 100, 255);
internal readonly static Color GreenColor = new Color32(75, 255, 0, 255); internal readonly static Color GreenColor = new Color32(75, 255, 0, 255);
internal readonly static Color RedColor = new Color32(255, 0, 75, 255); internal readonly static Color RedColor = new Color32(255, 0, 75, 255);
@ -274,6 +289,20 @@ namespace DCFApixels.DragonECS.Unity.Editors
public static class Layout public static class Layout
{ {
public static void DrawWorldBaseInfo(EcsWorld world)
{
bool isNull = world == null || world.id == 0;
int entitesCount = isNull ? 0 : world.Count;
int capacity = isNull ? 0 : world.Capacity;
int leakedEntitesCount = isNull ? 0 : world.CountLeakedEntitesDebug();
EditorGUILayout.IntField("Entities", entitesCount, EditorStyles.boldLabel);
EditorGUILayout.IntField("Capacity", capacity, EditorStyles.boldLabel);
Color color = leakedEntitesCount > 0 ? Color.yellow : GUI.contentColor;
using (new ContentColorScope(color))
{
EditorGUILayout.IntField("Leaked Entites", leakedEntitesCount, EditorStyles.boldLabel);
}
}
public static void EntityBar(EntityStatus status, int id, short gen, short world) public static void EntityBar(EntityStatus status, int id, short gen, short world)
{ {
float width = EditorGUIUtility.currentViewWidth; float width = EditorGUIUtility.currentViewWidth;

View File

@ -20,6 +20,43 @@ namespace DCFApixels.DragonECS.Unity.Editors
private static GUIContent _singletonContent = null; private static GUIContent _singletonContent = null;
#region TransformFieldName #region TransformFieldName
public static string TransformToUpperName(string name)
{
if (name.Length <= 0)
{
return name;
}
StringBuilder b = new StringBuilder();
bool nextWorld = true;
bool prewIsUpper = false;
for (int i = 0; i < name.Length; i++)
{
char c = name[i];
if (char.IsLetter(c) == false)
{
nextWorld = true;
prewIsUpper = false;
continue;
}
bool isUpper = char.IsUpper(c);
if (isUpper)
{
if (nextWorld == false && prewIsUpper == false)
{
b.Append('_');
}
}
b.Append(char.ToUpper(c));
nextWorld = false;
prewIsUpper = isUpper;
}
return b.ToString();
}
public static string TransformFieldName(string name) public static string TransformFieldName(string name)
{ {
if (name.Length <= 0) if (name.Length <= 0)