GMCP in Aardwolf MUD using Mushclient.

Clients.MushclientGMCP History

Hide minor edits - Show changes to markup

February 15, 2020, at 04:23 AM EST by Fiendish
Changed lines 11-12 from:

GMCP in Mushclient

to:

PLEASE READ:

Changed lines 17-20 from:

NOTE: The Aardwolf MUSHclient Package obsoletes the information on this page. The information below is only useful if you are using MUSHclient but not using the Aardwolf MUSHclient Package.

For information on using GMCP in the Aardwolf MUSHclient Package, see: https://github.com/fiendish/aardwolfclientpackage/wiki/Using-GMCP

to:

The information on this page is obsolete if you use The Aardwolf MUSHclient Package.

To learn about using GMCP in the Aardwolf MUSHclient Package, visit: https://github.com/fiendish/aardwolfclientpackage/wiki/Using-GMCP

GMCP in Mushclient


March 13, 2017, at 03:58 AM EST by Fiendish
Added lines 15-18:

NOTE: The Aardwolf MUSHclient Package obsoletes the information on this page. The information below is only useful if you are using MUSHclient but not using the Aardwolf MUSHclient Package.

For information on using GMCP in the Aardwolf MUSHclient Package, see: https://github.com/fiendish/aardwolfclientpackage/wiki/Using-GMCP

Deleted lines 20-21:

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

February 28, 2014, at 06:59 PM EST by Fiendish2
Added lines 17-18:

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

January 02, 2012, at 02:07 AM EST by Fiendish2
Added lines 63-64:

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.

Added line 73:
January 02, 2012, at 02:03 AM EST by Fiendish2
Changed lines 70-71 from:

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):

to:

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)

January 02, 2012, at 02:01 AM EST by Fiendish2
Changed lines 68-71 from:

To access individial 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 which will check each level of the table hierarchy and return an empty value if the data is not found. For example:

to:

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):

Changed lines 73-74 from:
    require "gmcphelper" -- this line is required for us to be able to use the gmcpval helper function defined in gmcphelper.lua
to:
    require "gmcphelper" -- this line is necessary for us to be able to use the gmcpval helper function defined in gmcphelper.lua
January 02, 2012, at 01:56 AM EST by Fiendish2
Changed lines 73-74 from:
to:
    require "gmcphelper" -- this line is required for us to be able to use the gmcpval helper function defined in gmcphelper.lua
October 03, 2010, at 06:19 PM EST by admin
Added lines 21-23:

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.

October 03, 2010, at 06:18 PM EST by admin
October 03, 2010, at 06:12 PM EST by admin
Changed lines 20-21 from:
  • The 'GMCP_handler.xml' should go into your main plugins directory, usually under 'worlds' in the main Mushclient directory. It 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.
to:
  • The 'GMCP_handler.xml' should go into your main plugins directory, usually under 'worlds' in the main Mushclient 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.
September 17, 2010, at 07:06 PM EST by admin
Changed lines 27-28 from:

You can confirm that GMCP is working by typing 'sendgmcp hi!'. This is invalid GMCP so you should see back from the MUD: "GMCP Error: Invalid GMCP tag: hi (data:)"

to:

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.

September 08, 2010, at 06:58 PM EST by admin
Added lines 27-28:

You can confirm that GMCP is working by typing 'sendgmcp hi!'. This is invalid GMCP so you should see back from the MUD: "GMCP Error: Invalid GMCP tag: hi (data:)"

September 08, 2010, at 06:53 PM EST by admin
Changed lines 17-18 from:

The download includes two files:

to:

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

September 08, 2010, at 06:04 PM EST by admin
Added lines 83-84:

Table example1:

Deleted lines 86-88:

Table example1:


September 08, 2010, at 06:03 PM EST by admin
Changed lines 56-57 from:
to:


September 08, 2010, at 06:03 PM EST by admin
Changed lines 13-14 from:
to:


September 08, 2010, at 04:54 PM EST by admin
Changed lines 14-15 from:

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

to:

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.

Changed lines 18-20 from:
  • The 'gmcphelper.lua' file should go into your lua library directory. This is the 'lua' directory 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 and 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.
to:
  • 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. It 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.
Changed lines 23-25 from:
  • gmcpdebug [0|1|2] - View GMCP data coming from the MUD at varying levels of detail (0 is off).
  • sendgmcp [message] - Send raw GMCP data to the MUD. This is useful for sending the GMCP Commands directly to the Aardwolf.
to:
  • 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.
Changed lines 29-30 from:

Other plugins can 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 at any level of the overall hierarchy. For example, a snippet from the stats plugin:

to:

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:

Changed lines 58-59 from:

To access individial attributes, while you could access gmcdata directly this is not recommended. Using room 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.

to:

To access individial 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.

September 08, 2010, at 04:51 PM EST by admin
Changed lines 2-3 from:

Table of Contents

to:
Changed lines 4-6 from:

