From c6699170ae4d400d4c3ee9103babb5db22c64dd8 Mon Sep 17 00:00:00 2001 From: Leopotam Date: Sun, 20 Jun 2021 12:22:43 +0300 Subject: [PATCH] * EcsWorldUnityEditorSystem: renamed to EcsWorldDebugSystem. * Mass refactoring. --- .../{EcsEntity.cs => EcsEntityDebugView.cs} | 37 ++-- ...ity.cs.meta => EcsEntityDebugView.cs.meta} | 0 Editor/EcsWorld.cs | 28 --- Editor/EcsWorld.cs.meta | 11 - Editor/Templates/Startup.cs.txt | 22 +- README.md | 11 +- ...EditorSystem.cs => EcsWorldDebugSystem.cs} | 12 +- ...em.cs.meta => EcsWorldDebugSystem.cs.meta} | 0 Runtime/EditorExtensions.cs | 33 +++ Runtime/EditorExtensions.cs.meta | 3 + Runtime/EditorHelpers.cs | 189 ------------------ Runtime/EditorHelpers.cs.meta | 13 -- ...eopotam.EcsLite.UnityEditor.Runtime.asmdef | 2 +- 13 files changed, 73 insertions(+), 288 deletions(-) rename Editor/{EcsEntity.cs => EcsEntityDebugView.cs} (83%) rename Editor/{EcsEntity.cs.meta => EcsEntityDebugView.cs.meta} (100%) delete mode 100644 Editor/EcsWorld.cs delete mode 100644 Editor/EcsWorld.cs.meta rename Runtime/{EcsWorldUnityEditorSystem.cs => EcsWorldDebugSystem.cs} (87%) rename Runtime/{EcsWorldUnityEditorSystem.cs.meta => EcsWorldDebugSystem.cs.meta} (100%) create mode 100644 Runtime/EditorExtensions.cs create mode 100644 Runtime/EditorExtensions.cs.meta delete mode 100644 Runtime/EditorHelpers.cs delete mode 100644 Runtime/EditorHelpers.cs.meta diff --git a/Editor/EcsEntity.cs b/Editor/EcsEntityDebugView.cs similarity index 83% rename from Editor/EcsEntity.cs rename to Editor/EcsEntityDebugView.cs index 3496a16..30362b9 100644 --- a/Editor/EcsEntity.cs +++ b/Editor/EcsEntityDebugView.cs @@ -12,47 +12,38 @@ using UnityEngine; namespace Leopotam.EcsLite.UnityEditor { - [CustomEditor (typeof (EcsEntityObserver))] - sealed class EcsEntityObserverInspector : Editor { + [CustomEditor (typeof (EcsEntityDebugView))] + sealed class EcsEntityDebugViewInspector : Editor { const int MaxFieldToStringLength = 128; static object[] _componentsCache = new object[32]; - EcsEntityObserver _observer; - public override void OnInspectorGUI () { - if (_observer.World != null) { + var observer = (EcsEntityDebugView) target; + if (observer.World != null) { var guiEnabled = GUI.enabled; GUI.enabled = true; - DrawComponents (); + DrawComponents (observer); GUI.enabled = guiEnabled; EditorUtility.SetDirty (target); } } - void OnEnable () { - _observer = target as EcsEntityObserver; - } - - void OnDisable () { - _observer = null; - } - - void DrawComponents () { - if (_observer.gameObject.activeSelf) { - var count = _observer.World.GetComponents (_observer.Entity, ref _componentsCache); + void DrawComponents (EcsEntityDebugView debugView) { + if (debugView.gameObject.activeSelf) { + var count = debugView.World.GetComponents (debugView.Entity, ref _componentsCache); for (var i = 0; i < count; i++) { var component = _componentsCache[i]; _componentsCache[i] = null; var type = component.GetType (); GUILayout.BeginVertical (GUI.skin.box); - var typeName = EditorHelpers.GetCleanGenericTypeName (type); - if (!EcsComponentInspectors.Render (typeName, type, component, _observer)) { + var typeName = EditorExtensions.GetCleanGenericTypeName (type); + if (!EcsComponentInspectors.Render (typeName, type, component, debugView)) { EditorGUILayout.LabelField (typeName, EditorStyles.boldLabel); var indent = EditorGUI.indentLevel; EditorGUI.indentLevel++; foreach (var field in type.GetFields (BindingFlags.Instance | BindingFlags.Public)) { - DrawTypeField (component, field, _observer); + DrawTypeField (component, field, debugView); } EditorGUI.indentLevel = indent; } @@ -62,7 +53,7 @@ void DrawComponents () { } } - void DrawTypeField (object instance, FieldInfo field, EcsEntityObserver entity) { + void DrawTypeField (object instance, FieldInfo field, EcsEntityDebugView entity) { var fieldValue = field.GetValue (instance); var fieldType = field.FieldType; if (!EcsComponentInspectors.Render (field.Name, fieldType, fieldValue, entity)) { @@ -107,9 +98,9 @@ static EcsComponentInspectors () { } } - public static bool Render (string label, Type type, object value, EcsEntityObserver observer) { + public static bool Render (string label, Type type, object value, EcsEntityDebugView debugView) { if (Inspectors.TryGetValue (type, out var inspector)) { - inspector.OnGUI (label, value, observer.World, observer.Entity); + inspector.OnGUI (label, value, debugView.World, debugView.Entity); return true; } return false; diff --git a/Editor/EcsEntity.cs.meta b/Editor/EcsEntityDebugView.cs.meta similarity index 100% rename from Editor/EcsEntity.cs.meta rename to Editor/EcsEntityDebugView.cs.meta diff --git a/Editor/EcsWorld.cs b/Editor/EcsWorld.cs deleted file mode 100644 index 276b768..0000000 --- a/Editor/EcsWorld.cs +++ /dev/null @@ -1,28 +0,0 @@ -// ---------------------------------------------------------------------------- -// The MIT License -// UnityEditor integration https://github.com/Leopotam/ecslite-unityeditor -// for LeoECS Lite https://github.com/Leopotam/ecslite -// Copyright (c) 2021 Leopotam -// ---------------------------------------------------------------------------- - -using UnityEditor; -using UnityEngine; - -namespace Leopotam.EcsLite.UnityEditor { - [CustomEditor (typeof (EcsWorldObserver))] - sealed class EcsWorldObserverInspector : Editor { - public override void OnInspectorGUI () { - // var observer = (Runtime.EcsWorldObserver) target; - // var stats = observer.GetStats (); - var guiEnabled = GUI.enabled; - GUI.enabled = true; - GUILayout.BeginVertical (GUI.skin.box); - // EditorGUILayout.LabelField ("Components", stats.Components.ToString ()); - // EditorGUILayout.LabelField ("Filters", stats.Filters.ToString ()); - // EditorGUILayout.LabelField ("Active entities", stats.ActiveEntities.ToString ()); - // EditorGUILayout.LabelField ("Reserved entities", stats.ReservedEntities.ToString ()); - GUILayout.EndVertical (); - GUI.enabled = guiEnabled; - } - } -} \ No newline at end of file diff --git a/Editor/EcsWorld.cs.meta b/Editor/EcsWorld.cs.meta deleted file mode 100644 index d5973ba..0000000 --- a/Editor/EcsWorld.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: d8f89072c4ea643e3bc3fc36cb0c1d41 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Editor/Templates/Startup.cs.txt b/Editor/Templates/Startup.cs.txt index 509931e..1ca2060 100644 --- a/Editor/Templates/Startup.cs.txt +++ b/Editor/Templates/Startup.cs.txt @@ -3,18 +3,13 @@ using UnityEngine; namespace #NS# { sealed class #SCRIPTNAME# : MonoBehaviour { - EcsWorld _world; EcsSystems _systems; void Start () { - _world = new EcsWorld (); // register your shared data here, for example: // var shared = new Shared (); - // systems = new EcsSystems (world, shared); - _systems = new EcsSystems (_world); -#if UNITY_EDITOR - Leopotam.EcsLite.UnityEditor.EcsWorldObserver.Create (_world); -#endif + // systems = new EcsSystems (new EcsWorld (), shared); + _systems = new EcsSystems (new EcsWorld ()); _systems // register your systems here, for example: // .Add (new TestSystem1 ()) @@ -27,7 +22,11 @@ namespace #NS# { // for components cleanup (order is important), for example: // .DelHere () // .DelHere () - +#if UNITY_EDITOR + // add debug systems for custom worlds here, for example: + // .Add (new Leopotam.EcsLite.UnityEditor.EcsWorldDebugSystem ("events")) + .Add (new Leopotam.EcsLite.UnityEditor.EcsWorldDebugSystem ()) +#endif .Init (); } @@ -38,12 +37,11 @@ namespace #NS# { void OnDestroy () { if (_systems != null) { _systems.Destroy (); + // add here cleanup for custom worlds, for example: + // _systems.GetWorld ("events").Destroy (); + _systems.GetWorld ().Destroy (); _systems = null; } - if (_world != null) { - _world.Destroy (); - _world = null; - } } } } \ No newline at end of file diff --git a/README.md b/README.md index aa617a0..fc71c60 100644 --- a/README.md +++ b/README.md @@ -39,13 +39,14 @@ If you can't / don't want to use unity modules, code can be cloned or downloaded ```csharp // ecs-startup code: void Start () { - _world = new EcsWorld (); - _systems = new EcsSystems (_world); -#if UNITY_EDITOR - Leopotam.EcsLite.UnityEditor.EcsWorldObserver.Create (_world); -#endif + _systems = new EcsSystems (new EcsWorld ()); _systems .Add (new TestSystem1 ()) +#if UNITY_EDITOR + // add debug systems for custom worlds here, for example: + // .Add (new Leopotam.EcsLite.UnityEditor.EcsWorldDebugSystem ("events")) + .Add (new Leopotam.EcsLite.UnityEditor.EcsWorldDebugSystem ()) +#endif .Init (); } ``` diff --git a/Runtime/EcsWorldUnityEditorSystem.cs b/Runtime/EcsWorldDebugSystem.cs similarity index 87% rename from Runtime/EcsWorldUnityEditorSystem.cs rename to Runtime/EcsWorldDebugSystem.cs index f3b64e9..af96c7b 100644 --- a/Runtime/EcsWorldUnityEditorSystem.cs +++ b/Runtime/EcsWorldDebugSystem.cs @@ -11,17 +11,17 @@ using Object = UnityEngine.Object; namespace Leopotam.EcsLite.UnityEditor { - public sealed class EcsWorldUnityEditorSystem : IEcsPreInitSystem, IEcsRunSystem, IEcsWorldEventListener { + public sealed class EcsWorldDebugSystem : IEcsPreInitSystem, IEcsRunSystem, IEcsWorldEventListener { readonly string _worldName; readonly GameObject _rootGO; readonly Transform _entitiesRoot; readonly bool _bakeComponentsInName; EcsWorld _world; - EcsEntityObserver[] _entities; + EcsEntityDebugView[] _entities; Dictionary _dirtyEntities; Type[] _typesCache; - public EcsWorldUnityEditorSystem (string worldName = null, bool bakeComponentsInName = true) { + public EcsWorldDebugSystem (string worldName = null, bool bakeComponentsInName = true) { _bakeComponentsInName = bakeComponentsInName; _worldName = worldName; _rootGO = new GameObject (_worldName != null ? $"[ECS-WORLD {_worldName}]" : "[ECS-WORLD]"); @@ -35,7 +35,7 @@ public EcsWorldUnityEditorSystem (string worldName = null, bool bakeComponentsIn public void PreInit (EcsSystems systems) { _world = systems.GetWorld (_worldName); if (_world == null) { throw new Exception ("Cant find required world."); } - _entities = new EcsEntityObserver [_world.GetWorldSize ()]; + _entities = new EcsEntityDebugView [_world.GetWorldSize ()]; _dirtyEntities = new Dictionary (_entities.Length); _world.AddEventListener (this); } @@ -47,7 +47,7 @@ public void Run (EcsSystems systems) { if (_world.GetEntityGen (entity) > 0) { var count = _world.GetComponentTypes (entity, ref _typesCache); for (var i = 0; i < count; i++) { - entityName = $"{entityName}:{EditorHelpers.GetCleanGenericTypeName (_typesCache[i])}"; + entityName = $"{entityName}:{EditorExtensions.GetCleanGenericTypeName (_typesCache[i])}"; } } _entities[entity].name = entityName; @@ -59,7 +59,7 @@ public void OnEntityCreated (int entity) { if (!_entities[entity]) { var go = new GameObject (); go.transform.SetParent (_entitiesRoot, false); - var entityObserver = go.AddComponent (); + var entityObserver = go.AddComponent (); entityObserver.Entity = entity; entityObserver.World = _world; _entities[entity] = entityObserver; diff --git a/Runtime/EcsWorldUnityEditorSystem.cs.meta b/Runtime/EcsWorldDebugSystem.cs.meta similarity index 100% rename from Runtime/EcsWorldUnityEditorSystem.cs.meta rename to Runtime/EcsWorldDebugSystem.cs.meta diff --git a/Runtime/EditorExtensions.cs b/Runtime/EditorExtensions.cs new file mode 100644 index 0000000..eb637bb --- /dev/null +++ b/Runtime/EditorExtensions.cs @@ -0,0 +1,33 @@ +// ---------------------------------------------------------------------------- +// The MIT License +// UnityEditor integration https://github.com/Leopotam/ecslite-unityeditor +// for LeoECS Lite https://github.com/Leopotam/ecslite +// Copyright (c) 2021 Leopotam +// ---------------------------------------------------------------------------- + +#if UNITY_EDITOR +using System; +using UnityEngine; + +namespace Leopotam.EcsLite.UnityEditor { + public static class EditorExtensions { + public static string GetCleanGenericTypeName (Type type) { + if (!type.IsGenericType) { + return type.Name; + } + var constraints = ""; + foreach (var constraint in type.GetGenericArguments ()) { + constraints += constraints.Length > 0 ? $", {GetCleanGenericTypeName (constraint)}" : constraint.Name; + } + return $"{type.Name.Substring (0, type.Name.LastIndexOf ("`", StringComparison.Ordinal))}<{constraints}>"; + } + } + + public sealed class EcsEntityDebugView : MonoBehaviour { + [NonSerialized] + public EcsWorld World; + [NonSerialized] + public int Entity; + } +} +#endif \ No newline at end of file diff --git a/Runtime/EditorExtensions.cs.meta b/Runtime/EditorExtensions.cs.meta new file mode 100644 index 0000000..b683b79 --- /dev/null +++ b/Runtime/EditorExtensions.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 72f47a1fd68b4b029e3db6a33a9061a3 +timeCreated: 1624175353 \ No newline at end of file diff --git a/Runtime/EditorHelpers.cs b/Runtime/EditorHelpers.cs deleted file mode 100644 index f6b88df..0000000 --- a/Runtime/EditorHelpers.cs +++ /dev/null @@ -1,189 +0,0 @@ -// ---------------------------------------------------------------------------- -// The MIT License -// UnityEditor integration https://github.com/Leopotam/ecslite-unityeditor -// for LeoECS Lite https://github.com/Leopotam/ecslite -// Copyright (c) 2021 Leopotam -// ---------------------------------------------------------------------------- - -#if UNITY_EDITOR -using System; -using System.Collections.Generic; -using UnityEngine; - -// ReSharper disable UnusedMethodReturnValue.Global -// ReSharper disable InconsistentNaming - -namespace Leopotam.EcsLite.UnityEditor { - public static class EditorHelpers { - public static string GetCleanGenericTypeName (Type type) { - if (!type.IsGenericType) { - return type.Name; - } - var constraints = ""; - foreach (var constraint in type.GetGenericArguments ()) { - constraints += constraints.Length > 0 ? $", {GetCleanGenericTypeName (constraint)}" : constraint.Name; - } - return $"{type.Name.Substring (0, type.Name.LastIndexOf ("`", StringComparison.Ordinal))}<{constraints}>"; - } - } - - public sealed class EcsEntityObserver : MonoBehaviour { - public EcsWorld World; - public int Entity; - } - - // public sealed class EcsSystemsObserver : MonoBehaviour, IEcsSystemsDebugListener { - // EcsSystems _systems; - // - // public static GameObject Create (EcsSystems systems) { - // if (systems == null) { throw new ArgumentNullException (nameof (systems)); } - // var go = new GameObject (systems.Name != null ? $"[ECS-SYSTEMS {systems.Name}]" : "[ECS-SYSTEMS]"); - // DontDestroyOnLoad (go); - // go.hideFlags = HideFlags.NotEditable; - // var observer = go.AddComponent (); - // observer._systems = systems; - // systems.AddDebugListener (observer); - // return go; - // } - // - // public EcsSystems GetSystems () { - // return _systems; - // } - // - // void OnDestroy () { - // if (_systems != null) { - // _systems.RemoveDebugListener (this); - // _systems = null; - // } - // } - // - // void IEcsSystemsDebugListener.OnSystemsDestroyed (EcsSystems systems) { - // // for immediate unregistering this MonoBehaviour from ECS. - // OnDestroy (); - // // for delayed destroying GameObject. - // Destroy (gameObject); - // } - // } - - public sealed class EcsWorldObserver : MonoBehaviour, IEcsWorldEventListener { - EcsWorld _world; - public readonly Dictionary EntityGameObjects = new Dictionary (1024); - static Type[] _componentTypesCache = new Type[32]; - - Transform _entitiesRoot; - // Transform _filtersRoot; - - public static GameObject Create (EcsWorld world, string name = null) { - if (world == null) { throw new ArgumentNullException (nameof (world)); } - var go = new GameObject (name != null ? $"[ECS-WORLD {name}]" : "[ECS-WORLD]"); - DontDestroyOnLoad (go); - go.hideFlags = HideFlags.NotEditable; - var observer = go.AddComponent (); - observer._world = world; - var worldTr = observer.transform; - // entities root. - observer._entitiesRoot = new GameObject ("Entities").transform; - observer._entitiesRoot.gameObject.hideFlags = HideFlags.NotEditable; - observer._entitiesRoot.SetParent (worldTr, false); - // filters root. - // observer._filtersRoot = new GameObject ("Filters").transform; - // observer._filtersRoot.gameObject.hideFlags = HideFlags.NotEditable; - // observer._filtersRoot.SetParent (worldTr, false); - // subscription to events. - world.AddEventListener (observer); - return go; - } - - // public EcsWorldStats GetStats () { - // return _world.GetStats (); - // } - - public void OnEntityCreated (int entity) { - if (!EntityGameObjects.TryGetValue (entity, out var go)) { - go = new GameObject (); - go.transform.SetParent (_entitiesRoot, false); - go.hideFlags = HideFlags.NotEditable; - var unityEntity = go.AddComponent (); - unityEntity.World = _world; - unityEntity.Entity = entity; - EntityGameObjects[entity] = go; - UpdateEntityName (entity, false); - } else { - // need to update cached entity generation. - go.GetComponent ().Entity = entity; - } - go.SetActive (true); - } - - public void OnEntityChanged (int entity) { - UpdateEntityName (entity, true); - } - - public void OnEntityDestroyed (int entity) { - if (!EntityGameObjects.TryGetValue (entity, out var go)) { - throw new Exception ("Unity visualization not exists, looks like a bug"); - } - UpdateEntityName (entity, false); - go.SetActive (false); - } - - public void OnFilterCreated (EcsFilter filter) { - // var go = new GameObject (); - // go.transform.SetParent (_filtersRoot); - // go.hideFlags = HideFlags.NotEditable; - // var observer = go.AddComponent (); - // observer.World = this; - // observer.Filter = filter; - // - // // included components. - // var goName = $"Inc<{filter.IncludedTypes[0].Name}"; - // for (var i = 1; i < filter.IncludedTypes.Length; i++) { - // goName += $",{filter.IncludedTypes[i].Name}"; - // } - // goName += ">"; - // // excluded components. - // if (filter.ExcludedTypes != null) { - // goName += $".Exc<{filter.ExcludedTypes[0].Name}"; - // for (var i = 1; i < filter.ExcludedTypes.Length; i++) { - // goName += $",{filter.ExcludedTypes[i].Name}"; - // } - // goName += ">"; - // } - // go.name = goName; - } - - public void OnWorldResized (int newSize) { } - - public void OnWorldDestroyed (EcsWorld world) { - // for immediate unregistering this MonoBehaviour from ECS. - OnDestroy (); - // for delayed destroying GameObject. - Destroy (gameObject); - } - - void UpdateEntityName (int entity, bool requestComponents) { - var entityName = entity.ToString ("X8"); - if (_world.GetEntityGen (entity) > 0 && requestComponents) { - var count = _world.GetComponentTypes (entity, ref _componentTypesCache); - for (var i = 0; i < count; i++) { - entityName = $"{entityName}:{EditorHelpers.GetCleanGenericTypeName (_componentTypesCache[i])}"; - _componentTypesCache[i] = null; - } - } - EntityGameObjects[entity].name = entityName; - } - - void OnDestroy () { - if (_world != null) { - _world.RemoveEventListener (this); - _world = null; - } - } - } - - // public sealed class EcsFilterObserver : MonoBehaviour { - // public EcsWorldObserver World; - // public EcsFilter Filter; - // } -} -#endif \ No newline at end of file diff --git a/Runtime/EditorHelpers.cs.meta b/Runtime/EditorHelpers.cs.meta deleted file mode 100644 index e9f3bf1..0000000 --- a/Runtime/EditorHelpers.cs.meta +++ /dev/null @@ -1,13 +0,0 @@ -fileFormatVersion: 2 -guid: 24d43f345c6cb4440964c581f6d2f589 -timeCreated: 1519891912 -licenseType: Free -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/Leopotam.EcsLite.UnityEditor.Runtime.asmdef b/Runtime/Leopotam.EcsLite.UnityEditor.Runtime.asmdef index 7a792d2..843b97a 100644 --- a/Runtime/Leopotam.EcsLite.UnityEditor.Runtime.asmdef +++ b/Runtime/Leopotam.EcsLite.UnityEditor.Runtime.asmdef @@ -1,6 +1,6 @@ { "name": "Leopotam.EcsLite.UnityEditor.Runtime", - "rootNamespace": "Leopotam.EcsLite.UnityEditor.Runtime", + "rootNamespace": "Leopotam.EcsLite.UnityEditor", "references": [ "Leopotam.EcsLite" ],