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

Scripting callbacks - plugins

The following subroutines/functions will be called in your plugin if they are present. The names are hard-coded, and a check is made to see if such names exist when the plugin is installed. As each one starts with the characters "OnPlugin" you should not get clashes with your own routines, provided you avoid using that particular prefix when naming your own functions. The example code below is in Lua.

-- Plugin has been installed (added).
-- This is done immediately after the plugin has been added to the world's
-- list of plugins, and all plugin callback entry points found.
-- Note that any script instructions *outside* a plugin function will be
-- executed *before* this (as part of loading the script space).
function OnPluginInstall ()
end -- function

-- The list of plugins has changed
-- This includes: adding, removing, enabling, disabling a plugin
-- It also includes scripted loading and reloading of a plugin.
-- It is also called when loading a world file, after all plugins are loaded.
function OnPluginListChanged ()
end -- function

-- Plugin is being removed (closed).
-- Note that all plugins are closed when the world file is closed.
function OnPluginClose ()
end -- function

-- This world has been connected (to the MUD).
-- This is done after the username and password have been sent (if any).
-- It is done after the NAWS telnet negotiation, if any. (IAC, WILL, TELOPT_NAWS)
-- It is done after the main world's "connect" function, if any.
-- It is done after the log file is opened, if one is being opened automatically.
function OnPluginConnect ()
end -- function

-- This world has been disconnected (from the MUD).
-- This is called after the main world's "disconnect" function, if any.
-- It is called before the log file is closed, if any.
function OnPluginDisconnect ()
end -- function

-- The plugin is about to save its state
-- If you want to create new variables to be saved (eg. save script variables as MUSHclient variables)
--  now is the time to do it.
function OnPluginSaveState ()
end -- function

-- The main world file is being saved.
-- If you want to save things (eg. to a database or separate file) when the
-- world file is being saved do it now).
function OnPluginWorldSave ()
end -- function

-- The plugin is being enabled.
-- This is done *after* the enable flag is turned on.
function OnPluginEnable ()
end -- function

-- The plugin is being disabled.
-- This is done *after* the enable flag is turned off.
function OnPluginDisable ()
end -- function

-- The world to which the plugin belongs is getting the focus
function OnPluginGetFocus ()
end -- function

-- The world to which the plugin belongs is losing the focus
function OnPluginLoseFocus ()
end -- function


--  The player has typed the command 'sText'
--  Return TRUE to process the command, FALSE to discard it
function OnPluginCommand (sText)
  return true -- process it
end -- function


--  The contents of the command window has changed.

function OnPluginCommandChanged ()
  -- check contents of command window (eg. spellcheck)
end -- function 


-- The player has typed the command 'sText' and pressed <Enter>
-- You can modify the command in this function, and return the modified string
--   which is what will be sent to the command processor.
-- If you return an empty string, that will sent to the command processor.
-- If you return a tab character on its own (\t or hex 09) then the command will be
-- discarded, and the command window cleared (unless auto-repeat commands is set).
-- If you return a carriage-return character on its own (\r or hex 0D) then the command will be
-- discarded, and retained in the command window.
-- This differs from OnPluginCommand which processes individual command lines,
--  after command stacking and other processing has taken place.
--  The example replaces line breaks by %r.
--  You might use this to implement your own "rules" for evaluating command stacking,
--  spell checking, keeping a command history, and so on.

function OnPluginCommandEntered (sText)
  return string.gsub (sText, "\n", "%r")
end -- function 


-- The player has typed some text into the command window and pressed <Tab>.
-- The tab completion processing has found a match.
-- You can modify the match text in this function, and return the modified string
--   which is what will be replaced into the command window.

function OnPluginTabComplete (s)
  utils.msgbox (s)
end -- function 

--  MUSHclient is proposing to send 'sText' to the MUD
--  Return TRUE to send the text, FALSE to discard it
-- If any plugin returns FALSE, then the text is not actually sent.
-- If you want to know what was actually sent, use OnPluginSent (below).
--  If you call world.Send from within this function, OnPluginSend is not called again (however OnPluginSent will be).
function OnPluginSend (sText)
  return true  -- process it
end -- function

--  MUSHclient is definitely sending 'sText' to the MUD
-- This is called after every plugin has a chance to reject the text in the
--   OnPluginSend callback.
--  An example of use of this would be for an auto-mapper, as this function gets
--   text that has definitely been sent to the MUD.
-- If you call world.Send from within this callback, it will return an error.
--  OnPluginSent is supposed to be recording what is being sent, not sending new things.
function OnPluginSent (sText)
end -- function

--  MUSHclient has received the line 'sText'
--  Return TRUE to process the text, FALSE to discard it
function OnPluginLineReceived (sText)
  return true  -- display it
