Playmaker Forum

PlayMaker Help & Tips => PlayMaker Help => Topic started by: Broken Stylus on December 12, 2018, 12:27:56 PM

Title: Blocking/ignoring events, rendering a FSM deaf[SOLVED]
Post by: Broken Stylus on December 12, 2018, 12:27:56 PM
Events are brutal.
They short-circuit everything and it's really a pain in the **** to manage them when one wants to prevent a FSM from being attentive to new events or receiving the same event twice.

I haven't found an option that renders the FSM deaf to all or certain events.
This means I need to circumvent that by creating a monitoring central FSM that dispatches orders (like activate FSM) or events (forwarding) to other FSMs based on the events received, using alongside bools to check if event #n was already received or not.
This creates an unnecessary extra step, preventing the other FSMs from directly receiving the events.
It also creates a potential bottleneck if there are many FSMs are tons of events sent at once.

I just wish there were actions (in StateMachine) that would allow me to have a FSM ignore all or specific events until I lift the ban or the game object or until the FSM is reset or disabled and reactivated later on.

PS: what's the "eat event" option in Forward FSM btw?
Title: Re: Blocking/ignoring events, rendering a FSM deaf
Post by: djaydino on December 12, 2018, 07:38:29 PM
Hi,
Can you show some fsm with your setup?

Maybe you can set some of the transitions to local so that they can't get triggered twice?
Title: Re: Blocking/ignoring events, rendering a FSM deaf
Post by: Thore on December 13, 2018, 06:12:49 AM
Events are brutal.
They short-circuit everything and it's really a pain in the **** to manage them when one wants to prevent a FSM from being attentive to new events or receiving the same event twice.

For that problem use a simple design pattern: when the event is received, place a bool check that asks “did we do this already” with a bool, and if true, go out to a different state (a dead end, for example). Underneath that very action, put the routine you want done, and after the crucial bits, place a set bool that turns the “did we do this already” variable to true. Next time, it runs through, the bool check on top sees it was done already, and goes off a different track. Don’t forget to set the variable to false later on again, when you want to permit retriggering the event again.

If that still isn’t good enough, you can broadcast the event, trigger the receiver and at once tell all senders to cease sending that event. I’d go with the above method, though and rethink the design.
Title: Re: Blocking/ignoring events, rendering a FSM deaf
Post by: Broken Stylus on December 13, 2018, 06:13:43 AM
Hi,
Can you show some fsm with your setup?

Maybe you can set some of the transitions to local so that they can't get triggered twice?

What do you mean?

Also, the problem exists because I have a major FSM regulating reward, victory and defeat conditions that are sending global events on broadcast to a large quantity of objects with different purposes.

It is logical to have the objects manage how they react to these global events by deciding locally if they'll "listen" or even "react" to a received event.

Thus far I haven't found any other solution than using a monitoring FSM that acts as a gatekeeper on each game object that could be receiving the global events multiple times but actually must not do anything beyond the first reception.

That's related to the way Playmaker's FSM handle events, more precisely global transitions, whether the event itself is global (sent by another FSM) or sent internally within a FSM: regardless of what a FSM was doing, the flow is rerouted to the state where the event is meant to be received.
I haven't found a way to control that, to switch the "listeners" off, whether to be totally deaf or to only ignore events that belong to a list—typically the action would allow the user to add any given amount of FsmStrings, each string being the name of the event to ignore.

My effective solution consists of having a FSM-0, acting as a filter, that receives events and uses bools to decide whether to activate FSM-1, FSM-2, etc.. Those other FSMs actually hold the real functions fir the object(s).

The activated (monitored) FSMs are either meant to be active once or remain active as long as the game object is active.

This works, but it would be straighter and faster to initialize FSMs by putting them in a given mode where I decided how they'll react to events. This initialization would simply be done through a primary state with START and actions that define the kind of behavior to follow for incoming events, whether external or internal.
Title: Re: Blocking/ignoring events, rendering a FSM deaf
Post by: Broken Stylus on December 13, 2018, 06:20:26 AM
Events are brutal.
They short-circuit everything and it's really a pain in the **** to manage them when one wants to prevent a FSM from being attentive to new events or receiving the same event twice.

