Skip to content
bawNg edited this page Apr 28, 2013 · 2 revisions

This is a basic introduction to writing a SparkMod plugin. If you are not already familiar with the Lua scripting language, it is recommended that you read a basic Lua tutorial.

Creating your first plugin

SparkMod plugins can run on both server and client but client-side plugins are not always needed. For your first ever SparkMod plugin, we will be creating a single file, server only plugin.

Open your favorite text editor and create a new empty file. If you do not already have a decent text editor which has Lua syntax highlighting, Decoda or Sublime Text 2 are recommended.

Defining plugin info

The first thing we do when creating a new plugin is define some basic information about our plugin, which can be viewed with the sm plugins list command. This info is defined by assigning the info variable to a table containing our plugin information.

info = {
    name = "Hello World",
    author = "Me",
    description = "My very first plugin ever",
    version = "0.1",
    url = "https://github.com/IntoxicatedGaming/SparkMod"
}

At this point our plugin is valid and can be loaded, but it does absolutely nothing. So let's first tell our plugin to print a message to the server console when it has been loaded. We'll do this by implementing a function named OnLoaded (you could also use OnPluginStart if you are already familiar with the SourceMod API). So let's go ahead and define our OnLoaded function and use the Puts function (short for "Put String") to print out a message.

function OnLoaded()
    Puts "Hello World"
end

That's it, we now have a complete Hello World plugin. Your full plugins code should look like this:

info = {
    name = "Hello SparkMod",
    author = "Me",
    description = "My very first plugin ever",
    version = "0.1",
    url = "https://github.com/IntoxicatedGaming/SparkMod"
}

function OnLoaded()
    Puts "Hello SparkMod"
end

We can now save our new plugin file as hello_world.lua, put it inside our sparkmod/plugins directory located in our NS2 server config directory and then load the plugin either by starting the server or using the console command sm plugins load hello_world. You should then see the message printed out in your server console.

Plugin Configs

Plugins can define a default config containing any JSON serializable data which is used to generate the plugins config file the first time the plugin is loaded. Plugin configuration is stored in your server config directory under sparkmod/configs/plugin_name.json and is loaded whenever your plugin is loaded.

Let's go ahead and define a single config value in our plugins default config which we will use in the next section.

default_config = {
    default_center_message = "Hello from SparkMod"
}

To reference this value from your plugin you use config.default_center_message.

Plugin Commands

Both admin and client commands are registered using specially named forwards which are defined as normal functions in your plugin. Client command forwards start with OnCommand or OnClientCommand and will by default respond to commands typed in both client console as well as in the normal global or team chat. Admin command forwards start with OnAdminCommand and can only be used in the client console of a server admin.

If you use CamelCase it will be automatically converted to under_scored, so using HelloWorld will register a command named hello_world. The command forward is passed a ServerClient instance followed by any space seperated arguments that were typed after the command. You can also define a description for your command by using a magic comment on the line above. Let's go ahead and implement our first admin command.

-- Prints a message to the center of a players screen
function OnAdminCommandCenterMessage(client, target_name, ...)
    if not target_name then
        -- The SendError helper responds to the client with an error message and stops processing the command.
        SendError "You need to give a target name to send the message to. Usage: center_message <target> [message]"
    end
    -- The FindPlayerMatchingName helper finds a single player matching the partial name given if possible. If there are
    -- multiple or no matches it will respond to the client with an appropriate error and will stop processing the command.
    local target_player = FindPlayerMatchingName(target_name)
    -- Join all remaining arguments together with spaces if any arguments are given else use the default_center_message
    local message = ArgCount(...) > 0 and ArgString(...) or config.default_center_message
    -- Send a message to the center of the target players screen
    PrintCenterText(target_player, message)
    -- Send a reply to the admin who used the command
    SendReply("Your message has been sent to the center of %N's screen.", target_player)
end

After saving and reloading your plugin, an admin will be able to send a message saying "Hello John" to the center of the screen of a player named "John Doe" by using the following command in their console: center_message john Hello John

Event Callbacks

SparkMod exposes many useful event callbacks to plugins in the form of forwards. Forwards are specially named callback functions which are defined in plugin files are and called by SparkMod when a certain event fires. SparkMod forwards can be used to hook many different kinds of events, including SparkMod specific events, standard Spark engine events, registering commands (as you have seen above), pre/post hooking a large number of game code functions and pre/post hooking network messages. Plugins can also fire global forwards which will be called in all other plugins.

The same forward can be defined in many different files belonging to a single plugin and all of these functions will be called when the event fires. Any forwards a plugin has registered are automatically removed when the plugin is unloaded.

General Callbacks

These callbacks are listed in the order they are called during the lifetime of a plugin.

  • OnLoaded / OnPluginStart - Called when the plugin is fully initialized and all plugin dependencies are resolved. This is only called once in the lifetime of the plugin. If any error occurs during this callback, the plugin will be unloaded and will have an error state set.
  • OnAllPluginsLoaded - Called once, after all non-late loaded plugins have called OnLoaded.
  • OnMapStart - Called every time the map loads. If the plugin is loaded late and the map has already started, this forward will be called after OnLoaded.
  • At this point almost any of the other available forwards can be called while the plugin is loaded.
  • OnMapEnd - Called when the map is about to end, clients will be disconnected and reconnect once the server has loaded the new map.
  • OnUnloaded / OnPluginEnd - Called when a plugin is about to be unloaded.

Client Callbacks

  • OnClientConnect - Called when a client attempts to connect.
  • OnClientPutInServer - Called when a connecting client has been assigned their correct nickname. At this point the client is in-game and is able to receive messages.
  • OnClientDisconnect - Called when a client is disconnecting, before the client has completely disconnected.
  • OnClientDisconnected / OnClientDisconnect_Post - Called when a client has disconnected.