#Lookup data in a DynamicBuffer?

1 messages · Page 1 of 1 (latest)

runic spindle
#

Say I have a buffer with a component { Enum Type, float Value }, what is the best way to find the value for a specific type? Considering this could be frequent access

high path
#

How large is the buffer most likely going to be? Can multiple buffer elements have the same enum value / how do you want to handle multiple of the same value? Is it frequent access on a buffer on a singleton or is the buffer on multiple entities?

runic spindle
#

The buffer should be pretty much static and hold one value per key. It's for an attribute system. I'm hoping to do something like attributesBuffer[Type.Health].Value

#

I can't have the attributes in separate components because I need generic logic to write to them through modifiers that point to a specific attribute type

fading spear
#

As long as it's not going to be huge, iterating is probably fine

#

If you have a lot of data though, I wrote dynamic hash maps for this exact problem

high path
#

Also possible to just initialize it into a nativehashmap before processing it, though probably not ideal for this usecase

#

Depending on how many attributes there are and how many entities need them, you can also make all entities always have all attributes, and just use the enum as an index. Then you could even make it a component since the enum size is known at compile time

runic spindle
#

I made a little attribute reader aspect for now:

    public readonly partial struct AttributeReader : IAspect
    {
        public readonly DynamicBuffer<Attribute> _attributes;

        public float this[AttributeType type]
        {
            get
            {
                foreach (var attribute in this._attributes)
                {
                    if (attribute.Type == type)
                    {
                        return attribute.Value;
                    }
                }

                return 0f;
            }
        }
    }

Can't say I'm too happy with this, but maybe it's just my OOP brain.

runic spindle
#
            foreach (var (attributes, modifiers) in SystemAPI
                         .Query<DynamicBuffer<Attribute>, DynamicBuffer<AttributeModifier>>())
            {
                foreach (var modifier in modifiers)
                {
                    //find correct attribute with modifier.AttributeType
                    //edit the Attribute value with the modifier
                }
            }
high path
#

Probably fine to do it like that for now, and change it later only if you actually experience lag from it

runic spindle
high path
#

That works too, though again, that forces all attributes to be on all entities with that component. So really depends on your usecase.
For indexing I usually convert it to a span:

        public static unsafe Span<Container> AsSpan(this ref ResourceContainer resourceContainer)
        {
            var elements = sizeof(ResourceContainer) / sizeof(Container);
            var span = new Span<Container>(Unsafe.AsPointer(ref resourceContainer), elements);
            return span;
        }

Then just index that instead. Haven't checked if it's fast or not though, I think the sizeof might have some issues?

#

Though then you need the fields to be strictly in the same order as the enum, I don't know how that interacts with networking

fading spear
#

i'd suggest just making this an extension method instead

runic spindle
#

Didn't know that about aspects, thanks!

Now I'm having even more of a headache. I'd like to have attributes as individual components so that I can selectively read what interests my system.

Health component with Value field.

That's easy to do. But I would also like to have generic logic running on all my attributes. That's where I'm lost. There doesn't seem to be a way for me to tell ECS; "gather all modifiers that match that attribute, and change its value field to the computed value".

high path
#

There are two attribute systems made for ecs already, might be a good idea to look at or use those if they fit your usecase

fading spear
#

reaction is a very different way of working with entities though

#

probably not for everyone

#

though you can implement a similar stat solution without reaction in a more traditional project

#

which i did at work

runic spindle
#

Thanks for the link I'll take a look! My main issue is that my stats need to be flat with the character to be serialized with Netcode. It would be easy to run the generic logic on separate stat entities for example

fading spear
#

I'm actually adding custom netcode support atm for dynamic buffers to serialize them much more efficient

#

from memory the implementation at work though just copies stats the player should be aware of to a separate network buffer (so not all stats) and then rebuilds the map on client