From 7642151569f99ace8e0cac0a063303572f2cc095 Mon Sep 17 00:00:00 2001 From: novgorodschi catalin Date: Tue, 28 Jul 2026 08:48:19 +0300 Subject: [PATCH] Add Plus Statistics Add Plus Statistics --- Admin/Templates/config.tpl | 12 +- Admin/Templates/editNewFunctions.tpl | 25 ++ GameEngine/Admin/Mods/editNewFunctions.php | 10 + GameEngine/Automation.php | 5 +- .../Automation/AutomationPlayerStatistics.php | 226 +++++++++++++ GameEngine/Lang/en.php | 31 ++ GameEngine/Lang/fr.php | 31 ++ GameEngine/Lang/ro.php | 31 ++ Templates/Alliance/alli_menu.tpl | 10 +- Templates/Ranking/overview.tpl | 17 + Templates/Ranking/player_attack.tpl | 17 + Templates/Ranking/player_defend.tpl | 17 + Templates/Ranking/player_top10.tpl | 26 +- Templates/Ranking/statistics.tpl | 307 ++++++++++++++++++ cron.php | 8 +- gpack/travian_default/img/s/stats.gif | Bin 0 -> 835 bytes gpack/travian_default/lang/en/compact.css | 3 + gpack/travian_t4/img/s/stats.gif | Bin 0 -> 835 bytes gpack/travian_t4/lang/en/compact.css | 3 + install/data/constant_format.tpl | 20 ++ install/process.php | 11 + install/templates/config.tpl | 6 + statistiken.php | 8 + var/db/struct.sql | 29 ++ 24 files changed, 844 insertions(+), 9 deletions(-) create mode 100644 GameEngine/Automation/AutomationPlayerStatistics.php create mode 100644 Templates/Ranking/statistics.tpl create mode 100644 gpack/travian_default/img/s/stats.gif create mode 100644 gpack/travian_t4/img/s/stats.gif diff --git a/Admin/Templates/config.tpl b/Admin/Templates/config.tpl index 41bab0a5..ba83787c 100644 --- a/Admin/Templates/config.tpl +++ b/Admin/Templates/config.tpl @@ -110,7 +110,7 @@ $editIcon = '
? - + @@ -267,6 +267,16 @@ $cronKeyMasked = ($cronKey === '') ?Enabled" : "Disabled"; ?> ? ?Enabled" : "Disabled"; ?> + ?Enabled (" + . (defined('PLUS_STATS_INTERVAL_HOURS') ? PLUS_STATS_INTERVAL_HOURS : 6) . "h, " + . ($psKeep > 0 ? $psKeep . "d" : "∞") . ")"; + } else { + echo "Disabled"; + } + ?> diff --git a/Admin/Templates/editNewFunctions.tpl b/Admin/Templates/editNewFunctions.tpl index 89194946..ebc71152 100644 --- a/Admin/Templates/editNewFunctions.tpl +++ b/Admin/Templates/editNewFunctions.tpl @@ -255,6 +255,31 @@ if($_SESSION['access'] < 9) die(ACCESS_DENIED_ADMIN); + + ? +
+ + + + + + + ? + + + + + + ? + + + + ?
diff --git a/GameEngine/Admin/Mods/editNewFunctions.php b/GameEngine/Admin/Mods/editNewFunctions.php index dd101980..4c805fe9 100644 --- a/GameEngine/Admin/Mods/editNewFunctions.php +++ b/GameEngine/Admin/Mods/editNewFunctions.php @@ -113,6 +113,16 @@ $fh = fopen($myFile, 'w') or die("


Can't open file: GameEngine\con tz_config_set($text, '%SERVER%', SERVER); tz_config_set($text, '%NEW_FUNCTIONS_OASIS%', $_POST['new_functions_oasis'] ?? ''); tz_config_set($text, '%ALLIANCEBONUSES%', $_POST['alliance_bonuses'] ?? 'false'); + tz_config_set($text, '%PLUSSTATS%', $_POST['plus_statistics'] ?? 'false'); + + // intervalul si retentia: valori numerice, cu limite rezonabile + $psHours = isset($_POST['plus_stats_hours']) ? (float) $_POST['plus_stats_hours'] : 6; + if ($psHours < 0.25 || $psHours > 168) { $psHours = 6; } + tz_config_set($text, '%PLUSSTATSHOURS%', $psHours); + + $psKeep = isset($_POST['plus_stats_keep']) ? (int) $_POST['plus_stats_keep'] : 0; + if ($psKeep < 0 || $psKeep > 3650) { $psKeep = 0; } + tz_config_set($text, '%PLUSSTATSKEEP%', $psKeep); tz_config_set($text, '%NEW_FUNCTIONS_ALLIANCE_INVITATION%', $_POST['new_functions_alliance_invitation'] ?? ''); tz_config_set($text, '%NEW_FUNCTIONS_EMBASSY_MECHANICS%', $_POST['new_functions_embassy_mechanics'] ?? ''); tz_config_set($text, '%NEW_FUNCTIONS_FORUM_POST_MESSAGE%', $_POST['new_functions_forum_post_message'] ?? ''); diff --git a/GameEngine/Automation.php b/GameEngine/Automation.php index 8a301032..691aa6a0 100644 --- a/GameEngine/Automation.php +++ b/GameEngine/Automation.php @@ -74,6 +74,7 @@ include_once __DIR__ . '/Automation/AutomationStarvation.php'; include_once __DIR__ . '/Automation/AutomationNatarsWW.php'; include_once __DIR__ . '/Automation/AutomationMedals.php'; include_once __DIR__ . '/Automation/AutomationCleanup.php'; +include_once __DIR__ . '/Automation/AutomationPlayerStatistics.php'; class Automation { // === Faza S2: metodele clasei, grupate pe domenii === @@ -92,6 +93,7 @@ class Automation { use AutomationCleanup; + use AutomationPlayerStatistics; /** * @var object The artifacts class, used to create Natars, artifacts and obtaining info about them */ @@ -135,7 +137,8 @@ class Automation { "spawnWWVillages", "spawnWWBuildingPlans", "activateArtifacts", "heroAdventureComplete", // P3: curatenie periodica (are interval propriu, nu ruleaza la fiecare tick) - "cleanupOldData"]; + "cleanupOldData", + "recordPlayerStatistics"]; foreach($methodsArrays as $method){ $file = fopen($autoprefix."GameEngine/Prevention/".$method.".txt", "w"); diff --git a/GameEngine/Automation/AutomationPlayerStatistics.php b/GameEngine/Automation/AutomationPlayerStatistics.php new file mode 100644 index 00000000..5f65048e --- /dev/null +++ b/GameEngine/Automation/AutomationPlayerStatistics.php @@ -0,0 +1,226 @@ +dblink, "SHOW TABLES LIKE '" . $table . "'"); + + if (!$check || mysqli_num_rows($check) === 0) { + return false; + } + + $hours = defined('PLUS_STATS_INTERVAL_HOURS') ? (float) PLUS_STATS_INTERVAL_HOURS : 6.0; + $interval = (int) max(600, round($hours * 3600)); + $now = time(); + + $res = mysqli_query($database->dblink, + "SELECT MAX(recorded_at) AS last FROM " . $table); + $row = $res ? mysqli_fetch_assoc($res) : null; + $last = $row ? (int) $row['last'] : 0; + + if ($last > 0 && ($now - $last) < $interval) { + return false; + } + + $this->writePlayerStatisticsSnapshot($now); + $this->trimPlayerStatistics($now); + + return true; + } + + /** + * Scrie efectiv instantaneul. + * + * Populatia, satele si punctele vin dintr-o singura interogare. Trupele se + * numara separat, fiindca hrana consumata are nevoie de datele de unitate + * din PHP (fiecare unitate are alt consum). + */ + private function writePlayerStatisticsSnapshot($now) + { + global $database; + + $table = TB_PREFIX . 'player_statistics_history'; + + // rang, populatie, sate si puncte de lupta, per jucator + $q = "SELECT + u.id AS uid, + u.oldrank AS rank, + COALESCE(SUM(v.pop), 0) AS population, + COUNT(CASE WHEN v.type != 99 THEN v.wref END) AS villages, + u.apall AS attack_points, + u.dpall AS defence_points + FROM " . TB_PREFIX . "users u + LEFT JOIN " . TB_PREFIX . "vdata v ON v.owner = u.id + WHERE u.id > 5 AND u.access > 0 + GROUP BY u.id"; + + $res = mysqli_query($database->dblink, $q); + + if (!$res) { + return; + } + + $players = array(); + + while ($row = mysqli_fetch_assoc($res)) { + $players[(int) $row['uid']] = array( + 'rank' => (int) $row['rank'], + 'population' => (int) $row['population'], + 'villages' => (int) $row['villages'], + 'attack_points' => (int) $row['attack_points'], + 'defence_points' => (int) $row['defence_points'], + 'troop_count' => 0, + 'troop_upkeep' => 0, + ); + } + + if (!$players) { + return; + } + + $this->addTroopTotals($players); + + // scriem in loturi, ca sa nu facem o interogare per jucator + $values = array(); + + foreach ($players as $uid => $p) { + $values[] = '(' . (int) $uid . ',' . (int) $now . ',' + . $p['rank'] . ',' . $p['population'] . ',' . $p['villages'] . ',' + . $p['troop_count'] . ',' . $p['troop_upkeep'] . ',' + . $p['attack_points'] . ',' . $p['defence_points'] . ')'; + } + + foreach (array_chunk($values, 200) as $chunk) { + mysqli_query($database->dblink, + "INSERT IGNORE INTO " . $table . " + (uid, recorded_at, `rank`, population, villages, + troop_count, troop_upkeep, attack_points, defence_points) + VALUES " . implode(',', $chunk)); + } + } + + /** + * Aduna trupele fiecarui jucator si hrana pe care o consuma. + * + * Se numara trupele din satele proprii SI intaririle trimise altora + * (enforcement.`from` pastreaza satul de origine, deci ele raman ale + * trimitatorului). Trupele straine stationate la tine NU se numara: nu sunt + * armata ta. + * + * Numarul brut de unitati e inselator - 1000 de falange nu inseamna cat 1000 + * de calareti de elita - de aceea inregistram si hrana consumata, care e + * cantarul propriu al jocului si pondereaza automat unitatile dupa putere. + */ + private function addTroopTotals(array &$players) + { + global $database; + + // consumul fiecarei unitati, din datele de joc + $upkeep = array(); + + for ($i = 1; $i <= 90; $i++) { + $name = 'u' . $i; + + if (isset($GLOBALS[$name]) && isset($GLOBALS[$name]['pop'])) { + $upkeep[$i] = (int) $GLOBALS[$name]['pop']; + } + } + + if (!$upkeep) { + return; + } + + // suma pe coloane, pentru trupele din satele proprii + $sumCount = array(); + $sumUpkeep = array(); + + foreach ($upkeep as $i => $cost) { + $sumCount[] = 'SUM(t.u' . $i . ')'; + $sumUpkeep[] = 'SUM(t.u' . $i . ') * ' . $cost; + } + + $sources = array( + // trupele din satele proprii + "SELECT v.owner AS uid, + " . implode(' + ', $sumCount) . " AS cnt, + " . implode(' + ', $sumUpkeep) . " AS upk + FROM " . TB_PREFIX . "units t + JOIN " . TB_PREFIX . "vdata v ON v.wref = t.vref + GROUP BY v.owner", + + // intaririle trimise altora: raman ale satului de origine + "SELECT v.owner AS uid, + " . implode(' + ', $sumCount) . " AS cnt, + " . implode(' + ', $sumUpkeep) . " AS upk + FROM " . TB_PREFIX . "enforcement t + JOIN " . TB_PREFIX . "vdata v ON v.wref = t.`from` + GROUP BY v.owner", + ); + + foreach ($sources as $q) { + $res = @mysqli_query($database->dblink, $q); + + while ($res && ($row = mysqli_fetch_assoc($res))) { + $uid = (int) $row['uid']; + + if (!isset($players[$uid])) { + continue; + } + + $players[$uid]['troop_count'] += (int) $row['cnt']; + $players[$uid]['troop_upkeep'] += (int) $row['upk']; + } + } + } + + /** Sterge instantaneele mai vechi decat retentia configurata. */ + private function trimPlayerStatistics($now) + { + global $database; + + $days = defined('PLUS_STATS_KEEP_DAYS') ? (int) PLUS_STATS_KEEP_DAYS : 0; + + if ($days <= 0) { + return; // 0 = pastram tot + } + + mysqli_query($database->dblink, + "DELETE FROM " . TB_PREFIX . "player_statistics_history + WHERE recorded_at < " . (int) ($now - $days * 86400) . " + LIMIT 5000"); + } +} diff --git a/GameEngine/Lang/en.php b/GameEngine/Lang/en.php index 5e9c7e50..8dbe927f 100755 --- a/GameEngine/Lang/en.php +++ b/GameEngine/Lang/en.php @@ -1990,6 +1990,11 @@ tz_def('TZ_ARRIVED', 'Arrived:'); tz_def('TZ_ASSIGN_TO_POSITION', 'Assign to position'); tz_def('TZ_AS_SOON_AS_A_PLAYER_YOU_INVITED_FO', 'As soon as a player you invited founds his'); tz_def('TZ_ATTACKS', 'Attacks'); +tz_def('TZ_OVERVIEW', 'Overview'); +tz_def('TZ_FORUM', 'Forum'); +tz_def('TZ_CHAT', 'Chat'); +tz_def('TZ_NEWS', 'News'); +tz_def('TZ_OPTIONS', 'Options'); tz_def('TZ_BOLD', 'bold'); tz_def('TZ_BUILDING', 'Building'); tz_def('TZ_CATAPULT_TARGET', 'catapult target'); @@ -4245,3 +4250,29 @@ tz_def('ALLYBONUS_RECRUITMENT_DESC', 'Speeds up troop training in every troop-pr tz_def('ALLYBONUS_PHILOSOPHY_DESC', 'Increases culture point production from buildings and hero helmets. Town hall celebrations are not affected.'); tz_def('ALLYBONUS_METALLURGY_DESC', 'Increases the offensive and defensive strength of your troops, on top of your smithy upgrades.'); tz_def('ALLYBONUS_COMMERCE_DESC', 'Increases how much each merchant can carry. Multiplies with the trade office.'); + +////////////////////////////////////////////////////////////////////////////////////////////////////// +// STATISTICI GRAFICE (Travian Plus) +////////////////////////////////////////////////////////////////////////////////////////////////////// +tz_def('PLUSSTATS_TITLE', 'Graphical statistics'); +tz_def('PLUSSTATS_INTRO', 'The development of your account over time.'); +tz_def('PLUSSTATS_RANK', 'Ranking'); +tz_def('PLUSSTATS_POP', 'Population'); +tz_def('PLUSSTATS_ARMY', 'Army strength (crop upkeep per hour)'); +tz_def('PLUSSTATS_VILLAGES', 'Villages'); +tz_def('PLUSSTATS_TROOPS', 'Troops'); +tz_def('PLUSSTATS_UPKEEP', 'Crop upkeep per hour'); +tz_def('PLUSSTATS_METRIC', 'Metric'); +tz_def('PLUSSTATS_NOW', 'Now'); +tz_def('PLUSSTATS_CHANGE', 'Change'); +tz_def('PLUSSTATS_NODATA', 'Not enough data yet'); +tz_def('PLUSSTATS_WAIT', 'Your account is being recorded. The graphs appear once at least two snapshots exist.'); +tz_def('PLUSSTATS_NEEDPLUS', 'Graphical statistics are a Travian Plus feature. Activate Plus to see the development of your account.'); +tz_def('PLUSSTATS_DISABLED', 'Graphical statistics are not enabled on this server.'); +tz_def('PLUSSTATS_FOOT', 'Army strength is measured by crop upkeep, which is the game\'s own weighting: it counts a strong unit for more than a weak one. Troops reinforcing other players still count as yours.'); +tz_def('ADM_PLUS_STATISTICS', 'Plus graphical statistics'); +tz_def('ADM_PLUS_STATISTICS_TIP', 'Records rank, population, villages and army for every player, so Plus players can see how their account developed. The tab is only visible with an active Plus account.'); +tz_def('ADM_PLUS_STATISTICS_INTERVAL', 'Statistics snapshot interval (hours)'); +tz_def('ADM_PLUS_STATISTICS_INTERVAL_TIP', 'How often a snapshot is taken. On a fast server a day is a lot of play, so a few hours gives a readable curve.'); +tz_def('ADM_PLUS_STATISTICS_KEEP', 'Statistics history kept (days)'); +tz_def('ADM_PLUS_STATISTICS_KEEP_TIP', '0 keeps everything, so players see the full history of their account since recording began.'); diff --git a/GameEngine/Lang/fr.php b/GameEngine/Lang/fr.php index 62357779..c10d5099 100644 --- a/GameEngine/Lang/fr.php +++ b/GameEngine/Lang/fr.php @@ -1996,6 +1996,11 @@ tz_def('TZ_ARRIVED', 'Arrivé :'); tz_def('TZ_ASSIGN_TO_POSITION', 'Assigner à un poste'); tz_def('TZ_AS_SOON_AS_A_PLAYER_YOU_INVITED_FO', 'Dès qu\'un joueur que vous avez invité fonde son'); tz_def('TZ_ATTACKS', 'Attaques'); +tz_def('TZ_OVERVIEW', 'Vue d\'ensemble'); +tz_def('TZ_FORUM', 'Forum'); +tz_def('TZ_CHAT', 'Chat'); +tz_def('TZ_NEWS', 'Actualités'); +tz_def('TZ_OPTIONS', 'Options'); tz_def('TZ_BOLD', 'gras'); tz_def('TZ_BUILDING', 'Bâtiment'); tz_def('TZ_CATAPULT_TARGET', 'cible de la catapulte'); @@ -4188,3 +4193,29 @@ tz_def('ALLYBONUS_RECRUITMENT_DESC', 'Accélère l\'entraînement des troupes da tz_def('ALLYBONUS_PHILOSOPHY_DESC', 'Augmente la production de points de culture des bâtiments et des casques du héros. Les fêtes de l\'hôtel de ville ne sont pas affectées.'); tz_def('ALLYBONUS_METALLURGY_DESC', 'Augmente la force d\'attaque et de défense de vos troupes, en plus des améliorations de la forge.'); tz_def('ALLYBONUS_COMMERCE_DESC', 'Augmente la capacité de charge de chaque marchand. Se multiplie avec le bureau de commerce.'); + +////////////////////////////////////////////////////////////////////////////////////////////////////// +// STATISTICI GRAFICE (Travian Plus) +////////////////////////////////////////////////////////////////////////////////////////////////////// +tz_def('PLUSSTATS_TITLE', 'Statistiques graphiques'); +tz_def('PLUSSTATS_INTRO', 'L\'évolution de votre compte au fil du temps.'); +tz_def('PLUSSTATS_RANK', 'Classement'); +tz_def('PLUSSTATS_POP', 'Population'); +tz_def('PLUSSTATS_ARMY', 'Puissance de l\'armée (consommation de céréales par heure)'); +tz_def('PLUSSTATS_VILLAGES', 'Villages'); +tz_def('PLUSSTATS_TROOPS', 'Troupes'); +tz_def('PLUSSTATS_UPKEEP', 'Consommation de céréales par heure'); +tz_def('PLUSSTATS_METRIC', 'Indicateur'); +tz_def('PLUSSTATS_NOW', 'Maintenant'); +tz_def('PLUSSTATS_CHANGE', 'Évolution'); +tz_def('PLUSSTATS_NODATA', 'Pas encore assez de données'); +tz_def('PLUSSTATS_WAIT', 'Votre compte est en cours d\'enregistrement. Les graphiques apparaîtront dès qu\'il y aura au moins deux relevés.'); +tz_def('PLUSSTATS_NEEDPLUS', 'Les statistiques graphiques sont une fonction Travian Plus. Activez Plus pour voir l\'évolution de votre compte.'); +tz_def('PLUSSTATS_DISABLED', 'Les statistiques graphiques ne sont pas activées sur ce serveur.'); +tz_def('PLUSSTATS_FOOT', 'La puissance de l\'armée se mesure à la consommation de céréales, la pondération propre au jeu : une unité forte compte plus qu\'une faible. Les troupes en renfort chez d\'autres joueurs restent les vôtres.'); +tz_def('ADM_PLUS_STATISTICS', 'Statistiques graphiques Plus'); +tz_def('ADM_PLUS_STATISTICS_TIP', 'Enregistre le classement, la population, les villages et l\'armée de chaque joueur, afin que les joueurs Plus puissent voir l\'évolution de leur compte. L\'onglet n\'est visible qu\'avec un compte Plus actif.'); +tz_def('ADM_PLUS_STATISTICS_INTERVAL', 'Intervalle des relevés (heures)'); +tz_def('ADM_PLUS_STATISTICS_INTERVAL_TIP', 'Fréquence des relevés. Sur un serveur rapide, une journée représente beaucoup de jeu ; quelques heures donnent une courbe lisible.'); +tz_def('ADM_PLUS_STATISTICS_KEEP', 'Historique conservé (jours)'); +tz_def('ADM_PLUS_STATISTICS_KEEP_TIP', '0 conserve tout, afin que les joueurs voient l\'historique complet de leur compte depuis le début de l\'enregistrement.'); diff --git a/GameEngine/Lang/ro.php b/GameEngine/Lang/ro.php index 31521cb7..6fad3af6 100644 --- a/GameEngine/Lang/ro.php +++ b/GameEngine/Lang/ro.php @@ -1957,6 +1957,11 @@ tz_def('TZ_ARRIVED', 'Sosit:'); tz_def('TZ_ASSIGN_TO_POSITION', 'Atribuie la poziție'); tz_def('TZ_AS_SOON_AS_A_PLAYER_YOU_INVITED_FO', 'De îndată ce un jucător invitat de tine își întemeiază'); tz_def('TZ_ATTACKS', 'Atacuri'); +tz_def('TZ_OVERVIEW', 'Prezentare'); +tz_def('TZ_FORUM', 'Forum'); +tz_def('TZ_CHAT', 'Chat'); +tz_def('TZ_NEWS', 'Noutăți'); +tz_def('TZ_OPTIONS', 'Opțiuni'); tz_def('TZ_BOLD', 'îngroșat'); tz_def('TZ_BUILDING', 'Clădire'); tz_def('TZ_CATAPULT_TARGET', 'ținta catapultei'); @@ -3985,3 +3990,29 @@ tz_def('ALLYBONUS_RECRUITMENT_DESC', 'Grabeste instruirea trupelor in toate clad tz_def('ALLYBONUS_PHILOSOPHY_DESC', 'Creste productia de puncte de cultura de la cladiri si de la coifurile eroului. Serbarile din primarie nu sunt afectate.'); tz_def('ALLYBONUS_METALLURGY_DESC', 'Creste forta de atac si de aparare a trupelor, peste imbunatatirile din fierarie.'); tz_def('ALLYBONUS_COMMERCE_DESC', 'Creste cat poate cara fiecare negustor. Se inmulteste cu biroul comercial.'); + +////////////////////////////////////////////////////////////////////////////////////////////////////// +// STATISTICI GRAFICE (Travian Plus) +////////////////////////////////////////////////////////////////////////////////////////////////////// +tz_def('PLUSSTATS_TITLE', 'Statistici grafice'); +tz_def('PLUSSTATS_INTRO', 'Evolutia contului tau in timp.'); +tz_def('PLUSSTATS_RANK', 'Clasament'); +tz_def('PLUSSTATS_POP', 'Populatie'); +tz_def('PLUSSTATS_ARMY', 'Puterea armatei (cereale consumate pe ora)'); +tz_def('PLUSSTATS_VILLAGES', 'Sate'); +tz_def('PLUSSTATS_TROOPS', 'Trupe'); +tz_def('PLUSSTATS_UPKEEP', 'Cereale consumate pe ora'); +tz_def('PLUSSTATS_METRIC', 'Indicator'); +tz_def('PLUSSTATS_NOW', 'Acum'); +tz_def('PLUSSTATS_CHANGE', 'Evolutie'); +tz_def('PLUSSTATS_NODATA', 'Inca nu sunt destule date'); +tz_def('PLUSSTATS_WAIT', 'Contul tau se inregistreaza. Graficele apar dupa ce exista cel putin doua masuratori.'); +tz_def('PLUSSTATS_NEEDPLUS', 'Statisticile grafice sunt o functie Travian Plus. Activeaza Plus ca sa vezi evolutia contului.'); +tz_def('PLUSSTATS_DISABLED', 'Statisticile grafice nu sunt activate pe acest server.'); +tz_def('PLUSSTATS_FOOT', 'Puterea armatei se masoara prin cerealele consumate, cantarul propriu al jocului: o unitate puternica valoreaza mai mult decat una slaba. Trupele trimise ca intarire la alti jucatori raman ale tale.'); +tz_def('ADM_PLUS_STATISTICS', 'Statistici grafice Plus'); +tz_def('ADM_PLUS_STATISTICS_TIP', 'Inregistreaza rangul, populatia, satele si armata fiecarui jucator, ca jucatorii cu Plus sa vada cum a evoluat contul. Tabul se vede doar cu Plus activ.'); +tz_def('ADM_PLUS_STATISTICS_INTERVAL', 'Intervalul intre masuratori (ore)'); +tz_def('ADM_PLUS_STATISTICS_INTERVAL_TIP', 'Cat de des se ia o masuratoare. Pe un server rapid o zi inseamna mult joc, asa ca cateva ore dau o curba lizibila.'); +tz_def('ADM_PLUS_STATISTICS_KEEP', 'Istoric pastrat (zile)'); +tz_def('ADM_PLUS_STATISTICS_KEEP_TIP', '0 pastreaza tot, ca jucatorii sa vada istoricul complet al contului de la inceputul inregistrarii.'); diff --git a/Templates/Alliance/alli_menu.tpl b/Templates/Alliance/alli_menu.tpl index f8e932ab..2a6c11f7 100644 --- a/Templates/Alliance/alli_menu.tpl +++ b/Templates/Alliance/alli_menu.tpl @@ -28,17 +28,17 @@ if ($session->alliance == $aid && $session->alliance > 0) { > - Overview + | > - Forum + | > - Chat + | @@ -48,7 +48,7 @@ if ($session->alliance == $aid && $session->alliance > 0) { | > - News + @@ -64,7 +64,7 @@ if ($session->alliance == $aid && $session->alliance > 0) { ?> | > - Options + '; + return; +} + +$psSeries = array('rank' => array(), 'population' => array(), 'villages' => array(), + 'troop_upkeep' => array(), 'troop_count' => array()); + +foreach ($psRows as $psRow) { + $t = (int) $psRow['recorded_at']; + + // rangul 0 inseamna "neclasat inca" - il sarim, ca sa nu strice scara + if ((int) $psRow['rank'] > 0) { + $psSeries['rank'][] = array($t, (int) $psRow['rank']); + } + + $psSeries['population'][] = array($t, (int) $psRow['population']); + $psSeries['villages'][] = array($t, (int) $psRow['villages']); + $psSeries['troop_upkeep'][] = array($t, (int) $psRow['troop_upkeep']); + $psSeries['troop_count'][] = array($t, (int) $psRow['troop_count']); +} + +echo '
' + . (defined('PLUSSTATS_INTRO') ? PLUSSTATS_INTRO + : 'The development of your account over time.') + . '
'; + +echo '
' + . ps_line_chart($psSeries['rank'], + defined('PLUSSTATS_RANK') ? PLUSSTATS_RANK : 'Ranking', + '#3b7dd8', true) + . '
'; + +echo '
' + . ps_line_chart($psSeries['population'], + defined('PLUSSTATS_POP') ? PLUSSTATS_POP : 'Population', + '#7db72f') + . '
'; + +echo '
' + . ps_line_chart($psSeries['villages'], + defined('PLUSSTATS_VILLAGES') ? PLUSSTATS_VILLAGES : 'Villages', + '#8e6fc4') + . '
'; + +echo '
' + . ps_line_chart($psSeries['troop_upkeep'], + defined('PLUSSTATS_ARMY') ? PLUSSTATS_ARMY : 'Army strength (crop upkeep per hour)', + '#d9822b') + . '
'; + +// ------------------------------------------------- +// REZUMAT: acum fata de primul instantaneu +// ------------------------------------------------- +$psFirst = $psRows[0]; +$psLast = $psRows[count($psRows) - 1]; + +$psFields = array( + 'rank' => defined('PLUSSTATS_RANK') ? PLUSSTATS_RANK : 'Ranking', + 'population' => defined('PLUSSTATS_POP') ? PLUSSTATS_POP : 'Population', + 'villages' => defined('PLUSSTATS_VILLAGES') ? PLUSSTATS_VILLAGES : 'Villages', + 'troop_count' => defined('PLUSSTATS_TROOPS') ? PLUSSTATS_TROOPS : 'Troops', + 'troop_upkeep' => defined('PLUSSTATS_UPKEEP') ? PLUSSTATS_UPKEEP : 'Crop upkeep per hour', +); +?> + + + + + + + + + $psLabel) { + $a = (int) $psFirst[$psKey]; + $b = (int) $psLast[$psKey]; + $d = $b - $a; + + // la rang, scaderea numarului inseamna urcare in clasament + $good = ($psKey === 'rank') ? ($d < 0) : ($d > 0); + $cls = ($d == 0) ? '' : ($good ? 'ps-delta-up' : 'ps-delta-down'); + $sign = ($d > 0) ? '+' : ''; + ?> + + + + + + + +
+ +
+ +
+ + diff --git a/cron.php b/cron.php index a28effbc..835b1fc4 100644 --- a/cron.php +++ b/cron.php @@ -209,7 +209,13 @@ function cron_reset_db_caches() continue; } - $prop->setAccessible(true); + // Din PHP 8.1 proprietatile private sunt accesibile prin reflectie + // fara acest apel, iar din 8.5 apelul e depreciat si umple + // error_log cu zeci de avertismente la fiecare tick de cron. + // Il pastram doar pentru versiunile vechi, unde chiar e necesar. + if (PHP_VERSION_ID < 80100) { + $prop->setAccessible(true); + } if (is_array($prop->getValue())) { $prop->setValue(null, []); diff --git a/gpack/travian_default/img/s/stats.gif b/gpack/travian_default/img/s/stats.gif new file mode 100644 index 0000000000000000000000000000000000000000..123cfffbe2d1ba81efa663e82015e073e7f6ea83 GIT binary patch literal 835 zcmZ?wbhEHblw+`GXk}pd_y5oDzdwKe{{H>vx3Ay7eE$0B)0dAQKY#e}>HWJ8Z{NOu z{p!uji(l7mc~iOhP3??+8|Dxjg^aG;@|S)*=)1`~^$prQ|xL*}RCMiy3i zhlU3emU3{Ig)g(&d3j+AC$}V*tk;x`c3vJSjo4FLRt8NJ^-Owkp|QDnnb?A$oP^1* z{g(1A3)}naOZN56@zMq}UO6thz1>unO(4La;qGoB*GW%S7OiV+V&hYgn6tUSe|EE| z14q;br?%r0l)a~|S@_@ppPzAdnpNqM8)v<@R+(llbc|RPHg%GTWt7Y7>&vXm4>0Wd z7Q`pZvaR)W^rJ&}_udWKqv4c%@PY8+pf{WccC`0hu)Y?uFJ|f4K4v}UzCi0_JCyCNi=S#ieA zfa8kar={+?DRC#?ii+$L zyjsO{^2L;Zb=MNioYwg5Ja#3}bLTGwSK+(`uU*9&mnJqZs7()U<1s3A3_dokBe6rn z=<1u+HICkEHp&NOzwQi|v|hCBkXm%uwkKB6y4x2vdOr#}ye#_N_N!(WBqR9Vq`$B8 OI_mLywK59}gEasJS7#^y literal 0 HcmV?d00001 diff --git a/gpack/travian_default/lang/en/compact.css b/gpack/travian_default/lang/en/compact.css index 1f8375a3..ecf961dc 100644 --- a/gpack/travian_default/lang/en/compact.css +++ b/gpack/travian_default/lang/en/compact.css @@ -7881,6 +7881,9 @@ div.alliance div#submenu img.btn_def, div.statistics div#submenu img.btn_def { div.alliance div#submenu img.btn_off, div.statistics div#submenu img.btn_off { background-image: url("../../img/s/off.gif"); } +div.statistics div#submenu img.btn_stats { + background-image: url("../../img/s/stats.gif"); +} div.statistics div#submenu img.btn_top10 { background-image: url("../../img/s/top10.gif"); } diff --git a/gpack/travian_t4/img/s/stats.gif b/gpack/travian_t4/img/s/stats.gif new file mode 100644 index 0000000000000000000000000000000000000000..123cfffbe2d1ba81efa663e82015e073e7f6ea83 GIT binary patch literal 835 zcmZ?wbhEHblw+`GXk}pd_y5oDzdwKe{{H>vx3Ay7eE$0B)0dAQKY#e}>HWJ8Z{NOu z{p!uji(l7mc~iOhP3??+8|Dxjg^aG;@|S)*=)1`~^$prQ|xL*}RCMiy3i zhlU3emU3{Ig)g(&d3j+AC$}V*tk;x`c3vJSjo4FLRt8NJ^-Owkp|QDnnb?A$oP^1* z{g(1A3)}naOZN56@zMq}UO6thz1>unO(4La;qGoB*GW%S7OiV+V&hYgn6tUSe|EE| z14q;br?%r0l)a~|S@_@ppPzAdnpNqM8)v<@R+(llbc|RPHg%GTWt7Y7>&vXm4>0Wd z7Q`pZvaR)W^rJ&}_udWKqv4c%@PY8+pf{WccC`0hu)Y?uFJ|f4K4v}UzCi0_JCyCNi=S#ieA zfa8kar={+?DRC#?ii+$L zyjsO{^2L;Zb=MNioYwg5Ja#3}bLTGwSK+(`uU*9&mnJqZs7()U<1s3A3_dokBe6rn z=<1u+HICkEHp&NOzwQi|v|hCBkXm%uwkKB6y4x2vdOr#}ye#_N_N!(WBqR9Vq`$B8 OI_mLywK59}gEasJS7#^y literal 0 HcmV?d00001 diff --git a/gpack/travian_t4/lang/en/compact.css b/gpack/travian_t4/lang/en/compact.css index 1f8375a3..ecf961dc 100644 --- a/gpack/travian_t4/lang/en/compact.css +++ b/gpack/travian_t4/lang/en/compact.css @@ -7881,6 +7881,9 @@ div.alliance div#submenu img.btn_def, div.statistics div#submenu img.btn_def { div.alliance div#submenu img.btn_off, div.statistics div#submenu img.btn_off { background-image: url("../../img/s/off.gif"); } +div.statistics div#submenu img.btn_stats { + background-image: url("../../img/s/stats.gif"); +} div.statistics div#submenu img.btn_top10 { background-image: url("../../img/s/top10.gif"); } diff --git a/install/data/constant_format.tpl b/install/data/constant_format.tpl index fb22e09a..7ee8f971 100644 --- a/install/data/constant_format.tpl +++ b/install/data/constant_format.tpl @@ -168,6 +168,26 @@ define("ALLIANCE_BONUS_PCT_LARGE", 4); // Gold cost to triple a donation. define("ALLIANCE_BONUS_TRIPLE_GOLD", 3); +// ***** Graphical statistics (Travian Plus) +// The game periodically records each player's rank, population, villages, and +// army from the moment this feature is enabled. These snapshots are then used +// to generate the account progression graphs. +// +// Data is collected for ALL players, but the Statistics tab is visible ONLY to +// users with an active Plus account. Otherwise, players who purchase Plus would +// open the page and see an empty graph immediately after paying. +define("NEW_FUNCTIONS_PLUS_STATISTICS", %PLUSSTATS%); + +// Number of hours between snapshots. On a fast server, a single day represents +// a significant amount of gameplay, so taking a snapshot every 6 hours provides +// a smooth graph without filling the database table too quickly. +define("PLUS_STATS_INTERVAL_HOURS", %PLUSSTATSHOURS%); + +// Number of days to retain historical data. Set to 0 to keep all snapshots, +// allowing the complete account progression to be displayed. Even over the +// lifetime of an entire server, this only amounts to a few tens of thousands of records. +define("PLUS_STATS_KEEP_DAYS", %PLUSSTATSKEEP%); + // ***** Graphic Pack // // SERVER_GP is the pack every player sees by default (chosen at install or in diff --git a/install/process.php b/install/process.php index c40442e6..d77be357 100644 --- a/install/process.php +++ b/install/process.php @@ -84,6 +84,17 @@ class Process { // Bonusuri de alianta (port T4) $findReplace["%ALLIANCEBONUSES%"] = (isset($_POST['alliance_bonuses']) && $_POST['alliance_bonuses'] === 'true') ? 'true' : 'false'; + // Statistici grafice (Travian Plus) + $findReplace["%PLUSSTATS%"] = (isset($_POST['plus_statistics']) && $_POST['plus_statistics'] === 'false') ? 'false' : 'true'; + + $psHours = isset($_POST['plus_stats_hours']) ? (float) $_POST['plus_stats_hours'] : 6; + if ($psHours < 0.25 || $psHours > 168) { $psHours = 6; } + $findReplace["%PLUSSTATSHOURS%"] = $psHours; + + $psKeep = isset($_POST['plus_stats_keep']) ? (int) $_POST['plus_stats_keep'] : 0; + if ($psKeep < 0 || $psKeep > 3650) { $psKeep = 0; } + $findReplace["%PLUSSTATSKEEP%"] = $psKeep; + $findReplace["%GP%"] = (isset($_POST['gpack']) && $_POST['gpack'] === 'true') ? 'true' : 'false'; $findReplace["%SSERVER%"] = $_POST['sserver']; $findReplace["%SPORT%"] = $_POST['sport']; diff --git a/install/templates/config.tpl b/install/templates/config.tpl index e59c40b7..33dc160b 100644 --- a/install/templates/config.tpl +++ b/install/templates/config.tpl @@ -312,6 +312,12 @@ foreach($mechs as $k => $l){
+
+
+