New modules supplied with MUSHclient 3.80

Posted by Nick Gammon on Thu 07 Sep 2006 06:42 AM — 7 posts, 36,183 views.

Australia Forum Administrator #0
I am encouraging the use of modules with MUSHclient 3.80 Lua scripts.

The module feature, combined with the "require" keyword, simplifies the importing of commonly-used scripts.

Various scripts that used to part of the exampscript.lua file in the MUSHclient distribution are now supplied separately in the (new) "lua" subdirectory (under the directory where the MUSHclient executable resides).

The reason for putting them there is that one of the default places that "require" looks is a subdirectory called "lua" under the directory of the current executable, and thus they should be found automatically.

If you prefer to put your script modules somewhere else, all you need to do to have them incorporated automatically is to amend the package.path variable somewhere, for example in the Global Preferences Lua sandbox code.

Something like this might do the trick:


package.path = "C:\\mushclient\\lua\\?.lua"


You need 2 backslashes because it is inside a quoted string. What this example would do is look for packages in the lua directory under C:\mushclient.

If you want to look in a second place, simply use a semicolon, and then mention the next place to search, like this:



package.path = "C:\\mushclient\\lua\\?.lua;C:\\mushclient\\plugins\\lua\\?.lua;"


A simple way of doing that is to get the paths from MUSHclient itself, like this:


package.path = GetInfo (66) .. "lua\\?.lua" -- application directory
package.path = package.path .. ";" .. GetInfo (59) .. "\\?.lua" -- script files directory
package.path = package.path .. ";" .. GetInfo (60) .. "?.lua" -- plugins directory


This example would look in the lua subdirectory under the MUSHclient application, and also directly inside the script files directory, and the plugins directory.

If you are a plugin author you may want to require your scripts relative to where the current plugin is (GetPluginInfo (20)), so that the plugin will find the appropriate scripts, regardless of where the user has installed the plugin.

The following Lua scripts are being supplied with MUSHclient 3.80:

  • addxml.lua - add triggers, timers, aliases, macros by supplying a table (and convert back to a table)
  • check.lua - check a world function return code
  • declare.lua - ensure variables in a function are declared
  • getlines.lua - iterator to convert a block of text into lines
  • pairsbykeys.lua - iterator to traverse a table, sorted by key order
  • serialize.lua - serialize Lua variables into a string
  • strict.lua - enforce use of local variables inside functions
  • tprint.lua - table printer
  • var.lua - use MUSHclient variables as if they are Lua variables
  • wait.lua - for pausing scripts until time elapsed, or certain text arrives from the MUD


Once your package.path is set up correctly, you simply require the package without the .lua extension. For example:


require "var"  -- use the var.lua package


If you like to have all of these packages available all the time, you could simply require them all as part of the global sandbox.
Amended on Thu 07 Sep 2006 07:40 AM by Nick Gammon
Australia #1
In serialize.lua at line 116:
assert( string.find( name, "^[_%a][_%a%d%.]*$" )
	and not lua_reserved_words[name],
	"Invalid name '" .. name .. "' for table")

incorrectly fails when serializing a nested table with spaces in the name.

Should be this?
assert( string.find( name, '^[_%a][_%a%d%.%[%]" ]*$' )
	and not lua_reserved_words[name],
	"Invalid name '" .. name .. "' for table" )



Thanks for the new version!
Australia Forum Administrator #2
Well, the generator generates lines like this:


foo.bar = 22

or

foo ['bar bar'] = 22


However it is expecting the table name itself to be a valid Lua name. Otherwise you might get something like this:


foo foo.bar = 22



Now that isn't valid syntax, so you would have to change the way it generates the table data in those cases.
Australia #3
I see. Substituting underscores in for spaces when capturing from string.match seems like the way to go for now.

But yes, probably trying to do something in not the best way again. Just confused as nested tables are actually allowed spaces (for now anyway). Is something like the following table to be discouraged from now on?
info = {}
info.items = {}
info.items["item name may contain spaces"] = {}
info.items["item name may contain spaces"].duration = 1
info.items["item name may contain spaces"].other_regular_elements = 1
USA #4
For the addxml.lua module, correct me if I'm wrong, but using the trigger function to add a trigger in a plugin will not work absolutely if you specify the script tag. Ie:

require "addxml"
addxml.trigger {  match = "swordfish", 
                regexp = true,
                ['repeat'] = true,   -- repeat is lua keyword
                script = "function_call",
                sequence = 50,
                enabled = true,
                name = "boris",
              }


Since you are using the ImportXML function, I am recalling this: http://www.gammon.com.au/forum/bbshowpost.php?id=6369 post, which states that setting the script entry points through ImportXML wil not work correctly in a plugin. I was wondering if you'd come up with a fix for this yet?
Australia Forum Administrator #5
Quote:

info = {}
info.items = {}
info.items["item name may contain spaces"] = {}
info.items["item name may contain spaces"].duration = 1
info.items["item name may contain spaces"].other_regular_elements = 1


Well, unless you rewrite the serializer a bit, that won't work. It eventually wants to use the table names on the left.

You could change it to make it work, it is only a suggestion, and as the Lua author says, various functions suit various purposes.
Australia Forum Administrator #6
Quote:

... setting the script entry points through ImportXML wil not work correctly in a plugin ...


It appears that is still the case. However the workaround mentioned will work, or we could probably improve the module to do that for us:


function trigger (t)
  GeneralAdd (t, "trigger", "triggers")

  -- force script entry-point resolution
  if t.name and t.script then
    SetTriggerOption (t.name, "script", t.script)
  end -- if trigger has a name, and a script name

end -- addxml.trigger

function alias (t)
  GeneralAdd (t, "alias", "aliases")

  -- force script entry-point resolution
  if t.name and t.script then
    SetAliasOption (t.name, "script", t.script)
  end -- if alias has a name, and a script name

end -- addxml.alias 

function timer (t)
  GeneralAdd (t, "timer", "timers")
  -- force script entry-point resolution
  if t.name and t.script then
    SetTimerOption (t.name, "script", t.script)
  end -- if timer has a name, and a script name

end -- addxml.timer 



New code in bold. That seems to make it work, however you will need a name (eg. a trigger name) for it to work.