For that problem use a simple design pattern: when the event is received, place a bool check that asks “did we do this already” with a bool, and if true, go out to a different state (a dead end, for example). Underneath that very action, put the routine you want done, and after the crucial bits, place a set bool that turns the “did we do this already” variable to true. Next time, it runs through, the top bool check sees it was done already, abd goes off a different track.

If that still isn’t good enough, you can to broadcast the event and, trigger the receiver and at once tell all senders to cease sending that event. I’d go with the above method.

The monitoring FSM does indeed uses bools, but it requires to be its own FSM that acts as a gatekeeper and filters events ahead of other FSMs that wait to be activated.

Otherwise, that wouldn't solve the problem because the events literally force the current FSM's flow to return to the state that is receiving events.

And even if I used "get last state" in the receiving state to know what state the flow was in just before the arrival of an event, returning to the former state with a goto action would retrigger this state instead of resuming operations as they were just before the event-hijack.

Essentially, I don't want to mute event senders. I want to deafen/blind receiving FSMs as I see fit.
Title: Re: Blocking/ignoring events, rendering a FSM deaf
Post by: Thore on December 13, 2018, 08:18:56 AM
You can make an FSM not receive further events by either putting a buffer FSM in front (on the same target object) that does what I wrote above, which triggers the destination FSM exactly once. Or maybe you can dynamically change the target FSM’s name or by whatever it is called.
Title: Re: Blocking/ignoring events, rendering a FSM deaf
Post by: djaydino on December 13, 2018, 09:58:04 AM
Hi.
Quote
This works, but it would be straighter and faster to initialize FSMs by putting them in a given mode where I decided how they'll react to events. This initialization would simply be done through a primary state with START and actions that define the kind of behavior to follow for incoming events, whether external or internal.

I don't think that will be possible to achieve.
As these event in c# would be static and you can not just set them to non static.
Title: Re: Blocking/ignoring events, rendering a FSM deaf
Post by: Broken Stylus on December 16, 2018, 06:28:00 AM
You can make an FSM not receive further events by either putting a buffer FSM in front (on the same target object) that does what I wrote above, which triggers the destination FSM exactly once. Or maybe you can dynamically change the target FSM’s name or by whatever it is called.

That's the method I already use too, but adding a supplementary FSM and more localized events for monitored FSMs just adds unnecessary weight and obfuscation to a project imho, and I even wonder if there wouldn't be a risk of losing a frame here and there down the road since all events are queued, so adding more of them may not be good.
One is pretty much stuck having to micromanage the events on the sending side of things or by introducing a mediating FSM between the sender and the potential receivers on each game object.
Shucks, never mind... :(
Title: Re: Blocking/ignoring events, rendering a FSM deaf
Post by: Fat Pug Studio on December 16, 2018, 09:03:28 AM
Yeah, if you're having something so complex you'll have to using additional FSMs for event rerouting. Even in code, i doubt you ciuld make it simpler.
Title: Re: Blocking/ignoring events, rendering a FSM deaf
Post by: jeanfabre on December 17, 2018, 01:31:01 AM
Hi,

 Events are not brutal :) they are extremly powerful, that's all :)

when I want to filter the reception a global event, I use two technics:

-- I have a dedicated FSM catching that event always, and the check if it needs to be processed or not, this is by far the best solution, your actual logic fsm implement your own global event that you fire yourself, so for ON TRIGGER ENTER, you would have ON MY TRIGGER ENTER or something.

-- the second option is to not have the global event as a global transition, but as a regular transition, which means it won't be processed if the active state is not the one implementation that transition. It's powerful as well.


So you can indeed do these kind of filtering, I do that all the time.

Your problem I think is that you don't implement the necessary level of indirection to allow your fsm to be flexible enough on that regards.

If you have a concrete example, I can make a sample to show you how to achieve that.

Bye,

 Jean
