[Home] [Downloads] [Search] [Help/forum]


Register forum user name Search FAQ

Gammon Forum

[Folder]  Entire forum
-> [Folder]  MUSHclient
. -> [Folder]  Suggestions
. . -> [Subject]  Multiple identical aliases wreak havoc with one another

Multiple identical aliases wreak havoc with one another

It is now over 60 days since the last post. This thread is closed.     [Refresh] Refresh page


Posted by Worstje   Netherlands  (899 posts)  [Biography] bio
Date Thu 03 Aug 2006 03:16 PM (UTC)
Message
I ran into a problem which I have not been able to find a solution for. This concerns the use of multiple aliases responding to the same action. I'll first describe my problem, and then the way I feel it ought to be fixed.

I have two plugins which need to work independantly from eachother. Both need to handle the 'sit' command. The first plugin, ProneHandler, will (globally) do this:

def DoSit(name, line, wildcs):
global VoluntaryProne
# Make sure we don't 'stand' again while roleplaying.
VoluntaryProne = True
world.Send("sit")


Another plugin, does the following (ok, this one is made up at the spot due to the actual code taking far more variables in account, which for this example would only distract):

def DoSit(name, line, wildcs):
if (not "needles" in Room):
world.Send("sit")

Now, the problem manifests itself when BOTH aliases are in effect. If only one is enabled, all works as it should.

Suppose, all is okay. Life is splendid and no dangers in sight. I 'sit'.

sit
sit

Oops, I'm sitting twice. Besides getting a tadbit spammy, I can live with that.

Now suppose, there are needles in the room, but I, the silly one, never noticed. I decide to 'sit'. What will the plugins, 'correctly', do?

sit

Oops, I just impaled myself. The poison on the needles will surely kill me. Atleast I'm not standing up again, like I should. Yay?

I've been searching for a way to solve this problem, and I think there is no reasonable way to solve it without having to write 'compatibility' code with other plugins. (Some may want to suggest 'oh, but use world.Execute(), or maybe keep_evaluating'. Been there, done that, got looped horribly bad. keep_evaluating does not solve this problem either, as plugins would need their sequence set to values higher/lower than other aliases.) This is unacceptable, as you want other people to be able to script their things and not get it messed up.

My solution is as follows. Add a pass_through="y" to be able to be added to aliases. This would allow for them, if ALL aliases have it set, the command to transparently pass-through. If only a single alias has pass_through="n", then don't let it through. If someone decides not to let something pass through, then that plugin can be decided to be an incompatible factor.

Of course, this still leaves the problem with the 'if'. Suppose I have yet another alias for 'sit', made by the user itself. He too, wants to check by using 'if', and only let the command through conditionally. World.Send("sit")... oops, same problem again.

So, an addendum would be to add the following (since I don't think return values work):

world.AllowAliasPassThrough(boolean PassesThrough)

This would -not- change the definition of the alias, but merely affect the way MUSH interprets this triggering of the alias. The needles-code would become as simple as this (with pass_through="y"):

def DoSit(name, line, wildcs):
if ("needles" in Room):
world.AllowAliasPassThrough(False)

One last thing...

If I missed something obvious in the help file or on the forums that deals with this situation, tell me? :)
[Go to top] top

Posted by Ked   Russia  (524 posts)  [Biography] bio
Date Reply #1 on Thu 03 Aug 2006 09:02 PM (UTC)
Message
I don't think a pass_through option would work either, since it would depend on the execution order of aliases. In your example, all would work as expected if the "needles" alias is executed before the "voluntary" one, but if they are executed in reverse order then you'll still end up sitting on the needles.

The correct solution would seem to be in using global flags, which can be checked in any plugin. Mushclient variables don't work for this, due to the fact that plugin vars are a pain to set and get and the global world ones can't be set without resorting to world.Execute. So instead of Mushclient vars I use MXP entities, which can be set and checked from anywhere without any problems.

The callbacks for those are:

void world.SetEntity(String name, String value)
String world.GetEntity(String name)


With entities as flags your code would become:


def DoSit(name,line,wildcs):
    needles = int(world.GetEntity("sit-needles"))
    if needles == 0:
        world.Send("sit")
[Go to top] top

