您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
358 行
14 KiB
358 行
14 KiB
using System;
|
|
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 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 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->ChangeVersion[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->ChangeVersion[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->ChangeVersion[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);
|
|
|
|
dstChunk->ChangeVersion[t] = srcChunk->ChangeVersion[t];
|
|
UnsafeUtility.MemCpy(dst, src, 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 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, types[t].BufferCapacity);
|
|
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 dstArchetype = dstChunk->Archetype;
|
|
var srcBuffer = srcChunk->Buffer;
|
|
var dstBuffer = dstChunk->Buffer;
|
|
var srcOffsets = srcArchetype->Offsets;
|
|
var srcSizeOfs = srcArchetype->SizeOfs;
|
|
var srcTypesCount = srcArchetype->TypesCount;
|
|
var srcTypes = srcArchetype->Types;
|
|
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 = srcTypes[dstTypeIndex];
|
|
|
|
// Type does not exist in destination. Skip it.
|
|
if (srcType.TypeIndex != dstType.TypeIndex)
|
|
continue;
|
|
|
|
var srcOffset = srcOffsets[srcTypeIndex];
|
|
var srcSizeOf = srcSizeOfs[srcTypeIndex];
|
|
|
|
var src = srcBuffer + (srcOffset + srcSizeOf * srcIndex);
|
|
var dst = dstBuffer + (srcOffset + srcSizeOf * dstBaseIndex);
|
|
|
|
if (!srcType.IsBuffer)
|
|
{
|
|
UnsafeUtility.MemCpyReplicate(dst, src, srcSizeOf, count);
|
|
}
|
|
else
|
|
{
|
|
var alignment = 8; // TODO: Need a way to compute proper alignment for arbitrary non-generic types in TypeManager
|
|
for (int i = 0; i < count; ++i)
|
|
{
|
|
BufferHeader* srcHdr = (BufferHeader*) src;
|
|
BufferHeader* dstHdr = (BufferHeader*) dst;
|
|
BufferHeader.Initialize(dstHdr, srcType.BufferCapacity);
|
|
BufferHeader.Assign(dstHdr, BufferHeader.GetElementPointer(srcHdr), srcHdr->Length, srcSizeOf, alignment);
|
|
|
|
src += srcSizeOf;
|
|
dst += srcSizeOf;
|
|
}
|
|
}
|
|
|
|
dstTypeIndex++;
|
|
}
|
|
}
|
|
|
|
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->Types[dstI].BufferCapacity);
|
|
}
|
|
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->Types[srcI].BufferCapacity);
|
|
}
|
|
|
|
++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->Types[dstI].BufferCapacity);
|
|
}
|
|
else
|
|
{
|
|
UnsafeUtility.MemClear(dst, dstArch->SizeOfs[dstI]);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void PoisonUnusedChunkData(Chunk* chunk, byte value)
|
|
{
|
|
var arch = chunk->Archetype;
|
|
var bufferSize = Chunk.GetChunkBufferSize(arch->TypesCount, arch->NumSharedComponents);
|
|
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 void CopyManagedObjects(ArchetypeManager typeMan, Chunk* srcChunk, int srcStartIndex,
|
|
Chunk* dstChunk, int dstStartIndex, int count)
|
|
{
|
|
var srcArch = srcChunk->Archetype;
|
|
var dstArch = dstChunk->Archetype;
|
|
|
|
var srcI = 0;
|
|
var dstI = 0;
|
|
while (srcI < srcArch->TypesCount && dstI < dstArch->TypesCount)
|
|
if (srcArch->Types[srcI] < dstArch->Types[dstI])
|
|
{
|
|
++srcI;
|
|
}
|
|
else if (srcArch->Types[srcI] > dstArch->Types[dstI])
|
|
{
|
|
++dstI;
|
|
}
|
|
else
|
|
{
|
|
if (srcArch->ManagedArrayOffset[srcI] >= 0)
|
|
for (var i = 0; i < count; ++i)
|
|
{
|
|
var obj = typeMan.GetManagedObject(srcChunk, srcI, srcStartIndex + i);
|
|
typeMan.SetManagedObject(dstChunk, dstI, dstStartIndex + i, obj);
|
|
}
|
|
|
|
++srcI;
|
|
++dstI;
|
|
}
|
|
}
|
|
|
|
public static void ClearManagedObjects(ArchetypeManager typeMan, Chunk* chunk, int index, int count)
|
|
{
|
|
var arch = chunk->Archetype;
|
|
|
|
for (var type = 0; type < arch->TypesCount; ++type)
|
|
{
|
|
if (arch->ManagedArrayOffset[type] < 0)
|
|
continue;
|
|
|
|
for (var i = 0; i < count; ++i)
|
|
typeMan.SetManagedObject(chunk, type, index + i, null);
|
|
}
|
|
}
|
|
}
|
|
}
|