What is GMCP?
Glad you asked, gov'nor. GMCP stands for Generic MUD Communication Protocol. It's an underlying communication layer sent to your MU* client in addition to the usual text-based output. In simpler terms, it's a wealth of information about your character and their environment, that updates in realtime as you play.
Aetolia (and other IREs, for that matter) send this info to your client in this order:
- Primary events (gmcp.Room, gmcp.Char, ...)
- Secondary events (gmcp.Room.Players, gmcp.Comm.Channel.Start, ...)
- Output text (what you typically see on your screen)
- Telnet GA sequence (the prompt)
How do I access GMCP data?
Interpretation of GMCP data will vary by client.
- To enable GMCP in Mudlet, navigate to Options --> Preferences and view the main General tab. Make sure the checkbox marked Enable GMCP is enabled, and restart the program.
Mudlet catches this GMCP data and populates the following table: gmcp. Remember, Lua is case sensitive. It's not GMCP or Gmcp, it's gmcp. The gmcp table is further divided into sub-tables representing each module: Char, Room, Comm, and others.
When gmcp is updated, Mudlet raises an event for every single table within gmcp. For instance, when you take damage or level up, gmcp.Char.Vitals is updated with new health or XP information. Mudlet also raises an event, which itself is called gmcp.Char.Vitals.
This system of updating and event raising is practically enough to build an entire comprehensive system!
How do I use events?
Lua is a scripting language with extensibility in mind. When implemented in applications like Mudlet or World of Warcraft, its purpose is to act as a layer on top of whatever the program was written in, to provide the end user with an easy and intuitive coding interface that they can use to modify the application.
Events have many implementations, but one of the chief uses is to signal to the Lua interface that the program has done something. A very common Mudlet example is the window resize event, which is raised every time you move or resize your Mudlet window. This event is hidden from the user, but a function exists to help us use it: handleWindowResizeEvent().
What we're going to learn here is how to capture GMCP events, for the purposes of using them in our system.
Navigate to your scripting window:
And let's make a new script:
- (yes, my Aetolia profile is named Lusternia, it's a long story)
- Create a new script.
- Make sure it's activated! Click the lock icon on the left.
- Name the script. IMPORTANT: There MUST be a function in the script file with the exact same name as this script page for this to work!
With our new script page created, we're gonna add some events that we want to capture. For the purposes of demonstration, I'm going to keep this one super simple. We'll make our system respond to the Room information being updated, and our Character information being updated.
- Type in the name of the event(s) you want handled. This must be the exact same name of the gmcp sub-table you want and IT IS CASE SENSITIVE.
- Enter each one and hit the plus (+) button to add the event.
Now, at this point, we have a fresh new test script and we're watching these events! There's only two steps left to go: We need to add our handler function (the one that shares the same name as the script page), and then write a little code to show that it's all working okay.
- I'm gonna show you how this is done, but you have to write it yourself!
Now, here's how this madness works:
- Every single time gmcp.Room and gmcp.Char are raised (you move into a room, you look into a room, you take damage, you check your SCORE, you receive a prompt, etc.), this script page will call the handler function, in this case, handleTestEvent().
- When a handler function is called, the first argument (that's the stuff that goes between the parentheses in a function call) is the name of the event that called it. As you can see in handleTestEvent(), our first argument is passed as "e", and you can see how we're checking to see whether "e" was gmcp.Room, or gmcp.Char. If either one checks out, we're going to call functions made just to handle those, listed below. You can also just pop your code into the handler function, but I think this is cleaner.
- When we get room info, we're going to get a gold echo.
- When we get character info, we're going to get a subdued but equally hard working red echo.
Make sure to save your script, and then try it out in-game. Here's how it works for me:
As you can see, our information should be coming up properly!
So why are the echoes firing so much?
In this example, we handled two events: gmcp.Room and gmcp.Char. The problem with this is that these are primary modules, and are, in fact, made up of several secondary modules. Let's take a look, for instance, at what is actually being passed from gmcp.Room:
As you can see, gmcp.Room is divided into two secondary modules: gmcp.Room.Info, and gmcp.Room.Players. When we handle the event gmcp.Room, we not only handle that event, but every event beneath it.
This is why we're getting two golden echoes in the image above; one is the room's statistics being raised, and the other is a list of players! The same is occurring with gmcp.Char: We're actually seeing events raised for gmcp.Char.Vitals, and gmcp.Char.Status.
- gmcp.Char actually contains a lot more secondary events (Items, Name, Skills, and StatusVars), but these are only raised under special circumstances.
So how do we make this more efficient?
Divide our handled events into their respective submodules. I prefer to maintain a script page for each primary module (one for Room, one for Char, etc.), with a handler that works with each submodule, but let's be lazy and just modify our test module to make it more specific.
With this structure, we only care about two bits of information: Players in the room, and our vitals. I'll leave it to you to try this and see what it does, but it's guaranteed to be a lot less spammy!
So, this concludes my little tutorial on how to play with GMCP. If you have any questions or want to throw out some pointers, please feel free to do so.