to:
Deleted lines 51-56:

--- Later in the plugin where the data is actually used: ... fstr = "@GStrength : @C\[@W%3d@C/@W%-3d@C\] @GHealth : @C\[@W%6d@C/@W%6d@C\]@w" s = fstr:format(gmcpval("stats.str"),gmcpval("maxstats.maxstr"),gmcpval("vitals.hp"),gmcpval("maxstats.maxhp")) ...

Changed lines 54-58 from:

Table example1:


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

to:

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 individial attributes, while you could access gmcdata directly this is not recommended. Using room 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 which will check each level of the table hierarchy and return an empty value if the data is not found. For example:

Added lines 63-88:
    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):

[@

September 08, 2010, at 04:34 PM EST by admin
Changed lines 63-64 from:
to:


Changed lines 127-128 from:
to:


September 08, 2010, at 04:34 PM EST by admin
Deleted line 124:
Added line 129:

[@

Changed lines 140-141 from:
  }
to:
  }

@]

September 08, 2010, at 04:33 PM EST by admin
Added lines 126-140:

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",
  }
September 08, 2010, at 04:30 PM EST by admin
Added line 30:

\\

Deleted lines 125-514:

GMCP Char. table example

GMCP in CMUD

GMCP comes enabled by default in CMUD. To set high level GMCP modules supported, enter the 'protocols' section of 'preferences' and add/remove items as necessary in the "supported packages" window. Each of the options is included below. For most users, we recommend leaving the defaults enabled and adding a "Debug 1" option.

GMCP in Mudlet

