Boat Attack使用了Universal RP的许多新图形功能,可以用于探索 Universal RP 的使用方式和技巧。
您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 

462 行
19 KiB

using System;
using System.Collections.Generic;
using System.Linq;
namespace Unity.Entities
{
public class CircularSystemDependencyException : Exception
{
public CircularSystemDependencyException(IEnumerable<ComponentSystemBase> chain)
{
Chain = chain;
#if NET_DOTS
var lines = new List<string>();
Console.WriteLine($"The following systems form a circular dependency cycle (check their [UpdateBefore]/[UpdateAfter] attributes):");
foreach (var s in Chain)
{
int index = TypeManager.GetSystemTypeIndex(s.GetType());
string name = TypeManager.SystemNames[index];
Console.WriteLine(name);
}
#endif
}
public IEnumerable<ComponentSystemBase> Chain { get; }
#if !NET_DOTS
public override string Message
{
get
{
var lines = new List<string>();
lines.Add($"The following systems form a circular dependency cycle (check their [UpdateBefore]/[UpdateAfter] attributes):");
foreach (var s in Chain)
{
lines.Add($"- {s.GetType().ToString()}");
}
return lines.Aggregate((str1, str2) => str1 + "\n" + str2);
}
}
#endif
}
public abstract class ComponentSystemGroup : ComponentSystem
{
private bool m_systemSortDirty = false;
protected List<ComponentSystemBase> m_systemsToUpdate = new List<ComponentSystemBase>();
public virtual IEnumerable<ComponentSystemBase> Systems => m_systemsToUpdate;
public void AddSystemToUpdateList(ComponentSystemBase sys)
{
if (sys != null)
{
if (this == sys)
{
#if !NET_DOTS
throw new ArgumentException($"Can't add {GetType()} to its own update list");
#else
throw new ArgumentException($"Can't add a ComponentSystemGroup to its own update list");
#endif
}
// Check for duplicate Systems. Also see issue #1792
if (m_systemsToUpdate.IndexOf(sys) >= 0)
return;
m_systemsToUpdate.Add(sys);
m_systemSortDirty = true;
}
}
public void RemoveSystemFromUpdateList(ComponentSystemBase sys)
{
m_systemsToUpdate.Remove(sys);
m_systemSortDirty = true;
m_systemSortDirty = true;
}
class Heap<T>
where T : IComparable<T>
{
private T[] _elements;
private int _size;
private int _capacity;
private static readonly int BaseIndex = 1;
public Heap(int capacity) {
_capacity = capacity;
_size = 0;
_elements = new T[capacity + BaseIndex];
}
public bool Empty { get { return _size <= 0; } }
public void Insert(T e) {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
if (_size >= _capacity)
{
throw new InvalidOperationException($"Attempted to Insert() to a full heap.");
}
#endif
int i = BaseIndex + _size++;
while (i > BaseIndex) {
int parent = i / 2;
if (e.CompareTo(_elements[parent]) > 0) {
break;
}
_elements[i] = _elements[parent];
i = parent;
}
_elements[i] = e;
}
public T Peek() {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
if (Empty)
{
throw new InvalidOperationException($"Attempted to Peek() an empty heap.");
}
#endif
return _elements[BaseIndex];
}
public T Extract() {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
if (Empty)
{
throw new InvalidOperationException($"Attempted to Extract() from an empty heap.");
}
#endif
T top = _elements[BaseIndex];
_elements[BaseIndex] = _elements[_size--];
if (!Empty) {
Heapify(BaseIndex);
}
return top;
}
private void Heapify(int i) {
// The index taken by this function is expected to be already biased by BaseIndex.
// Thus, m_Heap[size] is a valid element (specifically, the final element in the heap)
//Debug.Assert(i >= BaseIndex && i < (_size+BaseIndex), $"heap index {i} is out of range with size={_size}");
T val = _elements[i];
while (i <= _size / 2) {
int child = 2 * i;
if (child < _size && _elements[child + 1].CompareTo(_elements[child]) < 0) {
child++;
}
if (val.CompareTo(_elements[child]) < 0) {
break;
}
_elements[i] = _elements[child];
i = child;
}
_elements[i] = val;
}
}
struct SysAndDep
{
public ComponentSystemBase system;
public List<Type> updateBefore;
public int nAfter;
}
public struct TypeHeapElement : IComparable<TypeHeapElement>
{
private string typeName;
public int unsortedIndex;
public TypeHeapElement(int index, Type t)
{
unsortedIndex = index;
typeName = TypeManager.SystemName(t);
}
public int CompareTo(TypeHeapElement other)
{
#if NET_DOTS
// Workaround for missing string.CompareTo() in HPC#. This is not a fully compatible substitute,
// but should be suitable for comparing system names.
if (typeName.Length < other.typeName.Length)
return -1;
if (typeName.Length > other.typeName.Length)
return 1;
for (int i = 0; i < typeName.Length; ++i)
{
if (typeName[i] < other.typeName[i])
return -1;
if (typeName[i] > other.typeName[i])
return 1;
}
return 0;
#else
return typeName.CompareTo(other.typeName);
#endif
}
}
// Tiny doesn't have a data structure that can take Type as a key.
// For now, this gives Tiny a linear search. Would like to do better.
#if !NET_DOTS
private Dictionary<Type, int> lookupDictionary = null;
private int LookupSysAndDep(Type t, SysAndDep[] array) {
if (lookupDictionary == null) {
lookupDictionary = new Dictionary<Type, int>();
for(int i=0; i<array.Length; ++i) {
lookupDictionary[array[i].system.GetType()] = i;
}
}
if (lookupDictionary.ContainsKey(t))
return lookupDictionary[t];
return -1;
}
#else
private int LookupSysAndDep(Type t, SysAndDep[] array)
{
for (int i = 0; i < array.Length; ++i)
{
if (array[i].system != null && array[i].system.GetType() == t)
{
return i;
}
}
return -1;
}
#endif
public virtual void SortSystemUpdateList()
{
if (!m_systemSortDirty)
return;
m_systemSortDirty = false;
#if !NET_DOTS
lookupDictionary = null;
#endif
// Populate dictionary mapping systemType to system-and-before/after-types.
// This is clunky - it is easier to understand, and cleaner code, to
// just use a Dictionary<Type, SysAndDep>. However, Tiny doesn't currently have
// the ability to use Type as a key to a NativeHash, so we're stuck until that gets addressed.
//
// Likewise, this is important shared code. It can be done cleaner with 2 versions, but then...
// 2 sets of bugs and slightly different behavior will creep in.
//
var sysAndDep = new SysAndDep[m_systemsToUpdate.Count];
for(int i=0; i<m_systemsToUpdate.Count; ++i)
{
var sys = m_systemsToUpdate[i];
if (TypeManager.IsSystemAGroup(sys.GetType()))
{
(sys as ComponentSystemGroup).SortSystemUpdateList();
}
sysAndDep[i] = new SysAndDep
{
system = sys,
updateBefore = new List<Type>(),
nAfter = 0,
};
}
for(int i=0; i<m_systemsToUpdate.Count; ++i)
{
var sys = m_systemsToUpdate[i];
var before = TypeManager.GetSystemAttributes(sys.GetType(), typeof(UpdateBeforeAttribute));
var after = TypeManager.GetSystemAttributes(sys.GetType(), typeof(UpdateAfterAttribute));
foreach (var attr in before)
{
var dep = attr as UpdateBeforeAttribute;
if (!typeof(ComponentSystemBase).IsAssignableFrom(dep.SystemType))
{
#if !NET_DOTS
Debug.LogWarning(
$"Ignoring invalid [UpdateBefore] attribute on {sys.GetType()} because {dep.SystemType} is not a subclass of {nameof(ComponentSystemBase)}.\n"
+ $"Set the target parameter of [UpdateBefore] to a system class in the same {nameof(ComponentSystemGroup)} as {sys.GetType()}.");
#else
Debug.LogWarning($"WARNING: invalid [UpdateBefore] attribute:");
Debug.LogWarning(TypeManager.SystemName(dep.SystemType));
Debug.LogWarning(" is not derived from ComponentSystemBase. Set the target parameter of [UpdateBefore] to a system class in the same ComponentSystemGroup.");
#endif
continue;
}
if (dep.SystemType == sys.GetType())
{
#if !NET_DOTS
Debug.LogWarning(
$"Ignoring invalid [UpdateBefore] attribute on {sys.GetType()} because a system cannot be updated before itself.\n"
+ $"Set the target parameter of [UpdateBefore] to a different system class in the same {nameof(ComponentSystemGroup)} as {sys.GetType()}.");
#else
Debug.LogWarning($"WARNING: invalid [UpdateBefore] attribute:");
Debug.LogWarning(TypeManager.SystemName(sys.GetType()));
Debug.LogWarning(" depends on itself. Set the target parameter of [UpdateBefore] to a system class in the same ComponentSystemGroup.");
#endif
continue;
}
int depIndex = LookupSysAndDep(dep.SystemType, sysAndDep);
if (depIndex < 0)
{
#if !NET_DOTS
Debug.LogWarning(
$"Ignoring invalid [UpdateBefore] attribute on {sys.GetType()} because {dep.SystemType} belongs to a different {nameof(ComponentSystemGroup)}.\n"
+ $"This attribute can only order systems that are children of the same {nameof(ComponentSystemGroup)}.\n"
+ $"Make sure that both systems are in the same parent group with [UpdateInGroup(typeof({GetType()})].\n"
+ $"You can also change the relative order of groups when appropriate, by using [UpdateBefore] and [UpdateAfter] attributes at the group level.");
#else
Debug.LogWarning("WARNING: invalid [UpdateBefore] dependency:");
Debug.LogWarning(TypeManager.SystemName(sys.GetType()));
Debug.LogWarning(" depends on a non-sibling system: ");
Debug.LogWarning(TypeManager.SystemName(dep.SystemType));
#endif
continue;
}
sysAndDep[i].updateBefore.Add(dep.SystemType);
sysAndDep[depIndex].nAfter++;
}
foreach (var attr in after)
{
var dep = attr as UpdateAfterAttribute;
if (!typeof(ComponentSystemBase).IsAssignableFrom(dep.SystemType))
{
#if !NET_DOTS
Debug.LogWarning(
$"Ignoring invalid [UpdateAfter] attribute on {sys.GetType()} because {dep.SystemType} is not a subclass of {nameof(ComponentSystemBase)}.\n"
+ $"Set the target parameter of [UpdateAfter] to a system class in the same {nameof(ComponentSystemGroup)} as {sys.GetType()}.");
#else
Debug.LogWarning($"WARNING: invalid [UpdateAfter] attribute:");
Debug.LogWarning(TypeManager.SystemName(dep.SystemType));
Debug.LogWarning(" is not derived from ComponentSystemBase. Set the target parameter of [UpdateAfter] to a system class in the same ComponentSystemGroup.");
#endif
continue;
}
if (dep.SystemType == sys.GetType())
{
#if !NET_DOTS
Debug.LogWarning(
$"Ignoring invalid [UpdateAfter] attribute on {sys.GetType()} because a system cannot be updated after itself.\n"
+ $"Set the target parameter of [UpdateAfter] to a different system class in the same {nameof(ComponentSystemGroup)} as {sys.GetType()}.");
#else
Debug.LogWarning($"WARNING: invalid [UpdateAfter] attribute:");
Debug.LogWarning(TypeManager.SystemName(sys.GetType()));
Debug.LogWarning(" depends on itself. Set the target parameter of [UpdateAfter] to a system class in the same ComponentSystemGroup.");
#endif
continue;
}
int depIndex = LookupSysAndDep(dep.SystemType, sysAndDep);
if (depIndex < 0)
{
#if !NET_DOTS
Debug.LogWarning(
$"Ignoring invalid [UpdateAfter] attribute on {sys.GetType()} because {dep.SystemType} belongs to a different {nameof(ComponentSystemGroup)}.\n"
+ $"This attribute can only order systems that are children of the same {nameof(ComponentSystemGroup)}.\n"
+ $"Make sure that both systems are in the same parent group with [UpdateInGroup(typeof({GetType()})].\n"
+ $"You can also change the relative order of groups when appropriate, by using [UpdateBefore] and [UpdateAfter] attributes at the group level.");
#else
Debug.LogWarning("WARNING: invalid [UpdateAfter] dependency:");
Debug.LogWarning(TypeManager.SystemName(sys.GetType()));
Debug.LogWarning(" depends on a non-sibling system: ");
Debug.LogWarning(TypeManager.SystemName(dep.SystemType));
#endif
continue;
}
sysAndDep[depIndex].updateBefore.Add(sys.GetType());
sysAndDep[i].nAfter++;
}
}
// Clear the systems list and rebuild it in sorted order from the lookup table
var readySystems = new Heap<TypeHeapElement>(m_systemsToUpdate.Count);
m_systemsToUpdate.Clear();
for (int i = 0; i < sysAndDep.Length; ++i)
{
if (sysAndDep[i].nAfter == 0)
{
readySystems.Insert(new TypeHeapElement(i, sysAndDep[i].system.GetType()));
}
}
while (!readySystems.Empty)
{
int sysIndex = readySystems.Extract().unsortedIndex;
SysAndDep sd = sysAndDep[sysIndex];
Type sysType = sd.system.GetType();
sysAndDep[sysIndex] = new SysAndDep(); // "Remove()"
m_systemsToUpdate.Add(sd.system);
foreach (var beforeType in sd.updateBefore)
{
int beforeIndex = LookupSysAndDep(beforeType, sysAndDep);
if (beforeIndex < 0) throw new Exception("Bug in SortSystemUpdateList(), beforeIndex < 0");
if (sysAndDep[beforeIndex].nAfter <= 0) throw new Exception("Bug in SortSystemUpdateList(), nAfter <= 0");
sysAndDep[beforeIndex].nAfter--;
if (sysAndDep[beforeIndex].nAfter == 0)
{
readySystems.Insert(new TypeHeapElement(beforeIndex, sysAndDep[beforeIndex].system.GetType()));
}
}
}
for(int i=0; i<sysAndDep.Length; ++i)
{
if (sysAndDep[i].system != null)
{
// Since no System in the circular dependency would have ever been added
// to the heap, we should have values for everything in sysAndDep. Check,
// just in case.
#if ENABLE_UNITY_COLLECTIONS_CHECKS
var visitedSystems = new List<ComponentSystemBase>();
var startIndex = i;
var currentIndex = i;
while (true)
{
if (sysAndDep[currentIndex].system != null)
visitedSystems.Add(sysAndDep[currentIndex].system);
currentIndex = LookupSysAndDep(sysAndDep[currentIndex].updateBefore[0], sysAndDep);
if (currentIndex < 0 || currentIndex == startIndex || sysAndDep[currentIndex].system == null)
{
throw new CircularSystemDependencyException(visitedSystems);
}
}
#else
sysAndDep[i] = new SysAndDep();
#endif
}
}
}
#if NET_DOTS
public void RecursiveLogToConsole()
{
foreach (var sys in m_systemsToUpdate)
{
if (sys is ComponentSystemGroup)
{
(sys as ComponentSystemGroup).RecursiveLogToConsole();
}
var index = TypeManager.GetSystemTypeIndex(sys.GetType());
var names = TypeManager.SystemNames;
var name = names[index];
Debug.Log(name);
}
}
#endif
protected override void OnUpdate()
{
if (m_systemSortDirty)
SortSystemUpdateList();
foreach (var sys in m_systemsToUpdate)
{
try
{
sys.Update();
}
catch (Exception e)
{
Debug.LogException(e);
}
if (World.QuitUpdate)
break;
}
}
}
}