Posted by Worstje   Netherlands  (899 posts)  [Biography] bio
Date Reply #2 on Thu 03 Aug 2006 10:01 PM (UTC)
Message
Eh, it would work.

The first one would simply have pass_through="y" on, and not call world.Send("sit"). And because ALL aliases need pass_through="y", which the second one would end up not having, it would end up in the command not being executed.

And your way of solving it still conflicts my main problem: plugins need to be designed having other plugins using this particular system, in mind. If I have to go and rewrite other peoples plugins to be able to work along with mine, I could just as well rewrite most of them.

My point is: MUSH supports multiple aliases triggering on the same command, so why not let them be able to work better together?
[Go to top] top

Posted by Nick Gammon   Australia  (22,973 posts)  [Biography] bio   Forum Administrator
Date Reply #3 on Thu 03 Aug 2006 10:26 PM (UTC)
Message
MXP entities eh? An original idea. :)

While you were writing that I was testing a solution to the original problem.

I don't think the pass-through flag will totally solve your problem anyway. Consider a couple of cases:


  1. An alias that does a sit amongst other things (which you mentioned). Like this:

    
    Alias match: drink
    Send: sit
          drink
          stand
    


    Now passing through the alias (drink) does not help the sit alias to match on it, because it is a different word.

  2. A trigger that does a sit. For example:

    
    Trigger match: You are thirsty
    Send: sit
          drink
          stand
    


    No amount of fiddling around with alias pass-through is going to affect trigger behaviour.


What has worked for me is to use the plugin callback OnPluginSend, like this:


function OnPluginSend (s)

  if string.lower (s) == "sit" then
    if GetVariable ("can_sit") ~= "1" then
      Note "sit disabled in plugin 1"
      return false
    end -- if
  end -- if doing sit

return true

end -- OnPluginSend 


Now you don't use the sit alias at all. The condition it needs to test for (needles in room or whatever) can be placed in a variable (that the plugin maintains itself), and then disable the send of sit to the MUD.

If any plugin disables the send, then the line is not sent, so this will work regardless of what other plugins do with aliases, triggers or whatever.

Now your other example only wanted to know if you were sitting, so rather than have an alias that matches on 'sit' and then sends 'sit', you could do this:


function OnPluginCommand (s)

  if string.lower (s) == "sit" then
    VoluntaryProne = true
  end -- if doing sit

  return true  -- allow command to proceed
end -- OnPluginCommand 


These examples are in Lua, but you get the idea.

Effectively using OnPluginCommand lets you write an alias that "passes through", as it isn't in the chain of alias processing.

I do see a problem here however. Using OnPluginCommand only detects commands you type, not someone doing a "sit" from an alias or trigger.

A way around that would be to modify the earlier function:


function OnPluginSend (s)

  if string.lower (s) == "sit" then
    if GetVariable ("can_sit") ~= "1" then
      Note "sit disabled in plugin 1"
      return false
    else
       VoluntaryProne = true  -- they are sitting now
    end -- if
  end -- if doing sit

return true

end -- OnPluginSend 


However there is a problem. If two plugins incorporate this, and the first one allows sitting it has set the VoluntaryProne flag. However it doesn't realize the second plugin will not allow the "sit" command through.

To do this we really need a callback that tells us what actually got sent, not what might or might not be sent if another plugin disables it.

I can't think of an easy way around this, short of this extra callback. You could conceivably test a variable (or entity as Ked suggested) however that relies on each plugin cooperating on what that entity name might be.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Nick Gammon   Australia  (22,973 posts)  [Biography] bio   Forum Administrator
Date Reply #4 on Thu 03 Aug 2006 10:31 PM (UTC)
Message
To put this another way, we would have 2 bites at the cherry:


  1. What we propose to send: OnPluginSend - can disable the send

  2. What we actually sent (if anything): OnPluginSent


Thus all plugins first get a chance to disable the sent text (OnPluginSend).

Then all plugins get told what actually got send (OnPluginSent). They can then adjust their flags about what we actually sent accordingly.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Nick Gammon   Australia  (22,973 posts)  [Biography] bio   Forum Administrator
Date Reply #5 on Thu 03 Aug 2006 10:42 PM (UTC)

Amended on Thu 03 Aug 2006 10:43 PM (UTC) by Nick Gammon

