Lost in your ES world

Hello,

I’ve been using an E/S for one year in my game and events has been a hell to handle for me (not e/s related at all, just a bad event system), at first i was using events as components but since i was relying on system orders it naturally ended up falling apart and i had to use a more traditional event-system. I’m not pleased with my code and i kinda stumbled upon all the e/s threads on jMonkey and feel curious about how elegant the pspeed implementation is. Still i’m nowhere to have a full grasp of the architecture.

  1. You kinda give hints in another topic but are threads needed to be run at specific rates, are they pumped by some master loop ? It seems like not but i want to be sure. Is it safe to have a 1fps system ?

  2. While reading your posts i thought that an entity view was an Entity object + components clones for that specific Entity object. But now i think i was mistaken and since updating a component means creating a new one i guess Component objects are shared across several systems, sometimes all, sometimes not.

  3. I read the ogerlord implementation which has a nice diagram of the events and zay-es but i’m still lost. I’m trying to get the big picture through your sources but i’m not sure i’m understanding who’s doing what.

For example in yours setting a component is : entity set > setcomponent > entitychange > push to listeners / calling sets for change

and it goes through several classes, using thread-safe structures…

I wanted to make a diagram of my understanding of it but there’s too many things i’m not sure about that it wouldn’t make much sense so i’ll give a shot with this really brief summary :

Am i wrong in saying that :

  • Systems (sorry) holds entitysets
  • updating component values means changing a Component object linked to an Entity object (the view)
  • changing a Component implies dispatching an event to all concerned entityset
  • dispatching is made right-away (because using thread-safe structures !?)
  • every concerned entityset is queuing that change
  • the change is just the passed object
  • END OF DISPATCHING
  • whenever a system tick, it checks for changes
  • checking changes is actually eating the queue, filtering each of the potential change
  • since a change is just an object (ogerlord has order messages though) you find out depending on what you already have if it’s an add, change, deletion (not sure about the latter though)
  • done !?

I have a lot of questions game-related but i’m preventing myself to ask them since i might be wrong in my understanding of your E/S but i’ll just ask one to help you see how off i am :3

If I have a TrapSystem checking every second if a player is standing on that trap, since the systems are caching component adding/updating/removing wouldn’t the system process each of the cached positions and end up giving wrong behaviour. I don’t know if that’s rubber-duck thinking but maybe it’s not a buffer but just a cache of orders, meaning that each new component update might override the last one in the queue ? Or maybe all the old values are filtered out when applyChanges() !? hum

As a subsdiary question : I see that a lot of your iterations are made on array when looking for == instead of map, does it mean that, getting from a map can be slower than a small array loop ?

Edit : Sorry i’m saying “you” in the post, i was aiming at pspeed but of course i’m willing to listen to any kind of advice from anyone :slight_smile:

@Moop said: Hello,

I’ve been using an E/S for one year in my game and events has been a hell to handle for me (not e/s related at all, just a bad event system), at first i was using events as components but since i was relying on system orders it naturally ended up falling apart and i had to use a more traditional event-system. I’m not pleased with my code and i kinda stumbled upon all the e/s threads on jMonkey and feel curious about how elegant the pspeed implementation is. Still i’m nowhere to have a full grasp of the architecture.

  1. You kinda give hints in another topic but are threads needed to be run at specific rates, are they pumped by some master loop ? It seems like not but i want to be sure. Is it safe to have a 1fps system ?

Sure. It just depends on what you need. It’s quite common to run the physics simulation at one rate and the rest of the game (ai, game logic, etc.) at a different rate.

It’s also quite common that it is easier if some system is consistently run after another, in which case running them both from the same thread in the proper order may be best. (For example, Asteroid Panic does everything on the render thread, as I recall. Monkey Trap has one game thread separate from the render thread that runs all of the systems in order.)

@Moop said: 2) While reading your posts i thought that an entity view was an Entity object + components clones for that specific Entity object. But now i think i was mistaken and since updating a component means creating a new one i guess Component objects are shared across several systems, sometimes all, sometimes not.

