NAME

SpadsPluginApi - SPADS Plugin API

SYNOPSIS

Perl:

package MyPlugin;

use SpadsPluginApi;

my $pluginVersion='0.1';
my $requiredSpadsVersion='0.11';

sub getVersion { return $pluginVersion; }
sub getRequiredSpadsVersion { return $requiredSpadsVersion; }

sub new {
  my $class=shift;
  my $self = {};
  bless($self,$class);
  slog("MyPlugin plugin loaded (version $pluginVersion)",3);
  return $self;
}

1;

Python:

import perl
spads=perl.MyPlugin

pluginVersion = '0.1'
requiredSpadsVersion = '0.12.29'

def getVersion(pluginObject):
    return pluginVersion

def getRequiredSpadsVersion(pluginName):
    return requiredSpadsVersion


class MyPlugin:

    def __init__(self,context):
        spads.slog("MyPlugin plugin loaded (version %s)" % pluginVersion,3)

DESCRIPTION

SpadsPluginApi is a Perl module implementing the plugin API for SPADS. This API allows anyone to add new features as well as customize existing SPADS features (such as balancing algorithms, battle status presentation, players skills management, command aliases...).

This API relies on plugin callback functions (implemented by SPADS plugins), which can in turn call plugin API functions (implemented by SPADS core) and access shared SPADS data.

Plugins can be coded in Perl (since SPADS 0.11) or Python (since SPADS 0.12.29).

PYTHON SPECIFIC NOTES

How to read the documentation

This documentation was written when SPADS was only supporting plugins coded in Perl, so types for function parameters and return values are described using Perl terminology, with Perl sigils (% for hash, @ for array, $ for scalars). Python plugins just need to ignore these sigils and use their equivalent internal Python types instead (Python dictionaries instead of Perl hashes, Python lists instead of Perl arrays, Python tuples instead of Perl lists, Python None value instead of Perl undef value...).

In order to call functions from the plugin API, Python plugin modules must first import the special perl module, and then use the global variable of this module named after the plugin name to call the functions (refer to the SYNOPSYS for an example of a Python plugin named MyPlugin calling the slog API function).

Perl strings conversions

SPADS uses the Inline::Python Perl module to interface Perl code with Python code. Unfortunately, some versions of this module don't auto-convert Perl strings entirely when used with Python 3 (Python 2 is unaffected): depending on the version of Python and the version of the Inline::Python Perl module used by your system, it is possible that the Python plugin callbacks receive Python byte strings as parameters instead of normal Python strings. In order to mitigate this problem, the plugin API offers both a way to detect from the Python plugin code if current system is affected (by calling the get_flag function with parameter 'use_byte_string'), and a way to workaround the problem by calling a dedicated fix_string function which fixes the string values if needed. For additional information regarding these Python specific functions of the plugin API, refer to the API FUNCTIONS - Python specific section. Python plugins can also choose to implement their own pure Python function which fixes strings coming from SPADS if needed like this for example:

 def fix_spads_string(spads_string):
     if hasattr(spads_string,'decode'):
         return spads_string.decode('utf-8')
     return spads_string
 
 def fix_spads_strings(*spads_strings):
     fixed_strings=[]
     for spads_string in spads_strings:
         fixed_strings.append(fix_spads_string(spads_string))
     return fixed_strings

Windows limitations

On Windows systems, Perl emulates the fork functionality using threads. As the Inline::Python Perl module used by SPADS to interface with Python code isn't thread-safe, the fork functions of the plugin API (forkProcess and forkCall) aren't available from Python plugins when running on a Windows system. On Windows systems, using native Win32 processes for parallel processing is recommended anyway. Plugins can check if the fork functions of the plugin API are available by calling the get_flag Python specific plugin API function with parameter 'can_fork', instead of checking by themselves if the current system is Windows. Refer to the API FUNCTIONS - Python specific section for more information regarding this function.

Automatic asynchronous socket management (addSocket plugin API function) is also unavailable for Python plugins on Windows systems (this is due to the file descriptor numbers being thread-specific on Windows, preventing SPADS from accessing sockets opened in Python interpreter scope). However, it is still possible to manage asynchronous sockets manually, for example by hooking the SPADS event loop (eventLoop plugin callback) to perform non-blocking select with 0 timeout (refer to Python select documentation). Plugins can check if the addSocket function of the plugin API is available by calling the get_flag Python specific plugin API function with parameter 'can_add_socket', instead of checking by themselves if the current system is Windows. Refer to the API FUNCTIONS - Python specific section for more information regarding this function.

CALLBACK FUNCTIONS

The callback functions are called from SPADS core and implemented by SPADS plugins. SPADS plugins are actually Perl or Python classes instanciated as objects. So most callback functions are called as object methods and receive a reference to the plugin object as first parameter. The exceptions are the constructor (Perl: new receives the class/plugin name as first parameter, Python: __init__ receives the plugin object being created as first parameter), and a few other callbacks which are called/checked before the plugin object is actually created: getVersion and getRequiredSpadsVersion (mandatory callbacks), getParams and getDependencies (optional callbacks).

Mandatory callbacks

To be valid, a SPADS plugin must implement at least these 3 callbacks:

[Perl] new($pluginName,$context) . . . . [Python] __init__(self,context)

This is the plugin constructor, it is called when SPADS (re)loads the plugin.

The $context parameter is a string which indicates in which context the plugin constructor has been called: "autoload" means the plugin is being loaded automatically at startup, "load" means the plugin is being loaded manually using !plugin <pluginName> load command, "reload" means the plugin is being reloaded manually using !plugin <pluginName> reload command.

getVersion($self)

returns the plugin version number (example: "0.1").

getRequiredSpadsVersion($pluginName)

returns the required minimum SPADS version number (example: "0.11").

Configuration callback

SPADS plugins can use the core SPADS configuration system to manage their own configuration parameters. This way, all configuration management tools in place (parameter values checking, !reloadconf etc.) can be reused by the plugins. To do so, the plugin must implement following configuration callback:

getParams($pluginName)

This callback must return a reference to an array containing 2 elements. The first element is a reference to a hash containing the plugin global settings declarations, the second one is the same but for plugin preset settings declarations. These hashes use setting names as keys, and references to array of allowed types as values. The types must be either strings that match the keys of the %paramTypes hash defined in SpadsConf.pm file, or custom functions to implement custom value checks. Such custom value checking functions take 2 parameters: the value to check as first parameter and a boolean specifying if the value is the default value (i.e. first value declared in the definition, for preset settings) as second parameter. The function must return true if the value is valid, or false if it is invalid (refer to examples below).

