add runtime editing

This commit is contained in:
Mikhail 2024-03-07 21:22:48 +08:00
parent a356d31937
commit cb4ef1c853
4 changed files with 169 additions and 27 deletions

View File

@ -24,25 +24,45 @@ namespace DCFApixels.DragonECS
[Header("Default Configs")]
[Header("Entites")]
[SerializeField]
private int EntitiesCapacity = EcsWorldConfig.Default.EntitiesCapacity;
private int _entitiesCapacity = EcsWorldConfig.Default.EntitiesCapacity;
[Header("Groups")]
[SerializeField]
private int GroupCapacity = EcsWorldConfig.Default.GroupCapacity;
private int _groupCapacity = EcsWorldConfig.Default.GroupCapacity;
[Header("Pools/Components")]
[SerializeField]
private int PoolsCapacity = EcsWorldConfig.Default.PoolsCapacity;
private int _poolsCapacity = EcsWorldConfig.Default.PoolsCapacity;
[SerializeField]
private int PoolComponentsCapacity = EcsWorldConfig.Default.PoolComponentsCapacity;
private int _poolComponentsCapacity = EcsWorldConfig.Default.PoolComponentsCapacity;
[SerializeField]
private int PoolRecycledComponentsCapacity = EcsWorldConfig.Default.PoolRecycledComponentsCapacity;
private int _poolRecycledComponentsCapacity = EcsWorldConfig.Default.PoolRecycledComponentsCapacity;
#region Properties
public sealed override bool IsEmpty
{
get { return _world == null; }
}
public int EntitiesCapacity
{
get { return _entitiesCapacity; }
}
public int GroupCapacity
{
get { return _groupCapacity; }
}
public int PoolsCapacity
{
get { return _poolsCapacity; }
}
public int PoolComponentsCapacity
{
get { return _poolComponentsCapacity; }
}
public int PoolRecycledComponentsCapacity
{
get { return _poolRecycledComponentsCapacity; }
}
#endregion
#region Methods
@ -94,7 +114,7 @@ namespace DCFApixels.DragonECS
#region Events
protected virtual TWorld BuildWorld()
{
EcsWorldConfig config = new EcsWorldConfig(EntitiesCapacity, GroupCapacity, PoolsCapacity, PoolComponentsCapacity, PoolRecycledComponentsCapacity);
EcsWorldConfig config = new EcsWorldConfig(_entitiesCapacity, _groupCapacity, _poolsCapacity, _poolComponentsCapacity, _poolRecycledComponentsCapacity);
ConfigContainer configs = new ConfigContainer().Set(config);
return (TWorld)Activator.CreateInstance(typeof(TWorld), new object[] { configs, _worldID });
}

View File

@ -12,32 +12,32 @@ namespace DCFApixels.DragonECS.Unity.Editors
private static readonly Rect RemoveButtonRect = new Rect(0f, 0f, 17f, 19f);
private static readonly Rect TooltipIconRect = new Rect(0f, 0f, 21f, 15f);
private GUIStyle removeButtonStyle;
private GenericMenu genericMenu;
private GUIStyle _removeButtonStyle;
private GenericMenu _genericMenu;
private bool _isInit = false;
#region Init
private void Init()
{
if (genericMenu == null) { _isInit = false; }
if (_genericMenu == null) { _isInit = false; }
if (_isInit) { return; }
var tmpstylebase = UnityEditorUtility.GetStyle(new Color(0.9f, 0f, 0.22f), 0.5f);
var tmpStyle = UnityEditorUtility.GetStyle(new Color(1f, 0.5f, 0.7f), 0.5f);
removeButtonStyle = new GUIStyle(EditorStyles.linkLabel);
removeButtonStyle.alignment = TextAnchor.MiddleCenter;
_removeButtonStyle = 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.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);
_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();
_genericMenu = new GenericMenu();
var componentTemplateDummies = ComponentTemplateTypeCache.Dummies;
foreach (var dummy in componentTemplateDummies)
@ -56,7 +56,7 @@ namespace DCFApixels.DragonECS.Unity.Editors
{
name = $"{name} {EcsUnityConsts.INFO_MARK}";
}
genericMenu.AddItem(new GUIContent(name, description), false, OnAddComponent, dummy);
_genericMenu.AddItem(new GUIContent(name, description), false, OnAddComponent, dummy);
}
_isInit = true;
@ -122,7 +122,7 @@ namespace DCFApixels.DragonECS.Unity.Editors
if (GUILayout.Button("Add Component", GUILayout.Height(24f)))
{
Init();
genericMenu.ShowAsContext();
_genericMenu.ShowAsContext();
}
}
private void DrawFooter(ITemplateInternal target)
@ -167,8 +167,6 @@ namespace DCFApixels.DragonECS.Unity.Editors
string description = meta.Description;
Color panelColor = meta.Color.ToUnityColor().Desaturate(EscEditorConsts.COMPONENT_DRAWER_DESATURATE);
Rect removeButtonRect = GUILayoutUtility.GetLastRect();
//GUIContent label = new GUIContent(name);
GUIContent label = UnityEditorUtility.GetLabel(name);
bool isEmpty = componentType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).Length <= 0;
@ -176,6 +174,8 @@ namespace DCFApixels.DragonECS.Unity.Editors
Color alphaPanelColor = panelColor;
alphaPanelColor.a = EscEditorConsts.COMPONENT_DRAWER_ALPHA;
Rect removeButtonRect = GUILayoutUtility.GetLastRect();
EditorGUI.BeginChangeCheck();
GUILayout.BeginVertical(UnityEditorUtility.GetStyle(alphaPanelColor));
@ -231,7 +231,7 @@ namespace DCFApixels.DragonECS.Unity.Editors
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))
if (GUI.Button(removeButtonRect, "x", _removeButtonStyle))
{
OnRemoveComponentAt(index);
}

