mirror of
https://github.com/DCFApixels/DragonECS-Unity.git
synced 2026-04-22 04:35:55 +08:00
update
This commit is contained in:
parent
dd41a6f2b8
commit
dc575bd516
@ -1,6 +1,7 @@
|
|||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Runtime.Versioning;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using UnityEditor.ProjectWindowCallback;
|
using UnityEditor.ProjectWindowCallback;
|
||||||
@ -12,9 +13,9 @@ namespace DCFApixels.DragonECS.Editors
|
|||||||
{
|
{
|
||||||
private const int MENU_ITEM_PRIORITY = -198;
|
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 NAMESPACE_TAG = "#NAMESPACE#";
|
||||||
private const string SCRIPTANAME_TAG = "#SCRIPTNAME#";
|
private const string SCRIPTANAME_TAG = "#SCRIPTNAME#";
|
||||||
@ -29,25 +30,25 @@ namespace DCFApixels.DragonECS.Editors
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region GenerateMethods
|
#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");
|
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");
|
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");
|
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");
|
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");
|
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");
|
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");
|
public static void CreateRunnerScript() => CreateScript("RunnerExtended");
|
||||||
|
|
||||||
|
|
||||||
@ -15,7 +15,7 @@ namespace DCFApixels.DragonECS
|
|||||||
string log;
|
string log;
|
||||||
if (!string.IsNullOrEmpty(tag))
|
if (!string.IsNullOrEmpty(tag))
|
||||||
{
|
{
|
||||||
log = $"[{tag}] {v}";
|
log = $".[{tag}] {v}";
|
||||||
string taglower = tag.ToLower();
|
string taglower = tag.ToLower();
|
||||||
if (taglower.Contains("warning"))
|
if (taglower.Contains("warning"))
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,20 +1,40 @@
|
|||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace DCFApixels.DragonECS.Editors
|
namespace DCFApixels.DragonECS.Editors
|
||||||
{
|
{
|
||||||
public static class EcsEditor
|
public static class EcsEditor
|
||||||
{
|
{
|
||||||
|
private static SparseArray<GUIStyle> colorBoxeStyles = new SparseArray<GUIStyle>();
|
||||||
public static GUIStyle GetStyle(Color color, float alphaMultiplier)
|
public static GUIStyle GetStyle(Color color, float alphaMultiplier)
|
||||||
{
|
{
|
||||||
GUIStyle style = new GUIStyle(GUI.skin.box);
|
color.a *= alphaMultiplier;
|
||||||
Color componentColor = color;
|
return GetStyle(color);
|
||||||
componentColor.a *= alphaMultiplier;
|
}
|
||||||
style.normal.background = CreateTexture(2, 2, componentColor);
|
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;
|
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)
|
private static Texture2D CreateTexture(int width, int height, Color color)
|
||||||
{
|
{
|
||||||
var pixels = new Color[width * height];
|
var pixels = new Color[width * height];
|
||||||
@ -26,6 +46,73 @@ namespace DCFApixels.DragonECS.Editors
|
|||||||
result.Apply();
|
result.Apply();
|
||||||
return result;
|
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
|
#endif
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
{
|
{
|
||||||
public sealed class DebugModule : IEcsModule
|
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 EcsWorld[] _worlds;
|
||||||
public DebugModule(params EcsWorld[] worlds)
|
public DebugModule(params EcsWorld[] worlds)
|
||||||
{
|
{
|
||||||
@ -11,11 +11,11 @@
|
|||||||
|
|
||||||
void IEcsModule.ImportSystems(EcsPipeline.Builder b)
|
void IEcsModule.ImportSystems(EcsPipeline.Builder b)
|
||||||
{
|
{
|
||||||
b.InsertSystemsBlock(DEBUG_SYSTEMS_BLOCK, EcsConsts.POST_END_SYSTEMS_BLOCK);
|
b.Layers.Insert(EcsConsts.POST_END_LAYER, DEBUG_LAYER);
|
||||||
b.Add(new PipelineDebugSystem(), DEBUG_SYSTEMS_BLOCK);
|
b.Add(new PipelineDebugSystem(), DEBUG_LAYER);
|
||||||
foreach (var world in _worlds)
|
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 UnityEngine;
|
||||||
using System.Collections.Generic;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
|
|
||||||
namespace DCFApixels.DragonECS.Unity.Debug
|
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 System.Reflection;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
@ -7,7 +6,7 @@ using UnityEngine;
|
|||||||
namespace DCFApixels.DragonECS
|
namespace DCFApixels.DragonECS
|
||||||
{
|
{
|
||||||
[DebugHide, DebugColor(DebugColor.Gray)]
|
[DebugHide, DebugColor(DebugColor.Gray)]
|
||||||
public class PipelineDebugSystem : IEcsPreInitSystem
|
public class PipelineDebugSystem : IEcsPreInitProcess
|
||||||
{
|
{
|
||||||
private string _monitorName;
|
private string _monitorName;
|
||||||
public PipelineDebugSystem(string monitorName = "Pipeline")
|
public PipelineDebugSystem(string monitorName = "Pipeline")
|
||||||
@ -15,13 +14,20 @@ namespace DCFApixels.DragonECS
|
|||||||
_monitorName = monitorName;
|
_monitorName = monitorName;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IEcsPreInitSystem.PreInit(EcsPipeline pipeline)
|
void IEcsPreInitProcess.PreInit(EcsPipeline pipeline)
|
||||||
{
|
{
|
||||||
PipelineDebugMonitor monitor = new GameObject(EcsConsts.DEBUG_PREFIX + _monitorName).AddComponent<PipelineDebugMonitor>();
|
PipelineDebugMonitor monitor = new GameObject(EcsConsts.DEBUG_PREFIX + _monitorName).AddComponent<PipelineDebugMonitor>();
|
||||||
monitor.source = this;
|
monitor.source = this;
|
||||||
monitor.pipeline = pipeline;
|
monitor.pipeline = pipeline;
|
||||||
monitor.monitorName = _monitorName;
|
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
|
//foreach (var item in pipeline.AllSystems) //Вырезано пока не сделаю TODO в SystemDebugMonitor
|
||||||
//{
|
//{
|
||||||
// DebugNameAttribute debugName = item.GetType().GetCustomAttribute<DebugNameAttribute>();
|
// DebugNameAttribute debugName = item.GetType().GetCustomAttribute<DebugNameAttribute>();
|
||||||
@ -37,11 +43,18 @@ namespace DCFApixels.DragonECS
|
|||||||
internal EcsPipeline pipeline;
|
internal EcsPipeline pipeline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class PipelineProcessesDebugMonitor : DebugMonitorBase
|
||||||
|
{
|
||||||
|
internal PipelineDebugSystem source;
|
||||||
|
internal EcsPipeline pipeline;
|
||||||
|
}
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
namespace Editors
|
namespace Editors
|
||||||
{
|
{
|
||||||
using DCFApixels.DragonECS.RunnersCore;
|
using DCFApixels.DragonECS.RunnersCore;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
|
|
||||||
@ -102,7 +115,7 @@ namespace DCFApixels.DragonECS
|
|||||||
|
|
||||||
private void DrawSystem(IEcsSystem system)
|
private void DrawSystem(IEcsSystem system)
|
||||||
{
|
{
|
||||||
if(system is SystemsBlockMarkerSystem markerSystem)
|
if (system is SystemsBlockMarkerSystem markerSystem)
|
||||||
{
|
{
|
||||||
GUILayout.EndVertical();
|
GUILayout.EndVertical();
|
||||||
GUILayout.BeginVertical(EcsEditor.GetStyle(Color.black, 0.2f));
|
GUILayout.BeginVertical(EcsEditor.GetStyle(Color.black, 0.2f));
|
||||||
@ -120,7 +133,7 @@ namespace DCFApixels.DragonECS
|
|||||||
if (CheckIsHidden(type))
|
if (CheckIsHidden(type))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
string name = type.Name;
|
string name = EcsEditor.GetGenericName(type);
|
||||||
Color color = (GetAttribute<DebugColorAttribute>(type) ?? _fakeDebugColorAttribute).GetUnityColor();
|
Color color = (GetAttribute<DebugColorAttribute>(type) ?? _fakeDebugColorAttribute).GetUnityColor();
|
||||||
|
|
||||||
GUILayout.BeginVertical(EcsEditor.GetStyle(color, 0.2f));
|
GUILayout.BeginVertical(EcsEditor.GetStyle(color, 0.2f));
|
||||||
@ -140,7 +153,7 @@ namespace DCFApixels.DragonECS
|
|||||||
|
|
||||||
Color color = (GetAttribute<DebugColorAttribute>(type) ?? _fakeDebugColorAttribute).GetUnityColor();
|
Color color = (GetAttribute<DebugColorAttribute>(type) ?? _fakeDebugColorAttribute).GetUnityColor();
|
||||||
GUILayout.BeginVertical(EcsEditor.GetStyle(color, 0.2f));
|
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.Label(string.Join(", ", runner.Targets.Cast<object>().Select(o => o.GetType().Name)), systemsListStyle);
|
||||||
GUILayout.EndVertical();
|
GUILayout.EndVertical();
|
||||||
}
|
}
|
||||||
@ -161,7 +174,166 @@ namespace DCFApixels.DragonECS
|
|||||||
return target.GetCustomAttribute<DebugHideAttribute>() != null;
|
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
|
#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
|
namespace DCFApixels.DragonECS
|
||||||
{
|
{
|
||||||
[DebugHide, DebugColor(DebugColor.Gray)]
|
[DebugHide, DebugColor(DebugColor.Gray)]
|
||||||
public class WorldDebugSystem : IEcsRunSystem
|
public class WorldDebugSystem : IEcsRunProcess
|
||||||
{
|
{
|
||||||
private string _monitorName;
|
private string _monitorName;
|
||||||
private EcsWorld _ecsWorld;
|
private EcsWorld _ecsWorld;
|
||||||
|
|
||||||
public WorldDebugSystem(EcsWorld ecsWorld, string monitorName = "World")
|
public WorldDebugSystem(EcsWorld ecsWorld, string monitorName = null)
|
||||||
{
|
{
|
||||||
_monitorName = monitorName;
|
_monitorName = monitorName;
|
||||||
|
if (string.IsNullOrEmpty(_monitorName)) _monitorName = ecsWorld.GetType().Name;
|
||||||
_ecsWorld = ecsWorld;
|
_ecsWorld = ecsWorld;
|
||||||
WorldDebugMonitor monitor = new GameObject(EcsConsts.DEBUG_PREFIX + _monitorName).AddComponent<WorldDebugMonitor>();
|
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);
|
poolsmonitor.transform.SetParent(monitor.transform);
|
||||||
|
|
||||||
monitor.source = this;
|
monitor.source = this;
|
||||||
@ -49,8 +50,11 @@ namespace DCFApixels.DragonECS
|
|||||||
{
|
{
|
||||||
private WorldDebugMonitor Target => (WorldDebugMonitor)target;
|
private WorldDebugMonitor Target => (WorldDebugMonitor)target;
|
||||||
|
|
||||||
|
public override void OnInspectorGUI()
|
||||||
|
{
|
||||||
|
GUILayout.Label($"Size: {Target.world.Capacity}");
|
||||||
|
GUILayout.Label($"Total entities: {Target.world.Count}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -83,75 +87,81 @@ namespace DCFApixels.DragonECS
|
|||||||
|
|
||||||
public override void OnInspectorGUI()
|
public override void OnInspectorGUI()
|
||||||
{
|
{
|
||||||
// _scroll = GUILayout.BeginScrollView(_scroll, GUILayout.Height(800f));
|
_scroll = GUILayout.BeginScrollView(_scroll, GUILayout.Height(800f));
|
||||||
// var pools = Target.world.GetAllPools().ToArray().Where(o => !(o is EcsNullPool)).OfType<IEcsPool>();
|
var pools = Target.world.AllPools.ToArray().Where(o => !o.IsNullOrDummy()).OfType<IEcsPool>();
|
||||||
//
|
|
||||||
// GUILayout.Label("", GUILayout.ExpandWidth(true));
|
GUILayout.Label("", GUILayout.ExpandWidth(true));
|
||||||
//
|
|
||||||
// float width = GUILayoutUtility.GetLastRect().width;
|
float width = GUILayoutUtility.GetLastRect().width;
|
||||||
//
|
|
||||||
// Vector3 newPoolBlockSize = _poolBlockMinSize;
|
Vector3 newPoolBlockSize = _poolBlockMinSize;
|
||||||
// int widthCount = Mathf.Max(1, Mathf.Min((Mathf.FloorToInt(width / _poolBlockMinSize.x)), pools.Count()));
|
int widthCount = Mathf.Max(1, Mathf.Min((Mathf.FloorToInt(width / _poolBlockMinSize.x)), pools.Count()));
|
||||||
// newPoolBlockSize.x = width / widthCount;
|
newPoolBlockSize.x = width / widthCount;
|
||||||
//
|
|
||||||
// int x = -1, y = 0;
|
int x = -1, y = 0;
|
||||||
// foreach (var pool in pools)
|
foreach (var pool in pools)
|
||||||
// {
|
{
|
||||||
// if(++x >= widthCount)
|
if(++x >= widthCount)
|
||||||
// {
|
{
|
||||||
// x = 0;
|
x = 0;
|
||||||
// y++;
|
y++;
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// DrawPoolBlock(pool, new Rect(newPoolBlockSize.x * x, newPoolBlockSize.y * y, newPoolBlockSize.x, newPoolBlockSize.y));
|
DrawPoolBlock(pool, new Rect(newPoolBlockSize.x * x, newPoolBlockSize.y * y, newPoolBlockSize.x, newPoolBlockSize.y));
|
||||||
// }
|
}
|
||||||
// GUILayout.EndScrollView();
|
GUILayout.EndScrollView();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// private void DrawPoolBlock(IEcsPool pool, Rect position)
|
private void DrawPoolBlock(IEcsPool pool, Rect position)
|
||||||
// {
|
{
|
||||||
// Color defaultContentColor = GUI.contentColor;
|
int count = pool.Count;
|
||||||
// GUI.contentColor = Color.black * 0.925f;
|
int capacity = pool.Capacity < 0 ? count : pool.Capacity;
|
||||||
//
|
|
||||||
// position = AddMargin(position, 1f, 1f);
|
Color defaultContentColor = GUI.contentColor;
|
||||||
//
|
GUI.contentColor = Color.black * 0.925f;
|
||||||
// EditorGUI.DrawRect(position, Color.black* 0.16f);
|
|
||||||
//
|
position = AddMargin(position, 1f, 1f);
|
||||||
// Rect progressBar = new Rect(Vector2.zero, _poolProgressBasrSize);
|
|
||||||
// progressBar.width = position.width;
|
EditorGUI.DrawRect(position, Color.black* 0.16f);
|
||||||
// progressBar.center = position.center - Vector2.up * _poolBlockMinSize.y * 0.09f;
|
|
||||||
//
|
Rect progressBar = new Rect(Vector2.zero, _poolProgressBasrSize);
|
||||||
//
|
progressBar.width = position.width;
|
||||||
// Color mainColor = new Color(0.3f, 1f, 0f, 1f);
|
progressBar.center = position.center - Vector2.up * _poolBlockMinSize.y * 0.09f;
|
||||||
// var debugColor = pool.ComponentType.GetCustomAttribute<DebugColorAttribute>();
|
|
||||||
// if (debugColor != null)
|
|
||||||
// {
|
Color mainColor = new Color(0.3f, 1f, 0f, 1f);
|
||||||
// mainColor = debugColor.GetUnityColor();
|
var debugColor = pool.ComponentType.GetCustomAttribute<DebugColorAttribute>();
|
||||||
// }
|
if (debugColor != null)
|
||||||
// Color backgroundColor = mainColor * 0.3f + Color.white * 0.2f;
|
{
|
||||||
//
|
mainColor = debugColor.GetUnityColor();
|
||||||
// EditorGUI.DrawRect(progressBar, backgroundColor);
|
}
|
||||||
//
|
Color backgroundColor = mainColor * 0.3f + Color.white * 0.2f;
|
||||||
// progressBar.yMin = progressBar.yMax - ((float)pool.Count / pool.Capacity) * progressBar.height;
|
|
||||||
//
|
EditorGUI.DrawRect(progressBar, backgroundColor);
|
||||||
// GUIStyle textStyle0 = EditorStyles.miniBoldLabel;
|
|
||||||
// textStyle0.alignment = TextAnchor.MiddleCenter;
|
progressBar.yMin = progressBar.yMax - ((float)count / capacity) * progressBar.height;
|
||||||
//
|
|
||||||
// Color foregroundColor = mainColor;
|
GUIStyle textStyle0 = new GUIStyle(EditorStyles.miniBoldLabel);
|
||||||
// EditorGUI.DrawRect(progressBar, foregroundColor);
|
textStyle0.alignment = TextAnchor.MiddleCenter;
|
||||||
// GUI.Label(progressBar, pool.Count.ToString(), textStyle0);
|
|
||||||
//
|
Color foregroundColor = mainColor;
|
||||||
// GUIStyle textStyle1 = EditorStyles.miniBoldLabel;
|
EditorGUI.DrawRect(progressBar, foregroundColor);
|
||||||
// textStyle1.alignment = TextAnchor.UpperCenter;
|
GUI.Label(progressBar, count.ToString(), textStyle0);
|
||||||
// GUI.Label(AddMargin(position, 3f, 3f), "Total\r\n"+ pool.Capacity, textStyle1);
|
|
||||||
//
|
GUIStyle textStyle1 = new GUIStyle(EditorStyles.miniBoldLabel);
|
||||||
// GUI.contentColor = defaultContentColor;
|
textStyle1.alignment = TextAnchor.UpperCenter;
|
||||||
// GUIStyle textStyle2 = EditorStyles.miniBoldLabel;
|
GUI.Label(AddMargin(position, 3f, 3f), "Total\r\n"+ capacity, textStyle1);
|
||||||
// textStyle2.alignment = TextAnchor.LowerCenter;
|
|
||||||
// GUI.Label(AddMargin(position, -10f, 3f), pool.ComponentType.Name, textStyle2);
|
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)
|
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
|
fileFormatVersion: 2
|
||||||
guid: bf4cdc68b5b89a14c81a53b600078536
|
guid: b33e303fef8298b4db42987fe9b94e45
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 70c8e3cb9125ee14fad9fdee48c3e8ba
|
guid: 11dc6a014c6c7e84ab61979e25010c57
|
||||||
folderAsset: yes
|
folderAsset: yes
|
||||||
DefaultImporter:
|
DefaultImporter:
|
||||||
externalObjects: {}
|
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
|
namespace DCFApixels.DragonECS
|
||||||
{
|
{
|
||||||
public interface IEcsLateRunSystem : IEcsSystem
|
public interface IEcsLateRunProcess : IEcsSystem
|
||||||
{
|
{
|
||||||
public void LateRun(EcsPipeline pipeline);
|
public void LateRun(EcsPipeline pipeline);
|
||||||
}
|
}
|
||||||
@ -10,10 +10,10 @@ namespace DCFApixels.DragonECS
|
|||||||
{
|
{
|
||||||
public static void LateRun(this EcsPipeline systems)
|
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);
|
public void FixedRun(EcsPipeline pipeline);
|
||||||
}
|
}
|
||||||
@ -21,14 +21,14 @@ namespace DCFApixels.DragonECS
|
|||||||
{
|
{
|
||||||
public static void FixedRun(this EcsPipeline pipeline)
|
public static void FixedRun(this EcsPipeline pipeline)
|
||||||
{
|
{
|
||||||
pipeline.GetRunner<IEcsFixedRunSystem>().FixedRun(pipeline);
|
pipeline.GetRunner<IEcsFixedRunProcess>().FixedRun(pipeline);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Internal
|
namespace Internal
|
||||||
{
|
{
|
||||||
[DebugColor(DebugColor.Orange)]
|
[DebugColor(DebugColor.Orange)]
|
||||||
public class EcsLateRunSystemRunner : EcsRunner<IEcsLateRunSystem>, IEcsLateRunSystem
|
public class EcsLateRunSystemRunner : EcsRunner<IEcsLateRunProcess>, IEcsLateRunProcess
|
||||||
{
|
{
|
||||||
#if DEBUG && !DISABLE_DEBUG
|
#if DEBUG && !DISABLE_DEBUG
|
||||||
private EcsProfilerMarker[] _markers;
|
private EcsProfilerMarker[] _markers;
|
||||||
@ -58,7 +58,7 @@ namespace DCFApixels.DragonECS
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
[DebugColor(DebugColor.Orange)]
|
[DebugColor(DebugColor.Orange)]
|
||||||
public class EcsFixedRunSystemRunner : EcsRunner<IEcsFixedRunSystem>, IEcsFixedRunSystem
|
public class EcsFixedRunSystemRunner : EcsRunner<IEcsFixedRunProcess>, IEcsFixedRunProcess
|
||||||
{
|
{
|
||||||
#if DEBUG && !DISABLE_DEBUG
|
#if DEBUG && !DISABLE_DEBUG
|
||||||
private EcsProfilerMarker[] _markers;
|
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 System.Runtime.CompilerServices;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using System.Linq;
|
|
||||||
using UnityEditor.ShortcutManagement;
|
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
#endif
|
#endif
|
||||||
@ -62,11 +60,11 @@ namespace DCFApixels.DragonECS
|
|||||||
|
|
||||||
public static class GameObjectRefExt
|
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);
|
GameObject newGameObject = new GameObject(name);
|
||||||
newGameObject.AddComponent<EcsEntityConnect>().ConectWith(result);
|
newGameObject.AddComponent<EcsEntityConnect>().ConnectWith(result);
|
||||||
// self.GetPool<UnityGameObject>().Add(result.id) =
|
// self.GetPool<UnityGameObject>().Add(result.id) =
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
if (icon != GameObjectIcon.NONE)
|
if (icon != GameObjectIcon.NONE)
|
||||||
@ -90,76 +88,4 @@ namespace DCFApixels.DragonECS
|
|||||||
return result;
|
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