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

View File

@ -23,6 +23,9 @@ namespace DCFApixels.DragonECS.Unity.Editors
EcsWorld world = Target.GetRaw();
GUILayout.Box($"{world.GetMeta().Name} ( {world.id} )", style, GUILayout.ExpandWidth(true));
}
EcsGUI.Layout.DrawWorldBaseInfo(Target.GetCurrentWorldRaw());
base.OnInspectorGUI();
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 const string DEBUG_LAYER = nameof(DEBUG_LAYER);
public EcsWorld[] _worlds;
public DebugModule(params EcsWorld[] worlds)
{
_worlds = worlds;
}
void IEcsModule.Import(EcsPipeline.Builder b)
{
UnityDebugService.Activate();
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)
{
//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;
namespace DCFApixels.DragonECS
namespace DCFApixels.DragonECS.Unity.Internal
{
[MetaTags(MetaTags.HIDDEN), MetaColor(MetaColor.Gray)]
public class EntityMonitor : MonoBehaviour, IEcsProcess
[MetaTags(MetaTags.HIDDEN)]
[MetaColor(MetaColor.Gray)]
public class EntityMonitor : MonoBehaviour
{
private entlong _entity;
private int _entityID;
private short _gen;
private EcsWorld _world;
public EcsWorld World
public entlong Entity
{
get { return _world; }
get { return _entity; }
}
public int EntityID
{
get { return _entityID; }
}
public EntityMonitor(entlong entity)
public void Set(entlong 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)]
public class PipelineMonitor : MonoBehaviour, IEcsProcess
[MetaTags(MetaTags.HIDDEN)]
[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)]
public class WorldMonitor : MonoBehaviour, IEcsProcess
[MetaTags(MetaTags.HIDDEN)]
[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
using Codice.Client.Common.GameUI;
using DCFApixels.DragonECS.Unity.Internal;
using System;
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 GreenColor = new Color32(75, 255, 0, 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 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)
{
float width = EditorGUIUtility.currentViewWidth;

View File

@ -20,6 +20,43 @@ namespace DCFApixels.DragonECS.Unity.Editors
private static GUIContent _singletonContent = null;
#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)
{
if (name.Length <= 0)