With the entities 1.0.0-exp.8, I’m trying to use the IAspect to check if a component is enabled, and if so, get it’s value.
Here is what I’m trying to do:
public struct SetTerrainTypeIndexComponent : IComponentData, IEnableableComponent
{
public int Value;
}
public readonly partial struct EditHexCellComponentsAspect : IAspect
{
public readonly RefRO<SetTerrainTypeIndexComponent> SetTerrainTypeIndex;
public readonly EnabledRefRO<SetTerrainTypeIndexComponent> SetTerrainTypeIndexEnabled;
// Same concept 10 times
}
But I get the following error:
SGA0001: A field of type RefRO/RefRW is areadly defined. An aspect struct must not contain more than one field of the same component type.
The EnabledRefRO.ValueRO allow me to get if the enabled flag is not, but not the component itself.
I manated to get it work by splitting the RefRO + EnabledRefRO into 2 IAspect, then create a parent one containing both:
public readonly partial struct EditHexCellComponentsAspect : IAspect
{
[ReadOnly] public readonly EditHexCellComponentsValuesAspect Values;
[ReadOnly] public readonly EditHexCellComponentsEnabledAspect Enablable;
}
public readonly partial struct EditHexCellComponentsValuesAspect : IAspect
{
public readonly RefRO<SetTerrainTypeIndexComponent> SetTerrainTypeIndex;
// Same concept 10 times
}
public readonly partial struct EditHexCellComponentsEnabledAspect : IAspect
{
public readonly EnabledRefRW<SetTerrainTypeIndexComponent> SetTerrainTypeIndexEnableable;
// Same concept 10 times
}
The only way I got it working is to split into 2 IAspect without a parent IAspect. Any better idea how to use the Aspect at the moment? Did I get something wrong?
I think your solution is probably the most straightforward way to do this. I haven’t been able to directly reference a value and its enabled status in a single aspect either, I’m not sure whether or not this restriction was intended or if this is a bug. Either way, you’re definitely not the only one who’s run into this problem.
You want to define a behavior based on the existance of a component (or in that case the enabled state of the component).
Since disabled component are considered non existing, you could try to use the [Optional] attribute on the ```public readonly RefRO SetTerrainTypeIndex;
Then use ```SetTerrainTypeIndex.IsValid``` to check the existance of the component.
```csharp
public readonly partial struct EditHexCellComponentsAspect : IAspect
{
[Optional]
public readonly RefRO<SetTerrainTypeIndexComponent> SetTerrainTypeIndex;
}
My latest video covers this (see signature).
Edit : Does not seem to work with IEnableableComponent, the IsValid property willl return true even for disabled components…
Alternatively, using IJobChunk, I made an extension function to ArchetypeChunk to pull the specific component type enable-able bits v128 and used that for enabled components.
// ! Modified from ArchetypeChunk.GetEnabledMask<T>()
public static unsafe v128 GetEnableableBits<T>(this ArchetypeChunk chunk, ref ComponentTypeHandle<T> handle)
where T : unmanaged, IComponentData, IEnableableComponent
{
#if ENABLE_UNITY_COLLECTIONS_CHECKS
AtomicSafetyHandle.CheckReadAndThrow(handle.m_Safety);
#endif
int typeIndexInArchetype;
if (Hint.Unlikely(handle.m_LookupCache.Archetype != chunk.m_Chunk->Archetype))
{
typeIndexInArchetype =
ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, handle.m_TypeIndex);
if (Hint.Unlikely(typeIndexInArchetype == -1))
return new();
handle.m_LookupCache.Update(chunk.m_Chunk->Archetype, new() { Value = typeIndexInArchetype });
}
else
{
typeIndexInArchetype = handle.m_LookupCache.IndexInArchetype;
}
return *chunk.m_Chunk->Archetype->Chunks.GetComponentEnabledMaskArrayForTypeInChunk(typeIndexInArchetype,
chunk.m_Chunk->ListIndex);
}
Use the resulting v128 as the “chunkEnabledMask” for component specific iteration (i.e. ChunkEntityEnumerator) rather than the merged values they provide in the Execute parameter list.
It’s so odd that Unity provides a merged bitarray rather than per component. What even is the use of a merged bitarray for component iteration?
Reading over this code again, I guess you can also modify this to return a write-able reference to the enabled bit array but none of the other methods does so. This is just a frankenstein conglomeration of some internal methods Unity uses in chunk iteration so use it at your own risk. It works for me so far at least.
If you want a writable access version of the function above, remove the * from the return statement at the bottom, replace the early return with a null return, and replace v128 in the function header with v128* pointer. Now you can unsafe toggle components enabled and disabled.
That is a good workaround when you are only trying to read the enabled status. Although, you end up iterating all entities rather than just the ones with the IEnableableComponent.
But what if we want to write to the enabled bit and write new data for the same component type? Do we really need to use two different aspects for this?
I feel like EnabledRefRW and EnabledRefRO should have properties to both get/set the enabled bit AND get/set the component data. Only being able to retrieve the enabled bit or the data but not both in the same aspect feels like an oversight or bug.
Plus I just tested and it seems the IsValid property don’t return false as expected when the component is there but disabled… So my soilution wouldn’t work for the OP case.