As for global SPADS core settings, the global settings of the plugin cannot be changed dynamically except by editing and reloading the configuration files (for example by using the !reloadConf command). The global settings are defined before the preset definition sections in the plugin configuration file. Only one definition is allowed for each global setting, and only one value can be configured in each global setting definition. Global settings aren't impacted by preset changes. Global settings should be used for the structural parameterization of the plugin, which isn't supposed to be modified during runtime and isn't useful from end user point of view (for example file/directory path settings...).

As for SPADS core preset settings, the preset settings of the plugin can be changed dynamically (using the !plugin <pluginName> set <settingName> <settingValue> command for example, or simply by changing current global preset). The preset settings are defined in the preset definition sections of the plugin configuration file, after the global plugin settings. The preset settings can be defined multiple times (once in each preset declaration section). Multiple values can be configured in each preset setting definition (values are separated by pipe character |, the first value is the default value applied when loading the preset and the remaining values are the other allowed values). Preset settings are impacted by preset changes. Preset settings should be used for settings that need to be visible by end users and/or modifiable easily at runtime.

Example of implementation in Perl:

my %globalPluginParams = ( MyGlobalSetting1 => ['integer'],
                           MyGlobalSetting2 => ['ipAddr']);
my %presetPluginParams = ( MyPresetSetting1 => ['readableDir','null'],
                           MyPresetSetting2 => ['bool', \&myCustomSettingValueCheck] );

sub myCustomSettingValueCheck {
  my ($settingValue,$isDefault)=@_;
  return $settingValue eq 'true' || $settingValue eq 'false'
}

sub getParams { return [\%globalPluginParams,\%presetPluginParams] }

Example of implementation in Python:

def myCustomSettingValueCheck(settingValue,isDefault):
    return settingValue == 'true' or settingValue == 'false'

globalPluginParams = { 'MyGlobalSetting1': ['integer'],
                       'MyGlobalSetting2': ['ipAddr'] }
presetPluginParams = { 'MyPresetSetting1': ['readableDir','null'],
                       'MyPresetSetting2': ['bool', myCustomSettingValueCheck], };

def getParams(pluginName):
    return [ globalPluginParams , presetPluginParams ]

In these examples, the preset setting MyPresetSetting2 is declared as supporting both the values of the predefined type "bool" and the values allowed by the custom function myCustomSettingValueCheck. The predefined type "bool" allows values 0 and 1. The custom function myCustomSettingValueCheck allows values "true" and "false". So in the end the allowed values for the preset setting MyPresetSetting2 are: 0, 1, "true" and "false".

Dependencies callback

SPADS plugins can use data and functions from other plugins (dependencies). But this can only work if the plugin dependencies are loaded before the plugin itself. That's why following callback should be used by such dependent plugins to declare their dependencies, which will allow SPADS to perform the check for them. Also, SPADS will automatically unload dependent plugins when one of their dependencies is unloaded.

getDependencies($pluginName)

This callback must return the plugin dependencies (list of plugin names).

Example of implementation in Perl:

sub getDependencies { return ('SpringForumInterface','MailAlerts'); }

Example of implementation in Python:

def getDependencies(pluginName):
    return ('SpringForumInterface','MailAlerts')

Event-based callbacks

Following callbacks are triggered by events from various sources (SPADS, Spring lobby, Spring server...):

onBattleClosed($self)

This callback is called when the battle lobby of the autohost is closed.

onBattleOpened($self)

This callback is called when the battle lobby of the autohost is opened.

onGameEnd($self,\%endGameData)

This callback is called each time a game hosted by the autohost ends.

The \%endGameData parameter is a reference to a hash containing all the data stored by SPADS concerning the game that just ended. It is recommended to use a data printing function (such as the Dumper function from the standard Data::Dumper module included in Perl core) to check the content of this hash for the desired data.

onJoinBattleRequest($self,$userName,$ipAddr)

This callback is called each time a client requests to join the battle lobby managed by the autohost.

$userName is the name of the user requesting to join the battle

$ipAddr is the IP address of the user requesting to join the battle

This callback must return:

0 if the user is allowed to join the battle

1 if the user isn't allowed to join the battle (without explicit reason)

"<explicit reason string>" if the user isn't allowed to join the battle, with explicit reason

onJoinedBattle($self,$userName)

This callback is called each time a user joins the battle lobby of the autohost.

$userName is the name of the user who just joined the battle lobby

onLeftBattle($self,$userName)

This callback is called each time a user leaves the battle lobby of the autohost.

$userName is the name of the user who just left the battle lobby

onLobbyConnected($self,$lobbyInterface)

/!\ RENAMED TO onLobbySynchronized /!\

This callback has been renamed to onLobbySynchronized since SPADS v0.13.35. It can still be used under the name onLobbyConnected for the sake of backward compatibility, however this name is misleading so its usage under this name is not recommended (the callback is only called when the lobby connection is fully synchronized, i.e. when all the initial commands sent by the lobby server after successfully logging in have been received).

The $lobbyInterface parameter is the instance of the SpringLobbyInterface module used by SPADS.

onLobbyDisconnected($self)

This callback is called each time the autohost is disconnected from the lobby server.

onLobbyLoggedIn($self,$lobbyInterface)

This callback is called each time the autohost successfully logins on the lobby server. It is one of the three callbacks triggered when a new connection to the lobby server is established. These callbacks are called in following order:

The $lobbyInterface parameter is the instance of the SpringLobbyInterface module used by SPADS.

Note: This callback is the ideal place for a plugin to register its lobby command handlers using the addLobbyCommandHandler function of the plugin API, if this plugin needs to process the commands sent by the lobby server during the initial lobby state synchronization phase (i.e. commands sent before the LOGININFOEND command). For plugins that do not require being called back during the initial lobby state synchronization phase, the onLobbySynchronized callback should be used instead to register the lobby command handlers.

onLobbyLogin($self,$lobbyInterface)

This callback is called each time the autohost tries to login on the lobby server. It is one of the three callbacks triggered when a new connection to the lobby server is established. These callbacks are called in following order:

The $lobbyInterface parameter is the instance of the SpringLobbyInterface module used by SPADS.

onLobbySynchronized($self,$lobbyInterface)

This callback is called each time the autohost completes the lobby state synchronization phase, which occurs after successfully logging in. It is one of the three callbacks triggered when a new connection to the lobby server is established. These callbacks are called in following order:

