#SharedComponentData not possible for filtering when created through EntityCommandBuffer

1 messages · Page 1 of 1 (latest)

serene cypress
#

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?

#

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.
...

eager quartz
#

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

serene cypress
#

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.

eager quartz
serene cypress
#

I don't understand that? Doesn't that mean it's remapping the BatchEntityReference?

eager quartz
#

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

serene cypress
#

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.

eager quartz
#

so when you attempt to filter

#

you rely on entity value for filter

#

but shared component value consists of deferred entity value

serene cypress
eager quartz
#

yes

serene cypress
#

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.

eager quartz
#

can you show in inspector entity created by ecb code?

serene cypress
#

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).

eager quartz
#

Oh, so it does remapping after all. I didn't expect it

serene cypress
#

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?

eager quartz
#

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

pliant spade
#

Can you post what the code gen looks like

serene cypress
#

Where can I find the code gen?

pliant spade
#

Are you using rider

serene cypress
#

Nope, visual studio 2022

pliant spade
#

If so just hit the DOTS button

#

Well then no idea

serene cypress
pliant spade
#

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

serene cypress
#

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

pliant spade
#

The code this system is generating

serene cypress
#

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?

pliant spade
#

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

serene cypress
#

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?

pliant spade
#

Oh ignore me

#

Is empty ignore filter

#

Doesn't care about previous shared filter

vernal oxide
serene cypress