playMaker

Author Topic: Return behavior of "Send Event" [SOLVED PARTIALLY]  (Read 5250 times)

FrozenTarzan

  • Playmaker Newbie
  • *
  • Posts: 9
Return behavior of "Send Event" [SOLVED PARTIALLY]
« on: September 13, 2013, 04:30:36 PM »
Hi,

I have a FSM, called A, that holds a reference to a gameobject. I want to change this gameobject from another FSM, called B. But I want FSM A to be able to react to the change, maybe because some exit/cleanup method has to be called. So I basically want to send an event from FSM B with the new gameobject to FSM A. Then FSM A could handle the event, call the exit/cleanup stuff and finally change its reference of the gameobject with the new one.
How could I realize this behavior?
[EDIT]: I have solved this by using the "Set Event Data" and "Get Event Info" actions. :-)

And here is an extended problem problem:
I have to send more than one gameobject to FSM A, because it holds multiple references to all kind of gameobjects/variables. So I basically want to create a custom Event with custom parameters, that can be sent from FSM B to FSM A.
Is this possible?
[EDIT]: I found this post here from jeanfabre:
Quote
-- send a event to a Fsm, that fsm will then query the caller or what it needs when it receives that events, this is much easier, but introduce some dependancies, aka the receiver has to know where to get the informations. This is solved by creating what I call "META" Fsm, that acts as data repository, so if I have a player, all my enemies have a reference of "META PLAYER" fsm, and when the player wants to comnunicate with an enemy, it send an event, with no data, and the enemy simply pull from "META PLAYER" what it needs to react and act upon this event.

What I have done right now:
FSM A holds the reference/references. FSM B sends an event "Reset gameobjects". FSM A calls some exit/cleanup stuff for the objects. Then FSM B sets all the variables directly in FSM A. But here is the danger! Is it guaranteed that the "Send Event" for "Reset gameobjects" is processed BEFORE the direct setting happens? Is it possible that FSM A (holding the data) receives the "Reset gameobjects" event and FSM B sets the variables BEFORE FSM A was able to react to the event (calling cleanup stuff)?

I come from C++ and all my FSMs were designed like this:  All generated events were pushed directly into a queue and were processed in another iteration. This is really useful, because the program flow is easy to understand. Only one iteration of events is handled at a time. The programmer could then choose if he/she wants to process an other iteration... and another... but only one set of events at a time. In this case the solution above would fail completely!

I quess all my questions are a bit confusing, but being a programmer I need to know a lot of the technology underneath, so we don't run into problems later on.

Thanks!
« Last Edit: September 14, 2013, 07:06:11 AM by FrozenTarzan »

jeanfabre

  • Administrator
  • Hero Member
  • *****
  • Posts: 15500
  • Official Playmaker Support
Re: Return behavior of "Send Event" [SOLVED PARTIALLY]
« Reply #1 on: September 16, 2013, 01:50:19 AM »
Hi,

 yes, events do not bubble up, that's a bit frustrating in some cases ( for advanced use and framework design). I am facing this currently actually. So typically, set your mind to the fact that events are one way only. Passing information with the event is possible but information can not be passed back to the sender as is.

 What I do, is complety bin this kind of expectations and try to simply find another way. Typically what works for me is:

-- maintain hashtables of data for fsm that receives a particular event can refer to instead of the bubble up mechanism, each fsm is aware of the location of that common hashtable and so data can be get/set at anytime during the processing of a particualr event by several fsm. BE CAREFUL of the order of execution tho. that also solves a lot of data accessing problems, where fsm have to know too much about others ( breaks encapsulation), by opening a special place where data is publicly share, I keep individual fsm encapsulated. It does mean a lot of careful thinking to design your processes properly around that design pattern.

-- have two events: "DO SOMETHING" and "DO SOMETHING CALLBACK" that works quite well, and it actually makes things very clear. To keep things clean I use a trick, I use "/" in my variables and events name, it separate them in menus. So if you write "DO SOMETHING / FORWARD" and "DO SOMETHING / CALLBACK" then in menus, it will show in the first level "DO SOMETHING" and then two sub entries "FORWARD" and "BACKWARD".

-- make it so that it doesn't need data back. Maybe pass it on demand, or simply find another way to design your feature so that you don't need information back. Sometimes it's possible.


in your particular case I would go very granular on the tasks, and have an event call "I CHANGED FSM" or something and then anyone interested in watching for changes can do so. You pass as event data whatever is need to know what gameObject changed, and like triggers you can then filter these events to ignore what's not relevant for a given fsm or context. Note that, as part of some advanced integration, I sometime generate events using a string, so that they are local, not global, and then I can have "I CHANGED FSM A", I CHANGED FSM B" etc. this way I don't pollute the public list of global events with these very hardcoded event. BUT under the hood I can really send a particular to only the fsm that requires it. It's not really scalable because it requires clean and standardize design, if you change one event, you will have to manually refactor them everywhere, something that playmaker does automatically if you are using global events or local events properly.


