Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
    michaelSchrier
    @michaelSchrier
    Ah fair enough then.
    michaelSchrier
    @michaelSchrier
    In cases where you have many worlds (like 10 or even 100), I assume that Entity Sets are updated on a per world basis? Like if there is some Health Component added to an Entity in World 3 and an Entity Set that observed Health Components in World 16, the set wouldn't get some update ping, right?
    Likely a stupid question but just wanted to make sure.
    Paillat Laszlo
    @Doraku
    you are "limited" to short.MaxValue concurrent worlds, so that would be 32767, hopefully it is enough! EntitySet (and other containers) are relatif to a world, and a world can only see its own entities :) World instances are thread safe from each other too.
    michaelSchrier
    @michaelSchrier
    Thanks for clarification. Ya luckily I don't think I'll be hitting 32k worlds anytime soon :P
    michaelSchrier
    @michaelSchrier
    image.png
    Does DefaultECS have a way to hold a reference to a specific entity's component?
    Something like this basically^
    Paillat Laszlo
    @Doraku
    not natively yet :( This is one of the big thing I want to add in the futur but it is hard to do correctly, as the state of the referenced component should be synced with the reference component (enable/change/remove), handle serialization, stuff like that. In the meantime the type you use (maybe change it for a struct instead of class?) is probably the best way to handle it for now.
    Ross Squires
    @ross.squires:matrix.org
    [m]
    hey, just started on my ECS journey!
    built a little ECS system by hand to learn about the general principles
    then discovered it was a ton of work to build something efficient on my own
    so, after some digging, this framework looks pretty great
    now to port my existing prototype over to DefaultEcs...
    Paillat Laszlo
    @Doraku
    welcome to the rabbit hole haha feel free to ask if there is a workflow you can't port :) that's mostly how I get ideas for missing features
    Ross Squires
    @ross.squires:matrix.org
    [m]
    what's the best way to listen to all changes to components? i.e., for debugging and logging
    Paillat Laszlo
    @Doraku
    I guess you can use all the World.SubscribeComponentAdded/Changed/Removed/Disabled/Enabled methods but you would have to do it for all your component types
    Lazy
    @michaelSchrier_gitlab
    Do you think it would be possible to expose some Added/Removed/Changed events on EntitySets? It would make creating our own custom groupings a lot easier. The ability to sort entities based on some method Func "key" would be amazing. Trying to put something like that together.
    Paillat Laszlo
    @Doraku
    EntitySortedSet should be coming in the next version (already available in the pre-release 0.17.0-beta1) if this is similar to your needs
    Lazy
    @michaelSchrier_gitlab
    Oh interesting. Mind linking it? I'd love to take a look.
    Lazy
    @michaelSchrier_gitlab
    Also, I think I may have a suggestion.
    So I noticed a bit of a disconnect between the With rules and the When rules for EntitySets, specifically how Complete needs to be called only if When rules are present.
    The "When" rules are for holding all entities with a certain composition, while When holds entities of a certain composition that undergo some type of event (and are typically executed on a system by system basis).
    Maybe what can be done is the rules for "When" could be handled by a completely different type of object. Entity sets would have events for when entities are added/changed/removed, and these When objects hook into these events to update their internal state.
    Since the two would be disconnected, you could have the Entity sets be stored in a way where multiple identical copies of the sets aren't being generated if you call GetEntities over and over with the same rule set.
    Paillat Laszlo
    @Doraku
    Yeah the Complete method was the best I came up with (it can be called safely even if you don't have When rules btw). Since the processing is up to the user, it needed an api to say "ok I have finished processing this set, you can empty it". I didn't wanted to create a different type of entity container for reactive rules, which would have needed its own system implementation, the api for querying would also have also needed to be duplicated to differentiate the two mode, hence why I went that way to keep thing simpler implementation wise (but maybe a little more complicated usage wise...).
    A long time ago there was actually callbacks on set for when entities where added/removed but it has been replaced with the World level SubscribeComponent/Entity... methods which I think works better.
    I also had the idea to make EntitySet a front for the real internal container, which could have been shared between multiple EntitySet with the same query to limit memory usage. I never got around to actually doing it since in my usage I actually never had duplicated sets so I have yet to actually do it ^^"
    Lazy
    @michaelSchrier_gitlab
    The World's Subscribe method is definitely useful, but from my understanding it can only be used to hook into changes surrounding a single type of component. I mention this because Entitas' Group implementation (which is basically your EntitySet equivalent) does allow you to hook into Add/Changed/Remove on the set level, as does LeoECS with it's ECSFilterListeners, and it's a really useful feature.
    Paillat Laszlo
    @Doraku
    @michaelSchrier_gitlab after some testing that it had no impact on performance when there is no delegate, you will be happy to know that I added EntityAdded and EntityRemoved events on all DefaultEcs entity containers :)
    Lazy
    @michaelSchrier_gitlab
    @Doraku Ya it looks great. It definitely seems more complicated to do, but if you can sneak in a Entity Update/Changed event in there as well, then you'll give users the ability to create their own custom Entity collections just by making wrappers for the EntitySet and hooking into these events.
    Paillat Laszlo
    @Doraku
    Since the IEntityContainer interface emerged, I am planning on trying to make the EntitiyQueryBuilder extendable so you can create your own container types instead, making a EntityUpdate/Changed event would open up a little too much the inner working of the library which I want to keep hidden to not over complicate the api. Hopefully that would allow people to customize their storing types as they see fit relying on the same query api as everything else
    Keith Evans
    @KaynSD_twitter
    I'm assuming it's bad practice to have a database of entity references since entities are structs and are passed by value and not reference. However, there are plenty of places where I need a "get the entity where [IDComponent.value = X]", so what would a good way to achieve this be?
    (assuming for now I can guaruntee that IDComponent values are effectively unique)
    Keith Evans
    @KaynSD_twitter
    Seems somewhat overkill to use "world.GetEntities().With<GameIDComponent>(testIDMatchesWhatImLookingForMethod).AsSet().GetEntities()[0];", but that feels correct?
    Paillat Laszlo
    @Doraku
    you should use a EntityMap for this which is basically a dictionary of entity with a specific component type acting as key, so EntityMap<GameIdComponent> map = world.GetEntities().AsMap<GameIDComponent>();
    You will be able to quickly do map[componentValue] to get the corresponding entity.
    If multiple entities can have the same component value, you can change it to a EntityMultiMap too (which is roughly a Dictionary<TComponent, List<Entity>>
    Keith Evans
    @KaynSD_twitter
    What I've got is a lot of Commands that are refering to entities by ID (since the command calls can be sent from another machine to this system), so the command on Execute() needs to get the entity at that point, and then alter component values as appopriate (it's all called from within an AEntitySystem already), so seems a little excessive to store an entire EntityMap in each Command
    So for example, I've got a command buffer of ("Move", "Bob", "x=4, y=4") and ("Wave", "Bob", "At-> Jane") that gets processed in a parser, I need my MoveCommand to get the entity with an IDComponent value of Bob, and change/set it's PositionComponent to 4,4 and then need my WaveCommand to get Bob, rotate it to face the entity with ID=Jane and set the AnimationComponent to waving.
    (and then of course, since it's Command pattern, to hypothetically store this all in a History queue so I can see what's happened, and save values to Undo them later if needs be)
    Paillat Laszlo
    @Doraku
    the EntityMap would be in your systems, not in the command if I understand correctly
    (and the same EntityMap can be shared across all systems)
    Keith Evans
    @KaynSD_twitter
    Sure, but then the command would need to access that; I assume by passing the system in so it can reference that
    Because I assume having a permenant variable for the Entity inside the command is unsafe, it would need to get that every time Command.Execute() or Command.Validate() or Command.Undo() is called
    Paillat Laszlo
    @Doraku
    hum yeah, depending on what you are doing you may store the Entity directly inside the command, there are just some limitation to keep in mind:
    • as you said the Entity is a struct so if you were to Dispose this particular Entity some other places, you may access a completely different Entity than the one that you expect because the internal ids are recycled, you can put a safeguard by checking Entity.IsAlive property
    • your command can't be serialized as is, you need to replace the entity with some kind of id so you can look up the actual entity on deserialization to recreate your command
    either you reference directly Entity in your commands, or you need to change the Command api and add an EntityMap as parameter for all method to safely get the entity you want
    Keith Evans
    @KaynSD_twitter
    Yeah. The hypothetical "Move" command has EntityID, PositionX, PositionY, and then on Execute is using World.Get()..... to get the entity (somehow) and then setting it's component to PositionX,PositionY (and if already had values, stores those in a PreviousPosX and PreviousPosY for undoing, etc)
    So I imagine instead of World its better to pass in the EntityMap instead.
    Paillat Laszlo
    @Doraku
    if you were already passing a World it is definitely better, the EntityMap cache the results and is updated as the components change so it is truly an o(1) operation when accessing an Entity, the previous code world.GetEntities().With<GameIDComponent>(testIDMatchesWhatImLookingForMethod).AsSet().GetEntities()[0]; would iterate all entities every time you want to get one, even worse the created EntitySet is not disposed and it will keep receiving notifications of component changed, worsening performance little by little.
    if needed the EntityMap also expose the World it was created from as a property too
    Keith Evans
    @KaynSD_twitter
    awesome. Thanks :)
    mubiquity
    @mubiquity
    Is there a recommended way to handle optional components in systems?
    I could get the entity and use Get but that throws an exception if the component isn't available which isn't ideal.
    Paillat Laszlo
    @Doraku
    You can check if a component is actually there with entity.Has<T>() before doing the get