Plugin issues (difficult to regulate which function fires first)

Posted by Elin on Tue 06 Mar 2007 12:58 AM — 11 posts, 38,250 views.

#0
Hey,

I am writing a curing script for an IRE mud, and so far, have had pretty good success by breaking each cure type into its own plugin. (focus, writhing, potion, herb, etc.)

I keep each affliction in lists (arrays) within the separate plugin, which means that although I declare them as global variables, MUSH only lets me reference them from within the same plugin.

This is fine for most afflictions, but there are some that can be cured by two ways (stupidity can be cured with a focus, and also with an herb).

I run my cures off of my prompt by using the following:

world.execute("try_next_pcure")
world.execute("try_next_fcure")
world.execute("try_next_potioncure")
world.execute("try_next_herbcure")
world.execute("try_next_salvecure")

Which calls functions from each plugin to attempt the next cure.

However, if I get afflicted with stupidity, it flags the stupidity affliction in both plugins. When the prompt runs, it attempts to cure stupidity in both ways, essentially at the same time.

What I'm wondering is if there is some way for me to make sure that the cure from one curetype is processed before moving on to the next one?

For example, it should:
-try the focus cure, which will result in the unaffliction line for stupidity
-since the unaffliction line unflags the stupidity flag in both plugins
-the herb curing attempt won't fire, since the affliciton is no longer present
#1
Just to share, I was able to get this to work by creating a MUSHclient variable in my prompt parsing plugin called "lastcure".

Whenever one of my plugins attempted to cure one of these "double cures", it would use a function that looked like this:

world.execute("lastcure stupidity")

...to set the MUSHclient variable equal to "stupidity". Then all of the alternate curing methods check to see if the lastcure variable is equal to the same thing it is trying to cure.

If they are equal, then the plugin recognizes that some other function has tried to cure it on that particular prompt.

I have my prompt reset "lastcure" every time a prompt is caught.

This works, but if there's a better way to do it, please tell me.

Also: anyone have ideas on how I can set priorities? So that if I'd rather cure stupidity by focus instead of by herbs, or vice versa, I can manage the flow somewhat intelligently?
Amended on Tue 06 Mar 2007 02:37 AM by Elin
Netherlands #2
It's hard to answer that given the fact we don't know your code at all. I can easily see that your code will be hard to maintain though.

What IRE mud is this for if I may ask? I've written a curing one myself for one of them, so I may be able to help out in detail.
#3
Would be for Lusternia. And as to the difficulty of the maintenance - that's definitely a possibility.
Australia Forum Administrator #4
This general topic has been covered at some length recently:

http://www.gammon.com.au/forum/?id=7683


I suggest there, as I do here, that if you have some closely-related functionality (curing stupidity in your case), it should probably be in a single plugin, so the execution order is not important.

An alternative, as you seem to have done, is make a "notify plugin" command that other plugins pick up. However this does not guarantee execution order.
Netherlands #5
Ah, I can't really help you in on any details then. I wrote a pretty extensive curing system for Aetolia, but Aetolia isn't all that comparable to Lusternia.

Oh well. If you have any specific questions, let me know. :)
#6
Thank you Nick, and Worstje for your comments. I read through the other thread that was linked here, and it looks like I'm having the same problem as the author of that thread.

Like I said earlier, I'm breaking my curing into little plugin files for each separate balance. These plugins track when I have afflictions, when I cure afflictions, and when I have the appropriate balance, and when I do not. I know it's frowned upon to have plugins rely on each other, but there are so many afflictions to track that I'd rather not have to deal with flagging/unflagging and curing each one (not to mention safety lines, or diagnose lines) that show up in one giant plugin.

It would be a nightmare to sift through thousands of lines of code any time I wanted to make an update. The way I have it currently set up, any time I need to mess around with a specific affliction, or add a new one, I only need to make changes to the specific plugin that handles it.

What exactly is the problem with having plugins depend on each other, as long as I have one main plugin that loads all the others?
Netherlands #7
My curing system is all one plugin. The different functionalities (writhing, salves, herbs, other curing methods, illusions, defenses, diagnosing etc) are all loose include files. This way I can use the same variables all over the place. General.xml holds all of the definition pretty much like a header file would. The other stuff merely sets the variables declared there.

This has a distinct advantage: if something is cured by one of the functionalities, all know about it. The only thing that is 'kludgy' and that I don't think I'll be able to remove is some kind of 'integrator' that hooks the different logics together. I have solved this with a seperate Logic.xml file which holds all the functions that aren't specific to the task that module is doing. You'd be surprised: there are only ~5 functions in that file!

They get called rather often, but it's only 5 functions I have to keep up to date for my curing to behave sensibly. (In case you're interested, the functions I have in there are DoCuring(), TreeFavorable(), FocusFavorable() etc. Names should speak for their content I think.)

#8
Can you be more specific about what you mean by loose include files?

More importantly, can I see what your prompt parsing looks like? How do you send cure commands using your prompt curing?

Mine invokes all the different cures at once (focuscure, herbcure, salvecure, potioncure), and these call functions in separate plugins called try_next_herbcure, try_next_focuscure, and so on.

These either do nothing (if no afflictions, or if there's something preventing them from curing - like if I have another affliction that blocks eating), or sends the next cure.

Since immediately after I get afflicted with stupidity, it's running try_next_focuscure and try_next_herbcure almost simultaneously, at the last prompt, both plugins see stupidity, and both attempt to cure it.

Even if these functions were in the same plugin, I'd still have to write code that would see if a particular affliction is already being cured by another method.

I'm thinking about storing the last cures of each type "last_herbcure", "last_focuscure" in each category, and every time one of the plugins is about to send a cure, it will check to see if any of the other plugins are attempting to cure it.

If so, then I'll have it move on to the next affliction.

I guess I just don't see the benefit to having one big plugin, as opposed to little ones that I can update separately, and it looks like regardless, I'm going to have a similar problem with program flow, so..
Australia Forum Administrator #9
Quote:

Even if these functions were in the same plugin, I'd still have to write code that would see if a particular affliction is already being cured by another method.


Exactly. In which case the order of plugin evaluation is not the problem.

You need to maintain some sort of list of outstanding afflictions, and ones that you are in the process of curing. This would preferably be in the one spot - perhaps its own plugin for modularity, in which case you could communicate with that plugin by using CallPlugin (or BroadcastPlugin).

One technique would be for the detection plugins to do either of those calls to update a list held in the "master plugin" so that it adds a new affliction to its master list. Since you can *read* variables from other plugins that list could be queried easily.

Then you could use a similar technique to update a list of "treatments in progress" (eg. stupidity). Again that could be queried, so that you don't treat it twice.

The four major actions I can see you would want to implement are:

  • Add affliction to list
  • Remove affliction from list (after successful cure, or affliction times out)
  • Add pending treatment to list
  • Remove pending treatment from list (eg. after success or failure of treatment).

Amended on Wed 07 Mar 2007 05:11 AM by Nick Gammon
#10
Hey,

I just wanted to say that I was able to get this problem fixed by having each plugin store a variable called "lastcure". For each cure that could have been cured by some alternate method, I check it against the lastcure variables of all the other plugins. If there's no match, I go ahead and send the cure command. Otherwise, I cure the next affliction.