At the time of writing GMCP in Mudlet is only supported via a source version of the client which users have to compile for themselves so is not covered. If this is no longer true, please contact us (or just update the page, it's a wiki after all :) )

GMCP Debug Modes

GMCP is a very quiet protocol - all data exchange takes place behind the scenes. This is great when things are working, but can make the protocol difficult to debug when things are not. Aardwolf supports a number of debug options to provide the client with feedback on what is happening server side.

Standard Debug Mode - "Debug 1"


When "debug 1" is set in the "packages supported" window, any GMCP errors recognized server side will be sent to the screen. Depending on your client, a situation may occur where you cannot get GMCP working well enough to establish the initial exchange of tags supported so are unable to turn on 'debug 1'. On the Aardwolf test port (aardmud.net 6555) GMCP debug mode defaults to 'on'. To turn it off, explicitly set 'debug 0' in your Cmud settings.

The data below shows several invalid "supported package" strings and the output seen in the client when debug mode is on:
badopt 1
testopt 3
pudding 1 2 3 4
2

MUD Output:
GMCP Error: core.supports.set -> unsupported keyword badopt (data:badopt 1)

GMCP Error: core.supports.set -> setting should be 0 or 1 - received 3 (data:testopt 3)

GMCP Error: core.supports.set -> expected format is [key 0|1] - received (data:pudding 1 2 3 4)

GMCP Error: core.supports.set -> expected element to be string, got Integer


JSON Debug Mode - "Debug.json 1"


A number of the standard tags in GMCP use the JSON data format. For each piece of GMCP data sent to Aardwolf, whether or not it will be processed through a JSON parser will depend on the tag type. Most of the standard tags such as 'core.' are in JSON format, most of the Aardwolf specific tags (see below) are not.

There will be times when it is useful to see how the JSON parsed data appears to the server. The 'debug.json' config option is available on the test port only. When this option is turned on, JSON received by the server will be echod back to the client. Note that during connection time no JSON debug information is sent as the "debug.json 1" message has not been exchanged yet. Using the sample program from the CMUD GMPC link with the JSON debug option on:


$response = ""
#addkey $response client "CMUD"
#addkey $response version 3.22
#SENDGMCP "core.hello" $response
$list = {core 1|char 1|room 1|comm 1}
#SENDGMCP "core.supports.set" $list

Gives the response:

------------ Json Message Received -----------
{
   "client": "CMUD",
   "version": 3.2200000000000002
}
-------------- End Json Message --------------

------------ Json Message Received -----------
[
   "core 1",
   "char 1",
   "room 1",
   "comm 1"
]
-------------- End Json Message --------------


Packet Debug Mode - "Debug.packets 1"


If all else fails and GMCP debug mode combined with Json debug mode are not enough to resolve a problem, turning on this option will cause a byte-level dump of all GMCP (protocol 201) data received to be echod back to the client. For example, with this option active, the program above returns the output below. Note that there are two separate IAC-SB-201 messages because there are 2 'SENDGMCP' statements in the program:

--------------- Telnet Data Start-----------------
IAC SB 201
63 6f 72 65 2e 68 65 6c 6c 6f 20 7b 22 63 6c 69      core.hello {"cli        
65 6e 74 22 3a 22 43 4d 55 44 22 2c 22 76 65 72      ent":"CMUD","ver        
73 69 6f 6e 22 3a 33 2e 32 32 7d                     sion":3.22}             
IAC SE
---------------- Telnet Data End -----------------

--------------- Telnet Data Start-----------------
IAC SB 201
63 6f 72 65 2e 73 75 70 70 6f 72 74 73 2e 73 65      core.supports.se        
74 20 5b 22 63 6f 72 65 20 31 22 2c 22 63 68 61      t ["core 1","cha        
72 20 31 22 2c 22 72 6f 6f 6d 20 31 22 2c 22 63      r 1","room 1","c        
6f 6d 6d 20 31 22 5d                                 omm 1"]                 
IAC SE
---------------- Telnet Data End -----------------


Aardwolf Commands


The protocols command in Aardwolf MUD exists to provide some feedback on which protocols are enabled:

Using the syntax protocols gmcp will show which specific GMCP options are on and off:

The following commands also help configure or debug GMCP within Aardwolf

CommandAction
protocols gmcp sendbaseImmediately send GMCP char.base variables.
protocols gmcp sendcharImmediately send all GMCP char variables.
protocols gmcp sendmaxImmediately send GMCP char.maxstats data.
protocols gmcp sendstatsImmediately send GMCP char.stats data.
protocols gmcp sendstatusImmediately send GMCP char.status data
protocols gmcp sendvitalsImmediately send GMCP char.vitals data
protocols gmcp sendworthImmediately send GMCP char.worth data
protocols gmcp rawcolorToggle between GMCP rawcolor and ANSI mode
protocols gmcp restartTrigger sending of telnet negotiation to restart GMCP

GMCP Commands

GMCP also supports sending messages from the client to the server. The following "commands" can be sent from the client via GMCP. Some of these duplicate in-game command options, giving you the choice of whether to use GMCP itself to configure the session or in-game commands. The 'request' commands are often useful when a plugin is changed and needs to be redrawn - instead of having special "redraw" functions in the plugin, just let the data refresh and trigger a redraw the normal way.

CommandAction
request roomImmediately send GMCP room.info for current room
request charImmediately request GMCP char.* data
debug on/offTurns the debug mode on or off
rawcolor on/offTurns the rawcolor mode on or off

Example client triggers and scripts

CMUD Examples

CMUD - char.vitals.health trigger

The trigger below is a simple example to show data available in CMUD when GMCP messages are received. Whenever the player health changes, a GMCP message is sent to the client. The trigger is on a change in char.vitals.health:

The full code for this trigger is:

execwin stats { #clr }
#win stats {%ansi(high, white) --------------- Stats for %gmcp.char.base.name -------------------%cr}
#win stats {%ansi(high, green)Class   : %ansi(high, white)%gmcp.char.base.class    
            %ansi(high, green)Subclass: %ansi(high, white)%gmcp.char.base.subclass}
#win stats {%ansi(high, green)Race    : %ansi(high, white)%gmcp.char.base.race        
            %ansi(high, green)Clan    : %ansi(high, white)%gmcp.char.base.clan}

#win stats {%cr%ansi(high, cyan)Strength     : %ansi(high, green)%gmcp.char.stats.str%ansi(high, white) /
               %ansi(high, green)%gmcp.char.maxstats.maxstr   %ansi(high, cyan)Health : %ansi(high, green)
               %gmcp.char.vitals.hp%ansi(high, white) / %ansi(high, green)%gmcp.char.maxstats.maxhp }
#win stats {%ansi(high, cyan)Intelligence : %ansi(high, green)%gmcp.char.stats.int%ansi(high, white) /
               %ansi(high, green) %gmcp.char.maxstats.maxint   %ansi(high, cyan)Mana   : 
               %ansi(high, green)%gmcp.char.vitals.mana%ansi(high, white) / %ansi(high, green)%gmcp.char.maxstats.maxmana }
#win stats {%ansi(high, cyan)Wisdom       : %ansi(high, green)%gmcp.char.stats.wis%ansi(high, white) /
               %ansi(high, green) %gmcp.char.maxstats.maxwis  %ansi(high, cyan) Moves  : %ansi(high, green)
               %gmcp.char.vitals.moves%ansi(high, white) / %ansi(high, green)%gmcp.char.maxstats.maxmoves }
#win stats {%ansi(high, cyan)Dexterity    : %ansi(high, green)%gmcp.char.stats.dex%ansi(high, white)
               %ansi(high, white) / %ansi(high, green)%gmcp.char.maxstats.maxdex}
#win stats {%ansi(high, cyan)Constitution : %ansi(high, green)%gmcp.char.stats.con%ansi(high, white) /
                %ansi(high, green) %gmcp.char.maxstats.maxcon   %ansi(high, cyan)
                Hitroll: %ansi(high, green)%gmcp.char.stats.hr }
#win stats {%ansi(high, cyan)Luck         : %ansi(high, green)%gmcp.char.stats.luck%ansi(high, white) /
            %ansi(high, green) %gmcp.char.maxstats.maxluck   %ansi(high, cyan)Damroll: %ansi(high, green)
            %gmcp.char.stats.dr }

