您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
409 行
15 KiB
409 行
15 KiB
<#/*THIS IS A T4 FILE - see t4_text_templating.md for what it is and how to run codegen*/#>
|
|
<#@ assembly name="System.Collections" #>
|
|
<#@ assembly name="System.Core" #>
|
|
<#@ assembly name="System.Linq" #>
|
|
<#@ import namespace="System.Collections.Generic" #>
|
|
<#@ import namespace="System.Linq" #>
|
|
<#@ output extension=".gen.cs" #>
|
|
//------------------------------------------------------------------------------
|
|
// <auto-generated>
|
|
// This code was generated by a tool.
|
|
//
|
|
// Changes to this file may cause incorrect behavior and will be lost if
|
|
// the code is regenerated.
|
|
// </auto-generated>
|
|
//------------------------------------------------------------------------------
|
|
<# var combinations = InitCombinations(); #>
|
|
// Generated by EntityQueryBuilder.tt (<#=combinations.Count * 2 - 1#> `foreach` combinations)
|
|
|
|
using System;
|
|
using System.ComponentModel;
|
|
using Unity.Collections;
|
|
using Unity.Collections.LowLevel.Unsafe;
|
|
using Unity.Jobs;
|
|
|
|
namespace Unity.Entities
|
|
{
|
|
public partial struct EntityQueryBuilder
|
|
{
|
|
<#
|
|
foreach (var categories in combinations) {
|
|
foreach (var hasEntity in new[] { true, false }) {
|
|
if (!categories.Any() && !hasEntity)
|
|
continue;
|
|
var mappedCategories = categories.Select((c, i) => (c: (int)c, i: i));
|
|
var delegateName = GetDelegateName(categories, hasEntity);
|
|
var delegateParameters = GetDelegateParameters(categories, hasEntity);
|
|
var genericTypes = categories.Any() ? ("<" + Series("T{0}", categories.Length, ", ") + ">") : "";
|
|
var genericTypesWithJob = "<TJob" + (categories.Any() ? (", " + Series("T{0}", categories.Length, ", ")) : "") + ">";
|
|
var genericConstraints = GetGenericConstraints(categories);
|
|
var actionParams = GetActionParams(categories, hasEntity);
|
|
#>
|
|
public delegate void <#=delegateName#><#=genericTypes#>(<#=delegateParameters#>)<#=categories.Any() ? "" : ";"#>
|
|
<# foreach (var constraint in Smart(genericConstraints)) {#>
|
|
<#=constraint.Value#><#=constraint.IfLast(";")#>
|
|
<# }#>
|
|
|
|
public unsafe void ForEach<#=genericTypes#>(<#=delegateName#><#=genericTypes#> action)
|
|
<# foreach (var constraint in genericConstraints) {#>
|
|
<#=constraint#>
|
|
<# }#>
|
|
{
|
|
#if ENABLE_UNITY_COLLECTIONS_CHECKS
|
|
using (InsideForEach())
|
|
#endif
|
|
{
|
|
var query = m_Query;
|
|
if (query == null)
|
|
{
|
|
<# if (categories.Any()) {#>
|
|
var delegateTypes = stackalloc[]
|
|
{
|
|
<# foreach (var (c, i) in mappedCategories) { #>
|
|
TypeManager.GetTypeIndex<T<#=i#>>(),
|
|
<# }#>
|
|
};
|
|
|
|
<# }#>
|
|
query = ResolveEntityQuery(<#=categories.Any() ? "delegateTypes" : "null"#>, <#=categories.Length#>);
|
|
}
|
|
|
|
<# if (hasEntity) {#>
|
|
var entityType = m_System.GetArchetypeChunkEntityType();
|
|
<# }#>
|
|
<# foreach (var (c, i) in mappedCategories) {#>
|
|
var chunkComponentType<#=i#> = m_System.<#=AccessFunction[c]#><T<#=i#>>(<#=IsReadOnly[c]#>);
|
|
<# }#>
|
|
|
|
using (var chunks = query.CreateArchetypeChunkArray(Allocator.TempJob))
|
|
{
|
|
foreach (var chunk in chunks)
|
|
{
|
|
<# foreach (var (c, i) in mappedCategories) {#>
|
|
var array<#=i#> = chunk.<#=string.Format(ChunkGetArray[c], i)#>;
|
|
<# }#>
|
|
<# if (hasEntity) {#>
|
|
var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr();
|
|
<# }#>
|
|
|
|
for (int i = 0, count = chunk.Count; i < count; ++i)
|
|
action(<#=actionParams#>);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
<#}}#>
|
|
}
|
|
|
|
// Schedule() implementation for DOTS-standalone.
|
|
// The IDE calls Schedule(), and then code-gen is used to
|
|
// replace the call to the correct Schedule_D method, With
|
|
// known types.
|
|
|
|
#if UNITY_DOTSPLAYER
|
|
public static partial class JobForEachExtensions
|
|
{
|
|
<#
|
|
|
|
string GetScheduleParams(Category[] categories, bool hasEntity)
|
|
{
|
|
var parts = categories.Select((c, i) => string.Format(ArrayAccess[(int)c], i));
|
|
if (hasEntity) {
|
|
parts = parts.Prepend("entityArray[i].Index");
|
|
parts = parts.Prepend("entityArray[i]");
|
|
}
|
|
return string.Join(", ", parts);
|
|
}
|
|
|
|
foreach (var categories in combinations) {
|
|
foreach (var hasEntity in new[] { false, true }) {
|
|
if (!categories.Any())
|
|
continue;
|
|
var mappedCategories = categories.Select((c, i) => (c: (int)c, i: i));
|
|
var delegateName = GetDelegateName(categories, hasEntity);
|
|
var delegateParameters = GetDelegateParameters(categories, hasEntity);
|
|
var genericTypes = categories.Any() ? ("<" + Series("T{0}", categories.Length, ", ") + ">") : "";
|
|
var genericTypesWithJob = "<TJob" + (categories.Any() ? (", " + Series("T{0}", categories.Length, ", ")) : "") + ">";
|
|
var genericConstraints = GetGenericConstraints(categories);
|
|
var actionParams = GetScheduleParams(categories, hasEntity);
|
|
var dName = (hasEntity ? "E" : "") + Series("D", categories.Length, "");
|
|
var jobInterface = hasEntity ? "IJobForEachWithEntity" : "IJobForEach";
|
|
|
|
// See "Code-Gen of Schedule()" IJobForEach.cs for an explanation of the code-gen steps and how this works.
|
|
#>
|
|
<# if (categories.Any() && !categories.Any(c => c != Category.D)) { #>
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
internal unsafe static void Execute_<#=dName#><#=genericTypesWithJob#>(TJob job, ComponentSystemBase system, EntityQuery query, JobHandle dependsOn = default(JobHandle))
|
|
where TJob : struct, <#=jobInterface#><#=genericTypes#>
|
|
<# foreach (var constraint in genericConstraints) {#>
|
|
<#=constraint#>
|
|
<# }#>
|
|
{
|
|
<# if (hasEntity) {#>
|
|
var entityType = system.GetArchetypeChunkEntityType();
|
|
<# }#>
|
|
<# foreach (var (c, i) in mappedCategories) {#>
|
|
var chunkComponentType<#=i#> = system.<#=AccessFunction[c]#><T<#=i#>>(<#=IsReadOnly[c]#>);
|
|
<# }#>
|
|
|
|
using (var chunks = query.CreateArchetypeChunkArray(Allocator.TempJob))
|
|
{
|
|
foreach (var chunk in chunks)
|
|
{
|
|
<# foreach (var (c, i) in mappedCategories) {#>
|
|
var array<#=i#> = chunk.<#=string.Format(ChunkGetArray[c], i)#>;
|
|
<# }#>
|
|
<# if (hasEntity) {#>
|
|
var entityArray = (Entity*)chunk.GetNativeArray(entityType).GetUnsafeReadOnlyPtr();
|
|
<# }#>
|
|
|
|
for (int i = 0, count = chunk.Count; i < count; ++i)
|
|
job.Execute(<#=actionParams#>);
|
|
}
|
|
}
|
|
DoDeallocateOnJobCompletion(job);
|
|
}
|
|
<#
|
|
for(int bits=0; bits < (1 << categories.Length); ++bits) {
|
|
var accessID = hasEntity ? "E" : "";
|
|
String[] accessName = new String[categories.Length];
|
|
for(int i=0; i<categories.Length; ++i) {
|
|
if ((bits & (1<<i)) != 0) {
|
|
accessID += "wD";
|
|
accessName[i] = "ReadWrite";
|
|
}
|
|
else {
|
|
accessID += "rD";
|
|
accessName[i] = "ReadOnly";
|
|
}
|
|
}
|
|
#>
|
|
<# // See "Code-Gen of Schedule()" IJobForEach.cs for an explanation of the code-gen steps and how this works.
|
|
#>
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
internal unsafe static JobHandle Schedule_<#=accessID#><#=genericTypesWithJob#>(TJob job, ComponentSystemBase system, JobHandle dependsOn = default(JobHandle))
|
|
where TJob : struct, <#=jobInterface#><#=genericTypes#>
|
|
<# foreach (var constraint in genericConstraints) {#>
|
|
<#=constraint#>
|
|
<# }#>
|
|
{
|
|
{
|
|
<# if (categories.Any()) {#>
|
|
var delegateTypes = stackalloc ComponentType[<#=categories.Length#>]
|
|
{
|
|
<# foreach (var (c, i) in mappedCategories) { #>
|
|
ComponentType.<#=accessName[i]#><T<#=i#>>(),
|
|
<# }#>
|
|
};
|
|
<# }#>
|
|
EntityQuery query = /*ResolveEntityQuery*/system.GetEntityQueryInternal(<#=categories.Any() ? "delegateTypes" : "null"#>, <#=categories.Length#>);
|
|
Execute_<#=dName#><#=genericTypesWithJob#>(job, system, query, dependsOn);
|
|
}
|
|
return new JobHandle();
|
|
}
|
|
<#
|
|
}
|
|
#>
|
|
<# } #>
|
|
<#}}#>
|
|
}
|
|
#endif // UNITY_DOTSPLAYER
|
|
|
|
// BACK-COMPAT
|
|
|
|
public partial class ComponentSystem
|
|
{
|
|
<#
|
|
foreach (var categories in combinations) {
|
|
foreach (var hasEntity in new[] { true, false }) {
|
|
if (!categories.Any() && !hasEntity)
|
|
continue;
|
|
var delegateName = GetDelegateName(categories, hasEntity);
|
|
var genericTypes = categories.Any() ? ("<" + Series("T{0}", categories.Length, ", ") + ">") : "";
|
|
var genericConstraints = GetGenericConstraints(categories);
|
|
#>
|
|
[System.Obsolete("Call Entities.ForEach() or Entities.With(query).ForEach() instead (RemovedAfter 2019-07-11)")]
|
|
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
|
public unsafe void ForEach<#=genericTypes#>(EntityQueryBuilder.<#=delegateName#><#=genericTypes#> action, EntityQuery query = null)
|
|
<#=string.Join(" ", genericConstraints)#>
|
|
{
|
|
var q = Entities;
|
|
if (query != null)
|
|
q = q.With(query);
|
|
q.ForEach(action);
|
|
}
|
|
|
|
<#}}#>
|
|
}
|
|
|
|
} // namespace Unity.Entities
|
|
|
|
<#+
|
|
enum Category
|
|
{
|
|
// note: 'in' is broken in c# (very easy for user to accidentally cause a copy) so we do not
|
|
// include it in the combos we support yet.
|
|
|
|
D, // ref ComponentData
|
|
I, // in ComponentData
|
|
C, // class
|
|
B, // IBufferElementData
|
|
K, // in IBufferElementData
|
|
S, // ISharedComponentData
|
|
}
|
|
|
|
static string GetDelegateName(Category[] categories, bool hasEntity)
|
|
{
|
|
var parts = string.Join("", categories.Select(c => c.ToString()));
|
|
return $"F_{(hasEntity ? "E" : "")}{parts}";
|
|
}
|
|
|
|
string[] Param =
|
|
{
|
|
"ref T{0} d{0}", // ref ComponentData
|
|
"in T{0} i{0}", // in ComponentData
|
|
"T{0} c{0}", // class
|
|
"DynamicBuffer<T{0}> b{0}", // IBufferElementData
|
|
"in DynamicBuffer<T{0}> k{0}", // in IBufferElementData
|
|
"T{0} s{0}", // ISharedComponentData
|
|
};
|
|
|
|
string[] FwdParam =
|
|
{
|
|
"ref d{0}", // ref ComponentData
|
|
"i{0}", // in ComponentData
|
|
"c{0}", // class
|
|
"b{0}", // IBufferElementData
|
|
"k{0}", // in IBufferElementData
|
|
"s{0}", // ISharedComponentData
|
|
};
|
|
|
|
string GetDelegateParameters(Category[] categories, bool hasEntity)
|
|
{
|
|
var parts = categories.Select((c, i) => string.Format(Param[(int)c], i));
|
|
if (hasEntity)
|
|
parts = parts.Prepend("Entity entity");
|
|
return string.Join(", ", parts);
|
|
}
|
|
|
|
string[] GenericConstraints =
|
|
{
|
|
"where T{0} : struct, IComponentData", // ref ComponentData
|
|
"where T{0} : struct, IComponentData", // in ComponentData
|
|
"where T{0} : class", // class
|
|
"where T{0} : struct, IBufferElementData", // IBufferElementData
|
|
"where T{0} : struct, IBufferElementData", // in IBufferElementData
|
|
"where T{0} : struct, ISharedComponentData", // ISharedComponentData
|
|
};
|
|
|
|
IEnumerable<string> GetGenericConstraints(Category[] categories) =>
|
|
categories.Select((c, i) => string.Format(GenericConstraints[(int)c], i));
|
|
|
|
string[] AccessFunction =
|
|
{
|
|
"GetArchetypeChunkComponentType", // ref ComponentData
|
|
"GetArchetypeChunkComponentType", // in ComponentData
|
|
"GetArchetypeChunkComponentType", // class
|
|
"GetArchetypeChunkBufferType", // IBufferElementData
|
|
"GetArchetypeChunkBufferType", // in IBufferElementData
|
|
"GetArchetypeChunkSharedComponentType", // ISharedComponentData
|
|
};
|
|
|
|
static string[] IsReadOnly=
|
|
{
|
|
"false", // ref ComponentData
|
|
"true", // in ComponentData
|
|
"", // class
|
|
"false", // IBufferElementData
|
|
"true", // in IBufferElementData
|
|
"", // ISharedComponentData
|
|
};
|
|
|
|
string[] ChunkGetArray =
|
|
{
|
|
"GetNativeArray(chunkComponentType{0}).GetUnsafePtr()", // ref ComponentData
|
|
"GetNativeArray(chunkComponentType{0}).GetUnsafeReadOnlyPtr()", // in ComponentData
|
|
"GetComponentObjects(chunkComponentType{0}, m_System.EntityManager)", // class
|
|
"GetBufferAccessor(chunkComponentType{0})", // IBufferElementData
|
|
"GetBufferAccessor(chunkComponentType{0})", // in IBufferElementData
|
|
"GetSharedComponentData(chunkComponentType{0}, m_System.EntityManager)", // ISharedComponentData
|
|
};
|
|
|
|
string[] ArrayAccess =
|
|
{
|
|
"ref UnsafeUtilityEx.ArrayElementAsRef<T{0}>(array{0}, i)", // ref ComponentData
|
|
"in UnsafeUtilityEx.ArrayElementAsRef<T{0}>(array{0}, i)", // in ComponentData
|
|
"array{0}[i]", // class
|
|
"array{0}[i]", // IBufferElementData
|
|
"array{0}[i]", // in IBufferElementData
|
|
"array{0}", // ISharedComponentData
|
|
};
|
|
|
|
string GetActionParams(Category[] categories, bool hasEntity)
|
|
{
|
|
var parts = categories.Select((c, i) => string.Format(ArrayAccess[(int)c], i));
|
|
if (hasEntity)
|
|
parts = parts.Prepend("entityArray[i]");
|
|
return string.Join(", ", parts);
|
|
}
|
|
|
|
static List<Category[]> InitCombinations()
|
|
{
|
|
var combinations = new List<Category[]>();
|
|
|
|
GetCombinations(new[] { Category.D, Category.C, Category.B, Category.S }, new Category[0], 1);
|
|
|
|
var baseCount = combinations.Count;
|
|
for (int i = 0; i != baseCount; ++i)
|
|
GetCombinations(new[] { Category.D }, combinations[i], 5);
|
|
for (int i = 0; i != baseCount; ++i)
|
|
GetCombinations(new[] { Category.C }, combinations[i], 5);
|
|
for (int i = 0; i != baseCount; ++i)
|
|
GetCombinations(new[] { Category.B }, combinations[i], 5);
|
|
|
|
combinations.Insert(0, new Category[0]);
|
|
|
|
void GetCombinations(Category[] supported, Category[] parent, int depth)
|
|
{
|
|
for (int i = 0; i != supported.Length; ++i)
|
|
{
|
|
var categories = new Category[parent.Length + 1];
|
|
parent.CopyTo(categories, 0);
|
|
categories[categories.Length - 1] = supported[i];
|
|
|
|
combinations.Add(categories);
|
|
|
|
if (depth-1 > 0)
|
|
GetCombinations(supported, categories, depth-1);
|
|
}
|
|
}
|
|
|
|
return combinations;
|
|
}
|
|
|
|
// misc support utils
|
|
|
|
class SmartElement<T>
|
|
{
|
|
public T Value;
|
|
public int Index;
|
|
public int Count;
|
|
|
|
public bool First => Index == 0;
|
|
public bool Last => Index == Count - 1;
|
|
|
|
public string IfFirst(string text) => First ? text : "";
|
|
public string IfLast(string text) => Last ? text : "";
|
|
}
|
|
|
|
static IEnumerable<SmartElement<T>> Smart<T>(IEnumerable<T> items)
|
|
{
|
|
var list = items.ToList();
|
|
for (var i = 0; i < list.Count; ++i)
|
|
yield return new SmartElement<T> { Value = list[i], Index = i, Count = list.Count };
|
|
}
|
|
|
|
static string Series(string formatString, int count, string separator) =>
|
|
string.Join(separator, Enumerable.Range(0, count).Select(i => string.Format(formatString, i)));
|
|
#>
|