The $lobbyInterface parameter is the instance of the SpringLobbyInterface module used by SPADS.

Note: This callback is the ideal place for a plugin to register its lobby command handlers using the addLobbyCommandHandler function of the plugin API, as long as this plugin does not need to process the commands sent by the lobby server during the initial lobby state synchronization phase (i.e. commands sent before the LOGININFOEND command). For plugins that require being called back during the initial lobby state synchronization phase, the onLobbyLoggedIn callback must be used instead to register the lobby command handlers.

onPresetApplied($self,$oldPresetName,$newPresetName)

This callback is called each time a global preset is applied.

$oldPresetName is the name of the previous global preset

$newPresetName is the name of the new global preset

onPrivateMsg($self,$userName,$message)

This callback is called each time the autohost receives a private message.

$userName is the name of the user who sent a private message to the autohost

$message is the private message received by the autohost

This callback must return:

0 if the message can be processed by other plugins and SPADS core

1 if the message must not be processed by other plugins and SPADS core (this prevents logging)

onReloadConf($self,$keepSettings)

This callback is called each time the SPADS configuration is reloaded.

$keepSettings is a boolean parameter indicating if current settings must be kept.

This callback must return:

0 if an error occured while reloading the plugin configuration

1 if the plugin configuration has been reloaded correctly

onSettingChange($self,$settingName,$oldValue,$newValue)

This callback is called each time a setting of the plugin configuration is changed (using !plugin <pluginName> set ... command).

$settingName is the name of the updated setting

$oldValue is the previous value of the setting

$newValue is the new value of the setting

onSpringStart($self,$springPid)

This callback is called each time a Spring process is launched to host a game.

$springPid is the PID of the Spring process that has just been launched.

onSpringStop($self,$springPid)

This callback is called each time the Spring process ends.

$springPid is the PID of the Spring process that just ended.

onUnload($self,$context)

This callback is called when the plugin is unloaded. If the plugin has added handlers for SPADS command, lobby commands, or Spring commands, then they must be removed here. If the plugin has added timers or forked process callbacks, they should also be removed here. If the plugin handles persistent data, then these data must be serialized and written to persistent storage here.

The $context parameter is a string which indicates in which context the callback has been called: "exiting" means the plugin is being unloaded because SPADS is exiting, "restarting" means the plugin is being unloaded because SPADS is restarting, "unload" means the plugin is being unloaded manually using !plugin <pluginName> unload command, "reload" means the plugin is being reloaded manually using !plugin <pluginName> reload command.

onVoteRequest($self,$source,$user,\@command,\%remainingVoters)

This callback is called each time a vote is requested by a player.

$source indicates the way the vote has been requested ("pv": private lobby message, "battle": battle lobby message, "chan": master lobby channel message, "game": in game message)

$user is the name of the user requesting the vote

\@command is an array reference containing the command for which a vote is requested

\%remainingVoters is a reference to a hash containing the players allowed to vote. This hash is indexed by player names. Perl plugins can filter these players by removing the corresponding entries from the hash directly, but Python plugins must use the alternate method based on the return value described below.

This callback must return 0 to prevent the vote call from happening, or 1 to allow it without changing the remaining voters list, or an array reference containing the player names that should be removed from the remaining voters list.

onVoteStart($self,$user,\@command)

This callback is called each time a new vote poll is started.

$user is the name of the user who started the vote poll

\@command is an array reference containing the command for which a vote is started

onVoteStop($self,$voteResult)

This callback is called each time a vote poll is stoped.

$voteResult indicates the result of the vote: -1 (vote failed), 0 (vote cancelled), 1 (vote passed)

postSpadsCommand($self,$command,$source,$user,\@params,$commandResult)

This callback is called each time a SPADS command has been called.

$command is the name of the command (without the parameters)

$source indicates the way the command has been called ("pv": private lobby message, "battle": battle lobby message, "chan": master lobby channel message, "game": in game message)

$user is the name of the user who called the command

\@params is a reference to an array containing the parameters of the command

$commandResult indicates the result of the command (if it is defined and set to 0 then the command failed, in all other cases the command succeeded)

preGameCheck($self,$force,$checkOnly,$automatic)

This callback is called each time a game is going to be launched, to allow plugins to perform pre-game checks and prevent the game from starting if needed.

$force is 1 if the game is being launched using !forceStart command, 0 else

$checkOnly is 1 if the callback is being called in the context of a vote call, 0 else

$automatic is 1 if the game is being launched automatically through autoStart functionality, 0 else

The return value must be the reason for preventing the game from starting (for example "too many players for current map"), or 1 if no reason can be given, or undef to allow the game to start.

preSpadsCommand($self,$command,$source,$user,\@params)

This callback is called each time a SPADS command is called, just before it is actually executed. This callback is called after the commandRightsOverride callback.

$command is the name of the command (without the parameters)

$source indicates the way the command has been called ("pv": private lobby message, "battle": battle lobby message, "chan": master lobby channel message, "game": in game message)

$user is the name of the user who called the command

\@params is a reference to an array containing the parameters of the command

This callback must return 0 to prevent the command from being processed by other plugins and SPADS core, or 1 to allow it.

Customization callbacks

Following callbacks are called by SPADS during specific operations to allow plugins to customize features (more callbacks can be added on request):

addStartScriptTags($self,\%additionalData)

This callback is called when a Spring start script is generated, just before launching the game. It allows plugins to declare additional scrip tags which will be written in the start script.

\%additionalData is a reference to a hash which must be updated by Perl plugins by adding the desired keys/values. For example a Perl plugin can add a modoption named hiddenoption with value test like this: $additionalData{"game/modoptions/hiddenoption"}="test". For tags to be added in player sections, the special key playerData must be used. This special key must point to a hash associating each account ID to a hash containing the tags to add in the corresponding player section (subsections can be created by using nested hashes). For tags to be added in AI bot sections, the special key aiData must be used. This special key must point to a hash associating each AI bot name to a hash containing the tags to add in the corresponding AI bot section (subsections can be created by using nested hashes).

Note for Python plugins: As Python plugins cannot modify the data structures passed as parameters to the callbacks, an alternate way to implement this callback is offered. Instead of modifying the additionnalData dictionary directly, the callback can return a new dictionary containing the entries which must be added. For example a Python plugin can add a tag named CommanderLevel set to value 8 in the player section of the player whose account ID is 1234 like this: return {'playerData': { '1234': { 'CommanderLevel': 8 } } }