#win stats {%cr%ansi(high, cyan)Exp To Level : %ansi(high, green)%gmcp.char.status.tnl        
               %ansi(high, cyan)Level    : %ansi(high, green)%gmcp.char.status.level}
#win stats {%ansi(high, cyan)Alignment    : %ansi(high, yellow)%gmcp.char.status.align       
            %ansi(high, cyan)Gold     : %ansi(high, yellow)%gmcp.char.worth.gold}

#win stats {%cr%ansi(high, red)Fighting     : %gmcp.char.status.enemy%cr%ansi(high, green)E
            nemy Health : %gmcp.char.status.enemypct}

Sample output from this trigger is:

Disclaimer - there are probably better ways to present and format this data. For example, the formatting will completely break once someone with a different class or race uses it. The point of this trigger is to demonstrate how easy it is to get at the GMCP data. Someone else can make it pretty.

Aardwolf GMCP Modules




Feel free to experiment with these, but do not use them to build production plugins yet. Many of the 
attributes are difficult to put into a single category and could fit in several -- some of them may 
move. Compared to scraping tagged output such as statmon, adding new fields to groups will not break 
any existing scripts, but moving data between tag groups might.

Aardwolf Char. modules

The goal with these groups is to separate the total pool of stats into groups that tend to change together, rather than sending the whole set of data when any single value changes.

char.base

The 'char.base' set of data contains are items that will rarely change such as your class, subclass, race, clan, name. The char.base data is sent at login for scripts that want to capture this 'header' information and then not sent again unless one of these items changes.

char.base { "name": Lasher, "class": Warrior, "subclass": Soldier, "race": Elf, "clan": wolf, "pretitle": "Testing ", "perlevel": 1000 }

char.vitals

Contains health, mana and moves information. Example output is:

char.vitals { "hp": 100000, "mana": 90000, "moves": 41599 }

char.stats

Contains stats that are usually affected by spellups and training:

char.stats { "str": 251, "int": 250, "wis": 250, "dex": 250, "con": 250, "luck": 250, "hr": 2298, "dr": 207, "saves": 13 }

char.maxstats

Contains max values for stats. In a separate group because these change far less often:

char.maxstats { "maxhp": 50099, "maxmana": 50029, "maxmoves": 41629, "maxstr": 51, "maxint": 134, "maxwis": 50, 
                "maxdex": 183, "maxcon": 99, "maxluck": 200 }

char.status

Experience to level, enemy if fighting and enemy percentage. Hunger and Thirst levels, position, etc:

char.status { "level": 210, "tnl": 1000, "hunger": 70, "thirst": 70, "align": 1867, "state": 3, 
              "pos": "Standing" , "enemy": "an owl", "enemypct": 93 }

The 'state' field is the character's current state. It partly duplicates the 'position' field but provides more information. The list of values for state is given below. The value of this field is that if you use plugins that send commands to the MUD, you can detect if your character is in note mode or the pager and wait before sending those commands. This is particularly useful for things like spellup scripts.

  1         At login screen, no player yet
  2         Player at MOTD or other login sequence
  3         Player fully active and able to receive MUD commands
  4         Player AFK
  5         Player in note 
  6         Player in Building/Edit mode
  7         Player at paged output prompt
  8         Player in combat
  9         Player sleeping
  11        Player resting

char.worth

These fields are related to achievements or 'worth' in the game and cover qp, tp, etc:

char.worth { "gold": 23128310661, "bank": 750000, "qp": 5052186, "tp": 10930, "trains": 6, "pracs": 14 }

Aardwolf Room. modules


room.info

Room.info contains information about the current room and is in 3 main sections:

  • The header data such as room name and similar.

  • The exit directions and where they lead, with the following notes:
    • Inside a maze, room ids are not shown, just directions.
    • Custom exits are not shown, only the regular n/e/s/w/u/d for mapping purposes.
    • The recommended way to capture the ASCII map is still using maptags - there is no value in sending this out of band.

  • The coordinate info. The continent list is:
 0 = Mesolar
 1 = Southern Ocean
 2 = Gelidus
 3 = Abend
 4 = Alagh
 5 = Uncharted Oceans
 6 = Vidblain

room.info { "num": 16542, "brief" : "A Quiet Section of the Swamp", "zone": "fens", "sector": "forest", "flags": null, 
            "exits" : { "n": 16543, "s": 16545, "w": 16541 }, 
            "coord" : { "id": 2, "x": 5, "y": 33 } 
          }

A sample script to access/print this data in CMUD is:

#PRINT GMCP.room: %gmcp.room
#PRINT GMCP.room.exits: %gmcp.room.info.exits
#PRINT GMCP.room.exits.n: %gmcp.room.info.exits.n
#PRINT Continent: %gmcp.room.info.coord.id
#PRINT -----------------------------------------------

Which produces:

