pages/online: add cache, resulting in 20x performance boost

(for an example server with 2k players)
This commit is contained in:
slawkens
2025-07-31 13:28:46 +02:00
parent 0efe47ce71
commit c836308601
3 changed files with 98 additions and 80 deletions

View File

@@ -9,18 +9,21 @@
* @link https://my-aac.org * @link https://my-aac.org
*/ */
use MyAAC\Cache\Cache;
use MyAAC\Models\ServerConfig; use MyAAC\Models\ServerConfig;
use MyAAC\Models\ServerRecord; use MyAAC\Models\ServerRecord;
defined('MYAAC') or die('Direct access not allowed!'); defined('MYAAC') or die('Direct access not allowed!');
$title = 'Who is online?'; $title = 'Who is online?';
if (setting('core.account_country')) if (setting('core.account_country')) {
require SYSTEM . 'countries.conf.php'; require SYSTEM . 'countries.conf.php';
}
$promotion = ''; $promotion = '';
if($db->hasColumn('players', 'promotion')) if($db->hasColumn('players', 'promotion')) {
$promotion = '`promotion`,'; $promotion = '`promotion`,';
}
$order = $_GET['order'] ?? 'name_asc'; $order = $_GET['order'] ?? 'name_asc';
if(!in_array($order, ['country_asc', 'country_desc', 'name_asc', 'name_desc', 'level_asc', 'level_desc', 'vocation_asc', 'vocation_desc'])) { if(!in_array($order, ['country_asc', 'country_desc', 'name_asc', 'name_desc', 'level_asc', 'level_desc', 'vocation_asc', 'vocation_desc'])) {
@@ -30,86 +33,80 @@ else if($order == 'vocation_asc' || $order == 'vocation_desc') {
$order = $promotion . 'vocation_' . (str_contains($order, 'asc') ? 'asc' : 'desc'); $order = $promotion . 'vocation_' . (str_contains($order, 'asc') ? 'asc' : 'desc');
} }
$orderExplode = explode('_', $order); $cached = Cache::remember("online_$order", setting('core.online_cache_ttl') * 60, function() use($db, $promotion, $order) {
$orderSql = $orderExplode[0] . ' ' . $orderExplode[1]; $orderExplode = explode('_', $order);
$orderSql = $orderExplode[0] . ' ' . $orderExplode[1];
$skull_type = 'skull'; $skull_type = 'skull';
if($db->hasColumn('players', 'skull_type')) { if($db->hasColumn('players', 'skull_type')) {
$skull_type = 'skull_type'; $skull_type = 'skull_type';
} }
$skull_time = 'skulltime'; $skull_time = 'skulltime';
if($db->hasColumn('players', 'skull_time')) { if($db->hasColumn('players', 'skull_time')) {
$skull_time = 'skull_time'; $skull_time = 'skull_time';
} }
$outfit_addons = false; $outfit_addons = false;
$outfit = '';
if (setting('core.online_outfit')) {
$outfit = ', lookbody, lookfeet, lookhead, looklegs, looktype'; $outfit = ', lookbody, lookfeet, lookhead, looklegs, looktype';
if($db->hasColumn('players', 'lookaddons')) { if($db->hasColumn('players', 'lookaddons')) {
$outfit .= ', lookaddons'; $outfit .= ', lookaddons';
$outfit_addons = true; $outfit_addons = true;
} }
}
$vocs = []; $vocations = array_map(function ($name) {
if (setting('core.online_vocations')) { return 0;
foreach($config['vocations'] as $id => $name) { }, setting('core.vocations'));
$vocs[$id] = 0;
}
}
if($db->hasTable('players_online')) // tfs 1.0 if($db->hasTable('players_online')) // tfs 1.0
$playersOnline = $db->query('SELECT `accounts`.`country`, `players`.`name`, `players`.`level`, `players`.`vocation`' . $outfit . ', `' . $skull_time . '` as `skulltime`, `' . $skull_type . '` as `skull` FROM `accounts`, `players`, `players_online` WHERE `players`.`id` = `players_online`.`player_id` AND `accounts`.`id` = `players`.`account_id` ORDER BY ' . $orderSql); $playersOnline = $db->query('SELECT `accounts`.`country`, `players`.`name`, `players`.`level`, `players`.`vocation`' . $outfit . ', `' . $skull_time . '` as `skulltime`, `' . $skull_type . '` as `skull` FROM `accounts`, `players`, `players_online` WHERE `players`.`id` = `players_online`.`player_id` AND `accounts`.`id` = `players`.`account_id` ORDER BY ' . $orderSql);
else else
$playersOnline = $db->query('SELECT `accounts`.`country`, `players`.`name`, `players`.`level`, `players`.`vocation`' . $outfit . ', ' . $promotion . ' `' . $skull_time . '` as `skulltime`, `' . $skull_type . '` as `skull` FROM `accounts`, `players` WHERE `players`.`online` > 0 AND `accounts`.`id` = `players`.`account_id` ORDER BY ' . $orderSql); $playersOnline = $db->query('SELECT `accounts`.`country`, `players`.`name`, `players`.`level`, `players`.`vocation`' . $outfit . ', ' . $promotion . ' `' . $skull_time . '` as `skulltime`, `' . $skull_type . '` as `skull` FROM `accounts`, `players` WHERE `players`.`online` > 0 AND `accounts`.`id` = `players`.`account_id` ORDER BY ' . $orderSql);
$players_data = []; $settingVocations = setting('core.vocations');
$players = 0; $settingVocationsAmount = setting('core.vocations_amount');
$data = '';
foreach($playersOnline as $player) { $players = [];
foreach($playersOnline as $player) {
$skull = ''; $skull = '';
if (setting('core.online_skulls')) if($player['skulltime'] > 0) {
{ if($player['skull'] == 3) {
if($player['skulltime'] > 0)
{
if($player['skull'] == 3)
$skull = ' <img style="border: 0;" src="images/white_skull.gif"/>'; $skull = ' <img style="border: 0;" src="images/white_skull.gif"/>';
elseif($player['skull'] == 4) }
elseif($player['skull'] == 4) {
$skull = ' <img style="border: 0;" src="images/red_skull.gif"/>'; $skull = ' <img style="border: 0;" src="images/red_skull.gif"/>';
elseif($player['skull'] == 5) }
elseif($player['skull'] == 5) {
$skull = ' <img style="border: 0;" src="images/black_skull.gif"/>'; $skull = ' <img style="border: 0;" src="images/black_skull.gif"/>';
} }
} }
if(isset($player['promotion'])) { if(isset($player['promotion'])) {
if((int)$player['promotion'] > 0) if((int)$player['promotion'] > 0)
$player['vocation'] += ($player['promotion'] * $config['vocations_amount']); $player['vocation'] += ($player['promotion'] * $settingVocationsAmount);
} }
$players_data[] = array( $players[] = array(
'name' => getPlayerLink($player['name']), 'name' => getPlayerLink($player['name']),
'player' => $player, 'player' => $player,
'level' => $player['level'], 'level' => $player['level'],
'vocation' => $config['vocations'][$player['vocation']], 'vocation' => $settingVocations[$player['vocation']],
'country_image' => setting('core.account_country') ? getFlagImage($player['country']) : null, 'skull' => $skull,
'outfit' => setting('core.online_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'] : null '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'],
); );
if (setting('core.online_vocations')) { $vocations[($player['vocation'] > $settingVocationsAmount ? $player['vocation'] - $settingVocationsAmount : $player['vocation'])]++;
$vocs[($player['vocation'] > $config['vocations_amount'] ? $player['vocation'] - $config['vocations_amount'] : $player['vocation'])]++;
} }
}
$record = ''; $record = '';
if(count($players_data) > 0) { if(count($players) > 0) {
if( setting('core.online_record')) { if( setting('core.online_record')) {
$result = null; $result = null;
$timestamp = false; $timestamp = false;
if($db->hasTable('server_record')) { if($db->hasTable('server_record')) {
$timestamp = true; $timestamp = true;
$result = ServerRecord::where('world_id', $config['lua']['worldId'])->orderByDesc('record')->first()->toArray(); $result = ServerRecord::where('world_id', configLua('worldId'))->orderByDesc('record')->first()->toArray();
} else if($db->hasTable('server_config')) { // tfs 1.0 } else if($db->hasTable('server_config')) { // tfs 1.0
$row = ServerConfig::where('config', 'players_record')->first(); $row = ServerConfig::where('config', 'players_record')->first();
if ($row) { if ($row) {
@@ -121,15 +118,22 @@ if(count($players_data) > 0) {
$record = $result['record'] . ' player' . ($result['record'] > 1 ? 's' : '') . ($timestamp ? ' (on ' . date("M d Y, H:i:s", $result['timestamp']) . ')' : ''); $record = $result['record'] . ' player' . ($result['record'] > 1 ? 's' : '') . ($timestamp ? ' (on ' . date("M d Y, H:i:s", $result['timestamp']) . ')' : '');
} }
} }
} }
return [
'players' => $players,
'record' => $record,
'vocations' => $vocations,
];
});
$twig->display('online.html.twig', array( $twig->display('online.html.twig', array(
'players' => $players_data, 'players' => $cached['players'],
'record' => $record, 'record' => $cached['record'],
'vocs' => $vocs, 'vocations' => $cached['vocations'],
'vocs' => $cached['vocations'], // deprecated, to be removed
'order' => $order, 'order' => $order,
)); ));
//search bar // search bar
$twig->display('characters.form.html.twig'); $twig->display('characters.form.html.twig');
?>

View File

@@ -1247,6 +1247,14 @@ Sent by MyAAC,<br/>
'type' => 'section', 'type' => 'section',
'title' => 'Online Page' 'title' => 'Online Page'
], ],
'online_cache_ttl' => [
'name' => 'Online Cache TTL (in minutes)',
'type' => 'number',
'min' => 0,
'desc' => 'How often to update online list from database in minutes. Too low may slow down your website.' . PHP_EOL .
'0 to disable.',
'default' => 15,
],
'online_record' => [ 'online_record' => [
'name' => 'Display Players Record', 'name' => 'Display Players Record',
'type' => 'boolean', 'type' => 'boolean',

View File

@@ -1,3 +1,9 @@
{% set onlineTTL = setting('core.online_cache_ttl') %}
{% if onlineTTL > 0 and cache.enabled() %}
<small>*Note: Online List is updated every {{ onlineTTL > 1 ? ' ' ~ onlineTTL : '' }} minute{{ onlineTTL > 1 ? 's' : '' }}.</small>
<br/>
{% endif %}
{# vocation statistics #} {# vocation statistics #}
{% if setting('core.online_vocations') %} {% if setting('core.online_vocations') %}
<br/> <br/>