diff --git a/package.json b/package.json index 4b134a8..6a84a35 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ }, "displayName": "DragonECS-Unity", "description": "Integration with Unity for DragonECS", - "unity": "2020.3", + "unity": "2021.2", "version": "0.3.0", "repository": { "type": "git", diff --git a/src/Debug/DebugService.meta b/src/Buildin.meta similarity index 77% rename from src/Debug/DebugService.meta rename to src/Buildin.meta index d45a1b6..e8b4de6 100644 --- a/src/Debug/DebugService.meta +++ b/src/Buildin.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: a124aa9f464ff79439c89b52281215d3 +guid: f2b9c91714b4752468a3a5691cbf5237 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/src/Buildin/EcsDefaultWorldProvider.cs b/src/Buildin/EcsDefaultWorldProvider.cs new file mode 100644 index 0000000..dcd6b34 --- /dev/null +++ b/src/Buildin/EcsDefaultWorldProvider.cs @@ -0,0 +1,7 @@ +using UnityEngine; + +namespace DCFApixels.DragonECS +{ + [CreateAssetMenu(fileName = nameof(EcsDefaultWorldProvider), menuName = EcsConsts.FRAMEWORK_NAME + "/WorldProviders/" + nameof(EcsDefaultWorldProvider), order = 1)] + public class EcsDefaultWorldProvider : EcsWorldProvider { } +} diff --git a/src/Debug/Systems/WorldDebugSystem.cs.meta b/src/Buildin/EcsDefaultWorldProvider.cs.meta similarity index 83% rename from src/Debug/Systems/WorldDebugSystem.cs.meta rename to src/Buildin/EcsDefaultWorldProvider.cs.meta index a314c41..a5fb423 100644 --- a/src/Debug/Systems/WorldDebugSystem.cs.meta +++ b/src/Buildin/EcsDefaultWorldProvider.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: d36835beef2392f40854af962ff47472 +guid: 15b6f990a7e05b34a937a9a850d7c68c MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/src/Buildin/EcsDefaultWorldSingletonProvider.cs b/src/Buildin/EcsDefaultWorldSingletonProvider.cs new file mode 100644 index 0000000..cccf86b --- /dev/null +++ b/src/Buildin/EcsDefaultWorldSingletonProvider.cs @@ -0,0 +1,18 @@ +namespace DCFApixels.DragonECS +{ + public class EcsDefaultWorldSingletonProvider : EcsWorldProvider + { + private static EcsDefaultWorldSingletonProvider _instance; + public static EcsDefaultWorldSingletonProvider Instance + { + get + { + if (_instance == null) + { + _instance = FindOrCreateSingleton("SingletonDefaultWorld"); + } + return _instance; + } + } + } +} diff --git a/src/Debug/Editor/EcsEditor.cs.meta b/src/Buildin/EcsDefaultWorldSingletonProvider.cs.meta similarity index 83% rename from src/Debug/Editor/EcsEditor.cs.meta rename to src/Buildin/EcsDefaultWorldSingletonProvider.cs.meta index 1ab7889..ee5180f 100644 --- a/src/Debug/Editor/EcsEditor.cs.meta +++ b/src/Buildin/EcsDefaultWorldSingletonProvider.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: f72bc8ca8108c2b4aac41df126dba1e1 +guid: 7592c6e5a68845c4abeac089e561d8c7 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/src/Buildin/UnityComponents.cs b/src/Buildin/UnityComponents.cs new file mode 100644 index 0000000..57f5e73 --- /dev/null +++ b/src/Buildin/UnityComponents.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace DCFApixels.DragonECS +{ + internal static class UnityComponentConsts + { + private const string UNITY_COMPONENT_NAME = "UnityComponent"; + public static readonly MetaGroup BaseGroup = new MetaGroupRef(UNITY_COMPONENT_NAME); + public static readonly MetaGroup ColliderGroup = new MetaGroupRef($"{UNITY_COMPONENT_NAME}/Collider/"); + public static readonly MetaGroup JointGroup = new MetaGroupRef($"{UNITY_COMPONENT_NAME}/Joint/"); + } + [Serializable] + [MetaColor(255 / 3, 255, 0)] + public struct UnityComponent : IEcsComponent, IEnumerable//IntelliSense hack + where T : Component + { + public T obj; + public UnityComponent(T obj) + { + this.obj = obj; + } + IEnumerator IEnumerable.GetEnumerator() //IntelliSense hack + { + throw new NotImplementedException(); + } + IEnumerator IEnumerable.GetEnumerator() //IntelliSense hack + { + throw new NotImplementedException(); + } + } + + #region Unity Component Templates + public class UnityComponentTemplate : ComponentTemplateBase> where T : Component + { + public override string Name + { + get { return typeof(T).Name; } + } + public override MetaGroup Group + { + get { return UnityComponentConsts.BaseGroup; } + } + public sealed override void Apply(int worldID, int entityID) + { + EcsWorld.GetPoolInstance>>(worldID).TryAddOrGet(entityID) = component; + } + public override void OnValidate(UnityEngine.Object obj) + { + if (component.obj == null) + { + if (obj is GameObject go) + { + component.obj = go.GetComponent(); + } + } + } + } + + [Serializable] + public sealed class UnityComponentRigitBodyInitializer : UnityComponentTemplate { } + [Serializable] + public sealed class UnityComponentAnimatorInitializer : UnityComponentTemplate { } + [Serializable] + public sealed class UnityComponentCharacterControllerInitializer : UnityComponentTemplate { } + #endregion + + #region Collider Templates + [Serializable] + public sealed class UnityComponentColliderTemplate : UnityComponentTemplate + { + public override MetaGroup Group { get { return UnityComponentConsts.ColliderGroup; } } + } + [Serializable] + public sealed class UnityComponentBoxColliderTemplate : UnityComponentTemplate + { + public override MetaGroup Group { get { return UnityComponentConsts.ColliderGroup; } } + } + [Serializable] + public sealed class UnityComponentSphereColliderTemplate : UnityComponentTemplate + { + public override MetaGroup Group { get { return UnityComponentConsts.ColliderGroup; } } + } + [Serializable] + public sealed class UnityComponentCapsuleColliderTemplate : UnityComponentTemplate + { + public override MetaGroup Group { get { return UnityComponentConsts.ColliderGroup; } } + } + [Serializable] + public sealed class UnityComponentMeshColliderTemplate : UnityComponentTemplate + { + public override MetaGroup Group { get { return UnityComponentConsts.ColliderGroup; } } + } + #endregion + + #region Joint Templates + [Serializable] + public sealed class UnityComponentJointTemplate : UnityComponentTemplate + { + public override MetaGroup Group { get { return UnityComponentConsts.JointGroup; } } + } + [Serializable] + public sealed class UnityComponentFixedJointTemplate : UnityComponentTemplate + { + public override MetaGroup Group { get { return UnityComponentConsts.JointGroup; } } + } + [Serializable] + public sealed class UnityComponentCharacterJointTemplate : UnityComponentTemplate + { + public override MetaGroup Group { get { return UnityComponentConsts.JointGroup; } } + } + [Serializable] + public sealed class UnityComponentConfigurableJointTemplate : UnityComponentTemplate + { + public override MetaGroup Group { get { return UnityComponentConsts.JointGroup; } } + } + #endregion +} diff --git a/src/Extensions/UnityComponents.cs.meta b/src/Buildin/UnityComponents.cs.meta similarity index 83% rename from src/Extensions/UnityComponents.cs.meta rename to src/Buildin/UnityComponents.cs.meta index a32753d..5fb8d60 100644 --- a/src/Extensions/UnityComponents.cs.meta +++ b/src/Buildin/UnityComponents.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 47a8547ed46c26e4bb6a68651ad40be0 +guid: 637d69c48b6c0164abe654cd7f5ceb07 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/src/Buildin/UnityGameCyclieProcesses.cs b/src/Buildin/UnityGameCyclieProcesses.cs new file mode 100644 index 0000000..12a1f0e --- /dev/null +++ b/src/Buildin/UnityGameCyclieProcesses.cs @@ -0,0 +1,141 @@ +using DCFApixels.DragonECS.RunnersCore; +using DCFApixels.DragonECS.Unity.Internal; + +namespace DCFApixels.DragonECS +{ + [MetaName(nameof(DrawGizmos))] + [MetaColor(MetaColor.Orange)] + public interface IEcsGizmosProcess : IEcsProcess + { + public void DrawGizmos(); + } + [MetaName(nameof(LateRun))] + [MetaColor(MetaColor.Orange)] + public interface IEcsLateRunProcess : IEcsProcess + { + public void LateRun(); + } + [MetaName(nameof(FixedRun))] + [MetaColor(MetaColor.Orange)] + public interface IEcsFixedRunProcess : IEcsProcess + { + public void FixedRun(); + } + + public static class UnityProcessExtensions + { + public static void DrawGizmos(this EcsPipeline pipeline) + { + pipeline.GetRunnerInstance().DrawGizmos(); + } + public static void LateRun(this EcsPipeline pipeline) + { + pipeline.GetRunnerInstance().LateRun(); + } + public static void FixedRun(this EcsPipeline pipeline) + { + pipeline.GetRunnerInstance().FixedRun(); + } + } +} +namespace DCFApixels.DragonECS.Unity.Internal +{ + + [MetaColor(MetaColor.Orange)] + public class EcsLateGizmosRunner : EcsRunner, IEcsGizmosProcess + { +#if DEBUG && !DISABLE_DEBUG + private EcsProfilerMarker[] _markers; +#endif + public void DrawGizmos() + { +#if DEBUG && !DISABLE_DEBUG + for (int i = 0; i < Process.Length; i++) + { + using (_markers[i].Auto()) + { + Process[i].DrawGizmos(); + } + } +#else + foreach (var item in targets) item.DrawGizmos(); +#endif + } + +#if DEBUG && !DISABLE_DEBUG + protected override void OnSetup() + { + _markers = new EcsProfilerMarker[Process.Length]; + for (int i = 0; i < Process.Length; i++) + { + _markers[i] = new EcsProfilerMarker($"{Process[i].GetType().Name}.{nameof(DrawGizmos)}"); + } + } +#endif + } + + [MetaColor(MetaColor.Orange)] + public class EcsLateRunRunner : EcsRunner, IEcsLateRunProcess + { +#if DEBUG && !DISABLE_DEBUG + private EcsProfilerMarker[] _markers; +#endif + public void LateRun() + { +#if DEBUG && !DISABLE_DEBUG + for (int i = 0; i < Process.Length; i++) + { + using (_markers[i].Auto()) + { + Process[i].LateRun(); + } + } +#else + foreach (var item in targets) item.LateRun(); +#endif + } + +#if DEBUG && !DISABLE_DEBUG + protected override void OnSetup() + { + _markers = new EcsProfilerMarker[Process.Length]; + for (int i = 0; i < Process.Length; i++) + { + _markers[i] = new EcsProfilerMarker($"EcsRunner.{Process[i].GetType().Name}.{nameof(LateRun)}"); + } + } +#endif + } + [MetaColor(MetaColor.Orange)] + public class EcsFixedRunRunner : EcsRunner, IEcsFixedRunProcess + { +#if DEBUG && !DISABLE_DEBUG + private EcsProfilerMarker[] _markers; +#endif + public void FixedRun() + { +#if DEBUG && !DISABLE_DEBUG + for (int i = 0; i < Process.Length; i++) + { + using (_markers[i].Auto()) + { + Process[i].FixedRun(); + } + } +#else + foreach (var item in targets) item.FixedRun(); +#endif + } + +#if DEBUG && !DISABLE_DEBUG + protected override void OnSetup() + { + _markers = new EcsProfilerMarker[Process.Length]; + for (int i = 0; i < Process.Length; i++) + { + _markers[i] = new EcsProfilerMarker($"EcsRunner.{Process[i].GetType().Name}.{nameof(FixedRun)}"); + } + } +#endif + } +} diff --git a/src/Debug/Systems/DebugMonitorBase.cs.meta b/src/Buildin/UnityGameCyclieProcesses.cs.meta similarity index 83% rename from src/Debug/Systems/DebugMonitorBase.cs.meta rename to src/Buildin/UnityGameCyclieProcesses.cs.meta index c35ff94..f2b4894 100644 --- a/src/Debug/Systems/DebugMonitorBase.cs.meta +++ b/src/Buildin/UnityGameCyclieProcesses.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 6b7b4bd406553d64589aa4e085d4ff28 +guid: 9b692b77d059ff445912bada1712ccab MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/src/Extensions.meta b/src/Connectors.meta similarity index 77% rename from src/Extensions.meta rename to src/Connectors.meta index 4a9e845..93be778 100644 --- a/src/Extensions.meta +++ b/src/Connectors.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 37d966ee996491b4d923ae68af4b67cd +guid: 2b32116c3998f6742a35e492a88176be folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/src/Connectors/AutoEntityCreator.cs b/src/Connectors/AutoEntityCreator.cs new file mode 100644 index 0000000..90d3945 --- /dev/null +++ b/src/Connectors/AutoEntityCreator.cs @@ -0,0 +1,92 @@ +using UnityEngine; + +namespace DCFApixels.DragonECS +{ + [DisallowMultipleComponent] + public class AutoEntityCreator : MonoBehaviour + { + [SerializeField] + private EcsEntityConnect _connect; + [SerializeField] + private EcsWorldProviderBase _world; + + private bool _created; + + #region Properties + public EcsEntityConnect Connect => _connect; + #endregion + + #region UnityEvents + private void OnValidate() + { + if (_world == null) + { + AutoResolveWorldProviderDependensy(); + } + } + private void Start() + { + + CreateEntity(); + } + #endregion + + #region Methods + private void AutoResolveWorldProviderDependensy() + { + _world = EcsDefaultWorldSingletonProvider.Instance; + } + public void ManualStart() + { + CreateEntity(); + } + private void CreateEntity() + { + if (_created) + { + return; + } + if (_world == null) + { + AutoResolveWorldProviderDependensy(); + } + else + { + InitConnect(_connect, _world.GetRaw()); + } + _created = true; + } + private void InitConnect(EcsEntityConnect connect, EcsWorld world) + { + connect.ConnectWith(world.NewEntityLong(), true); + } + #endregion + + #region Editor +#if UNITY_EDITOR + [ContextMenu("Autoset")] + internal void Autoset_Editor() + { + foreach (var connect in GetComponentsInChildren()) + { + if (connect.GetComponentInParent() == this) + { + _connect = connect; + AutoResolveWorldProviderDependensy(); + break; + } + } + } + [ContextMenu("Autoset Cascade")] + internal void AutosetCascade_Editor() + { + foreach (var target in GetComponentsInChildren()) + { + target.Autoset_Editor(); + } + + } +#endif + #endregion + } +} \ No newline at end of file diff --git a/src/Debug/Systems/PipelineDebugSystem.cs.meta b/src/Connectors/AutoEntityCreator.cs.meta similarity index 83% rename from src/Debug/Systems/PipelineDebugSystem.cs.meta rename to src/Connectors/AutoEntityCreator.cs.meta index 54d26b0..f8a686f 100644 --- a/src/Debug/Systems/PipelineDebugSystem.cs.meta +++ b/src/Connectors/AutoEntityCreator.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 1caa902906afea3409fc63ed94cbbc11 +guid: e244d7ed454067a4bb82fecd87513856 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/src/Connectors/EcsEntityConnect.cs b/src/Connectors/EcsEntityConnect.cs new file mode 100644 index 0000000..1e6f997 --- /dev/null +++ b/src/Connectors/EcsEntityConnect.cs @@ -0,0 +1,215 @@ +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using UnityEditor; +using UnityEngine; + +namespace DCFApixels.DragonECS +{ + public static class EcsConnect + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Connect(this Component cmp, entlong entity, bool applyTemplates) + { + Connect(entity, cmp, applyTemplates); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Connect(this entlong entity, Component cmp, bool applyTemplates) + { + if (cmp.TryGetComponent(out EcsEntityConnect connect) == false) + { + connect = cmp.gameObject.AddComponent(); + } + connect.ConnectWith(entity, applyTemplates); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Connect(this GameObject go, entlong entity, bool applyTemplates) + { + Connect(entity, go, applyTemplates); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Connect(this entlong entity, GameObject go, bool applyTemplates) + { + if (go.TryGetComponent(out EcsEntityConnect connect) == false) + { + connect = go.AddComponent(); + } + connect.ConnectWith(entity, applyTemplates); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Connect(this EcsEntityConnect connect, entlong entity, bool applyTemplates) + { + Connect(entity, connect, applyTemplates); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Connect(this entlong entity, EcsEntityConnect connect, bool applyTemplates) + { + connect.ConnectWith(entity, applyTemplates); + } + } + + [DisallowMultipleComponent] + public class EcsEntityConnect : MonoBehaviour + { + private entlong _entity; + private EcsWorld _world; + + [SerializeField] + private ScriptableEntityTemplate[] _scriptableTemplates; + [SerializeField] + private MonoEntityTemplate[] _monoTemplates; + + private bool _isConnected = false; + + #region Properties + public entlong Entity + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _entity; } + } + public EcsWorld World + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _world; } + } + public bool IsConnected + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _entity.IsAlive; } + } + public IEnumerable ScriptableTemplates + { + get { return _scriptableTemplates; } + } + public IEnumerable MonoTemplates + { + get { return _monoTemplates; } + } + public IEnumerable AllTemplates + { + get { return ((IEnumerable)_scriptableTemplates).Concat(_monoTemplates); } + } + #endregion + + #region Connect + public void ConnectWith(entlong entity, bool applyTemplates) + { + Disconnect(); + + if (entity.TryUnpack(out int newEntityID, out EcsWorld world)) + { + _isConnected = true; + _entity = entity; + _world = world; + var goConnects = world.GetPool(); + if (goConnects.Has(newEntityID)) + { + ref readonly var goConnect = ref goConnects.Read(newEntityID); + if (goConnect.IsConnected) + { + goConnect.Connect.Disconnect(); + } + } + + goConnects.TryAddOrGet(newEntityID) = new GameObjectConnect(this); + if (applyTemplates) + { + ApplyTemplatesFor(world.id, newEntityID); + } + } + } + public void Disconnect() + { + if(_isConnected == false) + { + return; + } + _isConnected = false; + if (_entity.TryGetID(out int oldEntityID) && _world != null) + { + var unityGameObjects = _world.GetPool(); + unityGameObjects.TryDel(oldEntityID); + } + _world = null; + _entity = entlong.NULL; + } + #endregion + + #region ApplyTemplates + public void ApplyTemplatesFor(short worldID, int entityID) + { + foreach (var template in _scriptableTemplates) + { + template.Apply(worldID, entityID); + } + foreach (var template in _monoTemplates) + { + template.Apply(worldID, entityID); + } + } + #endregion + + #region UnityEvents + private void OnDestroy() + { + Disconnect(); + } + #endregion + + #region Editor +#if UNITY_EDITOR + [ContextMenu("Autoset")] + internal void Autoset_Editor() + { + Autoset(this); + } + [ContextMenu("Autoset Cascade")] + internal void AutosetCascade_Editor() + { + foreach (var item in GetComponentsInChildren()) + { + Autoset(item); + } + } + [ContextMenu("Unlink Entity")] + internal void UnlinkEntity_Editor() + { + ConnectWith(entlong.NULL, false); + } + [ContextMenu("Delete Entity")] + internal void DeleteEntity_Editor() + { + if (_entity.TryUnpack(out int id, out EcsWorld world)) + { + world.DelEntity(id); + } + UnlinkEntity_Editor(); + } + + private static void Autoset(EcsEntityConnect target) + { + var result = target.MonoTemplates.Where(o => o != null).Union(GetTemplatesFor(target.transform)); + + target._monoTemplates = result.ToArray(); + EditorUtility.SetDirty(target); + } + private static IEnumerable GetTemplatesFor(Transform parent) + { + IEnumerable result = parent.GetComponents(); + for (int i = 0; i < parent.childCount; i++) + { + var child = parent.GetChild(i); + if (child.TryGetComponent(out _)) + { + return Enumerable.Empty(); + } + result = result.Concat(GetTemplatesFor(child)); + } + return result; + } +#endif + #endregion + } +} \ No newline at end of file diff --git a/src/Extensions/EcsEntityConnect.cs.meta b/src/Connectors/EcsEntityConnect.cs.meta similarity index 83% rename from src/Extensions/EcsEntityConnect.cs.meta rename to src/Connectors/EcsEntityConnect.cs.meta index aff4433..302c05e 100644 --- a/src/Extensions/EcsEntityConnect.cs.meta +++ b/src/Connectors/EcsEntityConnect.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: cdc92b01ccc1e684f955830aa7cea7d4 +guid: 495156623a7b1e94087f916ba42745e6 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/src/Connectors/EcsWorldProvider.cs b/src/Connectors/EcsWorldProvider.cs new file mode 100644 index 0000000..21145d2 --- /dev/null +++ b/src/Connectors/EcsWorldProvider.cs @@ -0,0 +1,129 @@ +using System; +using UnityEngine; +#if UNITY_EDITOR +using UnityEditor; +#endif + +namespace DCFApixels.DragonECS +{ + [Serializable] + public abstract class EcsWorldProviderBase : ScriptableObject + { + public abstract bool IsEmpty { get; } + public abstract void SetRaw(EcsWorld world); + public abstract EcsWorld GetRaw(); + public abstract EcsWorld GetCurrentWorldRaw(); + } + [Serializable] + public abstract class EcsWorldProvider : EcsWorldProviderBase where TWorld : EcsWorld + { + private TWorld _world; + + [SerializeField] + public short _worldID = -1; + + [Header("Default Configs")] + [Header("Entites")] + [SerializeField] + private int _entitiesCapacity = EcsWorldConfig.Default.EntitiesCapacity; + + [Header("Groups")] + [SerializeField] + private int _groupCapacity = EcsWorldConfig.Default.GroupCapacity; + + [Header("Pools/Components")] + [SerializeField] + private int _poolsCapacity = EcsWorldConfig.Default.PoolsCapacity; + [SerializeField] + private int _poolComponentsCapacity = EcsWorldConfig.Default.PoolComponentsCapacity; + [SerializeField] + private int _poolRecycledComponentsCapacity = EcsWorldConfig.Default.PoolRecycledComponentsCapacity; + + #region Properties + public sealed override bool IsEmpty + { + get { return _world == null; } + } + public int EntitiesCapacity + { + get { return _entitiesCapacity; } + } + public int GroupCapacity + { + get { return _groupCapacity; } + } + public int PoolsCapacity + { + get { return _poolsCapacity; } + } + public int PoolComponentsCapacity + { + get { return _poolComponentsCapacity; } + } + public int PoolRecycledComponentsCapacity + { + get { return _poolRecycledComponentsCapacity; } + } + #endregion + + #region Methods + public sealed override void SetRaw(EcsWorld worldRaw) + { + Set((TWorld)worldRaw); + } + public void Set(TWorld world) + { + _world = world; + } + public sealed override EcsWorld GetRaw() + { + return Get(); + } + public sealed override EcsWorld GetCurrentWorldRaw() + { + return _world; + } + public TWorld Get() + { + if (_world == null || _world.IsDestroyed) + { + _world = BuildWorld(); + OnWorldCreated(_world); + } + return _world; + } + protected static TProvider FindOrCreateSingleton() where TProvider : EcsWorldProvider + { + return FindOrCreateSingleton(typeof(TProvider).Name + "Singleton"); + } + protected static TProvider FindOrCreateSingleton(string name) where TProvider : EcsWorldProvider + { + TProvider instance = Resources.Load(name); + if (instance == null) + { + instance = CreateInstance(); +#if UNITY_EDITOR + if (AssetDatabase.IsValidFolder("Assets/Resources/") == false) + { + System.IO.Directory.CreateDirectory(Application.dataPath + "/Resources/"); + AssetDatabase.Refresh(); + } + AssetDatabase.CreateAsset(instance, "Assets/Resources/" + name + ".asset"); + AssetDatabase.Refresh(); +#endif + } + return instance; + } + #endregion + + #region Events + protected virtual TWorld BuildWorld() + { + EcsWorldConfig config = new EcsWorldConfig(_entitiesCapacity, _groupCapacity, _poolsCapacity, _poolComponentsCapacity, _poolRecycledComponentsCapacity); + ConfigContainer configs = new ConfigContainer().Set(config); + return (TWorld)Activator.CreateInstance(typeof(TWorld), new object[] { configs, _worldID }); + } + protected virtual void OnWorldCreated(TWorld world) { } + #endregion + } +} \ No newline at end of file diff --git a/src/Connectors/EcsWorldProvider.cs.meta b/src/Connectors/EcsWorldProvider.cs.meta new file mode 100644 index 0000000..0929240 --- /dev/null +++ b/src/Connectors/EcsWorldProvider.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b041a062a2a5b2643bec37be4fad79f1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Fetures.meta b/src/Connectors/Editor.meta similarity index 77% rename from src/Fetures.meta rename to src/Connectors/Editor.meta index c6ada3a..310c075 100644 --- a/src/Fetures.meta +++ b/src/Connectors/Editor.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: a20b387d9272da846b2a1206bfb6d53a +guid: 2593ccf9a57f4f045a7e3bf6a839f3c3 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/src/Connectors/Editor/AutoEntityCreatorEditor.cs b/src/Connectors/Editor/AutoEntityCreatorEditor.cs new file mode 100644 index 0000000..402618d --- /dev/null +++ b/src/Connectors/Editor/AutoEntityCreatorEditor.cs @@ -0,0 +1,58 @@ +#if UNITY_EDITOR +using DCFApixels.DragonECS.Unity.Internal; +using UnityEditor; +using UnityEngine; + +namespace DCFApixels.DragonECS.Unity.Editors +{ + [CustomEditor(typeof(AutoEntityCreator))] + [CanEditMultipleObjects] + internal class AutoEntityCreatorEditor : Editor + { + private AutoEntityCreator Target => (AutoEntityCreator)target; + + public override void OnInspectorGUI() + { + EditorGUI.BeginChangeCheck(); + var iterator = serializedObject.GetIterator(); + iterator.NextVisible(true); + while (iterator.NextVisible(false)) + { + EditorGUILayout.PropertyField(iterator, true); + } + if (EditorGUI.EndChangeCheck()) + { + serializedObject.ApplyModifiedProperties(); + } + DrawControlButtons(); + } + + + private void DrawControlButtons() + { + float height = EcsGUI.EntityBarHeight; + Rect rect = GUILayoutUtility.GetRect(EditorGUIUtility.currentViewWidth, height); + EditorGUI.DrawRect(rect, new Color(0f, 0f, 0f, 0.1f)); + rect = RectUtility.AddPadding(rect, 2f, 0f); + var (left, autosetCascadeRect) = RectUtility.HorizontalSliceRight(rect, height); + var (_, autosetRect) = RectUtility.HorizontalSliceRight(left, height); + + if (EcsGUI.AutosetCascadeButton(autosetCascadeRect)) + { + foreach (AutoEntityCreator target in targets) + { + target.AutosetCascade_Editor(); + } + } + + if (EcsGUI.AutosetButton(autosetRect)) + { + foreach (AutoEntityCreator target in targets) + { + target.Autoset_Editor(); + } + } + } + } +} +#endif \ No newline at end of file diff --git a/src/Connectors/Editor/AutoEntityCreatorEditor.cs.meta b/src/Connectors/Editor/AutoEntityCreatorEditor.cs.meta new file mode 100644 index 0000000..ab1c1f5 --- /dev/null +++ b/src/Connectors/Editor/AutoEntityCreatorEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7e21fcbcfdafbb64d86bf965cd16c6b0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Connectors/Editor/EcsEntityConnectEditor.cs b/src/Connectors/Editor/EcsEntityConnectEditor.cs new file mode 100644 index 0000000..453144e --- /dev/null +++ b/src/Connectors/Editor/EcsEntityConnectEditor.cs @@ -0,0 +1,126 @@ +#if UNITY_EDITOR +using DCFApixels.DragonECS.Unity.Internal; +using UnityEditor; +using UnityEngine; + +namespace DCFApixels.DragonECS.Unity.Editors +{ + [CustomEditor(typeof(EcsEntityConnect))] + [CanEditMultipleObjects] + internal class EcsEntityConnectEditor : Editor + { + private bool _isInit = false; + private EcsEntityConnect Target => (EcsEntityConnect)target; + private bool IsMultipleTargets => targets.Length > 1; + + private void Init() + { + if (_isInit) + { + return; + } + _isInit = true; + } + + public override void OnInspectorGUI() + { + Init(); + EcsEntityConnect[] targets = new EcsEntityConnect[this.targets.Length]; + for (int i = 0; i < targets.Length; i++) + { + targets[i] = (EcsEntityConnect)this.targets[i]; + } + DrawEntityInfo(targets); + + DrawTemplates(); + + DrawControlButtons(targets); + DrawComponents(targets); + } + + private void DrawEntityInfo(EcsEntityConnect[] targets) + { + bool isConnected = Target.Entity.TryUnpack(out int id, out short gen, out EcsWorld world); + EcsGUI.EntityStatus status = IsMultipleTargets ? EcsGUI.EntityStatus.Undefined : isConnected ? EcsGUI.EntityStatus.Alive : EcsGUI.EntityStatus.NotAlive; + EcsGUI.Layout.EntityBar(status, id, gen, world.id); + } + + private void DrawTemplates() + { + EditorGUI.BeginChangeCheck(); + var iterator = serializedObject.GetIterator(); + iterator.NextVisible(true); + while (iterator.NextVisible(false)) + { + EditorGUILayout.PropertyField(iterator, true); + } + if (EditorGUI.EndChangeCheck()) + { + serializedObject.ApplyModifiedProperties(); + } + } + + private void DrawControlButtons(EcsEntityConnect[] targets) + { + float height = EcsGUI.EntityBarHeight; + Rect rect = GUILayoutUtility.GetRect(EditorGUIUtility.currentViewWidth, height); + EditorGUI.DrawRect(rect, new Color(0f, 0f, 0f, 0.1f)); + rect = RectUtility.AddPadding(rect, 2f, 0f); + var (_, buttonRect) = RectUtility.HorizontalSliceRight(rect, height); + if (EcsGUI.AutosetCascadeButton(buttonRect)) + { + foreach (var target in targets) + { + target.AutosetCascade_Editor(); + } + } + buttonRect = RectUtility.Move(buttonRect, -height, 0); + if (EcsGUI.AutosetButton(buttonRect)) + { + foreach (var target in targets) + { + target.Autoset_Editor(); + } + } + using (new EditorGUI.DisabledScope(!Application.isPlaying)) + { + buttonRect = RectUtility.Move(buttonRect, -height, 0); + if (EcsGUI.DelEntityButton(buttonRect)) + { + foreach (var target in targets) + { + target.DeleteEntity_Editor(); + } + } + buttonRect = RectUtility.Move(buttonRect, -height, 0); + if (EcsGUI.UnlinkButton(buttonRect)) + { + foreach (var target in targets) + { + target.UnlinkEntity_Editor(); + } + } + } + } + + private void DrawComponents(EcsEntityConnect[] targets) + { + if (IsMultipleTargets) + { + for (int i = 0; i < targets.Length; i++) + { + if (targets[i].IsConnected == true) + { + EditorGUILayout.HelpBox("Multiple component editing is not available.", MessageType.Warning); + return; + } + } + } + if (Target.Entity.TryUnpack(out int entityID, out EcsWorld world)) + { + EcsGUI.Layout.DrawRuntimeComponents(entityID, world); + } + } + } +} +#endif \ No newline at end of file diff --git a/src/Connectors/Editor/EcsEntityConnectEditor.cs.meta b/src/Connectors/Editor/EcsEntityConnectEditor.cs.meta new file mode 100644 index 0000000..497dfeb --- /dev/null +++ b/src/Connectors/Editor/EcsEntityConnectEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 846d3d07f90835048902b412bfac73aa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Connectors/Editor/EcsWorldProviderBaseEditor.cs b/src/Connectors/Editor/EcsWorldProviderBaseEditor.cs new file mode 100644 index 0000000..93cee9f --- /dev/null +++ b/src/Connectors/Editor/EcsWorldProviderBaseEditor.cs @@ -0,0 +1,51 @@ +#if UNITY_EDITOR +using UnityEditor; +using UnityEngine; + +namespace DCFApixels.DragonECS.Unity.Editors +{ + [CustomEditor(typeof(EcsWorldProviderBase), true)] + [CanEditMultipleObjects] + internal class EcsWorldProviderBaseEditor : Editor + { + private EcsWorldProviderBase Target => (EcsWorldProviderBase)target; + + public override void OnInspectorGUI() + { + if (Target.IsEmpty) + { + var style = UnityEditorUtility.GetStyle(new Color32(255, 0, 75, 100)); + GUILayout.Box("Is Empty", style, GUILayout.ExpandWidth(true)); + } + else + { + var style = UnityEditorUtility.GetStyle(new Color32(75, 255, 0, 100)); + 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); + + if (GUILayout.Button("Destroy")) + { + var w = Target.GetRaw(); + if (w != null && w.IsDestroyed == false) + { + w.Destroy(); + } + Target.SetRaw(null); + } + + Rect r = GUILayoutUtility.GetRect(EditorGUIUtility.currentViewWidth, 2f); + Color c = Color.white; + c.a = 0.3f; + EditorGUI.DrawRect(r, c); + GUILayout.Space(10); + } + } +} +#endif \ No newline at end of file diff --git a/src/Connectors/Editor/EcsWorldProviderBaseEditor.cs.meta b/src/Connectors/Editor/EcsWorldProviderBaseEditor.cs.meta new file mode 100644 index 0000000..34cddd1 --- /dev/null +++ b/src/Connectors/Editor/EcsWorldProviderBaseEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1db1c2bb174625249a07a4cef8eff757 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Extensions/UnityGameObject.cs b/src/Connectors/GameObjectConnect.cs similarity index 65% rename from src/Extensions/UnityGameObject.cs rename to src/Connectors/GameObjectConnect.cs index aaa8025..71c21ec 100644 --- a/src/Extensions/UnityGameObject.cs +++ b/src/Connectors/GameObjectConnect.cs @@ -6,22 +6,32 @@ using UnityEditor; namespace DCFApixels.DragonECS { - [DebugColor(DebugColor.Cyan)] - public struct UnityGameObject : IEcsComponent + [MetaColor(MetaColor.Cyan)] + public readonly struct GameObjectConnect : IEcsComponent, IEcsComponentLifecycle { - public GameObject gameObject; - public Transform transform; - - public string Name + public readonly EcsEntityConnect Connect; + public bool IsConnected { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => gameObject.name; + get { return Connect != null; } + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal GameObjectConnect(EcsEntityConnect connect) + { + Connect = connect; } - public UnityGameObject(GameObject gameObject) + void IEcsComponentLifecycle.Enable(ref GameObjectConnect component) { - this.gameObject = gameObject; - transform = gameObject.transform; + component = default; + } + void IEcsComponentLifecycle.Disable(ref GameObjectConnect component) + { + if (component.Connect != null) + { + component.Connect.Disconnect(); + } + component = default; } } @@ -53,19 +63,18 @@ namespace DCFApixels.DragonECS Diamond_Red, Diamond_Purple } - public static class GameObjectIconConsts + internal static class GameObjectIconConsts { public const int RAW_LABEL_ICON_LAST = (int)GameObjectIcon.Label_Purple; } public static class GameObjectRefExt { - public static entlong NewEntityWithGameObject(this EcsWorld self, string name = "EcsEntity", GameObjectIcon icon = GameObjectIcon.NONE) + public static entlong NewEntityWithGameObject(this EcsWorld self, string name = "Entity", GameObjectIcon icon = GameObjectIcon.NONE) { - entlong result = self.GetEntityLong(self.NewEmptyEntity()); + entlong result = self.NewEntityLong(); GameObject newGameObject = new GameObject(name); - newGameObject.AddComponent().ConnectWith(result); - // self.GetPool().Add(result.id) = + newGameObject.AddComponent().ConnectWith(result, false); #if UNITY_EDITOR if (icon != GameObjectIcon.NONE) { @@ -84,7 +93,6 @@ namespace DCFApixels.DragonECS EditorGUIUtility.SetIconForObject(newGameObject, (Texture2D)iconContent.image); } #endif - return result; } } diff --git a/src/Connectors/GameObjectConnect.cs.meta b/src/Connectors/GameObjectConnect.cs.meta new file mode 100644 index 0000000..7ec5d76 --- /dev/null +++ b/src/Connectors/GameObjectConnect.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 398c78166eea90647a60b91b2b9a0f0b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Debug/DebugModule.cs b/src/Debug/DebugModule.cs new file mode 100644 index 0000000..c0bdec7 --- /dev/null +++ b/src/Debug/DebugModule.cs @@ -0,0 +1,33 @@ +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 PipelineMonitorSystem(), DEBUG_LAYER); + foreach (var world in _worlds) + { + 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; + } + } +} diff --git a/src/Debug/Systems/DebugModule.cs.meta b/src/Debug/DebugModule.cs.meta similarity index 100% rename from src/Debug/Systems/DebugModule.cs.meta rename to src/Debug/DebugModule.cs.meta diff --git a/src/Debug/Editor/DebugMonitorPrefs.cs b/src/Debug/Editor/DebugMonitorPrefs.cs deleted file mode 100644 index 276f963..0000000 --- a/src/Debug/Editor/DebugMonitorPrefs.cs +++ /dev/null @@ -1,41 +0,0 @@ -#if UNITY_EDITOR -using UnityEditor; -using UnityEngine; - -namespace DCFApixels.DragonECS.Editors -{ - [FilePath("DragonECS/DebugMonitorPrefs.prefs", FilePathAttribute.Location.ProjectFolder)] - public class DebugMonitorPrefs : ScriptableSingleton - { - private bool _isShowInterfaces = false; - public bool IsShowInterfaces - { - get => _isShowInterfaces; set - { - _isShowInterfaces = value; - Save(false); - } - } - private bool _isShowHidden = false; - public bool IsShowHidden - { - get => _isShowHidden; set - { - _isShowHidden = value; - Save(false); - } - } - - private bool _poolsToggle = false; - public bool PoolsToggle - { - get => _poolsToggle; set - { - _poolsToggle = value; - Save(false); - } - } - - } -} -#endif diff --git a/src/Debug/Editor/EcsEditor.cs b/src/Debug/Editor/EcsEditor.cs deleted file mode 100644 index 3bbd300..0000000 --- a/src/Debug/Editor/EcsEditor.cs +++ /dev/null @@ -1,102 +0,0 @@ -#if UNITY_EDITOR -using System; -using System.Runtime.InteropServices; -using UnityEditor; -using UnityEngine; - -namespace DCFApixels.DragonECS.Editors -{ - [InitializeOnLoad] - public static class EcsEditor - { - static EcsEditor() - { - colorBoxeStyles = new SparseArray(); - } - private static SparseArray colorBoxeStyles = new SparseArray(); - public static GUIStyle GetStyle(Color color, float alphaMultiplier) - { - color.a *= alphaMultiplier; - return GetStyle(color); - } - public static GUIStyle GetStyle(Color32 color32) - { - int colorCode = new Color32Union(color32).colorCode; - if (colorBoxeStyles.TryGetValue(colorCode, out GUIStyle style)) - { - if (style == null || style.normal.background == null) - { - style = CreateStyle(color32, colorCode); - colorBoxeStyles[colorCode] = style; - } - return style; - } - - style = CreateStyle(color32, colorCode); - colorBoxeStyles.Add(colorCode, style); - return style; - } - private static GUIStyle CreateStyle(Color32 color32, int colorCode) - { - GUIStyle result = new GUIStyle(GUI.skin.box); - Color componentColor = color32; - result.normal.background = CreateTexture(2, 2, componentColor); - result.active.background = CreateTexture(2, 2, componentColor); - result.hover.background = CreateTexture(2, 2, componentColor); - result.focused.background = CreateTexture(2, 2, componentColor); - return result; - } - private static Texture2D CreateTexture(int width, int height, Color color) - { - var pixels = new Color[width * height]; - for (var i = 0; i < pixels.Length; ++i) - pixels[i] = color; - - var result = new Texture2D(width, height); - result.SetPixels(pixels); - result.Apply(); - return result; - } - - - public static string GetGenericName(Type type) => EcsDebugUtility.GetGenericTypeName(type); - - public static string GetName() => GetName(typeof(T)); - public static string GetName(Type type) => EcsDebugUtility.GetName(type); - - public static string GetDescription() => GetDescription(typeof(T)); - public static string GetDescription(Type type) => EcsDebugUtility.GetDescription(type); - - #region Utils - [StructLayout(LayoutKind.Explicit, Pack = 1, Size = 4)] - private readonly ref struct Color32Union - { - [FieldOffset(0)] - public readonly int colorCode; - [FieldOffset(0)] - public readonly byte r; - [FieldOffset(1)] - public readonly byte g; - [FieldOffset(2)] - public readonly byte b; - [FieldOffset(3)] - public readonly byte a; - public Color32Union(byte r, byte g, byte b, byte a) : this() - { - this.r = r; - this.g = g; - this.b = b; - this.a = a; - } - public Color32Union(Color32 color) : this() - { - r = color.r; - g = color.g; - b = color.b; - a = color.a; - } - } - #endregion - } -} -#endif diff --git a/src/Debug/Editor/SettingsPrefs.cs b/src/Debug/Editor/SettingsPrefs.cs new file mode 100644 index 0000000..fdedf29 --- /dev/null +++ b/src/Debug/Editor/SettingsPrefs.cs @@ -0,0 +1,57 @@ +#if UNITY_EDITOR +using UnityEditor; +using UnityEngine; + +namespace DCFApixels.DragonECS.Unity.Editors +{ + [FilePath(EcsConsts.FRAMEWORK_NAME + "/" + nameof(SettingsPrefs) + ".prefs", FilePathAttribute.Location.ProjectFolder)] + public class SettingsPrefs : ScriptableSingleton + { + [SerializeField] + private bool _isShowInterfaces = false; + public bool IsShowInterfaces + { + get => _isShowInterfaces; + set + { + _isShowInterfaces = value; + Save(false); + } + } + [SerializeField] + private bool _isShowHidden = false; + public bool IsShowHidden + { + get => _isShowHidden; + set + { + _isShowHidden = value; + Save(false); + } + } + [SerializeField] + private bool _isShowRuntimeComponents = false; + public bool IsShowRuntimeComponents + { + get => _isShowRuntimeComponents; + set + { + _isShowRuntimeComponents = value; + Save(false); + } + } + + [SerializeField] + private bool _poolsToggle = false; + public bool PoolsToggle + { + get => _poolsToggle; + set + { + _poolsToggle = value; + Save(false); + } + } + } +} +#endif diff --git a/src/Debug/Editor/DebugMonitorPrefs.cs.meta b/src/Debug/Editor/SettingsPrefs.cs.meta similarity index 100% rename from src/Debug/Editor/DebugMonitorPrefs.cs.meta rename to src/Debug/Editor/SettingsPrefs.cs.meta diff --git a/src/Debug/Monitors.meta b/src/Debug/Monitors.meta new file mode 100644 index 0000000..58d6270 --- /dev/null +++ b/src/Debug/Monitors.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8b7186fd57cbf9c42b4759c49920a688 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Debug/Monitors/Editor.meta b/src/Debug/Monitors/Editor.meta new file mode 100644 index 0000000..bcd0c58 --- /dev/null +++ b/src/Debug/Monitors/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b1105324b07e39d449acceb24bdd7eb3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Debug/Monitors/Editor/EntityMonitorEditor.cs b/src/Debug/Monitors/Editor/EntityMonitorEditor.cs new file mode 100644 index 0000000..9bbbeba --- /dev/null +++ b/src/Debug/Monitors/Editor/EntityMonitorEditor.cs @@ -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 \ No newline at end of file diff --git a/src/Debug/Monitors/Editor/EntityMonitorEditor.cs.meta b/src/Debug/Monitors/Editor/EntityMonitorEditor.cs.meta new file mode 100644 index 0000000..89a9d88 --- /dev/null +++ b/src/Debug/Monitors/Editor/EntityMonitorEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c5457dbe0f53566419d37e0ee9d9c13f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Debug/Monitors/Editor/PipelineMonitorEditor.cs b/src/Debug/Monitors/Editor/PipelineMonitorEditor.cs new file mode 100644 index 0000000..9936e29 --- /dev/null +++ b/src/Debug/Monitors/Editor/PipelineMonitorEditor.cs @@ -0,0 +1,139 @@ +#if UNITY_EDITOR +using DCFApixels.DragonECS.RunnersCore; +using DCFApixels.DragonECS.Unity.Internal; +using System; +using System.Linq; +using UnityEditor; +using UnityEngine; + +namespace DCFApixels.DragonECS.Unity.Editors +{ + [CustomEditor(typeof(PipelineMonitor))] + internal class PipelineMonitorEditor : Editor + { + private MetaColorAttribute _fakeDebugColorAttribute = new MetaColorAttribute(190, 190, 190); + private Type _debugColorAttributeType = typeof(MetaColorAttribute); + private GUIStyle _headerStyle; + private GUIStyle _interfacesStyle; + private Color _interfaceColor = new Color(0.96f, 1f, 0.16f); + + private GUIStyle systemsListStyle; + + private PipelineMonitor Target => (PipelineMonitor)target; + private bool IsShowInterfaces + { + get { return SettingsPrefs.instance.IsShowInterfaces; } + set { SettingsPrefs.instance.IsShowInterfaces = value; } + } + private bool IsShowHidden + { + get { return SettingsPrefs.instance.IsShowHidden; } + set { SettingsPrefs.instance.IsShowHidden = value; } + } + + public override void OnInspectorGUI() + { + systemsListStyle = new GUIStyle(EditorStyles.miniLabel); + systemsListStyle.wordWrap = true; + + if (Target.Pipeline == null || Target.Pipeline.IsDestoryed) + { + return; + } + if (_headerStyle == null) + { + _headerStyle = new GUIStyle(EditorStyles.boldLabel); + _interfacesStyle = new GUIStyle(EditorStyles.miniLabel); + _interfacesStyle.hover.textColor = _interfaceColor; + _interfacesStyle.focused.textColor = _interfaceColor; + _interfacesStyle.active.textColor = _interfaceColor; + _interfacesStyle.normal.textColor = _interfaceColor; + _interfacesStyle.wordWrap = true; + _headerStyle.fontSize = 28; + } + + GUILayout.Label("[Systems]", _headerStyle); + + IsShowInterfaces = EditorGUILayout.Toggle("Show Interfaces", IsShowInterfaces); + IsShowHidden = EditorGUILayout.Toggle("Show Hidden", IsShowHidden); + + GUILayout.BeginVertical(); + foreach (var item in Target.Pipeline.AllSystems) + { + DrawSystem(item); + } + GUILayout.EndVertical(); + + + GUILayout.Label("[Runners]", _headerStyle); + + GUILayout.BeginVertical(UnityEditorUtility.GetStyle(Color.black, 0.2f)); + foreach (var item in Target.Pipeline.AllRunners) + { + if (item.Key.IsInterface == false) + { + DrawRunner(item.Value); + } + } + GUILayout.EndVertical(); + } + private void DrawSystem(IEcsProcess system) + { + if (system is SystemsLayerMarkerSystem markerSystem) + { + GUILayout.EndVertical(); + GUILayout.BeginVertical(UnityEditorUtility.GetStyle(Color.black, 0.2f)); + + GUILayout.BeginHorizontal(); + GUILayout.Label("<"); + GUILayout.Label($"{markerSystem.name}", EditorStyles.boldLabel); + GUILayout.Label(">", GUILayout.ExpandWidth(false)); + GUILayout.EndHorizontal(); + return; + } + + Type type = system.GetType(); + TypeMeta meta = type.ToMeta(); + + if (CheckIsHidden(meta)) + { + return; + } + + string name = meta.Name; + Color color = meta.Color.ToUnityColor(); + + GUILayout.BeginVertical(UnityEditorUtility.GetStyle(color, 0.2f)); + if (IsShowInterfaces) + { + GUILayout.Label(string.Join(", ", type.GetInterfaces().Select(o => o.Name)), _interfacesStyle); + } + GUILayout.Label(name, EditorStyles.boldLabel); + GUILayout.EndVertical(); + } + private void DrawRunner(IEcsRunner runner) + { + Type type = runner.GetType(); + TypeMeta meta = type.ToMeta(); + + if (CheckIsHidden(meta)) + { + return; + } + Color color = meta.Color.ToUnityColor(); + + GUILayout.BeginVertical(UnityEditorUtility.GetStyle(color, 0.2f)); + GUILayout.Label(meta.Name, EditorStyles.boldLabel); + GUILayout.Label(string.Join(", ", runner.ProcessRaw.Cast().Select(o => o.GetType().Name)), systemsListStyle); + GUILayout.EndVertical(); + } + private bool CheckIsHidden(TypeMeta meta) + { + if (IsShowHidden) + return false; + + return meta.IsHidden; + } + } +} +#endif \ No newline at end of file diff --git a/src/Debug/Monitors/Editor/PipelineMonitorEditor.cs.meta b/src/Debug/Monitors/Editor/PipelineMonitorEditor.cs.meta new file mode 100644 index 0000000..99bc7f1 --- /dev/null +++ b/src/Debug/Monitors/Editor/PipelineMonitorEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 406298e83eb7a0b41b525c7e810c0c6f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Debug/Monitors/Editor/PipelineProcessesMonitorEditor.cs b/src/Debug/Monitors/Editor/PipelineProcessesMonitorEditor.cs new file mode 100644 index 0000000..b5b9e0a --- /dev/null +++ b/src/Debug/Monitors/Editor/PipelineProcessesMonitorEditor.cs @@ -0,0 +1,218 @@ +#if UNITY_EDITOR +using DCFApixels.DragonECS.Unity.Internal; +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEditor; +using UnityEngine; + +namespace DCFApixels.DragonECS.Unity.Editors +{ + [CustomEditor(typeof(PipelineProcessMonitor))] + internal class PipelineProcessesMonitorEditor : Editor + { + private static Type SYSTEM_INTERFACE_TYPE = typeof(IEcsProcess); + + private bool _isInit = false; + private List _processList = new List(); + private Dictionary _processeIndexes = new Dictionary(); + private SystemData[] _systemsList; + + private PipelineProcessMonitor Target => (PipelineProcessMonitor)target; + private bool IsShowInterfaces + { + get { return SettingsPrefs.instance.IsShowInterfaces; } + set { SettingsPrefs.instance.IsShowInterfaces = value; } + } + private bool IsShowHidden + { + get { return SettingsPrefs.instance.IsShowHidden; } + set { SettingsPrefs.instance.IsShowHidden = value; } + } + + private void Init() + { + if (_isInit) + { + return; + } + + _processList.Clear(); + _processeIndexes.Clear(); + IEnumerable fileretSystems = Target.Pipeline.AllSystems; + if (IsShowHidden) + { fileretSystems = fileretSystems.Where(o => o is SystemsLayerMarkerSystem == false); } + else + { fileretSystems = fileretSystems.Where(o => o.GetMeta().IsHidden == false); } + _systemsList = fileretSystems.Select(o => new SystemData(o.GetMeta(), o)).ToArray(); + + for (int i = 0; i < _systemsList.Length; i++) + { + var system = _systemsList[i]; + foreach (var interfaceType in system.meta.Type.GetInterfaces()) + { + TypeMeta meta = interfaceType.ToMeta(); + if (SYSTEM_INTERFACE_TYPE.IsAssignableFrom(interfaceType) && SYSTEM_INTERFACE_TYPE != interfaceType && (IsShowHidden || meta.IsHidden == false)) + { + ProcessData data; + if (_processeIndexes.TryGetValue(interfaceType, out int index) == false) + { + index = _processList.Count; + _processeIndexes.Add(interfaceType, index); + + data = new ProcessData(); + data.meta = meta; + data.systemsBitMask = new BitMask(_systemsList.Length); + _processList.Add(data); + } + data = _processList[index]; + data.systemsBitMask[i] = true; + } + } + } + _isInit = true; + } + private Vector2 _position; + private Vector2 _cellsize = new Vector2(EditorGUIUtility.singleLineHeight, EditorGUIUtility.singleLineHeight); + private Vector2 _nameCellSize = new Vector2(200f, 200f); + + private (TypeMeta system, TypeMeta process) _selectedPointMeta = default; + public override void OnInspectorGUI() + { + EditorGUI.BeginChangeCheck(); + IsShowHidden = EditorGUILayout.Toggle("Show Hidden", IsShowHidden); + if (EditorGUI.EndChangeCheck()) + { + _isInit = false; + } + Init(); + + GUILayout.Label("", GUILayout.ExpandWidth(true), GUILayout.Height(400f)); + Rect rect = GUILayoutUtility.GetLastRect(); + + rect.height = 400f; + + + Rect rectView = new Rect(0f, 0f, _nameCellSize.x + _cellsize.x * _processList.Count, _nameCellSize.y + _cellsize.y * _systemsList.Length); + EditorGUI.DrawRect(rect, new Color(0, 0, 0, 0.6f)); + GUI.Button(rect, "", EditorStyles.helpBox); + + _position = GUI.BeginScrollView(rect, _position, rectView, true, true); + + Vector2 pivod = _nameCellSize; + rect = default; + rect.y = _nameCellSize.y; + rect.width = _nameCellSize.x; + rect.height = _cellsize.x; + rect.y -= _cellsize.y; + //processes line + for (int i = 0; i < _processList.Count; i++) + { + TypeMeta meta = _processList[i].meta; + Rect lineRect = rect; + lineRect.y = 0f; + lineRect.x = _nameCellSize.x + _cellsize.x * i; + lineRect.width = _cellsize.x; + lineRect.height = rectView.height; + lineRect = RectUtility.AddPadding(lineRect, 1, 0); + + Color color = meta.Color.ToUnityColor(); + color = NormalizeGridColor(i, color); + EditorGUI.DrawRect(lineRect, color); + + if (EcsGUI.HitTest(lineRect)) + { + GUI.Button(lineRect, "", EditorStyles.selectionRect); + _selectedPointMeta.process = meta; + } + GUIUtility.RotateAroundPivot(90, pivod); + GUI.Label(rect, UnityEditorUtility.GetLabel(meta.Name), EditorStyles.miniBoldLabel); + GUIUtility.RotateAroundPivot(-90, pivod); + + pivod.x += _cellsize.x; + rect.x += _cellsize.x; + } + + rect = default; + rect.y = _nameCellSize.y; + rect.width = _nameCellSize.x; + rect.height = _cellsize.x; + //systems line + for (int i = 0; i < _systemsList.Length; i++) + { + TypeMeta meta = _systemsList[i].meta; + string name = meta.Name; + + Rect lineRect = rect; + lineRect.width = rectView.width; + lineRect = RectUtility.AddPadding(lineRect, 0, 1); + + Color color = meta.Color.ToUnityColor(); + color = NormalizeGridColor(i, color); + EditorGUI.DrawRect(lineRect, color); + + if (EcsGUI.HitTest(lineRect)) + { + GUI.Button(lineRect, "", EditorStyles.selectionRect); + _selectedPointMeta.system = meta; + } + GUI.Label(rect, UnityEditorUtility.GetLabel(name, i + " " + name), EditorStyles.miniBoldLabel); + rect.y += _cellsize.y; + } + + Texture checkIcon = EditorGUIUtility.IconContent("DotFill").image; + + //matrix + for (int x = 0; x < _processList.Count; x++) + { + var process = _processList[x]; + for (int y = 0; y < _systemsList.Length; y++) + { + rect = new Rect(x * _cellsize.x + _nameCellSize.x, y * _cellsize.y + _nameCellSize.y, _cellsize.x, _cellsize.y); + bool flag = process.systemsBitMask[y]; + if (flag) + { + GUI.Label(rect, UnityEditorUtility.GetLabel(checkIcon)); + } + } + } + GUI.EndScrollView(); + + Rect r = GUILayoutUtility.GetRect(EditorGUIUtility.currentViewWidth, EditorGUIUtility.singleLineHeight); + if (_selectedPointMeta.process != null && _selectedPointMeta.system != null) + { + GUI.Label(r, $"{_selectedPointMeta.process.Name}-{_selectedPointMeta.system.Name}"); + } + } + + private static Color NormalizeGridColor(int index, Color color) + { + if (index % 2 == 1) + { + color = color / 1.4f; + color.a = 0.3f; + } + else + { + color.a = 0.5f; + } + return color; + } + private class SystemData + { + public TypeMeta meta; + public IEcsProcess system; + public SystemData(TypeMeta meta, IEcsProcess system) + { + this.meta = meta; + this.system = system; + } + } + private class ProcessData + { + public TypeMeta meta; + public BitMask systemsBitMask; + } + } +} +#endif \ No newline at end of file diff --git a/src/Debug/Monitors/Editor/PipelineProcessesMonitorEditor.cs.meta b/src/Debug/Monitors/Editor/PipelineProcessesMonitorEditor.cs.meta new file mode 100644 index 0000000..8451072 --- /dev/null +++ b/src/Debug/Monitors/Editor/PipelineProcessesMonitorEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d3cd5a052acb5c4469a9802390bb532a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Debug/Monitors/Editor/WorldMonitorEditor.cs b/src/Debug/Monitors/Editor/WorldMonitorEditor.cs new file mode 100644 index 0000000..7470fec --- /dev/null +++ b/src/Debug/Monitors/Editor/WorldMonitorEditor.cs @@ -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 \ No newline at end of file diff --git a/src/Debug/Monitors/Editor/WorldMonitorEditor.cs.meta b/src/Debug/Monitors/Editor/WorldMonitorEditor.cs.meta new file mode 100644 index 0000000..84872b2 --- /dev/null +++ b/src/Debug/Monitors/Editor/WorldMonitorEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7aadf8c836c97694186e4b3aeb01fcce +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Debug/Monitors/EntityMonitor.cs b/src/Debug/Monitors/EntityMonitor.cs new file mode 100644 index 0000000..c3f5cbc --- /dev/null +++ b/src/Debug/Monitors/EntityMonitor.cs @@ -0,0 +1,19 @@ +using UnityEngine; + +namespace DCFApixels.DragonECS.Unity.Internal +{ + [MetaTags(MetaTags.HIDDEN)] + [MetaColor(MetaColor.Gray)] + internal class EntityMonitor : MonoBehaviour + { + private entlong _entity; + public entlong Entity + { + get { return _entity; } + } + public void Set(entlong entity) + { + _entity = entity; + } + } +} diff --git a/src/Debug/Monitors/EntityMonitor.cs.meta b/src/Debug/Monitors/EntityMonitor.cs.meta new file mode 100644 index 0000000..b9fb7dd --- /dev/null +++ b/src/Debug/Monitors/EntityMonitor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b3c51f9f4aa13e74fbb4339f8c1746d4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Debug/Monitors/PipelineMonitor.cs b/src/Debug/Monitors/PipelineMonitor.cs new file mode 100644 index 0000000..b5b1774 --- /dev/null +++ b/src/Debug/Monitors/PipelineMonitor.cs @@ -0,0 +1,48 @@ +using DCFApixels.DragonECS.Unity.Editors; +using UnityEngine; + +namespace DCFApixels.DragonECS.Unity.Internal +{ + [MetaTags(MetaTags.HIDDEN)] + [MetaColor(MetaColor.Gray)] + internal 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)] + internal class PipelineMonitorSystem : IEcsInit, IEcsPipelineMember, IEcsDestroy + { + private PipelineMonitor _monitor; + private PipelineProcessMonitor _processesMonitor; + public EcsPipeline Pipeline { get; set; } + + public void Init() + { + TypeMeta meta = typeof(EcsPipeline).ToMeta(); + _monitor = new GameObject($"{UnityEditorUtility.TransformToUpperName(meta.Name)}").AddComponent(); + UnityEngine.Object.DontDestroyOnLoad(_monitor); + _monitor.Set(Pipeline); + _monitor.gameObject.SetActive(false); + + _processesMonitor = new GameObject($"PROCESS_MATRIX").AddComponent(); + _processesMonitor.transform.SetParent(_monitor.transform); + _processesMonitor.Set(Pipeline); + _processesMonitor.gameObject.SetActive(false); + } + + public void Destroy() + { + UnityEngine.Object.Destroy(_monitor); + } + } +} diff --git a/src/Debug/Monitors/PipelineMonitor.cs.meta b/src/Debug/Monitors/PipelineMonitor.cs.meta new file mode 100644 index 0000000..0444ffa --- /dev/null +++ b/src/Debug/Monitors/PipelineMonitor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 03154a226ad86e24ebfa4faf43da8310 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Debug/Monitors/PipelineProcessMonitor.cs b/src/Debug/Monitors/PipelineProcessMonitor.cs new file mode 100644 index 0000000..3401463 --- /dev/null +++ b/src/Debug/Monitors/PipelineProcessMonitor.cs @@ -0,0 +1,19 @@ +using UnityEngine; + +namespace DCFApixels.DragonECS.Unity.Editors +{ + [MetaTags(MetaTags.HIDDEN)] + [MetaColor(MetaColor.Gray)] + internal class PipelineProcessMonitor : MonoBehaviour + { + private EcsPipeline _pipeline; + public EcsPipeline Pipeline + { + get { return _pipeline; } + } + public void Set(EcsPipeline pipeline) + { + _pipeline = pipeline; + } + } +} diff --git a/src/Debug/Monitors/PipelineProcessMonitor.cs.meta b/src/Debug/Monitors/PipelineProcessMonitor.cs.meta new file mode 100644 index 0000000..628f9be --- /dev/null +++ b/src/Debug/Monitors/PipelineProcessMonitor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2e20707e619a5b742aeb26e3eff3a9c4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Debug/Monitors/WorldMonitor.cs b/src/Debug/Monitors/WorldMonitor.cs new file mode 100644 index 0000000..0c5eca2 --- /dev/null +++ b/src/Debug/Monitors/WorldMonitor.cs @@ -0,0 +1,108 @@ +using DCFApixels.DragonECS.Unity.Editors; +using System; +using UnityEngine; + +namespace DCFApixels.DragonECS.Unity.Internal +{ + [MetaTags(MetaTags.HIDDEN)] + [MetaColor(MetaColor.Gray)] + internal 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)] + internal 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(); + 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 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(); + } + 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)); + } + } + } +} diff --git a/src/Debug/Monitors/WorldMonitor.cs.meta b/src/Debug/Monitors/WorldMonitor.cs.meta new file mode 100644 index 0000000..a595b88 --- /dev/null +++ b/src/Debug/Monitors/WorldMonitor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3d65916dbb4c8f74cb5239c5bbf7ba31 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Debug/Systems/DebugModule.cs b/src/Debug/Systems/DebugModule.cs deleted file mode 100644 index f64f978..0000000 --- a/src/Debug/Systems/DebugModule.cs +++ /dev/null @@ -1,22 +0,0 @@ -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.ImportSystems(EcsPipeline.Builder b) - { - b.Layers.Insert(EcsConsts.POST_END_LAYER, DEBUG_LAYER); - b.Add(new PipelineDebugSystem(), DEBUG_LAYER); - foreach (var world in _worlds) - { - b.Add(new WorldDebugSystem(world), DEBUG_LAYER); - } - } - } -} diff --git a/src/Debug/Systems/DebugMonitorBase.cs b/src/Debug/Systems/DebugMonitorBase.cs deleted file mode 100644 index f4f89d1..0000000 --- a/src/Debug/Systems/DebugMonitorBase.cs +++ /dev/null @@ -1,17 +0,0 @@ -using UnityEngine; - - -namespace DCFApixels.DragonECS.Unity.Debug -{ - public class DebugMonitorBase : MonoBehaviour - { - internal string monitorName; - - - private void Awake() - { - DontDestroyOnLoad(this.gameObject); - gameObject.SetActive(false); - } - } -} diff --git a/src/Debug/Systems/PipelineDebugSystem.cs b/src/Debug/Systems/PipelineDebugSystem.cs deleted file mode 100644 index 465a7e3..0000000 --- a/src/Debug/Systems/PipelineDebugSystem.cs +++ /dev/null @@ -1,337 +0,0 @@ -using DCFApixels.DragonECS.Unity.Debug; -using System.Reflection; -using UnityEngine; - -namespace DCFApixels.DragonECS -{ - [DebugHide, DebugColor(DebugColor.Gray)] - public class PipelineDebugSystem : IEcsPreInitProcess - { - private string _monitorName; - public PipelineDebugSystem(string monitorName = "Pipeline") - { - _monitorName = monitorName; - } - - void IEcsPreInitProcess.PreInit(EcsPipeline pipeline) - { - PipelineDebugMonitor monitor = new GameObject(EcsConsts.DEBUG_PREFIX + _monitorName).AddComponent(); - monitor.source = this; - monitor.pipeline = pipeline; - monitor.monitorName = _monitorName; - - PipelineProcessesDebugMonitor processesMonitor = new GameObject(EcsConsts.DEBUG_PREFIX + "Processes Matrix").AddComponent(); - processesMonitor.transform.parent = monitor.transform; - processesMonitor.source = this; - processesMonitor.pipeline = pipeline; - processesMonitor.monitorName = "Processes Matrix"; - - //foreach (var item in pipeline.AllSystems) //Вырезано пока не сделаю TODO в SystemDebugMonitor - //{ - // DebugNameAttribute debugName = item.GetType().GetCustomAttribute(); - // string name = debugName == null ? item.GetType().Name : debugName.name; - // SystemDebugMonitor.CreateMonitor(monitor.transform, item, name); - //} - } - } - - public class PipelineDebugMonitor : DebugMonitorBase - { - internal PipelineDebugSystem source; - internal EcsPipeline pipeline; - } - - public class PipelineProcessesDebugMonitor : DebugMonitorBase - { - internal PipelineDebugSystem source; - internal EcsPipeline pipeline; - } - -#if UNITY_EDITOR - namespace Editors - { - using DCFApixels.DragonECS.Internal; - using DCFApixels.DragonECS.RunnersCore; - using System; - using System.Collections.Generic; - using System.Linq; - using UnityEditor; - - [CustomEditor(typeof(PipelineDebugMonitor))] - public class PipelineDebugMonitorEditor : Editor - { - private DebugColorAttribute _fakeDebugColorAttribute = new DebugColorAttribute(190, 190, 190); - private Type _debugColorAttributeType = typeof(DebugColorAttribute); - private GUIStyle _headerStyle; - private GUIStyle _interfacesStyle; - private Color _interfaceColor = new Color(0.96f, 1f, 0.16f); - private PipelineDebugMonitor Target => (PipelineDebugMonitor)target; - - - private GUIStyle systemsListStyle; - - public override void OnInspectorGUI() - { - systemsListStyle = new GUIStyle(EditorStyles.miniLabel); - systemsListStyle.wordWrap = true; - - if (Target.source == null) - return; - if (_headerStyle == null) - { - _headerStyle = new GUIStyle(EditorStyles.boldLabel); - _interfacesStyle = new GUIStyle(EditorStyles.miniLabel); - _interfacesStyle.hover.textColor = _interfaceColor; - _interfacesStyle.focused.textColor = _interfaceColor; - _interfacesStyle.active.textColor = _interfaceColor; - _interfacesStyle.normal.textColor = _interfaceColor; - _interfacesStyle.wordWrap = true; - _headerStyle.fontSize = 28; - } - - GUILayout.Label("[Systems]", _headerStyle); - - DebugMonitorPrefs.instance.IsShowInterfaces = EditorGUILayout.Toggle("Show Interfaces", DebugMonitorPrefs.instance.IsShowInterfaces); - DebugMonitorPrefs.instance.IsShowHidden = EditorGUILayout.Toggle("Show Hidden", DebugMonitorPrefs.instance.IsShowHidden); - - GUILayout.BeginVertical(); - foreach (var item in Target.pipeline.AllSystems) - { - DrawSystem(item); - } - GUILayout.EndVertical(); - - - GUILayout.Label("[Runners]", _headerStyle); - - GUILayout.BeginVertical(EcsEditor.GetStyle(Color.black, 0.2f)); - foreach (var item in Target.pipeline.AllRunners) - { - DrawRunner(item.Value); - } - GUILayout.EndVertical(); - } - - private void DrawSystem(IEcsSystem system) - { - if (system is SystemsLayerMarkerSystem markerSystem) - { - GUILayout.EndVertical(); - GUILayout.BeginVertical(EcsEditor.GetStyle(Color.black, 0.2f)); - - GUILayout.BeginHorizontal(); - GUILayout.Label("<"); - GUILayout.Label($"{markerSystem.name}", EditorStyles.boldLabel); - GUILayout.Label(">", GUILayout.ExpandWidth(false)); - GUILayout.EndHorizontal(); - return; - } - - Type type = system.GetType(); - - if (CheckIsHidden(type)) - return; - - string name = EcsEditor.GetGenericName(type); - Color color = (GetAttribute(type) ?? _fakeDebugColorAttribute).GetUnityColor(); - - GUILayout.BeginVertical(EcsEditor.GetStyle(color, 0.2f)); - if (DebugMonitorPrefs.instance.IsShowInterfaces) - { - GUILayout.Label(string.Join(", ", type.GetInterfaces().Select(o => o.Name)), _interfacesStyle); - } - GUILayout.Label(name, EditorStyles.boldLabel); - GUILayout.EndVertical(); - } - - private void DrawRunner(IEcsRunner runner) - { - Type type = runner.GetType(); - if (CheckIsHidden(type)) - return; - - Color color = (GetAttribute(type) ?? _fakeDebugColorAttribute).GetUnityColor(); - GUILayout.BeginVertical(EcsEditor.GetStyle(color, 0.2f)); - GUILayout.Label(EcsEditor.GetGenericName(type), EditorStyles.boldLabel); - GUILayout.Label(string.Join(", ", runner.Targets.Cast().Select(o => o.GetType().Name)), systemsListStyle); - GUILayout.EndVertical(); - } - - private TAttribute GetAttribute(Type target) where TAttribute : Attribute - { - var result = target.GetCustomAttributes(_debugColorAttributeType, false); - if (result.Length > 0) - return (TAttribute)result[0]; - return null; - } - - private bool CheckIsHidden(Type target) - { - if (DebugMonitorPrefs.instance.IsShowHidden) - return false; - return target.GetCustomAttribute() != null; - } - } - - [CustomEditor(typeof(PipelineProcessesDebugMonitor))] - public class PipelineProcessesDebugMonitorEditor : Editor - { - private bool _isInit = false; - private List _processesList = new List(); - private Dictionary _processeIndexes = new Dictionary(); - - private PipelineProcessesDebugMonitor Target => (PipelineProcessesDebugMonitor)target; - private Type systemInterfaceType = typeof(IEcsSystem); - - private IEcsSystem[] _systems; - private void Init() - { - if (_isInit) - return; - bool showHidden = DebugMonitorPrefs.instance.IsShowHidden; - _processesList.Clear(); - _processeIndexes.Clear(); - if (showHidden) - _systems = Target.pipeline.AllSystems.Where(o => o is SystemsLayerMarkerSystem == false).ToArray(); - else - _systems = Target.pipeline.AllSystems.Where(o => o.GetType().GetCustomAttribute() == null).ToArray(); - - int i = 0; - foreach (var system in _systems) - { - foreach (var intr in system.GetType().GetInterfaces()) - { - if(systemInterfaceType.IsAssignableFrom(intr) && systemInterfaceType != intr && (showHidden || intr.GetCustomAttribute() == null)) - { - ProcessData data; - if (!_processeIndexes.TryGetValue(intr, out int index)) - { - index = _processesList.Count; - _processeIndexes.Add(intr, index); - - data = new ProcessData(); - _processesList.Add(data); - - data.name = EcsEditor.GetGenericName(intr); - data.interfaceType = intr; - data.systemsBitMask = new BitMask(_systems.Length); - } - data = _processesList[index]; - data.systemsBitMask[i] = true; - } - } - i++; - } - - _isInit = true; - } - private Vector2 _position; - private Vector2 _cellsize = new Vector2(EditorGUIUtility.singleLineHeight, EditorGUIUtility.singleLineHeight); - private Vector2 _nameCellSize = new Vector2(200f, 200f); - - public override void OnInspectorGUI() - { - EditorGUI.BeginChangeCheck(); - DebugMonitorPrefs.instance.IsShowHidden = EditorGUILayout.Toggle("Show Hidden", DebugMonitorPrefs.instance.IsShowHidden); - if (EditorGUI.EndChangeCheck()) - { - _isInit = false; - } - - Init(); - - Rect rect; - Rect lineRect; - GUILayout.Label("", GUILayout.ExpandWidth(true), GUILayout.Height(400f)); - rect = GUILayoutUtility.GetLastRect(); - - rect.height = 400f; - - - Rect rectView = new Rect(0f, 0f, _nameCellSize.x + _cellsize.x * _processesList.Count, _nameCellSize.y + _cellsize.y * _systems.Length); - _position = GUI.BeginScrollView(rect, _position, rectView, true, true); - - List systeNames = new List(); - - var blackStyle = EcsEditor.GetStyle(Color.black, 0.04f); - var whiteStyle = EcsEditor.GetStyle(Color.white, 0.04f); - GUIContent label = new GUIContent(); - - - Vector2 pivod = _nameCellSize; - rect = new Rect(); - rect.y = _nameCellSize.y; - rect.width = _nameCellSize.x; - rect.height = _cellsize.x; - rect.y -= _cellsize.y; - for (int i = 0; i < _processesList.Count; i++) - { - lineRect = rect; - lineRect.y = 0f; - lineRect.x = _nameCellSize.x + _cellsize.x * i; - lineRect.width = _cellsize.x; - lineRect.height = rectView.height; - GUI.Label(lineRect, "", i % 2 == 1 ? whiteStyle : blackStyle); - - GUIUtility.RotateAroundPivot(90, pivod); - //GUIContent label = new GUIContent(_processesList[i].name, "." + _processesList[i].name); - label.text = _processesList[i].name; - label.tooltip = "." + _processesList[i].name; - GUI.Label(rect, label, EditorStyles.miniBoldLabel); - GUIUtility.RotateAroundPivot(-90, pivod); - - pivod.x += _cellsize.x; - rect.x += _cellsize.x; - } - - //GUIUtility.RotateAroundPivot(-90, _nameCellSize); - rect = new Rect(); - rect.y = _nameCellSize.y; - rect.width = _nameCellSize.x; - rect.height = _cellsize.x; - for (int i = 0; i < _systems.Length; i++) - { - string name = EcsEditor.GetGenericName(_systems[i].GetType()); - systeNames.Add(name); - - lineRect = rect; - lineRect.width = rectView.width; - GUI.Label(lineRect, "", i % 2 == 1 ? whiteStyle : blackStyle); - - // GUIContent label = new GUIContent(name, i + " " + name); - label.text = name; - label.tooltip = i + " " + name; - GUI.Label(rect, label, EditorStyles.miniBoldLabel); - rect.y += _cellsize.y; - } - - for (int x = 0; x < _processesList.Count; x++) - { - var process = _processesList[x]; - for (int y = 0; y < _systems.Length; y++) - { - string systemName = systeNames[x]; - rect = new Rect(x * _cellsize.x + _nameCellSize.x, y * _cellsize.y + _nameCellSize.y, _cellsize.x, _cellsize.y); - bool flag = process.systemsBitMask[y]; - string labeltext = flag ? "^" : " "; - label.text = labeltext; - label.tooltip = $"{process.name}-{systemName}"; - GUI.Label(rect, label); - //GUI.Label(rect, lable, flag ? whiteStyle : blackStyle); - // GUI.Label(rect, label, EditorStyles.helpBox); - } - } - - GUI.EndScrollView(); - } - - private class ProcessData - { - public Type interfaceType; - public string name; - public BitMask systemsBitMask; - } - } - } -#endif -} diff --git a/src/Debug/Systems/WorldDebugSystem.cs b/src/Debug/Systems/WorldDebugSystem.cs deleted file mode 100644 index 7b92448..0000000 --- a/src/Debug/Systems/WorldDebugSystem.cs +++ /dev/null @@ -1,182 +0,0 @@ -using DCFApixels.DragonECS.Unity.Debug; -using System.Collections; -using System.Collections.Generic; -using UnityEngine; - -namespace DCFApixels.DragonECS -{ - [DebugHide, DebugColor(DebugColor.Gray)] - public class WorldDebugSystem : IEcsRunProcess - { - private string _monitorName; - private EcsWorld _ecsWorld; - - public WorldDebugSystem(EcsWorld ecsWorld, string monitorName = null) - { - _monitorName = monitorName; - if (string.IsNullOrEmpty(_monitorName)) _monitorName = ecsWorld.GetType().Name; - _ecsWorld = ecsWorld; - WorldDebugMonitor monitor = new GameObject(EcsConsts.DEBUG_PREFIX + _monitorName).AddComponent(); - WorldPoolsMonitor poolsmonitor = new GameObject(EcsConsts.DEBUG_PREFIX + "Pools").AddComponent(); - poolsmonitor.transform.SetParent(monitor.transform); - - monitor.source = this; - monitor.world = _ecsWorld; - monitor.monitorName = _monitorName; - - poolsmonitor.source = this; - poolsmonitor.world = _ecsWorld; - poolsmonitor.monitorName = "pools"; - } - - public void Run(EcsPipeline pipeline) - { - } - } - - public class WorldDebugMonitor : DebugMonitorBase - { - internal WorldDebugSystem source; - internal EcsWorld world; - } - -#if UNITY_EDITOR - namespace Editors - { - using UnityEditor; - - [CustomEditor(typeof(WorldDebugMonitor))] - public class WorldDebugMonitorEditor : Editor - { - private WorldDebugMonitor Target => (WorldDebugMonitor)target; - - public override void OnInspectorGUI() - { - GUILayout.Label($"Size: {Target.world.Capacity}"); - GUILayout.Label($"Total entities: {Target.world.Count}"); - } - } - } -#endif - - - - - public class WorldPoolsMonitor : DebugMonitorBase - { - internal WorldDebugSystem source; - internal EcsWorld world; - } - -#if UNITY_EDITOR - namespace Editors - { - using System.Linq; - using UnityEditor; - using System.Reflection; - - [CustomEditor(typeof(WorldPoolsMonitor))] - public class WorldPoolsMonitorEditor : Editor - { - private static Vector2 _poolBlockMinSize = new Vector2(80, 160); - private static Vector2 _poolProgressBasrSize = _poolBlockMinSize * new Vector2(1f, 0.8f); - - private WorldPoolsMonitor Target => (WorldPoolsMonitor)target; - - private Vector2 _scroll; - - public override void OnInspectorGUI() - { - _scroll = GUILayout.BeginScrollView(_scroll, GUILayout.Height(800f)); - - var pools = Target.world.AllPools.ToArray().Where(o => !o.IsNullOrDummy()).OfType(); - - GUILayout.Label("", GUILayout.ExpandWidth(true)); - - float width = GUILayoutUtility.GetLastRect().width; - - Vector3 newPoolBlockSize = _poolBlockMinSize; - int widthCount = Mathf.Max(1, Mathf.Min((Mathf.FloorToInt(width / _poolBlockMinSize.x)), pools.Count())); - newPoolBlockSize.x = width / widthCount; - - int x = -1, y = 0; - foreach (var pool in pools) - { - if(++x >= widthCount) - { - x = 0; - y++; - } - - DrawPoolBlock(pool, new Rect(newPoolBlockSize.x * x, newPoolBlockSize.y * y, newPoolBlockSize.x, newPoolBlockSize.y)); - } - GUILayout.EndScrollView(); - } - - - private void DrawPoolBlock(IEcsPool pool, Rect position) - { - int count = pool.Count; - int capacity = pool.Capacity < 0 ? count : pool.Capacity; - - Color defaultContentColor = GUI.contentColor; - GUI.contentColor = Color.black * 0.925f; - - position = AddMargin(position, 1f, 1f); - - EditorGUI.DrawRect(position, Color.black* 0.16f); - - Rect progressBar = new Rect(Vector2.zero, _poolProgressBasrSize); - progressBar.width = position.width; - progressBar.center = position.center - Vector2.up * _poolBlockMinSize.y * 0.09f; - - - Color mainColor = new Color(0.3f, 1f, 0f, 1f); - var debugColor = pool.ComponentType.GetCustomAttribute(); - if (debugColor != null) - { - mainColor = debugColor.GetUnityColor(); - } - Color backgroundColor = mainColor * 0.3f + Color.white * 0.2f; - - EditorGUI.DrawRect(progressBar, backgroundColor); - - progressBar.yMin = progressBar.yMax - ((float)count / capacity) * progressBar.height; - - GUIStyle textStyle0 = new GUIStyle(EditorStyles.miniBoldLabel); - textStyle0.alignment = TextAnchor.MiddleCenter; - - Color foregroundColor = mainColor; - EditorGUI.DrawRect(progressBar, foregroundColor); - GUI.Label(progressBar, count.ToString(), textStyle0); - - GUIStyle textStyle1 = new GUIStyle(EditorStyles.miniBoldLabel); - textStyle1.alignment = TextAnchor.UpperCenter; - GUI.Label(AddMargin(position, 3f, 3f), "Total\r\n"+ capacity, textStyle1); - - GUI.contentColor = defaultContentColor; - GUIStyle textStyle2 = new GUIStyle(EditorStyles.miniBoldLabel); - textStyle2.wordWrap = true; - textStyle2.alignment = TextAnchor.LowerCenter; - string name = EcsEditor.GetGenericName(pool.ComponentType); - GUIContent label = new GUIContent(name, $"{name} e:{count}"); - GUI.Label(AddMargin(position, -10f, 3f), label, textStyle2); - - } - - private Rect AddMargin(Rect rect, Vector2 value) - { - return AddMargin(rect, value.x, value.y); - } - private Rect AddMargin(Rect rect, float x, float y) - { - rect.yMax -= y; - rect.yMin += y; - rect.xMax -= x; - rect.xMin += x; - return rect; - } - } - } -#endif -} diff --git a/src/Debug/DebugService/UnityDebugService.cs b/src/Debug/UnityDebugService.cs similarity index 54% rename from src/Debug/DebugService/UnityDebugService.cs rename to src/Debug/UnityDebugService.cs index 90605e1..f29ed63 100644 --- a/src/Debug/DebugService/UnityDebugService.cs +++ b/src/Debug/UnityDebugService.cs @@ -1,19 +1,33 @@ using System; using Unity.Profiling; +using UnityEditor; using UnityEngine; namespace DCFApixels.DragonECS { + [InitializeOnLoad] public class UnityDebugService : DebugService { - public static void Init() => Set(); - private ProfilerMarker[] _profilerMarkers = new ProfilerMarker[64]; - + static UnityDebugService() + { + Activate(); + } + public static void Activate() + { + Set(); + } public override void Print(string tag, object v) { string log; - if (!string.IsNullOrEmpty(tag)) + if (v is Exception e) + { + Debug.LogException(e); + return; + } + + bool hasTag = string.IsNullOrEmpty(tag) == false; + if (hasTag) { log = $".[{tag}] {v}"; string taglower = tag.ToLower(); @@ -32,27 +46,29 @@ namespace DCFApixels.DragonECS } Debug.Log(v); } - - public override void ProfileMarkBegin(int id) + public override void Break() + { + Debug.Break(); + } + public sealed override void ProfilerMarkBegin(int id) { _profilerMarkers[id].Begin(); } - - public override void ProfileMarkEnd(int id) + public sealed override void ProfilerMarkEnd(int id) { _profilerMarkers[id].End(); } - - protected override void OnDelMark(int id) + protected sealed override void OnDelProfilerMark(int id) { _profilerMarkers[id] = default; } - - protected override void OnNewMark(int id, string name) + protected sealed override void OnNewProfilerMark(int id, string name) { - if (id >= _profilerMarkers.Length) Array.Resize(ref _profilerMarkers, _profilerMarkers.Length << 1); + if (id >= _profilerMarkers.Length) + { + Array.Resize(ref _profilerMarkers, _profilerMarkers.Length << 1); + } _profilerMarkers[id] = new ProfilerMarker(ProfilerCategory.Scripts, name); } - } } diff --git a/src/Debug/DebugService/UnityDebugService.cs.meta b/src/Debug/UnityDebugService.cs.meta similarity index 100% rename from src/Debug/DebugService/UnityDebugService.cs.meta rename to src/Debug/UnityDebugService.cs.meta diff --git a/src/EcsUnityConsts.cs b/src/EcsUnityConsts.cs index 5196c2e..fda3692 100644 --- a/src/EcsUnityConsts.cs +++ b/src/EcsUnityConsts.cs @@ -1,7 +1,7 @@ namespace DCFApixels.DragonECS { - public static class EcsUnityConsts + public static class EcsUnityConsts { - public const string INFO_MARK = "[i]"; + public const string INFO_MARK = "[D]"; } } diff --git a/src/EntityTemplate/Editor.meta b/src/EntityTemplate/Editor.meta new file mode 100644 index 0000000..9b140d9 --- /dev/null +++ b/src/EntityTemplate/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d8c6da13649cc094e80f3ec624bad02b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/EntityTemplate/Editor/EntityTemplateEditor.cs b/src/EntityTemplate/Editor/EntityTemplateEditor.cs new file mode 100644 index 0000000..2bba492 --- /dev/null +++ b/src/EntityTemplate/Editor/EntityTemplateEditor.cs @@ -0,0 +1,254 @@ +#if UNITY_EDITOR +using DCFApixels.DragonECS.Unity.Internal; +using System; +using System.Reflection; +using UnityEditor; +using UnityEngine; + +namespace DCFApixels.DragonECS.Unity.Editors +{ + public abstract class EntityTemplateEditorBase : Editor + { + private static readonly Rect RemoveButtonRect = new Rect(0f, 0f, 19f, 19f); + private static readonly Rect TooltipIconRect = new Rect(0f, 0f, 19f, 19f); + + private GUIStyle _removeButtonStyle; + private GenericMenu _genericMenu; + private bool _isInit = false; + + #region Init + private void Init() + { + if (_genericMenu == null) { _isInit = false; } + if (_isInit) { return; } + + var tmpstylebase = UnityEditorUtility.GetStyle(new Color(0.9f, 0f, 0.22f), 0.5f); + var tmpStyle = UnityEditorUtility.GetStyle(new Color(1f, 0.5f, 0.7f), 0.5f); + + _removeButtonStyle = new GUIStyle(EditorStyles.linkLabel); + _removeButtonStyle.alignment = TextAnchor.MiddleCenter; + + _removeButtonStyle.normal = tmpstylebase.normal; + _removeButtonStyle.hover = tmpStyle.normal; + _removeButtonStyle.active = tmpStyle.normal; + _removeButtonStyle.focused = tmpStyle.normal; + + _removeButtonStyle.padding = new RectOffset(0, 0, 0, 0); + _removeButtonStyle.margin = new RectOffset(0, 0, 0, 0); + _removeButtonStyle.border = new RectOffset(0, 0, 0, 0); + + _genericMenu = new GenericMenu(); + + var componentTemplateDummies = ComponentTemplateTypeCache.Dummies; + foreach (var dummy in componentTemplateDummies) + { + ITypeMeta meta = dummy is ITypeMeta metaOverride ? metaOverride : dummy.Type.ToMeta(); + string name = meta.Name; + string description = meta.Description; + MetaGroup group = meta.Group; + + if (group.Name.Length > 0) + { + name = group.Name + name; + } + + if (string.IsNullOrEmpty(description) == false) + { + name = $"{name} {EcsUnityConsts.INFO_MARK}"; + } + _genericMenu.AddItem(new GUIContent(name, description), false, OnAddComponent, dummy); + } + + _isInit = true; + } + #endregion + + #region Add/Remove + private void OnAddComponent(object obj) + { + Type componentType = obj.GetType(); + if (this.target is ITemplateInternal target) + { + SerializedProperty componentsProp = serializedObject.FindProperty(target.ComponentsPropertyName); + for (int i = 0; i < componentsProp.arraySize; i++) + { + if (componentsProp.GetArrayElementAtIndex(i).managedReferenceValue.GetType() == componentType) + { + return; + } + } + + componentsProp.InsertArrayElementAtIndex(0); + + componentsProp.GetArrayElementAtIndex(0).managedReferenceValue = ((IComponentTemplate)obj).Clone(); + + serializedObject.ApplyModifiedProperties(); + EditorUtility.SetDirty(this.target); + } + } + private void OnRemoveComponentAt(int index) + { + if (this.target is ITemplateInternal target) + { + SerializedProperty componentsProp = serializedObject.FindProperty(target.ComponentsPropertyName); + componentsProp.DeleteArrayElementAtIndex(index); + serializedObject.ApplyModifiedProperties(); + EditorUtility.SetDirty(this.target); + } + } + #endregion + + protected void Draw(ITemplateInternal target) + { + Init(); + SerializedProperty componentsProp = serializedObject.FindProperty(target.ComponentsPropertyName); + if (componentsProp == null) + { + return; + } + + GUILayout.BeginVertical(UnityEditorUtility.GetStyle(Color.black, 0.2f)); + DrawTop(target); + GUILayout.Label("", GUILayout.Height(0), GUILayout.ExpandWidth(true)); + for (int i = 0; i < componentsProp.arraySize; i++) + { + DrawComponentData(componentsProp.GetArrayElementAtIndex(i), i); + } + GUILayout.EndVertical(); + } + private void DrawTop(ITemplateInternal target) + { + switch (EcsGUI.Layout.AddClearComponentButtons()) + { + case EcsGUI.AddClearComponentButton.AddComponent: + Init(); + _genericMenu.ShowAsContext(); + break; + case EcsGUI.AddClearComponentButton.Clear: + Init(); + serializedObject.FindProperty(target.ComponentsPropertyName).ClearArray(); + serializedObject.ApplyModifiedProperties(); + break; + } + } + + private void DrawComponentData(SerializedProperty componentRefProp, int index) + { + IComponentTemplate template = componentRefProp.managedReferenceValue as IComponentTemplate; + if (template == null || componentRefProp.managedReferenceValue == null) + { + DrawDamagedComponent(componentRefProp, index); + return; + } + + + Type componentType; + SerializedProperty componentProperty = componentRefProp; + ComponentTemplateBase customInitializer = componentProperty.managedReferenceValue as ComponentTemplateBase; + if (customInitializer != null) + { + componentProperty = componentRefProp.FindPropertyRelative("component"); + componentType = customInitializer.GetType().GetField("component", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FieldType; + } + else + { + componentType = componentProperty.managedReferenceValue.GetType(); ; + } + + ITypeMeta meta = template is ITypeMeta metaOverride ? metaOverride : template.Type.ToMeta(); + string name = meta.Name; + string description = meta.Description; + Color panelColor = meta.Color.ToUnityColor().Desaturate(EscEditorConsts.COMPONENT_DRAWER_DESATURATE); + + //GUIContent label = new GUIContent(name); + GUIContent label = UnityEditorUtility.GetLabel(name); + bool isEmpty = componentType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).Length <= 0; + float padding = EditorGUIUtility.standardVerticalSpacing; + Color alphaPanelColor = panelColor; + alphaPanelColor.a = EscEditorConsts.COMPONENT_DRAWER_ALPHA; + + Rect removeButtonRect = GUILayoutUtility.GetLastRect(); + + EditorGUI.BeginChangeCheck(); + GUILayout.BeginVertical(UnityEditorUtility.GetStyle(alphaPanelColor)); + + #region Draw Component Block + bool isRemoveComponent = false; + removeButtonRect.yMin = removeButtonRect.yMax; + removeButtonRect.yMax += RemoveButtonRect.height; + removeButtonRect.xMin = removeButtonRect.xMax - RemoveButtonRect.width; + removeButtonRect.center += Vector2.up * padding * 2f; + + if (EcsGUI.CloseButton(removeButtonRect)) + { + isRemoveComponent = true; + } + + if (isEmpty) + { + GUILayout.Label(label); + } + else + { + EditorGUILayout.PropertyField(componentProperty, label, true); + } + if (isRemoveComponent) + { + OnRemoveComponentAt(index); + } + if (string.IsNullOrEmpty(description) == false) + { + Rect tooltipIconRect = TooltipIconRect; + tooltipIconRect.center = removeButtonRect.center; + tooltipIconRect.center -= Vector2.right * tooltipIconRect.width; + EcsGUI.DescriptionIcon(tooltipIconRect, description); + } + #endregion + + GUILayout.EndVertical(); + + if (EditorGUI.EndChangeCheck()) + { + componentProperty.serializedObject.ApplyModifiedProperties(); + EditorUtility.SetDirty(componentProperty.serializedObject.targetObject); + } + } + + private void DrawDamagedComponent(SerializedProperty componentRefProp, int index) + { + GUILayout.BeginHorizontal(); + + EditorGUILayout.HelpBox($"Damaged component. If the problem occurred after renaming a component or initializer. use MovedFromAttrubute", MessageType.Warning); + + Rect lastrect = GUILayoutUtility.GetLastRect(); + Rect removeButtonRect = RemoveButtonRect; + removeButtonRect.center = new Vector2(lastrect.xMax + removeButtonRect.width, lastrect.yMin + removeButtonRect.height / 2f); + + GUILayout.Label("", GUILayout.Width(removeButtonRect.width)); + if (GUI.Button(removeButtonRect, "x", _removeButtonStyle)) + { + OnRemoveComponentAt(index); + } + + GUILayout.EndHorizontal(); + } + } + + [CustomEditor(typeof(ScriptableEntityTemplate), true)] + public class EntityTemplatePresetEditor : EntityTemplateEditorBase + { + public override void OnInspectorGUI() + { + Draw((ITemplateInternal)target); + } + } + [CustomEditor(typeof(MonoEntityTemplate), true)] + public class EntityTemplateEditor : EntityTemplateEditorBase + { + public override void OnInspectorGUI() + { + Draw((ITemplateInternal)target); + } + } +} +#endif diff --git a/src/EntityTemplate/EntityTemplateEditor.cs.meta b/src/EntityTemplate/Editor/EntityTemplateEditor.cs.meta similarity index 100% rename from src/EntityTemplate/EntityTemplateEditor.cs.meta rename to src/EntityTemplate/Editor/EntityTemplateEditor.cs.meta diff --git a/src/EntityTemplate/EntityTemplate.cs b/src/EntityTemplate/EntityTemplate.cs deleted file mode 100644 index 837cae8..0000000 --- a/src/EntityTemplate/EntityTemplate.cs +++ /dev/null @@ -1,40 +0,0 @@ -using UnityEngine; - -namespace DCFApixels.DragonECS -{ - public class EntityTemplate : MonoBehaviour, ITemplateInternal - { - [SerializeReference] - private ITemplateComponent[] _components; - string ITemplateInternal.ComponentsPropertyName => nameof(_components); - - public void Apply(EcsWorld world, int entityID) - { - foreach (var item in _components) - item.Add(world, entityID); - } - - private void OnDrawGizmos() - { - if (_components == null) return; - foreach (var item in _components) - { - if (item is ITemplateComponentGizmos g) - g.OnGizmos(transform, ITemplateComponentGizmos.Mode.Always); - } - } - private void OnDrawGizmosSelected() - { - if (_components == null) return; - foreach (var item in _components) - { - if (item is ITemplateComponentGizmos g) - g.OnGizmos(transform, ITemplateComponentGizmos.Mode.Selected); - } - } - public void Clear() - { - _components = new ITemplateComponent[0]; - } - } -} diff --git a/src/EntityTemplate/EntityTemplate.cs.meta b/src/EntityTemplate/EntityTemplate.cs.meta deleted file mode 100644 index 3a14226..0000000 --- a/src/EntityTemplate/EntityTemplate.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 3c96e3aedd5a69443af75096e5561265 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/src/EntityTemplate/EntityTemplateEditor.cs b/src/EntityTemplate/EntityTemplateEditor.cs deleted file mode 100644 index 78f66c3..0000000 --- a/src/EntityTemplate/EntityTemplateEditor.cs +++ /dev/null @@ -1,259 +0,0 @@ -using System; -using System.Reflection; - -namespace DCFApixels.DragonECS -{ -#if UNITY_EDITOR - namespace Editors - { - using UnityEditor; - using UnityEngine; - - public abstract class EntityTemplateEditorBase: Editor - { - private static readonly Rect RemoveButtonRect = new Rect(0f, 0f, 15f, 15f); - private static readonly Rect TooltipIconRect = new Rect(0f, 0f, 15f, 15f); - - private GUIStyle removeButtonStyle; - private GenericMenu genericMenu; - private bool _isInit = false; - - #region Init - private void Init() - { - if (genericMenu == null) - _isInit = false; - if (_isInit) - return; - - var tmpstylebase = EcsEditor.GetStyle(new Color(0.9f, 0f, 0.22f), 0.5f); - var tmpStyle = EcsEditor.GetStyle(new Color(1f, 0.5f, 0.7f), 0.5f); - - removeButtonStyle = new GUIStyle(EditorStyles.linkLabel); - removeButtonStyle.alignment = TextAnchor.MiddleCenter; - - removeButtonStyle.normal = tmpstylebase.normal; - removeButtonStyle.hover = tmpStyle.normal; - removeButtonStyle.active = tmpStyle.normal; - removeButtonStyle.focused = tmpStyle.normal; - - removeButtonStyle.padding = new RectOffset(0, 0, 0, 0); - removeButtonStyle.margin = new RectOffset(0, 0, 0, 0); - removeButtonStyle.border = new RectOffset(0, 0, 0, 0); - - genericMenu = new GenericMenu(); - - var dummies = TemplateBrowsableTypeCache.Dummies; - foreach ( var dummy in dummies ) - { - string name, description; - if (dummy is ITemplateComponentName browsableName) - name = browsableName.Name; - else - name = EcsEditor.GetName(dummy.GetType()); - - if (dummy is TemplateComponentInitializerBase initializer) - description = initializer.Description; - else - description = EcsEditor.GetDescription(dummy.GetType()); - - if (!string.IsNullOrEmpty(description)) - { - name = $"{name} {EcsUnityConsts.INFO_MARK}"; - } - - genericMenu.AddItem(new GUIContent(name, description), false, OnAddComponent, dummy); - } - - _isInit = true; - } - #endregion - - #region Add/Remove - private void OnAddComponent(object obj) - { - Type componentType = obj.GetType(); - if (this.target is ITemplateInternal target) - { - SerializedProperty componentsProp = serializedObject.FindProperty(target.ComponentsPropertyName); - for (int i = 0; i < componentsProp.arraySize; i++) - { - if (componentsProp.GetArrayElementAtIndex(i).managedReferenceValue.GetType() == componentType) - return; - } - - componentsProp.InsertArrayElementAtIndex(0); - - componentsProp.GetArrayElementAtIndex(0).managedReferenceValue = ((ITemplateComponent)obj).Clone(); - - serializedObject.ApplyModifiedProperties(); - EditorUtility.SetDirty(this.target); - } - } - private void OnRemoveComponentAt(int index) - { - if (this.target is ITemplateInternal target) - { - SerializedProperty componentsProp = serializedObject.FindProperty(target.ComponentsPropertyName); - componentsProp.DeleteArrayElementAtIndex(index); - serializedObject.ApplyModifiedProperties(); - EditorUtility.SetDirty(this.target); - } - } - #endregion - - protected void Draw(ITemplateInternal target) - { - Init(); - SerializedProperty componentsProp = serializedObject.FindProperty(target.ComponentsPropertyName); - if (componentsProp == null) - return; - - DrawTop(target); - for (int i = 0; i < componentsProp.arraySize; i++) - { - DrawComponentData(componentsProp.GetArrayElementAtIndex(i), i); - GUILayout.Space(EditorGUIUtility.standardVerticalSpacing * 2); - } - DrawFooter(target); - } - private void DrawTop(ITemplateInternal target) - { - if (GUILayout.Button("Add Component", GUILayout.Height(24f))) - { - Init(); - genericMenu.ShowAsContext(); - } - } - private void DrawFooter(ITemplateInternal target) - { - if (GUILayout.Button("Clear", GUILayout.Height(24f))) - { - Init(); - serializedObject.FindProperty(target.ComponentsPropertyName).ClearArray(); - serializedObject.ApplyModifiedProperties(); - } - } - private void DrawComponentData(SerializedProperty componentRefProp, int index) - { - ITemplateComponent browsable = componentRefProp.managedReferenceValue as ITemplateComponent; - if(browsable == null) - { - DrawDamagedComponent(componentRefProp, index); - return; - } - ITemplateComponentName browsableName = browsable as ITemplateComponentName; - - if (componentRefProp.managedReferenceValue == null) - { - DrawDamagedComponent(componentRefProp, index); - return; - } - - Type initializerType; - Type componentType; - SerializedProperty componentProperty = componentRefProp; - TemplateComponentInitializerBase customInitializer = componentProperty.managedReferenceValue as TemplateComponentInitializerBase; - if (customInitializer != null) - { - componentProperty = componentRefProp.FindPropertyRelative("component"); - initializerType = customInitializer.Type; - componentType = customInitializer.GetType().GetField("component", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FieldType; - } - else - { - initializerType = componentProperty.managedReferenceValue.GetType(); - componentType = initializerType; - } - - Type type = browsable.GetType(); - string name = browsableName == null ? type.Name : GetLastPathComponent(browsableName.Name); - string description = customInitializer != null ? customInitializer.Description : initializerType.GetCustomAttribute()?.description; - Color panelColor = customInitializer != null ? customInitializer.Color : initializerType.GetCustomAttribute()?.GetUnityColor() ?? Color.black; - - GUILayout.BeginHorizontal(); - - GUILayout.BeginVertical(EcsEditor.GetStyle(panelColor, 0.2f)); - - EditorGUI.BeginChangeCheck(); - GUIContent label = new GUIContent(name, $"{name} "); - if (componentType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).Length <= 0) - { - GUILayout.Label(label); - } - else - { - EditorGUILayout.PropertyField(componentProperty, label, true); - } - if (EditorGUI.EndChangeCheck()) - { - componentProperty.serializedObject.ApplyModifiedProperties(); - EditorUtility.SetDirty(componentProperty.serializedObject.targetObject); - } - - Rect lastrect = GUILayoutUtility.GetLastRect(); - Rect removeButtonRect = RemoveButtonRect; - removeButtonRect.center = new Vector2(lastrect.xMax + removeButtonRect.width, lastrect.yMin + removeButtonRect.height / 2f); - - GUILayout.EndVertical(); - GUILayout.Label("", GUILayout.Width(removeButtonRect.width)); - - if (GUI.Button(removeButtonRect, "x", removeButtonStyle)) - OnRemoveComponentAt(index); - - if (!string.IsNullOrEmpty(description)) - { - Rect tooltipIconRect = TooltipIconRect; - tooltipIconRect.center = new Vector2(lastrect.xMax - removeButtonRect.width / 2f, lastrect.yMin + removeButtonRect.height / 2f); - GUIContent descriptionLabel = new GUIContent(EcsUnityConsts.INFO_MARK, description); - GUI.Label(tooltipIconRect, descriptionLabel, EditorStyles.boldLabel); - } - GUILayout.EndHorizontal(); - } - - private void DrawDamagedComponent(SerializedProperty componentRefProp, int index) - { - GUILayout.BeginHorizontal(); - - EditorGUILayout.HelpBox($"Damaged component. If the problem occurred after renaming a component or initializer. use MovedFromAttrubute", MessageType.Warning); - - Rect lastrect = GUILayoutUtility.GetLastRect(); - Rect removeButtonRect = RemoveButtonRect; - removeButtonRect.center = new Vector2(lastrect.xMax + removeButtonRect.width, lastrect.yMin + removeButtonRect.height / 2f); - - GUILayout.Label("", GUILayout.Width(removeButtonRect.width)); - if (GUI.Button(removeButtonRect, "x", removeButtonStyle)) - OnRemoveComponentAt(index); - - GUILayout.EndHorizontal(); - } - - public string GetLastPathComponent(string input) - { - int lastSlashIndex = input.LastIndexOfAny(new char[] { '/', '\\' }); - if (lastSlashIndex == -1) - return input; - else - return input.Substring(lastSlashIndex + 1); - } - } - - [CustomEditor(typeof(EntityTemplatePreset), true)] - public class EntityTemplatePresetEditor : EntityTemplateEditorBase - { - public override void OnInspectorGUI() - { - Draw((ITemplateInternal)target); - } - } - [CustomEditor(typeof(EntityTemplate), true)] - public class EntityTemplateEditor : EntityTemplateEditorBase - { - public override void OnInspectorGUI() - { - Draw((ITemplateInternal)target); - } - } - } -#endif -} diff --git a/src/EntityTemplate/EntityTemplatePreset.cs b/src/EntityTemplate/EntityTemplatePreset.cs deleted file mode 100644 index 2de34e3..0000000 --- a/src/EntityTemplate/EntityTemplatePreset.cs +++ /dev/null @@ -1,29 +0,0 @@ -using UnityEngine; - -namespace DCFApixels.DragonECS -{ - [CreateAssetMenu(fileName = "EntityTemplatePreset", menuName = EcsConsts.FRAMEWORK_NAME + "/EntityTemplatePreset", order = 1)] - public class EntityTemplatePreset : ScriptableObject, ITemplateInternal - { - [SerializeReference] - private ITemplateComponent[] _components; - string ITemplateInternal.ComponentsPropertyName => nameof(_components); - - //ITemplateBrowsable[] ITemplateInternal.Components - //{ - // get => _components; - // set => _components = value; - //} - - public void Apply(EcsWorld world, int entityID) - { - foreach (var item in _components) - item.Add(world, entityID); - } - - public void Clear() - { - _components = new ITemplateComponent[0]; - } - } -} diff --git a/src/EntityTemplate/EntityTemplatePreset.cs.meta b/src/EntityTemplate/EntityTemplatePreset.cs.meta deleted file mode 100644 index 10e7c2d..0000000 --- a/src/EntityTemplate/EntityTemplatePreset.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 54d84d8749e68c044b4f13a512808a67 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/src/EntityTemplate/ITemplate.cs b/src/EntityTemplate/ITemplate.cs deleted file mode 100644 index c331ec0..0000000 --- a/src/EntityTemplate/ITemplate.cs +++ /dev/null @@ -1,25 +0,0 @@ -using UnityEngine; - -namespace DCFApixels.DragonECS -{ - public interface ITemplate - { - public void Apply(EcsWorld world, int entityID); - } - - public interface ITemplateInternal : ITemplate - { - // internal ITemplateBrowsable[] Components { get; set; } - internal string ComponentsPropertyName { get; } - } - - public static class ITemplateExt - { - public static int NewEntity(this ITemplate self, EcsWorld world) - { - int e = world.NewEmptyEntity(); - self.Apply(world, e); - return e; - } - } -} diff --git a/src/EntityTemplate/ITemplateNode.cs b/src/EntityTemplate/ITemplateNode.cs new file mode 100644 index 0000000..b2c9967 --- /dev/null +++ b/src/EntityTemplate/ITemplateNode.cs @@ -0,0 +1,57 @@ +namespace DCFApixels.DragonECS +{ + public interface ITemplateNode + { + void Apply(int worldID, int entityID); + } + public interface ITemplate : ITemplateNode + { + //void Add(ITemplateNode template); + //void Remove(ITemplateNode template); + } + + public interface ITemplateInternal : ITemplate + { + string ComponentsPropertyName { get; } + //EntityTemplateInheritanceMatrix InheritanceMatrix { get; } + } + + public static class ITemplateExtensions + { + public static int NewEntity(this EcsWorld world, ITemplateNode template) + { + int e = world.NewEntity(); + template.Apply(world.id, e); + return e; + } + public static entlong NewEntityLong(this EcsWorld world, ITemplateNode template) + { + entlong e = world.NewEntityLong(); + template.Apply(world.id, e.ID); + return e; + } + public static entlong NewEntityWithGameObject(this EcsWorld world, ITemplateNode template, string name = "Entity", GameObjectIcon icon = GameObjectIcon.NONE) + { + entlong e = world.NewEntityWithGameObject(name, icon); + template.Apply(world.id, e.ID); + return e; + } + } + + //[Serializable] + //public class EntityTemplateInheritanceMatrix + //{ + // [SerializeReference] + // private ITemplateNode[] _components; + // + // #region Methods + // public void Apply(int worldID, int entityID) + // { + // foreach (var item in _components) + // { + // item.Apply(worldID, entityID); + // } + // } + // #endregion + //} +} diff --git a/src/EntityTemplate/ITemplate.cs.meta b/src/EntityTemplate/ITemplateNode.cs.meta similarity index 100% rename from src/EntityTemplate/ITemplate.cs.meta rename to src/EntityTemplate/ITemplateNode.cs.meta diff --git a/src/EntityTemplate/TemplateComponent.cs b/src/EntityTemplate/TemplateComponent.cs deleted file mode 100644 index a2486c7..0000000 --- a/src/EntityTemplate/TemplateComponent.cs +++ /dev/null @@ -1,146 +0,0 @@ -using DCFApixels.DragonECS.Editors; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using UnityEngine; - -namespace DCFApixels.DragonECS -{ - public interface ITemplateComponent - { - public void Add(EcsWorld w, int e); - } - public interface ITemplateComponentName : ITemplateComponent - { - public string Name { get; } - } - public interface ITemplateComponentGizmos - { - public void OnGizmos(Transform transform, Mode mode); - public enum Mode - { - Always, - Selected - } - } - - [Serializable] - public abstract class TemplateComponentInitializerBase - { - public virtual string Name => string.Empty; - public virtual Color Color => Color.black; - public virtual string Description => string.Empty; - public abstract Type Type { get; } - - internal abstract object ComponentRef { get; } - - #region Get meta - internal static Color GetColor(Type type) - { - var atr = type.GetCustomAttribute(); - if (atr == null) return Color.black; - return atr.GetUnityColor(); - } - internal static string GetName(Type type) - { - string friendlyName = type.Name; - if (type.IsGenericType) - { - int iBacktick = friendlyName.IndexOf('`'); - if (iBacktick > 0) - friendlyName = friendlyName.Remove(iBacktick); - - friendlyName += "/" + friendlyName; - friendlyName += "<"; - Type[] typeParameters = type.GetGenericArguments(); - for (int i = 0; i < typeParameters.Length; ++i) - { - string typeParamName = GetName(typeParameters[i]); - friendlyName += (i == 0 ? typeParamName : "," + typeParamName); - } - friendlyName += ">"; - } - return friendlyName; - } - - internal static string GetDescription(Type type) - { - var atr = type.GetCustomAttribute(); - if (atr == null) return string.Empty; - return atr.description; - } - #endregion - } - [Serializable] - public abstract class TemplateComponentInitializer : TemplateComponentInitializerBase, ITemplateComponentName, ITemplateComponentGizmos - { - private static string _autoname = GetName(typeof(T)); - private static Color _autoColor = GetColor(typeof(T)); - private static string _autoDescription = GetDescription(typeof(T)); - - [SerializeField] - protected T component; - - #region Properties - public override string Name => _autoname; - public override Color Color => _autoColor; - public override string Description => _autoDescription; - public sealed override Type Type => typeof(T); - - internal T Component => component; - internal override object ComponentRef => component; - #endregion - - public abstract void Add(EcsWorld w, int e); - public virtual void OnGizmos(Transform transform, ITemplateComponentGizmos.Mode mode) { } - } - - internal static class ITemplateBrowsableExt - { - private static MethodInfo memberwiseCloneMethdo = typeof(object).GetMethod("MemberwiseClone", BindingFlags.Instance | BindingFlags.NonPublic); - internal static ITemplateComponent Clone(this ITemplateComponent obj) - { - return (ITemplateComponent)memberwiseCloneMethdo.Invoke(obj, null); - } - } - -#if UNITY_EDITOR - namespace Editors - { - internal static class TemplateBrowsableTypeCache - { - private static Type[] _types; - private static ITemplateComponent[] _dummies; - internal static ReadOnlySpan Types => _types; - internal static ReadOnlySpan Dummies => _dummies; - - static TemplateBrowsableTypeCache() - { - List types = new List(); - Type interfaceType = typeof(ITemplateComponent); - foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) - { - var targetTypes = assembly.GetTypes().Where(type => !type.IsGenericType && (type.IsValueType|| type.IsClass) && type.GetCustomAttribute() != null); - - types.AddRange(targetTypes.Where(type => interfaceType.IsAssignableFrom(type))); - - foreach (var t in targetTypes) - { - if (t.IsSubclassOf(typeof(TemplateComponentInitializer<>))) - { - if(t.GetCustomAttribute() != null) - types.Add(t); - } - } - } - _types = types.ToArray(); - _dummies = new ITemplateComponent[_types.Length]; - - for (int i = 0; i < _types.Length; i++) - _dummies[i] = (ITemplateComponent)Activator.CreateInstance(_types[i]); - } - } - } -#endif -} diff --git a/src/EntityTemplate/TemplateComponent.cs.meta b/src/EntityTemplate/TemplateComponent.cs.meta deleted file mode 100644 index 77e0d5d..0000000 --- a/src/EntityTemplate/TemplateComponent.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 0ce52308e352f734e8a21c5ae282c246 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/src/EntityTemplate/Templates.meta b/src/EntityTemplate/Templates.meta new file mode 100644 index 0000000..7e9abc7 --- /dev/null +++ b/src/EntityTemplate/Templates.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 14555d6350df03d448d362de7b6a31c1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/EntityTemplate/Templates/ComponentTemplateBase.cs b/src/EntityTemplate/Templates/ComponentTemplateBase.cs new file mode 100644 index 0000000..288b663 --- /dev/null +++ b/src/EntityTemplate/Templates/ComponentTemplateBase.cs @@ -0,0 +1,159 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using UnityEngine; +using static DCFApixels.DragonECS.IComponentTemplate; + +namespace DCFApixels.DragonECS +{ + public interface IComponentTemplate : ITemplateNode + { + #region Properties + Type Type { get; } + #endregion + + #region Methods + object GetRaw(); + void SetRaw(object raw); + void OnGizmos(Transform transform, GizmosMode mode); + void OnValidate(UnityEngine.Object obj); + #endregion + + public enum GizmosMode + { + Always, + Selected + } + } + public interface IComponentTemplateWithMetaOverride : IComponentTemplate, ITypeMeta { } + + [Serializable] + public abstract class ComponentTemplateBase : IComponentTemplateWithMetaOverride + { + #region Properties + public abstract Type Type { get; } + public virtual string Name { get { return string.Empty; } } + public virtual MetaColor Color { get { return new MetaColor(MetaColor.Black); } } + public virtual MetaGroup Group { get { return MetaGroup.Empty; } } + public virtual string Description { get { return string.Empty; } } + public virtual IReadOnlyCollection Tags { get { return Array.Empty(); } } + #endregion + + #region Methods + public abstract object GetRaw(); + public abstract void SetRaw(object raw); + public virtual void OnGizmos(Transform transform, GizmosMode mode) { } + public virtual void OnValidate(UnityEngine.Object obj) { } + + public abstract void Apply(int worldID, int entityID); + #endregion + } + [Serializable] + public abstract class ComponentTemplateBase : ComponentTemplateBase + { + protected static TypeMeta Meta = EcsDebugUtility.GetTypeMeta(); + [SerializeField] + protected T component; + + #region Properties + public override Type Type { get { return typeof(T); } } + public override string Name { get { return Meta.Name; } } + public override MetaGroup Group { get { return Meta.Group; } } + public override string Description { get { return Meta.Description; } } + public override IReadOnlyCollection Tags { get { return Meta.Tags; } } + public override MetaColor Color { get { return Meta.Color; } } + #endregion + + #region Methods + public override object GetRaw() + { + return component; + } + public override void SetRaw(object raw) + { + component = (T)raw; + } + #endregion + } + + public abstract class ComponentTemplate : ComponentTemplateBase + where T : struct, IEcsComponent + { + public override void Apply(int worldID, int entityID) + { + EcsWorld.GetPoolInstance>(worldID).TryAddOrGet(entityID) = component; + } + } + public abstract class TagComponentTemplate : ComponentTemplateBase + where T : struct, IEcsTagComponent + { + public override void Apply(int worldID, int entityID) + { + EcsWorld.GetPoolInstance>(worldID).Set(entityID, true); + } + } +} + +namespace DCFApixels.DragonECS.Unity.Internal +{ + internal static class ComponentTemplateExtensions + { + private static MethodInfo memberwiseCloneMethdo = typeof(object).GetMethod("MemberwiseClone", BindingFlags.Instance | BindingFlags.NonPublic); + internal static IComponentTemplate Clone(this IComponentTemplate obj) + { + return (IComponentTemplate)memberwiseCloneMethdo.Invoke(obj, null); + } + } +} + +#if UNITY_EDITOR +namespace DCFApixels.DragonECS.Unity.Editors +{ + internal static class ComponentTemplateTypeCache + { + private static Type[] _types; + private static IComponentTemplate[] _dummies; + internal static ReadOnlySpan Types + { + get { return _types; } + } + internal static ReadOnlySpan Dummies + { + get { return _dummies; } + } + + static ComponentTemplateTypeCache() + { + List types = new List(); + Type interfaceType = typeof(IComponentTemplate); + foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) + { + var targetTypes = assembly.GetTypes().Where(type => !type.IsGenericType && !(type.IsAbstract || type.IsInterface) && type.GetCustomAttribute() != null); + + types.AddRange(targetTypes.Where(type => interfaceType.IsAssignableFrom(type))); + + foreach (var t in targetTypes) + { + if (t.IsSubclassOf(typeof(ComponentTemplateBase<>))) + { + types.Add(t); + } + } + } + _types = types.ToArray(); + foreach (var type in _types) + { + EcsDebugUtility.GetTypeMeta(type); + } + _dummies = new IComponentTemplate[_types.Length]; + + for (int i = 0; i < _types.Length; i++) + { + _dummies[i] = (IComponentTemplate)Activator.CreateInstance(_types[i]); + } + } + } +} +#endif + diff --git a/src/EntityTemplate/Templates/ComponentTemplateBase.cs.meta b/src/EntityTemplate/Templates/ComponentTemplateBase.cs.meta new file mode 100644 index 0000000..8ee6928 --- /dev/null +++ b/src/EntityTemplate/Templates/ComponentTemplateBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b532f9d8441035d49b9acb99ea23c231 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/EntityTemplate/Templates/MonoEntityTemplate.cs b/src/EntityTemplate/Templates/MonoEntityTemplate.cs new file mode 100644 index 0000000..5bb3d5f --- /dev/null +++ b/src/EntityTemplate/Templates/MonoEntityTemplate.cs @@ -0,0 +1,66 @@ +using System; +using UnityEngine; + +namespace DCFApixels.DragonECS +{ + [DisallowMultipleComponent] + public class MonoEntityTemplate : MonoBehaviour, ITemplateInternal + { + [SerializeReference] + private IComponentTemplate[] _components; + //[SerializeField] + //private EntityTemplateInheritanceMatrix _inheritanceMatrix; + + #region Properties + string ITemplateInternal.ComponentsPropertyName + { + get { return nameof(_components); } + } + //EntityTemplateInheritanceMatrix ITemplateInternal.InheritanceMatrix + //{ + // get { return _inheritanceMatrix; } + //} + #endregion + + #region Methods + public void Apply(int worldID, int entityID) + { + foreach (var item in _components) + { + item.Apply(worldID, entityID); + } + } + public void Clear() + { + _components = Array.Empty(); + } + #endregion + + #region UnityEvents + private void OnValidate() + { + if (_components == null) { return; } + foreach (var item in _components) + { + item.OnValidate(gameObject); + } + } + private void OnDrawGizmos() + { + if (_components == null) { return; } + foreach (var item in _components) + { + item.OnGizmos(transform, IComponentTemplate.GizmosMode.Always); + } + } + private void OnDrawGizmosSelected() + { + if (_components == null) { return; } + foreach (var item in _components) + { + item.OnGizmos(transform, IComponentTemplate.GizmosMode.Selected); + } + } + #endregion + } +} diff --git a/src/EntityTemplate/Templates/MonoEntityTemplate.cs.meta b/src/EntityTemplate/Templates/MonoEntityTemplate.cs.meta new file mode 100644 index 0000000..38b24c0 --- /dev/null +++ b/src/EntityTemplate/Templates/MonoEntityTemplate.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 351338ca92ace49499f450172d857af6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/EntityTemplate/Templates/ScriptableEntityTemplate.cs b/src/EntityTemplate/Templates/ScriptableEntityTemplate.cs new file mode 100644 index 0000000..95dde5a --- /dev/null +++ b/src/EntityTemplate/Templates/ScriptableEntityTemplate.cs @@ -0,0 +1,50 @@ +using System; +using UnityEngine; + +namespace DCFApixels.DragonECS +{ + [CreateAssetMenu(fileName = nameof(ScriptableEntityTemplate), menuName = EcsConsts.FRAMEWORK_NAME + "/" + nameof(ScriptableEntityTemplate), order = 1)] + public class ScriptableEntityTemplate : ScriptableObject, ITemplateInternal + { + [SerializeReference] + private IComponentTemplate[] _components; + //[SerializeField] + //private EntityTemplateInheritanceMatrix _inheritanceMatrix; + + #region Properties + string ITemplateInternal.ComponentsPropertyName + { + get { return nameof(_components); } + } + //EntityTemplateInheritanceMatrix ITemplateInternal.InheritanceMatrix + //{ + // get { return _inheritanceMatrix; } + //} + #endregion + + #region Methods + public void Apply(int worldID, int entityID) + { + foreach (var item in _components) + { + item.Apply(worldID, entityID); + } + } + public void Clear() + { + _components = Array.Empty(); + } + #endregion + + #region UnityEvents + private void OnValidate() + { + if (_components == null) { return; } + foreach (var item in _components) + { + item.OnValidate(this); + } + } + #endregion + } +} diff --git a/src/EntityTemplate/Templates/ScriptableEntityTemplate.cs.meta b/src/EntityTemplate/Templates/ScriptableEntityTemplate.cs.meta new file mode 100644 index 0000000..7d1bf18 --- /dev/null +++ b/src/EntityTemplate/Templates/ScriptableEntityTemplate.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3d2b62f9703592042befb46ac1fee09c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Extensions/EcsEntityConnect.cs b/src/Extensions/EcsEntityConnect.cs deleted file mode 100644 index ddd2041..0000000 --- a/src/Extensions/EcsEntityConnect.cs +++ /dev/null @@ -1,143 +0,0 @@ -using System.Runtime.CompilerServices; -using UnityEngine; - -namespace DCFApixels.DragonECS -{ - public class EcsEntityConnect : MonoBehaviour - { - private sealed class Subject : EcsSubject - { - public readonly EcsPool unityGameObjects; - public Subject(Builder b) - { - unityGameObjects = b.Include(); - } - } - - private entlong _entity; - private EcsWorld _world; - - [SerializeField] - private EntityTemplatePreset[] _entityTemplatePresets; - [SerializeField] - private EntityTemplate[] _entityTemplates; - - internal void SetTemplates_Editor(EntityTemplate[] tempaltes) - { - _entityTemplates = tempaltes; - } - - #region Properties - public entlong Entity - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => _entity; - } - public EcsWorld World - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => _world; - } - public bool IsAlive - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => _entity.IsAlive; - } - #endregion - - public void ConnectWith(entlong entity, bool applyTemplates = false) - { - if(_entity.TryGetID(out int oldE) && _world != null) - { - var s = _world.GetSubject(); - s.unityGameObjects.Del(oldE); - } - _world = null; - - if (entity.TryGetID(out int newE)) - { - _entity = entity; - _world = _entity.World; - var s = _world.GetSubject(); - if (!s.unityGameObjects.Has(newE)) s.unityGameObjects.Add(newE) = new UnityGameObject(gameObject); - - if (applyTemplates) - ApplyTemplates(); - } - else - { - _entity = entlong.NULL; - } - } - public void ApplyTemplates() => ApplyTemplatesFor(_entity.ID); - public void ApplyTemplatesFor(int entityID) - { - foreach (var t in _entityTemplatePresets) - t.Apply(_world, entityID); - foreach (var t in _entityTemplates) - t.Apply(_world, entityID); - } - } - -#if UNITY_EDITOR - - namespace Editors - { - using UnityEditor; - [CustomEditor(typeof(EcsEntityConnect))] - public class EcsEntityEditor : Editor - { - private EcsEntityConnect Target => (EcsEntityConnect)target; - private GUIStyle _greenStyle; - private GUIStyle _redStyle; - - - private bool _isInit = false; - - private void Init() - { - if (_isInit) - return; - - _greenStyle = EcsEditor.GetStyle(new Color32(75, 255, 0, 100)); - _redStyle = EcsEditor.GetStyle(new Color32(255, 0, 75, 100)); - - - _isInit = true; - } - - public override void OnInspectorGUI() - { - Init(); - if (Target.IsAlive) - GUILayout.Box("Connected", _greenStyle, GUILayout.ExpandWidth(true)); - else - GUILayout.Box("Not connected", _redStyle, GUILayout.ExpandWidth(true)); - - if(Target.Entity.TryGetID(out int id)) - EditorGUILayout.IntField(id); - else - EditorGUILayout.IntField(0); - GUILayout.Label(Target.Entity.ToString()); - - base.OnInspectorGUI(); - - if(GUILayout.Button("Autoset Templates")) - { - Target.SetTemplates_Editor(Target.GetComponents()); - - EditorUtility.SetDirty(target); - } - if (GUILayout.Button("Autoset Templates Cascade")) - { - foreach (var item in Target.GetComponentsInChildren()) - { - item.SetTemplates_Editor(item.GetComponents()); - EditorUtility.SetDirty(item); - } - } - } - } - } -#endif -} diff --git a/src/Extensions/Runners.cs b/src/Extensions/Runners.cs deleted file mode 100644 index 94a5731..0000000 --- a/src/Extensions/Runners.cs +++ /dev/null @@ -1,91 +0,0 @@ -using DCFApixels.DragonECS.RunnersCore; - -namespace DCFApixels.DragonECS -{ - public interface IEcsLateRunProcess : IEcsSystem - { - public void LateRun(EcsPipeline pipeline); - } - public static class IEcsLateRunSystemExtensions - { - public static void LateRun(this EcsPipeline systems) - { - systems.GetRunner().LateRun(systems); - } - } - public interface IEcsFixedRunProcess : IEcsSystem - { - public void FixedRun(EcsPipeline pipeline); - } - public static class IEcsFixedRunSystemExtensions - { - public static void FixedRun(this EcsPipeline pipeline) - { - pipeline.GetRunner().FixedRun(pipeline); - } - } - - namespace Internal - { - [DebugColor(DebugColor.Orange)] - public class EcsLateRunSystemRunner : EcsRunner, IEcsLateRunProcess - { -#if DEBUG && !DISABLE_DEBUG - private EcsProfilerMarker[] _markers; -#endif - public void LateRun(EcsPipeline pipeline) - { -#if DEBUG && !DISABLE_DEBUG - for (int i = 0; i < targets.Length; i++) - { - using (_markers[i].Auto()) - targets[i].LateRun(pipeline); - } -#else - foreach (var item in targets) item.LateRun(pipeline); -#endif - } - -#if DEBUG && !DISABLE_DEBUG - protected override void OnSetup() - { - _markers = new EcsProfilerMarker[targets.Length]; - for (int i = 0; i < targets.Length; i++) - { - _markers[i] = new EcsProfilerMarker(EcsDebug.RegisterMark($"EcsRunner.{targets[i].GetType().Name}.{nameof(LateRun)}")); - } - } -#endif - } - [DebugColor(DebugColor.Orange)] - public class EcsFixedRunSystemRunner : EcsRunner, IEcsFixedRunProcess - { -#if DEBUG && !DISABLE_DEBUG - private EcsProfilerMarker[] _markers; -#endif - public void FixedRun(EcsPipeline pipeline) - { -#if DEBUG && !DISABLE_DEBUG - for (int i = 0; i < targets.Length; i++) - { - using (_markers[i].Auto()) - targets[i].FixedRun(pipeline); - } -#else - foreach (var item in targets) item.FixedRun(pipeline); -#endif - } - -#if DEBUG && !DISABLE_DEBUG - protected override void OnSetup() - { - _markers = new EcsProfilerMarker[targets.Length]; - for (int i = 0; i < targets.Length; i++) - { - _markers[i] = new EcsProfilerMarker(EcsDebug.RegisterMark($"EcsRunner.{targets[i].GetType().Name}.{nameof(FixedRun)}")); - } - } -#endif - } - } -} diff --git a/src/Extensions/Runners.cs.meta b/src/Extensions/Runners.cs.meta deleted file mode 100644 index 2b4d105..0000000 --- a/src/Extensions/Runners.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 385a6c66660032944ad2cce7130715d7 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/src/Extensions/Systems.cs b/src/Extensions/Systems.cs deleted file mode 100644 index 4296026..0000000 --- a/src/Extensions/Systems.cs +++ /dev/null @@ -1,56 +0,0 @@ -namespace DCFApixels.DragonECS -{ - [DebugHide, DebugColor(DebugColor.Grey)] - public class DeleteOneFrameComponentFixedSystem : IEcsFixedRunProcess, IEcsInject - where TWorld : EcsWorld - where TComponent : struct, IEcsComponent - { - private TWorld _world; - public void Inject(TWorld obj) => _world = obj; - - private sealed class Subject : EcsSubject - { - public EcsPool pool; - public Subject(Builder b) - { - pool = b.Include(); - } - } - public void FixedRun(EcsPipeline pipeline) - { - foreach (var e in _world.Where(out Subject s)) - { - //try - //{ - s.pool.Del(e); - //} - //catch (System.Exception) - //{ - // - // throw; - //} - } - } - } - - public static class DeleteOneFrameComponentFixedSystemExt - { - private const string AUTO_DEL_FIXED_LAYER = nameof(AUTO_DEL_FIXED_LAYER); - public static EcsPipeline.Builder AutoDelFixed(this EcsPipeline.Builder b) - where TWorld : EcsWorld - where TComponent : struct, IEcsComponent - { - b.Layers.Insert(EcsConsts.POST_END_LAYER, AUTO_DEL_FIXED_LAYER); - b.AddUnique(new DeleteOneFrameComponentFixedSystem(), AUTO_DEL_FIXED_LAYER); - return b; - } - /// for EcsDefaultWorld - public static EcsPipeline.Builder AutoDelFixed(this EcsPipeline.Builder b) - where TComponent : struct, IEcsComponent - { - b.Layers.Insert(EcsConsts.POST_END_LAYER, AUTO_DEL_FIXED_LAYER); - b.AddUnique(new DeleteOneFrameComponentFixedSystem(), AUTO_DEL_FIXED_LAYER); - return b; - } - } -} diff --git a/src/Extensions/Systems.cs.meta b/src/Extensions/Systems.cs.meta deleted file mode 100644 index 21f2963..0000000 --- a/src/Extensions/Systems.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: e8c608fea9f3569409826ec54affa822 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/src/Extensions/UnityComponents.cs b/src/Extensions/UnityComponents.cs deleted file mode 100644 index 5f539ba..0000000 --- a/src/Extensions/UnityComponents.cs +++ /dev/null @@ -1,98 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using UnityEngine; -using UnityEngine.Scripting.APIUpdating; - -namespace DCFApixels.DragonECS -{ - [Serializable] - [DebugColor(255 / 3, 255, 0)] - public struct UnityComponent : IEcsComponent, IEnumerable//IntelliSense hack - where T : class - { - public T obj; - - IEnumerator IEnumerable.GetEnumerator() => throw new NotImplementedException(); //IntelliSense hack - IEnumerator IEnumerable.GetEnumerator() => throw new NotImplementedException(); //IntelliSense hack - } - - [Serializable] - [MovedFrom(false, "Client", null, "RefRigitBodyInitializer")] - public sealed class UnityComponentRigitBodyInitializer : TemplateComponentInitializer> - { - public override void Add(EcsWorld w, int e) => w.GetPool>().Add(e) = component; - } - - [Serializable] - [MovedFrom(false, "Client", null, "RefAnimatorInitializer")] - public sealed class UnityComponentAnimatorInitializer : TemplateComponentInitializer> - { - public override void Add(EcsWorld w, int e) => w.GetPool>().Add(e) = component; - } - [Serializable] - public sealed class UnityComponentCharacterControllerInitializer : TemplateComponentInitializer> - { - public override void Add(EcsWorld w, int e) => w.GetPool>().Add(e) = component; - } - - #region Colliders - [Serializable] - public sealed class UnityComponentColliderInitializer : TemplateComponentInitializer> - { - public override string Name => "UnityComponent/Collider/" + nameof(Collider); - public override void Add(EcsWorld w, int e) => w.GetPool>().Add(e) = component; - } - [Serializable] - public sealed class UnityComponentBoxColliderInitializer : TemplateComponentInitializer> - { - public override string Name => "UnityComponent/Collider/" + nameof(BoxCollider); - public override void Add(EcsWorld w, int e) => w.GetPool>().Add(e) = component; - } - [Serializable] - public sealed class UnityComponentSphereColliderInitializer : TemplateComponentInitializer> - { - public override string Name => "UnityComponent/Collider/" + nameof(SphereCollider); - public override void Add(EcsWorld w, int e) => w.GetPool>().Add(e) = component; - } - [Serializable] - public sealed class UnityComponentCapsuleColliderInitializer : TemplateComponentInitializer> - { - public override string Name => "UnityComponent/Collider/" + nameof(CapsuleCollider); - public override void Add(EcsWorld w, int e) => w.GetPool>().Add(e) = component; - } - [Serializable] - public sealed class UnityComponentMeshColliderInitializer : TemplateComponentInitializer> - { - public override string Name => "UnityComponent/Collider/" + nameof(MeshCollider); - public override void Add(EcsWorld w, int e) => w.GetPool>().Add(e) = component; - } - #endregion - - #region Joints - [Serializable] - public sealed class UnityComponentJointInitializer : TemplateComponentInitializer> - { - public override string Name => "UnityComponent/Joint/" + nameof(Joint); - public override void Add(EcsWorld w, int e) => w.GetPool>().Add(e) = component; - } - [Serializable] - public sealed class UnityComponentFixedJointInitializer : TemplateComponentInitializer> - { - public override string Name => "UnityComponent/Joint/" + nameof(FixedJoint); - public override void Add(EcsWorld w, int e) => w.GetPool>().Add(e) = component; - } - [Serializable] - public sealed class UnityComponentCharacterJointInitializer : TemplateComponentInitializer> - { - public override string Name => "UnityComponent/Joint/" + nameof(CharacterJoint); - public override void Add(EcsWorld w, int e) => w.GetPool>().Add(e) = component; - } - [Serializable] - public sealed class UnityComponentConfigurableJointInitializer : TemplateComponentInitializer> - { - public override string Name => "UnityComponent/Joint/" + nameof(ConfigurableJoint); - public override void Add(EcsWorld w, int e) => w.GetPool>().Add(e) = component; - } - #endregion -} diff --git a/src/Extensions/UnityGameObject.cs.meta b/src/Extensions/UnityGameObject.cs.meta deleted file mode 100644 index 1b88100..0000000 --- a/src/Extensions/UnityGameObject.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 909b2b01fa1e58b4e9e739827e36cff4 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/src/Fetures/UnityWorldProvider.cs b/src/Fetures/UnityWorldProvider.cs deleted file mode 100644 index db141ad..0000000 --- a/src/Fetures/UnityWorldProvider.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; - -namespace DCFApixels.DragonECS -{ - public static class UnityWorldProvider - where TWorld : EcsWorld - { - private static TWorld _world; - - public static TWorld Get(Func builder) - { - if (builder == null) - throw new ArgumentNullException(); - - if (_world == null) - _world = builder(); - - return _world; - } - - public static TWorld Get() - { - if (_world == null) - _world = (TWorld)Activator.CreateInstance(typeof(TWorld)); - return _world; - } - } - -} diff --git a/src/Fetures/UnityWorldProvider.cs.meta b/src/Fetures/UnityWorldProvider.cs.meta deleted file mode 100644 index 107dcbc..0000000 --- a/src/Fetures/UnityWorldProvider.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: d0af8ddc3edb89242a26c1d308a18c87 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/src/Internal.meta b/src/Internal.meta new file mode 100644 index 0000000..8241104 --- /dev/null +++ b/src/Internal.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fc246fdeda320b649899ee44aca24e18 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Utils/BitMask.cs b/src/Internal/BitMask.cs similarity index 77% rename from src/Utils/BitMask.cs rename to src/Internal/BitMask.cs index 7096bfe..f31f7bb 100644 --- a/src/Utils/BitMask.cs +++ b/src/Internal/BitMask.cs @@ -1,7 +1,7 @@ using System; using System.Runtime.CompilerServices; -namespace DCFApixels.DragonECS.Editors +namespace DCFApixels.DragonECS.Unity.Internal { internal class BitMask { @@ -21,21 +21,30 @@ namespace DCFApixels.DragonECS.Editors public bool this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => (_data[index >> OFFSET] & (1 << (index & MOD_MASK))) != 0; + get + { + return (_data[index >> OFFSET] & (1 << (index & MOD_MASK))) != 0; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { - if(value) + if (value) + { _data[index >> OFFSET] |= (1 << (index & MOD_MASK)); + } else + { _data[index >> OFFSET] &= ~(1 << (index & MOD_MASK)); + } } } public void Resize(int newSize) { if (newSize <= _size) + { return; + } _size = newSize / DATA_BITS + 1; Array.Resize(ref _data, _size); diff --git a/src/Utils/BitMask.cs.meta b/src/Internal/BitMask.cs.meta similarity index 100% rename from src/Utils/BitMask.cs.meta rename to src/Internal/BitMask.cs.meta diff --git a/src/Internal/Editor.meta b/src/Internal/Editor.meta new file mode 100644 index 0000000..732f508 --- /dev/null +++ b/src/Internal/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 93ac43c51e44bbb459de81017f530fbe +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Internal/Editor/EcsGUI.cs b/src/Internal/Editor/EcsGUI.cs new file mode 100644 index 0000000..5d13281 --- /dev/null +++ b/src/Internal/Editor/EcsGUI.cs @@ -0,0 +1,502 @@ +#if UNITY_EDITOR +using DCFApixels.DragonECS.Unity.Internal; +using System; +using System.Reflection; +using UnityEditor; +using UnityEngine; + +namespace DCFApixels.DragonECS.Unity.Editors +{ + internal static class EcsGUI + { + public struct ColorScope : IDisposable + { + private readonly Color _oldColor; + public ColorScope(Color color) + { + _oldColor = GUI.color; + GUI.color = color; + } + public void Dispose() + { + GUI.color = _oldColor; + } + } + + 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); + + private static readonly Rect RemoveButtonRect = new Rect(0f, 0f, 19f, 19f); + private static readonly Rect TooltipIconRect = new Rect(0f, 0f, 19f, 19f); + + public static float EntityBarHeight => EditorGUIUtility.singleLineHeight + 3f; + + private static bool IsShowHidden + { + get { return SettingsPrefs.instance.IsShowHidden; } + set { SettingsPrefs.instance.IsShowHidden = value; } + } + private static bool IsShowRuntimeComponents + { + get { return SettingsPrefs.instance.IsShowRuntimeComponents; } + set { SettingsPrefs.instance.IsShowRuntimeComponents = value; } + } + + public enum AddClearComponentButton : byte + { + None = 0, + AddComponent, + Clear, + } + [Flags] + public enum EntityStatus + { + NotAlive = 0, + Alive = 1 << 0, + Undefined = 1 << 1, + } + + //private static GUILayoutOption[] _defaultParams; + //private static bool _isInit = false; + //private static void Init() + //{ + // if (_isInit) + // { + // return; + // } + // _defaultParams = new GUILayoutOption[] { GUILayout.ExpandWidth(true) }; + // _isInit = true; + //} + + internal static bool HitTest(Rect rect) + { + return HitTest(rect, Event.current.mousePosition); + } + internal static bool HitTest(Rect rect, Event evt) + { + return HitTest(rect, evt.mousePosition); + } + internal static bool HitTest(Rect rect, Vector2 point) + { + int offset = 0; + return HitTest(rect, point, offset); + } + internal static bool HitTest(Rect rect, Vector2 point, int offset) + { + return point.x >= rect.xMin - (float)offset && point.x < rect.xMax + (float)offset && point.y >= rect.yMin - (float)offset && point.y < rect.yMax + (float)offset; + } + + //public static bool IconButton(Rect position, Texture normal, Texture hover, GUIStyle normalStyle = null, GUIStyle hoverStyle = null) + //{ + // Color dc = GUI.color; + // GUI.color = Color.clear; //Хак чтобы сделать реакцию от курсора мыши без лага + // bool result = GUI.Button(position, "", EditorStyles.miniButtonMid); + // GUI.color = dc; + // + // var current = Event.current; + // { + // if (HitTest(position, current)) + // { + // if (hoverStyle != null && Event.current.type == EventType.Repaint) + // { + // hoverStyle.Draw(position, true, false, false, false); + // } + // GUI.DrawTexture(position, hover); + // } + // else + // { + // if (normalStyle != null && Event.current.type == EventType.Repaint) + // { + // normalStyle.Draw(position, false, false, false, false); + // } + // GUI.DrawTexture(position, normal); + // } + // } + // + // return result; + //} + public static (bool, bool) IconButtonGeneric(Rect position) + { + Color dc = GUI.color; + GUI.color = Color.clear; //Хак чтобы сделать реакцию от курсора мыши без лага + bool result = GUI.Button(position, "", EditorStyles.miniButtonMid); + GUI.color = dc; + + var current = Event.current; + return (GUI.enabled && HitTest(position, current), result); + } + public static bool IconButton(Rect position, Texture icon, float iconPadding, string description) + { + //var (hover, click) = IconButton(position); + //Color color = GUI.color; + //float enableMultiplier = GUI.enabled ? 1f : 0.72f; + // + //if (hover) + //{ + // if (Event.current.type == EventType.Repaint) + // { + // GUI.color = Color.white * 2.2f * enableMultiplier; + // EditorStyles.helpBox.Draw(position, hover, false, false, false); + // } + // + // Rect rect = RectUtility.AddPadding(position, -1f); + // GUI.color = Color.white * enableMultiplier; + // GUI.DrawTexture(rect, icon); + //} + //else + //{ + // if (Event.current.type == EventType.Repaint) + // { + // GUI.color = Color.white * 1.7f * enableMultiplier; + // EditorStyles.helpBox.Draw(position, hover, false, false, false); + // } + // GUI.color = Color.white * enableMultiplier; + // GUI.DrawTexture(position, icon); + //} + //GUI.color = color; + //return click; + + bool result = GUI.Button(position, UnityEditorUtility.GetLabel(string.Empty)); + GUI.Label(RectUtility.AddPadding(position, iconPadding), UnityEditorUtility.GetLabel(icon, description)); + return result; + } + public static void DescriptionIcon(Rect position, string description) + { + using (new ColorScope(new Color(1f, 1f, 1f, 0.8f))) + { + GUIContent descriptionLabel = UnityEditorUtility.GetLabel(EditorGUIUtility.IconContent("d__Help").image, description); + GUI.Label(position, descriptionLabel, EditorStyles.boldLabel); + } + } + public static bool CloseButton(Rect position) + { + using (new ColorScope(new Color(1f, 1f, 1f, 0.8f))) + { + var (hover, click) = IconButtonGeneric(position); + if (hover) + { + Rect rect = RectUtility.AddPadding(position, -4f); + GUI.DrawTexture(rect, EditorGUIUtility.IconContent("P4_DeletedLocal@2x").image); + } + else + { + GUI.DrawTexture(position, EditorGUIUtility.IconContent("d_winbtn_win_close").image); + } + return click; + } + } + public static bool AutosetCascadeButton(Rect position) + { + return IconButton(position, EditorGUIUtility.IconContent("d_winbtn_win_restore@2x").image, 0f, "Autoset Cascade"); + } + public static bool AutosetButton(Rect position) + { + return IconButton(position, EditorGUIUtility.IconContent("d_winbtn_win_max@2x").image, 1f, "Autoset"); + } + public static bool UnlinkButton(Rect position) + { + bool result = GUI.Button(position, UnityEditorUtility.GetLabel(string.Empty)); + GUI.Label(RectUtility.Move(position, 0, -1f), UnityEditorUtility.GetLabel(EditorGUIUtility.IconContent("d_Unlinked").image, "Unlink Entity")); + return result; + } + public static bool DelEntityButton(Rect position) + { + return IconButton(position, EditorGUIUtility.IconContent("d_winbtn_win_close").image, 0f, "Delete Entity"); + } + public static void EntityBar(Rect position, EntityStatus status, int id, short gen, short world) + { + var (entityInfoRect, statusRect) = RectUtility.VerticalSliceBottom(position, 3f); + + Color w = Color.gray; + w.a = 0.6f; + Color b = Color.black; + b.a = 0.55f; + EditorGUI.DrawRect(entityInfoRect, w); + + var (idRect, genWorldRect) = RectUtility.HorizontalSliceLerp(entityInfoRect, 0.4f); + var (genRect, worldRect) = RectUtility.HorizontalSliceLerp(genWorldRect, 0.5f); + + idRect = RectUtility.AddPadding(idRect, 2, 1, 0, 0); + genRect = RectUtility.AddPadding(genRect, 1, 1, 0, 0); + worldRect = RectUtility.AddPadding(worldRect, 1, 2, 0, 0); + EditorGUI.DrawRect(idRect, b); + EditorGUI.DrawRect(genRect, b); + EditorGUI.DrawRect(worldRect, b); + + + GUIStyle style = new GUIStyle(EditorStyles.numberField); + style.alignment = TextAnchor.MiddleCenter; + style.font = EditorStyles.boldFont; + if (status == EntityStatus.Alive) + { + Color statusColor = EcsGUI.GreenColor; + statusColor.a = 0.6f; + EditorGUI.DrawRect(statusRect, statusColor); + + EditorGUI.IntField(idRect, id, style); + EditorGUI.IntField(genRect, gen, style); + EditorGUI.IntField(worldRect, world, style); + } + else + { + Color statusColor = status == EntityStatus.Undefined ? new Color32(200, 200, 200, 255) : EcsGUI.RedColor; + statusColor.a = 0.6f; + EditorGUI.DrawRect(statusRect, statusColor); + + using (new EditorGUI.DisabledScope(true)) + { + GUI.Label(idRect, "Entity ID", style); + GUI.Label(genRect, "Generation", style); + GUI.Label(worldRect, "World ID", style); + } + } + } + + public static bool AddComponentButtons(Rect position) + { + position = RectUtility.AddPadding(position, 20f, 20f, 12f, 2f); + return GUI.Button(position, "Add Component"); + } + public static AddClearComponentButton AddClearComponentButtons(Rect position) + { + //Rect rect = GUILayoutUtility.GetRect(EditorGUIUtility.currentViewWidth, 36f); + position = RectUtility.AddPadding(position, 20f, 20f, 12f, 2f); + var (left, right) = RectUtility.HorizontalSliceLerp(position, 0.75f); + + if (GUI.Button(left, "Add Component")) + { + return AddClearComponentButton.AddComponent; + } + if (GUI.Button(right, "Clear")) + { + return AddClearComponentButton.Clear; + } + return AddClearComponentButton.None; + } + + 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; + float height = EntityBarHeight; + EcsGUI.EntityBar(GUILayoutUtility.GetRect(width, height), status, id, gen, world); + } + public static bool AddComponentButtons() + { + return EcsGUI.AddComponentButtons(GUILayoutUtility.GetRect(EditorGUIUtility.currentViewWidth, 36f)); + } + public static AddClearComponentButton AddClearComponentButtons() + { + return EcsGUI.AddClearComponentButtons(GUILayoutUtility.GetRect(EditorGUIUtility.currentViewWidth, 36f)); + } + public static void DrawRuntimeComponents(entlong entity, bool isWithFoldout = true) + { + if (entity.TryUnpack(out int entityID, out EcsWorld world)) + { + DrawRuntimeComponents(entityID, world, isWithFoldout); + } + } + public static void DrawRuntimeComponents(int entityID, EcsWorld world, bool isWithFoldout = true) + { + var componentTypeIDs = world.GetComponentTypeIDsFor(entityID); + + GUILayout.BeginVertical(UnityEditorUtility.GetStyle(Color.black, 0.2f)); + + if (isWithFoldout) + { + IsShowRuntimeComponents = EditorGUILayout.BeginFoldoutHeaderGroup(IsShowRuntimeComponents, "RUNTIME COMPONENTS", EditorStyles.foldout); + EditorGUILayout.EndFoldoutHeaderGroup(); + } + if (isWithFoldout == false || IsShowRuntimeComponents) + { + if (EcsGUI.Layout.AddComponentButtons()) + { + GenericMenu genericMenu = RuntimeComponentsUtility.GetAddComponentGenericMenu(world); + RuntimeComponentsUtility.CurrentEntityID = entityID; + genericMenu.ShowAsContext(); + } + + GUILayout.Box("", UnityEditorUtility.GetStyle(GUI.color, 0.16f), GUILayout.ExpandWidth(true)); + IsShowHidden = EditorGUI.Toggle(GUILayoutUtility.GetLastRect(), "Show Hidden", IsShowHidden); + + foreach (var componentTypeID in componentTypeIDs) + { + var pool = world.GetPoolInstance(componentTypeID); + { + DrawRuntimeComponent(entityID, pool); + } + } + } + GUILayout.EndVertical(); + } + private static readonly BindingFlags fieldFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; + private static void DrawRuntimeComponent(int entityID, IEcsPool pool) + { + var meta = pool.ComponentType.ToMeta(); + if (meta.IsHidden == false || IsShowHidden) + { + object data = pool.GetRaw(entityID); + Color panelColor = meta.Color.ToUnityColor().Desaturate(EscEditorConsts.COMPONENT_DRAWER_DESATURATE); + + float padding = EditorGUIUtility.standardVerticalSpacing; + Rect removeButtonRect = GUILayoutUtility.GetLastRect(); + + GUILayout.BeginVertical(UnityEditorUtility.GetStyle(panelColor, EscEditorConsts.COMPONENT_DRAWER_ALPHA)); + EditorGUI.BeginChangeCheck(); + + bool isRemoveComponent = false; + removeButtonRect.yMin = removeButtonRect.yMax; + removeButtonRect.yMax += RemoveButtonRect.height; + removeButtonRect.xMin = removeButtonRect.xMax - RemoveButtonRect.width; + removeButtonRect.center += Vector2.up * padding * 2f; + if (EcsGUI.CloseButton(removeButtonRect)) + { + isRemoveComponent = true; + } + + Type componentType = pool.ComponentType; + ExpandMatrix expandMatrix = ExpandMatrix.Take(componentType); + bool changed = DrawRuntimeData(componentType, UnityEditorUtility.GetLabel(meta.Name), expandMatrix, data, out object resultData); + if (changed || isRemoveComponent) + { + if (isRemoveComponent) + { + pool.Del(entityID); + } + else + { + pool.SetRaw(entityID, resultData); + } + } + + if (string.IsNullOrEmpty(meta.Description) == false) + { + Rect tooltipIconRect = TooltipIconRect; + tooltipIconRect.center = removeButtonRect.center; + tooltipIconRect.center -= Vector2.right * tooltipIconRect.width; + EcsGUI.DescriptionIcon(tooltipIconRect, meta.Description); + } + + GUILayout.EndVertical(); + } + } + + private static bool DrawRuntimeData(Type fieldType, GUIContent label, ExpandMatrix expandMatrix, object data, out object outData) + { + outData = data; + Type type = data == null ? typeof(void) : data.GetType(); + + bool isUnityObject = typeof(UnityEngine.Object).IsAssignableFrom(fieldType); + + if (isUnityObject == false && data == null) + { + EditorGUILayout.TextField(label, "Null"); + return false; + } + ref bool isExpanded = ref expandMatrix.Down(); + bool changed = false; + outData = data; + + if (isUnityObject == false && (type.IsGenericType || !type.IsSerializable)) + { + isExpanded = EditorGUILayout.BeginFoldoutHeaderGroup(isExpanded, label, EditorStyles.foldout); + EditorGUILayout.EndFoldoutHeaderGroup(); + + if (isExpanded) + { + EditorGUI.indentLevel++; + foreach (var field in type.GetFields(fieldFlags)) + { + GUIContent subLabel = UnityEditorUtility.GetLabel(UnityEditorUtility.TransformFieldName(field.Name)); + if (DrawRuntimeData(field.FieldType, subLabel, expandMatrix, field.GetValue(data), out object fieldData)) + { + field.SetValue(data, fieldData); + outData = data; + changed = true; + } + } + EditorGUI.indentLevel--; + } + } + else + { + if (isUnityObject) + { + EditorGUI.BeginChangeCheck(); + var uobj = (UnityEngine.Object)data; + + bool isComponent = (typeof(UnityEngine.Component)).IsAssignableFrom(fieldType); + if (isComponent) + { + uobj = EditorGUILayout.ObjectField(label, uobj, typeof(UnityEngine.Object), true); + } + else + { + uobj = EditorGUILayout.ObjectField(label, uobj, fieldType, true); + } + if (isComponent && uobj is GameObject go) + { + uobj = go.GetComponent(fieldType); + } + if (EditorGUI.EndChangeCheck()) + { + outData = uobj; + changed = true; + } + } + else + { + EditorGUI.BeginChangeCheck(); + WrapperBase w = RefEditorWrapper.Take(data); + + w.IsExpanded = isExpanded; + EditorGUILayout.PropertyField(w.Property, label, true); + isExpanded = w.IsExpanded; + + if (EditorGUI.EndChangeCheck()) + { + w.SO.ApplyModifiedProperties(); + outData = w.Data; + changed = true; + } + w.Release(); + } + } + + expandMatrix.Up(); + return changed; + } + } + } +} +#endif diff --git a/src/Internal/Editor/EcsGUI.cs.meta b/src/Internal/Editor/EcsGUI.cs.meta new file mode 100644 index 0000000..40c8707 --- /dev/null +++ b/src/Internal/Editor/EcsGUI.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f27d7dd0452a826479d2b19d7885ce49 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Internal/Editor/ExpandMatrix.cs b/src/Internal/Editor/ExpandMatrix.cs new file mode 100644 index 0000000..8bf25c0 --- /dev/null +++ b/src/Internal/Editor/ExpandMatrix.cs @@ -0,0 +1,57 @@ +#if UNITY_EDITOR +using System; +using System.Collections.Generic; + +namespace DCFApixels.DragonECS.Unity.Editors +{ + internal class ExpandMatrix + { + private const bool TOP_DEFAULT = true; + private const bool DEFAULT = false; + private static Dictionary _instances = new Dictionary(); + public static ExpandMatrix Take(Type type) + { + if (_instances.TryGetValue(type, out ExpandMatrix result) == false) + { + result = new ExpandMatrix(); + _instances.Add(type, result); + } + return result; + } + private bool[] _flags = new bool[8]; + private int _count = 0; + private int _ptr = 0; + + public int Count + { + get { return _count; } + } + public ref bool CurrentIsExpanded + { + get { return ref _flags[_ptr]; } + } + public void Up() + { + if (_ptr < 0) + { + throw new Exception("нарушение баланса инкремент/декремент"); + } + _ptr--; + } + + public ref bool Down() + { + _ptr++; + if (_ptr >= _count) + { + if (_count >= _flags.Length) + { + Array.Resize(ref _flags, _flags.Length << 1); + } + _flags[_count++] = _ptr <= 1 ? TOP_DEFAULT : DEFAULT; + } + return ref _flags[_ptr]; + } + } +} +#endif \ No newline at end of file diff --git a/src/Internal/Editor/ExpandMatrix.cs.meta b/src/Internal/Editor/ExpandMatrix.cs.meta new file mode 100644 index 0000000..30baaf9 --- /dev/null +++ b/src/Internal/Editor/ExpandMatrix.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fef04508ed32be24386f6b2a43e01b2c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Internal/Editor/SOWrappers.meta b/src/Internal/Editor/SOWrappers.meta new file mode 100644 index 0000000..b4ebbe8 --- /dev/null +++ b/src/Internal/Editor/SOWrappers.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fc9ef2bbe6a95624e9c6d50e19f38a05 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Internal/Editor/SOWrappers/RefEditorWrapper.cs b/src/Internal/Editor/SOWrappers/RefEditorWrapper.cs new file mode 100644 index 0000000..6025990 --- /dev/null +++ b/src/Internal/Editor/SOWrappers/RefEditorWrapper.cs @@ -0,0 +1,36 @@ +#if UNITY_EDITOR +using System; +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace DCFApixels.DragonECS.Unity.Editors +{ + [Serializable] + internal class RefEditorWrapper : WrapperBase + { + [SerializeReference] + public object data; + + public override object Data + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return data; } + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RefEditorWrapper Take(object data) + { + var result = Take(); + result.data = data; + result.SO.Update(); + return result; + } + } + + [Serializable] + internal class EmptyDummy + { + public static readonly EmptyDummy Instance = new EmptyDummy(); + private EmptyDummy() { } + } +} +#endif diff --git a/src/Internal/Editor/SOWrappers/RefEditorWrapper.cs.meta b/src/Internal/Editor/SOWrappers/RefEditorWrapper.cs.meta new file mode 100644 index 0000000..2a823f7 --- /dev/null +++ b/src/Internal/Editor/SOWrappers/RefEditorWrapper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b0f14ae652b89744888db94704a170ef +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Internal/Editor/SOWrappers/WrapperBase.cs b/src/Internal/Editor/SOWrappers/WrapperBase.cs new file mode 100644 index 0000000..d068d01 --- /dev/null +++ b/src/Internal/Editor/SOWrappers/WrapperBase.cs @@ -0,0 +1,92 @@ +#if UNITY_EDITOR +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using UnityEditor; +using UnityEngine; + +namespace DCFApixels.DragonECS.Unity.Editors +{ + [Serializable] + internal abstract class WrapperBase : ScriptableObject + { + public abstract object Data { get; } + public abstract bool IsExpanded { get; set; } + public abstract SerializedObject SO { get; } + public abstract SerializedProperty Property { get; } + public abstract void Release(); + } + [Serializable] + internal abstract class WrapperBase : WrapperBase + where TSelf : WrapperBase + { + private SerializedObject _so; + private SerializedProperty _property; + + private bool _isDestroyed = false; + private bool _isReleased = false; + + private static Stack _wrappers = new Stack(); + + public override bool IsExpanded + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return Property.isExpanded; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set { Property.isExpanded = value; } + } + public override SerializedObject SO + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _so; } + } + public override SerializedProperty Property + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _property; } + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TSelf Take() + { + TSelf result; + if (_wrappers.Count <= 0) + { + result = CreateInstance(); + result._so = new SerializedObject(result); + result._property = result._so.FindProperty("data"); + } + else + { + result = _wrappers.Pop(); + if (result._isDestroyed) + { + result = Take(); + } + } + result._isReleased = false; + return result; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Release(TSelf wrapper) + { + if (wrapper._isReleased) + { + throw new Exception(); + } + wrapper._isReleased = true; + _wrappers.Push(wrapper); + } + + private void OnDestroy() + { + _isDestroyed = true; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override void Release() + { + Release((TSelf)this); + } + } +} +#endif diff --git a/src/Internal/Editor/SOWrappers/WrapperBase.cs.meta b/src/Internal/Editor/SOWrappers/WrapperBase.cs.meta new file mode 100644 index 0000000..4649771 --- /dev/null +++ b/src/Internal/Editor/SOWrappers/WrapperBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6c0cef58c08259f4bbb78af2fcec4c79 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Internal/Editor/UnityEditorUtility.cs b/src/Internal/Editor/UnityEditorUtility.cs new file mode 100644 index 0000000..eb0eeb5 --- /dev/null +++ b/src/Internal/Editor/UnityEditorUtility.cs @@ -0,0 +1,309 @@ +#if UNITY_EDITOR +using DCFApixels.DragonECS.Unity.Internal; +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; +using UnityEditor; +using UnityEngine; + +namespace DCFApixels.DragonECS.Unity.Editors +{ + [InitializeOnLoad] + internal static class UnityEditorUtility + { + static UnityEditorUtility() + { + colorBoxeStyles = new SparseArray(); + } + private static SparseArray colorBoxeStyles = new SparseArray(); + 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) + { + 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(' '); + nextWorld = true; + } + } + + if (nextWorld) + { + b.Append(char.ToUpper(c)); + } + else + { + b.Append(c); + } + nextWorld = false; + prewIsUpper = isUpper; + } + + return b.ToString(); + } + #endregion + + #region Label + public static GUIContent GetLabelTemp() + { + if (_singletonContent == null) + { + _singletonContent = new GUIContent(); + } + return _singletonContent; + } + public static GUIContent GetLabel(string name, string tooltip = null) + { + if (_singletonContent == null) + { + _singletonContent = new GUIContent(); + } + _singletonContent.text = name; + _singletonContent.image = null; + _singletonContent.tooltip = tooltip; + return _singletonContent; + } + public static GUIContent GetLabel(Texture image, string tooltip = null) + { + if (_singletonContent == null) + { + _singletonContent = new GUIContent(); + } + _singletonContent.text = string.Empty; + _singletonContent.image = image; + _singletonContent.tooltip = tooltip; + return _singletonContent; + } + #endregion + + #region GetStyle + public static GUIStyle GetStyle(Color color, float alphaMultiplier) + { + color.a *= alphaMultiplier; + return GetStyle(color); + } + public static GUIStyle GetStyle(Color32 color32) + { + int colorCode = new Color32Union(color32).colorCode; + if (colorBoxeStyles.TryGetValue(colorCode, out GUIStyle style)) + { + if (style == null || style.normal.background == null) + { + style = CreateStyle(color32, colorCode); + colorBoxeStyles[colorCode] = style; + } + return style; + } + + style = CreateStyle(color32, colorCode); + colorBoxeStyles.Add(colorCode, style); + return style; + } + private static GUIStyle CreateStyle(Color32 color32, int colorCode) + { + GUIStyle result = new GUIStyle(GUI.skin.box); + Color componentColor = color32; + Texture2D texture2D = CreateTexture(2, 2, componentColor); + result.hover.background = texture2D; + result.focused.background = texture2D; + result.active.background = texture2D; + result.normal.background = texture2D; + return result; + } + private static Texture2D CreateTexture(int width, int height, Color color) + { + var pixels = new Color[width * height]; + for (var i = 0; i < pixels.Length; ++i) + pixels[i] = color; + + var result = new Texture2D(width, height); + result.SetPixels(pixels); + result.Apply(); + return result; + } + #endregion + + #region Utils + [StructLayout(LayoutKind.Explicit, Pack = 1, Size = 4)] + private readonly ref struct Color32Union + { + [FieldOffset(0)] + public readonly int colorCode; + [FieldOffset(0)] + public readonly byte r; + [FieldOffset(1)] + public readonly byte g; + [FieldOffset(2)] + public readonly byte b; + [FieldOffset(3)] + public readonly byte a; + public Color32Union(byte r, byte g, byte b, byte a) : this() + { + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } + public Color32Union(Color32 color) : this() + { + r = color.r; + g = color.g; + b = color.b; + a = color.a; + } + } + #endregion + } + + internal static class RuntimeComponentsUtility + { + public struct WorldData + { + public GenericMenu addComponentGenericMenu; + public int poolsCount; + public WorldData(GenericMenu addComponentGenericMenu, int poolsCount) + { + this.addComponentGenericMenu = addComponentGenericMenu; + this.poolsCount = poolsCount; + } + } + //world id + private static Dictionary _worldDatas = new Dictionary(); + + public static GenericMenu GetAddComponentGenericMenu(EcsWorld world) + { + if (_worldDatas.TryGetValue(world, out WorldData data)) + { + if (data.poolsCount != world.PoolsCount) + { + data = CreateWorldData(world); + _worldDatas[world] = data; + } + } + else + { + data = CreateWorldData(world); + _worldDatas[world] = data; + world.AddListener(new Listener(world)); + } + + return data.addComponentGenericMenu; + } + + private static WorldData CreateWorldData(EcsWorld world) + { + GenericMenu genericMenu = new GenericMenu(); + + var pools = world.AllPools; + for (int i = 0; i < world.PoolsCount; i++) + { + var pool = pools[i]; + if (pool.IsNullOrDummy()) + { + i--; + continue; + } + var meta = pool.ComponentType.ToMeta(); + + genericMenu.AddItem(new GUIContent(meta.Name, meta.Description), false, OnAddComponent, pool); + } + return new WorldData(genericMenu, world.PoolsCount); + } + + public static int CurrentEntityID = 0; + + private static void OnAddComponent(object userData) + { + IEcsPool pool = (IEcsPool)userData; + if (pool.World.IsUsed(CurrentEntityID) == false) + { + return; + } + if (pool.Has(CurrentEntityID) == false) + { + pool.AddRaw(CurrentEntityID, Activator.CreateInstance(pool.ComponentType)); + } + else + { + Debug.LogWarning($"Entity({CurrentEntityID}) already has component {EcsDebugUtility.GetGenericTypeName(pool.ComponentType)}."); + } + } + + private class Listener : IEcsWorldEventListener + { + private EcsWorld _world; + public Listener(EcsWorld world) + { + _world = world; + } + public void OnReleaseDelEntityBuffer(ReadOnlySpan buffer) { } + public void OnWorldDestroy() + { + _worldDatas.Remove(_world); + } + public void OnWorldResize(int newSize) { } + } + } +} +#endif \ No newline at end of file diff --git a/src/Internal/Editor/UnityEditorUtility.cs.meta b/src/Internal/Editor/UnityEditorUtility.cs.meta new file mode 100644 index 0000000..520c132 --- /dev/null +++ b/src/Internal/Editor/UnityEditorUtility.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6f06edb81ead46c49895b58f42772b32 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Internal/EscEditorConsts.cs b/src/Internal/EscEditorConsts.cs new file mode 100644 index 0000000..9307e9a --- /dev/null +++ b/src/Internal/EscEditorConsts.cs @@ -0,0 +1,8 @@ +namespace DCFApixels.DragonECS.Unity.Editors +{ + internal static class EscEditorConsts + { + public const float COMPONENT_DRAWER_ALPHA = 0.26f; + public const float COMPONENT_DRAWER_DESATURATE = 0.86f; + } +} diff --git a/src/Internal/EscEditorConsts.cs.meta b/src/Internal/EscEditorConsts.cs.meta new file mode 100644 index 0000000..e704e9c --- /dev/null +++ b/src/Internal/EscEditorConsts.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b0bed74c1b3b07d44b9ea1ea917809e4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Internal/ReflectionExtensions.cs b/src/Internal/ReflectionExtensions.cs new file mode 100644 index 0000000..dfd0800 --- /dev/null +++ b/src/Internal/ReflectionExtensions.cs @@ -0,0 +1,20 @@ +#if UNITY_EDITOR +using System; +using System.Reflection; + +namespace DCFApixels.DragonECS.Unity.Internal +{ + internal static class ReflectionExtensions + { + public static bool TryGetAttribute(this MemberInfo self, out T attrbiute) where T : Attribute + { + attrbiute = self.GetCustomAttribute(); + return attrbiute != null; + } + public static bool HasAttribute(this MemberInfo self) where T : Attribute + { + return self.GetCustomAttribute() != null; + } + } +} +#endif diff --git a/src/Internal/ReflectionExtensions.cs.meta b/src/Internal/ReflectionExtensions.cs.meta new file mode 100644 index 0000000..00f17aa --- /dev/null +++ b/src/Internal/ReflectionExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5d6a12b84f1e0254b8c57e1a2f2bf8a1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Utils/SparseArray.cs b/src/Internal/SparseArray.cs similarity index 96% rename from src/Utils/SparseArray.cs rename to src/Internal/SparseArray.cs index 5699919..102d9ff 100644 --- a/src/Utils/SparseArray.cs +++ b/src/Internal/SparseArray.cs @@ -1,12 +1,9 @@ -//SparseArray. Analogous to Dictionary, but faster. -//Benchmark result of indexer.get speed test with 300 elements: -//[Dictinary: 5.786us] [SparseArray: 2.047us]. -using System; +using System; using System.Diagnostics.Contracts; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -namespace DCFApixels.DragonECS.Editors +namespace DCFApixels.DragonECS.Unity.Internal { internal class SparseArray { diff --git a/src/Utils/SparseArray.cs.meta b/src/Internal/SparseArray.cs.meta similarity index 100% rename from src/Utils/SparseArray.cs.meta rename to src/Internal/SparseArray.cs.meta diff --git a/src/Internal/Utils.meta b/src/Internal/Utils.meta new file mode 100644 index 0000000..1ae538d --- /dev/null +++ b/src/Internal/Utils.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c36fbe915640753488e69c6e5d6efe92 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Internal/Utils/ColorUtility.cs b/src/Internal/Utils/ColorUtility.cs new file mode 100644 index 0000000..fe2b945 --- /dev/null +++ b/src/Internal/Utils/ColorUtility.cs @@ -0,0 +1,20 @@ +using UnityEngine; + +namespace DCFApixels.DragonECS.Unity.Internal +{ + internal static class ColorUtility + { + public static Color Desaturate(this Color self, float t) + { + float r = self.r; + float g = self.g; + float b = self.b; + //float gray = r * 0.299f + g * 0.587f + b * 0.114f; + float gray = r * 0.3333333f + g * 0.3333333f + b * 0.3333333f; + r = r + (gray - r) * (1 - t); + g = g + (gray - g) * (1 - t); + b = b + (gray - b) * (1 - t); + return new Color(r, g, b, self.a); + } + } +} \ No newline at end of file diff --git a/src/Internal/Utils/ColorUtility.cs.meta b/src/Internal/Utils/ColorUtility.cs.meta new file mode 100644 index 0000000..c29ec5c --- /dev/null +++ b/src/Internal/Utils/ColorUtility.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ff5cb33212a8c8a4eb5111cc17759e47 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Internal/Utils/RectUtility.cs b/src/Internal/Utils/RectUtility.cs new file mode 100644 index 0000000..e341fbf --- /dev/null +++ b/src/Internal/Utils/RectUtility.cs @@ -0,0 +1,75 @@ +using UnityEngine; + +namespace DCFApixels.DragonECS.Unity.Internal +{ + internal static class RectUtility + { + public static (Rect, Rect) HorizontalSliceLerp(Rect rect, float t) + { + Rect l = rect; + Rect r = rect; + l.xMax -= rect.width * (1f - t); + r.xMin += rect.width * t; + return (l, r); + } + public static (Rect, Rect) HorizontalSliceLeft(Rect rect, float with) + { + Rect l = rect; + Rect r = rect; + l.xMax = l.xMin + with; + r.xMin += with; + return (l, r); + } + public static (Rect, Rect) HorizontalSliceRight(Rect rect, float with) + { + Rect l = rect; + Rect r = rect; + l.xMax -= with; + r.xMin = r.xMax - with; + return (l, r); + } + + public static (Rect, Rect) VerticalSliceTop(Rect rect, float height) + { + Rect t = rect; + Rect b = rect; + t.yMax = t.yMin + height; + b.yMin += height; + return (t, b); + } + public static (Rect, Rect) VerticalSliceBottom(Rect rect, float height) + { + Rect t = rect; + Rect b = rect; + t.yMax -= height; + b.yMin = b.yMax - height; + return (t, b); + } + + public static Rect AddPadding(Rect rect, float verticalHorizontal) + { + return AddPadding(rect, verticalHorizontal, verticalHorizontal, verticalHorizontal, verticalHorizontal); + } + public static Rect AddPadding(Rect rect, float horizontal, float vertical) + { + return AddPadding(rect, horizontal, horizontal, vertical, vertical); + } + public static Rect AddPadding(Rect rect, float left, float right, float top, float bottom) + { + rect.xMin += left; + rect.xMax -= right; + rect.yMin += top; + rect.yMax -= bottom; + return rect; + } + public static Rect Move(Rect rect, Vector2 addVector) + { + rect.center += addVector; + return rect; + } + public static Rect Move(Rect rect, float addX, float addY) + { + return Move(rect, new Vector2(addX, addY)); + } + } +} diff --git a/src/Internal/Utils/RectUtility.cs.meta b/src/Internal/Utils/RectUtility.cs.meta new file mode 100644 index 0000000..6a31900 --- /dev/null +++ b/src/Internal/Utils/RectUtility.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a08af8a9e1192f44c8aedf88340cb663 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Utils/DebugColorAttributeExt.cs b/src/Utils/DebugColorAttributeExt.cs deleted file mode 100644 index c9d8ad5..0000000 --- a/src/Utils/DebugColorAttributeExt.cs +++ /dev/null @@ -1,16 +0,0 @@ -using UnityEngine; - -namespace DCFApixels.DragonECS -{ - public static class DebugColorAttributeExt - { - public static Color GetUnityColor(this DebugColorAttribute self) - { - return new Color(self.rn, self.gn, self.bn); - } - public static Color32 GetUnityColor32(this DebugColorAttribute self) - { - return new Color32(self.r, self.g, self.b, 255); - } - } -} diff --git a/src/Utils/MetaColorExstensions.cs b/src/Utils/MetaColorExstensions.cs new file mode 100644 index 0000000..18238e6 --- /dev/null +++ b/src/Utils/MetaColorExstensions.cs @@ -0,0 +1,16 @@ +using UnityEngine; + +namespace DCFApixels.DragonECS +{ + public static class MetaColorExstensions + { + public static Color ToUnityColor(this T self) where T : IMetaColor + { + return new Color(self.R / 255f, self.G / 255f, self.B / 255f, self.A / 255f); + } + public static Color32 ToUnityColor32(this T self) where T : IMetaColor + { + return new Color32(self.R, self.G, self.B, self.A); + } + } +} diff --git a/src/Utils/DebugColorAttributeExt.cs.meta b/src/Utils/MetaColorExstensions.cs.meta similarity index 100% rename from src/Utils/DebugColorAttributeExt.cs.meta rename to src/Utils/MetaColorExstensions.cs.meta