lwb5-in-2025/game/scripts/lib/xml_config.inc

394 lines
12 KiB
PHP
Raw Normal View History

2016-01-10 11:01:49 +01:00
<?php
/****************************************************************************
* XML CONFIGURATION PARSER
****************************************************************************/
class xml_config {
private static $mVersion = null;
private static $mGame = null;
private static $versions = null;
private static $games = null;
private static $defGame = null;
private static function readFromEnv(string $varName, string $default): string {
if ($varName == '') {
return $default;
}
$fileVarName = $varName . '_FILE';
$fileName = getenv($fileVarName);
if ($fileName !== false) {
$value = @file_get_contents($fileName);
} else {
$value = getenv($varName);
}
return $value ?: $default;
}
private static function parseMainParams($root) {
2016-01-10 11:01:49 +01:00
$node = $root->firstChild;
while ($node) {
if ($node->nodeType == XML_ELEMENT_NODE && $node->nodeName == 'Param') {
$aName = $node->getAttribute('name');
if ($aName == '') {
2016-01-10 11:01:49 +01:00
l::warn("CONFIG: a main parameter is missing a 'name' attribute");
} elseif (!isset(xml_config::$mGame->params[$aName])) {
$aValue = $node->getAttribute('value');
$aFromEnv = $node->getAttribute('from-env');
$aValue = self::readFromEnv($aFromEnv, $aValue);
2016-01-10 11:01:49 +01:00
xml_config::$mGame->params[$aName] = $aValue;
} else {
l::notice("CONFIG: duplicate main parameter '$aName'");
}
} elseif ($node->nodeType == XML_ELEMENT_NODE) {
l::notice("CONFIG: found unexpected tag '{$node->nodeName}' in MainParams section");
}
$node = $node->nextSibling;
}
}
private static function parseMainTicks($root) {
2016-01-10 11:01:49 +01:00
$node = $root->firstChild;
while ($node) {
if ($node->nodeType == XML_ELEMENT_NODE && $node->nodeName == 'Tick') {
$tScript = $node->getAttribute('script');
$tFirst = $node->getAttribute('first');
$tInterval = $node->getAttribute('interval');
$tLast = $node->getAttribute('last');
if ($tScript == "" || $tFirst == "" || $tInterval == "") {
l::warn("CONFIG: a main tick declaration is missing a mandatory attribute");
} elseif ((int)$tInterval == 0) {
l::warn("CONFIG: invalid interval for main tick '$tScript'");
} elseif (is_null(xml_config::$mVersion->getTickDefinition($tScript))) {
new tick_definition(xml_config::$mVersion, $tScript, false);
new tick_instance(xml_config::$mGame, $tScript, (int)$tFirst,
(int)$tInterval, $tLast ? (int)$tLast : null);
} else {
l::notice("CONFIG: duplicate main tick '$tScript'");
}
} elseif ($node->nodeType == XML_ELEMENT_NODE) {
l::notice("CONFIG: found unexpected tag '{$node->nodeName}' in MainTicks section");
}
$node = $node->nextSibling;
}
}
private static function parseTickDefinition($version, $root) {
2016-01-10 11:01:49 +01:00
$script = $root->getAttribute('script');
$public = ($root->getAttribute('public') == 1);
if ($script == "") {
l::warn("CONFIG: invalid tick definition for version {$version->id}");
return;
}
if (!is_null($version->getTickDefinition($script))) {
l::notice("CONFIG: duplicate tick definition '$script' for version {$version->id}");
return;
}
$def = new tick_definition($version, $script, $public);
if (!$public) {
return;
}
$names = array();
$descs = array();
$node = $root->firstChild;
while ($node) {
if ($node->nodeType != XML_ELEMENT_NODE) {
$node = $node->nextSibling;
continue;
}
if ($node->nodeName != "Name" && $node->nodeName != 'Description') {
l::warn("CONFIG: unexpected tag '{$node->nodeName}' found in tick definition "
. "'{$script}' for version '{$version->id}'");
$node = $node->nextSibling;
continue;
}
$lang = $node->getAttribute('lang');
if ($lang == '') {
l::warn("CONFIG: missing language for {$node->nodeName} in tick definition "
. "'{$script}' for version '{$version->id}'");
$node = $node->nextSibling;
continue;
}
$contents = trim($node->textContent);
if ($contents == '') {
l::warn("CONFIG: missing contents for {$node->nodeName} in tick definition "
. "'{$script}' for version '{$version->id}'");
$node = $node->nextSibling;
continue;
}
if ($node->nodeName == 'Name') {
$names[$lang] = $contents;
} else {
$descs[$lang] = $contents;
}
$node = $node->nextSibling;
}
foreach ($names as $lang => $name) {
$def->addText($lang, $name, $descs[$lang]);
}
}
private static function parseVersion($root) {
2016-01-10 11:01:49 +01:00
$id = $root->getAttribute("id");
$cp = ($root->getAttribute("playable") == 1);
$tx = $root->getAttribute("text");
if ($id == "" || $tx == "") {
l::warn("CONFIG: invalid version definition (missing identifier or text)");
return null;
} elseif ($id == 'main') {
l::warn("CONFIG: invalid version definition (using 'main' identifier)");
return null;
}
$version = new version($id, $cp, $tx);
$node = $root->firstChild;
while ($node) {
if ($node->nodeType == XML_ELEMENT_NODE && $node->nodeName == 'Tick') {
xml_config::parseTickDefinition($version, $node);
} elseif ($node->nodeType == XML_ELEMENT_NODE) {
l::warn("CONFIG: found unexpected tag '{$node->nodeName}' in MainTicks section");
}
$node = $node->nextSibling;
}
return $version;
}
private static function parseVersions($root) {
2016-01-10 11:01:49 +01:00
$node = $root->firstChild;
$versions = array();
while ($node) {
if ($node->nodeType == XML_ELEMENT_NODE && $node->nodeName == 'Version') {
$v = xml_config::parseVersion($node);
if (!is_null($v)) {
if (isset($versions[$v->id])) {
2016-01-10 11:01:49 +01:00
l::notice("CONFIG: found duplicate definition for version '{$v->id}'");
} else {
$versions[$v->id] = $v;
2016-01-10 11:01:49 +01:00
}
}
} elseif ($node->nodeType == XML_ELEMENT_NODE) {
l::notice("CONFIG: found unexpected tag '{$node->nodeName}' in Versions section");
}
$node = $node->nextSibling;
}
return $versions;
}
private static function parseGame($root) {
2016-01-10 11:01:49 +01:00
$id = $root->getAttribute('id');
if ($id == '') {
l::warn("CONFIG: game definition is missing an identifier");
return null;
}
if ($id == 'main') {
l::warn("CONFIG: game definition with 'main' identifier ignored");
return null;
}
$version = $root->getAttribute('version');
if (is_null(xml_config::$versions[$version])) {
l::warn("CONFIG: game '$id' has unknown version '$version'");
return null;
}
$namespace = $root->getAttribute('namespace');
if ($namespace == '') {
l::warn("CONFIG: no namespace defined for game '$id'");
return null;
}
$text = $root->getAttribute('text');
if ($namespace == '') {
l::warn("CONFIG: no text for game '$id'");
return null;
}
$public = ($root->getAttribute('public') == 1);
$canJoin = ($root->getAttribute('canjoin') == 1);
$game = new game(xml_config::$versions[$version], $id, $namespace, $public, $canJoin, $text);
$node = $root->firstChild;
while ($node) {
if ($node->nodeType != XML_ELEMENT_NODE) {
$node = $node->nextSibling;
continue;
}
if ($node->nodeName == 'Param') {
$aName = $node->getAttribute('name');
$aValue = $node->getAttribute('value');
if ($aName == "") {
l::warn("CONFIG: a parameter is missing a 'name' attribute for game '$id'");
} elseif (isset($game->params[$aName])) {
2016-01-10 11:01:49 +01:00
l::notice("CONFIG: duplicate parameter '$aName'");
} else {
$game->params[$aName] = $aValue;
2016-01-10 11:01:49 +01:00
}
} elseif ($node->nodeName == 'Description') {
$lang = $node->getAttribute('lang');
$contents = trim($node->textContent);
if ($lang == "") {
l::warn("CONFIG: a description is missing the 'lang' attribute for game '$id'");
} elseif ($contents == "") {
l::warn("CONFIG: description in language '$lang' has no contents for game '$id'");
} elseif (isset($game->descriptions[$lang])) {
2016-01-10 11:01:49 +01:00
l::notice("CONFIG: description in language '$lang' appears twice for game '$id'");
} else {
$game->descriptions[$lang] = $contents;
}
} elseif ($node->nodeName == 'Tick') {
$tScript = $node->getAttribute('script');
$tFirst = $node->getAttribute('first');
$tInterval = $node->getAttribute('interval');
$tLast = $node->getAttribute('last');
if ($tScript == "" || $tFirst == "" || $tInterval == "") {
l::warn("CONFIG: a tick declaration is missing a mandatory attribute "
. "for game '$id'");
} elseif ((int)$tInterval == 0) {
l::warn("CONFIG: invalid interval for tick '$tScript' in game '$id'");
} elseif (is_null($game->version->getTickDefinition($tScript))) {
l::warn("CONFIG: no definition for tick '$tScript' in game '$id' "
. "(version '$version')");
} elseif (isset($game->ticks[$tScript])) {
l::notice("CONFIG: duplicate tick initialiser for tick '$tScript' in game '$id'");
} else {
2016-01-10 11:01:49 +01:00
new tick_instance($game, $tScript, (int)$tFirst, (int)$tInterval,
$tLast ? (int)$tLast : null);
}
} else {
l::notice("CONFIG: found unexpected tag '{$node->nodeName}' in game '$id' definition");
}
$node = $node->nextSibling;
}
return $game;
}
private static function parseGames($root) {
2016-01-10 11:01:49 +01:00
$defaultId = $root->getAttribute('default');
$games = array();
$node = $root->firstChild;
while ($node) {
if ($node->nodeType == XML_ELEMENT_NODE && $node->nodeName == 'Game') {
$g = xml_config::parseGame($node);
if (!is_null($g)) {
if (isset($games[$g->name])) {
2016-01-10 11:01:49 +01:00
l::notice("CONFIG: found duplicate definition for game '{$v->name}'");
} else {
$games[$g->name] = $g;
2016-01-10 11:01:49 +01:00
}
}
} elseif ($node->nodeType == XML_ELEMENT_NODE) {
l::notice("CONFIG: found unexpected tag '{$node->nodeName}' in Games section");
}
$node = $node->nextSibling;
}
if (count($games) && ($defaultId == '' || is_null($games[$defaultId]))) {
$defaultId = $games[0]->name;
l::notice("CONFIG: no default game, using '$defaultId'");
}
xml_config::$defGame = $defaultId;
return $games;
}
public static function parse($xmlData) {
2016-01-10 11:01:49 +01:00
$doc = new DOMDocument();
if (!$doc->loadXML($xmlData)) {
l::error("CONFIG: error while parsing XML configuration");
return false;
}
xml_config::$mVersion = new version('main', false, 'Legacy Worlds');
xml_config::$mGame = new game(xml_config::$mVersion, 'main', '', false, false, 'Legacy Worlds');
xml_config::$versions = null;
xml_config::$games = null;
xml_config::$defGame = null;
$root = $doc->documentElement;
$node = $root->firstChild;
while ($node) {
if ($node->nodeType == XML_ELEMENT_NODE) {
switch ($node->nodeName) :
case 'MainParams':
xml_config::parseMainParams($node);
break;
case 'MainTicks':
xml_config::parseMainTicks($node);
break;
case 'Versions':
if (is_array(xml_config::$versions)) {
l::notice("CONFIG: found duplicate set of version definitions");
} else {
xml_config::$versions = xml_config::parseVersions($node);
}
break;
case 'Games':
if (is_array(xml_config::$games)) {
l::notice("CONFIG: found duplicate set of game definitions");
} elseif (is_array(xml_config::$versions)) {
xml_config::$games = xml_config::parseGames($node);
} else {
l::notice("CONFIG: game definitions found before version "
. "definitions, ignored");
}
break;
default:
l::notice("CONFIG: found unknown tag '{$node->nodeName}' at toplevel");
break;
endswitch;
}
$node = $node->nextSibling;
}
if (!is_array(xml_config::$versions) || count(xml_config::$versions) == 0) {
l::error("CONFIG: no versions have been defined!");
return false;
}
if (!is_array(xml_config::$games) || count(xml_config::$games) == 0) {
l::error("CONFIG: no games have been defined!");
return false;
}
xml_config::$versions['main'] = xml_config::$mVersion;
xml_config::$games['main'] = xml_config::$mGame;
return new config(xml_config::$versions, xml_config::$games, xml_config::$defGame);
}
}
?>