end -- function

In the case of routines like OnPluginCommand (about to send a command to the MUD), each plugin is scanned for every command entered. If any plugin returns FALSE, then that command is not processed. This gives each plugin a chance to respond to various commands, and suppress them if it wants to. Likewise for OnPluginSend (attempting to send a line of text to the MUD) and OnPluginLineReceived (received a line of text from the MUD).

--  MUSHclient has received the packet 'sText'
function OnPluginPacketReceived (sText)
end -- function

This function is called when each incoming packet (data) arrives from the MUD. A packet does not necessarily start or end on line boundaries, and may consist of partial text lines, or more than one line. If compression (MCCP) is active, the packet is the data after decompression.

Be warned that when compression is turned on, one packet may contain both uncompressed and compressed data (with the "turn on compression" sequence between them). Changing data in that packet may cause decompression to fail, if you alter the compressed part of the packet.

You can return data from this function (in version 3.59 onwards). If you do, then the returned data will replace the incoming data. In other words, you can change words, omit lines, add new lines, and MUSHclient will proceed as if the altered line had arrived from the MUD.


This will be called when one of these events occurs:

  • A line fills up (eg. you hit 80 characters if that is your screen width)
  • A newline is received
  • A partial packet is received, and no more input is currently available

The plugin is passed the current line - not just the new text - (which may or may not be "full" if the third condition is met) - which it can then test or pass into a regular expression for more complex testing.

This is intended to catch those situations where you need an immediate update (eg. a prompt line, entering a username/password when the newline is not present) on data received from the MUD.

Note that triggers will still be evaluated in the usual way, at the usual time. The plugin callback just gives you the chance to get at it sooner.

function OnPluginPartialLine (sText)
  AppendToNotepad ("test", sText . "\r\n")
end -- function


When a script calls BroadcastPlugin then all installed plugins are checked for a function OnPluginBroadcast. If present, it is called with 4 arguments:

  • The message number (the first argument to BroadcastPlugin).
  • The ID of the calling plugin, or an empty string if BroadcastPlugin was called from the main script file.
  • The name of the calling plugin, or an empty string if BroadcastPlugin was called from the main script file.
  • The Text argument (the second argument to BroadcastPlugin)

An example of a plugin handler might be (in Lua):

function OnPluginBroadcast (msg, id, name, text)
  Note ("msg = " .. msg)
  Note ("id = " .. id)
  Note ("name = " .. name)
  Note ("text = " .. text)

The calling plugin ID and name are supplied so that plugin writers can verify which plugin originated a particular message. This cannot be spoofed as it is supplied automatically by MUSHclient.


This is called when you have tracing turned on. If a plugin is found with this function in it, then it is called and the trace line is not displayed on the world output window. Only the first plugin found is called.

Example, in Lua:

function OnPluginTrace (line)
  AppendToNotepad ("Trace", line .. "\r\n")


This is intended for people with screen readers, who want the contents of the main window read out, however don't want gagged text to be read. The current way MUSHclient works is to draw text as it arrives, and then "undraw it" if it is gagged. This approach doesn't really work with screen readers, as they can't "unread" something.

The arguments to OnPluginScreendraw are:

Type: type of line, where 0 = output line, 1 = note, 2 = command

Log: are we planning to log it?

Line: the text of the line itself

An example plugin function, which simply copies the text to a notepad window, is as follows:

function OnPluginScreendraw (type, log, line)
  AppendToNotepad ("mylog", type, " ", log, " ", line, "\r\n")
end -- function


This is intended to allow plugin writers to make a miniwindow that has text that scrolls with the output window. It is called at the start of drawing (refreshing) the output window (eg. when a new line arrives from the MUD, or after a Note).

The arguments to OnPluginDrawOutputWindow are:

FirstLine: The first line number which is going to be drawn (starting at 1). You can use GetLineInfo to get details about that line.

ScrollOffset: The pixel position which it will start drawing at (based on the scroll bar thumb position). You can use that to tweak which pixel to start drawing at vertically.

NotUsed: An empty string (required because of the way plugin callbacks are implemented).

Example of echoing the line number in the output buffer, plus the text of the line is:

function OnPluginDrawOutputWindow (firstline, offset, notused)
  local background_colour = ColourNameToRGB ("lightgray")
  local text_colour = ColourNameToRGB ("green")
  local main_height = GetInfo (263)
  local font_height = GetInfo (212)

  -- clear window  
  WindowRectOp (win, miniwin.rect_fill, 0, 0, 0, 0, background_colour)

  -- allow for scrolling position
  local top =  (((firstline - 1) * font_height) - offset) - 2

  -- how many lines to draw
  local lastline = firstline + (main_height / font_height)
  for line = firstline, lastline do
    if line >= 1 and GetLineInfo (line, 1) then
      WindowText (win, font, line .. ": " .. GetLineInfo (line, 1), 0, top, 
                  0, 0, text_colour)
      top = top + font_height  
    end -- if line exists
  end -- for each line