Bye,

 Jean


FrozenTarzan

  • Playmaker Newbie
  • *
  • Posts: 9
Re: Return behavior of "Send Event" [SOLVED PARTIALLY]
« Reply #2 on: September 16, 2013, 04:46:46 AM »
I think these are major design flaws, what I, and I guess a lot of others, would like:
* When sending event data, this data is defined per event, not a static/global limited structure that is overwritten by each other event.

* This would enable a redesign of Playmaker, so events are being processed like events and not (like it is now!) like method calls. Basically what playmaker does is not handling events in the original meaning, it just calls a method directly. And the data "sent" to an object is not sent at all, it simply sits in a global space and hopes that nobody overwrites it in the meantime. So the receiver HAS TO read back the data immediately so that the data is not lost.

* jeanfabre do you refer to "bubbling" as the mechanism and ability of processing events after each other as separate objects/commands with their own data like i have described it?

* Those major changes would break all existing code/fsms out there, but I think there is no architectural reason to not implement this in such a way, am I right?

* If it is not possible, I would at least suggest that the EventData structure can be extended in a useful way. Since the EventData is simply global memory, I can use my own memory, sure. But I think those type of things should be rethought in Playmaker itself. I use playmaker to overcome problems like global data, strings for eventnames, etc. and i see there is a lot of potential in Playmaker, but there is still a lot missing...

* The suggestion of the "EventHappendForward" and "EventHappendCallback" is a nice technique, though :-)

jeanfabre

  • Administrator
  • Hero Member
  • *****
  • Posts: 15500
  • Official Playmaker Support
Re: Return behavior of "Send Event" [SOLVED PARTIALLY]
« Reply #3 on: September 16, 2013, 08:05:37 AM »
Hi,

Nice thread! I like discussing these things :)

I think these are major design flaws, what I, and I guess a lot of others, would like:
* When sending event data, this data is defined per event, not a static/global limited structure that is overwritten by each other event.

That's case actually, each Fsm event host its data. NOW, if another event is fired, data is overwriten, if that's what you mean. And that's fine that data gets overwriten because if your FSM responds to both, it means it would switch states and therefore context, so it's a very important rule that event data is processes as early as possible in the state stack, preferably in the very same state that implemented the global event. in that regards, event data from a previous events would be very confusing actually because the FSM moved on to a completly different state and flow. So in a way I ( personaly) think it's the right approach actually that event data does not persist, just as event do not persist neither. Event data goes away ( at least should be not relied upon) with the event flow of states.

Quote
* This would enable a redesign of Playmaker, so events are being processed like events and not (like it is now!) like method calls. Basically what playmaker does is not handling events in the original meaning, it just calls a method directly. And the data "sent" to an object is not sent at all, it simply sits in a global space and hopes that nobody overwrites it in the meantime. So the receiver HAS TO read back the data immediately so that the data is not lost.

Yes. It's good analogy, PlayMaker events are really methods actually. I guess this comes from the fact that PlayMaker events adhere to the "FSM" meaning of "event".
http://en.wikipedia.org/wiki/Finite-state_machine

Quote
* jeanfabre do you refer to "bubbling" as the mechanism and ability of processing events after each other as separate objects/commands with their own data like i have described it?

No, I meant by bubbling, the behavior we see on some events framework where event data and flow is climbing up the chain of recipients.

http://stackoverflow.com/questions/4616694/what-is-event-bubbling-and-capturing

so events would go down the chain, and up again ( PlayMaker only goes down to states implementing an event, not back)

Quote
* If it is not possible, I would at least suggest that the EventData structure can be extended in a useful way. Since the EventData is simply global memory, I can use my own memory, sure. But I think those type of things should be rethought in Playmaker itself. I use playmaker to overcome problems like global data, strings for eventnames, etc. and i see there is a lot of potential in Playmaker, but there is still a lot missing...

I created a system where you can pass more data to events. you can certainly expand on these custom actions to do a lot more actually:

http://hutonggames.com/playmakerforum/index.php?topic=4296.msg20172#msg20172

Quote
* The suggestion of the "EventHappendForward" and "EventHappendCallback" is a nice technique, though :-)

Yeah, that's so far the best approach to work with PlayMaker, instead of against.

I would also certainly appreciate an event system with more raw power, but I definitly understand that it would break PlayMaker main reason of being; it would become basically as "hard" as conventionnal scripting in a way :)

I would very much enjoy discussing a use case for where PlayMaker events do not fit, that would be very good to see how we can overcome this properly. So if you have a use case, let me know and I'll do a unity scene trying to solve this elegantly.


 Bye,

 Jean