They can be. Immutable components make it easier to detect changes and make threading easier. The same “value” of a component is often shared but the systems don’t need to worry about that, really. They only care about the value they have and shouldn’t worry who else is using it.

On the other hand, it’s also possible to have mutable components but then you will have to deal with threading issues inside the component itself since that component instance will be shared across many entity views. Best only done by seasoned experts, I guess. It’s a very rare need anyway (I’ve only used it in one specific case).

@Moop said: 3) I read the ogerlord implementation which has a nice diagram of the events and zay-es but i’m still lost. I’m trying to get the big picture through your sources but i’m not sure i’m understanding who’s doing what.

For example in yours setting a component is : entity set > setcomponent > entitychange > push to listeners / calling sets for change

and it goes through several classes, using thread-safe structures…

I wanted to make a diagram of my understanding of it but there’s too many things i’m not sure about that it wouldn’t make much sense so i’ll give a shot with this really brief summary :

Am i wrong in saying that :

  • Systems (sorry) holds entitysets
  • updating component values means changing a Component object linked to an Entity object (the view)
  • changing a Component implies dispatching an event to all concerned entityset
  • dispatching is made right-away (because using thread-safe structures !?)
  • every concerned entityset is queuing that change
  • the change is just the passed object
  • END OF DISPATCHING
  • whenever a system tick, it checks for changes
  • checking changes is actually eating the queue, filtering each of the potential change
  • since a change is just an object (ogerlord has order messages though) you find out depending on what you already have if it’s an add, change, deletion (not sure about the latter though)
  • done !?

This is all supposed to be invisible to you and is really just a performance optimization that Zay-ES does internally. Systems grab an EntitySet and can update it when they want a fresh view. They should not worry too much about how this happens as it isn’t at all important to the system.

Think of systems like they are running a JDBC query just for the data they are interested in. You don’t really need to worry about how it’s getting you the data other than the results/performance. (Also its similar in that you have a cached view that may not represent current data until you reissue the query.)

@Moop said: I have a lot of questions game-related but i’m preventing myself to ask them since i might be wrong in my understanding of your E/S but i’ll just ask one to help you see how off i am :3

If I have a TrapSystem checking every second if a player is standing on that trap, since the systems are caching component adding/updating/removing wouldn’t the system process each of the cached positions and end up giving wrong behaviour. I don’t know if that’s rubber-duck thinking but maybe it’s not a buffer but just a cache of orders, meaning that each new component update might override the last one in the queue ? Or maybe all the old values are filtered out when applyChanges() !? hum

As a subsdiary question : I see that a lot of your iterations are made on array when looking for == instead of map, does it mean that, getting from a map can be slower than a small array loop ?

For an array of only two or three elements (Entities hardly ever have more than two or three components) this sort of loop can be faster than a hashmap but moreover it’s a way smaller footprint. If you ever have more than four component types in an EntitySet then it’s worth reexamining the design at least lightly.

I’m not sure I understand the question about the trap system or why you would check every second.

Presuming that you even wanted such a system you could just check for an entity’s intersection when it moves instead of checking every second. Even more general, you could have a collision system that generates collision entities for moving objects (an entity created just to link to other entities together with a Collision component or something).

But the TrapSystem is a perfectly acceptable idea. I just don’t understand where the perceived conflict is. The naive implementation would have an EntitySet of traps and an EntitySet of mobs. When a mob moves, check it against the traps… and then do something.

I don’t understand this part, though: “wouldn’t the system process each of the cached positions and end up giving wrong behaviour”

Thanks for your time :D/

@pspeed said: Sure. It just depends on what you need. It's quite common to run the physics simulation at one rate and the rest of the game (ai, game logic, etc.) at a different rate.

It’s also quite common that it is easier if some system is consistently run after another, in which case running them both from the same thread in the proper order may be best. (For example, Asteroid Panic does everything on the render thread, as I recall. Monkey Trap has one game thread separate from the render thread that runs all of the systems in order.)

What would be the advantage of running them in a specific order, deterministic physics ? less latency between events ?