end -- OnPluginDrawOutputWindow

Do not call WindowCreate inside this callback or strange things may happen as it is in the middle of drawing to the output device context. Reserve creating the window for OnPluginInstall and OnPluginWorldOutputResized.

Do not call Repaint inside this callback or the client will go into an infinite loop (it is already repainting the window, so trying to repaint it while repainting it will cause a loop). Also do not do things like print to the output window (eg. using Note) as that will cause the output window to be redrawn, and then the callback will be called again, and so on.


This is called when MUSHclient intends to play a sound (eg. new activity sound, trigger sound, world.Sound script function). If it finds a plugin with the OnPluginPlaySound function defined, then that is called, and the internal sound-player is not used. The only argument is the sound file name that is to be played.

function OnPluginPlaySound (sound)
  Note ("Playing sound ", sound)
end -- function

If you select the Display > Stop Sound Playing menu item, then OnPluginPlaySound will be called with an empty file name.


This is called when the output window is resized.

function OnPluginWorldOutputResized ()
  -- do something here
end -- function


This is called when the mouse is moved inside the output window.

function OnPluginMouseMoved (x, y, mw)
  -- do something here
  return 0
end -- function OnPluginMouseMoved

The x and y arguments (long integers) give the location of the mouse, relative to the top-left corner of the current world's output window.

The third argument is the miniwindow ID of any miniwindow the mouse may happen to be over, or "" if it is not over a miniwindow.


This is called 25 times a second.

function OnPluginTick ()
  -- do something here
  return 0
end -- function OnPluginTick

This is called 25 times a second (every 40 milliseconds), even if timers are disabled.

It is intended as a simple way of doing things that need to be done smoothly and more rapidly than timers allow (timer granularity is set to a minimum of 1/10 of a second). For example, when using the sound functions such as PlaySound, you could smoothly fade music up or down using this callback.

Also you might use it to implement scrolling text (eg. a miniwindow that says "Critical Hit!") which smoothly scrolls up the screen and disappears. The callback is called 25 times a second as 25 fps (frames per second) is about the minimum for smooth animation, so animated effects (like scrolling text) should look reasonably smooth if implemented using this.

Warning! This is implemented using a Windows timer event (WM_TIMER). This is a low-priority event, which means it may not be called if other things are happening. In other words, the timer may fire less frequently than 25 times a second, depending on what else is happening.


This is called if the server sends IAC WILL x, or IAC DO x to the client. In that case the callback lets you decide whether or not to handle the protocol (eg. ATCP or ZMP). The following protocols are handled internally and may not cause a call to this function (in some cases for DO and in some cases for WILL):

1 (ECHO) - output echo on/off
3 (SGA) - Suppress Go Ahead
24 (TERMTYPE) - send terminal type
25 (EOR) - End Of Record
31 (NAWS) - Negotiate About Window Size
70 (MSSP) - MUD Server Status Protocol
85 (MCCP v1) - MUD Client Compression Protocol version 1
86 (MCCP v2) - MUD Client Compression Protocol version 2
91 (MXP) - MUD eXtension Protocol
102 (Aardwolf options) - used by Aardwolf MUD and some MUSHclient plugins

If you return true then MUSHclient will send a positive response to the server and then call OnPluginTelnetRequest a second time with another code, as follows:

If it initially called the plugin with "WILL" it will call back with "SENT_DO".
If it initially called the plugin with "DO" it will call back with "SENT_WILL".

This is because the positive response to WILL is DO, and the positive response to DO is WILL. This second call to OnPluginTelnetRequest lets you do extra processing after agreeing to the negotiation with the server, such as logging on to it.

The OnPluginTelnetRequest function should return true to indicate it handled the message, or false if it did not. Once OnPluginTelnetRequest returns true in one plugin, no further plugins are checked. This is to stop multiple plugins logging in, as presumably a single login is all that is required.

function OnPluginTelnetRequest (type, data)

  if type == 200 and data == "WILL" then
    return true
  elseif type == 200 and data == "SENT_DO" then
    -- IAC SB 200 response IAC SE 
    SendPkt ("255250200Server.Logon Nick255240")  -- example only
  end -- if

end -- function OnPluginTelnetRequest


This is called if the server sends IAC SB x <data> IAC SE to the client. In that case the callback lets you handle the protocol yourself. The following types are not sent as they are handled internally.

