mirror of
https://github.com/Alex-Rachel/TEngine.git
synced 2025-08-14 16:51:28 +00:00
重构Ecs系统
重构Ecs系统
This commit is contained in:
@@ -1,8 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: d941eb2d2cbae294bb5d2788bb724e80
|
|
||||||
folderAsset: yes
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@@ -1,113 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
|
|
||||||
namespace TEngine
|
|
||||||
{
|
|
||||||
public interface IIndex
|
|
||||||
{
|
|
||||||
int Index { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class HashSetDebugView<T> where T : IIndex
|
|
||||||
{
|
|
||||||
private readonly ArrayPool<T> m_Set;
|
|
||||||
|
|
||||||
public HashSetDebugView(ArrayPool<T> set)
|
|
||||||
{
|
|
||||||
m_Set = set ?? throw new ArgumentNullException(nameof(set));
|
|
||||||
}
|
|
||||||
|
|
||||||
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
|
|
||||||
public T[] Items
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return m_Set.ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[DebuggerTypeProxy(typeof(HashSetDebugView<>))]
|
|
||||||
[DebuggerDisplay("Count = {Count}")]
|
|
||||||
public class ArrayPool<T> where T:IIndex
|
|
||||||
{
|
|
||||||
internal T[] m_Items = new T[256];
|
|
||||||
internal bool[] Buckets = new bool[256];
|
|
||||||
private int m_Index;
|
|
||||||
private int count;
|
|
||||||
|
|
||||||
public T this[int index]
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return m_Items[index];
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
m_Items[index] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Count
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public T[] ToArray()
|
|
||||||
{
|
|
||||||
List<T> elements = new List<T>();
|
|
||||||
for (int i = 0; i < m_Items.Length; i++)
|
|
||||||
{
|
|
||||||
if (Buckets[i])
|
|
||||||
{
|
|
||||||
elements.Add(m_Items[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return elements.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Remove(T item)
|
|
||||||
{
|
|
||||||
lock (this)
|
|
||||||
{
|
|
||||||
m_Items[item.Index] = default;
|
|
||||||
Buckets[item.Index] = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Add(T item)
|
|
||||||
{
|
|
||||||
lock (this)
|
|
||||||
{
|
|
||||||
if (item.Index != -1)
|
|
||||||
{
|
|
||||||
if (!Buckets[item.Index])
|
|
||||||
{
|
|
||||||
m_Items[item.Index] = item;
|
|
||||||
Buckets[item.Index] = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_Items[m_Index] = item;
|
|
||||||
Buckets[m_Index] = true;
|
|
||||||
item.Index = m_Index;
|
|
||||||
m_Index++;
|
|
||||||
if (m_Index >= m_Items.Length)
|
|
||||||
{
|
|
||||||
T[] newItems = new T[m_Items.Length * 2];
|
|
||||||
bool[] newBuckets = new bool[m_Items.Length * 2];
|
|
||||||
Array.Copy(m_Items,0,newItems,0,m_Items.Length);
|
|
||||||
Array.Copy(Buckets, 0, newBuckets, 0, Buckets.Length);
|
|
||||||
m_Items = newItems;
|
|
||||||
Buckets = newBuckets;
|
|
||||||
}
|
|
||||||
count = m_Index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 1abd052a77e45b44ebcde5803fb36afd
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@@ -1,8 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 385b1863dab169f4fa291611477e106c
|
|
||||||
folderAsset: yes
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@@ -1,25 +0,0 @@
|
|||||||
using TEngine;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
public class ECSDemoApp : MonoBehaviour
|
|
||||||
{
|
|
||||||
public ECSGameSystem EcsGameSystem = new ECSGameSystem();
|
|
||||||
public GameObject @object;
|
|
||||||
|
|
||||||
void Start()
|
|
||||||
{
|
|
||||||
var entity = EcsGameSystem.Create<Entity>();
|
|
||||||
ECSActor actor = entity.AddComponent<ECSActor>();
|
|
||||||
actor.Name = typeof(ECSActor).ToString();
|
|
||||||
actor.gameObject = Instantiate(@object);
|
|
||||||
actor.transform = actor.gameObject.GetComponent<Transform>();
|
|
||||||
entity.AddComponent<ECSComponent>();
|
|
||||||
|
|
||||||
Debug.Log(entity.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
void Update()
|
|
||||||
{
|
|
||||||
EcsGameSystem.OnUpdate();
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: fb5cf3287e9bf3949820b50049e4bd8c
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@@ -1,9 +0,0 @@
|
|||||||
using TEngine;
|
|
||||||
|
|
||||||
public class ECSGameSystem : ECSSystem
|
|
||||||
{
|
|
||||||
public void OnUpdate()
|
|
||||||
{
|
|
||||||
Update();
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: d9d458a85873d744ab382e86008b89a0
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@@ -1,13 +0,0 @@
|
|||||||
namespace TEngine
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// ECS Actor
|
|
||||||
/// </summary>
|
|
||||||
public class ECSActor : ECSComponent
|
|
||||||
{
|
|
||||||
public string Name;
|
|
||||||
public UnityEngine.GameObject gameObject;
|
|
||||||
public UnityEngine.Transform transform;
|
|
||||||
public uint ActorID;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 34a977c48d3bdb144b7c923a702164b0
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@@ -1,14 +0,0 @@
|
|||||||
namespace TEngine
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// ECS构架可以将此组件从Entity上移除这个组件并丢入对象池,给其他此刻需要此组件的Entity使用,
|
|
||||||
/// 因此可以节省大量的内存反复创建和释放, 这也是ECS的特性可以大量重复使用组件
|
|
||||||
/// </summary>
|
|
||||||
public class ECSComponent:ECSObject
|
|
||||||
{
|
|
||||||
#pragma warning disable IDE1006
|
|
||||||
public Entity Entity { get; set; }
|
|
||||||
#pragma warning restore IDE1006
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: e93d874e10ffedf488c413fd5bbc012f
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@@ -1,72 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace TEngine
|
|
||||||
{
|
|
||||||
public enum ECSDebugType
|
|
||||||
{
|
|
||||||
Entity,
|
|
||||||
System,
|
|
||||||
Component
|
|
||||||
}
|
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class ECSCmptDebugKeyInfo
|
|
||||||
{
|
|
||||||
public string m_name;
|
|
||||||
public string val;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class ECSCmptDebugInfo
|
|
||||||
{
|
|
||||||
public string m_name;
|
|
||||||
public ECSDebugType Type = ECSDebugType.Component;
|
|
||||||
public List<ECSCmptDebugKeyInfo> m_info = new List<ECSCmptDebugKeyInfo>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ECSDebugBehaviour : UnityEngine.MonoBehaviour
|
|
||||||
{
|
|
||||||
public List<ECSCmptDebugInfo> m_ECSInfo = new List<ECSCmptDebugInfo>();
|
|
||||||
public ECSCmptDebugInfo AddDebugCmpt(string cmptName)
|
|
||||||
{
|
|
||||||
var cmptInfo = m_ECSInfo.Find((item) => { return item.m_name == cmptName; });
|
|
||||||
if (cmptInfo == null)
|
|
||||||
{
|
|
||||||
cmptInfo = new ECSCmptDebugInfo();
|
|
||||||
cmptInfo.m_name = cmptName;
|
|
||||||
m_ECSInfo.Add(cmptInfo); ;
|
|
||||||
}
|
|
||||||
|
|
||||||
return cmptInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RmvDebugCmpt(string cmptName)
|
|
||||||
{
|
|
||||||
m_ECSInfo.RemoveAll((item) => { return item.m_name == cmptName; });
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetDebugInfo(string cmptName, string key, string val)
|
|
||||||
{
|
|
||||||
var cmptInfo = AddDebugCmpt(cmptName);
|
|
||||||
var entry = cmptInfo.m_info.Find((t) => { return t.m_name == key; });
|
|
||||||
if (entry == null)
|
|
||||||
{
|
|
||||||
entry = new ECSCmptDebugKeyInfo();
|
|
||||||
entry.m_name = key;
|
|
||||||
cmptInfo.m_info.Add(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
entry.val = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveAllDebugInfo(string cmpName)
|
|
||||||
{
|
|
||||||
var cmpInfo = m_ECSInfo.Find((item) => { return item.m_name == cmpName; });
|
|
||||||
if (cmpInfo != null)
|
|
||||||
{
|
|
||||||
cmpInfo.m_info.Clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 2dc3e456c545c0c419624e068b9249dc
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@@ -1,96 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace TEngine
|
|
||||||
{
|
|
||||||
public class ECSEventCmpt : ECSComponent
|
|
||||||
{
|
|
||||||
private GameEvent _gameEvent;
|
|
||||||
|
|
||||||
#region AddEventListener
|
|
||||||
public void AddEventListener<T>(int eventId, Action<T> action)
|
|
||||||
{
|
|
||||||
_gameEvent.AddEventListener(eventId, action);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddEventListener<T, U>(int eventId, Action<T, U> action)
|
|
||||||
{
|
|
||||||
_gameEvent.AddEventListener(eventId, action);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddEventListener<T, U, W>(int eventId, Action<T, U, W> action)
|
|
||||||
{
|
|
||||||
_gameEvent.AddEventListener(eventId, action);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddEventListener(int eventId, Action action)
|
|
||||||
{
|
|
||||||
_gameEvent.AddEventListener(eventId, action);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region RemoveEventListener
|
|
||||||
public void RemoveEventListener<T>(int eventId, Action<T> action)
|
|
||||||
{
|
|
||||||
_gameEvent.RemoveEventListener(eventId, action);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveEventListener<T, U>(int eventId, Action<T, U> action)
|
|
||||||
{
|
|
||||||
_gameEvent.RemoveEventListener(eventId, action);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveEventListener<T, U, W>(int eventId, Action<T, U, W> action)
|
|
||||||
{
|
|
||||||
_gameEvent.RemoveEventListener(eventId, action);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveEventListener(int eventId, Action action)
|
|
||||||
{
|
|
||||||
_gameEvent.RemoveEventListener(eventId, action);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Send
|
|
||||||
public void Send<T>(int eventId, T info)
|
|
||||||
{
|
|
||||||
_gameEvent.Send(eventId, info);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Send<T, U>(int eventId, T info, U info2)
|
|
||||||
{
|
|
||||||
_gameEvent.Send(eventId, info, info2);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Send<T, U, W>(int eventId, T info, U info2, W info3)
|
|
||||||
{
|
|
||||||
_gameEvent.Send(eventId, info, info2, info3);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Send(int eventId)
|
|
||||||
{
|
|
||||||
_gameEvent.Send(eventId);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Clear
|
|
||||||
public void Clear()
|
|
||||||
{
|
|
||||||
GameMemPool<GameEvent>.Free(_gameEvent);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region 生命周期
|
|
||||||
public override void OnDestroy()
|
|
||||||
{
|
|
||||||
Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Awake()
|
|
||||||
{
|
|
||||||
_gameEvent = GameMemPool<GameEvent>.Alloc();
|
|
||||||
Entity.Event = this;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: af343da6b3090a24b92fc12aaa638411
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@@ -1,112 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace TEngine
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// ECS架构基类Object
|
|
||||||
/// </summary>
|
|
||||||
public class ECSObject
|
|
||||||
{
|
|
||||||
internal int HashCode;
|
|
||||||
|
|
||||||
internal ECSSystem System;
|
|
||||||
|
|
||||||
public ECSObject()
|
|
||||||
{
|
|
||||||
HashCode = GetType().GetHashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void Awake() { }
|
|
||||||
|
|
||||||
public virtual void OnDestroy() { }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Remove The ECSEntity or Component And Throw the ECSObject to ArrayPool When AddComponent Or Create Can Use Again
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="ecsObject"></param>
|
|
||||||
/// <param name="reuse">此对象是否可以复用,复用会将对象丢入System对象池中 等待再次使用,如果是Entity对象,并且不复用的话,则把Entity所使用的组件也不复用</param>
|
|
||||||
public static void Destroy(ECSObject ecsObject, bool reuse = true)
|
|
||||||
{
|
|
||||||
if (ecsObject is ECSComponent ecsComponent)
|
|
||||||
{
|
|
||||||
ecsComponent.Entity.Components.Remove(ecsComponent);
|
|
||||||
if (ecsComponent is IUpdate update)
|
|
||||||
{
|
|
||||||
ecsComponent.Entity.Updates.Remove(update);
|
|
||||||
}
|
|
||||||
if (reuse)
|
|
||||||
{
|
|
||||||
ecsComponent.Entity.System.Push(ecsComponent);
|
|
||||||
}
|
|
||||||
ecsObject.OnDestroy();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (ecsObject is Entity entity)
|
|
||||||
{
|
|
||||||
entity.System.RemoveEntity(entity);
|
|
||||||
entity.OnDestroy();
|
|
||||||
while (entity.Components.Count > 0)
|
|
||||||
{
|
|
||||||
ECSComponent ecsComponentTemp = entity.Components[0];
|
|
||||||
entity.Components.RemoveAt(0);
|
|
||||||
ecsComponentTemp.OnDestroy();
|
|
||||||
if (reuse)
|
|
||||||
{
|
|
||||||
entity.System.Push(ecsComponentTemp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
entity.Updates.Clear();
|
|
||||||
entity.CanUpdate = false;
|
|
||||||
if (reuse)
|
|
||||||
{
|
|
||||||
entity.System.Push(entity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public T FindObjectOfType<T>() where T : ECSObject
|
|
||||||
{
|
|
||||||
Type type = typeof(T);
|
|
||||||
var elements = System.Entities.ToArray();
|
|
||||||
for (int i = 0; i < elements.Length; i++)
|
|
||||||
{
|
|
||||||
if (elements[i].GetType() == type)
|
|
||||||
{
|
|
||||||
return elements[i] as T;
|
|
||||||
}
|
|
||||||
for (int n = 0; n < elements[i].Components.Count; n++)
|
|
||||||
{
|
|
||||||
if (elements[i].Components[n].GetType() == type)
|
|
||||||
{
|
|
||||||
return elements[i].Components[n] as T;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T[] FindObjectsOfType<T>() where T : ECSObject
|
|
||||||
{
|
|
||||||
Type type = typeof(T);
|
|
||||||
var items = System.Entities.ToArray();
|
|
||||||
List<T> elements = new List<T>();
|
|
||||||
for (int i = 0; i < items.Length; i++)
|
|
||||||
{
|
|
||||||
if (items[i].GetType() == type)
|
|
||||||
{
|
|
||||||
elements.Add(items[i] as T);
|
|
||||||
}
|
|
||||||
for (int n = 0; n < items[i].Components.Count; n++)
|
|
||||||
{
|
|
||||||
if (items[i].Components[n].GetType() == type)
|
|
||||||
{
|
|
||||||
elements.Add(items[i].Components[n] as T);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return elements.ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 003794832e9179348a633bdafe92ff3c
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@@ -1,233 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace TEngine
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// ECS系统 管理Entity、ECSComponent复用对象池
|
|
||||||
/// </summary>
|
|
||||||
[Serializable]
|
|
||||||
public class ECSSystem : IDisposable
|
|
||||||
{
|
|
||||||
private static ECSSystem instance = new ECSSystem();
|
|
||||||
public static ECSSystem Instance => instance;
|
|
||||||
private readonly Dictionary<int,Stack<ECSObject>> m_ObjectPool = new Dictionary<int, Stack<ECSObject>>();
|
|
||||||
internal readonly ArrayPool<Entity> Entities = new ArrayPool<Entity>();
|
|
||||||
private bool m_IsDispose = false;
|
|
||||||
|
|
||||||
public void AddEntity(Entity entity)
|
|
||||||
{
|
|
||||||
entity.System = this;
|
|
||||||
entity.Awake();
|
|
||||||
Entities.Add(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveEntity(Entity entity)
|
|
||||||
{
|
|
||||||
Entities.Remove(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get Object From ECSSystem
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T"></typeparam>
|
|
||||||
/// <returns></returns>
|
|
||||||
public T Get<T>() where T : ECSObject, new()
|
|
||||||
{
|
|
||||||
int type = typeof(T).GetHashCode();
|
|
||||||
if (m_ObjectPool.TryGetValue(type,out Stack<ECSObject> stack))
|
|
||||||
{
|
|
||||||
if (stack.Count > 0)
|
|
||||||
{
|
|
||||||
return (T) stack.Pop();
|
|
||||||
}
|
|
||||||
goto Instantiate;
|
|
||||||
}
|
|
||||||
stack = new Stack<ECSObject>();
|
|
||||||
m_ObjectPool.Add(type,stack);
|
|
||||||
Instantiate: T ecsObject = new T();
|
|
||||||
return ecsObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Push Object To ECSSystem
|
|
||||||
/// </summary>
|
|
||||||
public void Push(ECSObject ecsObject)
|
|
||||||
{
|
|
||||||
int type = ecsObject.HashCode;
|
|
||||||
|
|
||||||
if (m_ObjectPool.TryGetValue(type,out Stack<ECSObject> stack))
|
|
||||||
{
|
|
||||||
stack.Push(ecsObject);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
stack = new Stack<ECSObject>();
|
|
||||||
m_ObjectPool.Add(type,stack);
|
|
||||||
stack.Push(ecsObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
public T Create<T>() where T : Entity, new()
|
|
||||||
{
|
|
||||||
T entity = Get<T>();
|
|
||||||
AddEntity(entity);
|
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T Create<T>(T entity) where T : Entity, new()
|
|
||||||
{
|
|
||||||
AddEntity(entity);
|
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 更新ECS系统
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="worker">线程池是否并行</param>
|
|
||||||
public void Update(bool worker = false)
|
|
||||||
{
|
|
||||||
Run(worker);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 更新ECS物理系统
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="worker">线程池是否并行</param>
|
|
||||||
public void FixedUpdate(bool worker = false)
|
|
||||||
{
|
|
||||||
RunFixed(worker);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 运行ECS系统
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="worker">线程池是否并行</param>
|
|
||||||
public void Run(bool worker = false)
|
|
||||||
{
|
|
||||||
int count = Entities.Count;
|
|
||||||
if (!worker)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
if (!Entities.Buckets[i])
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Entities[i].CanUpdate)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Entities[i].Execute();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Parallel.For(0, count, i =>
|
|
||||||
{
|
|
||||||
if (!Entities.Buckets[i])
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Entities[i].CanUpdate)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Entities[i].Execute();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RunFixed(bool worker = false)
|
|
||||||
{
|
|
||||||
int count = Entities.Count;
|
|
||||||
if (!worker)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
if (!Entities.Buckets[i])
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Entities[i].CanFixedUpdate)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Entities[i].FixedUpdate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Parallel.For(0, count, i =>
|
|
||||||
{
|
|
||||||
if (!Entities.Buckets[i])
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Entities[i].CanFixedUpdate)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Entities[i].FixedUpdate();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
if (m_IsDispose)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_IsDispose = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T FindObjectOfType<T>() where T : ECSObject
|
|
||||||
{
|
|
||||||
Type type = typeof(T);
|
|
||||||
var elements = Entities.ToArray();
|
|
||||||
for (int i = 0; i < elements.Length; i++)
|
|
||||||
{
|
|
||||||
if (elements[i].GetType() == type)
|
|
||||||
{
|
|
||||||
return elements[i] as T;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int j = 0; j < elements[i].Components.Count; j++)
|
|
||||||
{
|
|
||||||
if (elements[i].Components[j].GetType() == type)
|
|
||||||
{
|
|
||||||
return elements[i].Components[j] as T;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T[] FindObjectsOfType<T>() where T : ECSObject
|
|
||||||
{
|
|
||||||
Type type = typeof(T);
|
|
||||||
var entities = Entities.ToArray();
|
|
||||||
List<T> elements = new List<T>();
|
|
||||||
for (int i = 0; i < entities.Length; i++)
|
|
||||||
{
|
|
||||||
if (entities[i].GetType() == type)
|
|
||||||
{
|
|
||||||
elements.Add(entities[i] as T);
|
|
||||||
}
|
|
||||||
for (int n = 0; n < entities[i].Components.Count; n++)
|
|
||||||
{
|
|
||||||
if (entities[i].Components[n].GetType() == type)
|
|
||||||
{
|
|
||||||
elements.Add(entities[i].Components[n] as T);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return elements.ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: d2bd4af51a518164c8da0dff296b2bb1
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@@ -1,273 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace TEngine
|
|
||||||
{
|
|
||||||
public class Entity : ECSObject, IIndex
|
|
||||||
{
|
|
||||||
[SerializeField]
|
|
||||||
internal List<ECSComponent> Components = new List<ECSComponent>();
|
|
||||||
internal List<IUpdate> Updates = new List<IUpdate>();
|
|
||||||
internal List<IFixedUpdate> FixedUpdates = new List<IFixedUpdate>();
|
|
||||||
internal bool InActive;
|
|
||||||
internal bool CanUpdate;
|
|
||||||
internal bool CanFixedUpdate;
|
|
||||||
public int Index { get; set; } = -1;
|
|
||||||
public ECSEventCmpt Event { get; set; }
|
|
||||||
public Entity()
|
|
||||||
{
|
|
||||||
InActive = true;
|
|
||||||
System = ECSSystem.Instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
~Entity()
|
|
||||||
{
|
|
||||||
InActive = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void Execute()
|
|
||||||
{
|
|
||||||
for (int i = 0; i < Updates.Count; i++)
|
|
||||||
{
|
|
||||||
Updates[i].Update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void FixedUpdate()
|
|
||||||
{
|
|
||||||
for (int i = 0; i < FixedUpdates.Count; i++)
|
|
||||||
{
|
|
||||||
FixedUpdates[i].FixedUpdate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RmvComponent<T>() where T : ECSComponent, new()
|
|
||||||
{
|
|
||||||
for (int i = 0; i < Components.Count; i++)
|
|
||||||
{
|
|
||||||
if (Components[i] is T component)
|
|
||||||
{
|
|
||||||
if (component is IUpdate update)
|
|
||||||
{
|
|
||||||
Updates.Remove(update);
|
|
||||||
}
|
|
||||||
else if (component is IFixedUpdate fixedUpdate)
|
|
||||||
{
|
|
||||||
FixedUpdates.Remove(fixedUpdate);
|
|
||||||
}
|
|
||||||
|
|
||||||
System.Push(component);
|
|
||||||
|
|
||||||
CanUpdate = Updates.Count > 0;
|
|
||||||
|
|
||||||
CanFixedUpdate = FixedUpdates.Count > 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
|
||||||
CheckDebugInfo();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RmvComponent(Type componentType)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < Components.Count; i++)
|
|
||||||
{
|
|
||||||
if (Components[i].GetType() == componentType)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (componentType is IUpdate update)
|
|
||||||
{
|
|
||||||
Updates.Remove(update);
|
|
||||||
|
|
||||||
CanUpdate = Updates.Count > 0;
|
|
||||||
}
|
|
||||||
else if (componentType is IFixedUpdate fixedUpdate)
|
|
||||||
{
|
|
||||||
FixedUpdates.Remove(fixedUpdate);
|
|
||||||
|
|
||||||
CanFixedUpdate = FixedUpdates.Count > 0;
|
|
||||||
}
|
|
||||||
//if (componentType is ECSComponent component)
|
|
||||||
//{
|
|
||||||
// System.Push(component);
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#if UNITY_EDITOR
|
|
||||||
CheckDebugInfo();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
public T AddComponent<T>() where T : ECSComponent, new()
|
|
||||||
{
|
|
||||||
#if UNITY_EDITOR
|
|
||||||
CheckDebugInfo();
|
|
||||||
#endif
|
|
||||||
T component = System.Get<T>();
|
|
||||||
component.Entity = this;
|
|
||||||
component.System = System;
|
|
||||||
Components.Add(component);
|
|
||||||
component.Awake();
|
|
||||||
if (component is IUpdate update)
|
|
||||||
{
|
|
||||||
Updates.Add(update);
|
|
||||||
}
|
|
||||||
else if (component is IFixedUpdate fixedUpdate)
|
|
||||||
{
|
|
||||||
FixedUpdates.Add(fixedUpdate);
|
|
||||||
}
|
|
||||||
CanUpdate = Updates.Count > 0;
|
|
||||||
CanFixedUpdate = FixedUpdates.Count > 0;
|
|
||||||
return component;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ECSComponent AddComponent(ECSComponent component)
|
|
||||||
{
|
|
||||||
#if UNITY_EDITOR
|
|
||||||
CheckDebugInfo();
|
|
||||||
#endif
|
|
||||||
component.Entity = this;
|
|
||||||
component.System = System;
|
|
||||||
Components.Add(component);
|
|
||||||
component.Awake();
|
|
||||||
if (component is IUpdate update)
|
|
||||||
{
|
|
||||||
Updates.Add(update);
|
|
||||||
}
|
|
||||||
else if (component is IFixedUpdate fixedUpdate)
|
|
||||||
{
|
|
||||||
FixedUpdates.Add(fixedUpdate);
|
|
||||||
}
|
|
||||||
CanUpdate = Updates.Count > 0;
|
|
||||||
CanFixedUpdate = FixedUpdates.Count > 0;
|
|
||||||
return component;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T GetComponent<T>() where T : ECSComponent
|
|
||||||
{
|
|
||||||
for (int i = 0; i < Components.Count; i++)
|
|
||||||
{
|
|
||||||
if (Components[i] is T type)
|
|
||||||
{
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ECSComponent GetComponent(Type componentType)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < Components.Count; i++)
|
|
||||||
{
|
|
||||||
if (Components[i].GetType() == componentType)
|
|
||||||
{
|
|
||||||
return Components[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T[] GetComponents<T>() where T : ECSComponent
|
|
||||||
{
|
|
||||||
List<T> elements = new List<T>();
|
|
||||||
for (int i = 0; i < Components.Count; i++)
|
|
||||||
{
|
|
||||||
if (Components[i] is T type)
|
|
||||||
{
|
|
||||||
elements.Add(type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return elements.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<T> GetComponentsList<T>() where T : ECSComponent
|
|
||||||
{
|
|
||||||
List<T> elements = new List<T>();
|
|
||||||
for (int i = 0; i < Components.Count; i++)
|
|
||||||
{
|
|
||||||
if (Components[i] is T type)
|
|
||||||
{
|
|
||||||
elements.Add(type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return elements;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ECSComponent[] GetComponents(Type comType)
|
|
||||||
{
|
|
||||||
List<ECSComponent> elements = new List<ECSComponent>();
|
|
||||||
for (int i = 0; i < Components.Count; i++)
|
|
||||||
{
|
|
||||||
{
|
|
||||||
if (Components[i].GetType() == comType)
|
|
||||||
{
|
|
||||||
elements.Add(Components[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return elements.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
string str = "[";
|
|
||||||
for (int i = 0; i < Components.Count; i++)
|
|
||||||
{
|
|
||||||
str += Components[i].GetType().Name + ",";
|
|
||||||
}
|
|
||||||
str = str.TrimEnd(',');
|
|
||||||
str += "]";
|
|
||||||
return $"{GetType().Name} Components: {str}";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void CheckDebugInfo(GameObject gameObject)
|
|
||||||
{
|
|
||||||
#if UNITY_EDITOR
|
|
||||||
if (gameObject == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var debugBehaviour = UnityUtil.AddMonoBehaviour<ECSDebugBehaviour>(gameObject);
|
|
||||||
debugBehaviour.m_ECSInfo.Clear();
|
|
||||||
for (int i = 0; i < this.Components.Count; i++)
|
|
||||||
{
|
|
||||||
var component = this.Components[i];
|
|
||||||
var cmptName = component.GetType().Name;
|
|
||||||
debugBehaviour.SetDebugInfo(cmptName, "", "");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
public void CheckDebugInfo()
|
|
||||||
{
|
|
||||||
#if UNITY_EDITOR
|
|
||||||
//var actorEntity = this as Entity;
|
|
||||||
|
|
||||||
//if (actorEntity == null)
|
|
||||||
//{
|
|
||||||
// return;
|
|
||||||
//}
|
|
||||||
|
|
||||||
//if (actorEntity.gameObject == null)
|
|
||||||
//{
|
|
||||||
// return;
|
|
||||||
//}
|
|
||||||
|
|
||||||
//var debugBehaviour = UnityUtil.AddMonoBehaviour<ECSDebugBehaviour>(actorEntity.gameObject);
|
|
||||||
//debugBehaviour.m_ECSInfo.Clear();
|
|
||||||
//for (int i = 0; i < this.Components.Count; i++)
|
|
||||||
//{
|
|
||||||
// var component = this.Components[i];
|
|
||||||
// var cmptName = component.GetType().Name;
|
|
||||||
// debugBehaviour.SetDebugInfo(cmptName, "", "");
|
|
||||||
//}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 9f5bc14d7a4aee34695c39d02ae1c71f
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@@ -1,32 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace TEngine
|
|
||||||
{
|
|
||||||
public class HotfixComponent : ECSComponent,IUpdate
|
|
||||||
{
|
|
||||||
public object[] Values;
|
|
||||||
public Action OnAwake, OnUpdate, OnDestroyExt;
|
|
||||||
|
|
||||||
public override void Awake()
|
|
||||||
{
|
|
||||||
OnAwake?.Invoke();
|
|
||||||
}
|
|
||||||
|
|
||||||
void IUpdate.Update()
|
|
||||||
{
|
|
||||||
OnUpdate?.Invoke();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnDestroy()
|
|
||||||
{
|
|
||||||
OnDestroyExt?.Invoke();
|
|
||||||
OnAwake = null;
|
|
||||||
OnUpdate = null;
|
|
||||||
OnDestroyExt = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: c0ac8b7fabe2bae499a568608191eb57
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@@ -1,10 +0,0 @@
|
|||||||
namespace TEngine
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// ECS组件更新接口(减少组件for循环开销)
|
|
||||||
/// </summary>
|
|
||||||
public interface IFixedUpdate
|
|
||||||
{
|
|
||||||
void FixedUpdate();
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 7fb8a7b6d364a024e8a49a0a731de201
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@@ -1,10 +0,0 @@
|
|||||||
namespace TEngine
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// ECS组件更新接口(减少组件for循环开销)
|
|
||||||
/// </summary>
|
|
||||||
public interface IUpdate
|
|
||||||
{
|
|
||||||
void Update();
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: e7918afae3870234391c6e6f521e9ca7
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@@ -1,13 +0,0 @@
|
|||||||
namespace TEngine
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 热更层由此组件进行更新(ILRuntime不支持多继承, 接口继承)
|
|
||||||
/// </summary>
|
|
||||||
public class UpdateComponent :ECSComponent, IUpdate
|
|
||||||
{
|
|
||||||
public virtual void Update()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 02463b27b6971f0408bb517c32c66553
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
Reference in New Issue
Block a user