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

555 行
21 KiB

using System;
using System.Diagnostics;
using Unity.Assertions;
using Unity.Collections.LowLevel.Unsafe;
namespace Unity.Entities
{
internal static unsafe class ChunkDataUtility
{
public static int GetIndexInTypeArray(Archetype* archetype, int typeIndex)
{
var types = archetype->Types;
var typeCount = archetype->TypesCount;
for (var i = 0; i != typeCount; i++)
if (typeIndex == types[i].TypeIndex)
return i;
return -1;
}
public static int GetTypeIndexFromType(Archetype* archetype, Type componentType)
{
var types = archetype->Types;
var typeCount = archetype->TypesCount;
for (var i = 0; i != typeCount; i++)
if (componentType.IsAssignableFrom(TypeManager.GetType(types[i].TypeIndex)))
return types[i].TypeIndex;
return -1;
}
public static void GetIndexInTypeArray(Archetype* archetype, int typeIndex, ref int typeLookupCache)
{
var types = archetype->Types;
var typeCount = archetype->TypesCount;
if (typeLookupCache < typeCount && types[typeLookupCache].TypeIndex == typeIndex)
return;
for (var i = 0; i != typeCount; i++)
{
if (typeIndex != types[i].TypeIndex)
continue;
typeLookupCache = i;
return;
}
#if ENABLE_UNITY_COLLECTIONS_CHECKS
throw new InvalidOperationException("Shouldn't happen");
#endif
}
public static int GetSizeInChunk(Chunk* chunk, int typeIndex, ref int typeLookupCache)
{
var archetype = chunk->Archetype;
GetIndexInTypeArray(archetype, typeIndex, ref typeLookupCache);
var indexInTypeArray = typeLookupCache;
var sizeOf = archetype->SizeOfs[indexInTypeArray];
return sizeOf;
}
public static byte* GetComponentDataWithTypeRO(Chunk* chunk, int index, int typeIndex, ref int typeLookupCache)
{
var archetype = chunk->Archetype;
GetIndexInTypeArray(archetype, typeIndex, ref typeLookupCache);
var indexInTypeArray = typeLookupCache;
var offset = archetype->Offsets[indexInTypeArray];
var sizeOf = archetype->SizeOfs[indexInTypeArray];
return chunk->Buffer + (offset + sizeOf * index);
}
public static byte* GetComponentDataWithTypeRW(Chunk* chunk, int index, int typeIndex, uint globalSystemVersion,
ref int typeLookupCache)
{
var archetype = chunk->Archetype;
GetIndexInTypeArray(archetype, typeIndex, ref typeLookupCache);
var indexInTypeArray = typeLookupCache;
var offset = archetype->Offsets[indexInTypeArray];
var sizeOf = archetype->SizeOfs[indexInTypeArray];
chunk->SetChangeVersion(indexInTypeArray, globalSystemVersion);
return chunk->Buffer + (offset + sizeOf * index);
}
public static byte* GetComponentDataWithTypeRO(Chunk* chunk, int index, int typeIndex)
{
var indexInTypeArray = GetIndexInTypeArray(chunk->Archetype, typeIndex);
var offset = chunk->Archetype->Offsets[indexInTypeArray];
var sizeOf = chunk->Archetype->SizeOfs[indexInTypeArray];
return chunk->Buffer + (offset + sizeOf * index);
}
public static byte* GetComponentDataWithTypeRW(Chunk* chunk, int index, int typeIndex, uint globalSystemVersion)
{
var indexInTypeArray = GetIndexInTypeArray(chunk->Archetype, typeIndex);
var offset = chunk->Archetype->Offsets[indexInTypeArray];
var sizeOf = chunk->Archetype->SizeOfs[indexInTypeArray];
chunk->SetChangeVersion(indexInTypeArray, globalSystemVersion);
return chunk->Buffer + (offset + sizeOf * index);
}
public static byte* GetComponentDataRO(Chunk* chunk, int index, int indexInTypeArray)
{
var offset = chunk->Archetype->Offsets[indexInTypeArray];
var sizeOf = chunk->Archetype->SizeOfs[indexInTypeArray];
return chunk->Buffer + (offset + sizeOf * index);
}
public static byte* GetComponentDataRW(Chunk* chunk, int index, int indexInTypeArray, uint globalSystemVersion)
{
var offset = chunk->Archetype->Offsets[indexInTypeArray];
var sizeOf = chunk->Archetype->SizeOfs[indexInTypeArray];
chunk->SetChangeVersion(indexInTypeArray, globalSystemVersion);
return chunk->Buffer + (offset + sizeOf * index);
}
public static void Copy(Chunk* srcChunk, int srcIndex, Chunk* dstChunk, int dstIndex, int count)
{
Assert.IsTrue(srcChunk->Archetype == dstChunk->Archetype);
var arch = srcChunk->Archetype;
var srcBuffer = srcChunk->Buffer;
var dstBuffer = dstChunk->Buffer;
var offsets = arch->Offsets;
var sizeOfs = arch->SizeOfs;
var typesCount = arch->TypesCount;
for (var t = 0; t < typesCount; t++)
{
var offset = offsets[t];
var sizeOf = sizeOfs[t];
var src = srcBuffer + (offset + sizeOf * srcIndex);
var dst = dstBuffer + (offset + sizeOf * dstIndex);
UnsafeUtility.MemCpy(dst, src, sizeOf * count);
}
}
public static void SwapComponents(Chunk* srcChunk, int srcIndex, Chunk* dstChunk, int dstIndex, int count, uint srcGlobalSystemVersion, uint dstGlobalSystemVersion)
{
var srcArch = srcChunk->Archetype;
var typesCount = srcArch->TypesCount;
#if UNITY_ASSERTIONS
// This function is used to swap data between different world so assert that the layout is identical if
// the archetypes dont match
var dstArch = dstChunk->Archetype;
if (srcArch != dstArch)
{
Assert.AreEqual(typesCount, dstChunk->Archetype->TypesCount);
for (int i = 0; i < typesCount; ++i)
{
Assert.AreEqual(srcArch->Types[i], dstArch->Types[i]);
Assert.AreEqual(srcArch->Offsets[i], dstArch->Offsets[i]);
Assert.AreEqual(srcArch->SizeOfs[i], dstArch->SizeOfs[i]);
}
}
#endif
var srcBuffer = srcChunk->Buffer;
var dstBuffer = dstChunk->Buffer;
var offsets = srcArch->Offsets;
var sizeOfs = srcArch->SizeOfs;
for (var t = 1; t < typesCount; t++) // Only swap component data, not Entity
{
var offset = offsets[t];
var sizeOf = sizeOfs[t];
var src = srcBuffer + (offset + sizeOf * srcIndex);
var dst = dstBuffer + (offset + sizeOf * dstIndex);
Byte* buffer = stackalloc Byte[sizeOf * count];
dstChunk->SetChangeVersion(t, dstGlobalSystemVersion);
srcChunk->SetChangeVersion(t, srcGlobalSystemVersion);
UnsafeUtility.MemCpy(buffer, src, sizeOf * count);
UnsafeUtility.MemCpy(src, dst, sizeOf * count);
UnsafeUtility.MemCpy(dst, buffer, sizeOf * count);
}
}
public static void InitializeComponents(Chunk* dstChunk, int dstIndex, int count)
{
var arch = dstChunk->Archetype;
var offsets = arch->Offsets;
var sizeOfs = arch->SizeOfs;
var bufferCapacities = arch->BufferCapacities;
var dstBuffer = dstChunk->Buffer;
var typesCount = arch->TypesCount;
var types = arch->Types;
for (var t = 1; t != typesCount; t++)
{
var offset = offsets[t];
var sizeOf = sizeOfs[t];
var dst = dstBuffer + (offset + sizeOf * dstIndex);
if (types[t].IsBuffer)
{
for (var i = 0; i < count; ++i)
{
BufferHeader.Initialize((BufferHeader*)dst, bufferCapacities[t]);
dst += sizeOf;
}
}
else
{
UnsafeUtility.MemClear(dst, sizeOf * count);
}
}
}
public static void ReplicateComponents(Chunk* srcChunk, int srcIndex, Chunk* dstChunk, int dstBaseIndex, int count)
{
var srcArchetype = srcChunk->Archetype;
var srcBuffer = srcChunk->Buffer;
var dstBuffer = dstChunk->Buffer;
var dstArchetype = dstChunk->Archetype;
var srcOffsets = srcArchetype->Offsets;
var srcSizeOfs = srcArchetype->SizeOfs;
var srcBufferCapacities = srcArchetype->BufferCapacities;
var srcTypesCount = srcArchetype->TypesCount;
var srcTypes = srcArchetype->Types;
var dstTypes = dstArchetype->Types;
var dstOffsets = dstArchetype->Offsets;
var dstTypeIndex = 1;
// type[0] is always Entity, and will be patched up later, so just skip
for (var srcTypeIndex = 1; srcTypeIndex != srcTypesCount; srcTypeIndex++)
{
var srcType = srcTypes[srcTypeIndex];
var dstType = dstTypes[dstTypeIndex];
// Type does not exist in destination. Skip it.
if (srcType.TypeIndex != dstType.TypeIndex)
continue;
var srcOffset = srcOffsets[srcTypeIndex];
var srcSizeOf = srcSizeOfs[srcTypeIndex];
var dstOffset = dstOffsets[dstTypeIndex];
var src = srcBuffer + (srcOffset + srcSizeOf * srcIndex);
var dst = dstBuffer + (dstOffset + srcSizeOf * dstBaseIndex);
if (!srcType.IsBuffer)
{
UnsafeUtility.MemCpyReplicate(dst, src, srcSizeOf, count);
}
else
{
var srcBufferCapacity = srcBufferCapacities[srcTypeIndex];
var alignment = 8; // TODO: Need a way to compute proper alignment for arbitrary non-generic types in TypeManager
var elementSize = TypeManager.GetTypeInfo(srcType.TypeIndex).ElementSize;
for (int i = 0; i < count; ++i)
{
BufferHeader* srcHdr = (BufferHeader*) src;
BufferHeader* dstHdr = (BufferHeader*) dst;
BufferHeader.Initialize(dstHdr, srcBufferCapacity);
BufferHeader.Assign(dstHdr, BufferHeader.GetElementPointer(srcHdr), srcHdr->Length, elementSize, alignment);
dst += srcSizeOf;
}
}
dstTypeIndex++;
}
}
public static void Convert(Chunk* srcChunk, int srcIndex, Chunk* dstChunk, int dstIndex, int count)
{
var srcArch = srcChunk->Archetype;
var dstArch = dstChunk->Archetype;
//Debug.Log($"Convert {EntityManager.EntityManagerDebug.GetArchetypeDebugString(srcArch)} to {EntityManager.EntityManagerDebug.GetArchetypeDebugString(dstArch)}");
var srcI = 0;
var dstI = 0;
while (srcI < srcArch->NonZeroSizedTypesCount && dstI < dstArch->NonZeroSizedTypesCount)
{
var srcStride = srcArch->SizeOfs[srcI];
var dstStride = dstArch->SizeOfs[dstI];
var src = srcChunk->Buffer + srcArch->Offsets[srcI] + srcIndex * srcStride;
var dst = dstChunk->Buffer + dstArch->Offsets[dstI] + dstIndex * dstStride;
if (srcArch->Types[srcI] < dstArch->Types[dstI])
{
// Clear any buffers we're not going to keep.
if (srcArch->Types[srcI].IsBuffer)
{
var srcPtr = src;
for(int i = 0; i < count; i++)
{
BufferHeader.Destroy((BufferHeader*)srcPtr);
srcPtr += srcStride;
}
}
++srcI;
}
else if (srcArch->Types[srcI] > dstArch->Types[dstI])
{
// Clear components in the destination that aren't copied
if (dstArch->Types[dstI].IsBuffer)
{
var bufferCapacity = dstArch->BufferCapacities[dstI];
var dstPtr = dst;
for(int i = 0; i < count; i++)
{
BufferHeader.Initialize((BufferHeader*)dstPtr, bufferCapacity);
dstPtr += dstStride;
}
}
else
{
UnsafeUtility.MemClear(dst, count * dstStride);
}
++dstI;
}
else
{
UnsafeUtility.MemCpy(dst, src, count * srcStride);
// Poison source buffer to make sure there is no aliasing.
if (srcArch->Types[srcI].IsBuffer)
{
var bufferCapacity = srcArch->BufferCapacities[srcI];
var srcPtr = src;
for(int i = 0; i < count; i++)
{
BufferHeader.Initialize((BufferHeader*)srcPtr, bufferCapacity);
srcPtr += srcStride;
}
}
++srcI;
++dstI;
}
}
// Handle remaining components in the source that aren't copied
for (; srcI < srcArch->NonZeroSizedTypesCount; ++srcI)
{
var srcStride = srcArch->SizeOfs[srcI];
var src = srcChunk->Buffer + srcArch->Offsets[srcI] + srcIndex * srcStride;
if (srcArch->Types[srcI].IsBuffer)
{
var srcPtr = src;
for(int i = 0; i < count; i++)
{
BufferHeader.Destroy((BufferHeader*)srcPtr);
srcPtr += srcStride;
}
}
}
// Clear remaining components in the destination that aren't copied
for (; dstI < dstArch->NonZeroSizedTypesCount; ++dstI)
{
var dstStride = dstArch->SizeOfs[dstI];
var dst = dstChunk->Buffer + dstArch->Offsets[dstI] + dstIndex * dstStride;
if (dstArch->Types[dstI].IsBuffer)
{
var bufferCapacity = dstArch->BufferCapacities[dstI];
var dstPtr = dst;
for (int i = 0; i < count; i++)
{
BufferHeader.Initialize((BufferHeader*)dstPtr, bufferCapacity);
dstPtr += dstStride;
}
}
else
{
UnsafeUtility.MemClear(dst, count * dstStride);
}
}
}
public static void Convert(Chunk* srcChunk, int srcIndex, Chunk* dstChunk, int dstIndex)
{
var srcArch = srcChunk->Archetype;
var dstArch = dstChunk->Archetype;
//Debug.Log($"Convert {EntityManager.EntityManagerDebug.GetArchetypeDebugString(srcArch)} to {EntityManager.EntityManagerDebug.GetArchetypeDebugString(dstArch)}");
var srcI = 0;
var dstI = 0;
while (srcI < srcArch->TypesCount && dstI < dstArch->TypesCount)
{
var src = srcChunk->Buffer + srcArch->Offsets[srcI] + srcIndex * srcArch->SizeOfs[srcI];
var dst = dstChunk->Buffer + dstArch->Offsets[dstI] + dstIndex * dstArch->SizeOfs[dstI];
if (srcArch->Types[srcI] < dstArch->Types[dstI])
{
// Clear any buffers we're not going to keep.
if (srcArch->Types[srcI].IsBuffer)
{
BufferHeader.Destroy((BufferHeader*)src);
}
++srcI;
}
else if (srcArch->Types[srcI] > dstArch->Types[dstI])
{
// Clear components in the destination that aren't copied
if (dstArch->Types[dstI].IsBuffer)
{
BufferHeader.Initialize((BufferHeader*)dst, dstArch->BufferCapacities[dstI]);
}
else
{
UnsafeUtility.MemClear(dst, dstArch->SizeOfs[dstI]);
}
++dstI;
}
else
{
UnsafeUtility.MemCpy(dst, src, srcArch->SizeOfs[srcI]);
// Poison source buffer to make sure there is no aliasing.
if (srcArch->Types[srcI].IsBuffer)
{
BufferHeader.Initialize((BufferHeader*)src, srcArch->BufferCapacities[srcI]);
}
++srcI;
++dstI;
}
}
// Handle remaining components in the source that aren't copied
for (; srcI < srcArch->TypesCount; ++srcI)
{
var src = srcChunk->Buffer + srcArch->Offsets[srcI] + srcIndex * srcArch->SizeOfs[srcI];
if (srcArch->Types[srcI].IsBuffer)
{
BufferHeader.Destroy((BufferHeader*)src);
}
}
// Clear remaining components in the destination that aren't copied
for (; dstI < dstArch->TypesCount; ++dstI)
{
var dst = dstChunk->Buffer + dstArch->Offsets[dstI] + dstIndex * dstArch->SizeOfs[dstI];
if (dstArch->Types[dstI].IsBuffer)
{
BufferHeader.Initialize((BufferHeader*)dst, dstArch->BufferCapacities[dstI]);
}
else
{
UnsafeUtility.MemClear(dst, dstArch->SizeOfs[dstI]);
}
}
}
public static void MemsetUnusedChunkData(Chunk* chunk, byte value)
{
var arch = chunk->Archetype;
var bufferSize = Chunk.GetChunkBufferSize();
var buffer = chunk->Buffer;
var count = chunk->Count;
for (int i = 0; i<arch->TypesCount-1; ++i)
{
var index = arch->TypeMemoryOrder[i];
var nextIndex = arch->TypeMemoryOrder[i + 1];
var startOffset = arch->Offsets[index] + count * arch->SizeOfs[index];
var endOffset = arch->Offsets[nextIndex];
UnsafeUtilityEx.MemSet(buffer + startOffset, value, endOffset - startOffset);
}
var lastIndex = arch->TypeMemoryOrder[arch->TypesCount - 1];
var lastStartOffset = arch->Offsets[lastIndex] + count * arch->SizeOfs[lastIndex];
UnsafeUtilityEx.MemSet(buffer + lastStartOffset, value, bufferSize - lastStartOffset);
}
public static bool AreLayoutCompatible(Archetype* a, Archetype* b)
{
if ((a == null) || (b == null))
return false;
var typeCount = a->NonZeroSizedTypesCount;
if (typeCount != b->NonZeroSizedTypesCount)
return false;
for (int i = 0; i < typeCount; ++i)
{
if (a->Types[i] != b->Types[i])
return false;
}
return true;
}
[Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
public static void AssertAreLayoutCompatible(Archetype* a, Archetype* b)
{
Assert.IsTrue(AreLayoutCompatible(a,b));
Assert.AreEqual(a->BytesPerInstance, b->BytesPerInstance);
Assert.AreEqual(a->ChunkCapacity, b->ChunkCapacity);
var typeCount = a->NonZeroSizedTypesCount;
//If types are identical; SizeOfs, Offsets and BufferCapacities should match
for (int i = 0; i < typeCount; ++i)
{
Assert.AreEqual(a->SizeOfs[i], b->SizeOfs[i]);
Assert.AreEqual(a->Offsets[i], b->Offsets[i]);
Assert.AreEqual(a->BufferCapacities[i], b->BufferCapacities[i]);
}
}
public static void DeallocateBuffers(Chunk* chunk)
{
var archetype = chunk->Archetype;
for (var ti = 0; ti < archetype->TypesCount; ++ti)
{
var type = archetype->Types[ti];
if (!type.IsBuffer)
continue;
var basePtr = chunk->Buffer + archetype->Offsets[ti];
var stride = archetype->SizeOfs[ti];
for (int i = 0; i < chunk->Count; ++i)
{
byte* bufferPtr = basePtr + stride * i;
BufferHeader.Destroy((BufferHeader*) bufferPtr);
}
}
}
}
}