24 (terminal type)
42 (charset)
85 (MCCP v1)
86 (MCCP v2)
91 (MXP)

In the case of type 102, then OnPluginTelnetOption is called as well (without the option number, as that is fixed at 102).

function OnPluginTelnetSubnegotiation (type, data)
  Note ("received negotiation: ", telnet_option)
  Note ("Received option string ", utils.tohex (data))
end -- function OnPluginTelnetSubnegotiation

Note - despite the above example, it is not recommended that you do Notes (or anything similar) when receiving telnet subnegotiation packets. Doing a Note may switch the current line from "MUD output" to "Note line" in ways that are not expected, particularly if you are hoping to trigger on the next line that arrives.


This is called if the server sends IAC SB 102 <data> IAC SE to the client. In that case the callback lets you handle the protocol yourself. This is similar to OnPluginTelnetSubnegotiation but is included separately for backwards compatibility. Note that OnPluginTelnetSubnegotiation is also called (afterwards), so new scripts can just use OnPluginTelnetSubnegotiation.

function OnPluginTelnetOption (data)
  Note ("Received option string ", utils.tohex (data))
end -- function OnPluginTelnetOption


This is called if the server sends IAC GA (0xFF 0xF9) or IAC EOR (0xFF 0xEF) to the client. This is intended for situations like where the ATCP protocol sends a whole lot of telnet negotiation sequences, and then IAC GA when waiting for player input. In this case the IAC GA could be a signal to a plugin to start responding.

function OnPlugin_IAC_GA ()
  -- respond to server
end -- function OnPlugin_IAC_GA

Chat System Callbacks


--  MUSHclient has received a connection from IP,name
--  Return TRUE to accept it, FALSE to reject it
function OnPluginChatAccept (sText)

local username, ip = string.match (sText, "(.-),(.+)")

end -- function


--  MUSHclient has received chat message: id, message, text
--  Return TRUE to use the default processing, FALSE to ignore it
--  The message code indicating the chat message, where these are likely
--         to be received:

--   1    Name_change				  
--   2    Request_connections 
--   3    Connection_list	 		
--   4    Text_everybody			
--   5    Text_personal			  
--   6    Text_group				  
--   7    Message					    
--   8    Do_not_disturb			
--   9    Send_action				  
--  10    Send_alias				  
--  11    Send_macro				  
--  12    Send_variable				
--  13    Send_event			    
--  14    Send_gag				    
--  15    Send_highlight			
--  16    Send_list				    
--  17    Send_array				  
--  18    Send_baritem			  
--  19    Version					    
--  20    File_start				  
--  21    File_deny				    
--  22    File_block_request	
--  23    File_block			    
--  24    File_end				    
--  25    File_cancel				  
--  26    Ping_request				
--  27    Ping_response				
--  28    Peek_connections		
--  29    Peek_list			    	
--  30    Snoop					      
--  31    Snoop_data		
-- 105    Send_command		  

function OnPluginChatMessage (id, message, sText)
  return true -- process it
end -- function


--  MUSHclient is about to send chat message: id, message, text
--  Return TRUE to use the default processing, FALSE to ignore it
--  See above for the exact message numbers that might be sent.

function OnPluginChatMessageOut (id, message, sText)
  return true -- process it
end -- function


--  MUSHclient is about to display message: message, text
--  Return TRUE to use the default display, FALSE to not display
--  See above for the exact message types that might be received.

function OnPluginChatDisplay (message, sText)
  return true -- display it
end -- function


-- A new chat user has been accepted on: id, name
-- This script callback has been provided so you can take action if
-- you want (such as allowing file transfers).

function OnPluginChatNewUser (id, name)
end -- function


-- This chat user has disconnected for one reason or another.
-- This callback lets you take action (eg. notify others) however
-- you cannot send messages to this connection or change any options
-- once they have disconnected. The chat id is supplied so you can 
-- match the id to the one that connected.
-- For each call to OnPluginChatNewUser there should eventually be a
-- corresponding call to OnPluginChatUserDisconnect.
function OnPluginChatUserDisconnect (id, name)
end -- function

See Also ...


Lua base functions
Lua bc (big number) functions
Lua bit manipulation functions
Lua coroutine functions
Lua debug functions
Lua io functions
Lua LPEG library
Lua math functions
Lua os functions
Lua package functions
Lua PCRE regular expression functions
Lua script extensions
Lua SQLite (database) interface
Lua string functions
Lua syntax
Lua table functions
Lua utilities

(Help topic: general=plugin_callbacks)

Documentation contents page

Search ...

Enter a search string to find matching documentation.

Search for:   

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.


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 FutureQuest]