This is all supposed to be invisible to you and is really just a performance optimization that Zay-ES does internally. Systems grab an EntitySet and can update it when they want a fresh view. They should not worry too much about how this happens as it isn't at all important to the system.

Think of systems like they are running a JDBC query just for the data they are interested in. You don’t really need to worry about how it’s getting you the data other than the results/performance. (Also its similar in that you have a cached view that may not represent current data until you reissue the query.)

I understand that it’s just your implementation but i’m just using it as a research matter to understand the big picture. I don’t plan to duplicate it, just have a basic understanding of it so that i can make my naive and probably inefficient implementation but at least based on the right logic.

For an array of only two or three elements (Entities hardly ever have more than two or three components) this sort of loop can be faster than a hashmap but moreover it's a _way_ smaller footprint. If you ever have more than four component types in an EntitySet then it's worth reexamining the design at least lightly.

Oh i see, thanks.

I'm not sure I understand the question about the trap system or why you would check every second.

Presuming that you even wanted such a system you could just check for an entity’s intersection when it moves instead of checking every second. Even more general, you could have a collision system that generates collision entities for moving objects (an entity created just to link to other entities together with a Collision component or something).

But the TrapSystem is a perfectly acceptable idea. I just don’t understand where the perceived conflict is. The naive implementation would have an EntitySet of traps and an EntitySet of mobs. When a mob moves, check it against the traps… and then do something.

I don’t understand this part, though: “wouldn’t the system process each of the cached positions and end up giving wrong behaviour”

Yeah it might not be the perfect system but i wanted to understand the queue thing, it’s implementation, alright, but it defines game-code as i (mis)-understand it at the moment.

You have a queue of events in your entitysets which i assume are there for thread-safety and/or performances. I assumed that when you applyChanges() you check if there’s a change, and if so, you process the queue.

I thought the queue would be a list of EntityChange each pointing to a component; the first change in the list would be PlayerPosition at 10,20, PlayerPosition at 10,30… and then you would filter this list whenever the system needs those datas.

Hence the fake scenario of having to process cached positions that the TrapSystem wouldn’t care between those 1second ticks…

I’m still in the mist with where the data comes from, it feels like you could load the datas just once and just pass around the components during the game without having to touch the db/map at all. =_=

To me one of the huge benefit of your architecture is that you don’t care about system ordering, which would mean that if a player dies from a spell, even if the DamageSystem says “player dead”, the AnimationSystem maybe didn’t even notice the spell action yet but will process it one or more ticks later and since this system is living in its own world, it doesn’t matter. (or does it ?)

I always had issues with triggers, chained events and just proper design :

Let’s say my player is casting a spell, not from inputs but by validating a certain amount of conditions to happen, and that when that happens, a X animation (not the spell one) is started at the position of the spell. Do you handle the trigger of the X animation in the source System, let’s say DamageSystem is triggering a spell (the real one) when life is under 10, or in the AnimationSystem when noticing that there’s a new Entity added with an AnimationComponent, i guess not the latter otherwise AnimationSystem would have to handle all the cases where something special is happening.

I guess what i’m asking is : would i need to send some kind of “createThisEntity” component and catching it in what sounds like the appropriate system, the AnimationSystem or just create the entity as soon as possible. I kinda used to do the first one but it never ended well.

So i’m following my gut thinking that you should create everything at the source, the spell is casted but this is a chained event so the spell entity actually have a ChainedComponent with a list of spell types that will be chained. The spell did his job and is removed, There’s a ChainedSpellSystem which is looking for ChainedComponent and whenever he sees that an entity having this component is going to be removed, spawn another spell entity looking at the next spell in the ChainedComponent list. and create a new ChainedComponent for the new spell entity with the left spells to process.

It means that this system is basically just handling the case where an entity having a specific component is going to be removed, is it ok ? Is it common to have some kind of filter systems ? It seems almost like the core of it but how fine-grained do you go ?

