Catching late events before changing STATE - any tricks/suggestions?
|
|
Greg Hauptmann
Registered User
Join date: 30 Oct 2005
Posts: 283
|
02-19-2006 23:08
Hi,
Any tricks/ideas regarding how to check & process any late events (i.e. events that were already on their way in) before I change state in a script. I really want a "state nextState 5", where the script will wait and process any late events (e.g. listens, link_message) for the next 5 seconds before changign state.
(or do I have to uses timers, or put in a polling check for my event generators to make sure they've cleared)
Cheers
|
|
Ben Bacon
Registered User
Join date: 14 Jul 2005
Posts: 809
|
02-20-2006 02:35
Greg - without knowing in detail what you're trying to do I'm not sure if your application is one of the very few valid exceptions, but in general you should never have to worry about this, and should be glad that late events get discarded, as this is one of the things that LSL does to save us from some of the nightmares of real-world multi-threaded programming.
As an example - if an event fires that makes me want to transition to state A, but a pending event would send me to state B, to which state should I go? Far easier just to handle the first event, go to A and be done with it.
Can you post some code that illustrates your problem? We may be able to rework it so that it does not need to be sensitive to pending events.
|
|
Strife Onizuka
Moonchild
Join date: 3 Mar 2004
Posts: 5,887
|
02-20-2006 07:05
Or maybe we could help you right the script so it doesn't need states.
_____________________
Truth is a river that is always splitting up into arms that reunite. Islanded between the arms, the inhabitants argue for a lifetime as to which is the main river. - Cyril Connolly
Without the political will to find common ground, the continual friction of tactic and counter tactic, only creates suspicion and hatred and vengeance, and perpetuates the cycle of violence. - James Nachtwey
|
|
Lex Neva
wears dorky glasses
Join date: 27 Nov 2004
Posts: 1,361
|
02-20-2006 09:29
From: Strife Onizuka Or maybe we could help you right the script so it doesn't need states. What kind of advice is that? States are a great way to make complex scripts a lot simpler and more readable. As to your question, Greg, I don't think there's an "official" way to do this, and it's possibly a good thing for the reasons Ben outlined. Perhaps if you're not already using a timer event, when you decide that you want to do a state change "soon", set up a 5 second timer. Once the timer fires, switch to the target state. In the meantime, those "straggler" events will make it through. Ben, your post reminds me of what happens when you put a state change in the state_exit() event... everything blows up, because the state_exit() event keeps triggering repeatedly 
|
|
Strife Onizuka
Moonchild
Join date: 3 Mar 2004
Posts: 5,887
|
02-20-2006 10:56
From: Lex Neva What kind of advice is that? After elminiating the impossible (being sure to catch all stragling states before a state change) all that is left is the improbable/impracticle (removing dependancy on states) must be the right solution. A compromise may give a satisfactory solution or it might not. If the goal is to handle all staglers, then clearing the event queue is not viable; this requires the removal on the dependance of states. How ever nasty or impracticle the solution is, it's the right solution. Another solution could be to use two scripts. One to handle the interface and another to handle the mechanics. Then just use linked messages between them. Then the amount of code governing the scritps status should be minimal.
_____________________
Truth is a river that is always splitting up into arms that reunite. Islanded between the arms, the inhabitants argue for a lifetime as to which is the main river. - Cyril Connolly
Without the political will to find common ground, the continual friction of tactic and counter tactic, only creates suspicion and hatred and vengeance, and perpetuates the cycle of violence. - James Nachtwey
|
|
Eloise Pasteur
Curious Individual
Join date: 14 Jul 2004
Posts: 1,952
|
02-20-2006 11:04
It might be heresy, but states aren't always the answer.
They are a tool like any other part of the scripter's armoury but they aren't essential for a lot of scripts. Of course when they are essential they're absolutely vital...
|
|
Greg Hauptmann
Registered User
Join date: 30 Oct 2005
Posts: 283
|
02-20-2006 11:38
wow - thanks for the responses guys From: Ben Bacon Can you post some code that illustrates your problem? We may be able to rework it so that it does not need to be sensitive to pending events. So basically in this case (& I think its the design I'll have to change I guess - still trying to think event-based programming) is I have multiple client objects LINKed to a controller. The client objects can be paid L$ and then they post LINK messages to the controller to say "$ recieved", on the basis that I was trying to keep the intelligence in the controller. The controller had overall control including a timeout, so my thinking was when it does time out, and then change to next state, how do I make sure there wasn't a payment which still hadn't made it threw. So thats the background. Whilst this may be a rare occurance I'm thinking I probably need to mod the design so that the controller, after the timeout period, polls all the client objects to close down payment/confirm no outstanding payments (I guess it wouldn't have to do the last bit as scripts can only process one thing at a time). More work  , but I guess this would be the right thing to do. Your thought? [other other idea was to hand more control out to the client objects so that they each count down and shut off themselves - but I find it hard to tear myself away from the centralised control concept  - guess its good I don't develop submarine systems] Tks
|
|
Argent Stonecutter
Emergency Mustelid
Join date: 20 Sep 2005
Posts: 20,263
|
02-20-2006 14:56
Sounds to me that it would be a bad idea to make the controller operate on states. If you really want to, you probably need a proxy that communicates with the controller and serialises the incoming messages, and have the controller notify it whenever it gets to the state where it can accept messages again.
|
|
Strife Onizuka
Moonchild
Join date: 3 Mar 2004
Posts: 5,887
|
02-21-2006 02:06
From: Argent Stonecutter Sounds to me that it would be a bad idea to make the controller operate on states. If you really want to, you probably need a proxy that communicates with the controller and serialises the incoming messages, and have the controller notify it whenever it gets to the state where it can accept messages again. Thats exactly what i ment in my second post, your description is more clear.
_____________________
Truth is a river that is always splitting up into arms that reunite. Islanded between the arms, the inhabitants argue for a lifetime as to which is the main river. - Cyril Connolly
Without the political will to find common ground, the continual friction of tactic and counter tactic, only creates suspicion and hatred and vengeance, and perpetuates the cycle of violence. - James Nachtwey
|
|
Greg Hauptmann
Registered User
Join date: 30 Oct 2005
Posts: 283
|
02-21-2006 02:23
Tks Strife/Argent
|
|
Lex Neva
wears dorky glasses
Join date: 27 Nov 2004
Posts: 1,361
|
02-21-2006 09:32
From: Strife Onizuka After elminiating the impossible (being sure to catch all stragling states before a state change) all that is left is the improbable/impracticle (removing dependancy on states) must be the right solution. A compromise may give a satisfactory solution or it might not. If the goal is to handle all staglers, then clearing the event queue is not viable; this requires the removal on the dependance of states. How ever nasty or impracticle the solution is, it's the right solution.
Another solution could be to use two scripts. One to handle the interface and another to handle the mechanics. Then just use linked messages between them. Then the amount of code governing the scritps status should be minimal. Sorry, I'm used to people going "STATES SUCK SO LET'S GET RID OF THEM"... that's where that reaction came from. I'd tend to wonder if this could be done in another way before I recoded this thing not to use states, though...
|
|
Lex Neva
wears dorky glasses
Join date: 27 Nov 2004
Posts: 1,361
|
02-21-2006 09:38
From: Greg Hauptmann wow - thanks for the responses guys So basically in this case (& I think its the design I'll have to change I guess - still trying to think event-based programming) is I have multiple client objects LINKed to a controller. The client objects can be paid L$ and then they post LINK messages to the controller to say "$ recieved", on the basis that I was trying to keep the intelligence in the controller. The controller had overall control including a timeout, so my thinking was when it does time out, and then change to next state, how do I make sure there wasn't a payment which still hadn't made it threw.
Ooh, ouch. Say you wait 5 seconds for more events like my solution suggested... how do you know there won't be any stragglers THEN? Where do you draw the line? One question I have: is it really necessary for there to be multiple client scripts taking the money? A money event in the root prim will let you pay any prim in the link set. The downside, though, is that EVERY prim will be payable, and you won't be able to tell which prim was paid. If either of those apply, okay, but if not, consider consolidating this into one script.
|
|
Ziggy Puff
Registered User
Join date: 15 Jul 2005
Posts: 1,143
|
02-21-2006 10:11
I see another vulnerability in your design - let's say the controller script's event queue is full, so one of the link messages gets dropped. Now a customer has paid the object, but his payment never made it to the controller. You can be sure that he's going to be pissed. This weekend I had a slot machine not return money to me... serves me right for trying to kill time with a slot machine (should have found an escort instead), but I digress...
There are other things you could do. For instance, have a 2-way handshake, i.e. make the controller send a reply back to each payment prim that it received the payment link message. This way, the payment prim can use its own timer, and refund the money if it doesn't receive an ack in a certain amount of time. But you still have the problem of lost messages - what if the controller receives the payment, sends the response, and the response gets lost? Now the customer gets refunded, and his money is still in the game. Happy customer, unhappy game owner.
I suggest you think about this very carefully. An event-driven design should not have dependencies of this kind between the events, IMO. I'm with Strife on this - re-think your state changes and control layout.
|
|
Greg Hauptmann
Registered User
Join date: 30 Oct 2005
Posts: 283
|
02-21-2006 12:05
From: Lex Neva One question I have: is it really necessary for there to be multiple client scripts taking the money? I'm using mulitple prims morso. So the reason I'm using mulitple prims is a means to allow people betting to select what they want to bet on. What they can bet on is represented as an object(prim) and they can just pay this. From: Lex Neva A money event in the root prim will let you pay any prim in the link set. Ouch - I seem to have one of these "wish I'd had of realised this" once a day with LSL/SL  . Actually that should be OK as I am linking the payment objects to the controller. I'll keep the contoller as the root prim and it doesn't have a money() event. I think this covers things Lex(?). From: Ziggy Puff I see another vulnerability in your design - let's say the controller script's event queue is full, so one of the link messages gets dropped. So what I've now done (since I last checked this thread) is to enhance my scripts per the following (please tear it down where you can  ) - Assume the payment objects are source of reference for payments
- They still send payment messages to the controller during the betting phase, however this will be only for the purpose of updating a display
- At the end of the period the Controller sends out a "finish up betting phase" to all payment objects
- Betting objects receive this and send back an acknowlegement to the Controller. I'm still debating here whether they should send a full list of bets back to the Controller at this stage or not, i.e. the controller should already have everything.
- Controller keeps tabs on the incoming responses, and waits for all to come in prior to proceeding
- This way the payment objects are source of reference for payments, and are responsible for refunding money themselves if too much is paid etc.
From: Ziggy Puff There are other things you could do. For instance, have a 2-way handshake <cut> But you still have the problem of lost messages Whilst I've solved late events, I guess "lost messages" is still a potential concern as you point out Ziggy. If I only have 8 payment objects and one controller, then at STEP 5 above the controller should only really be expecting 8 responses, so couldn't I trust LSL/SL to queue these? Otherwise I guess I'd have to put a reliable delivery/buffering mechanism in place, perhaps just have the controller at STEP 3 send out the "are you finished" event one payment object at a time , however this would then impact on performance (i.e. time to complete this phase). Tks again (great to share the LSL pain with others)
|
|
Ziggy Puff
Registered User
Join date: 15 Jul 2005
Posts: 1,143
|
02-21-2006 12:18
Here's how I would do it. In fact, this is how I did a similar script where people could place bets on different options. * Have the user click on something. This shows him a dialog box where he selects the thing he wants to bet on. * Once you know his choice, tell him the bet, and set the pay price if that's applicable (i.e. if the prices differ). * Now he can pay. Before the touch event, keep a flag that says "not started", and if anyone pays, refund and tell them they need to touch and select an option first. Once you get a touch, change the flag to say "in progress", start a timer, and remember the key/name of the person who touched it. While the flag is "in progress", if anyone else touches it, tell them to try again later. If anyone else pays, refund and tell them to try again later. Once the right person pays, stop the timer, set the flag back to "not started", clear any information about who's currently expected to pay. If the timer times out, tell the person he waited too long and you're resetting, set the flag back, clear key/name information. This gives you a few things: * You always get a touch followed by a pay. if anyone reverses the sequence, you can catch it. * You always get the payment from the right person. * It's easy to have another timer running (maybe in a different script) that can shut the whole thing down with a "stop accepting payments message" With this, the only way you'll have queued up messages is if someone manages to generate a bunch of pay events faster than you can process one of them. Even there, assuming he doesn't overrun the queue (and you're not changing states and flushing out the queue), all the following events will result in refunds. Basically, it removes one problem area - link message lag. From: someone If I only have 8 payment objects and one controller, then at STEP 5 above the controller should only really be expecting 8 responses, so couldn't I trust LSL/SL to queue these? I don't know. Probably. I'm not sure if a full queue is the only situation in which a link message could get dropped.
|
|
Greg Hauptmann
Registered User
Join date: 30 Oct 2005
Posts: 283
|
02-21-2006 12:36
Good ideas Ziggy - I've have to good think  (already heading down a different direction). I guess I was hoping to allow betting to occur from mulitple people simultaneously, however your design would keep the number of prims down. I'd still have to use link messages I guess to send back final results to the controller script, i.e. assuming that the code would have to be broken across multiple scripts for the normal size/memory issues. Pity there isn't an easy way to load test this stuff hey. (e.g. need multiple AVs doing things all at once). I guess we have the Google release to production but mark as BETA concept 
|
|
Tiger Crossing
The Prim Maker
Join date: 18 Aug 2003
Posts: 1,560
|
02-21-2006 13:00
Of the hundreds and hundreds of scripts I've written in LSL, less than a dozen have used states. I think of it like this:
Using states is like putting each task in its own room. This makes it quite clear what can and can't be done at any time. For example, if you were following a recipe, and the rolling pin is on the dining room table, the mixer is in the den, and the fridge is in the garage... Then you always know what you can do by what room you are in.
But who wants to cook like that?
In a similar vein, case statements (which we don't have in LSL) are impractical when comparing more than one variable, or one variable with another. You could use case statement in such a situation, but you'd lose all the readability it provides in a wash of over-complexity. I only use case statements when I KNOW the checks are simple ones, like acting on an enumeration, or when I have a strong need for the fall-though ability case statements provide.
I treat states in LSL much the same way. I only use them for very SIMPLE scripts that have clear-cut states. A light switch, for example. But if I link that lightswitch to a virtual home automation system, OUT will go the states.
The value of a single variable can be far clearer and easier to understand than a complex tangle of cases. (And less prone to errors due to the programmer's mistakes or the limitations of the LSL message queue.)
Just my three cents.
_____________________
~ Tiger Crossing ~ (Nonsanity)
|
|
Greg Hauptmann
Registered User
Join date: 30 Oct 2005
Posts: 283
|
02-21-2006 15:06
From: Tiger Crossing Using states is like putting each task in its own room. I'm starting to see what you mean now. One issue I note is when debugging a system with multiple scripts, and some scripts might be stuck in a state you don't want them to be in, so you then have to go restart/reset such scripts. Whilst if the system was bug free it might be ok, very annoying for debugging.
|
|
Ziggy Puff
Registered User
Join date: 15 Jul 2005
Posts: 1,143
|
02-21-2006 15:18
Like others have said, states are one of the tools available to you. Some of my scripts would have been hell to debug if I had used states. Others would have been hell to debug if I hadn't used states. It all depends on what the problem is that you're trying to solve.
Remember, a script can get 'stuck' just as easily with variables that have the wrong values. Especially a variable that controls something like 'You can't do X now because Y is still in progress'.
|
|
Ben Bacon
Registered User
Join date: 14 Jul 2005
Posts: 809
|
02-22-2006 05:00
From: Ziggy Puff Like others have said, states are one of the tools available to you. Agreed. Much of programming is like this - as you learn programming, you learn about more and more tools, and how to use them. This is invaluable knowledge, but it is just knowledge. One of the many joys of programming develops over time as you use the different tools, sometimes choosing wisely  , sometimes not  , until one day, without you having noticed it, you approach a problem and know, almost intuitively, "I can solve this using, D, J, and X tools". The art of programming is in choosing the right tools/techniques/algorithms - the rest is (almost) nothing more than a boring typing excersise  - followed by debugging, which is a whole other art! "Hi. I'm Ben - and I'm a software development addict."
|