GMCP.room: info="num=16542|brief=A Quiet Section of the Swamp|zone=fens|sector=forest|flags|exits=""n=16543|s=16545|w=16541""|coord=""id=2|x=5|y=33"""
GMCP.room.exits: n=16543|s=16545|w=16541
GMCP.room.exits.n: 16543
Continent: 2

Aardwolf Comm. modules


comm.channels

The 'comm.channels' set of tags contain channel data and include regular channels, auction/market, tell, say and yell. Unlike the old output tags, these all share the same type of message format and the channel name within the GMCP data is what changes:

comm.channel { "chan": "gossip", "msg": "You gossip 'Testing'" }

comm.channel { "chan": "tell", "msg": "You tell Razor 'testing gmcp tells'" }

  • Notes on channels
   ** Says from mobs have their own channel known as 'mobsay'
   ** Colors can be configured to be ANSI or Raw. See GMCP options.

comm.events

The 'comm.events' group of tags are for actions and events the player may want to know about. Ticks, a global quest starting, the player requesting or completing a quest are all examples of 'events' that can be reported via GMCP. The event group of tags so far is:

comm.events - tick:

comm.event { "type" : "tick" }

comm.events - quest:

Sends information when anything related to a quest happens. The full set of messages is:

  Starting a new quest:
   comm.event { "type": "quest", "action": "start", "targ": "a swamp ape", "room": "Swamp Ape Enclosure", "area": "Aardwolf Zoological
                Park", "timer": 52 }

  Failing a quest:
   comm.event { "type": "quest", "action": "fail", "wait": 15 }

  Completing a quest:
   comm.event { "type": "quest", "action": "comp", "qp": 18, "tierqp": 9, "pracs": 0, "trains": 1, "tp": 0,
                "mccp": 2, "lucky": 0, "double": 0, "totqp": 29, "completed": 98 }

  Running out of time:
   comm.event { "type": "quest", "action": "timeout", "wait": 30 }

  Quest target killed:
   comm.event { "type": "quest", "action": "killed", "time": 52 }

  Quest time warning:
   comm.event { "type": "quest", "action": "warning", "time": 5 }

  Can now quest:
   comm.event { "type": "quest", "action": "ready" }
September 08, 2010, at 04:29 PM EST by admin
Changed lines 21-24 from:
  • The 'GMCP_handler.xml' should go into your main plugins directory 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.

The GMCP_handler plugin has two aliases that you can use:

to:
  • The 'GMCP_handler.xml' should go into your main plugins directory and 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.

The GMCP_handler plugin includes two aliases that you can use:

September 08, 2010, at 04:28 PM EST by admin
Added line 4:
Changed lines 7-8 from:
to:
September 08, 2010, at 04:27 PM EST by admin
Added lines 4-5:
September 08, 2010, at 04:27 PM EST by admin
Changed line 1 from:

(:title GMCP in Aardwolf MUD using Mushclient.

to:
September 08, 2010, at 04:26 PM EST by admin
Added lines 1-512:

(:title GMCP in Aardwolf MUD using Mushclient.

Table of Contents

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 4.59 is the first version that includes JSON support as part of the standard Mushclient package.

The download includes two files:

  • The 'gmcphelper.lua' file should go into your lua library directory. This is the 'lua' directory 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 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.

The GMCP_handler plugin has 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).
  • sendgmcp [message] - Send raw GMCP data to the MUD. This is useful for sending the GMCP Commands directly to the Aardwolf.

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 can 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 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

--- Later in the plugin where the data is actually used:
...
fstr = "@GStrength     : @C\[@W%3d@C/@W%-3d@C\]     @GHealth  : @C\[@W%6d@C/@W%6d@C\]@w"
s = fstr:format(gmcpval("stats.str"),gmcpval("maxstats.maxstr"),gmcpval("vitals.hp"),gmcpval("maxstats.maxhp"))
...

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 = "",
    },
  }

GMCP Char. table example

GMCP in CMUD

GMCP comes enabled by default in CMUD. To set high level GMCP modules supported, enter the 'protocols' section of 'preferences' and add/remove items as necessary in the "supported packages" window. Each of the options is included below. For most users, we recommend leaving the defaults enabled and adding a "Debug 1" option.

GMCP in Mudlet