Title: Re: Blocking/ignoring events, rendering a FSM deaf
Post by: Broken Stylus on December 17, 2018, 09:25:57 AM
Yeah, if you're having something so complex you'll have to using additional FSMs for event rerouting. Even in code, i doubt you ciuld make it simpler.

My project structure and logic are quite straightforward and simple, trust me, and I've already been using intermediary FSMs to filter global/parent->children events since ages, but I wanted to check out if I missed a simpler and much quicker option.
The point is about being able to turn off or fine tune the event-receiving abilities of a FSM; something that seemed to be logical and intuitive, without having to add another FSM and more (local) events or to activate FSMs.
Essentially the idea would be to put the subscription on halt either wholly or with minute detail, and also resume it if needed too.
Now, it's been more or less largely confirmed this wouldn't be possible. So be it really.  :(
Title: Re: Blocking/ignoring events, rendering a FSM deaf
Post by: jeanfabre on December 18, 2018, 03:32:15 AM
Hi,

 yes, broadcasting a global event will reach any fsm actively listening to that global event.

 If you are part of the beta, maybe you could sugges this feature, I think it would create more issues than solve, but I do admit that it would make sense in some cases, during debugging.

for such feature to become available, events would need to get an overhaul rewrite, as a lot more would then be likely good to have next to that option, so you could opt in ad out of event visual as well, and a good editor overview so that when things go south, you are not left wondering where is the bug, when it is actually that you turned off listening to that event.

 so I would definitly picking one of the two or both solutions I explains earlier, they work well and are exploitable and efficient.

 I could do a little sample to demonstrate this if you want.

Bye,

 Jean
Title: Re: Blocking/ignoring events, rendering a FSM deaf
Post by: jeanfabre on December 20, 2018, 07:22:58 AM
Hi,

 as I am wrapping up the KenPlane demo, I remembered about this post:

check out how I listen or not to Inputs, very simple, AND decoupled from Unity and system callbacks, these events are designed for this very game, and so now I have all the power to disable inputs with more events ( like pause menu, ads, etc)


(https://i.imgur.com/RNuzLyf.png)

I slightly modified the fsm for the sake of example. I have added a transition using a global event, this means that ONLY when "watch keys" is the active state that this fsm will listen to the global event KENPLANES / PROJECTILE / ON HIT


(https://i.imgur.com/Ad0VYde.png)

Bye,

 Jean
Title: Re: Blocking/ignoring events, rendering a FSM deaf
Post by: Broken Stylus on December 20, 2018, 02:42:26 PM
Hi,

 yes, broadcasting a global event will reach any fsm actively listening to that global event.

 If you are part of the beta, maybe you could sugges this feature, I think it would create more issues than solve, but I do admit that it would make sense in some cases, during debugging.

for such feature to become available, events would need to get an overhaul rewrite, as a lot more would then be likely good to have next to that option, so you could opt in ad out of event visual as well, and a good editor overview so that when things go south, you are not left wondering where is the bug, when it is actually that you turned off listening to that event.

 so I would definitly picking one of the two or both solutions I explains earlier, they work well and are exploitable and efficient.

 I could do a little sample to demonstrate this if you want.

Bye,

 Jean

If you add this feature for dev/debug and the plebe gets addicted to it, they'll wander why it's not available for builds and heads be rollin'.  ;D

PS : the KENPLANE example is interesting, would logically work, I didn't know it would work that way. I must say that from a UI/UX pov, it's not exactly intuitive. There's nothing indicating at first sight that this particular state is also receiving global events that way. It almost looks like a dirty hack.
...
Do you like dirty hacks?
Title: Re: Blocking/ignoring events, rendering a FSM deaf
Post by: jeanfabre on December 21, 2018, 01:42:01 AM
Hi,

 Visually it works like this:

- any global transition ( black transition sitting on top of a state), will be caught regardless of the current active state in that fsm.

- any transition (grey transition sitting below the state), will ONLY be caught if the state is active.


so it's not a hack nor dirty, it's by design and in purpose, and I strongly encourage this kind of pattern.

Bye,

 Jean

Title: Re: Blocking/ignoring events, rendering a FSM deaf
Post by: Broken Stylus on December 23, 2018, 01:15:01 PM
Hi,

 Visually it works like this:

- any global transition ( black transition sitting on top of a state), will be caught regardless of the current active state in that fsm.

- any transition (grey transition sitting below the state), will ONLY be caught if the state is active.


so it's not a hack nor dirty, it's by design and in purpose, and I strongly encourage this kind of pattern.

I understand that but I find it not visually obvious, since as in your example, one needs to actually open the state and check what it does in detail in order to know if the exit transitions are sent by actions in that state or if they're hidden global transitions.
There's simply to know just by looking at the state itself.
There should be no disruption of the visual clues and rules used for transitions. For example, such a transition could appear in almost pure black too (well actually very dark grey); which is not possible by using the color palette as transitions are of a lighter hue than the state's color so even a pure black will appear grey.

On the plus side, aside from what you revealed, this transition listening to outer events conveniently avoids having to do the usual "Get Last Event" + "String Compare" combo.
Let's just add, btw, that these two actions could really come under one new fused action.
Title: Re: Blocking/ignoring events, rendering a FSM deaf[SOLVED]
Post by: Thore on December 23, 2018, 02:55:33 PM
Perhaps, global events should be visually distinct in some way, since Playmaker strives to be a visual scripting solution, but nobody’s stopping you from following the convention used by Playmaker, namely writing global events in ALLCAPS—then you see at glance what is global and local. The other rule is perfectly clear, events underneath are only triggerable during that state, and the events coming in from the top (global or start) always listen.
Title: Re: Blocking/ignoring events, rendering a FSM deaf[SOLVED]
Post by: Broken Stylus on March 01, 2019, 04:41:08 PM
Perhaps, global events should be visually distinct in some way, since Playmaker strives to be a visual scripting solution

Absolutely! I think the whole UI could need a little refreshing plus an improved UX but that will wait until I find time to post a proper thread. I've got plenty of ideas I'd love to share.

Quote
but nobody’s stopping you from following the convention used by Playmaker, namely writing global events in ALLCAPS—then you see at glance what is global and local.

I'd greatly advise against this solution because of these two reasons:
1. PlayMaker has a mind of its own and decides to turn certain events global without asking and once it has decided that an event is global, to deglobalize it is a very troublesome endeavor.
2. I personally found it better to use small caps for all custom events to precisely make them distinct from all the default/system events. Swinging back to all caps for global events would prevent from knowing from a quick glance if the event in question is custom or not.

Quote
The other rule is perfectly clear, events underneath are only triggerable during that state, and the events coming in from the top (global or start) always listen.

That, yes, it is clear. What is not in the current shape of the tool though is to know if the transitive event is waiting for a global event or will be launched by an action inside the state.
Title: Re: Blocking/ignoring events, rendering a FSM deaf[SOLVED]
Post by: Thore on March 01, 2019, 07:13:51 PM
1. if events are global which you didn’t switch to global, it’s either a bug, you accidentally switched them on, or you created events that already exist as global events. I can’t confirm this “mind on its own”.

2. If you do not distinguish global from local events in some way, you might have an answer why the problem in (1) occurs. You can use any rule you like (camelCase, _globalevent etc), but all caps is simply consistent. I never needed to distinguish between default system events and custom global events. The system ones that are relevant to me are easy to remember too (ON...etc COLLISION TRIGGER). Also, there is no need to switch them around. I design with a global event in mind, and then use all caps. If I use another approch, I create a local event in lowercase.

3. It’s a rather specific case to use local events that are not used by any action of a state. But I agree such events could be made distinct somehow, though so far, I never needed that case, and not even sure what currently happens.
Title: Re: Blocking/ignoring events, rendering a FSM deaf[SOLVED]
Post by: Broken Stylus on March 08, 2019, 09:25:22 AM
1. if events are global which you didn’t switch to global, it’s either a bug, you accidentally switched them on, or you created events that already exist as global events. I can’t confirm this “mind on its own”.

I can already think of out two issues that I had to deal with on several occasions. There's one when sometimes an entire FSM's events are all switched to global. I haven't been able to pin point the origin of this issue. Fortunately it's rare enough not to piss me off too much when I go returning the events to a local state in the FSM, but then it ties into the second issue.
The other is that of an event that is global yet unused, remains stuck in global despite trying to unglobalize it. And this is being aggravated by the fact that some clearly global events are not even reported as used simply because they're only mentioned in actions (like send ---) instead of used as Enter or Exit transitions.
That's another topic about the management of the Events window though.

Quote
2. If you do not distinguish global from local events in some way, you might have an answer why the problem in (1) occurs.

That's now something I'll have to handle manually since the discovery that global events can be used as "conditional" exit points just by being added as exit transitions to a state.
See, since PlayMaker is a visual tool, one quickly considers that entry events are those on top of a state and the ones below are exit events. It doesn't automatically make sense to think that global events could also "enter from below" as some kind of shortcut.

There's an indirect clue to that capacity in the Manual Guide: https://hutonggames.fogbugz.com/default.asp?W133

Transition Event

By explaining what System Events can do, (2) hints at (but does not confirm that) some custom events could also leave a state whilst being triggered by something else than any action inside the state.
Now, (3) doesn't mention this. It says actions can trigger those events and logically you'd think that by default, it means actions inside the state.
But it should be noted that IF these events are global, they can actually be triggered by actions from external FSMs.

I still consider that users shouldn't have to go through this custom nomenclature though, as it's absolutely clear that PlayMaker already evidences a clear distinction in its current UI between Global Transitions and (local) Transitions, doubling with a global tag for events.
I wish they had gone with something differently for the transitions coming from the top considering they can be local too; something like Entry/Incoming transition instead of the misleading Global transition title, or perhaps Main Transitions considering the power they have to steal the flow of a FSM (which was the initial point of my OP because I wanted to control that flow).

Quote
You can use any rule you like (camelCase, _globalevent etc), but all caps is simply consistent. I never needed to distinguish between default system events and custom global events. The system ones that are relevant to me are easy to remember too (ON...etc COLLISION TRIGGER). Also, there is no need to switch them around. I design with a global event in mind, and then use all caps. If I use another approch, I create a local event in lowercase.

Yes, nice. I use a similar nomenclature for global vars. For events when I started PM, I was using all caps but then I preferred to leave that for default events.  :-[
This being said, I see many devs not bothering with a global-centric event-naming convention despite how helpful it may be.

Quote
3. It’s a rather specific case to use local events that are not used by any action of a state. But I agree such events could be made distinct somehow, though so far, I never needed that case, and not even sure what currently happens.

I think that a different hue or something like dashed lines or else, for global events, would be interesting to test out.
Also could be extended to global vars, to make them stick out better without having to come up with a homemade nomenclature.
Let's remember that it's a visual scripting tool, the user is sort of supposed to be taken by the hand when it comes to visual elements and hints.

Local events used as exit transitions cannot be triggered by actions outside of the state. But this isn't true for global events. So a clue would be helpful. I talked of hues or dashed lines but maybe they could go with a kind of small and stylized arrow on the left of the transition block, pointing to the right, to indicate that it's a global event?
Even System Events (ON STUFF, MOUSE, TRIGGER, etc.) that can trigger an exit node should also be indicated as potential shortcuts, just to be coherent.
The idea boiling down to indicating when exit transitions are susceptible to be triggered from outside the state and therefore act as "entry ports" too.
Title: Re: Blocking/ignoring events, rendering a FSM deaf[SOLVED]
Post by: jeanfabre on March 18, 2019, 02:42:55 AM
Hi,

- a global event remains global even if you uncheck it inside an FSM, you must uncheck it in the fsm event browser for it to affect your project.

- global events and events are one thing, transitions are something else. So it's indeed very important to understand that the global transition above a state can accept any event ( local or global), and the same holds true for local transitions. I wish there was a better way to word these concepts like you proposed... tricky. The issue with wording is that it rarely is sufficient to depict a behaviour, and it;'s only after actual experimentation that the concepts are understood.

Bye,

 Jean