GMCP in Aardwolf MUD using Mushclient.

GMCP in Mushclient


The GMCP plugin client for Mushclient can be download here: Mushclient GMCP Plugin. The plugin requires Mushclient version 4.59 or higher as this is the first version that includes JSON support as part of the standard Mushclient package.

The Aardwolf MUSHclient Package already includes this plugin, so you should not download it again. Just keep reading.

The download includes two files. If you unzip this in your main Mushclient directory the files should be where they need to be:

  • The 'gmcphelper.lua' file should go into your lua library directory. This is the 'lua' directory in your main Mushclient directory. For example, if you have Mushclient installed in c:\program files\mushclient then the main lua directory will be c:\program files\mushclient\lua.
  • The 'GMCP_handler.xml' should go into your main plugins directory, usually under 'worlds' in the main Mushclient directory.

Note: Most unzip utilities have the ability to browse to a directory and unzip the file in that directory. Use the main mushclient directory and the files will be in the correct place. If you are prompted to 'merge' directories, accept this for each directory.

  • Load Mushclient and connect to Aardwolf.
  • The GMCP handler then needs adding to your plugin list. Add the plugin by selecting the 'File' menu, then 'Plugins' then 'Add' and locate the GMCP_handler.xml file.
  • Type 'protocols gmcp restart - this causes Aardwolf to attempt to enable GMCP in the client.

The GMCP_handler plugin includes two aliases that you can use:

  • gmcpdebug [0|1|2] - View GMCP data coming from the MUD at varying levels of detail (0 is off). GMCPdebug 1 is the most useful.
  • sendgmcp [message] - Send raw GMCP data to the MUD. This is useful for sending the GMCP Commands directly to the Aardwolf.

You can confirm that GMCP is working by typing 'sendgmcp debug on'. You should get back '## GMCP Debug Mode On.'. Typing 'sendgmcp debug off' to turn it back off, GMCP is working.

Other than these two aliases, the GMCP handler itself doesn't do a whole lot. Its purpose is to capture the GMCP data into a single table then broadcast to other plugins that a new GMCP message has been received.

Other plugins then check for a broadcast from the GMCP handler, check to see if they are interested in the type of message and, if they are, request data from the GMCP handler. The plugins can request data at any level of the overall hierarchy. For example, a snippet from the stats plugin:

function OnPluginBroadcast (msg, id, name, text)

   -- Look for GMCP handler.
   if (id == '3e7dedbe37e44942dd46d264') then
      if (text == "char.stats" or text == "char.maxstats" or text == "char.vitals" or text == "char.worth" or text == "char.status") then
         res, gmcparg = CallPlugin("3e7dedbe37e44942dd46d264","gmcpval","char") --- We just want the gmcp.char section.
         luastmt = "gmcpdata = " .. gmcparg --- Convert the serialized string back into a lua table.

         assert (loadstring (luastmt or "")) ()

         -- We asked for all char data in CallPlugin, so we now have a lua table 'gmcpdata' containing 
         -- all char data. This can be seen in table example 1 below.

         -- If we had asked for char.stats instead, using:
         --     res, gmcparg = CallPlugin("3e7dedbe37e44942dd46d264","gmcpval","char.stats") --- 
         -- We would get a smaller table with only that information. See table example 2 below.
      end
   end
   ...
end -- onpluginbroadcast

One thing to note is that function OnPluginBroadcast (msg, id, name, text) is a special function only available inside of Plugins and is used to alert the plugin when something changes in another plugin (in this case the GMCP handler). If you are writing standalone triggers or aliases, you can't use this method to get automatically notified of GMCP updates. But you CAN still use everything inside the inner "if then end" block from the CallPlugin line to the loadstring line to grab values from the handler.

Using GMCP data in Mushclient plugins


The example above shows how to pull the GMCP data you are interested in into the table 'gmcpdata' via a call to the main GMCP handler.

To access individual attributes, while you could access gmcdata directly this is not recommended. Using room data as an example, to get the target destination of the room to the north you would need to access room.info.exits.n. As long as you had a full room data, this would work, but if room.info or room.info.exits were null, your plugin would error out and have to be reloaded to continue working.

The safe way to do this is via the helper function gmcpval inside gmcphelper.lua which will check each level of the table hierarchy and return an empty value if the data is not found. For example:

(Note: the following code assumes you've already done the CallPlugin/loadstring dance above to populate the gmcpdata table)

    require "gmcphelper" -- this line is necessary for us to be able to use the gmcpval helper function defined in gmcphelper.lua

    local hp = gmcpval("vitals.hp") -- we don't use char.vitals.hp - our toplevel is already "char".
    local maxhp = gmcpval("maxstats.maxhp")
    local hppct = 0

    if hp > 0 && maxhp > 0 then 
       local hppct = hp / maxhp * 100
    end

--- OR

    local north_dest = gmcpval("exits.n") -- our callplugin was for "room.info"
    if north_dest then
       -- do whatever we are interested in with north exit
    end


Table example1:


GMCP data after calling 'gmcpval' in the GMCP handler plugin with 'char' as the required level of data (all char data):

{
  stats = {
    str = "400",
    hr = "240",
    wis = "400",
    con = "400",
    luck = "400",
    saves = "0",
    dex = "400",
    int = "400",
    dr = "215",
    },
  base = {
    race = "Human",
    name = "Lasher",
    clan = "wolf",
    subclass = "Guardian",
    class = "Paladin",
    pretitle = "Testing ",
    perlevel = "10000",
    },
  worth = {
    tp = "10931",
    gold = "23128374229",
    qp = "5038867",
    pracs = "24",
    trains = "112",
    bank = "750000",
    },
  vitals = {
    mana = "50029",
    hp = "50054",
    moves = "41629",
    },
  maxstats = {
    maxcon = "400",
    maxluck = "400",
    maxstr = "400",
    maxdex = "400",
    maxmana = "50029",
    maxmoves = "41629",
    maxwis = "400",
    maxint = "400",
    maxhp = "50054",
    },
  status = {
    state = "3",
    tnl = "1000",
    thirst = "70",
    pos = "Standing",
    align = "984",
    level = "210",
    hunger = "70",
    enemy = "",
    },
  }

Table example2:


GMCP data after calling 'gmcpval' in the GMCP handler plugin with 'char.stats' as the required level of data (all char data). Note that we don't have a higher level 'stats' table here - the top level of our table is the top level of the data we requested:

gmcpdata = {
  str = "400",
  hr = "240",
  wis = "400",
  con = "400",
  luck = "400",
  saves = "0",
  dex = "400",
  int = "400",
  dr = "215",
  }