Compare commits

..

27 Commits

Author SHA1 Message Date
slawkens
6b89dd133d Fix phpstan 2026-04-19 17:29:25 +02:00
slawkens
6dc16397a1 [WIP] Lua + TOML stages loading
Lua extension required for .lua (canary)
2026-04-19 17:22:32 +02:00
slawkens
5dd97ad8fd Add more configs for ots-info site [skip ci] 2026-04-19 16:29:20 +02:00
slawkens
a6a3c76b8d gameplay & groups are also not needed [skip ci] 2026-04-19 16:17:18 +02:00
slawkens
1eba4cc509 [WIP] Loading of config .toml's
Deprecate load_config_lua, use MyAAC\Server\Lua\Loader::load instead
2026-04-19 16:05:22 +02:00
slawkens
6e603ad558 Merge branch 'develop' into blacktek-toml 2026-04-17 17:31:13 +02:00
slawkens
c16f95f8d2 Merge branch 'main' into develop 2026-04-17 17:30:53 +02:00
slawkens
ec7079dd57 Bye JetBrains, it was not my decision :( 2026-04-14 19:58:12 +02:00
slawkens
2c18f9c767 Backward support for MyAAC\Items class 2026-03-08 21:08:29 +01:00
slawkens
39614a22c4 Update Items.php 2026-03-07 21:16:17 +01:00
slawkens
02ce6b364b Update Items.php 2026-03-07 21:09:57 +01:00
slawkens
e10ebed2f4 Fix fromid toid parsing 2026-03-07 21:00:14 +01:00
slawkens
a6e658b1a2 60x faster items.xml loading
Using simplexml, which is enabled by default on php
2026-03-07 20:54:47 +01:00
slawkens
2a80bc1b46 Nothing important, var name 2026-03-02 21:05:19 +01:00
slawkens
fbb5034458 [WIP] Refactoring - Uniform error message + TOML exception catch 2026-03-01 21:45:48 +01:00
slawkens
4ca79a1e85 Use static methods instead, looks better 2026-02-27 15:25:06 +01:00
slawkens
f975bd2f2a [WIP] Mounts TOML + XML parsers 2026-02-26 19:48:16 +01:00
slawkens
8a5823a69c [WIP] Outfits TOML + XML
Deprecate old Outfits & Mounts functions
2026-02-26 18:39:08 +01:00
slawkens
f738448f2e [WIP] Refactoring 2026-02-26 16:45:58 +01:00
slawkens
058e80cfc6 Update Monsters.php 2026-02-15 02:02:07 +01:00
slawkens
980d5cb5d4 Update Items.php 2026-02-15 02:02:05 +01:00
slawkens
9146a0e53c Parse last item 2026-02-15 02:01:57 +01:00
slawkens
ad1d069b1f Copilot fixes 2026-02-15 01:57:26 +01:00
slawkens
4bc3923996 glob is not needed here 2026-02-15 01:20:11 +01:00
slawkens
8809467fc6 Delete debug output 2026-02-15 01:19:58 +01:00
slawkens
97ee430a91 Forgot about composer 2026-02-15 01:08:27 +01:00
slawkens
fc9d6b2b91 [WIP] Initial Blacktek support - groups, vocations, items
items.toml loading through custom parser - no .toml reader that I tested can read it
2026-02-15 00:54:18 +01:00
49 changed files with 1542 additions and 531 deletions

View File

@@ -86,12 +86,6 @@ Look: [Contributing](https://docs.my-aac.org/misc/contributing) in our wiki.
If you have a great idea or want to contribute to the project - visit our website at https://www.my-aac.org If you have a great idea or want to contribute to the project - visit our website at https://www.my-aac.org
## Project supported by JetBrains
Many thanks to Jetbrains for kindly providing a license for me to work on this and other open-source projects.
[![JetBrains](https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.svg)](https://www.jetbrains.com/?from=https://github.com/slawkens)
### License ### License
This program and all associated files are released under the GNU Public License. This program and all associated files are released under the GNU Public License.

View File

@@ -10,6 +10,7 @@
use MyAAC\Forum; use MyAAC\Forum;
use MyAAC\Models\Player; use MyAAC\Models\Player;
use MyAAC\Server\Outfits;
use MyAAC\Server\XML\Vocations; use MyAAC\Server\XML\Vocations;
defined('MYAAC') or die('Direct access not allowed!'); defined('MYAAC') or die('Direct access not allowed!');
@@ -659,14 +660,14 @@ else if (isset($_REQUEST['search'])) {
<div class="col-12 col-sm-12 col-lg-6"> <div class="col-12 col-sm-12 col-lg-6">
<label for="look_type" class="control-label">Type:</label> <label for="look_type" class="control-label">Type:</label>
<?php <?php
$outfitlist = null; $outfits = Outfits::get();
$outfitlist = Outfits_loadfromXML(); if ($outfits) { ?>
if ($outfitlist) { ?>
<select name="look_type" id="look_type" class="form-control custom-select"> <select name="look_type" id="look_type" class="form-control custom-select">
<?php <?php
foreach ($outfitlist as $_id => $outfit) { foreach ($outfits as $outfit) {
if ($outfit['enabled'] == 'yes') ; if ($outfit['enabled']) {
echo '<option value=' . $outfit['id'] . ($outfit['id'] == $player->getLookType() ? ' selected' : '') . '>' . $outfit['name'] . ' - ' . ($outfit['type'] == 1 ? 'Male' : 'Female') . '</option>'; echo '<option value=' . $outfit['id'] . ($outfit['id'] == $player->getLookType() ? ' selected' : '') . '>' . $outfit['name'] . ' - ' . ($outfit['sex'] == SEX_MALE ? 'Male' : 'Female') . '</option>';
}
} }
?> ?>
</select> </select>

View File

@@ -104,6 +104,8 @@ const OTSERV_FIRST = OTSERV;
const OTSERV_LAST = OTSERV_06; const OTSERV_LAST = OTSERV_06;
const TFS_02 = 3; const TFS_02 = 3;
const TFS_03 = 4; const TFS_03 = 4;
const BLACKTEK_2 = 5;
const BLACKTEK = 6;
const TFS_FIRST = TFS_02; const TFS_FIRST = TFS_02;
const TFS_LAST = TFS_03; const TFS_LAST = TFS_03;

View File

@@ -5,6 +5,7 @@
"ext-pdo_mysql": "*", "ext-pdo_mysql": "*",
"ext-json": "*", "ext-json": "*",
"ext-xml": "*", "ext-xml": "*",
"ext-simplexml": "*",
"ext-dom": "*", "ext-dom": "*",
"phpmailer/phpmailer": "^6.1", "phpmailer/phpmailer": "^6.1",
"composer/semver": "^3.2", "composer/semver": "^3.2",
@@ -19,7 +20,8 @@
"symfony/var-dumper": "^6.4", "symfony/var-dumper": "^6.4",
"filp/whoops": "^2.15", "filp/whoops": "^2.15",
"maximebf/debugbar": "1.*", "maximebf/debugbar": "1.*",
"guzzlehttp/guzzle": "7.9.3" "guzzlehttp/guzzle": "7.9.3",
"devium/toml": "^1.0"
}, },
"require-dev": { "require-dev": {
"phpstan/phpstan": "^1.10" "phpstan/phpstan": "^1.10"

127
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "5317e97a5025ebc2a977214bd3fa964c", "content-hash": "de1219601202cf55861809fd69c5feb4",
"packages": [ "packages": [
{ {
"name": "brick/math", "name": "brick/math",
@@ -216,6 +216,75 @@
], ],
"time": "2024-09-19T14:15:21+00:00" "time": "2024-09-19T14:15:21+00:00"
}, },
{
"name": "devium/toml",
"version": "1.0.6",
"source": {
"type": "git",
"url": "https://github.com/vanodevium/toml.git",
"reference": "190882f9d92e88f8031285129ba9df501da899a6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/vanodevium/toml/zipball/190882f9d92e88f8031285129ba9df501da899a6",
"reference": "190882f9d92e88f8031285129ba9df501da899a6",
"shasum": ""
},
"require": {
"ext-json": "*",
"php": ">=8.1",
"php-ds/php-ds": "^1.5",
"symfony/polyfill-mbstring": "^1.30"
},
"require-dev": {
"laravel/pint": "^1.17.3",
"pestphp/pest": "^2.35.1",
"phpstan/phpstan": "^1.12.2",
"rector/rector": "^1.2.4",
"symfony/var-dumper": "^6.4|^7.1.4"
},
"suggest": {
"ext-ds": "For best performance",
"ext-mbstring": "For best performance"
},
"type": "library",
"autoload": {
"files": [
"src/helpers.php"
],
"psr-4": {
"Devium\\Toml\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Vano Devium",
"email": "vano@devium.me"
}
],
"description": "A PHP encoder/decoder for TOML compatible with specification 1.0.0",
"keywords": [
"decode",
"encode",
"parser",
"toml"
],
"support": {
"issues": "https://github.com/vanodevium/toml/issues",
"source": "https://github.com/vanodevium/toml/tree/v1.0.6"
},
"funding": [
{
"url": "https://github.com/vanodevium",
"type": "github"
}
],
"time": "2025-04-22T18:10:54+00:00"
},
{ {
"name": "doctrine/inflector", "name": "doctrine/inflector",
"version": "2.0.10", "version": "2.0.10",
@@ -1615,6 +1684,62 @@
}, },
"time": "2021-04-22T21:32:03+00:00" "time": "2021-04-22T21:32:03+00:00"
}, },
{
"name": "php-ds/php-ds",
"version": "v1.7.0",
"source": {
"type": "git",
"url": "https://github.com/php-ds/polyfill.git",
"reference": "017fb5cdfa52a1f13126c94987b04b884c44f9cd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-ds/polyfill/zipball/017fb5cdfa52a1f13126c94987b04b884c44f9cd",
"reference": "017fb5cdfa52a1f13126c94987b04b884c44f9cd",
"shasum": ""
},
"require": {
"ext-json": "*",
"php": ">=7.4"
},
"provide": {
"ext-ds": "1.5.0"
},
"require-dev": {
"php-ds/tests": "^1.5"
},
"suggest": {
"ext-ds": "to improve performance and reduce memory usage"
},
"type": "library",
"autoload": {
"psr-4": {
"Ds\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Rudi Theunissen",
"email": "rudolf.theunissen@gmail.com"
}
],
"description": "Specialized data structures as alternatives to the PHP array",
"keywords": [
"data structures",
"ds",
"php",
"polyfill"
],
"support": {
"issues": "https://github.com/php-ds/polyfill/issues",
"source": "https://github.com/php-ds/polyfill/tree/v1.7.0"
},
"time": "2025-05-18T04:50:53+00:00"
},
{ {
"name": "phpmailer/phpmailer", "name": "phpmailer/phpmailer",
"version": "v6.9.3", "version": "v6.9.3",

View File

@@ -1,4 +1,7 @@
<?php <?php
use MyAAC\Server\Lua\Loader;
defined('MYAAC') or die('Direct access not allowed!'); defined('MYAAC') or die('Direct access not allowed!');
if(!isset($_SESSION['var_server_path'])) { if(!isset($_SESSION['var_server_path'])) {
@@ -11,13 +14,18 @@ $config['server_path'] = $_SESSION['var_server_path'];
if($config['server_path'][strlen($config['server_path']) - 1] != '/') if($config['server_path'][strlen($config['server_path']) - 1] != '/')
$config['server_path'] .= '/'; $config['server_path'] .= '/';
if((!isset($error) || !$error) && !file_exists($config['server_path'] . 'config.lua')) { $configLuaExists = file_exists($config['server_path'] . 'config.lua');
$configTomlExists = file_exists($config['server_path'] . 'config/server.toml');
if((!isset($error) || !$error)
&& !$configLuaExists
&& !$configTomlExists) {
error($locale['step_database_error_config']); error($locale['step_database_error_config']);
$error = true; $error = true;
} }
if (!isset($error) || !$error) { if (!isset($error) || !$error) {
$config['lua'] = load_config_lua($config['server_path'] . 'config.lua'); if($configLuaExists) {
$config['lua'] = Loader::load($config['server_path'] . 'config.lua');
if (isset($config['lua']['sqlType'])) // tfs 0.3 if (isset($config['lua']['sqlType'])) // tfs 0.3
$config['database_type'] = $config['lua']['sqlType']; $config['database_type'] = $config['lua']['sqlType'];
elseif (isset($config['lua']['mysqlHost'])) // tfs 0.2/1.0 elseif (isset($config['lua']['mysqlHost'])) // tfs 0.2/1.0
@@ -29,6 +37,13 @@ if(!isset($error) || !$error) {
else { else {
$config['database_type'] = ''; $config['database_type'] = '';
} }
}
elseif ($configTomlExists) {
$tomlConfig = new MyAAC\Server\TOML\Config();
$tomlConfig->load();
$config['server'] = $tomlConfig->get();
$config['database_type'] = (isset($config['server']['database']['mysql']) ? 'mysql' : '');
}
$config['database_type'] = strtolower($config['database_type']); $config['database_type'] = strtolower($config['database_type']);
if(empty($config['database_type'])) { if(empty($config['database_type'])) {

View File

@@ -1,5 +1,6 @@
<?php <?php
use MyAAC\Server\Config;
use Twig\Environment as Twig_Environment; use Twig\Environment as Twig_Environment;
use Twig\Loader\FilesystemLoader as Twig_FilesystemLoader; use Twig\Loader\FilesystemLoader as Twig_FilesystemLoader;
@@ -83,7 +84,7 @@ if($step == 'database') {
$config['server_path'] .= '/'; $config['server_path'] .= '/';
} }
if(!file_exists($config['server_path'] . 'config.lua')) { if(!Config::exists()) {
$errors[] = $locale['step_database_error_config']; $errors[] = $locale['step_database_error_config'];
break; break;
} }

View File

@@ -9,6 +9,8 @@
*/ */
defined('MYAAC') or die('Direct access not allowed!'); defined('MYAAC') or die('Direct access not allowed!');
use MyAAC\Server\Lua\Loader;
class Validator extends \MyAAC\Validator {} class Validator extends \MyAAC\Validator {}
function check_name($name, &$errors = '') { function check_name($name, &$errors = '') {
@@ -74,3 +76,77 @@ function fieldExist($field, $table)
global $db; global $db;
return $db->hasColumn($table, $field); return $db->hasColumn($table, $field);
} }
function Outfits_loadfromXML(): ?array
{
global $config;
$file_path = $config['data_path'] . 'XML/outfits.xml';
if (!file_exists($file_path)) { return null; }
$xml = new DOMDocument;
$xml->load($file_path);
$outfits = null;
foreach ($xml->getElementsByTagName('outfit') as $outfit) {
$outfits[] = Outfit_parseNode($outfit);
}
return $outfits;
}
function Outfit_parseNode($node): array
{
$looktype = (int)$node->getAttribute('looktype');
$type = (int)$node->getAttribute('type');
$lookname = $node->getAttribute('name');
$premium = $node->getAttribute('premium');
$unlocked = $node->getAttribute('unlocked');
$enabled = $node->getAttribute('enabled');
return array('id' => $looktype, 'type' => $type, 'name' => $lookname, 'premium' => $premium, 'unlocked' => $unlocked, 'enabled' => $enabled);
}
function Mounts_loadfromXML(): ?array
{
global $config;
$file_path = $config['data_path'] . 'XML/mounts.xml';
if (!file_exists($file_path)) { return null; }
$xml = new DOMDocument;
$xml->load($file_path);
$mounts = null;
foreach ($xml->getElementsByTagName('mount') as $mount) {
$mounts[] = Mount_parseNode($mount);
}
return $mounts;
}
function Mount_parseNode($node): array
{
$id = (int)$node->getAttribute('id');
$clientid = (int)$node->getAttribute('clientid');
$name = $node->getAttribute('name');
$speed = (int)$node->getAttribute('speed');
$premium = $node->getAttribute('premium');
$type = $node->getAttribute('type');
return array('id' => $id, 'clientid' => $clientid, 'name' => $name, 'speed' => $speed, 'premium' => $premium, 'type' => $type);
}
function load_config_lua(string $file): array
{
$result = Loader::load($file);
if ($result === false) {
log_append('error.log', '[load_config_file] Fatal error: Cannot load config.lua (' . $file . ').');
throw new \RuntimeException('ERROR: Cannot find ' . $file . ' file.');
}
return $result;
}
function configLua($key) {
global $config;
if (is_array($key)) {
return $config['lua'][$key[0]] = $key[1];
}
return @$config['lua'][$key];
}

View File

@@ -18,6 +18,19 @@ if (!isset($config['database_overwrite'])) {
if(!$config['database_overwrite'] && !isset($config['database_user'][0], $config['database_password'][0], $config['database_name'][0])) if(!$config['database_overwrite'] && !isset($config['database_user'][0], $config['database_password'][0], $config['database_name'][0]))
{ {
if (isset($config['server']['database']['mysql'])) { // BlackTek
$config['otserv_version'] = BLACKTEK;
$config['database_type'] = 'mysql';
$config['database_host'] = $config['server']['database']['mysql']['host'];
$config['database_port'] = $config['server']['database']['mysql']['port'];
$config['database_user'] = $config['server']['database']['mysql']['user'];
$config['database_password'] = $config['server']['database']['mysql']['pass'];
$config['database_name'] = $config['server']['database']['mysql']['database'];
if(!isset($config['database_socket'][0]) && !empty(trim($config['server']['database']['mysql']['socket']))) {
$config['database_socket'] = trim($config['server']['database']['mysql']['socket']);
}
$config['database_encryption'] = 'sha1';
}
if(isset($config['lua']['sqlType'])) {// tfs 0.3 if(isset($config['lua']['sqlType'])) {// tfs 0.3
if(isset($config['lua']['mysqlHost'])) {// tfs 0.2 if(isset($config['lua']['mysqlHost'])) {// tfs 0.2
$config['otserv_version'] = TFS_02; $config['otserv_version'] = TFS_02;
@@ -94,7 +107,6 @@ if(!isset($config['database_socket'])) {
$config['database_socket'] = ''; $config['database_socket'] = '';
} }
try { try {
$ots->connect(array( $ots->connect(array(
'host' => $config['database_host'], 'host' => $config['database_host'],

View File

@@ -11,7 +11,6 @@ defined('MYAAC') or die('Direct access not allowed!');
use MyAAC\Cache\Cache; use MyAAC\Cache\Cache;
use MyAAC\CsrfToken; use MyAAC\CsrfToken;
use MyAAC\Items;
use MyAAC\Models\Config; use MyAAC\Models\Config;
use MyAAC\Models\Guild; use MyAAC\Models\Guild;
use MyAAC\Models\House; use MyAAC\Models\House;
@@ -21,6 +20,7 @@ use MyAAC\Models\PlayerDeath;
use MyAAC\Models\PlayerKillers; use MyAAC\Models\PlayerKillers;
use MyAAC\News; use MyAAC\News;
use MyAAC\Plugins; use MyAAC\Plugins;
use MyAAC\Server\Items;
use MyAAC\Settings; use MyAAC\Settings;
use PHPMailer\PHPMailer\PHPMailer; use PHPMailer\PHPMailer\PHPMailer;
@@ -987,85 +987,6 @@ function log_append($file, $str, array $params = [])
fclose($f); fclose($f);
} }
function load_config_lua($filename)
{
global $config;
$config_file = $filename;
if(!@file_exists($config_file))
{
log_append('error.log', '[load_config_file] Fatal error: Cannot load config.lua (' . $filename . ').');
throw new RuntimeException('ERROR: Cannot find ' . $filename . ' file.');
}
$result = array();
$config_string = str_replace(array("\r\n", "\r"), "\n", file_get_contents($filename));
$lines = explode("\n", $config_string);
if(count($lines) > 0) {
foreach($lines as $ln => $line)
{
$line = trim($line);
if(isset($line[0]) && ($line[0] === '{' || $line[0] === '}')) {
// arrays are not supported yet
// just ignore the error
continue;
}
$tmp_exp = explode('=', $line, 2);
if(str_contains($line, 'dofile')) {
$delimiter = '"';
if(!str_contains($line, $delimiter)) {
$delimiter = "'";
}
$tmp = explode($delimiter, $line);
$result = array_merge($result, load_config_lua($config['server_path'] . $tmp[1]));
}
else if(count($tmp_exp) >= 2) {
$key = trim($tmp_exp[0]);
if(!str_starts_with($key, '--')) {
$value = trim($tmp_exp[1]);
if(str_contains($value, '--')) {// found some deep comment
$value = preg_replace('/--.*$/i', '', $value);
}
if(is_numeric($value))
$result[$key] = (float) $value;
elseif(in_array(@$value[0], array("'", '"')) && in_array(@$value[strlen($value) - 1], array("'", '"')))
$result[$key] = substr(substr($value, 1), 0, -1);
elseif(in_array($value, array('true', 'false')))
$result[$key] = $value === 'true';
elseif(@$value[0] === '{') {
// arrays are not supported yet
// just ignore the error
continue;
}
else
{
foreach($result as $tmp_key => $tmp_value) { // load values defined by other keys, like: dailyFragsToBlackSkull = dailyFragsToRedSkull
$value = str_replace($tmp_key, $tmp_value, $value);
}
try {
$ret = eval("return $value;");
}
catch (Throwable $e) {
throw new RuntimeException('ERROR: Loading config.lua file. Line: ' . ($ln + 1) . ' - Unable to parse value "' . $value . '" - ' . $e->getMessage());
}
if((string) $ret == '' && trim($value) !== '""') {
throw new RuntimeException('ERROR: Loading config.lua file. Line ' . ($ln + 1) . ' is not valid [key: ' . $key . ']');
}
$result[$key] = $ret;
}
}
}
}
}
return array_merge($result, $config['lua'] ?? []);
}
function str_replace_first($search,$replace, $subject) { function str_replace_first($search,$replace, $subject) {
$pos = strpos($subject, $search); $pos = strpos($subject, $search);
if ($pos !== false) { if ($pos !== false) {
@@ -1325,15 +1246,6 @@ function config($key) {
return @$config[$key]; return @$config[$key];
} }
function configLua($key) {
global $config;
if (is_array($key)) {
return $config['lua'][$key[0]] = $key[1];
}
return @$config['lua'][$key];
}
function setting($key) function setting($key)
{ {
$settings = Settings::getInstance(); $settings = Settings::getInstance();
@@ -1640,58 +1552,6 @@ function verify_number($number, $name, $max_length)
echo_error($name . ' cannot be longer than ' . $max_length . ' digits.'); echo_error($name . ' cannot be longer than ' . $max_length . ' digits.');
} }
function Outfits_loadfromXML()
{
global $config;
$file_path = $config['data_path'] . 'XML/outfits.xml';
if (!file_exists($file_path)) { return null; }
$xml = new DOMDocument;
$xml->load($file_path);
$outfits = null;
foreach ($xml->getElementsByTagName('outfit') as $outfit) {
$outfits[] = Outfit_parseNode($outfit);
}
return $outfits;
}
function Outfit_parseNode($node) {
$looktype = (int)$node->getAttribute('looktype');
$type = (int)$node->getAttribute('type');
$lookname = $node->getAttribute('name');
$premium = $node->getAttribute('premium');
$unlocked = $node->getAttribute('unlocked');
$enabled = $node->getAttribute('enabled');
return array('id' => $looktype, 'type' => $type, 'name' => $lookname, 'premium' => $premium, 'unlocked' => $unlocked, 'enabled' => $enabled);
}
function Mounts_loadfromXML()
{
global $config;
$file_path = $config['data_path'] . 'XML/mounts.xml';
if (!file_exists($file_path)) { return null; }
$xml = new DOMDocument;
$xml->load($file_path);
$mounts = null;
foreach ($xml->getElementsByTagName('mount') as $mount) {
$mounts[] = Mount_parseNode($mount);
}
return $mounts;
}
function Mount_parseNode($node) {
$id = (int)$node->getAttribute('id');
$clientid = (int)$node->getAttribute('clientid');
$name = $node->getAttribute('name');
$speed = (int)$node->getAttribute('speed');
$premium = $node->getAttribute('premium');
$type = $node->getAttribute('type');
return array('id' => $id, 'clientid' => $clientid, 'name' => $name, 'speed' => $speed, 'premium' => $premium, 'type' => $type);
}
function left($str, $length) { function left($str, $length) {
return substr($str, 0, $length); return substr($str, 0, $length);
} }

View File

@@ -14,7 +14,8 @@ use MyAAC\CsrfToken;
use MyAAC\Hooks; use MyAAC\Hooks;
use MyAAC\Plugins; use MyAAC\Plugins;
use MyAAC\Models\Town; use MyAAC\Models\Town;
use MyAAC\Server\XML\Vocations; use MyAAC\Server\Config;
use MyAAC\Server\Vocations;
use MyAAC\Settings; use MyAAC\Settings;
defined('MYAAC') or die('Direct access not allowed!'); defined('MYAAC') or die('Direct access not allowed!');
@@ -90,28 +91,20 @@ foreach($_REQUEST as $var => $value) {
} }
// load otserv config file // load otserv config file
$config_lua_reload = true;
if($cache->enabled()) { if($cache->enabled()) {
$tmp = null; $tmp = null;
if($cache->fetch('server_path', $tmp) && $tmp == $config['server_path']) { if(!$cache->fetch('server_path', $tmp) || $tmp != config('server_path')) {
$tmp = null; $cache->delete('config_server');
if($cache->fetch('config_lua', $tmp) && $tmp) {
$config['lua'] = unserialize($tmp);
$config_lua_reload = false;
}
} }
} }
if($config_lua_reload) { if (empty($config['server'])) {
$config['lua'] = load_config_lua($config['server_path'] . 'config.lua'); $config['server'] = $config['lua'] = Config::get();
// cache config
if($cache->enabled()) { if($cache->enabled()) {
$cache->set('config_lua', serialize($config['lua']), 2 * 60); $cache->set('server_path', config('server_path'), 10 * 60);
$cache->set('server_path', $config['server_path'], 10 * 60);
} }
} }
unset($tmp);
if(isset($config['lua']['servername'])) if(isset($config['lua']['servername']))
$config['lua']['serverName'] = $config['lua']['servername']; $config['lua']['serverName'] = $config['lua']['servername'];

View File

@@ -8,7 +8,7 @@
* @license http://www.gnu.org/licenses/lgpl-3.0.txt GNU Lesser General Public License, Version 3 * @license http://www.gnu.org/licenses/lgpl-3.0.txt GNU Lesser General Public License, Version 3
*/ */
use MyAAC\Cache\Cache; use MyAAC\Server\Groups;
/** /**
* List of groups. * List of groups.
@@ -47,74 +47,9 @@ class OTS_Groups_List implements IteratorAggregate, Countable
return; return;
} }
if(!isset($file[0])) foreach(Groups::get() as $id => $info) {
{
global $config;
$file = $config['data_path'] . 'XML/groups.xml';
}
if(!@file_exists($file)) {
error('Error: Cannot load groups.xml. More info in system/logs/error.log file.');
log_append('error.log', '[OTS_Groups_List.php] Fatal error: Cannot load groups.xml (' . $file . '). It doesnt exist.');
return;
}
$cache = Cache::getInstance();
$data = array();
if($cache->enabled())
{
$tmp = '';
if($cache->fetch('groups', $tmp))
$data = unserialize($tmp);
else
{
$groups = new DOMDocument();
if(!@$groups->load($file)) {
error('Error: Cannot load groups.xml. More info in system/logs/error.log file.');
log_append('error.log', '[OTS_Groups_List.php] Fatal error: Cannot load groups.xml (' . $file . '). Error: ' . print_r(error_get_last(), true));
return;
}
// loads groups
foreach( $groups->getElementsByTagName('group') as $group)
{
$data[$group->getAttribute('id')] = array(
'id' => $group->getAttribute('id'),
'name' => $group->getAttribute('name'),
'access' => $group->getAttribute('access')
);
}
$cache->set('groups', serialize($data), 120);
}
foreach($data as $id => $info)
$this->groups[$id] = new OTS_Group($info); $this->groups[$id] = new OTS_Group($info);
} }
else
{
// loads DOM document
$groups = new DOMDocument();
if(!@$groups->load($file)) {
error('Error: Cannot load groups.xml. More info in system/logs/error.log file.');
log_append('error.log', '[OTS_Groups_List.php] Fatal error: Cannot load groups.xml (' . $file . '). Error: ' . print_r(error_get_last(), true));
return;
}
// loads groups
foreach($groups->getElementsByTagName('group') as $group)
{
$data[$group->getAttribute('id')] = array(
'id' => $group->getAttribute('id'),
'name' => $group->getAttribute('name'),
'access' => $group->getAttribute('access')
);
$this->groups[ $group->getAttribute('id') ] = new OTS_Group($data[$group->getAttribute('id')]);
//echo $this->getGroup(1)->getName();
}
}
} }
/** /**

View File

@@ -67,7 +67,7 @@ $locale['step_database'] = 'Schema importieren';
$locale['step_database_title'] = 'MySQL schema importieren'; $locale['step_database_title'] = 'MySQL schema importieren';
$locale['step_database_importing'] = 'Ihre Datenbank ist MySQL. Datenbankname ist: "$DATABASE_NAME$". Schema wird jetzt importiert...'; $locale['step_database_importing'] = 'Ihre Datenbank ist MySQL. Datenbankname ist: "$DATABASE_NAME$". Schema wird jetzt importiert...';
$locale['step_database_error_path'] = 'Bitte geben Sie den Serverpfad an.'; $locale['step_database_error_path'] = 'Bitte geben Sie den Serverpfad an.';
$locale['step_database_error_config'] = 'Datei config.lua kann nicht gefunden werden. Ist der Serverpfad korrekt? Gehen Sie zurück und überprüfen Sie noch einmal.'; $locale['step_database_error_config'] = 'Datei config.lua oder config/server.toml kann nicht gefunden werden. Ist der Serverpfad korrekt? Gehen Sie zurück und überprüfen Sie noch einmal.';
$locale['step_database_error_database_empty'] = 'Der Datenbanktyp kann nicht aus config.lua ermittelt werden. Ihr OTS wird von diesem AAC nicht unterstützt.'; $locale['step_database_error_database_empty'] = 'Der Datenbanktyp kann nicht aus config.lua ermittelt werden. Ihr OTS wird von diesem AAC nicht unterstützt.';
$locale['step_database_error_only_mysql'] = 'Dieser AAC unterstützt nur MySQL. Aus Ihrer Konfigurationsdatei scheint Ihr OTS die Datenbank $DATABASE_TYPE$ zu verwenden. Bitte ändern Sie Ihre Datenbank in MySQL und folgen Sie dann der Installation erneut.'; $locale['step_database_error_only_mysql'] = 'Dieser AAC unterstützt nur MySQL. Aus Ihrer Konfigurationsdatei scheint Ihr OTS die Datenbank $DATABASE_TYPE$ zu verwenden. Bitte ändern Sie Ihre Datenbank in MySQL und folgen Sie dann der Installation erneut.';
$locale['step_database_error_table'] = 'Die Tabelle $TABLE$ existiert nicht. Bitte importieren Sie zuerst Ihr OTS-Datenbankschema.'; $locale['step_database_error_table'] = 'Die Tabelle $TABLE$ existiert nicht. Bitte importieren Sie zuerst Ihr OTS-Datenbankschema.';

View File

@@ -72,7 +72,7 @@ $locale['step_database_title'] = 'Import MySQL schema';
$locale['step_database_importing'] = 'Your database is MySQL. Database name is: "$DATABASE_NAME$". Importing schema now...'; $locale['step_database_importing'] = 'Your database is MySQL. Database name is: "$DATABASE_NAME$". Importing schema now...';
$locale['step_database_config_saved'] = 'Local configuration has been saved into file: config.local.php'; $locale['step_database_config_saved'] = 'Local configuration has been saved into file: config.local.php';
$locale['step_database_error_path'] = 'Please specify server path.'; $locale['step_database_error_path'] = 'Please specify server path.';
$locale['step_database_error_config'] = 'Cannot find config.lua file. Is your server path correct? Go back and check again.'; $locale['step_database_error_config'] = 'Cannot find config.lua or config/server.toml file. Is your server path correct? Go back and check again.';
$locale['step_database_error_database_empty'] = 'Cannot determine database type from config.lua. Your OTS is unsupported by this AAC.'; $locale['step_database_error_database_empty'] = 'Cannot determine database type from config.lua. Your OTS is unsupported by this AAC.';
$locale['step_database_error_only_mysql'] = 'This AAC supports only MySQL. From your config file it seems that your OTS is using: $DATABASE_TYPE$ database. Please change your database to MySQL and then follow the installation again.'; $locale['step_database_error_only_mysql'] = 'This AAC supports only MySQL. From your config file it seems that your OTS is using: $DATABASE_TYPE$ database. Please change your database to MySQL and then follow the installation again.';
$locale['step_database_error_table'] = 'Table $TABLE$ doesn\'t exist. Please import your OTS database schema first.'; $locale['step_database_error_table'] = 'Table $TABLE$ doesn\'t exist. Please import your OTS database schema first.';

View File

@@ -71,7 +71,7 @@ $locale['step_database_title'] = 'Baza MySQL';
$locale['step_database_importing'] = 'Twoja baza to MySQL. Nazwa bazy danych to: "$DATABASE_NAME$". Importowanie schematu...'; $locale['step_database_importing'] = 'Twoja baza to MySQL. Nazwa bazy danych to: "$DATABASE_NAME$". Importowanie schematu...';
$locale['step_database_config_saved'] = 'Lokalna konfiguracja została zapisana do pliku: config.local.php'; $locale['step_database_config_saved'] = 'Lokalna konfiguracja została zapisana do pliku: config.local.php';
$locale['step_database_error_path'] = 'Proszę podać ścieżkę do serwera.'; $locale['step_database_error_path'] = 'Proszę podać ścieżkę do serwera.';
$locale['step_database_error_config'] = 'Nie można znaleźć pliku config.lua. Czy ścieżka do katalogu serwera jest poprawna? Wróć się i sprawdź ponownie.'; $locale['step_database_error_config'] = 'Nie można znaleźć pliku config.lua lub config/server.toml. Czy ścieżka do katalogu serwera jest poprawna? Wróć się i sprawdź ponownie.';
$locale['step_database_error_database_empty'] = 'Nie można wykryć typu bazy danych z pliku config.lua. Prawdopodobnie Twój OTS nie jest wspierany przez ten AAC.'; $locale['step_database_error_database_empty'] = 'Nie można wykryć typu bazy danych z pliku config.lua. Prawdopodobnie Twój OTS nie jest wspierany przez ten AAC.';
$locale['step_database_error_only_mysql'] = 'Ten AAC wspiera tylko bazy danych MySQL. Z Twojego pliku config wynika, że Twój serwera używa bazy: $DATABASE_TYPE$. Proszę zmienić typ bazy na MySQL i ponownie przystąpić do instalacji.'; $locale['step_database_error_only_mysql'] = 'Ten AAC wspiera tylko bazy danych MySQL. Z Twojego pliku config wynika, że Twój serwera używa bazy: $DATABASE_TYPE$. Proszę zmienić typ bazy na MySQL i ponownie przystąpić do instalacji.';
$locale['step_database_error_table'] = 'Tabela $TABLE$ nie istnieje. Proszę najpierw zaimportować schemat bazy danych serwera OTS.'; $locale['step_database_error_table'] = 'Tabela $TABLE$ nie istnieje. Proszę najpierw zaimportować schemat bazy danych serwera OTS.';

View File

@@ -61,7 +61,7 @@ $locale['step_database'] = 'Importar schema';
$locale['step_database_title'] = 'Importar MySQL schema'; $locale['step_database_title'] = 'Importar MySQL schema';
$locale['step_database_importing'] = 'Seu banco de dados é o MySQL. O nome do banco de dados é: "$DATABASE_NAME$". Importando schema agora...'; $locale['step_database_importing'] = 'Seu banco de dados é o MySQL. O nome do banco de dados é: "$DATABASE_NAME$". Importando schema agora...';
$locale['step_database_error_path'] = 'Por favor, especifique o caminho da pasta do servidor.'; $locale['step_database_error_path'] = 'Por favor, especifique o caminho da pasta do servidor.';
$locale['step_database_error_config'] = 'Não é possível encontrar o arquivo config.lua. O caminho da pasta do seu servidor está correto? Volte e verifique novamente.'; $locale['step_database_error_config'] = 'Não é possível encontrar o arquivo config.lua ou config/server.toml. O caminho da pasta do seu servidor está correto? Volte e verifique novamente.';
$locale['step_database_error_database_empty'] = 'Não é possível determinar o tipo de banco de dados a partir do config.lua. Seu OTS não é suportado por este AAC.'; $locale['step_database_error_database_empty'] = 'Não é possível determinar o tipo de banco de dados a partir do config.lua. Seu OTS não é suportado por este AAC.';
$locale['step_database_error_only_mysql'] = 'Este AAC suporta apenas o MySQL. A partir do seu arquivo de configuração, parece que o seu OTS está usando: $DATABASE_TYPE$ database. Por favor, mude seu banco de dados para o MySQL e siga a instalação novamente.'; $locale['step_database_error_only_mysql'] = 'Este AAC suporta apenas o MySQL. A partir do seu arquivo de configuração, parece que o seu OTS está usando: $DATABASE_TYPE$ database. Por favor, mude seu banco de dados para o MySQL e siga a instalação novamente.';
$locale['step_database_error_table'] = 'A tabela $TABLE$ não existe. Por favor, importe seu schema de banco de dados OTS primeiro.'; $locale['step_database_error_table'] = 'A tabela $TABLE$ não existe. Por favor, importe seu schema de banco de dados OTS primeiro.';

View File

@@ -11,22 +11,22 @@
defined('MYAAC') or die('Direct access not allowed!'); defined('MYAAC') or die('Direct access not allowed!');
$title = 'Experience Stages'; $title = 'Experience Stages';
if((!isset($config['lua']['experienceStages']) || !getBoolean($config['lua']['experienceStages']))
&& (!isset($config['lua']['rateUseStages']) || !getBoolean($config['lua']['rateUseStages']))
) {
$enabled = false;
if(file_exists($config['data_path'] . 'XML/stages.xml')) { if(file_exists($config['data_path'] . 'XML/stages.xml')) {
$stages = new DOMDocument(); $stages = new DOMDocument();
$stages->load($config['data_path'] . 'XML/stages.xml'); $stages->load($config['data_path'] . 'XML/stages.xml');
}
if(!isset($config['lua']['experienceStages']) || !getBoolean($config['lua']['experienceStages']))
{
$enabled = false;
if(isset($stages)) {
foreach($stages->getElementsByTagName('config') as $node) { foreach($stages->getElementsByTagName('config') as $node) {
/** @var DOMElement $node */ /** @var DOMElement $node */
if($node->getAttribute('enabled')) if($node->getAttribute('enabled')) {
$enabled = true; $enabled = true;
} }
} }
}
if(!$enabled) { if(!$enabled) {
$rate_exp = 'not set'; $rate_exp = 'not set';
@@ -42,21 +42,12 @@ if(!isset($config['lua']['experienceStages']) || !getBoolean($config['lua']['exp
} }
} }
if(!$stages) $stages = new MyAAC\Server\ExpStages();
{ $stagesArray = $stages->get();
echo 'Error: cannot load <b>stages.xml</b>!';
if (empty($stagesArray)) {
echo 'Error when loading experience stages.';
return; return;
} }
$stagesArray = [];
foreach($stages->getElementsByTagName('stage') as $stage)
{
/** @var DOMElement $stage */
$maxLevel = $stage->getAttribute('maxlevel');
$stagesArray[] = [
'levels' => $stage->getAttribute('minlevel') . (isset($maxLevel[0]) ? '-' . $maxLevel : '+'),
'multiplier' => $stage->getAttribute('multiplier')
];
}
$twig->display('experience_stages.html.twig', ['stages' => $stagesArray]); $twig->display('experience_stages.html.twig', ['stages' => $stagesArray]);

View File

@@ -13,7 +13,7 @@ use MyAAC\Cache\Cache;
use MyAAC\Models\Player; use MyAAC\Models\Player;
use MyAAC\Models\PlayerDeath; use MyAAC\Models\PlayerDeath;
use MyAAC\Models\PlayerKillers; use MyAAC\Models\PlayerKillers;
use MyAAC\Server\XML\Vocations; use MyAAC\Server\Vocations;
defined('MYAAC') or die('Direct access not allowed!'); defined('MYAAC') or die('Direct access not allowed!');
$title = 'Highscores'; $title = 'Highscores';

View File

@@ -12,7 +12,7 @@
use MyAAC\Cache\Cache; use MyAAC\Cache\Cache;
use MyAAC\Models\ServerConfig; use MyAAC\Models\ServerConfig;
use MyAAC\Models\ServerRecord; use MyAAC\Models\ServerRecord;
use MyAAC\Server\XML\Vocations; use MyAAC\Server\Vocations;
defined('MYAAC') or die('Direct access not allowed!'); defined('MYAAC') or die('Direct access not allowed!');
$title = 'Who is online?'; $title = 'Who is online?';
@@ -87,13 +87,16 @@ $cached = Cache::remember("online_$order", setting('core.online_cache_ttl') * 60
'name' => getPlayerLink($player['name']), 'name' => getPlayerLink($player['name']),
'player' => $player, 'player' => $player,
'level' => $player['level'], 'level' => $player['level'],
'vocation' => $configVocations[$player['vocation']], 'vocation' => $configVocations[$player['vocation']] ?? 'Unknown',
'skull' => $skull, 'skull' => $skull,
'country_image' => getFlagImage($player['country']), 'country_image' => getFlagImage($player['country']),
'outfit' => setting('core.outfit_images_url') . '?id=' . $player['looktype'] . ($outfit_addons ? '&addons=' . $player['lookaddons'] : '') . '&head=' . $player['lookhead'] . '&body=' . $player['lookbody'] . '&legs=' . $player['looklegs'] . '&feet=' . $player['lookfeet'], 'outfit' => setting('core.outfit_images_url') . '?id=' . $player['looktype'] . ($outfit_addons ? '&addons=' . $player['lookaddons'] : '') . '&head=' . $player['lookhead'] . '&body=' . $player['lookbody'] . '&legs=' . $player['looklegs'] . '&feet=' . $player['lookfeet'],
); );
$vocations[Vocations::getOriginal($player['vocation'])]++; $originalId = Vocations::getOriginal($player['vocation']);
if ($originalId) {
$vocations[$originalId]++;
}
} }
$record = ''; $record = '';

View File

@@ -12,6 +12,7 @@
*/ */
use MyAAC\Cache; use MyAAC\Cache;
use MyAAC\Server\Config;
use MyAAC\Settings; use MyAAC\Settings;
$templates = Cache::remember('templates', 5 * 60, function () { $templates = Cache::remember('templates', 5 * 60, function () {
@@ -1802,8 +1803,8 @@ Sent by MyAAC,<br/>
// test config.lua existence // test config.lua existence
// if fail - revert the setting and inform the user // if fail - revert the setting and inform the user
if (!file_exists($server_path . 'config.lua')) { if (!Config::exists()) {
error('Server Path is invalid - cannot find config.lua in the directory. Setting have been reverted.'); error('Server Path is invalid - cannot find config.lua or config/server.toml in the directory. Setting have been reverted.');
$configToSave['server_path'] = $configOriginal['server_path']; $configToSave['server_path'] = $configOriginal['server_path'];
} }

View File

@@ -2,6 +2,7 @@
namespace MyAAC\Commands; namespace MyAAC\Commands;
use MyAAC\Server\Config;
use POT; use POT;
trait Env trait Env
@@ -21,7 +22,7 @@ trait Env
if($config['server_path'][strlen($config['server_path']) - 1] !== '/') if($config['server_path'][strlen($config['server_path']) - 1] !== '/')
$config['server_path'] .= '/'; $config['server_path'] .= '/';
$config['lua'] = load_config_lua($config['server_path'] . 'config.lua'); $config['server'] = $config['lua'] = Config::get();
// POT // POT
require_once SYSTEM . 'libs/pot/OTS.php'; require_once SYSTEM . 'libs/pot/OTS.php';

View File

@@ -27,6 +27,7 @@ namespace MyAAC;
use MyAAC\Cache\Cache; use MyAAC\Cache\Cache;
use MyAAC\Models\Town; use MyAAC\Models\Town;
use MyAAC\Server\Items;
class DataLoader class DataLoader
{ {
@@ -40,7 +41,7 @@ class DataLoader
{ {
self::$startTime = microtime(true); self::$startTime = microtime(true);
if(Items::loadFromXML()) { if(Items::load()) {
success(self::$locale['step_database_loaded_items'] . self::getLoadedTime()); success(self::$locale['step_database_loaded_items'] . self::getLoadedTime());
} }
else { else {

View File

@@ -1,172 +1,14 @@
<?php <?php
/** /**
* Items class * @deprecated
* * This class is deprecated and will be removed in future versions. Please use the appropriate MyAAC\Server\Items class instead.
* @package MyAAC
* @author Gesior <jerzyskalski@wp.pl>
* @author Slawkens <slawkens@gmail.com>
* @copyright 2019 MyAAC
* @link https://my-aac.org
*/ */
namespace MyAAC; namespace MyAAC;
use MyAAC\Cache\PHP as CachePHP; class Items extends Server\Items
use MyAAC\Models\Spell;
class Items
{ {
private static $error = ''; public static function load(): bool {
public static $items; parent::init();
public static function loadFromXML($show = false)
{
$file_path = config('data_path') . 'items/items.xml';
if (!file_exists($file_path)) {
self::$error = 'Cannot load file ' . $file_path;
return false;
}
$xml = new \DOMDocument;
$xml->load($file_path);
$items = array();
foreach ($xml->getElementsByTagName('item') as $item) {
if ($item->getAttribute('fromid')) {
for ($id = $item->getAttribute('fromid'); $id <= $item->getAttribute('toid'); $id++) {
$tmp = self::parseNode($id, $item, $show);
$items[$tmp['id']] = $tmp['content'];
}
} else {
$tmp = self::parseNode($item->getAttribute('id'), $item, $show);
$items[$tmp['id']] = $tmp['content'];
}
}
$cache_php = new CachePHP(config('cache_prefix'), CACHE . 'persistent/');
$cache_php->set('items', $items, 5 * 365 * 24 * 60 * 60);
return true; return true;
} }
public static function parseNode($id, $node, $show = false) {
$name = $node->getAttribute('name');
$article = $node->getAttribute('article');
$plural = $node->getAttribute('plural');
$attributes = array();
foreach($node->getElementsByTagName('attribute') as $attr) {
$attributes[strtolower($attr->getAttribute('key'))] = $attr->getAttribute('value');
}
return array('id' => $id, 'content' => array('article' => $article, 'name' => $name, 'plural' => $plural, 'attributes' => $attributes));
}
public static function getError() {
return self::$error;
}
public static function load() {
if(self::$items) {
return;
}
$cache_php = new CachePHP(config('cache_prefix'), CACHE . 'persistent/');
self::$items = $cache_php->get('items');
}
public static function get($id) {
self::load();
return self::$items[$id] ?? [];
}
public static function getDescription($id, $count = 1): string
{
$item = self::get($id);
$attr = $item['attributes'];
$s = '';
if(!empty($item['name'])) {
if($count > 1) {
if($attr['showcount']) {
$s .= $count . ' ';
}
if(!empty($item['plural'])) {
$s .= $item['plural'];
}
else if((int)$attr['showcount'] == 0) {
$s .= $item['name'];
}
else {
$s .= $item['name'] . 's';
}
}
else {
if(!empty($item['aticle'])) {
$s .= $item['article'] . ' ';
}
$s .= $item['name'];
}
}
else
$s .= 'an item of type ' . $item['id'];
if(isset($attr['type']) && strtolower($attr['type']) == 'rune') {
$spell = Spell::where('item_id', $id)->first();
if($spell) {
if($spell->level > 0 && $spell->maglevel > 0) {
$s .= '. ' . ($count > 1 ? 'They' : 'It') . ' can only be used by ';
}
$configVocations = config('vocations');
if(!empty(trim($spell->vocations))) {
$vocations = json_decode($spell->vocations);
if(count($vocations) > 0) {
foreach($vocations as $voc => $show) {
$vocations[$configVocations[$voc]] = $show;
}
}
}
else {
$s .= 'players';
}
$s .= ' with';
if ($spell->level > 0) {
$s .= ' level ' . $spell->level;
}
if ($spell->maglevel > 0) {
if ($spell->level > 0) {
$s .= ' and';
}
$s .= ' magic level ' . $spell->maglevel;
}
$s .= ' or higher';
}
}
if (!empty($item['weaponType'])) {
if ($item['weaponType'] == 'distance' && isset($item['ammoType'])) {
$s .= ' (Range:' . $item['range'];
}
if (isset($item['attack']) && $item['attack'] != 0) {
$s .= ', Atk ' . ($item['attack'] > 0 ? '+' . $item['attack'] : '-' . $item['attack']);
}
if (isset($item['hitChance']) && $item['hitChance'] != -1) {
$s .= ', Hit% ' . ($item['hitChance'] > 0 ? '+' . $item['hitChance'] : '-' . $item['hitChance']);
}
elseif ($item['weaponType'] != 'ammo') {
}
}
return $s;
}
} }

View File

@@ -12,13 +12,11 @@
namespace MyAAC; namespace MyAAC;
use MyAAC\Models\Monster; use MyAAC\Models\Monster;
use MyAAC\Server\Items;
class Monsters { class Monsters {
/** private static \OTS_MonstersList $monstersList;
* @var \OTS_MonstersList private static string $lastError = '';
*/
private static $monstersList;
private static $lastError = '';
public static function loadFromXML($show = false) { public static function loadFromXML($show = false) {
try { try {
@@ -39,7 +37,7 @@ class Monsters {
} }
$items = array(); $items = array();
Items::load(); Items::init();
foreach((array)Items::$items as $id => $item) { foreach((array)Items::$items as $id => $item) {
$items[$item['name']] = $id; $items[$item['name']] = $id;
} }

View File

@@ -0,0 +1,28 @@
<?php
namespace MyAAC\Server;
use MyAAC\Cache\Cache;
class Config
{
public static function get()
{
return Cache::remember('config_server', 10 * 60, function () {
if (file_exists(config('server_path') . Lua\Config::FILE)) {
$config = new Lua\Config();
}
else {
$config = new TOML\Config();
}
$config->load();
return $config->get();
});
}
public static function exists(): bool {
return file_exists(config('server_path') . Lua\Config::FILE) || file_exists(config('server_path') . 'config/server.toml');
}
}

View File

@@ -0,0 +1,35 @@
<?php
namespace MyAAC\Server;
use MyAAC\Cache\Cache;
class ExpStages
{
private static array $stages = [];
public static function get() {
if (count(self::$stages) == 0) {
self::$stages = Cache::remember('exp_stages', 10 * 60, function () {
if (file_exists(config('server_path') . TOML\ExpStages::FILE)) {
$expStages = new TOML\ExpStages();
}
elseif (file_exists(config('data_path') . XML\ExpStages::FILE)) {
$expStages = new XML\ExpStages();
}
elseif (file_exists(config('data_path') . Lua\ExpStages::FILE)) {
$expStages = new Lua\ExpStages();
}
else {
return [];
}
$expStages->load();
return $expStages->get();
});
}
return self::$stages;
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace MyAAC\Server;
use MyAAC\Cache\Cache;
class Groups
{
private static array $groups = [];
public static function get() {
if (count(self::$groups) == 0) {
self::$groups = Cache::remember('groups', 10 * 60, function () {
if (file_exists(config('server_path') . TOML\Groups::FILE)) {
$groups = new TOML\Groups();
}
else {
$groups = new XML\Groups();
}
$groups->load();
return $groups->get();
});
}
return self::$groups;
}
}

154
system/src/Server/Items.php Normal file
View File

@@ -0,0 +1,154 @@
<?php
/**
* Items class
*
* @package MyAAC
* @author Gesior <jerzyskalski@wp.pl>
* @author Slawkens <slawkens@gmail.com>
* @copyright 2019 MyAAC
* @link https://my-aac.org
*/
namespace MyAAC\Server;
use MyAAC\Cache\PHP as CachePHP;
use MyAAC\Models\Spell;
class Items
{
public static array $items = [];
private static string $error = '';
const FILE_ITEMS_TOML = 'items/items.toml';
const FILE_ITEMS_XML = 'items/items.xml';
public static function getError(): string {
return self::$error;
}
public static function load(): bool {
if (file_exists(config('data_path') . self::FILE_ITEMS_TOML)) {
$items = new TOML\Items();
}
elseif (file_exists(config('data_path') . self::FILE_ITEMS_XML)) {
$items = new XML\Items();
}
else {
self::$error = 'Cannot load items.xml or items.toml file. Files not found.';
return false;
}
if (!$items->load()) {
self::$error = $items->getError();
return false;
}
return true;
}
public static function init(): void {
if(count(self::$items) > 0) {
return;
}
$cache_php = new CachePHP(config('cache_prefix'), CACHE . 'persistent/');
self::$items = (array)$cache_php->get('items');
}
public static function get($id) {
self::init();
return self::$items[$id] ?? [];
}
public static function getDescription($id, $count = 1): string
{
$item = self::get($id);
$attr = $item['attributes'];
$s = '';
if(!empty($item['name'])) {
if($count > 1) {
if($attr['showcount']) {
$s .= $count . ' ';
}
if(!empty($item['plural'])) {
$s .= $item['plural'];
}
else if((int)$attr['showcount'] == 0) {
$s .= $item['name'];
}
else {
$s .= $item['name'] . 's';
}
}
else {
if(!empty($item['aticle'])) {
$s .= $item['article'] . ' ';
}
$s .= $item['name'];
}
}
else
$s .= 'an item of type ' . $item['id'];
if(isset($attr['type']) && strtolower($attr['type']) == 'rune') {
$spell = Spell::where('item_id', $id)->first();
if($spell) {
if($spell->level > 0 && $spell->maglevel > 0) {
$s .= '. ' . ($count > 1 ? 'They' : 'It') . ' can only be used by ';
}
$configVocations = config('vocations');
if(!empty(trim($spell->vocations))) {
$vocations = json_decode($spell->vocations);
if(count($vocations) > 0) {
foreach($vocations as $voc => $show) {
$vocations[$configVocations[$voc]] = $show;
}
}
}
else {
$s .= 'players';
}
$s .= ' with';
if ($spell->level > 0) {
$s .= ' level ' . $spell->level;
}
if ($spell->maglevel > 0) {
if ($spell->level > 0) {
$s .= ' and';
}
$s .= ' magic level ' . $spell->maglevel;
}
$s .= ' or higher';
}
}
if (!empty($item['weaponType'])) {
if ($item['weaponType'] == 'distance' && isset($item['ammoType'])) {
$s .= ' (Range:' . $item['range'];
}
if (isset($item['attack']) && $item['attack'] != 0) {
$s .= ', Atk ' . ($item['attack'] > 0 ? '+' . $item['attack'] : '-' . $item['attack']);
}
if (isset($item['hitChance']) && $item['hitChance'] != -1) {
$s .= ', Hit% ' . ($item['hitChance'] > 0 ? '+' . $item['hitChance'] : '-' . $item['hitChance']);
}
elseif ($item['weaponType'] != 'ammo') {
}
}
return $s;
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace MyAAC\Server\Lua;
class Config
{
const FILE = 'config.lua';
private array $config = [];
public function load(): void
{
$file = config('server_path') . self::FILE;
$this->config = Loader::load($file);
if($this->config === false) {
log_append('error.log', '[Config] Fatal error: Cannot load config.lua (' . $file . ').');
throw new \RuntimeException('ERROR: Cannot find ' . $file . ' file.');
}
}
public function get(): array {
return $this->config;
}
}

View File

@@ -0,0 +1,46 @@
<?php
namespace MyAAC\Server\Lua;
class ExpStages
{
private array $stages = [];
const FILE = 'stages.lua';
public function load(): void
{
$file = config('data_path') . self::FILE;
if(!@file_exists($file)) {
return;
}
if (!extension_loaded('lua')) {
return;
}
$lua = new \Lua();
try {
$stagesContent = file_get_contents($file);
$stagesContent .= 'return experienceStages';
$stages = $lua->eval($stagesContent);
}
catch (\Exception $e) {
error('Error: Cannot load stages.lua. More info in system/logs/error.log file.');
log_append('error.log', "[" . __CLASS__ . "] Fatal error: Cannot load stages.lua - $file. Error: " . $e->getMessage());
return;
}
foreach ($stages as $stage) {
$this->stages[] = [
'levels' => $stage['minlevel'] . (isset($stage['maxlevel']) ? '-' . $stage['maxlevel'] : '+'),
'multiplier' => $stage['multiplier']
];
}
}
public function get(): array {
return $this->stages;
}
}

View File

@@ -0,0 +1,79 @@
<?php
namespace MyAAC\Server\Lua;
class Loader
{
public static function load($file): bool|array
{
if(!@file_exists($file)){
return false;
}
$result = [];
$config_string = str_replace(array("\r\n", "\r"), "\n", file_get_contents($file));
$lines = explode("\n", $config_string);
if(count($lines) > 0) {
foreach($lines as $ln => $line) {
$line = trim($line);
if(isset($line[0]) && ($line[0] === '{' || $line[0] === '}')) {
// arrays are not supported yet
// just ignore the error
continue;
}
$tmp_exp = explode('=', $line, 2);
if(str_contains($line, 'dofile')) {
$delimiter = '"';
if(!str_contains($line, $delimiter)) {
$delimiter = "'";
}
$tmp = explode($delimiter, $line);
$result = array_merge($result, self::load(config('server_path') . $tmp[1]));
}
else if(count($tmp_exp) >= 2) {
$key = trim($tmp_exp[0]);
if(!str_starts_with($key, '--')) {
$value = trim($tmp_exp[1]);
if(str_contains($value, '--')) {// found some deep comment
$value = preg_replace('/--.*$/i', '', $value);
}
if(is_numeric($value))
$result[$key] = (float) $value;
elseif(in_array(@$value[0], array("'", '"')) && in_array(@$value[strlen($value) - 1], array("'", '"')))
$result[$key] = substr(substr($value, 1), 0, -1);
elseif(in_array($value, array('true', 'false')))
$result[$key] = $value === 'true';
elseif(@$value[0] === '{') {
// arrays are not supported yet
// just ignore the error
continue;
}
else
{
foreach($result as $tmp_key => $tmp_value) { // load values defined by other keys, like: dailyFragsToBlackSkull = dailyFragsToRedSkull
$value = str_replace($tmp_key, $tmp_value, $value);
}
try {
$ret = eval("return $value;");
}
catch (\Throwable $e) {
throw new \RuntimeException('ERROR: Loading config.lua file. Line: ' . ($ln + 1) . ' - Unable to parse value "' . $value . '" - ' . $e->getMessage());
}
if((string) $ret == '' && trim($value) !== '""') {
throw new \RuntimeException('ERROR: Loading config.lua file. Line ' . ($ln + 1) . ' is not valid [key: ' . $key . ']');
}
$result[$key] = $ret;
}
}
}
}
}
return $result;
}
}

View File

@@ -0,0 +1,30 @@
<?php
namespace MyAAC\Server;
use MyAAC\Cache\Cache;
class Mounts
{
private static array $mounts = [];
public static function get()
{
if (count(self::$mounts) == 0) {
self::$mounts = Cache::remember('mounts', 10 * 60, function () {
if (file_exists(config('server_path') . TOML\Mounts::FILE)) {
$mounts = new TOML\Mounts();
}
else {
$mounts = new XML\Mounts();
}
$mounts->load();
return $mounts->get();
});
}
return self::$mounts;
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace MyAAC\Server;
use MyAAC\Cache\Cache;
class Outfits
{
private static array $outfits = [];
public static function get()
{
if (count(self::$outfits) == 0) {
self::$outfits = Cache::remember('outfits', 10 * 60, function () {
if (file_exists(config('server_path') . TOML\Outfits::FILE)) {
$outfits = new TOML\Outfits();
} else {
$outfits = new XML\Outfits();
}
$outfits->load();
return $outfits->get();
});
}
return self::$outfits;
}
}

View File

@@ -0,0 +1,69 @@
<?php
namespace MyAAC\Server\TOML;
use Devium\Toml\Toml;
use RuntimeException;
class Config
{
private array $config = [];
public function load(): void
{
$path = config('server_path') . 'config/';
$files = glob($path . '*.toml');
// filter files we don't need
$ignore = ['account_manager', 'groups', 'mounts', 'object_pools', 'outfits', 'scripts'];
$files = array_filter($files, function ($file) use ($ignore) {
foreach ($ignore as $item) {
if (str_contains($file, $item)) {
return false;
}
}
return true;
});
foreach ($files as $file) {
$key = basename($file, '.toml');
$toml = file_get_contents($file);
try {
$this->config[$key] = Toml::decode($toml, asArray: true);
}
catch (\Exception $e) {
throw new RuntimeException("Error: Cannot load config/$key.toml. More info in system/logs/error.log file.");
log_append('error.log', "[" . __CLASS__ . "] Fatal error: Cannot load config/$key.toml - $file. Error: " . $e->getMessage());
return;
}
}
$this->init();
}
private function init(): void
{
$this->config['serverName'] = $this->config['server']['identity']['name'] ?? 'Unknown';
$this->config['freePremium'] = $this->config['server']['accounts']['free_premium'] ?? false;
$this->config['ip'] = $this->config['server']['network']['ip'] ?? '127.0.0.1';
$this->config['worldType'] = $this->config['server']['world']['type'] ?? 'unknown';
$this->config['experienceStages'] = $this->config['stages']['config']['enabled'] ?? false;
$this->config['houseRentPeriod'] = $this->config['server']['houses']['rent_period'] ?? 'never';
$this->config['pzLocked'] = $this->config['combat']['skull']['pz_locked'] ?? 60 * 1000;
$this->config['url'] = $this->config['server']['identity']['url'] ?? 'http://localhost';
$this->config['protectionLevel'] = $this->config['server']['pvp']['protection_level'] ?? 0;
$this->config['rateExp'] = $this->config['rates']['rates']['experience'] ?? 1;
$this->config['rateMagic'] = $this->config['rates']['rates']['magic'] ?? 1;
$this->config['rateSkill'] = $this->config['rates']['rates']['skill'] ?? 1;
$this->config['rateLoot'] = $this->config['rates']['rates']['loot'] ?? 1;
$this->config['rateSpawn'] = $this->config['rates']['rates']['spawn'] ?? 1;
}
public function get(): array {
return $this->config;
}
}

View File

@@ -0,0 +1,44 @@
<?php
namespace MyAAC\Server\TOML;
use Devium\Toml\Toml;
class ExpStages
{
private array $stages = [];
const FILE = 'config/stages.toml';
public function load(): void
{
$file = config('server_path') . self::FILE;
if(!@file_exists($file)) {
return;
}
$toml = file_get_contents($file);
try {
$stages = Toml::decode($toml, asArray: true);
}
catch (\Exception $e) {
error('Error: Cannot load stages.toml. More info in system/logs/error.log file.');
log_append('error.log', "[" . __CLASS__ . "] Fatal error: Cannot load stages.toml - $file. Error: " . $e->getMessage());
return;
}
foreach ($stages['stage'] as $stage) {
$this->stages[] = [
'levels' => $stage['minlevel'] . (isset($stage['maxlevel']) ? '-' . $stage['maxlevel'] : '+'),
'multiplier' => $stage['multiplier']
];
}
}
public function get(): array {
return $this->stages;
}
}

View File

@@ -0,0 +1,47 @@
<?php
namespace MyAAC\Server\TOML;
use Devium\Toml\Toml;
class Groups
{
private array $groups = [];
const FILE = 'config/groups.toml';
public function load(): void
{
$file = config('server_path') . self::FILE;
if(!@file_exists($file)) {
error('Error: Cannot load groups.toml. More info in system/logs/error.log file.');
log_append('error.log', "[" . __CLASS__ . "] Fatal error: Cannot load groups.toml - $file. It doesn't exist.");
return;
}
$toml = file_get_contents($file);
try {
$groups = Toml::decode($toml, asArray: true);
}
catch (\Exception $e) {
error('Error: Cannot load groups.toml. More info in system/logs/error.log file.');
log_append('error.log', "[" . __CLASS__ . "] Fatal error: Cannot load groups.toml - $file. Error: " . $e->getMessage());
return;
}
foreach ($groups as $group)
{
$this->groups[$group['id']] = [
'id' => $group['id'],
'name' => $group['name'],
'access' => $group['access'],
];
}
}
public function get(): array {
return $this->groups;
}
}

View File

@@ -0,0 +1,52 @@
<?php
namespace MyAAC\Server\TOML;
use MyAAC\Cache\PHP as CachePHP;
class Items
{
private string $error = '';
public function getError(): string {
return $this->error;
}
public function load(): bool
{
$file = config('data_path') . 'items/items.toml';
if (!file_exists($file)) {
$this->error = 'Cannot load file ' . $file;
return false;
}
//$toml = file_get_contents($file);
//$items = \Devium\Toml\Toml::decode($toml, asArray: false);
$itemsParser = new ItemsParser();
$itemsParsed = $itemsParser->parse($file);
$items = [];
foreach ($itemsParsed as $item) {
$attributes = array_filter($item, function ($key) {
return !in_array($key, ['id', 'article', 'name', 'plural']);
}, ARRAY_FILTER_USE_KEY);
$id = $item['id'] ?? null;
if ($id === null) {
continue;
}
$items[$id] = [
'article' => $item['article'] ?? '',
'name' => $item['name'] ?? '',
'plural' => $item['plural'] ?? '',
'attributes' => $attributes,
];
}
$cache_php = new CachePHP(config('cache_prefix'), CACHE . 'persistent/');
$cache_php->set('items', $items, 5 * 365 * 24 * 60 * 60);
return true;
}
}

View File

@@ -0,0 +1,47 @@
<?php
namespace MyAAC\Server\TOML;
class ItemsParser
{
public function parse(string $path): array
{
$ret = [];
$i = 0;
$handle = fopen($path, 'r');
if ($handle === false) {
throw new \RuntimeException('Failed to open items file: ' . $path);
}
$parse = '';
while (($line = fgets($handle)) !== false) {
if (str_contains($line, '[[items]]') && $i++ != 0) {
//global $whoopsHandler;
//$whoopsHandler->addDataTable('ini', [$parse]);
$ret[] = parse_ini_string($parse);
$parse = '';
continue;
}
// skip lines like this
// field = {type = "fire", initdamage = 20, ticks = 10000, count = 7, damage = 10}
// as it cannot be parsed by parse_ini_string
if (str_starts_with(ltrim($line), 'field =')) {
continue;
}
$parse .= $line;
}
if ($parse !== '') {
$ret[] = parse_ini_string($parse);
}
fclose($handle);
return $ret;
}
}

View File

@@ -0,0 +1,47 @@
<?php
namespace MyAAC\Server\TOML;
use Devium\Toml\Toml;
class Mounts
{
private array $mounts = [];
const FILE = 'config/mounts.toml';
public function load(): void
{
$file = config('server_path') . self::FILE;
if(!@file_exists($file)) {
return;
}
$toml = file_get_contents($file);
try {
$mounts = Toml::decode($toml, asArray: true);
}
catch (\Exception $e) {
error('Error: Cannot load mounts.toml. More info in system/logs/error.log file.');
log_append('error.log', "[" . __CLASS__ . "] Fatal error: Cannot load mounts.toml - $file. Error: " . $e->getMessage());
return;
}
foreach ($mounts as $name => $mount)
{
$this->mounts[] = [
'id' => $mount['id'],
'client_id' => $mount['clientid'] ?? false,
'name' => $name,
'speed' => $mount['speed'] ?? 0,
'premium' => $mount['premium'] ?? false,
];
}
}
public function get(): array {
return $this->mounts;
}
}

View File

@@ -0,0 +1,48 @@
<?php
namespace MyAAC\Server\TOML;
use Devium\Toml\Toml;
class Outfits
{
private array $outfits = [];
const FILE = 'config/outfits.toml';
public function load(): void
{
$file = config('server_path') . self::FILE;
if(!@file_exists($file)) {
return;
}
$toml = file_get_contents($file);
try {
$outfits = Toml::decode($toml, asArray: true);
}
catch (\Exception $e) {
error('Error: Cannot load outfits.toml. More info in system/logs/error.log file.');
log_append('error.log', "[" . __CLASS__ . "] Fatal error: Cannot load outfits.toml - $file. Error: " . $e->getMessage());
return;
}
foreach ($outfits as $outfit)
{
$this->outfits[] = [
'id' => $outfit['id'],
'sex' => ($outfit['sex'] == 'male' ? SEX_MALE : SEX_FEMALE),
'name' => $outfit['name'],
'premium' => $outfit['premium'] ?? false,
'locked' => $outfit['locked'] ?? false,
'enabled' => $outfit['enabled'] ?? true,
];
}
}
public function get(): array {
return $this->outfits;
}
}

View File

@@ -0,0 +1,51 @@
<?php
namespace MyAAC\Server\TOML;
use Devium\Toml\Toml;
class Vocations
{
private array $vocations = [];
private array $vocationsFrom = [];
public function load(): void
{
$tomlVocations = glob(config('data_path') . 'vocations/*.toml');
if (count($tomlVocations) <= 0) {
throw new \RuntimeException('ERROR: Cannot load any .toml vocation from the data/vocations folder.');
}
foreach ($tomlVocations as $file) {
$toml = file_get_contents($file);
try {
$vocations = Toml::decode($toml, asArray: true);
}
catch (\Exception $e) {
$basename = basename($file);
error("Error: Cannot load vocations/$basename. More info in system/logs/error.log file.");
log_append('error.log', "[" . __CLASS__ . "] Fatal error: Cannot load mounts.toml - $file. Error: " . $e->getMessage());
break;
}
foreach ($vocations as $vocationArray) {
$id = $vocationArray['id'];
$this->vocations[$id] = $vocationArray['name'];
$this->vocationsFrom[$id] = $vocationArray['promotedfrom'];
}
}
ksort($this->vocations, SORT_NUMERIC);
ksort($this->vocationsFrom, SORT_NUMERIC);
}
public function get(): array {
return $this->vocations;
}
public function getFrom(): array {
return $this->vocationsFrom;
}
}

View File

@@ -0,0 +1,86 @@
<?php
namespace MyAAC\Server;
use MyAAC\Cache\Cache;
class Vocations
{
private static array $vocations = [];
private static array $vocationsFrom = [];
public function __construct() {
$cached = Cache::remember('vocations', 10 * 60, function () {
$tomlVocations = glob(config('data_path') . 'vocations/*.toml');
if (count($tomlVocations) > 0) {
$vocations = new TOML\Vocations();
}
else {
$vocations = new XML\Vocations();
}
$vocations->load();
$from = $vocations->getFrom();
$amount = 0;
foreach ($from as $vocId => $fromVocation) {
if ($vocId != 0 && $vocId == $fromVocation) {
$amount++;
}
}
return ['vocations' => $vocations->get(), 'vocationsFrom' => $from, 'amount' => $amount];
});
self::$vocations = $cached['vocations'];
self::$vocationsFrom = $cached['vocationsFrom'];
config(['vocations', self::$vocations]);
config(['vocations_amount', $cached['amount']]);
}
public static function get(): array {
return self::$vocations;
}
public static function getFrom(): array {
return self::$vocationsFrom;
}
public static function getPromoted(int $id): ?int {
foreach (self::$vocationsFrom as $vocId => $fromVocation) {
if ($id == $fromVocation && $vocId != $id) {
return $vocId;
}
}
return null;
}
public static function getOriginal(int $id): ?int {
if (!isset(self::$vocationsFrom[$id])) {
return null;
}
while ($tmpId = self::$vocationsFrom[$id]) {
if ($tmpId == $id) {
break;
}
$id = $tmpId;
}
return $id;
}
public static function getBase($includingRook = true): array {
$vocations = [];
foreach (self::$vocationsFrom as $vocId => $fromVoc) {
if ($vocId == $fromVoc && ($vocId != 0 || $includingRook)) {
$vocations[] = $vocId;
}
}
return $vocations;
}
}

View File

@@ -0,0 +1,40 @@
<?php
namespace MyAAC\Server\XML;
class ExpStages
{
private array $stages = [];
const FILE = 'XML/stages.xml';
public function load(): void
{
$file = config('data_path') . self::FILE;
if(!@file_exists($file)) {
return;
}
$xml = new \DOMDocument();
if(!$xml->load($file)) {
error('Error: Cannot load stages.xml. More info in system/logs/error.log file.');
log_append('error.log', "[" . __CLASS__ . "] Fatal error: Cannot load stages.xml - $file. Error: " . print_r(error_get_last(), true));
return;
}
foreach($xml->getElementsByTagName('stage') as $stage)
{
/** @var \DOMElement $stage */
$maxLevel = $stage->getAttribute('maxlevel');
$this->stages[] = [
'levels' => $stage->getAttribute('minlevel') . (isset($maxLevel[0]) ? '-' . $maxLevel : '+'),
'multiplier' => $stage->getAttribute('multiplier')
];
}
}
public function get(): array {
return $this->stages;
}
}

View File

@@ -0,0 +1,42 @@
<?php
namespace MyAAC\Server\XML;
class Groups
{
private array $groups = [];
const FILE = 'XML/groups.xml';
public function load(): void
{
$file = config('data_path') . self::FILE;
if(!@file_exists($file)) {
error('Error: Cannot load groups.xml. More info in system/logs/error.log file.');
log_append('error.log', "[" . __CLASS__ . "] Fatal error: Cannot load groups.xml - $file. It doesn't exist.");
return;
}
$groups = new \DOMDocument();
if(!@$groups->load($file)) {
error('Error: Cannot load groups.xml. More info in system/logs/error.log file.');
log_append('error.log', "[" . __CLASS__ . "] Fatal error: Cannot load groups.xml - $file. Error: " . print_r(error_get_last(), true));
return;
}
// loads groups
foreach( $groups->getElementsByTagName('group') as $group)
{
$this->groups[$group->getAttribute('id')] = [
'id' => $group->getAttribute('id'),
'name' => $group->getAttribute('name'),
'access' => $group->getAttribute('access')
];
}
}
public function get(): array {
return $this->groups;
}
}

View File

@@ -0,0 +1,79 @@
<?php
namespace MyAAC\Server\XML;
use MyAAC\Cache\PHP as CachePHP;
class Items
{
private string $error = '';
const FILE = 'items/items.xml';
public function getError(): string {
return $this->error;
}
public function load(): bool
{
$file = config('data_path') . self::FILE;
if (!file_exists($file)) {
$this->error = 'Cannot load file ' . $file;
return false;
}
$items = [];
try {
$xml = new \SimpleXMLElement(file_get_contents($file));
} catch (\Exception $e) {
$this->error = 'Error: Cannot load items.xml. More info in system/logs/error.log file.';
log_append('error.log', "[" . __CLASS__ . "] Fatal error: Cannot load items.xml - $file. Error: " . $e->getMessage());
return false;
}
foreach($xml->xpath('item') as $item) {
if ($item->attributes()->fromid) {
for ($id = (int)$item->attributes()->fromid; $id <= (int)$item->attributes()->toid; $id++) {
$tmp = $this->parseNode($id, $item);
$items[$tmp['id']] = $tmp['content'];
}
} else {
$tmp = $this->parseNode($item->attributes()->id, $item);
$items[$tmp['id']] = $tmp['content'];
}
}
$cache_php = new CachePHP(config('cache_prefix'), CACHE . 'persistent/');
$cache_php->set('items', $items, 5 * 365 * 24 * 60 * 60);
return true;
}
public function parseNode($id, $node): array
{
$name = $node->attributes()->name;
$article = $node->attributes()->article;
$plural = $node->attributes()->plural;
$attributes = [];
foreach($node->xpath('attribute') as $attr) {
$attributes[strtolower($attr->attributes()->key)] = (string)$attr->attributes()->value;
if ($attr->xpath('attribute')) {
foreach($attr->xpath('attribute') as $attr2) {
$attributes[strtolower($attr2->attributes()->key)] = (string)$attr2->attributes()->value;
}
}
}
return [
'id' => (int)$id,
'content' => [
'article' => (string)$article,
'name' => (string)$name,
'plural' => (string)$plural,
'attributes' => $attributes
],
];
}
}

View File

@@ -0,0 +1,53 @@
<?php
namespace MyAAC\Server\XML;
class Mounts
{
private array $mounts = [];
const FILE = 'XML/mounts.xml';
public function load(): void
{
$file = config('data_path') . self::FILE;
if(!@file_exists($file)) {
return;
}
$xml = new \DOMDocument();
if(!$xml->load($file)) {
error('Error: Cannot load mounts.xml. More info in system/logs/error.log file.');
log_append('error.log', "[" . __CLASS__ . "] Fatal error: Cannot load mounts.xml - $file. Error: " . print_r(error_get_last(), true));
return;
}
foreach ($xml->getElementsByTagName('mount') as $mount) {
$this->mounts[] = $this->parseMountNode($mount);
}
}
private function parseMountNode($node): array
{
$id = (int)$node->getAttribute('id');
$client_id = (int)$node->getAttribute('clientid');
$name = $node->getAttribute('name');
$speed = (int)$node->getAttribute('speed');
$premium = getBoolean($node->getAttribute('premium'));
$type = $node->getAttribute('type');
return [
'id' => $id,
'client_id' => $client_id,
'name' => $name,
'speed' => $speed,
'premium' => $premium,
'type' => $type
];
}
public function get(): array {
return $this->mounts;
}
}

View File

@@ -0,0 +1,53 @@
<?php
namespace MyAAC\Server\XML;
class Outfits
{
private array $outfits = [];
const FILE = 'XML/outfits.xml';
public function load(): void
{
$file = config('data_path') . self::FILE;
if(!@file_exists($file)) {
return;
}
$xml = new \DOMDocument();
if(!$xml->load($file)) {
error('Error: Cannot load outfits.xml. More info in system/logs/error.log file.');
log_append('error.log', "[" . __CLASS__ . "] Fatal error: Cannot load outfits.xml - $file. Error: " . print_r(error_get_last(), true));
return;
}
foreach ($xml->getElementsByTagName('outfit') as $outfit) {
$this->outfits[] = $this->parseOutfitNode($outfit);
}
}
private function parseOutfitNode($node): array
{
$looktype = (int)$node->getAttribute('looktype');
$type = (int)$node->getAttribute('type');
$name = $node->getAttribute('name');
$premium = getBoolean($node->getAttribute('premium'));
$locked = !getBoolean($node->getAttribute('unlocked'));
$enabled = getBoolean($node->getAttribute('enabled'));
return [
'id' => $looktype,
'sex' => ($type === 1 ? SEX_MALE : SEX_FEMALE),
'name' => $name,
'premium' => $premium,
'locked' => $locked,
'enabled' => $enabled,
];
}
public function get(): array {
return $this->outfits;
}
}

View File

@@ -2,100 +2,42 @@
namespace MyAAC\Server\XML; namespace MyAAC\Server\XML;
use MyAAC\Cache\Cache;
class Vocations class Vocations
{ {
private static array $vocations; private array $vocations = [];
private static array $vocationsFrom; private array $vocationsFrom = [];
public function __construct() const FILE = 'vocations.xml';
{
$cached = Cache::remember('vocations', 10 * 60, function () {
$this->load();
$from = $this->getFrom();
$amount = 0;
foreach ($from as $vocId => $fromVocation) {
if ($vocId != 0 && $vocId == $fromVocation) {
$amount++;
}
}
return ['vocations' => $this->get(), 'vocationsFrom' => $from, 'amount' => $amount];
});
self::$vocations = $cached['vocations'];
self::$vocationsFrom = $cached['vocationsFrom'];
config(['vocations', self::$vocations]);
config(['vocations_amount', $cached['amount']]);
}
public function load(): void public function load(): void
{ {
if(!class_exists('DOMDocument')) { $file = config('data_path') . 'XML/' . self::FILE;
throw new \RuntimeException('Please install PHP xml extension. MyAAC will not work without it.');
}
$vocationsXML = new \DOMDocument();
$file = config('data_path') . 'XML/vocations.xml';
if(!@file_exists($file)) { if(!@file_exists($file)) {
$file = config('data_path') . 'vocations.xml'; $file = config('data_path') . self::FILE;
} }
if(!$vocationsXML->load($file)) { $xml = new \DOMDocument();
throw new \RuntimeException('ERROR: Cannot load <i>vocations.xml</i> - the file is malformed. Check the file with xml syntax validator.'); if(!$xml->load($file)) {
error('Error: Cannot load vocations.xml. More info in system/logs/error.log file.');
log_append('error.log', "[" . __CLASS__ . "] Fatal error: Cannot load vocations.xml - $file. Error: " . print_r(error_get_last(), true));
return;
} }
foreach($vocationsXML->getElementsByTagName('vocation') as $vocation) { foreach($xml->getElementsByTagName('vocation') as $vocation) {
$id = $vocation->getAttribute('id'); $id = $vocation->getAttribute('id');
self::$vocations[$id] = $vocation->getAttribute('name'); $this->vocations[$id] = $vocation->getAttribute('name');
$fromVocation = (int) $vocation->getAttribute('fromvoc'); $fromVocation = (int) $vocation->getAttribute('fromvoc');
self::$vocationsFrom[$id] = $fromVocation; $this->vocationsFrom[$id] = $fromVocation;
} }
} }
public static function get(): array { public function get(): array {
return self::$vocations; return $this->vocations;
} }
public static function getFrom(): array { public function getFrom(): array {
return self::$vocationsFrom; return $this->vocationsFrom;
}
public static function getPromoted(int $id): ?int {
foreach (self::$vocationsFrom as $vocId => $fromVocation) {
if ($id == $fromVocation && $vocId != $id) {
return $vocId;
}
}
return null;
}
public static function getOriginal(int $id): ?int {
while ($tmpId = self::$vocationsFrom[$id]) {
if ($tmpId == $id) {
break;
}
$id = $tmpId;
}
return $id;
}
public static function getBase($includingRook = true): array {
$vocations = [];
foreach (self::$vocationsFrom as $vocId => $fromVoc) {
if ($vocId == $fromVoc && ($vocId != 0 || $includingRook)) {
$vocations[] = $vocId;
}
}
return $vocations;
} }
} }

View File

@@ -1,5 +1,8 @@
<?php <?php
const SEX_FEMALE = 0;
const SEX_MALE = 1;
const SKILL_FRAGS = -1; const SKILL_FRAGS = -1;
const SKILL_BALANCE = -2; const SKILL_BALANCE = -2;