At the time of writing GMCP in Mudlet is only supported via a source version of the client which users have to compile for themselves so is not covered. If this is no longer true, please contact us (or just update the page, it's a wiki after all :) )

GMCP Debug Modes

GMCP is a very quiet protocol - all data exchange takes place behind the scenes. This is great when things are working, but can make the protocol difficult to debug when things are not. Aardwolf supports a number of debug options to provide the client with feedback on what is happening server side.

Standard Debug Mode - "Debug 1"


When "debug 1" is set in the "packages supported" window, any GMCP errors recognized server side will be sent to the screen. Depending on your client, a situation may occur where you cannot get GMCP working well enough to establish the initial exchange of tags supported so are unable to turn on 'debug 1'. On the Aardwolf test port (aardmud.net 6555) GMCP debug mode defaults to 'on'. To turn it off, explicitly set 'debug 0' in your Cmud settings.

The data below shows several invalid "supported package" strings and the output seen in the client when debug mode is on:
badopt 1
testopt 3
pudding 1 2 3 4
2

MUD Output:
GMCP Error: core.supports.set -> unsupported keyword badopt (data:badopt 1)

GMCP Error: core.supports.set -> setting should be 0 or 1 - received 3 (data:testopt 3)

GMCP Error: core.supports.set -> expected format is [key 0|1] - received (data:pudding 1 2 3 4)

GMCP Error: core.supports.set -> expected element to be string, got Integer


JSON Debug Mode - "Debug.json 1"


A number of the standard tags in GMCP use the JSON data format. For each piece of GMCP data sent to Aardwolf, whether or not it will be processed through a JSON parser will depend on the tag type. Most of the standard tags such as 'core.' are in JSON format, most of the Aardwolf specific tags (see below) are not.

There will be times when it is useful to see how the JSON parsed data appears to the server. The 'debug.json' config option is available on the test port only. When this option is turned on, JSON received by the server will be echod back to the client. Note that during connection time no JSON debug information is sent as the "debug.json 1" message has not been exchanged yet. Using the sample program from the CMUD GMPC link with the JSON debug option on:


$response = ""
#addkey $response client "CMUD"
#addkey $response version 3.22
#SENDGMCP "core.hello" $response
$list = {core 1|char 1|room 1|comm 1}
#SENDGMCP "core.supports.set" $list

Gives the response:

------------ Json Message Received -----------
{
   "client": "CMUD",
   "version": 3.2200000000000002
}
-------------- End Json Message --------------

------------ Json Message Received -----------
[
   "core 1",
   "char 1",
   "room 1",
   "comm 1"
]
-------------- End Json Message --------------


Packet Debug Mode - "Debug.packets 1"


If all else fails and GMCP debug mode combined with Json debug mode are not enough to resolve a problem, turning on this option will cause a byte-level dump of all GMCP (protocol 201) data received to be echod back to the client. For example, with this option active, the program above returns the output below. Note that there are two separate IAC-SB-201 messages because there are 2 'SENDGMCP' statements in the program:

--------------- Telnet Data Start-----------------
IAC SB 201
63 6f 72 65 2e 68 65 6c 6c 6f 20 7b 22 63 6c 69      core.hello {"cli        
65 6e 74 22 3a 22 43 4d 55 44 22 2c 22 76 65 72      ent":"CMUD","ver        
73 69 6f 6e 22 3a 33 2e 32 32 7d                     sion":3.22}             
IAC SE
---------------- Telnet Data End -----------------

--------------- Telnet Data Start-----------------
IAC SB 201
63 6f 72 65 2e 73 75 70 70 6f 72 74 73 2e 73 65      core.supports.se        
74 20 5b 22 63 6f 72 65 20 31 22 2c 22 63 68 61      t ["core 1","cha        
72 20 31 22 2c 22 72 6f 6f 6d 20 31 22 2c 22 63      r 1","room 1","c        
6f 6d 6d 20 31 22 5d                                 omm 1"]                 
IAC SE
---------------- Telnet Data End -----------------


Aardwolf Commands


The protocols command in Aardwolf MUD exists to provide some feedback on which protocols are enabled:

Using the syntax protocols gmcp will show which specific GMCP options are on and off:

The following commands also help configure or debug GMCP within Aardwolf

CommandAction
protocols gmcp sendbaseImmediately send GMCP char.base variables.
protocols gmcp sendcharImmediately send all GMCP char variables.
protocols gmcp sendmaxImmediately send GMCP char.maxstats data.
protocols gmcp sendstatsImmediately send GMCP char.stats data.
protocols gmcp sendstatusImmediately send GMCP char.status data
protocols gmcp sendvitalsImmediately send GMCP char.vitals data
protocols gmcp sendworthImmediately send GMCP char.worth data
protocols gmcp rawcolorToggle between GMCP rawcolor and ANSI mode
protocols gmcp restartTrigger sending of telnet negotiation to restart GMCP

GMCP Commands

GMCP also supports sending messages from the client to the server. The following "commands" can be sent from the client via GMCP. Some of these duplicate in-game command options, giving you the choice of whether to use GMCP itself to configure the session or in-game commands. The 'request' commands are often useful when a plugin is changed and needs to be redrawn - instead of having special "redraw" functions in the plugin, just let the data refresh and trigger a redraw the normal way.

CommandAction
request roomImmediately send GMCP room.info for current room
request charImmediately request GMCP char.* data
debug on/offTurns the debug mode on or off
rawcolor on/offTurns the rawcolor mode on or off

Example client triggers and scripts

CMUD Examples

CMUD - char.vitals.health trigger

The trigger below is a simple example to show data available in CMUD when GMCP messages are received. Whenever the player health changes, a GMCP message is sent to the client. The trigger is on a change in char.vitals.health:

The full code for this trigger is:

execwin stats { #clr }
#win stats {%ansi(high, white) --------------- Stats for %gmcp.char.base.name -------------------%cr}
#win stats {%ansi(high, green)Class   : %ansi(high, white)%gmcp.char.base.class    
            %ansi(high, green)Subclass: %ansi(high, white)%gmcp.char.base.subclass}
#win stats {%ansi(high, green)Race    : %ansi(high, white)%gmcp.char.base.race        
            %ansi(high, green)Clan    : %ansi(high, white)%gmcp.char.base.clan}

#win stats {%cr%ansi(high, cyan)Strength     : %ansi(high, green)%gmcp.char.stats.str%ansi(high, white) /
               %ansi(high, green)%gmcp.char.maxstats.maxstr   %ansi(high, cyan)Health : %ansi(high, green)
               %gmcp.char.vitals.hp%ansi(high, white) / %ansi(high, green)%gmcp.char.maxstats.maxhp }
#win stats {%ansi(high, cyan)Intelligence : %ansi(high, green)%gmcp.char.stats.int%ansi(high, white) /
               %ansi(high, green) %gmcp.char.maxstats.maxint   %ansi(high, cyan)Mana   : 
               %ansi(high, green)%gmcp.char.vitals.mana%ansi(high, white) / %ansi(high, green)%gmcp.char.maxstats.maxmana }