View File

@ -13,6 +13,8 @@ namespace DCFApixels.DragonECS.Unity.Editors
internal readonly static Color GreenColor = new Color32(75, 255, 0, 255);
internal readonly static Color RedColor = new Color32(255, 0, 75, 255);
private static readonly Rect RemoveButtonRect = new Rect(0f, 0f, 17f, 19f);
private static readonly Rect TooltipIconRect = new Rect(0f, 0f, 21f, 15f);
//private static GUILayoutOption[] _defaultParams;
//private static bool _isInit = false;
//private static void Init()
@ -68,6 +70,13 @@ namespace DCFApixels.DragonECS.Unity.Editors
}
}
GUILayout.EndVertical();
if (GUILayout.Button("Add Component", GUILayout.Height(24f)))
{
GenericMenu genericMenu = RuntimeComponentsUtility.GetAddComponentGenericMenu(world);
RuntimeComponentsUtility.CurrentEntityID = entityID;
genericMenu.ShowAsContext();
}
}
private static readonly BindingFlags fieldFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
private static void DrawRuntimeComponent(int entityID, IEcsPool pool)
@ -77,16 +86,37 @@ namespace DCFApixels.DragonECS.Unity.Editors
{
object data = pool.GetRaw(entityID);
Color panelColor = meta.Color.ToUnityColor().Desaturate(EscEditorConsts.COMPONENT_DRAWER_DESATURATE);
float padding = EditorGUIUtility.standardVerticalSpacing;
Rect removeButtonRect = GUILayoutUtility.GetLastRect();
GUILayout.BeginVertical(UnityEditorUtility.GetStyle(panelColor, EscEditorConsts.COMPONENT_DRAWER_ALPHA));
EditorGUI.BeginChangeCheck();
bool isRemoveComponent = false;
removeButtonRect.yMin = removeButtonRect.yMax;
removeButtonRect.yMax += RemoveButtonRect.height;
removeButtonRect.xMin = removeButtonRect.xMax - RemoveButtonRect.width;
removeButtonRect.center += Vector2.up * padding * 2f;
if (GUI.Button(removeButtonRect, "x"))
{
isRemoveComponent = true;
}
Type componentType = pool.ComponentType;
ExpandMatrix expandMatrix = ExpandMatrix.Take(componentType);
bool changed = DrawRuntimeData(componentType, UnityEditorUtility.GetLabel(meta.Name), expandMatrix, data, out object resultData);
if (changed)
if (changed || isRemoveComponent)
{
if (isRemoveComponent)
{
pool.Del(entityID);
}
else
{
pool.SetRaw(entityID, resultData);
}
}
GUILayout.EndVertical();
}

View File

@ -1,5 +1,7 @@
#if UNITY_EDITOR
using DCFApixels.DragonECS.Unity.Internal;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using UnityEditor;
@ -156,5 +158,95 @@ namespace DCFApixels.DragonECS.Unity.Editors
}
#endregion
}
internal static class RuntimeComponentsUtility
{
public struct WorldData
{
public GenericMenu addComponentGenericMenu;
public int poolsCount;
public WorldData(GenericMenu addComponentGenericMenu, int poolsCount)
{
this.addComponentGenericMenu = addComponentGenericMenu;
this.poolsCount = poolsCount;
}
}
//world id
private static Dictionary<EcsWorld, WorldData> _worldDatas = new Dictionary<EcsWorld, WorldData>();
public static GenericMenu GetAddComponentGenericMenu(EcsWorld world)
{
if (_worldDatas.TryGetValue(world, out WorldData data))
{
if (data.poolsCount != world.PoolsCount)
{
data = CreateWorldData(world);
_worldDatas[world] = data;
}
}
else
{
data = CreateWorldData(world);
_worldDatas[world] = data;
world.AddListener(new Listener(world));
}
return data.addComponentGenericMenu;
}
private static WorldData CreateWorldData(EcsWorld world)
{
GenericMenu genericMenu = new GenericMenu();
var pools = world.AllPools;
for (int i = 0; i < world.PoolsCount; i++)
{
var pool = pools[i];
if (pool.IsNullOrDummy())
{
i--;
continue;
}
var meta = pool.ComponentType.ToMeta();
genericMenu.AddItem(new GUIContent(meta.Name, meta.Description), false, OnAddComponent, pool);
}
return new WorldData(genericMenu, world.PoolsCount);
}
public static int CurrentEntityID = 0;
private static void OnAddComponent(object userData)
{
IEcsPool pool = (IEcsPool)userData;
if (pool.World.IsUsed(CurrentEntityID) == false)
{
return;
}
if (pool.Has(CurrentEntityID) == false)
{
pool.AddRaw(CurrentEntityID, Activator.CreateInstance(pool.ComponentType));
}
else
{
Debug.LogWarning($"Entity({CurrentEntityID}) already has component {EcsDebugUtility.GetGenericTypeName(pool.ComponentType)}.");
}
}
private class Listener : IEcsWorldEventListener
{
private EcsWorld _world;
public Listener(EcsWorld world)
{
_world = world;
}
public void OnReleaseDelEntityBuffer(ReadOnlySpan<int> buffer) { }
public void OnWorldDestroy()
{
_worldDatas.Remove(_world);
}
public void OnWorldResize(int newSize) { }
}
}
}
#endif