Let’s say i have an InputSystem which is feeding an inputComponent with appropriate states, now probably in the game, inputs are not doing the same things depending on the situation, so maybe you have a new field “inputMode” in inputComponent or maybe a new component InputModeComponent. So now an inputModeSystem is probably handling inputs as proper orders (could be handled in the InputSystem though), so if i click left in attack inputmode a startAttackComponent will probably be attached to my entity.

Then the AttackSystem will catch the startAttackComponent and depending on my class, level… will spawn the approriate spell entity.
But it could have been handled right from the InputSystem or InputModeSystem and to me it’s hard sometimes to see who should delegate stuff.

I can clearly see an attack passing through several systems. Which would mean that if all the systems are running at the same tickrate, an action would take as many tick time as the number of systems the event is going to pass through. Not a complaint about latency or anything just checking out if i’m right or wrong.

Do you dare handling GUI stuff or more accurately mouse events interaction with GUI & Map and units… in a ES ?

I’m doing an action strategy game and while i used to think it’s good to not make everything ES my whole game is basically mouse interaction with my game so it’s hard to dissociate.

Still in my game, my map is basically a big list with block IDs, i make quite a lot of flood fill so i can’t really make each tile an entity and i don’t think you would have recommended that anyway :slight_smile:

But the interface can be tricky, i make a building, it has to be somewhere in my map(list) and in the meantime i need an entity to show it in my game with health and other attributes. The health being actually within an healthmap so there’s some synchronization to do that i’m not always comfortable with but there i have no choice. I might be overthinking this, it may not be that annoying in the end we’ll see.

Well a es shines really if you have a complex backend, if its mostly a complex frontend the benefit is low, while you still have all of the contras in regard to different thinking than oop necessary.

At the moment yes, the frontend outweight the backend complexity-wise. Now i’m not sure it will always be the case in my project; but even so, one of the reason i’m using an ES (i already have a working implementation) is for networking and the ease of serialization of components.

It doesn’t mean that using it is a good idea in my case but well i guess it’s hard for me to go back to clusterfuckland.

Your post was a lot to take in and much of it was speculation on different ways to implement something when I wasn’t even clear how it should look to the game or to the user. Maybe you can just describe the behavior you want to see from the users perspective and I can work from there?

Regarding how Zay-es’s internal change queue works, it’s a performance optimization so that when you call applyChanges() I don’t have to query all of the entities again. Internally, the ES has been tracking all of the relevant changes for that set and so can just apply them without having to rebuild the whole thing. But conceptually, you can think of it like reissuing the query.

Regarding system ordering, generally you are right that it shouldn’t matter but some logic might get simpler if you can rely on it. So don’t discount it as a tool in some cases. And sometimes ordering is not important but knowing that the frames are all in lock-step together can be. For example, if something like the AI system is moving a bunch of entities around then the other systems get a more consistent state if they only update when the AI system is known to be done for that frame. Generally frames are coming fast enough that it doesn’t really matter. Monkey Trap is running its game logic loop at only 10 hz and I recall one or two of the systems being simpler to write because they could count on consistent views of frames. At 10 hz things matter that might not at 60 hz, I guess. I’d have to go through my comments again to see what the issue was.

Thanks for your answer and sorry for that wall of text.

I’m finally finding some time to actually make an implementation and have more concrete questions.

I’m trying to make as few locks as possible and i’ve seen in some of your source comments that sometimes you made some tradeoffs by allowing a bit more hit to reduce the number of locks but it’s still a bit hard to follow the path of events for me and you’re gonna tell that i’m discussing implementation again and that it doesn’t matter but still…

The concurrency java package kinda abstract the lock part (i’m not working in java, sorry if it’s an heresy to take your time for a non jme user) but in a good way but harder for me to see all the threads interactions.

So basically my question is, when do you lock ?

I feel like everytime a system (EntityData?) is pushing a change it has to dispatch to the other ones, that’s one lock for me. And the second one would be when applyChanges(), when you need to apply the filter, you have to know what other components the changed entity has to satisfy the filter !?

Am i wrong with this ?

@Moop said: Thanks for your answer and sorry for that wall of text.