#win stats {%ansi(high, cyan)Wisdom       : %ansi(high, green)%gmcp.char.stats.wis%ansi(high, white) /
               %ansi(high, green) %gmcp.char.maxstats.maxwis  %ansi(high, cyan) Moves  : %ansi(high, green)
               %gmcp.char.vitals.moves%ansi(high, white) / %ansi(high, green)%gmcp.char.maxstats.maxmoves }
#win stats {%ansi(high, cyan)Dexterity    : %ansi(high, green)%gmcp.char.stats.dex%ansi(high, white)
               %ansi(high, white) / %ansi(high, green)%gmcp.char.maxstats.maxdex}
#win stats {%ansi(high, cyan)Constitution : %ansi(high, green)%gmcp.char.stats.con%ansi(high, white) /
                %ansi(high, green) %gmcp.char.maxstats.maxcon   %ansi(high, cyan)
                Hitroll: %ansi(high, green)%gmcp.char.stats.hr }
#win stats {%ansi(high, cyan)Luck         : %ansi(high, green)%gmcp.char.stats.luck%ansi(high, white) /
            %ansi(high, green) %gmcp.char.maxstats.maxluck   %ansi(high, cyan)Damroll: %ansi(high, green)
            %gmcp.char.stats.dr }

#win stats {%cr%ansi(high, cyan)Exp To Level : %ansi(high, green)%gmcp.char.status.tnl        
               %ansi(high, cyan)Level    : %ansi(high, green)%gmcp.char.status.level}
#win stats {%ansi(high, cyan)Alignment    : %ansi(high, yellow)%gmcp.char.status.align       
            %ansi(high, cyan)Gold     : %ansi(high, yellow)%gmcp.char.worth.gold}

#win stats {%cr%ansi(high, red)Fighting     : %gmcp.char.status.enemy%cr%ansi(high, green)E
            nemy Health : %gmcp.char.status.enemypct}

Sample output from this trigger is:

Disclaimer - there are probably better ways to present and format this data. For example, the formatting will completely break once someone with a different class or race uses it. The point of this trigger is to demonstrate how easy it is to get at the GMCP data. Someone else can make it pretty.

Aardwolf GMCP Modules




Feel free to experiment with these, but do not use them to build production plugins yet. Many of the 
attributes are difficult to put into a single category and could fit in several -- some of them may 
move. Compared to scraping tagged output such as statmon, adding new fields to groups will not break 
any existing scripts, but moving data between tag groups might.

Aardwolf Char. modules

The goal with these groups is to separate the total pool of stats into groups that tend to change together, rather than sending the whole set of data when any single value changes.

char.base

The 'char.base' set of data contains are items that will rarely change such as your class, subclass, race, clan, name. The char.base data is sent at login for scripts that want to capture this 'header' information and then not sent again unless one of these items changes.

char.base { "name": Lasher, "class": Warrior, "subclass": Soldier, "race": Elf, "clan": wolf, "pretitle": "Testing ", "perlevel": 1000 }

char.vitals

Contains health, mana and moves information. Example output is:

char.vitals { "hp": 100000, "mana": 90000, "moves": 41599 }

char.stats

Contains stats that are usually affected by spellups and training:

char.stats { "str": 251, "int": 250, "wis": 250, "dex": 250, "con": 250, "luck": 250, "hr": 2298, "dr": 207, "saves": 13 }

char.maxstats