FrozenTarzan

  • Playmaker Newbie
  • *
  • Posts: 9
Re: Return behavior of "Send Event" [SOLVED PARTIALLY]
« Reply #4 on: September 16, 2013, 06:13:37 PM »
Hey jeanfabre your comments and forum activity are amazing, thanks! :-)

Quote
And that's fine that data gets overwriten because if your FSM responds to both, it means it would switch states and therefore context, so it's a very important rule that event data is processes as early as possible in the state stack, preferably in the very same state that implemented the global event. in that regards, event data from a previous events would be very confusing actually because the FSM moved on to a completly different state and flow.

I think you have misunderstood my concept: Each event is packed with its relevant data to one message/object/event/packet. So when an event happens the waiting/listening FSMs do not get informed right away. Instead the message/event (including the data!) is pushed into a messaging-queue. The call to the queue returns immediately and the sender can switch state or do what ever it wants. The events are then processed in another iteration. This concept is described in "Games Coding Complete" (by Mike McShaffry). I try to give a picture:

Involved Objects:
* Global Messaging System handling the event (+data) and the queue
* Player (holding a gun, what else?!)
* Enemy (running in circles)
* SoundManager (wondering why the world is so cruel)

Now the Player shoots. The Player object creates an instance of an event called "PlayerShot". This event is a class and has its own clear and type-safe definition. It includes the Player ID, the position of the player and the weapon type used for the shot. This event is handed to the Messaging System (MS), which pushes the event (+data!) into a queue. After the call to the MS the call returns and no other code has been processed yet. The Player reacts to the shot himself and plays some animation and checks for current ammunition etc. Then the rest of the Player's code is completed and other objects do their stuff in their Update() method, eventually pushing new events with their own data into the queue of the MS. After all those objects have been updated the method "ProcessEvents()" from the MS is called. The events are taken from the queue, one by one, being in the correct order of their appearance, and the listeners (we could call them observers, because its a similar pattern here) are notified by calling the method "HandleEvent(IEvent event)". The Enemy is such a listener and determines the type of the event (this can be tricky in C++ so that it is sort of type-safe, but with little dependencies to lower compilation times) and reacts accordingly by checking data like the position of the event, he might be hearing the shot and wants to take cover or uses the information about the weapon type to switch to an other, more efficient tactic. In the methods handling the event new events can be pushed into the messaging queue, but this time in a new one, because the MS uses a DOUBLE BUFFER queue. After the Enemy, the SoundManager (another listener for this event) is notified and takes the position from the event for some 3D sound effects, also taking the weapon type into account.

When the queue is empty, the Messaging System swaps buffers and processes the other queue. There is no difference to the first queue! This double buffer queue simply offers the ability for the programmer to limit the processing iterations per update loop.

The advantages of such a systems are:
* The code is very clear and developers can follow the code easily and the debugging works like charm because there are no calls to completely different objects where the programmer doesn't know how the listener reacts. Instead, the programmer knows "ok, I've sent my message, everybody interested in it will do something, not my problem anymore"
* The events carry all important information with them, similar to a snapshot of the time when the event happened. The shot from the example above happened with a weapon type at a position from a player, and nothing will ever change this event.

Quote
Yes. It's good analogy, PlayMaker events are really methods actually. I guess this comes from the fact that PlayMaker events adhere to the "FSM" meaning of "event".
At first I thought that Playmaker uses events, but now I realize that they are no events in this sense. You are absolutely right, when you see Playmaker as a system for FSMs only. But in the last projects, I was involved in, I realized that FSMs are not enough for a stable and decoupled system. And a messaging system seems to fit perfectly into the system Playmaker offers right now.

Quote
I created a system where you can pass more data to events.
Thanks, I will take a look at your scripts. :-)

Quote
So if you have a use case, let me know and I'll do a unity scene trying to solve this elegantly.
Is this thread the right place? Should I open a new one, but what would be a useful title? Maybe "Playmaker FSM design discussion for a larger game project"?

jeanfabre

  • Administrator
  • Hero Member
  • *****
  • Posts: 15500
  • Official Playmaker Support
Re: Return behavior of "Send Event" [SOLVED PARTIALLY]
« Reply #5 on: September 17, 2013, 04:08:33 AM »
Hi,

 I see what you mean now.

I think maybe what you expect from "events" should be something totally abstracted away from PlayMaker event implementation and something new created for the purpose. Something called "Message" as you very well named it Global Messaging System.

I don't think Stacking events is a good thing in an FSM environment, but having this kind of power is however welcome indeed.

To solve this ( I faced the same needs too :) ) I implemented the following design pattern.

 I react instantly to what ever event, and I forward that event internaly in a given fsm to another fsm to get processed in its own time.

Typically. Sound Manager needs to do a lot of stuff when triggering a sound, it may need to download it, stop other sounds, check for context to play variants of the sound.

