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
Widget - Script Update
eXpansion 2 comes with a new approach for widget updates. We can either update the widget manialink for each player individually but this is a slow process when there is 200 players on the server. Even with eXpansions optimized GuiHandler that will group calls.
The second option you have is to use 2 manialinks. Both manialinks are sent to all players. One of the manialinks contains
the data
that needs to be displayed in maniascript. The other manialink contains the display, and a script that updates the data.
The server controller will then update only the data
manialink. The player specific process is executed on client side.
This way we can individual widgets for players even on very busy servers without compromising performance. eXpansion comes with all the tools to make this as easy as possible.
Pushing data to the front
To push data to the front you need 2 things :
- A
eXpansion\Bundle\WidgetBestCheckpoints\Plugins\Gui\ScriptVariableUpdateFactory
to update the variables - A plugin to update the data.
So first let’s imagine we wish to have list of best checkpoints times. We therefore need a variable of type Integer[Integer]
.
As nearly everything else in eXpansion this update factory is actually a service :
eXpansion.bundle.widget_best_checkpoints.plugins.Gui.updater_widget_factory:
class: eXpansion\Bundle\WidgetBestCheckpoints\Plugins\Gui\ScriptVariableUpdateFactory
autowire: true
arguments:
$name: "BestCheckpoints Updater"
$variables:
- {name: "LocalRecordCheckpoints", type: "Integer[Integer]", default: "Integer[Integer]"}
tags:
- {name: expansion.plugin, data_provider: exp.timer}
- {name: expansion.plugin, data_provider: expansion.user_group}
This plugin service has user_groups & timer as data providers. This allows it to update automatically.
As you can see one UpdaterScript can update multiple variables.
Second step is to fetch the data, we will use a simple plugin for that.
<?php
class BestCheckpoints implements StatusAwarePluginInterface {
protected $updater;
protected $playerGroup;
public function __construct(
ScriptVariableUpdateFactory $updater,
Group $playerGroup
) {
$this->updater = $updater;
$this->playerGroup = $playerGroup;
}
public function setStatus($status)
{
if ($status) {
$this->updater->create();
} else {
$this->updater->destroy();
}
}
/**
* Called when cp times are updated
*/
public function onDataUpdate($times)
{
if (count($times) > 0) {
$this->updater->updateValue($this->playerGroup, "LocalRecordCheckpoints", \FML\Script\Builder::getArray($times, true));
} else {
$this->updater->updateValue($this->playerGroup, "LocalRecordCheckpoints", "Integer[Integer]");
}
}
}
And the definition of the service.
services:
eXpansion\Bundle\WidgetBestCheckpoints\Plugins\BestCheckpoints:
class: eXpansion\Bundle\WidgetBestCheckpoints\Plugins\BestCheckpoints
autowire: true
arguments:
$allPlayers: '@expansion.framework.core.user_groups.all_players'
$updater: '@eXpansion.bundle.widget_best_checkpoints.plugins.Gui.updater_widget_factory'
tags:
- {name: 'expansion.plugin', data_provider: 'my_data_provider'}
With this in place the data will be sent properly. We now need to actually display it.
Displaying the data
To display the data we will need a widget.
<?php
class BestCheckpointsWidgetFactory extends WidgetFactory
{
/** @var UpdaterWidgetFactory */
protected $updaterWidgetFactory;
public function __construct(
$name,
$sizeX,
$sizeY,
$posX,
$posY,
WidgetFactoryContext $context,
UpdaterWidgetFactory $updaterWidgetFactory
) {
parent::__construct($name, $sizeX, $sizeY, $posX, $posY, $context);
$this->updaterWidgetFactory = $updaterWidgetFactory;
}
protected function createContent(ManialinkInterface $manialink)
{
// ... Creating all the fml manialinks.
// Get the name of the variable.
$cpVariable = $this->updaterWidgetFactory->getVariable('LocalRecordCheckpoints')->getVariableName();
// On initialization init properly the "shared" variables.
$manialink->getFmlManialink()->getScript()->addCustomScriptLabel(
ScriptLabel::OnInit,
<<<EOL
{$this->updaterWidgetFactory->getScriptInitialization()}
EOL
);
// Do a function that will update the content.
$manialink->getFmlManialink()->getScript()->addScriptFunction(
"",
<<<EOL
Void Refresh() {
// Do stuff
{$cpVariable}[_Index];
}
EOL
);
// Handle in script loop the update.
$manialink->getFmlManialink()->getScript()->addCustomScriptLabel(
ScriptLabel::Loop,
<<<EOL
// handle data change
{$this->updaterWidgetFactory->getScriptOnChange('Refresh();')}
EOL
);
}
}
Note that we don’t use
LocalRecordCheckpoints
directly in maniascript. We fetch the name of the variable from the updater. The updater creates a unique name to prevent unwanted interactions between widgets that might have same name.
And declare the widget
services:
eXpansion\Bundle\WidgetBestCheckpoints\Plugins\Gui\BestCheckpointsWidgetFactory:
class: eXpansion\Bundle\WidgetBestCheckpoints\Plugins\Gui\BestCheckpointsWidgetFactory
autowire: true
arguments:
$name: "BestCheckpoints"
$posX: -95
$posY: 89
$sizeX: null
$sizeY: null
$updaterWidgetFactory: '@eXpansion.bundle.widget_best_checkpoints.plugins.Gui.updater_widget_factory'