balanceBattle($self,\%players,\%bots,$clanMode,$nbTeams,$teamSize)

This callback is called each time SPADS needs to balance a battle and evaluate the resulting balance quality. It allows plugins to replace the built-in balance algorithm.

\%players is a reference to a hash containing the players in the battle lobby. This hash is indexed by player names, and the values are references to a hash containing player data. For balancing, you should only need to access the players skill as follows: $players->{<playerName>}->{skill}

\%bots is a reference to a hash containing the bots in the battle lobby. This hash has the exact same structure as \%players.

$clanMode is the current clan mode which must be applied to the balance. Clan modes are specified here. <maxUnbalance> thresholds are automatically managed by SPADS, plugins don't need to handle them. So basically, plugins only need to check if tag and/or pref clan modes are enabled and apply them to their balance algorithm.

$nbTeams and $teamSize are the target battle structue computed by SPADS. The number of entities to balance is the number of entries in \%players + number of entries in \%bots. The number of entities to balance is always > $nbTeams*($teamSize-1), and <= $nbTeams*$teamSize.

If the plugin is unable to balance the battle, it must not update \%players and \%bots. The callback must return undef or a negative value so that SPADS knows it has to use another plugin or the internal balance algorithm instead.

If the plugin is able to balance the battle, it can use two methods to transmit the desired balance to SPADS (Python plugins can only use the second method):

The first method consists in updating directly the \%players and \%bots hash references with the team and id information. Assigned player teams must be written in $players->{<playerName>}->{battleStatus}->{team}, and assigned player ids must be written in $players->{<playerName>}->{battleStatus}->{id}. The \%bots hash reference works the same way. The return value is the unbalance indicator, defined as follows: standardDeviationOfTeamSkills * 100 / averageTeamSkill.

The second method consists in returning an array reference containing the balance information instead of directly editing the \%players and \%bots parameters. The returned array must contain 3 items: the unbalance indicator (as defined in first method description above), the player assignation hash and the bot assignation hash. The player assignation hash and the bot assignation hash have exactly the same structure: the keys are the player/bot names and the values are hashes containing team and id items with the corresponding values for the balanced battle.

canBalanceNow($self)

This callback allows plugins to delay the battle balance operation. It is called each time a battle balance operation is required (either automatic if autoBalance is enabled, either manual if !balance command is called). If the plugin is ready for balance, it must return 1. Else, it can delay the operation by returning 0 (the balance algorithm won't be launched as long as the plugin didn't return 1).

changeUserAccessLevel($self,$userName,\%userData,$isAuthenticated,$currentAccessLevel)

This callback is called by SPADS each time it needs to get the access level of a user. It allows plugins to overwrite this level. Don't call the getUserAccessLevel($user) function from this callback, or the program will be locked in recursive loop! (and it would give you the same value as $currentAccessLevel anyway).

\%userData is a reference to a hash containing the lobby data of the user

$isAuthenticated indicates if the user has been authenticated (0: lobby server in LAN mode and not authenticated at autohost level, 1: authenticated by lobby server only, 2: authenticated by autohost)

The callback must return the new access level value if changed, or undef if not changed.

commandRightsOverride($self,$lowerCaseCommandName,\@command,$source,$user,$effectiveUserAccessLevel,$userAccessLevel,\%requiredAccessLevels)

This callback is called each time a SPADS command is called by a user, just before checking the user access level requirements. It allows plugins to bypass this check and implement their own logic to allow or disallow the command execution. This callback is called before the preSpadsCommand callback, which can still be used to prevent the command execution later in the workflow even though the commandRightsOverride callback allowed it.

$lowerCaseCommandName is the name of the command being called (in lowercase)

\@command is an array reference containing the full command being called

$source indicates the way the command was called ("pv": private lobby message, "battle": battle lobby message, "chan": master lobby channel message, "game": in game message)

$user is the name of the user who called the command

$effectiveUserAccessLevel is the effective access level of the user who called the command (taking boss mode into account if applicable)

$userAccessLevel is the original access level of the user who called the command (ignoring boss mode)

\%requiredAccessLevels is a reference to a hash containing the access levels normally required to call the command in current context. The hash keys are directLevel for the access level required to call the command directly, and voteLevel for the access level required to call a vote for the command. The values can be undefined or empty string when there is no access level associated (i.e. the command cannot be called), or the corresponding required access level value (integer).

The return value of the callback determines whether the default access level requirements for the command must be bypassed. If an undefined value is returned, the default behavior is applied (no bypass of access level requirements). If a true value is returned, the access level requirements are bypassed and the user is allowed to call the command directly. If a false value is returned, the user is denied the right to call the command directly, regardless of his access level.

delayShutdown($self)

This callback is called by SPADS each time it needs to quit or restart. It allows plugins to delay the shutdown operation, which can be useful to prevent SPADS from exiting before a process forked by the plugin ends for example.

The callback must return a false value if SPADS can quit right now, or a true value if SPADS must wait before exiting.

filterRotationMaps($self,\@rotationMaps)

This callback is called by SPADS each time a new map must be picked up for rotation. It allows plugins to remove some maps from the rotation maps list just before the new map is picked up.

\@rotationMaps is a reference to an array containing the names of the maps currently allowed for rotation.

The callback must return a reference to a new array containing the filtered map names.

fixColors($self,\%players,\%bots,\%battleStructure)

This callback is called each time SPADS needs to fix the teams colors. It allows plugins to replace the built-in color fixing algorithm.

\%players is a reference to a hash containing the players currently in the battle lobby. This hash is indexed by player names, and the values are references to hashes containing following player data: team (team number), id (id number) and color (current color configured in lobby, i.e. a hash containing keys "red", "green", "blue" and whose values are numbers between 0 and 255 included).

\%bots is a reference to a hash containing the bots currently in the battle lobby. This hash has the exact same structure as \%players.

\%battleStructure is a reference to a hash containing data concerning the battle structure. This parameter is provided to plugins for ease of use but actually these data are redundant with the data already provided in the two previous parameters (the %players and %bots hashes), they are just organized in a different way. The %battleStructure hash is indexed by team numbers. For each team number, the associated value is a reference to a hash indexed by the ID numbers contained in the team. For each ID number, the associated value is a reference to a hash containing the two following keys: players (the associated value is a reference to an array containing the names of the players belonging to this ID) and bots (the associated value is a reference to an array containing the names of the AI bots belonging to this ID).

If the plugin is unable to fix colors, then it must return undef so that SPADS knows it has to use another plugin or the internal color fixing algorithm instead.

