Blau
Dec 3 2003, 06:20 PM
Most scripts are built around some simple state machine. Is anyone using a class for managing state? Do you have a good methodology that you're proud of? I'm becoming increasingly dissatisfied with my state management and want to inject something better into my code.
I've been reading some good stuff about state management and I'm thinking about creating a "State Machine" class that would handle things much better than the way I do it now. Today I change state when events happen (detected by callback routines) or when an action completes/fails and then I have to pop off the stack (return) when I detect a state change that I didn't instigate. Then I have a bunch of checks in my callback routines that sorta prevent me from changing state when I don't want to. For example, when I'm doing something that's really important I will ignore certain events that might otherwise change the state on me. Something like this:
| CODE |
OnObjectCreate(args) { if (gState == eSomethingImportant || gState == eSomethingElseImportant) { // Ignoring objects because I'm doing something more important return; }
DoSomething(); } |
This wasn't a problem before, but as my code grows managing this is a major hassle. Anyway... I'm looking for something better and I'm fishing for ideas.
Maud-Dib
Dec 3 2003, 06:11 PM
Warbot's state changer isn't any better. The only thing I do is define a function called ChangeState() which accepts one parameter: the desired state. In that function I make sure the desired state is a higher priority than the current state before I switch it.
I don't save any states on a stack either since the lower priority states (looting, buffing, salvaging etc) are executed as a result of conditions (corpses on corpselist, buffs expired, items on salvage list) that will still be there when the higher priority state is finished.
Maud-Dib
Blau
Dec 3 2003, 09:13 PM
Well at least you defined state priorities. I was planning on adding this in this new class.
I guess I was unclear: I'm not popping states. I'm popping out of helper functions that were called within a single state. I might be 4 functions deep into the stack when the state changes and I have to return from all 4 before the main state code is hit and the state will actually change. This means that if I'm doing any WaitEvent stuff within the helper functions, I need to check the state after each one otherwise I might continue to try to open a stubborn door when I really need to respond to some higher priority state.
So anyway, one thing I want this state class to do is manage a flow chart that designates what states can be changed from and to. For example, it's acceptable to go from state A to state B, but not from state A to state C. That way I only have to configure it one time and don't have to have these big, long "if" statements where I'm checking to make sure I'm not in one of a dozen states before I'll proceed.
Still looking for ideas. I wrote a VT-100 emulator for the Macintosh once using "real" state machine (flex and yacc were the tools I used) so I'm not a *complete* idiot about this stuff, but my training is less formal than many here I'm sure.
Reficul
Dec 4 2003, 02:15 AM
I am very happy with how the statemachine in my macro worked out, haven't run into any big problems with it so far. Check it out and talk to me ig, if I recall correctly I think we are in the same monarchy.
Morkai
Dec 4 2003, 04:03 AM
just a crazy suggestion...
would it help you to use priorities in conjunction with an alert level? sort of like DefCon? for example:
8. out of 3d
7. in portal space
6. H/S/M level critical in some way
5. critical buff missing or under critical time
4. under attack or monsters inside danger radius
3. non critical buff missing or under critical time
2. monsters outside danger range but inside maximum range
1. no danger
you would then assign a priority level to each state matching the alert levels, for example:
8. character login
6. self transfer, heals and drains only
5. buff state high priority
4. kill state
3. buff state low priority
2. looting and inventory managment
if you set the alert level as you react to events all it takes is a quick check of the current state's priority vs the alert level to see if you need to abort whenever you come out of a waitevent loop
keep all your big nested if statements in one place to decide what the best action for the moment is, then just call that state whenever you exit any other state. putting the conditions in descending order of state priority will make sure you won't get bogged down in time critical situations, and it doesn't matter if you have to spend an extra 10 lines or so every time figuring out that the only action you need to take is usting some salvage.
am i wrong?
kgober
Dec 4 2003, 03:28 PM
you don't have to run the whole script on one state machine. you can have one 'strategy' state machine that defines the overall task to be performed, and within each of those states you can run a micro-state-machine that handles the details of that task. this way, you can easily bail out in exceptional conditions by defining 'abort' states in each micro-machine. these 'abort' states, when triggered, would cause the micro-machine to terminate, perhaps returning an exit code to the strategy state-machine, or setting global variables so that the strategy-machine can figure out what to do next.
the SpikeBot script in UserWare is set up somewhat like this. there are 5 or 6 'strategy' states that define high-level tasks (buy, sell, make, decide what to do next, etc.). within each strategy state, there is both a 'major' state and a 'minor' state that tracks low-level details. the major state tells my event handler which events I'm interested in (it tells the event handler which events to watch for, and what to do if it sees them). the minor state records which of those events have already happened, and which ones I'm still waiting for (because many of my tasks wait for combinations of events to occur before moving to the next step).
-ken
Maud-Dib
Dec 4 2003, 05:13 PM
Blau, Warbot uses what Ken described. Any state that requires lengthy processing uses substates or another method to pick up where it left off. The end result is that the main state machine loop executes constantly, with at most one action or spell cast between loop iterations.
For example my looting state has the following substates:
FindCorpse
OpenCorpse
WaitOpen
AssessItems
Pickup
Done
Between each substate the main FSM loop executes so changes to the main state are processed quickly.
Maud-Dib
Blau
Dec 4 2003, 08:26 PM
I'll have to check that out. Is it available for download? I didn't see a link in the support thread.
Chazcon
Jun 15 2006, 02:36 PM
tag to add to my informal education
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please
click here.