I’m finally finding some time to actually make an implementation and have more concrete questions.

I’m trying to make as few locks as possible and i’ve seen in some of your source comments that sometimes you made some tradeoffs by allowing a bit more hit to reduce the number of locks but it’s still a bit hard to follow the path of events for me and you’re gonna tell that i’m discussing implementation again and that it doesn’t matter but still…

The concurrency java package kinda abstract the lock part (i’m not working in java, sorry if it’s an heresy to take your time for a non jme user) but in a good way but harder for me to see all the threads interactions.

So basically my question is, when do you lock ?

I feel like everytime a system (EntityData?) is pushing a change it has to dispatch to the other ones, that’s one lock for me. And the second one would be when applyChanges(), when you need to apply the filter, you have to know what other components the changed entity has to satisfy the filter !?

I’m i wrong with this ?

applyChanges() is just emptying a thread-safe queue of changes that have accumulated since the last time it was called.

There is very little need to ‘lock’ anything since every EntitySet is its own view of the data.

It’s really best if you think of it as a bunch of computers on a network, each one of them iterating over the joined tables that it finds relevant to its task and writing out to some other tables. You’d have extremely minimal coordination in this type of setup.

Now, Zay-ES takes advantage of the fact that all of this is really running in the same VM, so it can optimize the “requery” step. Even in a distributed system this kind of thing could be done but it would require either some shared cache or marking the records or a combination of the two. (I designed a few napkin-level approaches just to make sure that the Zay-ES API would still work but I haven’t actually implemented anything like that.)

What language are you using?

Basically, if your language doesn’t have cheap thread safe queues then that’s where you should start. So many threading issues can be solved with clever application of queues.

I guess you are talking about ConcurrentLinkedQueue (changes) !?

My understanding of it is that you are feeding that queue from another thread but still every time you’re accessing it there’s some kind of locking logic behind it.

I’m still not sure how the filter is working, i guess every system has basically more or less the same elements in the queue and applyFilter sorts them out, but to do that it needs to know if a component change is from an entity which satisfies the system filter so it needs to access to some kind of master list of entity to check what other components this entity has (through locks !?)

I’m using Haxe (which compiles to several languages) and there’s actually no thread abstraction across languages targets, i can still access to some very basic thread functions for most of the supported languages like cpp/neko/java

http://api.haxe.org/cpp/vm/Thread.html
http://api.haxe.org/cpp/vm/Mutex.html

My point with this project is to have a satisfying architecture and being able to use it either non-threaded (client) or threaded (server) given a proper abstraction.

So even if i’m not that interested in threading for now, as you said, it’s free so i’m trying to at least have something working.

Note : I’m really new to the Thread world, to me a Mutex is the same than a Lock but it seems to not be the case, so here is where i am. Still i guess i could just add mutexes in a data structure and be good with that.

@Moop said: I guess you are talking about ConcurrentLinkedQueue (changes) !?

My understanding of it is that you are feeding that queue from another thread but still every time you’re accessing it there’s some kind of locking logic behind it.

Well, the literature is available. There are ways to do lock-free queues and there are much more complicated things. Knowing the difference between ‘volatile’, ‘memory barriers’, ‘synchronized’, ‘object monitors’, ‘locks’, etc. is important if you are going to be rolling your own threading stuff. I’m very well read on the subject and I don’t think I’d ever attempt it without a gun to my head. People way smarter than I am about threading wrote java.lang.concurrent and I’d been reading Doug Lea’s writing for years before these decent thread constructs started showing up.

At any rate, there are a couple ways to make “wait free” thread safe data structures. The javadoc of ConcurrentLinkedQueue might be a good place to start.

If you dig deep into threading architecture it might literally blow your mind. Wrapping ones head around things like why “double checked locking” was/is bad and when (hint: used to be always bad but now can be used in some isolated cases with proper volatile usage) and other multicore spin-lock or “wait free” designs can really warp a person.

I'm still not sure how the filter is working, i guess every *system* has basically more or less the same elements in the queue and applyFilter sorts them out, but to do that it needs to know if a component change is from an entity which satisfies the system filter so it needs to access to some kind of master list of entity to check what other components this entity has (through locks !?)

