Developer Documentation
- Introduction
- Plugin
- Data Providers
- Install
- Services
- Chat Notification
- Translations
- File System
- User Groups
- Admin Groups
- Player Storage
- Players DB Storage
- Maps Storage
- Components
- Cook Books
The Event System
Data Providers are a different way to create a controller…
eXpansion2 event system differs from previous controller design where dedicated server event gets routed directly to plugin method.
The idea is to separate dedicated and game mode script events from directly passing to plugin. This way it’s possible to route and re-organize events and even adapt the controller:
- different scripted game modes
- possible future game api changes
The diagram shows how event data flows from dedicated to plugin.
- Script Mode or Dedicated server sends event.
- Dedicated server api receives the event.
- Multiple DataProviders are set to work in certain conditions.
- at begin of a map eXpansion2 checks which data provider is most best suited for the current situation and starts those.
- The Selected DataProvider sends it’s abstracted events to Records plugin
- Records plugin doesn’t need to take into consideration changes coming from various scripts
- Records plugin can work as a new data provider which seeds data to other plugins who requested the data.
- Next plugins process the records plugin data, and show different things…
- a chat message plugin, which shows the new record at game chat.
- records widget, which draws hud element to the screen
- best scores widget
- etc…
Data Providers
Data providers, when initialized, will check for 3 conditions from the game:
- Title
- Generic:
- ALL
- TM
- SM
- Specific
- “TmStadium@nadeo”
- “Obstacle@steeffeen”
- …
- Generic:
- Dedicated Game Mode
- ALL
- Script
- Rounds
- Team
- …
- Script name
- ALL
- “TimeAttack.Script.txt”
- “Rounds.Script.txt”
- …
When registering a script mode we can use the keyword ALL
to make it compatible with all Titles and such.
In our example the PlayerDataProvider provides information onPlayerConnect and onPlayerDisconnect.
When choosing data provider, expansion will use the most suitable data provider - not the first one that is compatible.
Let’s say we have a Records plugin
which depends on TimeDataProvider
compatible with TM
script modes.
It works nicely for build-in modes, but in some custom script mode like acme.script.txt
we notice that the provider does not work well.
To make our plugin work well again, it’s now possible to create another TimeDataProvider
which is set
to be compatible with acme.script.txt
only.
The new data provider has more specific information on what callbacks the script has and it will be
chosen instead of the more generic one. This will allow the Records plugin to work without any effect.
What happens if controller is started on Storm ?
Well the LocalRecords plugin gets disabled, since there’s no TimeDataProvider
available for Storm titles.
Any developer can though easily make local records and widget and other dependent plugins to work,
by implementing TimeDataProvider
for Storm or other custom game mode.
Once this is created the LocalRecordsPlugin
will be enabled as a compatible TimeDataProvider
is found.
So the LocalRecordsDataProvider
will enable as well, which in it’s turn will enable LocalRecrodsWidget
.
So the development of a simple DataProvider will reconnect and render compatible whole features that was never meant to work on Storm.
Data providers can also be used to send game mode dependent “configuration” data to plugins. For example widget positions.
Registering a Data Provider
A data provider is basically a service, like nearly everything else in eXpansion2.
Very basic data provider compatible with everything:
file: bundle/resources/config/services.yaml
services: expansion.acme.acme_data_provider: class: yourName\AcmeBundle\DataProvider\Acme tags: - {name: expansion.dataprovider, provider: "your_name.acme", interface: "yourName\AcmeBundle\DataProvider\Listener\ListenerInterfaceYournameAcme"} - {name: expansion.dataprovider.compatibility, title: ALL}
The data provider uses the symfony tags.
The first tag declares the provider with 2 information:
- provider
- You can have multiple services for the same provider so that eXp can chose from.
- interface
- The interface that defines the methods the provider provides.
The second tag allows to add compatibility information.
In this case we have basically said our provider is compatible with all titles, and as we have not given any specification for mode & scrip it’s compatible with all of them as well.
To make it compatible in Trackmania for both Rounds & Laps script mode we could write something like this:
services:
expansion.acme.acme_dataprovider:
class: yourName\AcmeBundle\DataProvider\Acme
tags:
- {name: expansion.dataprovider, provider: "your_name.acme", interface: "YourName\AcmeBundle\DataProvider\Listener\ListenerInterfaceYournameAcme"}
- {name: expansion.dataprovider.compatibility, title: TM, mode: 0, script: Rounds.Script.txt }
- {name: expansion.dataprovider.compatibility, title: TM, mode: 0, script: Laps.Script.txt }
Providers are useless, if they don’t listen to events, so here we use another tag for that:
services:
expansion.acme.acme_dataprovider:
class: yourName\AcmeBundle\DataProvider\Acme
tags:
- {name: expansion.dataprovider, provider: "your_name.acme", interface: "ourName/AcmeBundle\DataProvider\Listener\ListenerInterfaceYournameAcme"}
- {name: expansion.dataprovider.compatibility, title: TM, mode: 0, script: Rounds.Script.txt }
- {name: expansion.dataprovider.compatibility, title: TM, mode: 0, script: Laps.Script.txt }
- {name: expansion.dataprovider.listener, event_name: PlayerConnect, method: onPlayerConnect }
When the dedicated server PlayerConnect
event happens the onPlayerConnect
method of this data provider should be called.
You can add as much of these listeners as you wish.
services:
expansion.acme.acme_dataprovider:
class: yourName\AcmeBundle\DataProvider\Acme
tags:
- {name: expansion.dataprovider, provider: "your_name.acme", interface: "ourName\AcmeBundle\DataProvider\Listener\Acme"}
- {name: expansion.dataprovider.compatibility, title: TM, mode: 0, script: Rounds.Script.txt}
- {name: expansion.dataprovider.compatibility, title: TM, mode: 0, script: Laps.Script.txt}
- {name: expansion.dataprovider.listener, event_name: PlayerConnect, method: onPlayerConnect}
- {name: expansion.dataprovider.listener, event_name: PlayerDisconnect, method: onPlayerDisconnect}
We can make a listener depend upon a parent plugin:
services:
expansion.acme.acme_dataprovider:
class: yourName/AcmeBundle\DataProvider\Acme
tags:
- {name: expansion.dataprovider, provider: "your_name.acme", interface: "ourName\AcmeBundle\DataProvider\Listener\Acme"}
- {name: expansion.dataprovider.compatibility, title: TM, mode: 0, script: Rounds.script.txt}
- {name: expansion.dataprovider.compatibility, title: TM, mode: 0, script: Laps.script.txt}
- {name: expansion.dataprovider.parent, parent: "Service id of the plugin it requires to run"}
- {name: expansion.dataprovider.listener, event_name: PlayerConnect, method: onPlayerConnect}
- {name: expansion.dataprovider.listener, event_name: PlayerDisconnect, method: onPlayerDisconnect}
Dispatching a custom event
As said, data provider might depend upon a another plugin. When this happens it means that the plugin is dispatching events that needs to be normalized.
To dispatch events you need the eXpansion dispatcher service
eXpansion\Framework\Core\Services\Application\DispatcherInterface
And using the dispatcher:
<?php
use eXpansion\Framework\Core\Services\Application\DispatcherInterface;
class MyClass {
/** @var DispatcherInterface */
private $dispatcher;
public function __construct(DispatcherInterface $dispatcher) {
$this->dispatcher = $dispatcher;
}
public function onSomeMethod() {
// do your code here, and when needed, just call dispatcher as...
$var1 = "foo";
$var2 = "bar";
$this->dispatcher->dispatch('my_name.acme.super_event', [$var1, $var2]);
}
}
?>
Available Data Providers
Here is a list & short description of available data providers that you are probably need. There are other data providers that you will probably won’t need. You can always contact us if you wish to know more.
Generic Providers
exp.tm
, exp.sm
and exp.all
are generic empty providers, which enables the plugin to work on certain environments.
Dataprovider | Interface Class | Dedicated Callback | Callbacks Methods |
---|---|---|---|
exp.application | ListenerInterfaceExpApplication | onApplicationInit onApplicationReady onApplicationStop |
|
exp.timer | ListenerInterfaceExpTimer | onEverySecond onPreloop onPostloop |
|
expansion.user_group | ListenerInterfaceExpUserGroup | onExpansionGroupAddUser onExpansionGroupRemoveUser onExpansionGroupDestroy |
|
exp.tm | StatusAwarePluginInterface | setStatus | |
exp.sm | StatusAwarePluginInterface | setStatus | |
exp.all | StatusAwarePluginInterface | setStatus |
Maniaplanet Legacy Callbacks
Dataprovider | Interface Class | Dedicated Callback | Callbacks Methods |
---|---|---|---|
mp.legacy.chat | ListenerInterfaceMpLegacyChat | *.PlayerChat | onPlayerChat |
mp.legacy.player | ListenerInterfaceMpLegacyPlayer | *.PlayerConnect *.PlayerDisconnect *.PlayerInfoChanged *.PlayerAlliesChanged |
onPlayerConnect onPlayerDisconnect onPlayerInfoChanged onPlayerAlliesChanged |
mp.legacy.maplist | ListenerInterfaceMpLegacyMaplist | *.MapListModified | onMapListModified |
mp.legacy.map | ListenerInterfaceMpLegacyMap | *.BeginMap *.EndMap |
onBeginMap onEndMap |
mp.legacy.manialink | ListenerInterfaceMpLegacyManialink | *.PlayerManialinkPageAnswer | onPlayerManialinkPageAnswer |
mp.legacy.script | ListenerInterfaceMpLegacyScript | *.ModeScriptCallbackArray | onModeScriptCallbackArray |
Maniaplanet Script Callbacks
Dataprovider | Interface Class | Dedicated Callback | Callbacks Methods |
---|---|---|---|
mp.script.map | ListenerInterfaceMpScriptMap | Maniaplanet.StartMap_Start Maniaplanet.StartMap_End Maniaplanet.EndMap_Start Maniaplanet.EndMap_End |
onStartMapStart onStartMapEnd onEndMapStart onEndMapEnd |
mp.script.match | ListenerInterfaceMpScriptMatch | Maniaplanet.StartMatch_Start Maniaplanet.StartMatch_End EndMatch_Start EndMatch_End StartTurn_Start StartTurn_End EndTurn_Start EndTurn_End StartRound_Start StartRound_End EndRound_Start EndRound_End |
onStartMatchStart onStartMatchEnd…. etc… |
mp.script.podium | ListenerInterfaceMPScriptPodium | Maniaplanet.Podium_Start Maniaplanet.Podium_End |
onPodiumStart onPodiumEnd |
TM Data Providers
Dataprovider | Interface Class | Dedicated Callback | Callbacks Methods |
---|---|---|---|
tm.script.waypoint | ListenerInterfaceWaypointData | Trackmania.OnWayPoint | onPlayerWayPoint |
tm.script.race | ListenerInterfaceRaceData | Trackmania.OnWayPoint | onPlayerEndRace |
tm.script.lap | ListenerInterfaceLapData | Trackmania.OnWayPoint | onPlayerEndLap |
tm.script.match | ListenerInterfaceMpScriptMatch | Maniaplanet.StartMatch_Start Maniaplanet.StartMatch_End EndMatch_Start EndMatch_End StartTurn_Start StartTurn_End EndTurn_Start EndTurn_End StartRound_Start StartRound_End EndRound_Start EndRound_End |
onStartMatchStart onStartMatchEnd…. etc… |
mp.script.podium | ListenerInterfaceMpScriptPodium | Maniaplanet.Podium_Start Maniaplanet.Podium_End |
onPlayerWayPoint onPlayerEndRace onPlayerEndLap |
tm.script.player | ListenerInterfacePlayerEvents | Trackmania.Event.StartLine Trackmania.Event.GiveUp Trackmania.Event.Respawn |
OnStartLine onGiveUp onRespawn |
SM Data Providers
Dataprovider | Interface Class | Dedicated Callback | Callbacks Methods |
---|---|---|---|
sm.player | ListenerInterfaceSmPlayer | Shootmania.Event.OnHit Shootmania.Event.OnArmorEmpty Shootmania.Event.OnCapture Shootmania.Event.OnPlayerTriggersSector Shootmania.Event.OnPlayerTouchesObject Shootmania.Event.OnPlayerThrowsObject |
|
sm.player.shoot | ListenerInterfaceSmPlayerShoot | Shootmania.Event.OnShoot | onShoot |
sm.player.extra | ListenerInterfaceSmPlayerExtra | Shootmania.Event.OnNearMiss Shootmania.Event.OnShotDeny Shootmania.Event.OnFallDamage Shootmania.Event.OnPlayerRequestRespawn |
|
sm.player.actions | ListenerInterfaceSmPlayerActions | Shootmania.Event.OnActionCustomEvent Shootmania.Event.OnActionEvent Shootmania.Event.OnPlayerRequestActionChange |
Compatibility Providers
These data providers contains no logic in them, they exist just to limit a plugin to a certain game mode & title.