#Baking a Prefab and Instantiating it with EntityCommandBuffer is suddenly broken in pre15? [SOLVED]

1 messages · Page 1 of 1 (latest)

fiery lynx
#

I'm having trouble instantiating objects - with or without a transform component, the objects never show up in the Hierachy - instead i get an entry for Unity.Rendering.PushBlendWeightSystem. If i go and expect that, it seems the underlying GameObject is None.

[Serializable]
public class CellConfiguration
{
    public int Id;
    public int NumberOfCells;
    public GameObject Prefab;
}

public class CellSpawnerMono : MonoBehaviour
{
    public float2 Dimension;
    public float Speed;
    [SerializeReference]
    public List<CellConfiguration> CellConfigurations;
}

public class CellSpawnerBaker : Baker<CellSpawnerMono>
{
    public override void Bake(CellSpawnerMono authoring)
    {
        var list = new NativeList<CellConfigurationProperties>(Allocator.Temp);
        authoring.CellConfigurations.ForEach(a =>
        {
            var ccp = new CellConfigurationProperties
            {
                Id = a.Id,
                NumberOfCells = a.NumberOfCells,
                Prefab = GetEntity(a.Prefab)
            };
            list.Add(ccp);
        });

        AddComponent(new WorldProperties
        {
            Dimension = authoring.Dimension,
            Speed = 42f,
            Properties = list.ToArray(Allocator.Persistent)
        });
    }
}
#

and the Job:

//[BurstCompile]
[UpdateInGroup(typeof(InitializationSystemGroup))]
public partial struct SpawnCellsSystem : ISystem
{
    //[BurstCompile]
    public void OnCreate(ref SystemState state)
    {
        state.RequireForUpdate<WorldProperties>();
    }

    //[BurstCompile]
    public void OnDestroy(ref SystemState state)
    {
    }

    //[BurstCompile]
    public void OnUpdate(ref SystemState state)
    {
        state.Enabled = false;
        var properties = SystemAPI.GetSingletonEntity<WorldProperties>();       
        var p = SystemAPI.GetAspectRW<WorldPropertiesAspect>(properties);

        var ecb = new EntityCommandBuffer(Allocator.Temp);

        for ( var i = 1; i < 50; i++ )
        {
            var entity = p.Properties[0].Prefab;
            var cell = ecb.Instantiate(entity);
            //ecb.SetComponent(cell, new LocalTransform
            //{
            //        Position = new float3 { x = i, y = 0, z = i },
            //        Rotation = quaternion.identity,
            //        Scale = 1f
            //});
        }

        ecb.Playback(state.EntityManager);
    } 

}

I've tried with and without the Burst compiler (also disabled in the menu). I tried with and without the LocalTransform component.

#

If I comment in the LocalTransform component i get an error:
ArgumentException: A component with type:Unity.Transforms.LocalTransform has not been added to the entity. Entities Journaling may be able to help determine more information. Please enable Entities Journaling for a more helpful error message.

still dust
#
        Properties = list.ToArray(Allocator.Persistent)
#

what's going on here?

#

you can't allocate native memory and store it in entities in baking

fiery lynx
#

are you sure? i tried with a single reference but got the same error

#

instead of an array

#

or actually i'm debugging and the error is actually Instantiate gives me "\'ENTITY NOT FOUND\' Entity(-1:-95) Default World"

still dust
#

you can't store entities in baking in anything other than IComponentData and IBufferElements

#

they won't remap

#

you'll just be referencing the non-existent entity that was in the baked world

fiery lynx
#

ok, so how would i instantiate the objects in my system? I'm following the tutoral from Turbo Makes Games and it's almost identical to what he is doing - but it seems a few things changed in pre15?

#
public struct WorldProperties : IComponentData
{
    public float2 Dimension;
    public float Speed;
    public NativeArray<CellConfigurationProperties> Properties;
}
#

That is my WorldProperties - it implements IComponentData

still dust
#

public NativeArray<CellConfigurationProperties> Properties;

#

why are you not just storing this on an IBufferElement

fiery lynx
#

I don't know what the difference is - it's data i will need to persist throughout the game

#

some used for instantiating and some used in each gameloop

#

Are you saying i can not use NativeArray on an IComponentData ?

still dust
#

im saying you can not use it this way

fiery lynx
#

Ok, i'm a total DOTS newbie but i just want to be able to configure a MonoBehaviour with a list of CellConfigurations - each configuration holds a prefab and a count and some other stuff that i'm not using now - i want the spawner to create the number of each cell with the prefab selected - my current example/test has three cells with three different prefabs - since it's dynamic i need some way to create/bake it at startup

