How to Implement a Player Extension
Player extensions are main ways of handling input in Limon Engine. Input from player is first handled by PhysicalPlayer class, which governs look around and movement, then all input information is passed to selected extension, so it can handle custom interactions, like pickups, shooting etc. On the other side, any interaction send by other entities to player is directly passed to player extension for handling.
Player extensions follow the unified parameter contract. Like Triggers, the base class holds the values on a protected parameters member: you seed any default parameters into that member in the constructor, the base getParameters() const returns it, and setParameters() overwrites it when the designer edits values or a map is loaded. The configured values are persisted with the map and editable in the editor. An extension with no configurable settings simply seeds nothing and the member stays empty.
PlayerExtensionInterface Class
|
processInput(const InputStates &inputState, const PlayerInformation &playerInformation, long time) |
|
interact(std::vector<LimonTypes::GenericParameter> ¶meters) |
|
|
|
setParameters(std::vector<LimonTypes::GenericParameter>parameters) |
|
PlayerExtensionInterface(LimonAPI *limonAPI)
The constructor of the interface. If the extension exposes editor-configurable settings, this is where it seeds their defaults: build each LimonTypes::GenericParameter descriptor and push_back it onto the protected this->parameters member.
Note
All Player Extension must have the same signature, no other parameters should be required.
void processInput(const InputStates &inputState, const PlayerInformation &playerInformation, long time)
Called each frame with updated input information, current player state, and the frame time in milliseconds.
Parameters:
const InputStates &inputState: Current input state for this frame.
const PlayerInformation &playerInformation: Current player position and look direction. See PlayerInformation struct below.
long time: Frame time in milliseconds.
void interact(std::vector<LimonTypes::GenericParameter> &interactionData)
Called by other entities to interact with player.
std::vector<LimonTypes::GenericParameter> getParameters() const
Returns the configurable parameters of this extension. These are rendered by the editor under the selected extension and persisted with the map. The base implementation returns the instance’s protected parameters member - the defaults you seeded in the constructor, or the configured values after an edit or load - so you normally do not override it. Override only to expose typed members as descriptors (Actor-style). An empty member means the extension has no editor-exposed configuration.
void setParameters(std::vector<LimonTypes::GenericParameter>parameters)
Stores the configured parameter values on the extension instance. Called when the map designer edits values in the editor and when a map is loaded. The base implementation keeps the values in the protected parameters member - the single source of truth for load, serialize, and editor edits. Override only if the extension needs to react to value changes.
std::string getName() const
Returns the name of the Player Extension.
Warning
The name must be unique, or the results will be undefined.
Note
To drive the camera from a player extension, activate a camera rig at runtime with createCameraRig / activateCameraRig (for example from processInput). The old getCustomCameraAttachment mechanism has been removed.
PlayerInformation struct
Passed to processInput each frame.
Type |
Name |
Description |
LimonTypes::Vec4 |
position |
Current world-space position of the player. |
LimonTypes::Vec4 |
lookDirection |
Normalized direction the player is looking at. w component unused. |
InputStates Class Usage
Input is queried through InputStates using hash-keyed action names. Any binding — keyboard, mouse, or gamepad — maps to the same logical action, so plugin code never needs to know which physical key is pressed.
See Input System for the full API reference, the built-in action name table, how to define custom game actions in XML, and how to detect which input device the player is using.
How to enable Dynamic Library discovery
Limon engine will try to load custom player extensions on engine startup, from libcustomTriggers file (extension based on platform). If the file is found, engine will check for a method with following signature:
void registerPlayerExtensions(std::map<std::string, PlayerExtensionInterface*(*)(LimonAPI*)>* playerExtensionMap)
This method should fill the actorMap passed, with all the custom actors, like this:
(*playerExtensionMap)["$EXTENSION_NAME1$"] = &createPlayerExtension<$ExtensionClass1$>;
(*playerExtensionMap)["$EXTENSION_NAME2$"] = &createPlayerExtension<$ExtensionClass2$>;
Note
Every registered extension name is available through the static PlayerExtensionInterface::getExtensionNames() (Python: get_extension_names()). The editor uses this list to present the launch-time extension as a drop-down in Player Properties, so the registered name you use here is the one a map designer will pick from. See Using Builtin Editor.
Note
getExtensionNames() was previously named getTriggerNames(). It returns registered player-extension names, not trigger names; the old name was a misnomer and has been corrected.
Sample Player Extensions
The engine ships with sample player extensions under samples/ that implement PlayerExtensionInterface:
ShooterPlayerExtension - a first-person shooter player controller.
CowboyShooterExtension - the western-demo shooter controller, which also activates a third-person camera rig at runtime (
createCameraRig/activateCameraRig).WesternMenuPlayerExtension - a menu controller using absolute mouse input for the western demo’s menus.
A Python player-extension sample ships under Engine/Scripts/ as python_player_extension.py (the PythonPlayerExtension class), subclassing the Python base in player_extension_interface.py.