Hey all. I'm getting into a situation that's confusing me a bit. I'm trying to create a shared component with a value that I can filter upon. Everything works great when I create my entity through the EntityManager, but not when I create it through an EntityCommandBuffer, even though my impression from the documentation is that that should work. Here's some repro code. Am I fundamentally missunderstanding something, or is this a bug in the EntityCommandBuffer?
#SharedComponentData not possible for filtering when created through EntityCommandBuffer
1 messages · Page 1 of 1 (latest)
Here's repro code:
struct BatchTag : IComponentData { }
public struct BatchEntityReference : ISharedComponentData
{
public Entity Value;
}
public partial struct TestSystem : ISystem
{
public void OnCreate(ref SystemState state)
{
// Works
{
var batch = state.EntityManager.CreateEntity();
state.EntityManager.AddComponentData(batch, new BatchTag());
var e = state.EntityManager.CreateEntity();
state.EntityManager.AddSharedComponent(e, new BatchEntityReference { Value = batch });
}
// Doesn't Work
{
using var ecb = new EntityCommandBuffer(Allocator.Temp);
var batch = ecb.CreateEntity();
ecb.AddComponent(batch, new BatchTag());
var e = ecb.CreateEntity();
ecb.AddSharedComponent(e, new BatchEntityReference { Value = batch });
ecb.Playback(state.EntityManager);
}
}
public void OnUpdate(ref SystemState state)
{
// I expect all Debug.Log statements to execute. However, only this one ends up executing if I run the EntityCommandBuffer code in OnCreate.
foreach (var (reference, entity) in SystemAPI.Query<BatchEntityReference>().WithEntityAccess())
{
Debug.Log($"{entity} references {reference.Value}");
}
foreach (var (entityInBatch, batch) in SystemAPI.Query<BatchTag>().WithEntityAccess())
{
foreach (var (reference, e) in SystemAPI.Query<BatchEntityReference>().WithSharedComponentFilter(new BatchEntityReference { Value = batch }).WithEntityAccess())
{
Debug.Log($"{batch} is referenced by {e}");
}
}
}
}
Here's the part of the documentation that gives me the indication that this should work (https://docs.unity3d.com/Packages/com.unity.entities@1.3/manual/systems-entity-command-buffers.html#temporary-entities-created-by-command-buffers)
The entities returned from EntityCommandBuffer's CreateEntity() and Instantiate() methods are special; they don't fully exist until the command buffer is played back, but they can still be used in subsequent commands within the same command buffer. There are two valid uses for temporary entities:
...** Unmanaged component values passed into commands can contain references to temporary entities. For example, EntityCommandBuffer.SetComponent(e2, new Parent{ Value = e}) is valid if e or e2 (or both) are temporary entities from the same command buffer. This includes IBufferElementData components (dynamic buffers) which contain entity fields.**
During command buffer playback, valid references to temporary entities created earlier in the buffer will be automatically replaced with a reference to the corresponding "real" entity. There is no way to determine which "real" entity corresponds to a given temporary entity after its command buffer has been played back.
...
shared components won't be remapped
shared components aren't remapped neither in baking nor in ECB
this is because their value itself is what defines them
if any field (entity reference) is modified - value is already different
But if it isn't remapped, then why are there legal values within the BatchEntityReference? When I print it out (and also look at it in the inspector) it shows valid entity values, not negative temporary ones.
because EntityManager creates valid ones
I don't understand that? Doesn't that mean it's remapping the BatchEntityReference?
It doesn't need to remap anything, because by the time things get created, they are already valid ones
ECB creates things only during Playback, so anything it returns is just temporary identifiers
Just so we're on the same page here. When I run batch = ecb.CreateEntity() I get back a temporary entity right? Then later, when I do ecb.AddSharedComponent(e, new BatchEntityReference {Value = batch}); I send give the temporary value to the BatchEntityReference. If there's no remapping, then why doesn't the BatchEntityRefernce hold the temporary value I got from the ecb after playback?
Like, if I look in the inspector, and print out the values of BatchEntityReference, it contains the correct values, I just can't filter on them for some reason.
yes, it contains deferred entity which is not valid globally
so when you attempt to filter
you rely on entity value for filter
but shared component value consists of deferred entity value
WHen you say deferred, do you mean the temporary entity? the negative one
yes
But that isn't correct, because if I print out the entity in the BatchEntityReference (or look at it in the inspector) it has the actual value I want it to.
can you show in inspector entity created by ecb code?
Yeah, two seconds and I'll give you a picture.
So, I have the same code as I posted initially, except that I don't run the // Works scope.
Here's the batch tag entity that I want to refer to (68:1)
And here's the entity that has the BatchEntity reference (68:1)
And here I'm debug logging the value (from the first for loop in the initial code)
It looks exactly the same if I just run the "works" code, with the exception that I also get the expected printout that Entity(68:1) is referenced by Entity(69:1).
Oh, so it does remapping after all. I didn't expect it
Yeah, that's why I'm a bit confused. Because from the documentation it seems like it remaps essentially everything (it says it even remaps DynamicBuffer) so I thought that if it didn't remap SharedComponents that would have been noted?
Well, generally blobs and shared components are special in all sorts of remapping logic
so I would have assumed otherwise
but either way, it is quite confusing why code fails
Can you post what the code gen looks like
Where can I find the code gen?
Are you using rider
Nope, visual studio 2022
https://discussions.unity.com/t/where-is-generated-code-in-entities-1-0-located/923469 Seems like I can get Unity to output it
Don't really want to output it
That's overkill
Maybe look Solution, dependencies, hopefully there's a list of source generators with what they do
But yeah last resort I guess would be to output
I'll output it now, and look for a better solution later :)
Anything in particular you want to look at? Would be nice t oavoid having to have all my computer paths etc included :P
The code this system is generating
Or, seems like it's not too much stuff. so I can just remove the #line parts with the paths.
What's the best way of sharing code this days, is it still hastebin?
if (!entityQuery.IsEmptyIgnoreFilter)
{
IFE_1252175251_2.CompleteDependencies(ref state);
typeHandle.Update(ref state);
entityQuery.SetSharedComponentFilter(sharedComponent0);
}
Is it just me or does this seem wrong
If your previous change filter is empty it won't add a new change filter to it
I don't know, It's been a while since last time I touched entities. But could that mean that there's a bug in the Query?
For VS 2022 you can use "Go to definition" on the type name. It will open a dialog showing partial definition parts of that type. Look for the file ends in .g.cs
That doesn't work here. Nothing changes, no popups or anything, it just centers on the system I try to go to the definition of. Is there something I need to enable to get this behaviour? I've installed the .NET Compiler Platform SDK, and can't really find any option in the visual studio options window that seems related to code gen files.