still dust
#

IBufferElement is just a list you can attach to entities

#

it will remap the entities and they'll be usable at runtime

fiery lynx
#

ok so i could attach a list of CellConfigurationsProperties (that each told a prefab GameObject and a count)?

#

i'll read up on it - thanks 🙂

#

it doesnt have to resize

#

it's fixed at runtime

still dust
#

yeah you can just use it as an array

#

you dont have to add/remove from it

fiery lynx
#

ok thanks

#

Is that because float3 is a blittable type?

hushed folio
#

But, that's separate from your original problem - i'll try and explain:

#

When you use GetEntity() during baking, and assign that Entity value to a field on a component, it is actually returning a sortof temporary entity value that only exists during baking..

#

What happens next is when you run your game, those Entity values that you assigned to fields inside components are resolved to the actual runtime Entities which have been streamed in from the loaded baked subscene data..

#

The problem in your case is - Unity will only track and resolve those temporary entity values if they are assigned to fields of IComponentData or DynamicBuffers

#

So because you were using a NativeList/NativeArray embedded inside an IComponentData, Unity isn't tracking it and updating those values..

still dust
#

(much better explanation than my ramblings of just do this)

hushed folio
#

If instead you had just did something like this ( what Tertle was suggesting, using a DynamicBuffer instead ):

public class CellSpawnerMono : MonoBehaviour
{
    public float2 Dimension;
    public float Speed;
    [SerializeReference]
    public List<CellConfiguration> CellConfigurations;
}
public struct CellConfigurationProperties: IBufferElementData
{
    public int Id;
    public int NumberOfCells;
    public Entity Prefab;
}
public class CellSpawnerBaker : Baker<CellSpawnerMono>
{
    public override void Bake(CellSpawnerMono authoring)
    {
        var propsBuffer = AddBuffer<CellConfigurationProperties>();
        authoring.CellConfigurations.ForEach(a =>
        {
            propsBuffer.Add(new CellConfigurationProperties
            {
                Id = a.Id,
                NumberOfCells = a.NumberOfCells,
                Prefab = GetEntity(a.Prefab)
            });
        });

        AddComponent(new WorldProperties
        {
            Dimension = authoring.Dimension,
            Speed = 42f
        });
    }
}
fiery lynx
#

Wow, thanks guys!

#

The Buffer will have to be added to the current entity somehow?

#

Oh calling AddBuffer adds it to the entity i guess - thanks both of you for spending the time to explain 🙂

fiery lynx
#

I know DOTS is ment for performance, but i kinda like this data oriented approach - for now 😄

fiery lynx
#

Oh and the data will be read from a lof of times each tick/frame as they are used in calculations

#

And also the data won't be changed once baked

#

Or at least not planning to...

hushed folio
# fiery lynx I have another list of `int`'s and `float`'s that i want to add to the entity. I...

I guess the question is how you will use it, for example if you only need access to the array and not necessarily the other data on the component, are you using IJobEntity in which case you pass in the buffer and it's optimized to burst through all of those buffers.. just do what makes sense to you as performance i think will be negligible unless you're dealing with millions of entities..
Additionally, if the array will never change you have the option of storing it in a Blob, which is specifically for data that never changes.. That would be useful if lots of entities share the same array values, but if each entity has it's own unique 'version' of this data probably better to stick with for example a dynamic buffer on each entity.

fiery lynx
#

Ok thank you 🙂 I'm just starting to learn about DOTS but am i correct in thinking down the lines
fastest to slowest: blob, nativearray, dynamic buffer
most rigid to most dynamic: blob, nativearray, dynamic buffer
So if you can live with data being very static go with blob, if you need a lot of flexibility go with dynamic buffer - or something in between go with nativearray?

#

For now i went with dynamic buffer, which doesn't sound optimal, but since it's working for the other part, this is what i start with

hushed folio
#

putting a NativeArray on an IComponentData i'm not 100% how this differs in terms of performance compared to using a DynamicBuffer of the same data..

#

( because putting native containers on componenst is relatively new and i'm not sure of performance implications - probably someone else could answer that )

#

for example because an array is fixed length, maybe it's faster, maybe if you ensure all components with that array use a fixed array length that is the same, maybe it's faster, i don't know

#

but honestly, i think just sticking with a buffer is fine

#

if you need to micro optimize do that later 🙂

fiery lynx
#

Yeah thanks a lot 🙂 I just wanted to make sure i was being an idiot for picking something obviously bad from the beginning 🙂 I will be benchmarking later 🙂

fiery lynx
#

Do i click somewhere to mark this thread solved or what am i supposed to do?

hushed folio