public void AddMultipleComponentsWithQuery_ExceedChunkCapacityThrows() { // TypeManager.AddNewComponentTypes is not supported in DOTS Runtime currently #if !UNITY_DOTSRUNTIME TypeManager.AddNewComponentTypes(new[] { typeof(EcsTestDataHuge) }); #endif var componentTypes = new ComponentTypes(typeof(EcsTestDataHuge)); // add really big component(s) Assert.AreEqual(16320, Chunk.GetChunkBufferSize()); // if chunk size changes, need to update this test var entity1 = m_Manager.CreateEntity(typeof(EcsTestData)); var entity2 = m_Manager.CreateEntity(typeof(EcsTestData), typeof(EcsTestData2)); var entity3 = m_Manager.CreateEntity(typeof(EcsTestData2)); var archetype1 = m_Manager.GetChunk(entity1).Archetype; var archetype2 = m_Manager.GetChunk(entity2).Archetype; var archetype3 = m_Manager.GetChunk(entity3).Archetype; var query = m_Manager.CreateEntityQuery(typeof(EcsTestData)); #if UNITY_DOTSRUNTIME Assert.Throws <InvalidOperationException>(() => m_Manager.AddComponent(query, componentTypes)); #else Assert.That(() => m_Manager.AddComponent(query, componentTypes), Throws.InvalidOperationException .With.Message.Contains("Entity archetype component data is too large.")); #endif m_ManagerDebug.CheckInternalConsistency(); // entities should be unchanged Assert.AreEqual(archetype1, m_Manager.GetChunk(entity1).Archetype); Assert.AreEqual(archetype2, m_Manager.GetChunk(entity2).Archetype); Assert.AreEqual(archetype3, m_Manager.GetChunk(entity3).Archetype); }
public unsafe void CreatingArchetypeWithToLargeEntityThrows() { // TypeManager.AddNewComponentTypes is not supported in DOTS Runtime currently #if !UNITY_DOTSRUNTIME TypeManager.AddNewComponentTypes(new [] { typeof(WillFitWithAlign), typeof(WontFitWithAlign), typeof(BigComponentWithAlign1) }); #endif Assert.DoesNotThrow(() => m_Manager.CreateArchetype(typeof(BigComponentWithAlign1), typeof(WillFitWithAlign))); Assert.Throws <ArgumentException>(() => m_Manager.CreateArchetype(typeof(BigComponentWithAlign1), typeof(WontFitWithAlign))); }
public void ThrowsWhenTooLargeCreate() { // TypeManager.AddNewComponentTypes is not supported in DOTS Runtime currently #if !UNITY_DOTSRUNTIME TypeManager.AddNewComponentTypes(typeof(TestTooBig)); #endif Assert.Throws <ArgumentException>(() => { m_Manager.CreateEntity(typeof(TestTooBig)); }); }
public void CreateTooBigArchetypeThrows() { // TypeManager.AddNewComponentTypes is not supported in DOTS Runtime currently #if !UNITY_DOTSRUNTIME TypeManager.AddNewComponentTypes(new [] { typeof(BigComponentData1), typeof(BigComponentData2) }); #endif Assert.Throws <System.ArgumentException>(() => { m_Manager.CreateArchetype(typeof(BigComponentData1), typeof(BigComponentData2)); }); }
public void ThrowsWhenTooLargeAddComponent() { // TypeManager.AddNewComponentTypes is not supported in DOTS Runtime currently #if !UNITY_DOTSRUNTIME TypeManager.AddNewComponentTypes(typeof(TestTooBig)); #endif var entity = m_Manager.CreateEntity(); Assert.Throws <InvalidOperationException>(() => { m_Manager.AddComponent <TestTooBig>(entity); }); }
public unsafe void ChunkComponentRunIsAligned(Type maxCapacityTagType) { // TypeManager.AddNewComponentTypes is not supported in DOTS Runtime currently #if !UNITY_DOTSRUNTIME TypeManager.AddNewComponentTypes(new [] { typeof(BigComponentWithAlign1) }); #endif // Create an entity var archetype = m_Manager.CreateArchetype(typeof(BigComponentWithAlign1), typeof(ComponentWithAlign8), maxCapacityTagType); var entity = m_Manager.CreateEntity(archetype); // Get a pointer to the first bigger-aligned component var p0 = m_Manager.GetComponentDataRawRW(entity, TypeManager.GetTypeIndex <Entity>()); var p1 = m_Manager.GetComponentDataRawRW(entity, TypeManager.GetTypeIndex <BigComponentWithAlign1>()); var p2 = m_Manager.GetComponentDataRawRW(entity, TypeManager.GetTypeIndex <ComponentWithAlign8>()); Assert.IsTrue(p0 < p1 && p1 < p2, "Order of components in memory is not as expected"); // all component arrays need to be cache line aligned Assert.True(CollectionHelper.IsAligned(p0, CollectionHelper.CacheLineSize)); Assert.True(CollectionHelper.IsAligned(p1, CollectionHelper.CacheLineSize)); Assert.True(CollectionHelper.IsAligned(p2, CollectionHelper.CacheLineSize)); }
public void AddNewComponentTypes() { var typeToAdd = typeof(UnregisteredComponent); bool testAlreadyRan = false; try { TypeManager.GetTypeIndex(typeToAdd); testAlreadyRan = true; } catch (ArgumentException) {} // If we haven't registered the component yet we should have thrown above before setting // however, since we cannot remove types from the TypeManager, subsequent test // runs without a domain reload will already have our test type registered so simply abort if (testAlreadyRan) { return; } Dictionary <int, TypeManager.TypeInfo> typeInfoMap = new Dictionary <int, TypeManager.TypeInfo>(); Dictionary <int, int[]> entityOffsetMap = new Dictionary <int, int[]>(); Dictionary <int, int[]> blobOffsetMap = new Dictionary <int, int[]>(); Dictionary <int, int[]> writeGroupMap = new Dictionary <int, int[]>(); void AddTypeInfoToCache(TypeManager.TypeInfo ti) { unsafe { var typeIndex = ti.TypeIndex; var entityOffsets = new int[ti.EntityOffsetCount]; var blobOffsets = new int[ti.BlobAssetRefOffsetCount]; var writeGroups = new int[ti.WriteGroupCount]; typeInfoMap.Add(typeIndex, ti); var pEntityOffsets = TypeManager.GetEntityOffsets(ti); for (int i = 0; i < ti.EntityOffsetCount; ++i) { entityOffsets[i] = pEntityOffsets[i].Offset; } entityOffsetMap.Add(typeIndex, entityOffsets); var pBlobOffsets = TypeManager.GetBlobAssetRefOffsets(ti); for (int i = 0; i < ti.BlobAssetRefOffsetCount; ++i) { blobOffsets[i] = pBlobOffsets[i].Offset; } blobOffsetMap.Add(typeIndex, blobOffsets); var pWriteGroups = TypeManager.GetWriteGroups(ti); for (int i = 0; i < ti.WriteGroupCount; ++i) { writeGroups[i] = pWriteGroups[i]; } writeGroupMap.Add(typeIndex, writeGroups); } } unsafe void EnsureMatch(TypeManager.TypeInfo expected, TypeManager.TypeInfo actual) { Assert.AreEqual(expected.TypeIndex, actual.TypeIndex); Assert.AreEqual(expected.SizeInChunk, actual.SizeInChunk); Assert.AreEqual(expected.ElementSize, actual.ElementSize); Assert.AreEqual(expected.AlignmentInBytes, actual.AlignmentInBytes); Assert.AreEqual(expected.BufferCapacity, actual.BufferCapacity); Assert.AreEqual(expected.FastEqualityIndex, actual.FastEqualityIndex); Assert.AreEqual(expected.Category, actual.Category); Assert.AreEqual(expected.EntityOffsetCount, actual.EntityOffsetCount); var expectedEntityOffsets = entityOffsetMap[expected.TypeIndex]; var pActualEntityOffsets = TypeManager.GetEntityOffsets(actual); for (int i = 0; i < actual.EntityOffsetCount; ++i) { Assert.AreEqual(expectedEntityOffsets[i], pActualEntityOffsets[i].Offset); } Assert.AreEqual(expected.BlobAssetRefOffsetCount, actual.BlobAssetRefOffsetCount); var expectedBlobOffsets = blobOffsetMap[expected.TypeIndex]; var pActualBlobOffsets = TypeManager.GetBlobAssetRefOffsets(actual); for (int i = 0; i < actual.BlobAssetRefOffsetCount; ++i) { Assert.AreEqual(expectedBlobOffsets[i], pActualBlobOffsets[i].Offset); } Assert.AreEqual(expected.WriteGroupCount, actual.WriteGroupCount); var expectedWriteGroups = writeGroupMap[expected.TypeIndex]; var pActualWriteGroups = TypeManager.GetWriteGroups(actual); for (int i = 0; i < actual.WriteGroupCount; ++i) { Assert.AreEqual(expectedWriteGroups[i], pActualWriteGroups[i]); } Assert.AreEqual(expected.MemoryOrdering, actual.MemoryOrdering); Assert.AreEqual(expected.StableTypeHash, actual.StableTypeHash); Assert.AreEqual(expected.MaximumChunkCapacity, actual.MaximumChunkCapacity); Assert.AreEqual(expected.AlignmentInChunkInBytes, actual.AlignmentInChunkInBytes); Assert.AreEqual(expected.Type, actual.Type); Assert.AreEqual(expected.IsZeroSized, actual.IsZeroSized); Assert.AreEqual(expected.HasWriteGroups, actual.HasWriteGroups); Assert.AreEqual(expected.HasEntities, actual.HasEntities); } foreach (var ti in TypeManager.AllTypes) { AddTypeInfoToCache(ti); } using (World w = new World("AddNewComponentsTestWorld")) { w.GetOrCreateSystem <TestSystem>(); // Ensure all the Types in the TypeManager match what we think they are foreach (var ti in TypeManager.AllTypes) { EnsureMatch(typeInfoMap[ti.TypeIndex], ti); } Assert.Throws <ArgumentException>(() => TypeManager.GetTypeIndex(typeToAdd)); TypeManager.AddNewComponentTypes(new Type[] { typeToAdd }); // Now that we added a new type, again ensure all the Types in the TypeManager match what we think they are // to ensure adding the new type didn't change any other type info foreach (var ti in TypeManager.AllTypes) { if (typeInfoMap.ContainsKey(ti.TypeIndex)) { EnsureMatch(typeInfoMap[ti.TypeIndex], ti); } else { // We should only enter this case for 'UnregisteredComponent' Assert.AreEqual(ti.Type, typeof(UnregisteredComponent)); AddTypeInfoToCache(ti); } } var e2 = w.EntityManager.CreateEntity(typeof(Translation), typeToAdd); // If adding the type did not succeed we might throw for many different reasons // stemming from bad type information. In fact even succeeding could cause issues if someone caches the // internal SharedStatic pointers (which is done, and now handled for, in the EntityComponentStore) Assert.DoesNotThrow(() => w.Update()); Assert.DoesNotThrow(() => w.EntityManager.CreateEntity(typeof(Translation), typeToAdd)); Assert.DoesNotThrow(() => TypeManager.GetTypeIndex(typeToAdd)); // We do not allow anyone to re-add the same type so ensure we throw Assert.Throws <ArgumentException>(() => TypeManager.AddNewComponentTypes(new Type[] { typeToAdd })); } }
static void AddECSTypesInEditor() { ECSToModGeneral.Print("ECSToUMod: ECSToUModEditor.AddECSTypesInEditor() called automatically by RuntimeInitializeLoadType.AfterAssembliesLoaded"); if (null == ECSToUMod.ModHosts) { throw new Exception($"ECSToUMod: ECSToUMod.ModHosts[] needs to be populated before ECSToUmod.AddECSTypesInEditor() is called automatically via the [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)] attribute"); } //if(IsWriteGroupEnabled) { // //Ensure the TypeManager has not been initialized yet // if(TypeManagerIsInitialized) { // Debug.LogError($"ECSToUMod: WriteGroup functionality is {IsWriteGroupEnabled} but TypeManager has already been initialized. WriteGroups will be ignored!"); // PrintWriteGroupInstructions(); // } // //TypeManager.Initialize() was interfered with, so we may need to call it manually here // //Or maybe not! // //TypeManager.Initialize(); //} else { //TypeDependencyCache and AttachToEntityClonerInjection both call TypeManager.Initialize() very early, in the Editor //However, using TypeManager.AddNewComponentTypes(), we can still include loaded mod code //Note- this way doesn't respect WriteGroup attributes! //Create a list of all interfaces that the TypeManager needs to know about List <System.Type> DOTSInterfaces = new List <System.Type> { typeof(IBufferElementData), typeof(IComponentData), typeof(ISharedComponentData), typeof(IConvertGameObjectToEntity), }; //Iterate mod hosts looking for types to add foreach (var host in ECSToUMod.ModHosts) { if (!host.IsModLoaded) { continue; } //Find all mod assemblies that reference the Entities namespace foreach (var modAssembly in host.ScriptDomain.Assemblies.Where(assembly => TypeManager.IsAssemblyReferencingEntities(assembly.RawAssembly))) { foreach (var DOTSInterface in DOTSInterfaces) { //Find all type definitions in the loaded mod code that implement this interface (for example MyComponent: IComponentData) and grab the actual underlying System.Type via .RawType var subTypes = modAssembly.FindAllSubTypesOf(DOTSInterface).Select(subtype => subtype.RawType); //Add it to the TypeManager using this special editor-only function TypeManager.AddNewComponentTypes(subTypes.ToArray()); //if (TypeManagerIsInitialized) { // bool displayInstructions = false; // foreach (var type in subTypes) { // var attribute = type.GetCustomAttribute<WriteGroupAttribute>(); // if (null == attribute) { // continue; // } // Debug.LogWarning($"ECSToUMod: Assembly {modAssembly.Name} has a type {type.Name} with the WriteGroup attribute"); // displayInstructions = true; // } // if (displayInstructions) { // Debug.LogError($"To enable WriteGroup functionality in the editor with UMod, toggle Tools/ECSToUMod/Toggle writegroup functionality"); // } //} } } //} } }