If the plugin is able to fix the players and AI bots colors, then it must return a reference to a hash containing all colors assignations, indexed by ID numbers. The keys must be the ID numbers and the values are references to hash whose keys are "red", "green" and "blue" and values are the corresponding RGB values (between 0 and 255 included) of the color assigned to the ID.

setMapStartBoxes($self,\@boxes,$mapName,$nbTeams,$nbExtraBox)

This callback allows plugins to set map start boxes (for "Choose in game" start position type).

\@boxes is a reference to an array containing the start boxes definitions. A start box definition is a string containing the box coordinates separated by spaces, in following order: left, top, right, bottom (0,0 is top left corner and 200,200 is bottom right corner). If the array already contains box definitions, it means SPADS already knows boxes for this map.

$mapName is the name of the map for which start boxes are requested

$nbTeams is the current number of teams configured (at least this number of start boxes must be provided)

$nbExtraBox is the number of extra box required. Usually this is 0, unless a special game mode is enabled such as King Of The Hill.

If the plugin isn't able or doesn't need to provide/override start boxes, it must not update the \@boxes array. It must return 0 so that SPADS knows it has to check other plugins for possible start boxes.

If the plugin needs to provide/override start boxes, it can use two methods to transmit the start box definitions (Python plugins can only use the second method):

The first method consists in replacing the \@boxes array content directly with the new desired start box definitions. If other plugins should be allowed to replace the start box definitions, the callback must return 0, else it must return 1.

The second method consists in returning an array reference containing the new start box definitions instead of directly updating the \@boxes parameter. The returned array must contain 2 items: the normal return value as first item (0 to allow other plugins to replace the start boxes, or 1 else), and an array reference containg the new start box definitions as second item.

setVoteMsg($self,$reqYesVotes,$maxReqYesVotes,$reqNoVotes,$maxReqNoVotes,$nbRequiredManualVotes)

This callback allows plugins to customize the vote status messages.

