Events missing



  • Since you suggest using event emitters, you mean asynchronous operations. But the players' code in Screeps runs strictly synchronously which is an important architectural element. The API explicitly does not imply any possibility of asynchronous calls, or else it would affect the whole concept of tracking player's CPU per tick and interruption in case of its exceeding. The main script of one player is fully executed, then server processor time is fully passed to another player. If asynchronous events are allowed, another player could interfere in this process and violate the CPU calculation.

    However, if you mean game events that occurred during the preceding tick rather than asynchronous events, we are considering this possibility. But there is still no reason to implement the Creep.onDeath event handler since a creep is still alive a tick before death, and in the next tick the object Creep does not exist anymore, so there is nobody to call the event from. Rather, we are considering adding a shared log of all room events that occurred in the latest tick. It will require heavy amount of traffic between runtime servers and the database, so we'll have to seriously think about optimization in this case.



  • I just added a feature request to add a message queue to the Room objects. Events could be generated by inserting a message into the Room message que, that the user could process during the next tick.



  • Dear Anton, thanks for your valuable input. I think there was a misunderstanding. I am fully aware of the ticked based architecture of screeps. (Strictly speeking, classical JS isn't fully asynchronous as well, as it's single threaded and uses an event stack to handle asynchronous calls). Also, I didn't mention Creeps dying, because this is a case which is very easy to detect.

    Let me explain my thought on the attack event:

    Of course the player can detect, whether a creep is being attacked, by tracking the health of all their creeps. In a battle however, you can't tell which creep was attacked by which enemy, since you only have the health information. However, the attack method could emit an attack event (on successful attacks), which would accordingly land in a message queue (which is the according implementation if asynchronous processing is not supported). Then one could check this queue in the next tick and see exactly, which creep was attacked by which enemy. As this is something which you already seem to consider, I will eagerly await your solution;) Rather than always logging all events in a room, you could give the player the option to opt out/in for certain events, which reduces the effort on both - your's and the player's - sides.



  • I really can't see any value in the event that creep has been attacked. You still have to act with a creep based on it current status.
    Acting on the attack event would be useful only for this one tick - tick after the attack, after that tick, creep is still in need of healing or moving to safety, but you have no event.
    You still have to check all the creeps on subsequent ticks and then act upon their status.

    Thus having this event fire once when the creep was first damaged offers zero benefit and would be actually harmful - duplicate effort by the player for the same thing, wasted effort by developers for stuff you don't really need.



  • If the queue persists from tick to tick, then there absolutely is a benefit. It could eliminate tons and tons and tons of polling each tick. if creep.hits < creep.hitsMax no longer needs to be checked for each creep. you get a message once (attacked) you know the specific creep. you don't need to loop over every creep to check. you just add the creep to a heal queue. then you can check only the creeps in the heal queue to target for a while hits < hitsMax loop to send your healers to.

    I won't get in an argument with the devs of the game.. if you don't want to do it, that's your choice of course.. but it absolutely can save cpu time to generate events and have them be responded to, rather than polling, especially if there are numerous creeps.. And extra especially if there are numerous creeps across numerous players.

    Also, if you don't want to generate a persistent message queue across ticks, that's fine, just tell people they have only 1 tick to take their messages out of the tick queue and put them in memory themselves.. You don't even have to change the tutorial, people can still do polling, they just have the option of being more efficient with message processing if they want to.



  • Events are wrong tool for the stated problem - OP wants events, but OP really needs a finite-state automata.
    Creep poll can't be eliminated due the nature of the game. Since it can't be eliminated, it's relatively cheap to incorporate aotomata state updates, based on creep current statistics and data stored in its memory, into this creep poll loop.
    Actions that creep does or that will be done on him, can then take this creep state into consideration.



  • take an example of a rampart attacked then. I may only scan my ramparts infrequently to save CPU. I'll stop arguing. You are correct about every creep needing a visit each turn.



  • Ok, time to kill some myths:

    • Event loops Its true that they can be simulated. But does it fit in fixing the problem
    • Death creeps Event trigger is no solution if the simulator itself can't reliable tell (timeouts) if the event has been handles. A solution has to fix within the screeps architecture. Logs or event history queue's may be a better solution.
    • creep.hits < creep.hitsMax is actually close to a no-op compared to computing done to complete a path finder. If you believe this is not true, run benchmarks and try to find the biggest time waster or post a question/discussion. Maybe we need some public benchmarks about this.
    • creep.hits < creep.hitsMax part II: its very easy to disagree with a certain architecture. It's also easy to get exhausted from these kinds of discussions as well 😉


  • just to clarify, I'm not proposing event triggers, I'm suggesting a message queue of events (and other user communication) that can be processed by the user each tick. see my other post linked in an earlier message



  • @nugarin: FSM and Events are two completely separate paradigms! They have nothing to do with each other. Did you ever hear of event driven FSM?
    Anyway, at the moment, there are situations which can lead to an "indeterminate" state of the FSM due to a lack of information, which could be leveraged with events.

    To make my point clear:

    The event system I would like to have:

    You subscribe to certain events, which (in case they are emitted) land in an event queue that can be processed in the next tick.

    Reason:

    Case 1:

    Two enemy creeps with 60 damage each - both in range to your creep, which receives exatly this 60 damage - which of the enemy creeps attacked yours? You can't decide, because you're lacking information. With events on the other hand, you process the emitted attack event (which includes the attacker information) and simply update your FSM accordingly.

    Case 2:

    A construction site finished. In the next tick, it's ID is not valid anymore. Thus you have to do several steps, to 1) register the new structure 2) reassign the worker. Of course, it can be done, but it just would be way easier, if you had an according event with the necessary information, e.g. the id of the former constructionsite and the id, type and position of the new structure.



  • I never said that FSM and events are connected. What I said is that your problems are better solved by using FSMs. Events are horrible solutions to both of your cases.
    Case 1 - it's really not important which of the enemy creeps attacked you, what is important, is their potential for the attack, which you would have to check for anyway.
    Case 2 - you loop construction sites for build anyway, removing an id from the list is not expensive. Events won't really make it easier, you still have to id sites that you don't have events for at initial stage, then keep your data model in sync as events fire - how is this any better than just getting these structures from game data model with appropriate filters applied?
    When you have a hammer, everything you see is a nail, now you don't have a hammer, but you want one to hammer in that philips-head screw.



  • well, you either are incapable or just don't want to understand my point. Also you seem to confuse terms here and contradict yourself. We obviously have different opinion on that matter, so it's no use arguing about it. I guess this thread can be closed, since there will be not much valuable input anyway.



  • I'm still wondering though why it takes such a fight to at least trying to get a clear solution.

    If we all would agree that something is a good solution, the solution is easy to integrate (some easy to implement code for example), we might not be in such a situation.

    Anyway, things takes time, lets at least hope we've learned something out of this.



  • I was just gonna post about this and stumbled about this thread in the procedure, and I very much agree to what chris said, especially the two examples he gave which I was gonna post myself (damage identifying the source; construction finished - identifying the new structure). I believe something needs to be done to let us REACT to stuff instead of just ACTING - if events aren't possible, some other solution needs to be found. I believe this could potentially even reduce CPU usage overall and thus reduce server load, since we wouldn't need to actively scan and monitor stuff quite as much as we do now. 

    and btw:

    > Case 1 - it's really not important which of the enemy creeps attacked you, what is important, is their potential for the attack, which you would have to check for anyway.

    yes it is important, if those creeps belong to different players, or to a player and invaders, in terms of diplomacy. For example, I might wanna have code that makes sure that my creeps do not attack a certain player unless he attacks me first - which is basically impossible with the current API, because scripts are completely unable to know who attacked.