so when the sound Manager front end receives the event "PLAYER FIRES", the sound manager actually doesn't do the job, it merely dispatch to another fsm that is responsible for handing a shot sound effect, it will do it in its own time and doesn't care about who wanted to hear a shot, be it the user that fires the shot in purpose, or programmatically.

With this one level of indirection you can stack repetitive calls. Indeed it's the job of the the sound Manager to stack it up, but the Fsm responsible for the final implementation is unaware of it, it woul dsimply callback the gameobject that triggered that event to say the feature was executed. The sound manager would then process the next event in the stack.

to maintain events stack ( playmaker event stacks), you can use  ArrayMaker, and store references to events, its data, etc etc, and implement a first in last out or first in first out iteration process based on your need. the sound manager fsm would expect a call back event to know that event has been processed. so we would have

-- "PLAYER FIRES" as the main global way to dispatch to the game that the player fired
-- the sound manager implements that call, and stack it together with its data
-- the sound manager then fires an event to its own childs or some gameobejct that it's responsible, something like "PLAY SHOOT SOUND" and would expect/listen to "PLAY SHOOT DONE" to remove the last or first entry in the stack ( one could even go further and have ids for each events, that's possible too).
-- When receiving "PLAY SHOOT DONE", the sound manager check the first or last entry in the stack and process it by firing again "PLAY SHOOT SOUND" and deleting that particular entry in the stack ONLY when it receives "PLAY SHOOT DONE"

All this is possible only with playmaker and arrayMaker.

Does that sound like something that could solve your needs?

bye,

Jean

FrozenTarzan

  • Playmaker Newbie
  • *
  • Posts: 9
Re: Return behavior of "Send Event" [SOLVED PARTIALLY]
« Reply #6 on: September 17, 2013, 05:42:15 AM »
Quote
I don't think Stacking events is a good thing in an FSM environment, but having this kind of power is however welcome indeed.
I don't want to be too picky, but "stacking" events is what actually happens in Playmaker right now. When an event happens (goes on the stack) another event can be processes before the first one. In a decoupled system the events have to use a queue, where it is not possible that an event is being processed before another one. The relative timing of events is important and preserved that way.

By the way, the concept of the event stack is the reason why "Magic: The Gathering" is such a fun card game, because you CAN react onto every action of you opponent :-)

I think I get the idea of your "forwarding" additional fsm. I tried to create them to visualize your idea:



So the SoundManager listens for the different events. Now the processing of the events has a few things in common: taking the event data and storing it into the queue of our PlaySoundObject. But there are parts of the events that have to be handled separately, like the name of the soundfile that should be played. This is a general problem that I have experienced a few times now. When multiple events needs to be processed in the same way, but afterwards I need to know what event was responsible. This would require some sort of branching? So do I have to have a single state for each one of the program flows?



Of course this is not possible. Without Playmaker, I would have all my States that need the same processing of the data before call a method of a base class. In Playmaker I would have to write a custom action, and have multiple state-blocks where each of them uses my custom action in the first place?



And the PlaySoundObject would not listen to events, right? Because it basically works on its data-packages/messages?

jeanfabre

  • Administrator
  • Hero Member
  • *****
  • Posts: 15500
  • Official Playmaker Support
Re: Return behavior of "Send Event" [SOLVED PARTIALLY]
« Reply #7 on: September 17, 2013, 07:23:15 AM »
Hi,

 Ah, Ok, I see the distinction you make between stack and queue. Ok, cool. queueing is actually what I proposed in the implementation I explained, where you could choose to have a fifo or lifo: http://en.wikipedia.org/wiki/FIFO_and_LIFO_accounting

In you impossible Fsm, that's where creating one fsm per task becomes necessary. So one fsm is responsible for one event. and yet it could queue on the same array if you wanted to.

one trick that I am using from time to time is to generate events with a string using "send Event by Name", it's very useful for complex branching that you don't want to have hardcoded.

your playsoundObject would need to implement a global event, that you would fire from your sound manager as it processed the queue. It must also be responsible for firing back an event to the sound manager ( or queue manager) to tell that this event has been processed so that it can move to the next item in the queue.

I'lls see if I have time this week to come up with a queueing system to have a working example.

bye,

 Jean

FrozenTarzan

  • Playmaker Newbie
  • *
  • Posts: 9
Re: Return behavior of "Send Event" [SOLVED PARTIALLY]
« Reply #8 on: September 17, 2013, 09:24:34 AM »
Quote
I see the distinction you make between stack and queue
That's not my distinction, that's the definition ;-)
Stack behaves as Last In First Out, LIFO (for example Callstack of methods)
Queue behaves as First In First Out, FIFO (for example a printer-queue, or people waiting in a row)

Quote
I'lls see if I have time this week to come up with a queueing system to have a working example.
Would be amazing! :-)