$reqYesVotes is the total number of "yes" votes required for vote to pass (if away-voters don't vote).

$reqNoVotes is the total number of "no" votes required for vote to fail (if away-voters don't vote).

$maxReqYesVotes is the maximum total number of "yes" votes required for vote to pass (if all away-voters come back and vote).

$maxReqNoVotes is the maximum total number of "no" votes required for vote to fail (if all away-voters come back and vote).

$nbRequiredManualVotes is the minimum number of manual votes required for vote to be taken into account.

The callback must return a list containing following 2 elements: the lobby vote message, and the in-game vote message (undef values can be used to keep default messages).

updateCmdAliases($self,\%aliases)

This callback allows plugins to add new SPADS command aliases by adding new entries in the \%aliases hash reference. This hash is indexed by alias names and the values are references to an array containing the associated command. For example, a Perl plugin can add an alias "!cvmap ..." for "!callVote map ..." like this: $aliases->{cvmap}=['callVote','map']

"%<N>%" can be used as placeholders for original alias command parameters. For example, a Perl plugin can add an alias "!iprank <playerName>" for "!chrank <playerName> ip" like this: $aliases->{iprank}=['chrank','%1%','ip']

Note for Python plugins: As Python plugins cannot modify the data structures passed as parameters to the callbacks, an alternate way to implement this callback is offered. Instead of modifying the aliases dictionary directly, the callback can return a new dictionary containing the alias entries which must be added.

updatePlayerSkill($self,\%playerSkill,$accountId,$modName,$gameType)

This callback is called by SPADS each time it needs to get or update the skill of a player (on battle join, on game type change...). This allows plugins to replace the built-in skill estimations (rank, TrueSkill...) with custom skill estimations (ELO, Glicko ...).

\%playerSkill is a reference to a hash containing the skill data of the player. A Perl plugin can update the skill entry as follows: $playerSkill->{skill}=<skillValue>. The skill uncertainty can also be updated by plugins, by updating the sigma entry as follows: $playerSkill->{sigma}=<skillUncertaintyValue>.

$accountId is the account ID of the player for whom skill value is requested.

$modName is the currently hosted MOD (example: "Balanced Annihilation V7.72")

$gameType is the current game type ("Duel", "Team", "FFA" or "TeamFFA")

The return value is the skill update status: 0 (skill not updated by the plugin), 1 (skill updated by the plugin), 2 (skill updated by the plugin in degraded mode)

Note for Python plugins: As Python plugins cannot modify the data structures passed as parameters to the callbacks, an alternate way to implement this callback is offered. Instead of modifying the playerSkill dictionary directly, the callback can return a list containing the normal return value as first item (described above), the new skill value as second item, and optionally the new skill uncertainty value as third item.

updateGameStatusInfo($self,\%playerStatus,$accessLevel)

This callback is called by SPADS for each player in game when the !status command is called, to allow plugins to update and/or add data which will be presented to the user issuing the command.

\%playerStatus is a reference to the hash containing current player status data. A Perl plugin can update existing data or add new data in this hash. For example: $playerStatus->{myPluginData}=<myPluginValue>

$accessLevel is the autohost access level of the user issuing the !status command.

The return value must be a reference to an array containing the names of the status information updated or added by the plugin.

Note for Python plugins: As Python plugins cannot modify the data structures passed as parameters to the callbacks, an alternate way to implement this callback is offered. Instead of modifying the playerStatus dictionary directly, the callback can return a new dictionary containing the data to add/modify in the playerStatus dictionary.

updateStatusInfo($self,\%playerStatus,$accountId,$modName,$gameType,$accessLevel)

This callback is called by SPADS for each player in the battle lobby when the !status command is called, to allow plugins to update and/or add data which will be presented to the user issuing the command.

\%playerStatus is a reference to the hash containing current player status data. A Perl plugin can update existing data or add new data in this hash. For example: $playerStatus->{myPluginData}=<myPluginValue>

$accountId is the account ID of the player for whom status data update is requested.

$modName is the currently hosted MOD (example: "Balanced Annihilation V7.72")

$gameType is the current game type ("Duel", "Team", "FFA" or "TeamFFA")

$accessLevel is the autohost access level of the user issuing the !status command.

The return value must be a reference to an array containing the names of the status information updated or added by the plugin.

Note for Python plugins: As Python plugins cannot modify the data structures passed as parameters to the callbacks, an alternate way to implement this callback is offered. Instead of modifying the playerStatus dictionary directly, the callback can return a new dictionary containing the data to add/modify in the playerStatus dictionary.

Event loop callback

SPADS uses the asynchronous programming paradigm, so it is based on a main event loop. The following callback is called during each iteration of this event loop:

eventLoop($self)

Warning: this callback is called very frequently (during each iteration of SPADS main event loop), so performing complex operations here can be very intensive on the CPU. It is recommended to use timers (addTimer/removeTimer functions) instead for all time related operations (timeouts, scheduled actions, regular serialization of persistent data to avoid data loss...). This callback shouldn't be blocking, otherwise SPADS may become unstable.

API FUNCTIONS

The API functions are implemented by SPADS core and can be called by SPADS plugins (directly from Perl plugins, or via spads.[...] from Python plugins).

Accessors

getBosses()

This accessor returns a reference to the hash containing the names of the bosses in the battle lobby (if the hash is empty, the boss mode is disabled).

getConfMacros()

This accessor returns a reference to the hash containing the configuration macros used to (re)start SPADS.

getCurrentVote()

This accessor returns a reference to a hash containing information regarding votes.

If there is no vote in progress and the last vote succeeded, then the returned hash is always empty.

If there is no vote in progress and the last vote failed, then the content of the returned hash depends on the delay since the last vote ended. If the delay is greater than the reCallVoteDelay, then the returned hash is empty, else it contains the two following keys:

If there is a vote in progress, then the returned hash contains following keys:

Note: An easy way to check if a vote is currently in progress consists in calling getCurrentVote() and checking if the returned hash contains the command key. If the hash contains the command key then it means a vote is in progress, else it means no vote is in progress.

getLobbyInterface()

This accessor returns the instance of the SpringLobbyInterface module used by SPADS.

Following methods, called on the SpringLobbyInterface object, can be useful to plugins for accessing various lobby data:

getLobbyState()

This accessor returns an integer describing the current lobby state. The corresponding constants are provided to ease lobby state handling/comparisons, as listed below:

Perl plugins can use these constants directly in the plugin code, like this for example:

if(getLobbyState() >= LOBBY_STATE_CONNECTED) {
  slog("SPADS is connected to lobby server",3);
}

Python plugins must call them as SPADS functions, like this for example:

if spads.getLobbyState() >= spads.LOBBY_STATE_CONNECTED():
    spads.slog("SPADS is connected to lobby server",3)
getPluginList()

This accessor returns a reference to an array containing the names of the plugins currently loaded (in load order).

getRunningBattle()

This accessor returns a reference to a hash representing the state of the battle lobby hosted by SPADS when the game currently running was launched. This is useful to find the actual characteristics of the currently running game (battle structure, settings...), because things might have changed in the battle lobby since the game started (players joined/left, map changed...) so the current battle lobby data aren't necessarily consistent with the game currently running.

If no game is in progress, this hash is empty.

If a game is in progress, the hash contains the same data as the data returned by the getBattle() and getBattles() methods of the SpringLobbyInterface object (see getLobbyInterface() accessor) when the game was launched. Concerning the getBattles() data, only the data related to the battle lobby hosted by SPADS are included in the hash.

getSpadsConf()
getSpadsConfFull()
getSpringInterface()
getSpringPid()
getSpringServerType()
getTimestamps()
getUserPref($userName,$prefName)

This accessor returns the current value of a user's preference.

Plugin management

getPlugin($pluginName=caller())

This function returns the plugin object matching the plugin name given as parameter $pluginName. If no parameter is provided, the plugin name of the plugin calling the function is used.

getPluginConf($pluginName=caller())

This function returns the plugin configuration for the plugin named $pluginName. If no parameter is provided, the plugin name of the plugin calling the function is used. The return value is a reference to a hash using plugin settings names as keys and plugin settings values as values.

Handlers management

addLobbyCommandHandler(\%handlers,$priority=caller(),$isPreCallback)

This function allows plugins to set up their own handlers for Spring lobby commands received by SPADS from lobby server.

\%handlers is a reference to a hash which contains the handlers to be added: each entry associates a lobby command (in uppercase) to a handler function implemented by the plugin. For example, with { JOINBATTLEREQUEST => \&hLobbyJoinBattleRequest }, the plugin has to implement the function hLobbyJoinBattleRequest. The parameters passed to the handlers are the command tokens: the command name followed by command parameters. Refer to Spring lobby protocol specifications for more information.

$priority is the priority of the handlers. Lowest priority number actually means higher priority. If not provided, the plugin name is used as priority, which means it is executed after handlers having priority < 1000, and before handlers having priority > 1000. Usually you don't need to provide priority, unless you use data managed by other handlers.

$isPreCallback specifies whether the command handlers must be called before or after the lobby interface module handlers. If this parameter is set to a true value, the command handlers will be called before the lobby interface module handlers. If this parameter is not provided or set to a false value, the command handlers will be called after the lobby interface module handlers.

Note: As all lobby command handlers are automatically removed by SPADS when it is disconnected from the lobby server (due to network problems for example), plugins should always re-set up their lobby command handlers each time SPADS successfully reconnects. This can be done automatically by doing the addLobbyCommandHandler call in the onLobbySynchronized event-based callback (for plugins that don't need to process the commands sent by the lobby server during the initial lobby state synchronization phase) or in the onLobbyLoggedIn event-based callback (for plugins that need to process the commands sent by the lobby server during the initial lobby state synchronization phase).

addSpadsCommandHandler(\%handlers,$replace=0)

This function allows plugins to add or replace SPADS command handlers.

\%handlers is a reference to a hash which contains the handlers to be added or replaced: each entry associates a SPADS command to a handler function implemented by the plugin. For example, with { myCommand => \&hSpadsMyCommand }, the plugin has to implement the function hSpadsMyCommand. The parameters passed to the handlers are: $source,$userName,\@params,$checkOnly.

$source indicates the way the command has been called ("pv": private lobby message, "battle": battle lobby message, "chan": master lobby channel message, "game": in game message)

$userName is the name of the user issuing the command

\@params is a reference to an array containing the command parameters

$checkOnly indicates that the command must not be executed but only checked for consistency (this mode is used for !callVote command)

If the command cannot be executed (invalid syntax ...) the handler must return 0. If the command is correct but requires automatic parameter adjustments (automatic case correction or name completion for example), a reference to an array containing the adjusted command must be returned. If it can be executed directly without any adjustment, 1 must be returned.

$replace indicates if the handlers provided can replace existing ones: 0 means add handlers only if there is no handler for the given command (default), 1 means add or replace if existing.

addSpringCommandHandler(\%handlers,$priority=caller())

This function allows plugins to set up their own handlers for Spring AutoHost commands received by SPADS from Spring server.

\%handlers is a reference to a hash which contains the handlers to be added: each entry associates a Spring AutoHost command to a handler function implemented by the plugin. The Spring AutoHost command names must match the values of %commandCodes defined in SpringAutoHostInterface.pm. For example, with { SERVER_STARTED => \&hSpringServerStarted }, the plugin has to implement the function hSpringServerStarted. The parameters passed to the handlers are the command tokens: the command name followed by command parameters. Refer to Spring autohost protocol specifications (from source comments) for more information.

$priority is the priority of the handlers. Lowest priority number actually means higher priority. If not provided, the plugin name is used as priority, which means it is executed after handlers having priority < 1000, and before handlers having priority > 1000. Usually you don't need to provide priority, unless you use data managed by other handlers.

removeLobbyCommandHandler(\@commands,$priority=caller(),$isPreCallback)

This function must be called by plugins which added lobby command handlers previously using addLobbyCommandHandler function, when these handlers are no longer required (for example in the onUnload callback, when the plugin is unloaded).

\@commands is a reference to an array containing the lobby command names (in uppercase) for which the handlers must be removed.

$priority is the priority of the handlers to remove. It must be the same as the priority used when adding the handlers. If not provided, the plugin name is used as priority. Usually you don't need to provide priority, unless you use data managed by other handlers.

$isPreCallback specifies the type of command handlers to remove (must match the value used for the addLobbyCommandHandler function call for these handlers)

removeSpadsCommandHandler(\@commands)

This function must be called by plugins which added SPADS command handlers previously using addSpadsCommandHandler function, when these handlers are no longer required (for example in the onUnload callback, when the plugin is unloaded).

\@commands is a reference to an array containing the SPADS command names (in uppercase) for which the handlers must be removed.

removeSpringCommandHandler(\@commands,$priority=caller())

This function must be called by plugins which added Spring AutoHost command handlers previously using addSpringCommandHandler function, when these handlers are no longer required (for example in the onUnload callback, when the plugin is unloaded).

\@commands is a reference to an array containing the Spring AutoHost command names for which the handlers must be removed.

$priority is the priority of the handlers to remove. It must be the same as the priority used when adding the handlers. If not provided, the plugin name is used as priority. Usually you don't need to provide priority, unless you use data managed by other handlers.

SPADS operations

applyPreset($presetName)
cancelCloseBattle()
cancelQuit($reason)
closeBattle($reason,$silentMode=0)

This function makes SPADS close current battle lobby.

The $reason parameter must be a string containing the reason for closing the battle lobby.

The $silentMode parameter is an optional boolean parameter specifying if the broadcast message (which is normally sent when the battle lobby is closed) must be prevented.

getUserAccessLevel($user)
loadArchives()
queueLobbyCommand(\@lobbyCommand)
quit($type,$reason,$exitCode=0)
rehost($reason)
slog($message,$level)

This function uses SPADS logging system to write a message in main SPADS log file.

$message is the log message

$level is the log level of the message: 0 (critical), 1 (error), 2 (warning), 3 (notice), 4 (info), 5 (debug)

updateSetting($type,$name,$value)

This function updates current SPADS configuration in memory by changing the value of a setting and applying it immediatly. This function does not modify configuration files on disk. The new value provided by the plugin is not checked: the plugin is reponsible for providing only correct values.

$type is the type of setting to update ("set" for preset setting, "hSet" for hosting setting, or "bSet" for battle setting)

$name is the name of the setting to update

$value is the new value of the setting

AutoHost messaging system

answer($message)

This function must only be called from a SPADS command handler. It sends a message to the user who issued the command, using the same communication channel that has been used to send the command to SPADS: a private message, a message in battle lobby, a message in game or a message in a lobby chat channel.

broadcastMsg($message)

This function sends a message simultaneously in the battle lobby (if open), in the game (if running) and in the broadcast channels (as configured by the broadcastChannels global setting).

invalidSyntax($user,$commandName,$cause='')

This function must only be called from a SPADS command handler. It triggers the default SPADS behavior when a user calls a command using invalid syntax, as detailed below:

It answers to the user (using the same communication channel as the one used to call the command) with a message indicating that the command usage is invalid. This message includes a detailed reason if provided as $cause parameter. If the user is not in game, it also automatically sends the corresponding command help in a private message.

$user is the user who called the SPADS command

$commandName is the name of the SPADS command which was called with invalid syntax

$cause is the detailed reason explaining why the command usage is invalid (optional)

sayBattle($message)

This functions sends a message in the battle lobby (if open).

sayBattleAndGame($message)

This function sends a message simultaneously in the battle lobby (if open) and in the game (if running).

sayBattleUser($user,$message)

This function sends a message in the battle lobby (if open) to a specific user: only this user will receive the message, but for this user the message will appear in the battle lobby instead of being a private chat message.

sayChan($channel,$message)

This functions sends a message in a specific lobby chat channel (if already joined by SPADS).

sayGame($message)

This functions sends a message in the game (if running).

sayPrivate($user,$message)

This function sends a private message to a user.

Time utils

getDirModifTime($directory)
secToDayAge($seconds)
secToTime($seconds)

Data formatting

formatArray
formatFloat($float)
formatInteger($integer)
formatList

Forking processes

createDetachedProcess($applicationPath,\@commandParams,$workingDirectory,$createNewConsole)

This function allows plugins to create a new detached/daemon process, which can keep running even if the main SPADS process exits. It returns 1 if the new process has correctly been created, 0 else.

$applicationPath is the absolute path of the application that will be executed in the detached process.

\@commandParams is a reference to an array containing the parameters passed to the application.

$workingDirectory is the working directory for the detached process.

$createNewConsole indicates if a console must be created for the detached process: 0 means no console is created for the process (daemon mode) 1 means a new console will be created for the detached process (this mode is only available on Windows system)

forkProcess(\&processFunction,\&endProcessCallback,$preventQueuing=1)

This function allows plugins to fork a process from main SPADS process, for parallel processing. In scalar context it returns the PID of the forked process on success, -1 if the fork request has been queued, or 0 if the fork request failed. In list context it returns the PID as first parameter and a handle as second parameter. This handle can be passed as parameter to the removeProcessCallback function to remove the endProcessCallback callback.

Note: this function cannot be used by Python plugins on Windows system (refer to section PYTHON SPECIFIC NOTES - Windows limitations for details).

\&processFunction is a reference to a function containing the code to be executed in the forked process (no parameter is passed to this function). This function can call exit to end the forked process with a specific exit code. If it returns without calling exit, then the exit code 0 will be used.

\&endProcessCallback is a reference to a function containing the code to be executed in main SPADS process, once the forked process exited. Following parameters are passed to this function: $exitCode (exit code of the forked process), $signalNb (signal number responsible for forked process termination if any), $hasCoreDump (boolean flag indicating if a core dump occured in the forked process), $pid (PID of the forked process that just exited).

$preventQueuing is an optional boolean parameter (default value: 1) indicating if the fork request must not be queued (i.e., the fork request will fail instead of being queued if too many forked processes are already running)

forkCall(\&processFunction,\&endProcessCallback,$preventQueuing=0)

This function allows plugins to call a function asynchronously and retrieve the data returned by this function (this is done internally by forking a process to execute the function and use a socketpair to transmit the result back to the parent process). In scalar context it returns the PID of the forked process on success, -1 if the fork request has been queued, or 0 on error. In list context it returns the PID as first parameter and a handle as second parameter. This handle can be passed as parameter to the removeProcessCallback function to remove the endProcessCallback callback.

Note: this function cannot be used by Python plugins on Windows system (refer to section PYTHON SPECIFIC NOTES - Windows limitations for details).

\&processFunction is a reference to a function containing the code to be executed in the forked process (no parameter is passed to this function). This function must not call exit, it should use return instead to return values (scalars, arrays, hashes...) that will be passed to the callback.

\&endProcessCallback is a reference to a function containing the code to be executed in main SPADS process, once the forked function call (\&processFunction) returned. The values returned by the forked function call will be passed as parameters to this callback.

$preventQueuing is an optional boolean parameter (default value: 0) indicating if the fork request must not be queued (i.e., the fork request will fail instead of being queued if too many forked processes are already running)

removeProcessCallback($processHandle)

This function can be used by plugins to remove the callbacks on forked processes added beforehand with the forkProcess and forkCall functions, if the callback hasn't been called yet (i.e. the corresponding forked process didn't exit yet). It returns 1 if the callback could be removed, 0 else.

$processHandle is an internal process handle, returned as second return value by the forkProcess and forkCall functions.

Timers management

addTimer($name,$delay,$interval,\&callback)

This function allows plugins to add timed events (timers) in order to delay and/or repeat code execution. It returns 1 if the timer has correctly been added, 0 else.

$name is a unique name given by the plugin for this timer.

$delay is the delay in seconds before executing the \&callback function.

$interval is the interval in seconds between each execution of the \&callback function. If this value is set to 0, the \&callback function will be executed only once.

\&callback is a reference to a function containing the code to be executed when the timed event occurs. This callback must not be blocking, otherwise SPADS may become unstable.

removeTimer($name)

This function must be used by plugins to remove timed events (timers) added previously with the addTimer function. It returns 1 if the timer could be removed, 0 else. Note: Non-repeating timers (i.e. having null interval value) are automatically removed once they are triggered.

$name is the unique timer name given by the plugin when the timer was added using the addTimer function.

Sockets management

addSocket(\$socketObject,\&readCallback)

This function allows plugins to add sockets to SPADS asynchronous network system. It returns 1 if the socket has correctly been added, 0 else.

Note: this function cannot be used by Python plugins on Windows system (refer to section PYTHON SPECIFIC NOTES - Windows limitations for details).

\$socketObject is a reference to a socket object created by the plugin

\&readCallback is a reference to a plugin function containing the code to read the data received on the socket. This function will be called automatically every time data are received on the socket, with the socket object as unique parameter. It must not block, and only unbuffered functions must be used to read data from the socket (sysread() or recv() for example).

removeSocket(\$socketObject)

This function allows plugins to remove sockets from SPADS asynchronous network system. It returns 1 if the socket has correctly been removed, 0 else.

\$socketObject is a reference to a socket object previously added by the plugin

Python specific

fix_string(spads_string[,...])

This function allows Python plugins to automatically convert byte strings to normal strings if needed. The function takes any number of byte strings or normal strings as parameters, and returns them converted to normal strings if needed (parameters which are already normal strings are returned without any modification). Refer to section PYTHON SPECIFIC NOTES - Perl strings conversions for the use case of this function. Here is an example of usage:

 import perl
 spads=perl.ExamplePlugin
 
 [...]
 
 class ExamplePlugin:

 [...]
 
     def onPrivateMsg(self,userName,message):
         (userName,message)=spads.fix_string(userName,message)

 [...]
 
 def hMyCommand(source,user,params,checkOnly):
     user=spads.fix_string(user)
     for i in range(len(params)):
         params[i]=spads.fix_string(params[i])
get_flag(flag_name)

This function allows Python plugins to retrieve indicators (boolean flags) regarding the behavior of the plugin API and the availability of functionalities on current system.

Currently 3 flags are supported:

Here is an example of usage:

 import perl
 spads=perl.ExamplePlugin
 
 [...]
 
     if spads.get_flag('can_add_socket'):
         spads.addSocket(socket,readSocketCallback)
     else:
         spads.slog("This plugin requires the addSocket function",1)
         return False

SHARED DATA

Constants

Following constants are directly accessible from Perl plugin modules (accessible via perl.eval('$::SpadsPluginApi::...') from Python plugin modules):

$spadsVersion
$spadsDir

Variables

Following variables are directly accessible from Perl plugin modules (accessible via perl.eval('...') from Python plugin modules), but it is strongly recommended to use the accessors from the API instead:

$::autohost
%::conf
%::confMacros
%::currentVote
$::lobby
$::lobbyState
$::p_runningBattle
%::plugins
@::pluginsOrder
$::spads
%::spadsCmdHandlers
$::springPid
$::springServerType
%::timestamps
%::bosses

SEE ALSO

SPADS plugin development tutorials (Perl)

SPADS plugin development tutorials (Python)

Commented SPADS plugin templates (Perl): Simple plugin, Configurable plugin, New command plugin

Commented SPADS plugin templates (Python): Simple plugin, Configurable plugin, New command plugin

SPADS documentation, especially regarding plugins management: pluginsDir setting, autoLoadPlugins setting, plugin command

Spring lobby protocol specifications

Spring autohost protocol specifications (from source comments)

Introduction to Perl

Inline::Python Perl module (the bridge between Perl and Python): documentation from meta::cpan, GitHub repository

COPYRIGHT

Copyright (C) 2013-2024 Yann Riou <yaribzh@gmail.com>

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.