Message
Quote:

MUSH supports multiple aliases triggering on the same command, so why not let them be able to work better together?


I still don't think it will work. Let's say we have three plugin writers, A, B and C. (Anthony, Bruce, and Charlie).

Anthony writes a plugin that detects "sit", sets a flag, and has "passthrough=y" in the plugin, knowing that the sit command eventually goes to the MUD.

Bruce writes a plugin that detects "sit", and conditionally sends "world.Send 'sit'", because he didn't know about the passthrough flag.

Charlie writes a plugin that detects "sit", sets his own flag, and then does "world.Send 'sit'", because he didn't know about the passthrough flag.

Problems here:


  • We get two "sit" command sent possibly

  • If Charlie's plugin is not installed, but Bruce's is, then the "sit" command is not sent at all, however Anthony has set the flag saying it has been sent.


I think the flag idea creates as many problems as it solves.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Ked   Russia  (524 posts)  [Biography] bio
Date Reply #6 on Thu 03 Aug 2006 11:44 PM (UTC)
Message
I like the OnPluginSent idea, even though I don't think that flags going out of synch with reality is that big of a deal. Frankly, I think that if a plugin author presumes that his command has reached the server and had the desired effect and sets a corresponding flag without first receiving solid proof in form of a message from the server then such author fully deserves his flags going out of synch :)

But the OnPluginSent callback would still be useful.
[Go to top] top

Posted by Nick Gammon   Australia  (22,973 posts)  [Biography] bio   Forum Administrator
Date Reply #7 on Thu 03 Aug 2006 11:55 PM (UTC)
Message
Quote:

... without first receiving solid proof in form of a message from the server ...


It isn't a message from the server, it is simply confirmation that this command was actually sent.

I think it would be a handy idea, that if you had lots of scripts, aliases, triggers, plugins etc., for a particular plugin to know that a particular command had actually been sent.

Of course, it isn't absolutely foolproof, perhaps the server would not process the command for some reason, but it is a start.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Nick Gammon   Australia  (22,973 posts)  [Biography] bio   Forum Administrator
Date Reply #8 on Fri 04 Aug 2006 03:12 AM (UTC)
Message
Added OnPluginSent callback to version 3.78.

This will let you set a flag (like VoluntaryProne = true) when you know that a command is definitely being sent to the MUD.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Worstje   Netherlands  (899 posts)  [Biography] bio
Date Reply #9 on Thu 14 Sep 2006 09:02 PM (UTC)

Amended on Thu 14 Sep 2006 09:04 PM (UTC) by Worstje

Message
The new function seems bugged, atleast when using Python.

Having OnPluginSent present causes an errorwindow to appeasr with the text 'Type mismatch'. After that, no input whatsoever is possible until closing the world window. Unloading plugin does not work.

Example:

def OnPluginSent(text):
world.Note("Test.")

or even simpler,

def OnPluginSent(text):
return


[Go to top] top

Posted by Nick Gammon   Australia  (22,973 posts)  [Biography] bio   Forum Administrator
Date Reply #10 on Thu 14 Sep 2006 09:41 PM (UTC)
Message
It seems that the Python interpreter insists on the correct function result. It worked for me if you return something:


def OnPluginSent(text):
  world.note ("Got " + text)
  return 0


- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Worstje   Netherlands  (899 posts)  [Biography] bio
Date Reply #11 on Thu 14 Sep 2006 11:27 PM (UTC)
Message
That worked wonders, thanks!
[Go to top] top

The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).

To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.


21,107 views.

It is now over 60 days since the last post. This thread is closed.     [Refresh] Refresh page

Go to topic:           Search the forum


[Go to top] top

Quick links: MUSHclient. MUSHclient help. Forum shortcuts. Posting templates. Lua modules. Lua documentation.

Information and images on this site are licensed under the Creative Commons Attribution 3.0 Australia License unless stated otherwise.

[Home]


Written by Nick Gammon - 5K   profile for Nick Gammon on Stack Exchange, a network of free, community-driven Q&A sites   Marriage equality

Comments to: Gammon Software support
[RH click to get RSS URL] Forum RSS feed ( https://gammon.com.au/rss/forum.xml )

[Best viewed with any browser - 2K]    [Hosted at HostDash]