mirror of
https://github.com/DCFApixels/DragonECS-Unity.git
synced 2025-11-12 23:15:56 +08:00
update
This commit is contained in:
parent
dd41a6f2b8
commit
dc575bd516
@ -1,6 +1,7 @@
|
||||
#if UNITY_EDITOR
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Text;
|
||||
using UnityEditor;
|
||||
using UnityEditor.ProjectWindowCallback;
|
||||
@ -12,9 +13,9 @@ namespace DCFApixels.DragonECS.Editors
|
||||
{
|
||||
private const int MENU_ITEM_PRIORITY = -198;
|
||||
|
||||
private const string TITLE = "DragonECS Template Generator";
|
||||
private const string TITLE = EcsConsts.FRAMEWORK_NAME + " Template Generator";
|
||||
|
||||
private const string MENU_ITEM_PATH = "Assets/Create/DragonECS/";
|
||||
private const string MENU_ITEM_PATH = "Assets/Create/" + EcsConsts.FRAMEWORK_NAME + "/";
|
||||
|
||||
private const string NAMESPACE_TAG = "#NAMESPACE#";
|
||||
private const string SCRIPTANAME_TAG = "#SCRIPTNAME#";
|
||||
@ -29,25 +30,25 @@ namespace DCFApixels.DragonECS.Editors
|
||||
#endregion
|
||||
|
||||
#region GenerateMethods
|
||||
[MenuItem(MENU_ITEM_PATH + "[Template]Startup", false, MENU_ITEM_PRIORITY)]
|
||||
[MenuItem(MENU_ITEM_PATH + "[CodeTemplate]Startup", false, MENU_ITEM_PRIORITY)]
|
||||
public static void CreateSturtupScript() => CreateScript("Startup");
|
||||
|
||||
[MenuItem(MENU_ITEM_PATH + "[Template]System", false, MENU_ITEM_PRIORITY)]
|
||||
[MenuItem(MENU_ITEM_PATH + "[CodeTemplate]System", false, MENU_ITEM_PRIORITY)]
|
||||
public static void CreateSystemSimpleScript() => CreateScript("System");
|
||||
|
||||
[MenuItem(MENU_ITEM_PATH + "[Template]Component", false, MENU_ITEM_PRIORITY)]
|
||||
[MenuItem(MENU_ITEM_PATH + "[CodeTemplate]Component", false, MENU_ITEM_PRIORITY)]
|
||||
public static void CreateComponentSimpleScript() => CreateScript("Component");
|
||||
|
||||
[MenuItem(MENU_ITEM_PATH + "[Template]Runner", false, MENU_ITEM_PRIORITY)]
|
||||
[MenuItem(MENU_ITEM_PATH + "[CodeTemplate]Runner", false, MENU_ITEM_PRIORITY)]
|
||||
public static void CreateRunnerSimpleScript() => CreateScript("Runner");
|
||||
|
||||
[MenuItem(MENU_ITEM_PATH + "[Template]System Extended", false, MENU_ITEM_PRIORITY)]
|
||||
[MenuItem(MENU_ITEM_PATH + "[CodeTemplate]System Extended", false, MENU_ITEM_PRIORITY)]
|
||||
public static void CreateSystemScript() => CreateScript("SystemExtended");
|
||||
|
||||
[MenuItem(MENU_ITEM_PATH + "[Template]Component Extended", false, MENU_ITEM_PRIORITY)]
|
||||
[MenuItem(MENU_ITEM_PATH + "[CodeTemplate]Component Extended", false, MENU_ITEM_PRIORITY)]
|
||||
public static void CreateComponentScript() => CreateScript("ComponentExtended");
|
||||
|
||||
[MenuItem(MENU_ITEM_PATH + "[Template]Runner Extended", false, MENU_ITEM_PRIORITY)]
|
||||
[MenuItem(MENU_ITEM_PATH + "[CodeTemplate]Runner Extended", false, MENU_ITEM_PRIORITY)]
|
||||
public static void CreateRunnerScript() => CreateScript("RunnerExtended");
|
||||
|
||||
|
||||
@ -15,7 +15,7 @@ namespace DCFApixels.DragonECS
|
||||
string log;
|
||||
if (!string.IsNullOrEmpty(tag))
|
||||
{
|
||||
log = $"[{tag}] {v}";
|
||||
log = $".[{tag}] {v}";
|
||||
string taglower = tag.ToLower();
|
||||
if (taglower.Contains("warning"))
|
||||
{
|
||||
|
||||
@ -1,20 +1,40 @@
|
||||
#if UNITY_EDITOR
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using UnityEngine;
|
||||
|
||||
namespace DCFApixels.DragonECS.Editors
|
||||
{
|
||||
public static class EcsEditor
|
||||
{
|
||||
private static SparseArray<GUIStyle> colorBoxeStyles = new SparseArray<GUIStyle>();
|
||||
public static GUIStyle GetStyle(Color color, float alphaMultiplier)
|
||||
{
|
||||
GUIStyle style = new GUIStyle(GUI.skin.box);
|
||||
Color componentColor = color;
|
||||
componentColor.a *= alphaMultiplier;
|
||||
style.normal.background = CreateTexture(2, 2, componentColor);
|
||||
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 = CreateStyle(color32, colorCode);
|
||||
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);
|
||||
return result;
|
||||
}
|
||||
private static Texture2D CreateTexture(int width, int height, Color color)
|
||||
{
|
||||
var pixels = new Color[width * height];
|
||||
@ -26,6 +46,73 @@ namespace DCFApixels.DragonECS.Editors
|
||||
result.Apply();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public static string GetGenericName(Type type)
|
||||
{
|
||||
string friendlyName = type.Name;
|
||||
if (type.IsGenericType)
|
||||
{
|
||||
int iBacktick = friendlyName.IndexOf('`');
|
||||
if (iBacktick > 0)
|
||||
friendlyName = friendlyName.Remove(iBacktick);
|
||||
|
||||
friendlyName += "<";
|
||||
Type[] typeParameters = type.GetGenericArguments();
|
||||
for (int i = 0; i < typeParameters.Length; ++i)
|
||||
{
|
||||
string typeParamName = GetGenericName(typeParameters[i]);
|
||||
friendlyName += (i == 0 ? typeParamName : "," + typeParamName);
|
||||
}
|
||||
friendlyName += ">";
|
||||
}
|
||||
return friendlyName;
|
||||
}
|
||||
|
||||
public static string GetName<T>() => GetName(typeof(T));
|
||||
public static string GetName(Type type)
|
||||
{
|
||||
var atr = type.GetCustomAttribute<DebugNameAttribute>();
|
||||
return atr != null ? atr.name : GetGenericName(type);
|
||||
}
|
||||
|
||||
public static string GetDescription<T>() => GetDescription(typeof(T));
|
||||
public static string GetDescription(Type type)
|
||||
{
|
||||
var atr = type.GetCustomAttribute<DebugDescriptionAttribute>();
|
||||
return atr != null ? atr.description : string.Empty;
|
||||
}
|
||||
|
||||
#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
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
{
|
||||
public sealed class DebugModule : IEcsModule
|
||||
{
|
||||
public const string DEBUG_SYSTEMS_BLOCK = nameof(DEBUG_SYSTEMS_BLOCK);
|
||||
public const string DEBUG_LAYER = nameof(DEBUG_LAYER);
|
||||
public EcsWorld[] _worlds;
|
||||
public DebugModule(params EcsWorld[] worlds)
|
||||
{
|
||||
@ -11,11 +11,11 @@
|
||||
|
||||
void IEcsModule.ImportSystems(EcsPipeline.Builder b)
|
||||
{
|
||||
b.InsertSystemsBlock(DEBUG_SYSTEMS_BLOCK, EcsConsts.POST_END_SYSTEMS_BLOCK);
|
||||
b.Add(new PipelineDebugSystem(), DEBUG_SYSTEMS_BLOCK);
|
||||
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_SYSTEMS_BLOCK);
|
||||
b.Add(new WorldDebugSystem(world), DEBUG_LAYER);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace DCFApixels.DragonECS.Unity.Debug
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
using DCFApixels.DragonECS.Unity;
|
||||
using DCFApixels.DragonECS.Unity.Debug;
|
||||
using DCFApixels.DragonECS.Unity.Debug;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
@ -7,7 +6,7 @@ using UnityEngine;
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
[DebugHide, DebugColor(DebugColor.Gray)]
|
||||
public class PipelineDebugSystem : IEcsPreInitSystem
|
||||
public class PipelineDebugSystem : IEcsPreInitProcess
|
||||
{
|
||||
private string _monitorName;
|
||||
public PipelineDebugSystem(string monitorName = "Pipeline")
|
||||
@ -15,13 +14,20 @@ namespace DCFApixels.DragonECS
|
||||
_monitorName = monitorName;
|
||||
}
|
||||
|
||||
void IEcsPreInitSystem.PreInit(EcsPipeline pipeline)
|
||||
void IEcsPreInitProcess.PreInit(EcsPipeline pipeline)
|
||||
{
|
||||
PipelineDebugMonitor monitor = new GameObject(EcsConsts.DEBUG_PREFIX + _monitorName).AddComponent<PipelineDebugMonitor>();
|
||||
monitor.source = this;
|
||||
monitor.pipeline = pipeline;
|
||||
monitor.monitorName = _monitorName;
|
||||
|
||||
PipelineProcessesDebugMonitor processesMonitor = new GameObject(EcsConsts.DEBUG_PREFIX + "Processes Matrix").AddComponent<PipelineProcessesDebugMonitor>();
|
||||
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<DebugNameAttribute>();
|
||||
@ -37,11 +43,18 @@ namespace DCFApixels.DragonECS
|
||||
internal EcsPipeline pipeline;
|
||||
}
|
||||
|
||||
public class PipelineProcessesDebugMonitor : DebugMonitorBase
|
||||
{
|
||||
internal PipelineDebugSystem source;
|
||||
internal EcsPipeline pipeline;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
namespace Editors
|
||||
{
|
||||
using DCFApixels.DragonECS.RunnersCore;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
|
||||
@ -102,7 +115,7 @@ namespace DCFApixels.DragonECS
|
||||
|
||||
private void DrawSystem(IEcsSystem system)
|
||||
{
|
||||
if(system is SystemsBlockMarkerSystem markerSystem)
|
||||
if (system is SystemsBlockMarkerSystem markerSystem)
|
||||
{
|
||||
GUILayout.EndVertical();
|
||||
GUILayout.BeginVertical(EcsEditor.GetStyle(Color.black, 0.2f));
|
||||
@ -120,7 +133,7 @@ namespace DCFApixels.DragonECS
|
||||
if (CheckIsHidden(type))
|
||||
return;
|
||||
|
||||
string name = type.Name;
|
||||
string name = EcsEditor.GetGenericName(type);
|
||||
Color color = (GetAttribute<DebugColorAttribute>(type) ?? _fakeDebugColorAttribute).GetUnityColor();
|
||||
|
||||
GUILayout.BeginVertical(EcsEditor.GetStyle(color, 0.2f));
|
||||
@ -140,7 +153,7 @@ namespace DCFApixels.DragonECS
|
||||
|
||||
Color color = (GetAttribute<DebugColorAttribute>(type) ?? _fakeDebugColorAttribute).GetUnityColor();
|
||||
GUILayout.BeginVertical(EcsEditor.GetStyle(color, 0.2f));
|
||||
GUILayout.Label(type.Name, EditorStyles.boldLabel);
|
||||
GUILayout.Label(EcsEditor.GetGenericName(type), EditorStyles.boldLabel);
|
||||
GUILayout.Label(string.Join(", ", runner.Targets.Cast<object>().Select(o => o.GetType().Name)), systemsListStyle);
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
@ -161,7 +174,166 @@ namespace DCFApixels.DragonECS
|
||||
return target.GetCustomAttribute<DebugHideAttribute>() != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[CustomEditor(typeof(PipelineProcessesDebugMonitor))]
|
||||
public class PipelineProcessesDebugMonitorEditor : Editor
|
||||
{
|
||||
private bool _isInit = false;
|
||||
private List<ProcessData> _processesList = new List<ProcessData>();
|
||||
private Dictionary<Type, int> _processeIndexes = new Dictionary<Type, int>();
|
||||
|
||||
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 SystemsBlockMarkerSystem == false).ToArray();
|
||||
else
|
||||
_systems = Target.pipeline.AllSystems.Where(o => o.GetType().GetCustomAttribute<DebugHideAttribute>() == 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<DebugHideAttribute>() == 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<string> systeNames = new List<string>();
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@ -1,29 +0,0 @@
|
||||
using DCFApixels.DragonECS.Unity.Debug;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace DCFApixels.DragonECS.Unity
|
||||
{
|
||||
public class SystemDebugMonitor :MonoBehaviour
|
||||
{
|
||||
[SerializeReference]
|
||||
private IEcsSystem _target; //TODO переделать подручнуюотрисовку, потому как [SerializeReference] не работает с generic-ами
|
||||
|
||||
public static SystemDebugMonitor CreateMonitor(Transform parent, IEcsSystem system, string name)
|
||||
{
|
||||
GameObject go = new GameObject(name);
|
||||
go.transform.parent = parent;
|
||||
go.transform.position = Vector3.zero;
|
||||
go.transform.rotation = Quaternion.identity;
|
||||
|
||||
go.SetActive(false);
|
||||
|
||||
SystemDebugMonitor result = go.AddComponent<SystemDebugMonitor>();
|
||||
|
||||
result._target = system;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6,17 +6,18 @@ using UnityEngine;
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
[DebugHide, DebugColor(DebugColor.Gray)]
|
||||
public class WorldDebugSystem : IEcsRunSystem
|
||||
public class WorldDebugSystem : IEcsRunProcess
|
||||
{
|
||||
private string _monitorName;
|
||||
private EcsWorld _ecsWorld;
|
||||
|
||||
public WorldDebugSystem(EcsWorld ecsWorld, string monitorName = "World")
|
||||
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<WorldDebugMonitor>();
|
||||
WorldPoolsMonitor poolsmonitor = new GameObject(EcsConsts.DEBUG_PREFIX + _monitorName).AddComponent<WorldPoolsMonitor>();
|
||||
WorldPoolsMonitor poolsmonitor = new GameObject(EcsConsts.DEBUG_PREFIX + "Pools").AddComponent<WorldPoolsMonitor>();
|
||||
poolsmonitor.transform.SetParent(monitor.transform);
|
||||
|
||||
monitor.source = this;
|
||||
@ -49,8 +50,11 @@ namespace DCFApixels.DragonECS
|
||||
{
|
||||
private WorldDebugMonitor Target => (WorldDebugMonitor)target;
|
||||
|
||||
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
GUILayout.Label($"Size: {Target.world.Capacity}");
|
||||
GUILayout.Label($"Total entities: {Target.world.Count}");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -83,75 +87,81 @@ namespace DCFApixels.DragonECS
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
// _scroll = GUILayout.BeginScrollView(_scroll, GUILayout.Height(800f));
|
||||
// var pools = Target.world.GetAllPools().ToArray().Where(o => !(o is EcsNullPool)).OfType<IEcsPool>();
|
||||
//
|
||||
// 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();
|
||||
_scroll = GUILayout.BeginScrollView(_scroll, GUILayout.Height(800f));
|
||||
var pools = Target.world.AllPools.ToArray().Where(o => !o.IsNullOrDummy()).OfType<IEcsPool>();
|
||||
|
||||
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)
|
||||
// {
|
||||
// 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<DebugColorAttribute>();
|
||||
// if (debugColor != null)
|
||||
// {
|
||||
// mainColor = debugColor.GetUnityColor();
|
||||
// }
|
||||
// Color backgroundColor = mainColor * 0.3f + Color.white * 0.2f;
|
||||
//
|
||||
// EditorGUI.DrawRect(progressBar, backgroundColor);
|
||||
//
|
||||
// progressBar.yMin = progressBar.yMax - ((float)pool.Count / pool.Capacity) * progressBar.height;
|
||||
//
|
||||
// GUIStyle textStyle0 = EditorStyles.miniBoldLabel;
|
||||
// textStyle0.alignment = TextAnchor.MiddleCenter;
|
||||
//
|
||||
// Color foregroundColor = mainColor;
|
||||
// EditorGUI.DrawRect(progressBar, foregroundColor);
|
||||
// GUI.Label(progressBar, pool.Count.ToString(), textStyle0);
|
||||
//
|
||||
// GUIStyle textStyle1 = EditorStyles.miniBoldLabel;
|
||||
// textStyle1.alignment = TextAnchor.UpperCenter;
|
||||
// GUI.Label(AddMargin(position, 3f, 3f), "Total\r\n"+ pool.Capacity, textStyle1);
|
||||
//
|
||||
// GUI.contentColor = defaultContentColor;
|
||||
// GUIStyle textStyle2 = EditorStyles.miniBoldLabel;
|
||||
// textStyle2.alignment = TextAnchor.LowerCenter;
|
||||
// GUI.Label(AddMargin(position, -10f, 3f), pool.ComponentType.Name, textStyle2);
|
||||
//
|
||||
// }
|
||||
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<DebugColorAttribute>();
|
||||
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, $"t({name})");
|
||||
GUI.Label(AddMargin(position, -10f, 3f), label, textStyle2);
|
||||
|
||||
}
|
||||
|
||||
private Rect AddMargin(Rect rect, Vector2 value)
|
||||
{
|
||||
|
||||
7
src/EcsUnityConsts.cs
Normal file
7
src/EcsUnityConsts.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
public static class EcsUnityConsts
|
||||
{
|
||||
public const string INFO_MARK = "[i]";
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bf4cdc68b5b89a14c81a53b600078536
|
||||
guid: b33e303fef8298b4db42987fe9b94e45
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 70c8e3cb9125ee14fad9fdee48c3e8ba
|
||||
guid: 11dc6a014c6c7e84ab61979e25010c57
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
17
src/EntityTemplate/EntityTemplate.cs
Normal file
17
src/EntityTemplate/EntityTemplate.cs
Normal file
@ -0,0 +1,17 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
src/EntityTemplate/EntityTemplate.cs.meta
Normal file
11
src/EntityTemplate/EntityTemplate.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3c96e3aedd5a69443af75096e5561265
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
235
src/EntityTemplate/EntityTemplateEditor.cs
Normal file
235
src/EntityTemplate/EntityTemplateEditor.cs
Normal file
@ -0,0 +1,235 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
namespace Editors
|
||||
{
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
public 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);
|
||||
}
|
||||
}
|
||||
private void DrawTop(ITemplateInternal target)
|
||||
{
|
||||
if (GUILayout.Button("Add Component", GUILayout.Height(24f)))
|
||||
{
|
||||
Init();
|
||||
genericMenu.ShowAsContext();
|
||||
}
|
||||
}
|
||||
private void DrawComponentData(SerializedProperty componentRefProp, int index)
|
||||
{
|
||||
ITemplateComponent browsable = (ITemplateComponent)componentRefProp.managedReferenceValue;
|
||||
ITemplateComponentName browsableName = browsable as ITemplateComponentName;
|
||||
|
||||
if (componentRefProp.managedReferenceValue == null)
|
||||
{
|
||||
DrawDamagedComponent(componentRefProp, index);
|
||||
return;
|
||||
}
|
||||
|
||||
Type componentType;
|
||||
SerializedProperty componentProperty = componentRefProp;
|
||||
TemplateComponentInitializerBase customInitializer = componentProperty.managedReferenceValue as TemplateComponentInitializerBase;
|
||||
if (customInitializer != null)
|
||||
{
|
||||
componentProperty = componentProperty.FindPropertyRelative("component");
|
||||
componentType = customInitializer.Type;
|
||||
}
|
||||
else
|
||||
{
|
||||
componentType = componentProperty.managedReferenceValue.GetType();
|
||||
}
|
||||
|
||||
Type type = browsable.GetType();
|
||||
string name = browsableName == null ? type.Name : GetLastPathComponent(browsableName.Name);
|
||||
string description = customInitializer != null ? customInitializer.Description : componentType.GetCustomAttribute<DebugDescriptionAttribute>()?.description;
|
||||
Color panelColor = customInitializer != null ? customInitializer.Color : componentType.GetCustomAttribute<DebugColorAttribute>()?.GetUnityColor() ?? Color.black;
|
||||
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
|
||||
GUILayout.BeginVertical(EcsEditor.GetStyle(panelColor, 0.2f));
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
GUIContent label = new GUIContent(name, $"{name} ");
|
||||
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
|
||||
}
|
||||
11
src/EntityTemplate/EntityTemplateEditor.cs.meta
Normal file
11
src/EntityTemplate/EntityTemplateEditor.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 90b44ae9b0ef473488a3befa9a120d61
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
24
src/EntityTemplate/EntityTemplatePreset.cs
Normal file
24
src/EntityTemplate/EntityTemplatePreset.cs
Normal file
@ -0,0 +1,24 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
src/EntityTemplate/EntityTemplatePreset.cs.meta
Normal file
11
src/EntityTemplate/EntityTemplatePreset.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 54d84d8749e68c044b4f13a512808a67
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
25
src/EntityTemplate/ITemplate.cs
Normal file
25
src/EntityTemplate/ITemplate.cs
Normal file
@ -0,0 +1,25 @@
|
||||
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.NewEntity();
|
||||
self.Apply(world, e);
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
src/EntityTemplate/ITemplate.cs.meta
Normal file
11
src/EntityTemplate/ITemplate.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 33a7d50d86178eb43a36d5e8bdd70982
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
131
src/EntityTemplate/TemplateComponent.cs
Normal file
131
src/EntityTemplate/TemplateComponent.cs
Normal file
@ -0,0 +1,131 @@
|
||||
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; }
|
||||
}
|
||||
|
||||
[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; }
|
||||
|
||||
#region Get meta
|
||||
internal static Color GetColor(Type type)
|
||||
{
|
||||
var atr = type.GetCustomAttribute<DebugColorAttribute>();
|
||||
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<DebugDescriptionAttribute>();
|
||||
if (atr == null) return string.Empty;
|
||||
return atr.description;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
[Serializable]
|
||||
public abstract class TemplateComponentInitializer<T> : TemplateComponentInitializerBase, ITemplateComponentName
|
||||
{
|
||||
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);
|
||||
#endregion
|
||||
|
||||
public abstract void Add(EcsWorld w, int e);
|
||||
}
|
||||
|
||||
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<Type> Types => _types;
|
||||
internal static ReadOnlySpan<ITemplateComponent> Dummies => _dummies;
|
||||
|
||||
static TemplateBrowsableTypeCache()
|
||||
{
|
||||
List<Type> types = new List<Type>();
|
||||
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<SerializableAttribute>() != null);
|
||||
|
||||
types.AddRange(targetTypes.Where(type => interfaceType.IsAssignableFrom(type)));
|
||||
|
||||
foreach (var t in targetTypes)
|
||||
{
|
||||
if (t.IsSubclassOf(typeof(TemplateComponentInitializer<>)))
|
||||
{
|
||||
if(t.GetCustomAttribute<SerializableAttribute>() != 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
|
||||
}
|
||||
11
src/EntityTemplate/TemplateComponent.cs.meta
Normal file
11
src/EntityTemplate/TemplateComponent.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0ce52308e352f734e8a21c5ae282c246
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
src/Extensions.meta
Normal file
8
src/Extensions.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 37d966ee996491b4d923ae68af4b67cd
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
143
src/Extensions/EcsEntityConnect.cs
Normal file
143
src/Extensions/EcsEntityConnect.cs
Normal file
@ -0,0 +1,143 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using UnityEngine;
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
public class EcsEntityConnect : MonoBehaviour
|
||||
{
|
||||
private sealed class Subject : EcsSubject
|
||||
{
|
||||
public readonly EcsPool<UnityGameObject> unityGameObjects;
|
||||
public Subject(Builder b)
|
||||
{
|
||||
unityGameObjects = b.Include<UnityGameObject>();
|
||||
}
|
||||
}
|
||||
|
||||
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<Subject>();
|
||||
s.unityGameObjects.Del(oldE);
|
||||
}
|
||||
_world = null;
|
||||
|
||||
if (entity.TryGetID(out int newE))
|
||||
{
|
||||
_entity = entity;
|
||||
_world = _entity.World;
|
||||
var s = _world.GetSubject<Subject>();
|
||||
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<EntityTemplate>());
|
||||
|
||||
EditorUtility.SetDirty(target);
|
||||
}
|
||||
if (GUILayout.Button("Autoset Templates Cascade"))
|
||||
{
|
||||
foreach (var item in Target.GetComponentsInChildren<EcsEntityConnect>())
|
||||
{
|
||||
item.SetTemplates_Editor(item.GetComponents<EntityTemplate>());
|
||||
EditorUtility.SetDirty(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
11
src/Extensions/EcsEntityConnect.cs.meta
Normal file
11
src/Extensions/EcsEntityConnect.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cdc92b01ccc1e684f955830aa7cea7d4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
public interface IEcsLateRunSystem : IEcsSystem
|
||||
public interface IEcsLateRunProcess : IEcsSystem
|
||||
{
|
||||
public void LateRun(EcsPipeline pipeline);
|
||||
}
|
||||
@ -10,10 +10,10 @@ namespace DCFApixels.DragonECS
|
||||
{
|
||||
public static void LateRun(this EcsPipeline systems)
|
||||
{
|
||||
systems.GetRunner<IEcsLateRunSystem>().LateRun(systems);
|
||||
systems.GetRunner<IEcsLateRunProcess>().LateRun(systems);
|
||||
}
|
||||
}
|
||||
public interface IEcsFixedRunSystem : IEcsSystem
|
||||
public interface IEcsFixedRunProcess : IEcsSystem
|
||||
{
|
||||
public void FixedRun(EcsPipeline pipeline);
|
||||
}
|
||||
@ -21,14 +21,14 @@ namespace DCFApixels.DragonECS
|
||||
{
|
||||
public static void FixedRun(this EcsPipeline pipeline)
|
||||
{
|
||||
pipeline.GetRunner<IEcsFixedRunSystem>().FixedRun(pipeline);
|
||||
pipeline.GetRunner<IEcsFixedRunProcess>().FixedRun(pipeline);
|
||||
}
|
||||
}
|
||||
|
||||
namespace Internal
|
||||
{
|
||||
[DebugColor(DebugColor.Orange)]
|
||||
public class EcsLateRunSystemRunner : EcsRunner<IEcsLateRunSystem>, IEcsLateRunSystem
|
||||
public class EcsLateRunSystemRunner : EcsRunner<IEcsLateRunProcess>, IEcsLateRunProcess
|
||||
{
|
||||
#if DEBUG && !DISABLE_DEBUG
|
||||
private EcsProfilerMarker[] _markers;
|
||||
@ -58,7 +58,7 @@ namespace DCFApixels.DragonECS
|
||||
#endif
|
||||
}
|
||||
[DebugColor(DebugColor.Orange)]
|
||||
public class EcsFixedRunSystemRunner : EcsRunner<IEcsFixedRunSystem>, IEcsFixedRunSystem
|
||||
public class EcsFixedRunSystemRunner : EcsRunner<IEcsFixedRunProcess>, IEcsFixedRunProcess
|
||||
{
|
||||
#if DEBUG && !DISABLE_DEBUG
|
||||
private EcsProfilerMarker[] _markers;
|
||||
56
src/Extensions/Systems.cs
Normal file
56
src/Extensions/Systems.cs
Normal file
@ -0,0 +1,56 @@
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
[DebugHide, DebugColor(DebugColor.Grey)]
|
||||
public class DeleteOneFrameComponentFixedSystem<TWorld, TComponent> : IEcsFixedRunProcess, IEcsInject<TWorld>
|
||||
where TWorld : EcsWorld<TWorld>
|
||||
where TComponent : struct, IEcsComponent
|
||||
{
|
||||
private TWorld _world;
|
||||
public void Inject(TWorld obj) => _world = obj;
|
||||
|
||||
private sealed class Subject : EcsSubject
|
||||
{
|
||||
public EcsPool<TComponent> pool;
|
||||
public Subject(Builder b)
|
||||
{
|
||||
pool = b.Include<TComponent>();
|
||||
}
|
||||
}
|
||||
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<TWorld, TComponent>(this EcsPipeline.Builder b)
|
||||
where TWorld : EcsWorld<TWorld>
|
||||
where TComponent : struct, IEcsComponent
|
||||
{
|
||||
b.Layers.Insert(EcsConsts.POST_END_LAYER, AUTO_DEL_FIXED_LAYER);
|
||||
b.AddUnique(new DeleteOneFrameComponentFixedSystem<TWorld, TComponent>(), AUTO_DEL_FIXED_LAYER);
|
||||
return b;
|
||||
}
|
||||
/// <summary> for EcsDefaultWorld </summary>
|
||||
public static EcsPipeline.Builder AutoDelFixed<TComponent>(this EcsPipeline.Builder b)
|
||||
where TComponent : struct, IEcsComponent
|
||||
{
|
||||
b.Layers.Insert(EcsConsts.POST_END_LAYER, AUTO_DEL_FIXED_LAYER);
|
||||
b.AddUnique(new DeleteOneFrameComponentFixedSystem<EcsDefaultWorld, TComponent>(), AUTO_DEL_FIXED_LAYER);
|
||||
return b;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
src/Extensions/Systems.cs.meta
Normal file
11
src/Extensions/Systems.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e8c608fea9f3569409826ec54affa822
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
72
src/Extensions/UnityComponents.cs
Normal file
72
src/Extensions/UnityComponents.cs
Normal file
@ -0,0 +1,72 @@
|
||||
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<T> : IEcsComponent, IEnumerable<T>//IntelliSense hack
|
||||
where T : class
|
||||
{
|
||||
public T obj;
|
||||
|
||||
IEnumerator<T> IEnumerable<T>.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<UnityComponent<Rigidbody>>
|
||||
{
|
||||
public override void Add(EcsWorld w, int e) => w.GetPool<UnityComponent<Rigidbody>>().Add(e) = component;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
[MovedFrom(false, "Client", null, "RefAnimatorInitializer")]
|
||||
public sealed class UnityComponentAnimatorInitializer : TemplateComponentInitializer<UnityComponent<Animator>>
|
||||
{
|
||||
public override void Add(EcsWorld w, int e) => w.GetPool<UnityComponent<Animator>>().Add(e) = component;
|
||||
}
|
||||
[Serializable]
|
||||
public sealed class UnityComponentCharacterControllerInitializer : TemplateComponentInitializer<UnityComponent<CharacterController>>
|
||||
{
|
||||
public override void Add(EcsWorld w, int e) => w.GetPool<UnityComponent<CharacterController>>().Add(e) = component;
|
||||
}
|
||||
|
||||
#region Colliders
|
||||
[Serializable]
|
||||
public sealed class UnityComponentColliderInitializer : TemplateComponentInitializer<UnityComponent<Collider>>
|
||||
{
|
||||
public override string Name => "UnityComponent/Collider/" + nameof(Collider);
|
||||
public override void Add(EcsWorld w, int e) => w.GetPool<UnityComponent<Collider>>().Add(e) = component;
|
||||
}
|
||||
[Serializable]
|
||||
public sealed class UnityComponentBoxColliderInitializer : TemplateComponentInitializer<UnityComponent<BoxCollider>>
|
||||
{
|
||||
public override string Name => "UnityComponent/Collider/" + nameof(BoxCollider);
|
||||
public override void Add(EcsWorld w, int e) => w.GetPool<UnityComponent<BoxCollider>>().Add(e) = component;
|
||||
}
|
||||
[Serializable]
|
||||
public sealed class UnityComponentSphereColliderInitializer : TemplateComponentInitializer<UnityComponent<SphereCollider>>
|
||||
{
|
||||
public override string Name => "UnityComponent/Collider/" + nameof(SphereCollider);
|
||||
public override void Add(EcsWorld w, int e) => w.GetPool<UnityComponent<SphereCollider>>().Add(e) = component;
|
||||
}
|
||||
[Serializable]
|
||||
public sealed class UnityComponentCapsuleColliderInitializer : TemplateComponentInitializer<UnityComponent<CapsuleCollider>>
|
||||
{
|
||||
public override string Name => "UnityComponent/Collider/" + nameof(CapsuleCollider);
|
||||
public override void Add(EcsWorld w, int e) => w.GetPool<UnityComponent<CapsuleCollider>>().Add(e) = component;
|
||||
}
|
||||
[Serializable]
|
||||
public sealed class UnityComponentMeshColliderInitializer : TemplateComponentInitializer<UnityComponent<MeshCollider>>
|
||||
{
|
||||
public override string Name => "UnityComponent/Collider/" + nameof(MeshCollider);
|
||||
public override void Add(EcsWorld w, int e) => w.GetPool<UnityComponent<MeshCollider>>().Add(e) = component;
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
11
src/Extensions/UnityComponents.cs.meta
Normal file
11
src/Extensions/UnityComponents.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 47a8547ed46c26e4bb6a68651ad40be0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -1,7 +1,5 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using UnityEngine;
|
||||
using System.Linq;
|
||||
using UnityEditor.ShortcutManagement;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
@ -62,11 +60,11 @@ namespace DCFApixels.DragonECS
|
||||
|
||||
public static class GameObjectRefExt
|
||||
{
|
||||
public static EcsEntity NewEntityWithGameObject(this EcsWorld self, string name = "EcsEntity", GameObjectIcon icon = GameObjectIcon.NONE)
|
||||
public static entlong NewEntityWithGameObject(this EcsWorld self, string name = "EcsEntity", GameObjectIcon icon = GameObjectIcon.NONE)
|
||||
{
|
||||
EcsEntity result = self.NewEntity();
|
||||
entlong result = self.GetEntityLong(self.NewEntity());
|
||||
GameObject newGameObject = new GameObject(name);
|
||||
newGameObject.AddComponent<EcsEntityConnect>().ConectWith(result);
|
||||
newGameObject.AddComponent<EcsEntityConnect>().ConnectWith(result);
|
||||
// self.GetPool<UnityGameObject>().Add(result.id) =
|
||||
#if UNITY_EDITOR
|
||||
if (icon != GameObjectIcon.NONE)
|
||||
@ -90,76 +88,4 @@ namespace DCFApixels.DragonECS
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class EcsEntityConnect : MonoBehaviour
|
||||
{
|
||||
private sealed class Query : EcsQuery
|
||||
{
|
||||
public readonly EcsPool<UnityGameObject> unityGameObjects;
|
||||
public Query(Builder b)
|
||||
{
|
||||
unityGameObjects = b.Include<UnityGameObject>();
|
||||
}
|
||||
}
|
||||
|
||||
private EcsEntity _entity;
|
||||
private EcsWorld _world;
|
||||
|
||||
#region Properties
|
||||
public EcsEntity 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 ConectWith(EcsEntity entity)
|
||||
{
|
||||
int e = _entity.id;
|
||||
if (_world != null && _entity.IsNotNull)
|
||||
{
|
||||
var q = _world.Select<Query>();
|
||||
q.unityGameObjects.Del(e);
|
||||
}
|
||||
_world = null;
|
||||
|
||||
_entity = entity;
|
||||
|
||||
if (_entity.IsNotNull)
|
||||
{
|
||||
_world = _entity.GetWorld();
|
||||
var q = _world.Select<Query>();
|
||||
if (!q.unityGameObjects.Has(e)) q.unityGameObjects.Add(e) = new UnityGameObject(gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
|
||||
namespace Editors
|
||||
{
|
||||
using UnityEditor;
|
||||
[CustomEditor(typeof(EcsEntityConnect))]
|
||||
public class EcsEntityEditor : Editor
|
||||
{
|
||||
private EcsEntityConnect Target => (EcsEntityConnect)target;
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
EditorGUILayout.IntField(Target.Entity.id);
|
||||
GUILayout.Label(Target.Entity.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
44
src/Utils/BitMask.cs
Normal file
44
src/Utils/BitMask.cs
Normal file
@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace DCFApixels.DragonECS.Editors
|
||||
{
|
||||
internal class BitMask
|
||||
{
|
||||
private const int OFFSET = 5;
|
||||
private const int MOD_MASK = 31;
|
||||
private const int DATA_BITS = 32;
|
||||
private int[] _data;
|
||||
|
||||
private int _size;
|
||||
|
||||
public BitMask(int size)
|
||||
{
|
||||
_data = Array.Empty<int>();
|
||||
Resize(size);
|
||||
}
|
||||
|
||||
public bool this[int index]
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => (_data[index >> OFFSET] & (1 << (index & MOD_MASK))) != 0;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
set
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
src/Utils/BitMask.cs.meta
Normal file
11
src/Utils/BitMask.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7f3449fe3fe92a747b97743ed020758e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
212
src/Utils/SparseArray.cs
Normal file
212
src/Utils/SparseArray.cs
Normal file
@ -0,0 +1,212 @@
|
||||
//SparseArray. Analogous to Dictionary<int, T>, but faster.
|
||||
//Benchmark result of indexer.get speed test with 300 elements:
|
||||
//[Dictinary: 5.786us] [SparseArray: 2.047us].
|
||||
using System;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace DCFApixels.DragonECS.Editors
|
||||
{
|
||||
internal class SparseArray<TValue>
|
||||
{
|
||||
public const int MIN_CAPACITY_BITS_OFFSET = 4;
|
||||
public const int MIN_CAPACITY = 1 << MIN_CAPACITY_BITS_OFFSET;
|
||||
private const int EMPTY = -1;
|
||||
|
||||
private int[] _buckets = Array.Empty<int>();
|
||||
private Entry[] _entries = Array.Empty<Entry>();
|
||||
|
||||
private int _count;
|
||||
|
||||
private int _freeList;
|
||||
private int _freeCount;
|
||||
|
||||
private int _modBitMask;
|
||||
|
||||
#region Properties
|
||||
public TValue this[int key]
|
||||
{
|
||||
get => _entries[FindEntry(key)].value;
|
||||
set => Insert(key, value);
|
||||
}
|
||||
|
||||
public int Count => _count;
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
public SparseArray(int minCapacity = MIN_CAPACITY)
|
||||
{
|
||||
minCapacity = NormalizeCapacity(minCapacity);
|
||||
_buckets = new int[minCapacity];
|
||||
for (int i = 0; i < minCapacity; i++)
|
||||
_buckets[i] = EMPTY;
|
||||
_entries = new Entry[minCapacity];
|
||||
_modBitMask = (minCapacity - 1) & 0x7FFFFFFF;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Add
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Add(int key, TValue value)
|
||||
{
|
||||
#if DEBUG
|
||||
if (Contains(key))
|
||||
throw new ArgumentException("Contains(hashKey) is true");
|
||||
#endif
|
||||
Insert(key, value);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Find/Insert/Remove
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private int FindEntry(int key)
|
||||
{
|
||||
for (int i = _buckets[key & _modBitMask]; i >= 0; i = _entries[i].next)
|
||||
if (_entries[i].hashKey == key) return i;
|
||||
return -1;
|
||||
}
|
||||
private void Insert(int key, TValue value)
|
||||
{
|
||||
int targetBucket = key & _modBitMask;
|
||||
|
||||
for (int i = _buckets[targetBucket]; i >= 0; i = _entries[i].next)
|
||||
{
|
||||
if (_entries[i].hashKey == key)
|
||||
{
|
||||
_entries[i].value = value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int index;
|
||||
if (_freeCount > 0)
|
||||
{
|
||||
index = _freeList;
|
||||
_freeList = _entries[index].next;
|
||||
_freeCount--;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_count == _entries.Length)
|
||||
{
|
||||
Resize();
|
||||
targetBucket = key & _modBitMask;
|
||||
}
|
||||
index = _count++;
|
||||
}
|
||||
|
||||
_entries[index].next = _buckets[targetBucket];
|
||||
_entries[index].hashKey = key;
|
||||
_entries[index].value = value;
|
||||
_buckets[targetBucket] = index;
|
||||
}
|
||||
public bool Remove(int key)
|
||||
{
|
||||
int bucket = key & _modBitMask;
|
||||
int last = -1;
|
||||
for (int i = _buckets[bucket]; i >= 0; last = i, i = _entries[i].next)
|
||||
{
|
||||
if (_entries[i].hashKey == key)
|
||||
{
|
||||
if (last < 0)
|
||||
{
|
||||
_buckets[bucket] = _entries[i].next;
|
||||
}
|
||||
else
|
||||
{
|
||||
_entries[last].next = _entries[i].next;
|
||||
}
|
||||
_entries[i].next = _freeList;
|
||||
_entries[i].hashKey = -1;
|
||||
_entries[i].value = default;
|
||||
_freeList = i;
|
||||
_freeCount++;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region TryGetValue
|
||||
public bool TryGetValue(int key, out TValue value)
|
||||
{
|
||||
int index = FindEntry(key);
|
||||
if (index < 0)
|
||||
{
|
||||
value = default;
|
||||
return false;
|
||||
}
|
||||
value = _entries[index].value;
|
||||
return true;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Contains
|
||||
public bool Contains(int key)
|
||||
{
|
||||
return FindEntry(key) >= 0;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Clear
|
||||
public void Clear()
|
||||
{
|
||||
if (_count > 0)
|
||||
{
|
||||
for (int i = 0; i < _buckets.Length; i++)
|
||||
{
|
||||
_buckets[i] = -1;
|
||||
}
|
||||
Array.Clear(_entries, 0, _count);
|
||||
_count = 0;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Resize
|
||||
private void Resize()
|
||||
{
|
||||
int newSize = _buckets.Length << 1;
|
||||
_modBitMask = (newSize - 1) & 0x7FFFFFFF;
|
||||
|
||||
Contract.Assert(newSize >= _entries.Length);
|
||||
int[] newBuckets = new int[newSize];
|
||||
for (int i = 0; i < newBuckets.Length; i++)
|
||||
newBuckets[i] = EMPTY;
|
||||
|
||||
Entry[] newEntries = new Entry[newSize];
|
||||
Array.Copy(_entries, 0, newEntries, 0, _count);
|
||||
for (int i = 0; i < _count; i++)
|
||||
{
|
||||
if (newEntries[i].hashKey >= 0)
|
||||
{
|
||||
int bucket = newEntries[i].hashKey % newSize;
|
||||
newEntries[i].next = newBuckets[bucket];
|
||||
newBuckets[bucket] = i;
|
||||
}
|
||||
}
|
||||
_buckets = newBuckets;
|
||||
_entries = newEntries;
|
||||
}
|
||||
|
||||
private int NormalizeCapacity(int capacity)
|
||||
{
|
||||
int result = MIN_CAPACITY;
|
||||
while (result < capacity) result <<= 1;
|
||||
return result;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Utils
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||
private struct Entry
|
||||
{
|
||||
public int next; // Index of next entry, -1 if last
|
||||
public int hashKey;
|
||||
public TValue value;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
11
src/Utils/SparseArray.cs.meta
Normal file
11
src/Utils/SparseArray.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7493e8f4d9d69e8478883dfd50d3ccee
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Loading…
Reference in New Issue
Block a user