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

925 行
33 KiB

using NUnit.Framework;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
namespace Unity.Entities.Tests
{
public class WorldDiffTestFixture
{
protected World m_PreviousWorld;
protected World m_Shadow;
protected World m_After;
protected World m_DstWorld;
protected EntityManager m_Manager;
protected EntityManager m_DstManager;
// There's no particular meaning to this bit pattern. The important thing is that the whole bit pattern isn't 0.
// If all the bits are 0, then the GUID has the special value of NULL ("invalid") GUID.
public static EntityGuid GenerateEntityGuid(int i)
{
return new EntityGuid {a = (ulong)i, b = ~(ulong)i};
}
[SetUp]
public void SetUp()
{
m_PreviousWorld = World.Active;
m_Shadow = new World("Before");
m_After = new World("After");
m_DstWorld = new World("DstWorld");
m_Manager = m_After.EntityManager;
m_DstManager = m_DstWorld.EntityManager;
}
[TearDown]
public void TearDown()
{
World.Active = m_PreviousWorld;
m_Shadow.EntityManager.Debug.CheckInternalConsistency();
m_After.EntityManager.Debug.CheckInternalConsistency();
m_DstWorld.EntityManager.Debug.CheckInternalConsistency();
m_Shadow.Dispose();
m_After.Dispose();
m_DstWorld.Dispose();
}
public NativeHashMap<EntityGuid, Entity> BuildLookup()
{
var map = new NativeHashMap<EntityGuid, Entity>(m_DstManager.Debug.EntityCount, Allocator.Temp);
var entities = m_DstManager.GetAllEntities();
foreach (var e in entities)
{
var guidOnEntity = m_DstManager.GetComponentData<EntityGuid>(e);
Assert.IsTrue(map.TryAdd(guidOnEntity, e));
}
return map;
}
public T GetDstWorldData<T>(EntityGuid guid, NativeHashMap<EntityGuid, Entity> lookup) where T : struct, IComponentData
{
var e = lookup[guid];
return m_DstManager.GetComponentData<T>(e);
}
public T GetDstWorldSharedData<T>(EntityGuid guid, NativeHashMap<EntityGuid, Entity> lookup) where T : struct, ISharedComponentData
{
var e = lookup[guid];
return m_DstManager.GetSharedComponentData<T>(e);
}
public bool HasDstWorldData<T>(EntityGuid guid, NativeHashMap<EntityGuid, Entity> lookup) where T : struct
{
var e = lookup[guid];
return m_DstManager.HasComponent<T>(e);
}
public void SetDstWorldData<T>(EntityGuid guid, T value, NativeHashMap<EntityGuid, Entity> lookup) where T : struct, IComponentData
{
var e = lookup[guid];
m_DstManager.SetComponentData(e, value);
}
public T GetDstWorldData<T>(EntityGuid guid) where T : struct, IComponentData
{
var entities = m_DstManager.GetAllEntities();
foreach (var e in entities)
{
var guidOnEntity = m_DstManager.GetComponentData<EntityGuid>(e);
if (guidOnEntity .Equals(guid))
return m_DstManager.GetComponentData<T>(e);
}
throw new System.ArgumentException($"Couldn't find {guid}");
}
public static Entity GetEntityByGuid(EntityManager mgr, EntityGuid guid)
{
var entities = mgr.GetAllEntities();
foreach (var e in entities)
{
var guidOnEntity = mgr.GetComponentData<EntityGuid>(e);
if (guidOnEntity.Equals(guid))
return e;
}
return default(Entity);
}
public Entity GetDstWorldEntity(EntityGuid guid)
{
return GetEntityByGuid(m_DstManager, guid);
}
public T GetDstWorldSharedData<T>(EntityGuid guid) where T : struct, ISharedComponentData
{
var entities = m_DstManager.GetAllEntities();
foreach (var e in entities)
{
var guidOnEntity = m_DstManager.GetComponentData<EntityGuid>(e);
if (guidOnEntity .Equals(guid))
return m_DstManager.GetSharedComponentData<T>(e);
}
throw new System.ArgumentException($"Couldn't find {guid}");
}
public bool HasDstWorldData<T>(EntityGuid guid) where T : struct, IComponentData
{
var entities = m_DstManager.GetAllEntities();
foreach (var e in entities)
{
var guidOnEntity = m_DstManager.GetComponentData<EntityGuid>(e);
if (guidOnEntity.Equals(guid))
return m_DstManager.HasComponent<T>(e);
}
throw new System.ArgumentException($"Couldn't find {guid}");
}
public void SetDstWorldData<T>(EntityGuid guid, T value) where T : struct, IComponentData
{
var entities = m_DstManager.GetAllEntities();
foreach (var e in entities)
{
var guidOnEntity = m_DstManager.GetComponentData<EntityGuid>(e);
if (guidOnEntity.Equals(guid))
{
m_DstManager.SetComponentData(e, value);
return;
}
}
throw new System.ArgumentException($"Couldn't find {guid}");
}
public void SyncDiff()
{
using (var diff = WorldDiffer.UpdateDiff(m_After, m_Shadow, Allocator.TempJob))
{
WorldDiffer.ApplyDiff(m_DstWorld, diff);
}
}
public void CreateStressData(int beginIndex, int endIndex, bool testData, bool testData2, bool testShared)
{
for (int i = beginIndex; i < endIndex; i++)
{
var guid = GenerateEntityGuid(i);
var e = m_Manager.CreateEntity();
m_Manager.AddComponentData(e, guid);
if (testData)
m_Manager.AddComponentData(e, new EcsTestData {value = i * 3});
if (testData2)
m_Manager.AddComponentData(e, new EcsTestData2 {value0 = i, value1 = i * 2});
if (testShared)
m_Manager.AddSharedComponentData(e, new EcsTestSharedComp() {value = i / 31});
}
}
public void TestStressData(int baseIndex, int endIndex, bool testData, bool testData2, bool testShared)
{
var lookup = BuildLookup();
for (int i = baseIndex; i < endIndex; i++)
{
var guid = GenerateEntityGuid(i);
if (testData)
Assert.AreEqual(i * 3, GetDstWorldData<EcsTestData>(guid, lookup).value);
else
Assert.IsFalse(HasDstWorldData<EcsTestData>(guid, lookup));
if (testData2)
{
Assert.AreEqual(i, GetDstWorldData<EcsTestData2>(guid, lookup).value0);
Assert.AreEqual(i * 2, GetDstWorldData<EcsTestData2>(guid, lookup).value1);
}
else
{
Assert.IsFalse(HasDstWorldData<EcsTestData2>(guid, lookup));
}
if (testShared)
Assert.AreEqual(i / 31, GetDstWorldSharedData<EcsTestSharedComp>(guid, lookup).value);
else
Assert.IsFalse(HasDstWorldData<EcsTestSharedComp>(guid, lookup));
}
lookup.Dispose();
}
}
public class WorldDiffTests : WorldDiffTestFixture
{
[Test]
[StandaloneFixme]
public void DiffOnly()
{
using (var diff = WorldDiffer.UpdateDiff(m_After, m_Shadow, Allocator.TempJob))
{
Assert.IsFalse(diff.HasChanges);
}
var guid = GenerateEntityGuid(0);
var e = m_Manager.CreateEntity(typeof(EntityGuid), typeof(EcsTestData));
m_Manager.SetComponentData(e, guid);
m_Manager.SetComponentData(e, new EcsTestData {value = 9});
using (var diff = WorldDiffer.UpdateDiff(m_After, m_Shadow, Allocator.TempJob))
{
Assert.AreEqual(0, diff.DeletedEntityCount);
Assert.AreEqual(1, diff.NewEntityCount);
Assert.AreEqual(2, diff.AddComponents.Length);
Assert.AreEqual(2, diff.SetCommands.Length);
}
m_Manager.SetComponentData(e, guid);
m_Manager.SetComponentData(e, new EcsTestData {value = 10});
using (var diff = WorldDiffer.UpdateDiff(m_After, m_Shadow, Allocator.TempJob))
{
Assert.AreEqual(0, diff.DeletedEntityCount);
Assert.AreEqual(0, diff.NewEntityCount);
Assert.AreEqual(1, diff.SetCommands.Length);
Assert.AreEqual(0, diff.AddComponents.Length);
}
m_Manager.DestroyEntity(e);
using (var diff = WorldDiffer.UpdateDiff(m_After, m_Shadow, Allocator.TempJob))
{
Assert.AreEqual(1, diff.DeletedEntityCount);
Assert.AreEqual(0, diff.NewEntityCount);
Assert.AreEqual(0, diff.SetCommands.Length);
Assert.AreEqual(0, diff.RemoveComponents.Length);
}
}
[Test]
[StandaloneFixme]
public void CreateWithComponentData()
{
var guid = GenerateEntityGuid(0);
var e = m_Manager.CreateEntity();
m_Manager.AddComponentData(e, guid );
m_Manager.AddComponentData(e, new EcsTestData {value = 9});
SyncDiff();
Assert.AreEqual(9, GetDstWorldData<EcsTestData>(guid).value);
}
[Test]
[StandaloneFixme]
public void CreateWithPrefabComponent()
{
var guid = GenerateEntityGuid(0);
var e = m_Manager.CreateEntity();
m_Manager.AddComponentData(e, guid );
m_Manager.AddComponentData(e, new Prefab());
SyncDiff();
Assert.IsTrue(HasDstWorldData<Prefab>(guid));
}
[Test]
[StandaloneFixme]
public void CreateWithDisabledComponent()
{
var guid = GenerateEntityGuid(0);
var e = m_Manager.CreateEntity();
m_Manager.AddComponentData(e, guid );
m_Manager.AddComponentData(e, new Disabled());
SyncDiff();
Assert.IsTrue(HasDstWorldData<Disabled>(guid));
}
[Test]
public void CreateWithPrefabAndDisabledComponent()
{
var guid = GenerateEntityGuid(0);
var e = m_Manager.CreateEntity();
m_Manager.AddComponentData(e, guid );
m_Manager.AddComponentData(e, new Prefab());
m_Manager.AddComponentData(e, new Disabled());
SyncDiff();
Assert.IsTrue(HasDstWorldData<Disabled>(guid));
Assert.IsTrue(HasDstWorldData<Prefab>(guid));
}
[Test]
[StandaloneFixme]
public void RemapEntityRef()
{
// Create extra entity to make sure test doesn't accidentally succeed with no remapping
m_Manager.CreateEntity();
var g0 = GenerateEntityGuid(0);
var g1 = GenerateEntityGuid(1);
var e0 = m_Manager.CreateEntity();
var e1 = m_Manager.CreateEntity();
m_Manager.AddComponentData(e0, g0);
m_Manager.AddComponentData(e0, new EcsTestDataEntity(){value1 = e1});
m_Manager.AddComponentData(e1, g1);
m_Manager.AddComponentData(e1, new EcsTestDataEntity(){value1 = e0});
SyncDiff();
Assert.AreEqual(GetDstWorldEntity(g1), GetDstWorldData<EcsTestDataEntity>(g0).value1);
Assert.AreEqual(GetDstWorldEntity(g0), GetDstWorldData<EcsTestDataEntity>(g1).value1);
}
[Test]
[StandaloneFixme]
public void MissingEntityRefBecomesNull()
{
var guid = GenerateEntityGuid(0);
var missing = m_Manager.CreateEntity();
var entity = m_Manager.CreateEntity();
m_Manager.AddComponentData(entity, guid);
m_Manager.AddComponentData(entity, new EcsTestDataEntity(){value1 = missing});
SyncDiff();
// missing entity has no GUID, so the reference becomes null.
Assert.AreEqual(Entity.Null, GetDstWorldData<EcsTestDataEntity>(guid).value1);
}
[Test]
[StandaloneFixme]
public void AddComponent()
{
var guid = GenerateEntityGuid(0);
var e = m_Manager.CreateEntity();
m_Manager.AddComponentData(e, guid );
m_Manager.AddComponentData(e, new EcsTestData {value = 9});
SyncDiff();
m_Manager.AddComponentData(e, new EcsTestData2(10));
SetDstWorldData(guid, new EcsTestData(-1));
SyncDiff();
Assert.AreEqual(-1, GetDstWorldData<EcsTestData>(guid).value);
Assert.AreEqual(10, GetDstWorldData<EcsTestData2>(guid).value0);
}
[Test]
[StandaloneFixme]
public void RemoveComponent()
{
var guid = GenerateEntityGuid(0);
var e = m_Manager.CreateEntity();
m_Manager.AddComponentData(e, guid );
m_Manager.AddComponentData(e, new EcsTestData(9));
m_Manager.AddComponentData(e, new EcsTestData2(7));
SyncDiff();
m_Manager.RemoveComponent<EcsTestData>(e);
SetDstWorldData(guid, new EcsTestData2(-1));
SyncDiff();
Assert.IsFalse(HasDstWorldData<EcsTestData>(guid));
Assert.AreEqual(-1, GetDstWorldData<EcsTestData2>(guid).value0);
}
[Test]
[StandaloneFixme]
public void CreateSharedComponent()
{
for (int i = 0; i != 3; i++)
{
var e = m_Manager.CreateEntity();
m_Manager.AddComponentData(e, GenerateEntityGuid(i));
m_Manager.AddSharedComponentData(e, new EcsTestSharedComp {value = i * 2});
}
SyncDiff();
for (int i = 0; i != 3; i++)
{
var sharedData = GetDstWorldSharedData<EcsTestSharedComp>(GenerateEntityGuid(i));
Assert.AreEqual(i * 2, sharedData.value);
}
}
[Test]
[StandaloneFixme]
public void ChangeSharedComponent()
{
var guid = GenerateEntityGuid(0);
var e = m_Manager.CreateEntity();
m_Manager.AddComponentData(e, guid);
m_Manager.AddSharedComponentData(e, new EcsTestSharedComp {value = 1});
SyncDiff();
Assert.AreEqual(1, GetDstWorldSharedData<EcsTestSharedComp>(guid).value);
m_Manager.SetSharedComponentData(e, new EcsTestSharedComp {value = 2});
SyncDiff();
Assert.AreEqual(2, GetDstWorldSharedData<EcsTestSharedComp>(guid).value);
}
[Test]
[StandaloneFixme]
public void SharedComponentDiff()
{
var e = m_Manager.CreateEntity();
var guid = GenerateEntityGuid(0);
m_Manager.AddComponentData(e, guid);
m_Manager.AddSharedComponentData(e, new EcsTestSharedComp {value = 2});
using (var diff = WorldDiffer.UpdateDiff(m_After, m_Shadow, Allocator.TempJob))
{
Assert.AreEqual(1, diff.NewEntityCount);
Assert.AreEqual(2, diff.AddComponents.Length);
Assert.AreEqual(1, diff.SetCommands.Length);
Assert.AreEqual(1, diff.SharedSetCommands.Length);
}
}
[Test]
[StandaloneFixme]
public void ChangeSrcAppliesToAllDstInstances([Values]bool prefabTag)
{
var guid = GenerateEntityGuid(0);
var prefab = m_Manager.CreateEntity();
m_Manager.AddComponentData(prefab, guid);
m_Manager.AddComponentData(prefab, new EcsTestData());
if (prefabTag)
m_Manager.AddComponentData(prefab, new Prefab());
SyncDiff();
var dstPrefab = GetDstWorldEntity(guid);
var dstInstance0 = m_DstManager.Instantiate(dstPrefab);
var dstInstance1 = m_DstManager.Instantiate(dstPrefab);
m_Manager.SetComponentData(prefab, new EcsTestData(10));
SyncDiff();
Assert.AreEqual(10, m_DstManager.GetComponentData<EcsTestData>(dstPrefab).value);
Assert.AreEqual(10, m_DstManager.GetComponentData<EcsTestData>(dstInstance0).value);
Assert.AreEqual(10, m_DstManager.GetComponentData<EcsTestData>(dstInstance1).value);
}
[Test]
[StandaloneFixme]
public void DynamicBuffer([Values(1, 100)]int bufferLength)
{
var guid = GenerateEntityGuid(0);
var e = m_Manager.CreateEntity();
m_Manager.AddComponentData(e, guid);
var buffer = m_Manager.AddBuffer<EcsIntElement>(e);
for (var i = 0; i < bufferLength; ++i)
buffer.Add(new EcsIntElement() { Value = i });
SyncDiff();
var f = GetDstWorldEntity(guid);
var dstBuffer = m_DstManager.GetBuffer<EcsIntElement>(f);
Assert.AreEqual(bufferLength, dstBuffer.Length);
for (int i = 0;i!= dstBuffer.Length;i++)
Assert.AreEqual(i, dstBuffer[i].Value);
}
[Test]
[StandaloneFixme]
public void DynamicBufferWithEntityStress()
{
int[] sizes = {10, 0, 100, 100, 7, 9, 13, 13, 13, 1};
// Create extra entity to make sure test doesn't accidentally succeed with no remapping
m_Manager.CreateEntity();
var targetEntityGuid = GenerateEntityGuid(0);
var targetEntity = m_Manager.CreateEntity();
m_Manager.AddComponentData(targetEntity, targetEntityGuid);
var guid = GenerateEntityGuid(1);
var e = m_Manager.CreateEntity();
m_Manager.AddComponentData(e, guid);
m_Manager.AddBuffer<EcsComplexEntityRefElement>(e);
for (int iter = 0;iter != sizes.Length;iter++)
{
var size = sizes[iter];
var buffer = m_Manager.GetBuffer<EcsComplexEntityRefElement>(e);
buffer.ResizeUninitialized(size);
var curTargetEntity = iter % 2 == 0 ? targetEntity : e;
for (var i = 0; i < size; ++i)
buffer[i] = new EcsComplexEntityRefElement { Dummy = i, Entity = curTargetEntity };
SyncDiff();
var dstTargetEntity = GetDstWorldEntity(iter % 2 == 0 ? targetEntityGuid : guid);
var dstEntity = GetDstWorldEntity(guid);
var dstBuffer = m_DstManager.GetBuffer<EcsComplexEntityRefElement>(dstEntity);
Assert.AreEqual(size, dstBuffer.Length);
for (var i = 0; i < size; ++i)
{
Assert.AreEqual(dstTargetEntity, dstBuffer[i].Entity);
Assert.AreEqual(i, dstBuffer[i].Dummy);
}
}
}
[Test]
[Ignore("Need field replacement - Should be driven by explicit opt-in attribute")]
public void ModifySingleProperty()
{
var guid = GenerateEntityGuid(0);
var e = m_Manager.CreateEntity();
m_Manager.AddComponentData(e, guid );
m_Manager.AddComponentData(e, new EcsTestData2 {value0 = 9, value1 = 11});
SyncDiff();
SetDstWorldData(guid, new EcsTestData2 {value0 = -1, value1 = -2});
m_Manager.SetComponentData(e, new EcsTestData2 {value0 = 9, value1 = 1023});
SyncDiff();
// Retain value from dst because it was not changed in src
Assert.AreEqual(-1, GetDstWorldData<EcsTestData2>(guid).value0);
// Change to new value in dst because it was changed in src
Assert.AreEqual(1023, GetDstWorldData<EcsTestData2>(guid).value1);
}
[Test]
[StandaloneFixme]
public void StressCreation()
{
// Add shared component to scramble src shared indices
var ent = m_Manager.CreateEntity();
m_Manager.AddSharedComponentData(ent, new EcsTestSharedComp(3));
CreateStressData(0, 99, false, true, false);
CreateStressData(99, 173, true, true, false);
CreateStressData(173, 250, true, true, true);
SyncDiff();
TestStressData(0, 99, false, true, false);
TestStressData(99, 173, true, true, false);
TestStressData(173, 250, true, true, true);
}
[Test]
[StandaloneFixme]
public void StressDestroyOnClient()
{
CreateStressData(0, 2000, false, true, false);
CreateStressData(2000, 4000, true, true, false);
SyncDiff();
m_DstManager.DestroyEntity(m_DstManager.GetAllEntities());
SyncDiff();
Assert.AreEqual(0, m_DstManager.GetAllEntities().Length);
}
[Test]
[StandaloneFixme]
public void StressDestroyOnServer()
{
CreateStressData(0, 2000, false, true, false);
CreateStressData(2000, 4000, true, true, false);
SyncDiff();
m_Manager.DestroyEntity(m_Manager.GetAllEntities());
SyncDiff();
Assert.AreEqual(0, m_DstManager.GetAllEntities().Length);
}
[Test]
[StandaloneFixme]
public void StressTestRecreation()
{
// Add shared component to scramble src shared indices
var ent = m_Manager.CreateEntity();
m_Manager.AddSharedComponentData(ent, new EcsTestSharedComp(3));
int end = 100;
CreateStressData(0, end, false, true, true);
SyncDiff();
for (int i = 0; i < 10; i++)
{
m_Manager.DestroyEntity(m_Manager.GetAllEntities());
CreateStressData(0, end, false, true, true);
using (var diff = WorldDiffer.UpdateDiff(m_After, m_Shadow, Allocator.TempJob))
{
Assert.IsFalse(diff.HasChanges);
WorldDiffer.ApplyDiff(m_DstWorld, diff);
}
TestStressData(0, end, false, true, true);
}
Assert.AreEqual(end, m_DstManager.GetAllEntities().Length);
}
[Test]
[Ignore("TODO")]
public void EntityIDOnComponentChangedButNotReferencedEntityGUID()
{
// Ensure that no change is generated in this case...
}
#if !UNITY_DOTSPLAYER
[TestCase("Manny")]
[TestCase("Moe")]
[TestCase("Jack")]
public void DebugNamesAreTransferred(string srcWorldName)
{
var guid = GenerateEntityGuid(0);
var srcWorldEntity = m_Manager.CreateEntity();
m_Manager.AddComponentData(srcWorldEntity, guid );
m_Manager.SetName(srcWorldEntity, srcWorldName);
SyncDiff();
var destWorldEntity = GetDstWorldEntity(guid);
var destWorldName = m_DstManager.GetName(destWorldEntity);
Assert.AreEqual(srcWorldName, destWorldName);
}
#endif
unsafe void Append<T>(ref NativeArray<T> array, T t) where T : struct
{
NativeArray<T> result = new NativeArray<T>(array.Length + 1, Allocator.TempJob);
UnsafeUtility.MemCpy(result.GetUnsafePtr(), array.GetUnsafePtr(), UnsafeUtility.SizeOf<T>() * array.Length);
UnsafeUtility.WriteArrayElement(result.GetUnsafePtr(), array.Length, t);
array.Dispose();
array = result;
}
[Test]
[StandaloneFixme]
public void EntityPatchWithMissingEntityDoesNotThrow()
{
var guid = GenerateEntityGuid(0);
var srcWorldEntity0 = m_Manager.CreateEntity();
m_Manager.AddComponentData(srcWorldEntity0, guid );
var srcWorldEntity1 = m_Manager.CreateEntity();
m_Manager.AddComponentData(srcWorldEntity1, guid );
var bogusGuid = GenerateEntityGuid(1);
Assert.DoesNotThrow(() =>
{
var diff = WorldDiffer.UpdateDiff(m_After, m_Shadow, Allocator.TempJob);
Append(ref diff.EntityPatches, new DiffEntityPatch {Guid = bogusGuid});
using (diff)
WorldDiffer.ApplyDiff(m_DstWorld, diff);
});
}
[Test]
[StandaloneFixme]
public void EntityPatchWithAmbiguousTargetDoesNotThrow()
{
var guid = GenerateEntityGuid(0);
var srcWorldEntity0 = m_Manager.CreateEntity();
m_Manager.AddComponentData(srcWorldEntity0, guid );
var dstWorldEntity0 = m_DstManager.CreateEntity();
m_DstManager.AddComponentData(dstWorldEntity0, guid );
Assert.DoesNotThrow(() =>
{
var diff = WorldDiffer.UpdateDiff(m_After, m_Shadow, Allocator.TempJob);
Append(ref diff.EntityPatches, new DiffEntityPatch {Guid = guid});
using (diff)
WorldDiffer.ApplyDiff(m_DstWorld, diff);
});
}
[Test]
[StandaloneFixme]
public void NewEntityIsReplicatedIntoExistingPrefabInstances([Values(1, 10)]int instanceCount)
{
var rootGUID = GenerateEntityGuid(1);
var childGUID = GenerateEntityGuid(2);
var root = m_Manager.CreateEntity(typeof(EcsTestDataEntity), typeof(Prefab), typeof(LinkedEntityGroup));
m_Manager.AddComponentData(root, rootGUID);
m_Manager.GetBuffer<LinkedEntityGroup>(root).Add(root);
SyncDiff();
var dstRootPrefab = GetDstWorldEntity(rootGUID);
// Instantiate root in dst world
var dstRootInstances = new Entity[instanceCount];
for (var i = 0; i != dstRootInstances.Length; i++)
{
var dstRootInstance = m_DstManager.Instantiate(GetDstWorldEntity(rootGUID));
dstRootInstances[i] = dstRootInstance;
Assert.AreEqual(1, m_DstManager.GetBuffer<LinkedEntityGroup>(dstRootInstance).Length);
Assert.AreEqual(dstRootInstance, m_DstManager.GetBuffer<LinkedEntityGroup>(dstRootInstance)[0].Value);
}
// Add a new entity into the prefab
var child = m_Manager.CreateEntity(typeof(EcsTestDataEntity), typeof(Prefab));
m_Manager.AddComponentData(child, childGUID);
m_Manager.GetBuffer<LinkedEntityGroup>(root).Add(child);
m_Manager.SetComponentData(root, new EcsTestDataEntity { value1 = child});
m_Manager.SetComponentData(child, new EcsTestDataEntity { value1 = root});
SyncDiff();
for (var i = 0; i != dstRootInstances.Length; i++)
{
var dstRootInstance = dstRootInstances[i];
var dstInstanceGroup = m_DstManager.GetBuffer<LinkedEntityGroup>(dstRootInstance);
Assert.AreEqual(2, dstInstanceGroup.Length);
Assert.AreEqual(dstRootInstance, dstInstanceGroup[0].Value);
var dstChildInstance = dstInstanceGroup[1].Value;
Assert.IsTrue(m_DstManager.HasComponent<Prefab>(dstRootPrefab));
Assert.IsFalse(m_DstManager.HasComponent<Prefab>(dstRootInstance));
Assert.IsFalse(m_DstManager.HasComponent<Prefab>(dstChildInstance));
Assert.AreEqual(dstRootInstance, m_DstManager.GetComponentData<EcsTestDataEntity>(dstChildInstance).value1);
Assert.AreEqual(dstChildInstance, m_DstManager.GetComponentData<EcsTestDataEntity>(dstRootInstance).value1);
}
}
// If there are only changed and deleted entities, but none added, we had a bug where deleting
// at apply time started at the wrong entity in the index
[StandaloneFixme]
public void OnlyChangedAndDeletedEntityDiffsWork()
{
EntityGuid[] guids = new EntityGuid[4];
Entity[] ents = new Entity[4];
// create 4 entities
for (int i = 0; i < 4; ++i)
{
guids[i] = GenerateEntityGuid(i + 1);
ents[i] = m_Manager.CreateEntity(typeof(EntityGuid), typeof(EcsTestData));
m_Manager.SetComponentData(ents[i], guids[i]);
m_Manager.SetComponentData(ents[i], new EcsTestData {value = i});
}
// sync to dst world and shadow
SyncDiff();
Assert.AreEqual(0, GetDstWorldData<EcsTestData>(guids[0]).value);
Assert.AreEqual(1, GetDstWorldData<EcsTestData>(guids[1]).value);
Assert.AreEqual(2, GetDstWorldData<EcsTestData>(guids[2]).value);
Assert.AreEqual(3, GetDstWorldData<EcsTestData>(guids[3]).value);
// change first two and delete last two entities
m_Manager.SetComponentData(ents[0], new EcsTestData {value = 42});
m_Manager.SetComponentData(ents[1], new EcsTestData {value = 43});
m_Manager.DestroyEntity(ents[2]);
m_Manager.DestroyEntity(ents[3]);
SyncDiff();
Assert.AreEqual(Entity.Null, GetDstWorldEntity(guids[2]));
Assert.AreEqual(Entity.Null, GetDstWorldEntity(guids[3]));
Assert.AreEqual(42, GetDstWorldData<EcsTestData>(guids[0]).value);
Assert.AreEqual(43, GetDstWorldData<EcsTestData>(guids[1]).value);
}
[Test]
[StandaloneFixme]
public void ComputeDiffOnly()
{
EntityGuid[] guids = new EntityGuid[4];
Entity[] ents = new Entity[4];
// create 4 entities
for (int i = 0; i < 4; ++i)
{
guids[i] = GenerateEntityGuid(i + 1);
ents[i] = m_Manager.CreateEntity(typeof(EntityGuid), typeof(EcsTestData));
m_Manager.SetComponentData(ents[i], guids[i]);
m_Manager.SetComponentData(ents[i], new EcsTestData {value = i});
}
WorldDiff diff = default;
// Calculate initial diff
diff = WorldDiffer.CreateDiff(m_After, m_Shadow, Allocator.TempJob);
Assert.AreEqual(diff.NewEntityCount, 4);
diff.Dispose();
// These shouldn't exist in the shadow world
foreach (var guid in guids)
Assert.AreEqual(Entity.Null, GetEntityByGuid(m_Shadow.EntityManager, guid));
// Calculate same diff again; results should be the same as above
diff = WorldDiffer.CreateDiff(m_After, m_Shadow, Allocator.TempJob);
Assert.AreEqual(diff.NewEntityCount, 4);
// These still shouldn't exist in the shadow world
foreach (var guid in guids)
Assert.AreEqual(Entity.Null, GetEntityByGuid(m_Shadow.EntityManager, guid));
// Now apply the diff to the dst world
WorldDiffer.ApplyDiff(m_DstWorld, diff);
diff.Dispose();
// and now they should exist in the dst world
for (int i = 0; i < 4; ++i)
Assert.AreEqual(ents[i], GetEntityByGuid(m_DstManager, guids[i]));
}
// We should be able to apply a diff to a world that is not 100% identical to the source,
// and a diff should show no changes even if the actual Entity index/version for a given Guid
// are different for two worlds.
[Test]
[StandaloneFixme]
public void WorldDiffsShowNoChangesWithPatchedReferences()
{
EntityGuid[] guids = new EntityGuid[2];
Entity[] ents = new Entity[2];
for (int i = 0; i < 2; ++i)
{
guids[i] = GenerateEntityGuid(i + 1);
ents[i] = m_Manager.CreateEntity(typeof(EntityGuid), typeof(EcsTestDataEntity));
}
for (int i = 0; i < 2; ++i)
{
m_Manager.SetComponentData(ents[i], guids[i]);
m_Manager.SetComponentData(ents[i], new EcsTestDataEntity {value0 = i, value1 = ents[i]});
}
// create and destroy a dummy entity in dst world, bumping up the version number
var e = m_DstWorld.EntityManager.CreateEntity(typeof(EcsTestData));
m_DstWorld.EntityManager.DestroyEntity(e);
// create and apply a diff of two entities being created with inner references
var diff = WorldDiffer.CreateDiff(m_After, m_Shadow, Allocator.TempJob);
using (diff)
{
WorldDiffer.ApplyDiff(m_DstWorld, diff);
}
// The diff between m_DstWorld and m_After should be empty, even though internally
// they refer to different Entity index/version values (but the guids are the same).
diff = WorldDiffer.CreateDiff(m_DstWorld, m_After, Allocator.TempJob);
using (diff)
{
Assert.IsFalse(diff.HasChanges);
}
}
//@TODO: Full test coverage for add / remove / destroy
//@TODO: Test for when world contains two entities with same EntityGUID (Is an error but should at minimum give a usable error message)
}
}