Contains max values for stats. In a separate group because these change far less often:

char.maxstats { "maxhp": 50099, "maxmana": 50029, "maxmoves": 41629, "maxstr": 51, "maxint": 134, "maxwis": 50, 
                "maxdex": 183, "maxcon": 99, "maxluck": 200 }

char.status

Experience to level, enemy if fighting and enemy percentage. Hunger and Thirst levels, position, etc:

char.status { "level": 210, "tnl": 1000, "hunger": 70, "thirst": 70, "align": 1867, "state": 3, 
              "pos": "Standing" , "enemy": "an owl", "enemypct": 93 }

The 'state' field is the character's current state. It partly duplicates the 'position' field but provides more information. The list of values for state is given below. The value of this field is that if you use plugins that send commands to the MUD, you can detect if your character is in note mode or the pager and wait before sending those commands. This is particularly useful for things like spellup scripts.

  1         At login screen, no player yet
  2         Player at MOTD or other login sequence
  3         Player fully active and able to receive MUD commands
  4         Player AFK
  5         Player in note 
  6         Player in Building/Edit mode
  7         Player at paged output prompt
  8         Player in combat
  9         Player sleeping
  11        Player resting

char.worth

These fields are related to achievements or 'worth' in the game and cover qp, tp, etc:

char.worth { "gold": 23128310661, "bank": 750000, "qp": 5052186, "tp": 10930, "trains": 6, "pracs": 14 }

Aardwolf Room. modules


room.info

Room.info contains information about the current room and is in 3 main sections:

  • The header data such as room name and similar.

  • The exit directions and where they lead, with the following notes:
    • Inside a maze, room ids are not shown, just directions.
    • Custom exits are not shown, only the regular n/e/s/w/u/d for mapping purposes.
    • The recommended way to capture the ASCII map is still using maptags - there is no value in sending this out of band.

  • The coordinate info. The continent list is:
 0 = Mesolar
 1 = Southern Ocean
 2 = Gelidus
 3 = Abend
 4 = Alagh
 5 = Uncharted Oceans
 6 = Vidblain

room.info { "num": 16542, "brief" : "A Quiet Section of the Swamp", "zone": "fens", "sector": "forest", "flags": null, 
            "exits" : { "n": 16543, "s": 16545, "w": 16541 }, 
            "coord" : { "id": 2, "x": 5, "y": 33 } 
          }

A sample script to access/print this data in CMUD is:

#PRINT GMCP.room: %gmcp.room
#PRINT GMCP.room.exits: %gmcp.room.info.exits
#PRINT GMCP.room.exits.n: %gmcp.room.info.exits.n
#PRINT Continent: %gmcp.room.info.coord.id
#PRINT -----------------------------------------------

Which produces:

GMCP.room: info="num=16542|brief=A Quiet Section of the Swamp|zone=fens|sector=forest|flags|exits=""n=16543|s=16545|w=16541""|coord=""id=2|x=5|y=33"""
GMCP.room.exits: n=16543|s=16545|w=16541
GMCP.room.exits.n: 16543
Continent: 2

Aardwolf Comm. modules


comm.channels

The 'comm.channels' set of tags contain channel data and include regular channels, auction/market, tell, say and yell. Unlike the old output tags, these all share the same type of message format and the channel name within the GMCP data is what changes:

comm.channel { "chan": "gossip", "msg": "You gossip 'Testing'" }

comm.channel { "chan": "tell", "msg": "You tell Razor 'testing gmcp tells'" }

  • Notes on channels
   ** Says from mobs have their own channel known as 'mobsay'
   ** Colors can be configured to be ANSI or Raw. See GMCP options.

comm.events

The 'comm.events' group of tags are for actions and events the player may want to know about. Ticks, a global quest starting, the player requesting or completing a quest are all examples of 'events' that can be reported via GMCP. The event group of tags so far is:

comm.events - tick:

comm.event { "type" : "tick" }

comm.events - quest:

Sends information when anything related to a quest happens. The full set of messages is:

  Starting a new quest:
   comm.event { "type": "quest", "action": "start", "targ": "a swamp ape", "room": "Swamp Ape Enclosure", "area": "Aardwolf Zoological
                Park", "timer": 52 }

  Failing a quest:
   comm.event { "type": "quest", "action": "fail", "wait": 15 }

  Completing a quest:
   comm.event { "type": "quest", "action": "comp", "qp": 18, "tierqp": 9, "pracs": 0, "trains": 1, "tp": 0,
                "mccp": 2, "lucky": 0, "double": 0, "totqp": 29, "completed": 98 }

  Running out of time:
   comm.event { "type": "quest", "action": "timeout", "wait": 30 }

  Quest target killed:
   comm.event { "type": "quest", "action": "killed", "time": 52 }

  Quest time warning:
   comm.event { "type": "quest", "action": "warning", "time": 5 }

  Can now quest:
   comm.event { "type": "quest", "action": "ready" }