The entity set knows what components it is interested in and will automatically reject components that aren’t in that set. Otherwise, it optimistically holds the changes events until applyChanges() and then throws away what it doesn’t need. With filters, predetermining this accurately is essentially impossible without a whole bunch of state management. For example, if a component doesn’t match the filter but is otherwise a type for the entity set then I still need to keep it because it might be the thing that causes it to be removed from the set.

@pspeed said: Well, the literature is available. There are ways to do lock-free queues and there are much more complicated things. Knowing the difference between 'volatile', 'memory barriers', 'synchronized', 'object monitors', 'locks', etc. is important if you are going to be rolling your own threading stuff. I'm very well read on the subject and I don't think I'd ever attempt it without a gun to my head. People way smarter than I am about threading wrote java.lang.concurrent and I'd been reading Doug Lea's writing for years before these decent thread constructs started showing up.

At any rate, there are a couple ways to make “wait free” thread safe data structures. The javadoc of ConcurrentLinkedQueue might be a good place to start.

If you dig deep into threading architecture it might literally blow your mind. Wrapping ones head around things like why “double checked locking” was/is bad and when (hint: used to be always bad but now can be used in some isolated cases with proper volatile usage) and other multicore spin-lock or “wait free” designs can really warp a person.

Wow thanks for the answer, i had a quick look at the paper, it’s interesting but i admit it’s a bit discouraging for someone who only wanted to make a simple implementation, now i’m jealous of your java.util.concurrent package.

The entity set knows what components it is interested in and will automatically reject components that aren't in that set. Otherwise, it optimistically holds the changes events until applyChanges() and then throws away what it doesn't need. With filters, predetermining this accurately is essentially impossible without a whole bunch of state management. For example, if a component doesn't match the filter but is otherwise a type for the entity set then I still need to keep it because it might be the thing that causes it to be removed from the set.
I'm sorry, i feel like the answer is in there but i'm not sure i understand it.

It seems like any change is made via EntityChange and that deltas from this EntityChange and what you have or don’t have in the entitySets will flag a change as an add/mod/remove but there are a few things i don’t get, how do you detect a “remove” since EntityChange doesn’t seem to hold any kind of messageType variable (which i think is because the architecture is decoupled).

Back to the filter, as you said if i receive a change for a component which is required for the entitySet but which is bound to an entity that doesn’t have this second Component needed for the entitySet, how do you know that the entity doesn’t have this second component from an EntityChange object. It seems like entity is only holding components required from the entityset so it doesn’t help much, unless you’re actually keeping track of what other components (even if not needed) every entity has !?

For example, if a component doesn't match the filter but is otherwise a type for the entity set then I still need to keep it because it might be the thing that causes it to be removed from the set.

I feel like i almost get this : an entity which has a component change but doesn’t satisfy the entityset might imply that the entity had his second component removed and then makes it a “remove entity” order !? (that would explain the “how you detect a remove” question) But this is assuming that a change has been dispatched after a component remove. What if from another EntityData, the entity is removed without components dispatching anything (since there’s no change) what kind of message will you catch from the other EntityDatas to say that the entity has been removed ?

I, maybe naively, thought that changes contain ANY component change in the entire program and that applyChanges will apply the filter at that time maybe there’s some prelogic that i’m not aware of. How do you detect entity adds is probably what would help me the most.

It seems weird to explain in detail what the code is already clearly explaining if you just look in DefaultEntitySet.java.

Essentially, if an EntitySet is watching A, B, and C components then the change queue will have all changed A, B, and C components since the last time the queue was emptied.

During applyChanges, all changes are applied. If there is a change for an entity that was not in the EntitySet before then it is created and added to the ‘potential adds’ set. After all changes have been applied, if that entity has any components missing then an attempt to retrieve them is made. If the attempt fails then the entity is not really in the set and so is ignored. If the entity has A, B, and C components and they match the filter then it is a new added entity for the set.