update templates

This commit is contained in:
Mikhail 2024-10-18 17:22:02 +08:00
parent 7569a6fec5
commit 461c626ed3
21 changed files with 334 additions and 97 deletions

View File

@ -0,0 +1,63 @@
using UnityEngine;
namespace DCFApixels.DragonECS
{
public class DragonEcsRootUnity : MonoBehaviour
{
[SerializeReference]
[ReferenceButton(false, typeof(IEcsModule))]
//[ArrayElement]
private IEcsModule _module = new MonoBehaviourSystemWrapper();
[SerializeField]
private AddParams _parameters;
private EcsPipeline _pipeline;
public IEcsModule Module
{
get { return _module; }
}
public AddParams AddParams
{
get { return _parameters; }
}
public EcsPipeline Pipeline
{
get { return _pipeline; }
}
public bool IsInit
{
get { return _pipeline != null && _pipeline.IsInit; }
}
private void Start()
{
_pipeline = EcsPipeline.New().AddModule(_module, _parameters).BuildAndInit();
}
private void Update()
{
_pipeline.Run();
}
private void LateUpdate()
{
_pipeline.LateRun();
}
private void FixedUpdate()
{
_pipeline.FixedRun();
}
private void OnDrawGizmos()
{
_pipeline?.DrawGizmos();
}
private void OnDestroy()
{
_pipeline.Destroy();
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 05638ccfe0703e549a32dd534f99de3b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -101,9 +101,9 @@ namespace DCFApixels.DragonECS
{ {
get { return _monoTemplates; } get { return _monoTemplates; }
} }
public IEnumerable<ITemplate> AllTemplates public IEnumerable<IEntityTemplate> AllTemplates
{ {
get { return ((IEnumerable<ITemplate>)_scriptableTemplates).Concat(_monoTemplates); } get { return ((IEnumerable<IEntityTemplate>)_scriptableTemplates).Concat(_monoTemplates); }
} }
#endregion #endregion

View File

@ -2,7 +2,7 @@
{ {
public class EcsUnityConsts public class EcsUnityConsts
{ {
public const string PACK_GROUP = "_" + EcsConsts.FRAMEWORK_NAME + "/Unity"; public const string PACK_GROUP = "_" + EcsConsts.FRAMEWORK_NAME + "/_Unity";
public const string ENTITY_BUILDING_GROUP = "Entity Building"; public const string ENTITY_BUILDING_GROUP = "Entity Building";
public const string PIPELINE_BUILDING_GROUP = "Pipeline Building"; public const string PIPELINE_BUILDING_GROUP = "Pipeline Building";
@ -12,8 +12,6 @@
public const string LOCAL_CACHE_FOLDER = "/Library/" + EcsConsts.AUTHOR + "/" + UNITY_PACKAGE_NAME; public const string LOCAL_CACHE_FOLDER = "/Library/" + EcsConsts.AUTHOR + "/" + UNITY_PACKAGE_NAME;
public const string USER_SETTINGS_FOLDER = "/UserSettings/" + EcsConsts.AUTHOR + "/" + UNITY_PACKAGE_NAME; public const string USER_SETTINGS_FOLDER = "/UserSettings/" + EcsConsts.AUTHOR + "/" + UNITY_PACKAGE_NAME;
//EcsConsts.AUTHOR + "/" + EcsConsts.FRAMEWORK_NAME + "/" + nameof(DragonDocsPrefs) + ".prefs"
} }
public class EcsUnityDefines public class EcsUnityDefines

View File

@ -1,14 +1,15 @@
#if UNITY_EDITOR #if UNITY_EDITOR
using DCFApixels.DragonECS.Unity.Internal; using DCFApixels.DragonECS.Unity.Internal;
using System; using System;
using System.Collections.Generic;
using UnityEditor; using UnityEditor;
using UnityEditorInternal; using UnityEditorInternal;
using UnityEngine; using UnityEngine;
namespace DCFApixels.DragonECS.Unity.Editors namespace DCFApixels.DragonECS.Unity.Editors
{ {
[CustomPropertyDrawer(typeof(EcsPipelineTemplateSO.Record))] [CustomPropertyDrawer(typeof(PipelineTemplateUtility.Record))]
internal class EcsPipelineTemplateSORecordDrawer : ExtendedPropertyDrawer internal class PipelineTemplateUtilityRecordDrawer : ExtendedPropertyDrawer
{ {
protected override void DrawCustom(Rect position, SerializedProperty property, GUIContent label) protected override void DrawCustom(Rect position, SerializedProperty property, GUIContent label)
{ {
@ -64,8 +65,8 @@ namespace DCFApixels.DragonECS.Unity.Editors
return result; return result;
} }
} }
[CustomEditor(typeof(EcsPipelineTemplateSO))] [CustomEditor(typeof(ScriptablePipelineTemplate))]
internal class EcsPipelineTemplateSOEditor : ExtendedEditor<EcsPipelineTemplateSO> internal class PipelineTemplateEditorBase : ExtendedEditor<IPipelineTemplate>
{ {
private SerializedProperty _layersProp; private SerializedProperty _layersProp;
private SerializedProperty _recordsProp; private SerializedProperty _recordsProp;
@ -136,12 +137,17 @@ namespace DCFApixels.DragonECS.Unity.Editors
#endregion #endregion
#region _reorderableLayersList #region _reorderableLayersList
private static readonly HashSet<string> _defaultLayersSet = new HashSet<string>(PipelineTemplateUtility.DefaultLayers);
private void OnReorderableLayersListDrawElement(Rect rect, int index, bool isActive, bool isFocused) private void OnReorderableLayersListDrawElement(Rect rect, int index, bool isActive, bool isFocused)
{ {
using (EcsGUI.CheckChanged()) using (EcsGUI.CheckChanged())
{ {
var elementProp = _layersProp.GetArrayElementAtIndex(index); var elementProp = _layersProp.GetArrayElementAtIndex(index);
elementProp.stringValue = EditorGUI.TextField(rect, elementProp.stringValue); string str = elementProp.stringValue;
using (EcsGUI.SetEnable(_defaultLayersSet.Contains(str) == false))
{
elementProp.stringValue = EditorGUI.TextField(rect, str);
}
} }
} }
private void OnReorderableLayersListAdd(ReorderableList list) private void OnReorderableLayersListAdd(ReorderableList list)
@ -162,7 +168,7 @@ namespace DCFApixels.DragonECS.Unity.Editors
using (EcsGUI.CheckChanged()) using (EcsGUI.CheckChanged())
{ {
SerializedProperty prop = _recordsProp.GetArrayElementAtIndex(index); SerializedProperty prop = _recordsProp.GetArrayElementAtIndex(index);
var targetProp = prop.FindPropertyRelative(nameof(EcsPipelineTemplateSO.Record.target)); var targetProp = prop.FindPropertyRelative(nameof(PipelineTemplateUtility.Record.target));
bool isNull = targetProp.managedReferenceValue == null; bool isNull = targetProp.managedReferenceValue == null;
ITypeMeta meta = isNull ? null : targetProp.managedReferenceValue.GetMeta(); ITypeMeta meta = isNull ? null : targetProp.managedReferenceValue.GetMeta();
@ -210,7 +216,7 @@ namespace DCFApixels.DragonECS.Unity.Editors
foreach (var target in Targets) foreach (var target in Targets)
{ {
target.Validate(); target.Validate();
EditorUtility.SetDirty(target); EditorUtility.SetDirty((UnityEngine.Object)target);
} }
serializedObject.Update(); serializedObject.Update();
} }
@ -245,5 +251,10 @@ namespace DCFApixels.DragonECS.Unity.Editors
} }
} }
} }
[CustomEditor(typeof(ScriptablePipelineTemplate), true)]
internal class ScriptablePipelineTemplateEditor : PipelineTemplateEditorBase { }
[CustomEditor(typeof(MonoPipelineTemplate), true)]
internal class MonoPipelineTemplateEditor : PipelineTemplateEditorBase { }
} }
#endif #endif

View File

@ -0,0 +1,19 @@
using DCFApixels.DragonECS.Unity;
using UnityEngine;
namespace DCFApixels.DragonECS
{
[MetaName("MonoBehaviourSystem")]
[MetaColor(MetaColor.DragonCyan)]
[MetaDescription("Wrapper for MonoBehaviour systems")]
[MetaID("2877029E9201347B4F58E1EC0A4BCD1B")]
[MetaGroup(EcsUnityConsts.PACK_GROUP, EcsConsts.OTHER_GROUP)]
public class MonoBehaviourSystemWrapper : IEcsModule
{
public MonoBehaviour system;
public void Import(EcsPipeline.Builder b)
{
b.Add(system);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 337c4dc120ce81c49958fcbcb95e0fe7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -3,13 +3,19 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using UnityEngine; using UnityEngine;
using static DCFApixels.DragonECS.Unity.PipelineTemplateUtility;
namespace DCFApixels.DragonECS namespace DCFApixels.DragonECS.Unity
{ {
[CreateAssetMenu(fileName = nameof(EcsPipelineTemplateSO), menuName = EcsConsts.FRAMEWORK_NAME + "/" + nameof(EcsPipelineTemplateSO), order = 1)] public interface IPipelineTemplate
public class EcsPipelineTemplateSO : ScriptableObject, IEcsModule
{ {
private static string[] _defaultLayers = new string[] ReadOnlySpan<string> Layers { get; }
ReadOnlySpan<Record> Records { get; }
bool Validate();
}
public static class PipelineTemplateUtility
{
internal static readonly string[] DefaultLayers = new string[]
{ {
EcsConsts.PRE_BEGIN_LAYER, EcsConsts.PRE_BEGIN_LAYER,
EcsConsts.BEGIN_LAYER, EcsConsts.BEGIN_LAYER,
@ -18,76 +24,16 @@ namespace DCFApixels.DragonECS
EcsConsts.POST_END_LAYER, EcsConsts.POST_END_LAYER,
}; };
[SerializeField] internal static bool ValidateLayers(ref string[] layers)
[ArrayElement]
private string[] _layers = _defaultLayers.ToArray();
[SerializeField]
[ArrayElement]
private Record[] _records;
public ReadOnlySpan<string> Layers
{
get { return _layers; }
}
public ReadOnlySpan<Record> Records
{
get { return _records; }
}
void IEcsModule.Import(EcsPipeline.Builder b)
{
b.Layers.MergeWith(_layers);
foreach (var s in _records)
{
if (s.target == null) { continue; }
b.Add(s.target, s.parameters);
}
}
public EcsPipelineTemplate GenerateSerializableTemplate()
{
EcsPipelineTemplate result = new EcsPipelineTemplate();
result.layers = new string[_layers.Length];
Array.Copy(_layers, result.layers, _layers.Length);
result.records = new EcsPipelineTemplate.Record[_records.Length];
for (int i = 0; i < result.records.Length; i++)
{
ref var s = ref _records[i];
result.records[i] = new EcsPipelineTemplate.Record(s.target, s.parameters);
}
return result;
}
public void SetFromSerializableTemplate(EcsPipelineTemplate template)
{
_layers = new string[template.layers.Length];
Array.Copy(template.layers, _layers, template.layers.Length);
_records = new Record[template.records.Length];
for (int i = 0; i < _records.Length; i++)
{
ref var s = ref template.records[i];
_records[i] = new Record(s.target, s.parameters);
}
}
public bool Validate()
{
bool resutl = ValidateLayers();
resutl |= ValidateSystems();
return resutl;
}
private bool ValidateLayers()
{ {
bool result = false; bool result = false;
Dictionary<string, int> builtinLayerIndexes = new Dictionary<string, int>(); Dictionary<string, int> builtinLayerIndexes = new Dictionary<string, int>();
foreach (var item in _defaultLayers) foreach (var item in DefaultLayers)
{ {
builtinLayerIndexes.Add(item, -1); builtinLayerIndexes.Add(item, -1);
} }
List<string> newLayers = _layers.Distinct().ToList(); List<string> newLayers = layers.Distinct().ToList();
for (int i = 0; i < newLayers.Count; i++) for (int i = 0; i < newLayers.Count; i++)
{ {
@ -115,23 +61,40 @@ namespace DCFApixels.DragonECS
int i = 0; int i = 0;
foreach (var pair in builtinLayerIndexes.OrderBy(o => o.Value)) foreach (var pair in builtinLayerIndexes.OrderBy(o => o.Value))
{ {
if (newLayers[pair.Value] != _defaultLayers[i]) if (newLayers[pair.Value] != DefaultLayers[i])
{ {
newLayers[pair.Value] = _defaultLayers[i]; newLayers[pair.Value] = DefaultLayers[i];
result = true; result = true;
} }
i++; i++;
} }
} }
_layers = newLayers.ToArray(); layers = newLayers.ToArray();
return result; return result;
} }
private bool ValidateSystems() internal static bool ValidateRecords(ref Record[] records)
{ {
return false; return false;
} }
public static EcsPipelineTemplate GenerateSerializableTemplate(this IPipelineTemplate self)
{
EcsPipelineTemplate result = new EcsPipelineTemplate();
result.layers = new string[self.Layers.Length];
for (int i = 0; i < self.Layers.Length; i++)
{
result.layers[i] = self.Layers[i];
}
result.records = new EcsPipelineTemplate.Record[self.Records.Length];
for (int i = 0; i < result.records.Length; i++)
{
var s = self.Records[i];
result.records[i] = new EcsPipelineTemplate.Record(s.target, s.parameters);
}
return result;
}
[Serializable] [Serializable]
public struct Record public struct Record
{ {

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 609f05a5f299be04db094296f731818a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f401f14661cf04b43a59144cf202a624
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,66 @@
using DCFApixels.DragonECS.Unity;
using DCFApixels.DragonECS.Unity.Internal;
using System;
using System.Linq;
using UnityEngine;
namespace DCFApixels.DragonECS
{
using static PipelineTemplateUtility;
public abstract class MonoPipelineTemplateBase : MonoBehaviour, IEcsModule
{
public abstract void Import(EcsPipeline.Builder b);
}
[DisallowMultipleComponent]
[AddComponentMenu(EcsConsts.FRAMEWORK_NAME + "/" + nameof(MonoPipelineTemplate), 30)]
public class MonoPipelineTemplate : MonoPipelineTemplateBase, IPipelineTemplate
{
[SerializeField]
[ArrayElement]
private string[] _layers = DefaultLayers.ToArray();
[SerializeField]
[ArrayElement]
private Record[] _records;
public ReadOnlySpan<string> Layers
{
get { return _layers; }
}
public ReadOnlySpan<Record> Records
{
get { return _records; }
}
public sealed override void Import(EcsPipeline.Builder b)
{
b.Layers.MergeWith(_layers);
foreach (var s in _records)
{
if (s.target == null) { continue; }
b.Add(s.target, s.parameters);
}
}
public void SetFromSerializableTemplate(EcsPipelineTemplate template)
{
_layers = new string[template.layers.Length];
Array.Copy(template.layers, _layers, template.layers.Length);
_records = new Record[template.records.Length];
for (int i = 0; i < _records.Length; i++)
{
ref var s = ref template.records[i];
_records[i] = new Record(s.target, s.parameters);
}
}
public bool Validate()
{
bool resutl = ValidateLayers(ref _layers);
resutl |= ValidateRecords(ref _records);
return resutl;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 72e04fe7bbcd12d419deca183aa10bb4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,65 @@
using DCFApixels.DragonECS.Unity;
using DCFApixels.DragonECS.Unity.Internal;
using System;
using System.Linq;
using UnityEngine;
namespace DCFApixels.DragonECS
{
using static PipelineTemplateUtility;
public abstract class ScriptablePipelineTemplateBase : ScriptableObject, IEcsModule
{
public abstract void Import(EcsPipeline.Builder b);
}
[CreateAssetMenu(fileName = nameof(ScriptablePipelineTemplate), menuName = EcsConsts.FRAMEWORK_NAME + "/" + nameof(ScriptablePipelineTemplate), order = 1)]
public sealed class ScriptablePipelineTemplate : ScriptablePipelineTemplateBase, IPipelineTemplate
{
[SerializeField]
[ArrayElement]
private string[] _layers = DefaultLayers.ToArray();
[SerializeField]
[ArrayElement]
private Record[] _records;
public ReadOnlySpan<string> Layers
{
get { return _layers; }
}
public ReadOnlySpan<Record> Records
{
get { return _records; }
}
public sealed override void Import(EcsPipeline.Builder b)
{
b.Layers.MergeWith(_layers);
foreach (var s in _records)
{
if (s.target == null) { continue; }
b.Add(s.target, s.parameters);
}
}
public void SetFromSerializableTemplate(EcsPipelineTemplate template)
{
_layers = new string[template.layers.Length];
Array.Copy(template.layers, _layers, template.layers.Length);
_records = new Record[template.records.Length];
for (int i = 0; i < _records.Length; i++)
{
ref var s = ref template.records[i];
_records[i] = new Record(s.target, s.parameters);
}
}
public bool Validate()
{
bool resutl = ValidateLayers(ref _layers);
resutl |= ValidateRecords(ref _records);
return resutl;
}
}
}

View File

@ -7,7 +7,7 @@ using UnityEngine;
namespace DCFApixels.DragonECS.Unity.Editors namespace DCFApixels.DragonECS.Unity.Editors
{ {
internal abstract class EntityTemplateEditorBase<T> : ExtendedEditor<ITemplateInternal> internal abstract class EntityTemplateEditorBase : ExtendedEditor<IEntityTemplateInternal>
{ {
private static readonly Rect HeadIconsRect = new Rect(0f, 0f, 19f, 19f); private static readonly Rect HeadIconsRect = new Rect(0f, 0f, 19f, 19f);
@ -140,7 +140,7 @@ namespace DCFApixels.DragonECS.Unity.Editors
#region Add/Remove #region Add/Remove
private void OnRemoveComponentAt(int index) private void OnRemoveComponentAt(int index)
{ {
if (this.target is ITemplateInternal target) if (this.target is IEntityTemplateInternal target)
{ {
SerializedProperty componentsProp = serializedObject.FindProperty(target.ComponentsPropertyName); SerializedProperty componentsProp = serializedObject.FindProperty(target.ComponentsPropertyName);
componentsProp.DeleteArrayElementAtIndex(index); componentsProp.DeleteArrayElementAtIndex(index);
@ -181,7 +181,7 @@ namespace DCFApixels.DragonECS.Unity.Editors
_reorderableComponentsList.DoLayoutList(); _reorderableComponentsList.DoLayoutList();
} }
} }
private void DrawTop(ITemplateInternal target, SerializedProperty componentsProp) private void DrawTop(IEntityTemplateInternal target, SerializedProperty componentsProp)
{ {
GUILayout.Space(2f); GUILayout.Space(2f);
@ -201,8 +201,8 @@ namespace DCFApixels.DragonECS.Unity.Editors
} }
[CustomEditor(typeof(ScriptableEntityTemplate), true)] [CustomEditor(typeof(ScriptableEntityTemplate), true)]
internal class EntityTemplatePresetEditor : EntityTemplateEditorBase<ScriptableEntityTemplate> { } internal class ScriptableEntityTemplateEditor : EntityTemplateEditorBase { }
[CustomEditor(typeof(MonoEntityTemplate), true)] [CustomEditor(typeof(MonoEntityTemplate), true)]
internal class EntityTemplateEditor : EntityTemplateEditorBase<MonoEntityTemplate> { } internal class MonoEntityTemplateEditor : EntityTemplateEditorBase { }
} }
#endif #endif

View File

@ -1,6 +1,6 @@
namespace DCFApixels.DragonECS namespace DCFApixels.DragonECS
{ {
public interface ITemplate : ITemplateNode { } public interface IEntityTemplate : ITemplateNode { }
public static class ITemplateNodeExtensions public static class ITemplateNodeExtensions
{ {
@ -15,7 +15,7 @@
namespace DCFApixels.DragonECS.Unity.Internal namespace DCFApixels.DragonECS.Unity.Internal
{ {
internal interface ITemplateInternal : ITemplate internal interface IEntityTemplateInternal : IEntityTemplate
{ {
string ComponentsPropertyName { get; } string ComponentsPropertyName { get; }
} }

View File

@ -5,7 +5,7 @@ using UnityEngine;
namespace DCFApixels.DragonECS namespace DCFApixels.DragonECS
{ {
public abstract class MonoEntityTemplateBase : MonoBehaviour, ITemplate public abstract class MonoEntityTemplateBase : MonoBehaviour, IEntityTemplate
{ {
public abstract void Apply(short worldID, int entityID); public abstract void Apply(short worldID, int entityID);
} }
@ -16,14 +16,14 @@ namespace DCFApixels.DragonECS
[MetaGroup(EcsUnityConsts.PACK_GROUP, EcsUnityConsts.ENTITY_BUILDING_GROUP)] [MetaGroup(EcsUnityConsts.PACK_GROUP, EcsUnityConsts.ENTITY_BUILDING_GROUP)]
[MetaDescription(EcsConsts.AUTHOR, nameof(MonoBehaviour) + " implementation of an entity template. Templates are a set of components that are applied to entities.")] [MetaDescription(EcsConsts.AUTHOR, nameof(MonoBehaviour) + " implementation of an entity template. Templates are a set of components that are applied to entities.")]
[MetaID("C734BA8092014833C14F21E05D7B1551")] [MetaID("C734BA8092014833C14F21E05D7B1551")]
public class MonoEntityTemplate : MonoEntityTemplateBase, ITemplateInternal public class MonoEntityTemplate : MonoEntityTemplateBase, IEntityTemplateInternal
{ {
[SerializeReference] [SerializeReference]
[ReferenceButton(true, typeof(IComponentTemplate))] [ReferenceButton(true, typeof(IComponentTemplate))]
private IComponentTemplate[] _components; private IComponentTemplate[] _components;
#region Properties #region Properties
string ITemplateInternal.ComponentsPropertyName string IEntityTemplateInternal.ComponentsPropertyName
{ {
get { return nameof(_components); } get { return nameof(_components); }
} }

View File

@ -5,7 +5,7 @@ using UnityEngine;
namespace DCFApixels.DragonECS namespace DCFApixels.DragonECS
{ {
public abstract class ScriptableEntityTemplateBase : ScriptableObject, ITemplate public abstract class ScriptableEntityTemplateBase : ScriptableObject, IEntityTemplate
{ {
public abstract void Apply(short worldID, int entityID); public abstract void Apply(short worldID, int entityID);
} }
@ -15,14 +15,14 @@ namespace DCFApixels.DragonECS
[MetaDescription(EcsConsts.AUTHOR, nameof(ScriptableObject) + " implementation of an entity template. Templates are a set of components that are applied to entities.")] [MetaDescription(EcsConsts.AUTHOR, nameof(ScriptableObject) + " implementation of an entity template. Templates are a set of components that are applied to entities.")]
[CreateAssetMenu(fileName = nameof(ScriptableEntityTemplate), menuName = EcsConsts.FRAMEWORK_NAME + "/" + nameof(ScriptableEntityTemplate), order = 1)] [CreateAssetMenu(fileName = nameof(ScriptableEntityTemplate), menuName = EcsConsts.FRAMEWORK_NAME + "/" + nameof(ScriptableEntityTemplate), order = 1)]
[MetaID("7C4DBA809201D959401A5BDFB6363EC0")] [MetaID("7C4DBA809201D959401A5BDFB6363EC0")]
public class ScriptableEntityTemplate : ScriptableEntityTemplateBase, ITemplateInternal public class ScriptableEntityTemplate : ScriptableEntityTemplateBase, IEntityTemplateInternal
{ {
[SerializeReference] [SerializeReference]
[ReferenceButton(true, typeof(IComponentTemplate))] [ReferenceButton(true, typeof(IComponentTemplate))]
private IComponentTemplate[] _components; private IComponentTemplate[] _components;
#region Properties #region Properties
string ITemplateInternal.ComponentsPropertyName string IEntityTemplateInternal.ComponentsPropertyName
{ {
get { return nameof(_components); } get { return nameof(_components); }
} }