Introduction to the Plugin SDK
One of the major new features available in the 0.4 server is the plugin SDK. Any user can now use an official SDK header to create plugins that can be used to interact with the server, clients, game world and other plugins.
The current plugin SDK can be found here:
https://gist.github.com/nsgomez/e0b525ed660db7f83b56
https://bitbucket.org/stormeus/0.4-squirrel/src/master/VCMP.h
Creating a Loadable Plugin
The VC:MP server expects the existence of a special exported function, VcmpPluginInit, to exist in a plugin in order to be able to load one. As part of this function, the server will pass a set of callable functions, a structure for the plugin to set the callbacks it accepts, and a structure for the plugin to set information about itself.
The structure of VcmpPluginInit is as follows:
#ifdef WIN32
#define EXPORT __declspec(dllexport)
#else
#define EXPORT
#endif
extern "C" EXPORT unsigned int VcmpPluginInit( PluginFuncs* pluginFuncs, PluginCallbacks* pluginCalls, PluginInfo* pluginInfo )
{
return 1;
}
- pluginFuncs is the PluginFuncs struct from the server header, which can be used to call any function available through the plugin SDK.
- pluginCalls is a struct of PluginCallbacks. pluginCalls essentially starts off empty; your plugin must provide its own callbacks and set them in the struct in order for them to be called, and you must use the same pointer to the struct provided.
- pluginInfo is a struct of PluginInfo (from the SDK) that, again, is empty at first. You can set your plugin's version and name (max 32 characters) through it, but you must use the same pointer to the struct.
Setting a Callback
To receive callbacks from the server, you need to create a function in the same format as the defined type of the callback:
typedef int (*SDK_OnInitServer) (void);
typedef void (*SDK_OnShutdownServer) (void);
typedef void (*SDK_OnFrame) (float fElapsedTime);
typedef void (*SDK_OnPlayerConnect) (int nPlayerId);
typedef void (*SDK_OnPlayerDisconnect) (int nPlayerId, int nReason);
typedef void (*SDK_OnPlayerBeginTyping) (int nPlayerId);
typedef void (*SDK_OnPlayerEndTyping) (int nPlayerId);
typedef int (*SDK_OnPlayerRequestClass) (int nPlayerId, int nOffset);
typedef int (*SDK_OnPlayerRequestSpawn) (int nPlayerId);
typedef void (*SDK_OnPlayerSpawn) (int nPlayerId);
typedef void (*SDK_OnPlayerDeath) (int nPlayerId, int nKillerId, int nReason, int nBodyPart);
typedef void (*SDK_OnPlayerUpdate) (int nPlayerId, int nUpdateType);
typedef int (*SDK_OnPlayerRequestEnter) (int nPlayerId, int nVehicleId, int nSlotId);
typedef void (*SDK_OnPlayerEnterVehicle) (int nPlayerId, int nVehicleId, int nSlotId);
typedef void (*SDK_OnPlayerExitVehicle) (int nPlayerId, int nVehicleId);
typedef int (*SDK_OnPickupClaimPicked) (int nPickupId, int nPlayerId);
typedef void (*SDK_OnPickupPickedUp) (int nPickupId, int nPlayerId);
typedef void (*SDK_OnPickupRespawn) (int nPickupId);
typedef void (*SDK_OnVehicleUpdate) (int nVehicleId, int nUpdateType);
typedef void (*SDK_OnVehicleExplode) (int nVehicleId);
typedef void (*SDK_OnVehicleRespawn) (int nVehicleId);
typedef void (*SDK_OnObjectShot) (int nObjectId, int nPlayerId, int nWeapon);
typedef void (*SDK_OnObjectBump) (int nObjectId, int nPlayerId);
typedef int (*SDK_OnPublicMessage) (int nPlayerId, const char* pszText);
typedef int (*SDK_OnCommandMessage) (int nPlayerId, const char* pszText);
typedef int (*SDK_OnPrivateMessage) (int nPlayerId, int nTargetId, const char* pszText);
typedef int (*SDK_OnInternalCommand) (unsigned int uCmdType, const char* pszText);
typedef int (*SDK_OnLoginAttempt) (char* pszPlayerName, const char* pszUserPassword, const char* pszIpAddress);
typedef void (*SDK_OnEntityPoolChange) (int nEntityType, int nEntityId, unsigned int bDeleted);
typedef void (*SDK_OnKeyBindDown) (int nPlayerId, int nBindId);
typedef void (*SDK_OnKeyBindUp) (int nPlayerId, int nBindId);
typedef void (*SDK_OnPlayerAwayChange) (int nPlayerId, unsigned int bNewStatus);
typedef void (*SDK_OnPlayerSpectate) (int nPlayerId, int nTargetId);
typedef void (*SDK_OnPlayerCrashReport) (int nPlayerId, const char* pszReport);
typedef void (*SDK_OnServerPerformanceReport) (int nNumStats, const char** ppszDescription, unsigned long long* pnMillisecsSpent);
typedef void (*SDK_OnPlayerNameChange) (int nPlayerId, const char* pszOldName, const char* pszNewName);
typedef void (*SDK_OnPlayerStateChange) (int nPlayerId, int nOldState, int nNewState);
typedef void (*SDK_OnPlayerActionChange) (int nPlayerId, int nOldAction, int nNewAction);
typedef void (*SDK_OnPlayerOnFireChange) (int nPlayerId, unsigned int bIsOnFireNow);
typedef void (*SDK_OnPlayerCrouchChange) (int nPlayerId, unsigned int bIsCrouchingNow);
typedef void (*SDK_OnPlayerGameKeysChange) (int nPlayerId, int nOldKeys, int nNewKeys);
For example, to create a callback for OnPublicMessage:
typedef int (*SDK_OnPublicMessage) (int nPlayerId, const char* pszText);
You would need to create a function like so:
int MyOnPublicMessage (int nPlayerId, const char* pszText)
{
return 1;
}
void functions need not return anything (and should not), whereas callbacks with a return type expect a value to be returned, and will react differently according to their return values. For example, returning 0 in OnPublicMessage will reject a given chat message and essentially mute it. Returning 1 will send it to other players if no other plugins suppress it.
To have the server recognize the callback and make use of it, set it in VcmpPluginInit:
extern "C" EXPORT unsigned int VcmpPluginInit( PluginFuncs* pluginFuncs, PluginCallbacks* pluginCalls, PluginInfo* pluginInfo )
{
pluginCalls->OnPublicMessage = MyOnPublicMessage;
return 1;
}
Using Plugin Functions
Using plugin functions is easier still than dealing with callbacks. To use a function, you can simply make a direct call to a function in the pluginFuncs struct:
extern "C" EXPORT unsigned int VcmpPluginInit( PluginFuncs* pluginFuncs, PluginCallbacks* pluginCalls, PluginInfo* pluginInfo )
{
pluginFuncs->SetServerName("My VC:MP Server");
return 1;
}