diff --git a/Multi-Instance Server/Templates/indexnews.tpl b/Multi-Instance Server/Templates/indexnews.tpl new file mode 100644 index 00000000..04942d7b --- /dev/null +++ b/Multi-Instance Server/Templates/indexnews.tpl @@ -0,0 +1,37 @@ + +

+

+ + diff --git a/Multi-Instance Server/Templates/menu.tpl b/Multi-Instance Server/Templates/menu.tpl new file mode 100644 index 00000000..a2f33c23 --- /dev/null +++ b/Multi-Instance Server/Templates/menu.tpl @@ -0,0 +1,439 @@ +pageLoadTimeStart(); + +/** + * Helper variables + * Avoid repeated isset() and direct $_SESSION access + */ +$isLoggedIn = !empty($session->logged_in); +$isPlus = !empty($session->plus); +$isAdmin = (isset($session->access) && $session->access == ADMIN); +$isMH = (isset($session->access) && $session->access == MULTIHUNTER); +$userId = isset($session->uid) ? (int)$session->uid : 0; +$username = isset($session->username) ? $session->username : ''; +$sessionOk = (isset($_SESSION['ok']) && $_SESSION['ok'] == 1); +$idUser = isset($_SESSION['id_user']) ? (int)$_SESSION['id_user'] : 0; +?> + + + + + + + + + + + + + +
+ + + +

+ + + + + + + + + + + +

+ +
+ + + +
+ + + + + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + +

+ + + +

+ + +

+ + Discord + +

+ + +

+ + + + + + P + l + u + s + + + + + + + + +

+ + isDeleting($userId); + + if($timestamp) { + + echo '
'; + + /** + * Allow cancellation if more than 48h remain + */ + if($timestamp > (time() + 172800)) { + + echo ' + '.CANCEL_PROCESS.' + '; + } + + /** + * Remaining deletion time + */ + $time = $generator->getTimeFormat($timestamp - time()); + + echo ' + The account will be deleted in + + ' . $time . ' + . + '; + + echo '
'; + } + ?> + +
+ +userTimeZoneOffset(); +$serverOffset = (int) date('Z'); +if ($localOffset !== $serverOffset): +?> + + + + + +
+ +

+ +

+ +
+ +

+ Hi , +

+ + + +
+ +
+ +

+ + » + +

+ +
+ +
+ +



+ +
+ +


"; + include("Templates/links.tpl"); + } + ?> + +
+ +
+ + + +
+ + + +
+ +
+ +
+ + + + + pageLoadTimeEnd() - $start_timer) * 1000 + ); + ?> + + + ms + +
+ + + + + + + +
+ +
+ +
+ +
+ + + + + + + diff --git a/Multi-Instance Server/anmelden.php b/Multi-Instance Server/anmelden.php new file mode 100644 index 00000000..614326a4 --- /dev/null +++ b/Multi-Instance Server/anmelden.php @@ -0,0 +1,571 @@ +getError('invt'); + +/* + * --------------------------------------------------------------------------- + * Registration wizard data + * --------------------------------------------------------------------------- + * Every label below can be overridden from the language files: if a constant + * with the given name exists it wins, otherwise the English fallback is used. + * No changes are required in lang/*.php for the page to work. + */ +if (!function_exists('regText')) { + function regText($constant, $fallback) { + return defined($constant) ? constant($constant) : $fallback; + } +} + +/* id => tribe definition. The order of this array is the order of the cards. */ +$regTribes = array( + 3 => array( /* Gauls */ + 'name' => TRIBE3, + 'flag' => true, + 'best' => true, + 'lines' => array( + regText('TRIBE3_L1', 'Low time requirements'), + regText('TRIBE3_L2', 'Loot protection and good defense'), + regText('TRIBE3_L3', 'Excellent, fast cavalry'), + regText('TRIBE3_L4', 'Well suited to new players'), + ), + ), + 1 => array( /* Romans */ + 'name' => TRIBE1, + 'flag' => true, + 'best' => false, + 'lines' => array( + regText('TRIBE1_L1', 'Moderate time requirements'), + regText('TRIBE1_L2', 'Can develop villages the fastest'), + regText('TRIBE1_L3', 'Very strong but expensive troops'), + regText('TRIBE1_L4', 'Hard to play for new players'), + ), + ), + 2 => array( /* Teutons */ + 'name' => TRIBE2, + 'flag' => true, + 'best' => false, + 'lines' => array( + regText('TRIBE2_L1', 'High time requirements'), + regText('TRIBE2_L2', 'Good at looting in early game'), + regText('TRIBE2_L3', 'Strong, cheap infantry'), + regText('TRIBE2_L4', 'For aggressive players'), + ), + ), + 7 => array( /* Egyptians */ + 'name' => defined('TRIBE7') ? TRIBE7 : 'Egyptians', + 'flag' => (defined('NEW_FUNCTION_TRIBE_EGIPTEANS') && NEW_FUNCTION_TRIBE_EGIPTEANS), + 'best' => false, + 'lines' => array( + regText('TRIBE7_L1', 'Low time requirements'), + regText('TRIBE7_L2', 'More resources available'), + regText('TRIBE7_L3', 'Excellent defensive units'), + regText('TRIBE7_L4', 'Well suited to new players'), + ), + ), + 6 => array( /* Huns */ + 'name' => defined('TRIBE6') ? TRIBE6 : 'Huns', + 'flag' => (defined('NEW_FUNCTION_TRIBE_HUNS') && NEW_FUNCTION_TRIBE_HUNS), + 'best' => false, + 'lines' => array( + regText('TRIBE6_L1', 'High time requirements'), + regText('TRIBE6_L2', 'Impressively strong cavalry'), + regText('TRIBE6_L3', 'Reliant on others for protection'), + regText('TRIBE6_L4', 'Not recommended for new players!'), + ), + ), + 8 => array( /* Spartans */ + 'name' => defined('TRIBE8') ? TRIBE8 : 'Spartans', + 'flag' => (defined('NEW_FUNCTION_TRIBE_SPARTANS') && NEW_FUNCTION_TRIBE_SPARTANS), + 'best' => false, + 'lines' => array( + regText('TRIBE8_L1', 'Moderate time requirements'), + regText('TRIBE8_L2', 'Efficient crop consumption'), + regText('TRIBE8_L3', 'Easier recovery from battles'), + regText('TRIBE8_L4', 'Recommended for active new players'), + ), + ), + 9 => array( /* Vikings */ + 'name' => defined('TRIBE9') ? TRIBE9 : 'Vikings', + 'flag' => (defined('NEW_FUNCTION_TRIBE_VIKINGS') && NEW_FUNCTION_TRIBE_VIKINGS), + 'best' => false, + 'lines' => array( + regText('TRIBE9_L1', 'High time requirements'), + regText('TRIBE9_L2', 'Fearless raiders, strong offense'), + regText('TRIBE9_L3', 'Weak defense in the early game'), + regText('TRIBE9_L4', 'Not recommended for new players!'), + ), + ), +); + +/* Drop every tribe that is disabled by the install feature flags. */ +foreach ($regTribes as $tribeId => $tribeData) { + if (!$tribeData['flag']) { + unset($regTribes[$tribeId]); + } +} + +/* Starting positions: 0 = random, 1 = NW (-|+), 2 = NE (+|+), 3 = SW (-|-), 4 = SE (+|-) */ +$regQuadrants = array( + 0 => array('name' => RANDOM, 'coords' => ''), + 1 => array('name' => NW, 'coords' => '(-|+)'), + 2 => array('name' => NE, 'coords' => '(+|+)'), + 3 => array('name' => SW, 'coords' => '(-|-)'), + 4 => array('name' => SE, 'coords' => '(+|-)'), +); + +/* Values coming back from a failed POST (Account::Signup redirects here). */ +$regErrors = ($form->returnErrors() > 0); +$regTribe = (int) $form->getValue('vid'); +if (!isset($regTribes[$regTribe])) { + reset($regTribes); + $regTribe = (int) key($regTribes); // first card = Gauls (the recommended tribe) +} +$regQuad = (int) $form->getValue('kid'); +if (!isset($regQuadrants[$regQuad])) { + $regQuad = 0; +} +/* When the server rejected the form we jump straight back to the recap step. */ +$regStep = $regErrors ? 3 : 1; +?> + + + + <?php echo SERVER_NAME; ?> - Registration + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+ + + + + + + + + +
+ +
+ +
+
+ + +
+ + +
+ + diff --git a/Multi-Instance Server/index.php b/Multi-Instance Server/index.php new file mode 100644 index 00000000..837f22ec --- /dev/null +++ b/Multi-Instance Server/index.php @@ -0,0 +1,785 @@ + array( + 'name' => 'Server 1', + 'url' => 'https://travianz.org/', + 'login' => 'https://travianz.org/login.php', + 'signup' => 'https://travianz.org/anmelden.php', + 'image' => 'en1_big.jpg', + 'status' => 'https://travianz.org/index.php?server_status=1', + 'newsbox' => 'https://travianz.org/index.php?server_newsbox=1' + ), + 2 => array( + 'name' => 'Server 2', + 'url' => 'https://s2.travianz.org/', + 'login' => 'https://s2.travianz.org/login.php', + 'signup' => 'https://s2.travianz.org/anmelden.php', + 'image' => 'en2_big.jpg', + 'status' => 'https://s2.travianz.org/index.php?server_status=1', + 'newsbox' => 'https://s2.travianz.org/index.php?server_newsbox=1' + ), + 3 => array( + 'name' => 'Speed 3x', + 'url' => 'https://speed.travianz.org/', + 'login' => 'https://speed.travianz.org/login.php', + 'signup' => 'https://speed.travianz.org/anmelden.php', + 'image' => 'enx_big.jpg', + 'status' => 'https://speed.travianz.org/index.php?server_status=1', + 'newsbox' => 'https://speed.travianz.org/index.php?server_newsbox=1' + ) + // Adauga aici worlds noi, ex: + // 4 => array( + // 'name' => 'Server 3', + // 'url' => 'https://s3.travianz.org/', + // 'login' => 'https://s3.travianz.org/login.php', + // 'signup' => 'https://s3.travianz.org/anmelden.php', + // 'image' => 'en3_big.jpg', + // 'status' => 'https://s3.travianz.org/index.php?server_status=1', + // 'newsbox' => 'https://s3.travianz.org/index.php?server_newsbox=1' + // ), +); + +/* + * Fiecare instanta de joc isi expune propriile statistici prin endpoint-ul + * ?server_status=1 de mai jos - ruleaza pe DB-ul instantei CURENTE, deci + * Server 1 nu poate afla niciodata contoarele de la Server 2/3. + */ +if (isset($_GET['server_status'])) { + header('Content-Type: application/json; charset=utf-8'); + + $tribes = '1, 2, 3, 6, 7, 8, 9'; + + $users = 0; + $active = 0; + $online = 0; + + $return = mysqli_query( + $link, + "SELECT COUNT(*) AS Total FROM " . TB_PREFIX . "users WHERE tribe IN(" . $tribes . ")" + ); + + if ($return) { + $row = mysqli_fetch_assoc($return); + $users = isset($row['Total']) ? (int)$row['Total'] : 0; + } + + $return = mysqli_query( + $link, + "SELECT COUNT(*) AS Total FROM " . TB_PREFIX . "users WHERE timestamp > " . (time() - (3600 * 24)) . " AND tribe IN(" . $tribes . ")" + ); + + if ($return) { + $row = mysqli_fetch_assoc($return); + $active = isset($row['Total']) ? (int)$row['Total'] : 0; + } + + $return = mysqli_query( + $link, + "SELECT COUNT(*) AS Total FROM " . TB_PREFIX . "users WHERE timestamp > " . (time() - (60 * 10)) . " AND tribe IN(" . $tribes . ")" + ); + + if ($return) { + $row = mysqli_fetch_assoc($return); + $online = isset($row['Total']) ? (int)$row['Total'] : 0; + } + + echo json_encode(array( + 'status' => 'online', + 'players' => $users, + 'active' => $active, + 'online' => $online + )); + + exit; +} + +/* + * Endpoint public nou: ?server_newsbox=1 + * Expune, in JSON, exact aceleasi date pe care in-game le arata deja + * Templates/News/newsbox1.tpl (jucatori online, viteza, harta, protectie, + * top player etc.) - aceleasi query-uri/conditii, doar output JSON in loc + * de HTML, ca sa poata fi citit de lobby-ul altui world (sau de acest + * index.php insusi, pentru propriile date). + */ +if (isset($_GET['server_newsbox'])) { + header('Content-Type: application/json; charset=utf-8'); + + $online_total = 0; + $return = mysqli_query( + $link, + "SELECT COUNT(*) AS Total FROM " . TB_PREFIX . "users WHERE timestamp > " . (time() - (60 * 10)) . " AND tribe != 0 AND tribe != 4 AND tribe != 5" + ); + if ($return) { + $row = mysqli_fetch_assoc($return); + if ($row && isset($row['Total'])) { + $online_total = (int)$row['Total']; + } + } + + $top_username = '-'; + $top_query = mysqli_query( + $link, + "SELECT username FROM " . TB_PREFIX . "users WHERE " . + (INCLUDE_ADMIN ? 'access > 0 AND ' : 'access > 0 AND access < 8 AND ') . + "id > 5 AND tribe IN (1,2,3,6,7,8,9) AND tribe > 0 ORDER BY oldrank ASC LIMIT 1" + ); + if ($top_query) { + $row = mysqli_fetch_assoc($top_query); + if ($row && !empty($row['username'])) { + $top_username = $row['username']; + } + } + + if (CP == 0) { + $village_exp = 'Fast'; + } else if (CP == 1) { + $village_exp = 'Slow'; + } else { + $village_exp = '-'; + } + + if (MEDALINTERVAL >= 86400) { + $medal_interval = (MEDALINTERVAL / 86400) . ' Days'; + } else { + $medal_interval = (MEDALINTERVAL / 3600) . ' Hours'; + } + + $peaceTypes = array('None', 'Normal', 'Christmas', 'New Year', 'Easter'); + $peace_system = isset($peaceTypes[PEACE]) ? $peaceTypes[PEACE] : 'Unknown'; + + echo json_encode(array( + 'online_users' => $online_total, + 'speed' => SPEED, + 'troop_speed' => INCREASE_SPEED, + 'evasion_speed' => EVASION_SPEED, + 'map_size' => WORLD_MAX, + 'village_exp' => $village_exp, + 'protection_hours' => (int)(PROTECTION / 3600), + 'medal_interval' => $medal_interval, + 'start_date' => START_DATE, + 'peace_system' => $peace_system, + 'best_player' => $top_username + )); + + exit; +} + +/* + * Fetch generic, in PARALEL (curl_multi), de JSON de la o lista de + * URL-uri indexate dupa id de world. Folosit atat pentru server_status + * cat si pentru server_newsbox - un singur loc care stie sa vorbeasca + * HTTP catre celelalte worlds. + */ +define('MULTI_STATUS_CONNECT_TIMEOUT', 2); +define('MULTI_STATUS_TIMEOUT', 3); + +function fetchJsonFromServers(array $urlsById) +{ + $results = array(); + + if (!function_exists('curl_multi_init')) { + // cURL indisponibil - toate worlds-urile raman fara date live. + foreach ($urlsById as $id => $url) { + $results[$id] = null; + } + return $results; + } + + $multiHandle = curl_multi_init(); + $handles = array(); + + foreach ($urlsById as $id => $url) { + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, MULTI_STATUS_CONNECT_TIMEOUT); + curl_setopt($ch, CURLOPT_TIMEOUT, MULTI_STATUS_TIMEOUT); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); + + curl_multi_add_handle($multiHandle, $ch); + $handles[$id] = $ch; + } + + $running = null; + do { + curl_multi_exec($multiHandle, $running); + curl_multi_select($multiHandle); + } while ($running > 0); + + foreach ($handles as $id => $ch) { + $decoded = null; + $httpCode = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE); + $response = curl_multi_getcontent($ch); + + if ($response !== false && $response !== null && $httpCode === 200) { + $data = json_decode($response, true); + if (is_array($data)) { + $decoded = $data; + } + } + + curl_multi_remove_handle($multiHandle, $ch); + curl_close($ch); + + $results[$id] = $decoded; + } + + curl_multi_close($multiHandle); + + return $results; +} + +function normalizeServerStatus($data) +{ + $default = array('status' => 'offline', 'players' => 0, 'active' => 0, 'online' => 0); + + if (!is_array($data) || !isset($data['players'])) { + return $default; + } + + return array( + 'status' => isset($data['status']) ? $data['status'] : 'online', + 'players' => (int)$data['players'], + 'active' => isset($data['active']) ? (int)$data['active'] : 0, + 'online' => isset($data['online']) ? (int)$data['online'] : 0 + ); +} + +function normalizeServerNewsbox($data) +{ + $default = array( + 'online_users' => 0, + 'speed' => '-', + 'troop_speed' => '-', + 'evasion_speed' => '-', + 'map_size' => '-', + 'village_exp' => '-', + 'protection_hours' => '-', + 'medal_interval' => '-', + 'start_date' => '-', + 'peace_system' => '-', + 'best_player' => '-' + ); + + if (!is_array($data)) { + return $default; + } + + $result = $default; + foreach ($default as $key => $unused) { + if (isset($data[$key]) && $data[$key] !== '') { + $result[$key] = $data[$key]; + } + } + + return $result; +} + +/* + * Helpere de afisare pentru cardurile de newsbox: cand un world nu a + * raspuns (ex. inca nu are endpoint-ul ?server_newsbox=1 activ), toate + * campurile raman pe placeholder-ul '-' din normalizeServerNewsbox(). Fara + * aceste helpere, sufixele (x / ore) s-ar lipi de placeholder si ar iesi + * afisari confuze de genul "-x" in loc de un simplu "-". + */ +function mi_newsbox_value($value, $suffix = '') +{ + $value = (string)$value; + if ($value === '-' || $value === '') { + return '-'; + } + return htmlspecialchars($value, ENT_QUOTES, 'UTF-8') . $suffix; +} + +function mi_newsbox_map_size($value) +{ + $value = (string)$value; + if ($value === '-' || $value === '') { + return '-'; + } + $escaped = htmlspecialchars($value, ENT_QUOTES, 'UTF-8'); + return $escaped . 'x' . $escaped; +} + +/* + * Cache scurt pentru fetch-urile intre worlds (status + newsbox). + * Fara asta, FIECARE vizitator pe pagina asta declanseaza N cereri HTTP + * catre celelalte worlds - inutil pentru date cvasi-statice si pune + * sarcina degeaba pe serverele celorlalte worlds. + */ +function getCachedJson($cacheFile, $ttlSeconds, callable $fetcher) +{ + if (is_readable($cacheFile) && (time() - filemtime($cacheFile)) < $ttlSeconds) { + $cached = json_decode(file_get_contents($cacheFile), true); + + if (is_array($cached)) { + return $cached; + } + // Anomalie: fisierul de cache exista dar nu e JSON valid - trecem + // peste el si reluam fetch-ul live in loc sa incredem date corupte. + } + + $data = $fetcher(); + + $cacheDir = dirname($cacheFile); + if (!is_dir($cacheDir)) { + @mkdir($cacheDir, 0755, true); + } + // Best-effort: daca var/cache nu e writable, pur si simplu nu se + // cacheaza si fiecare request face fetch live. + @file_put_contents($cacheFile, json_encode($data)); + + return $data; +} + +define('MULTI_STATUS_CACHE_TTL', 30); +define('MULTI_NEWSBOX_CACHE_TTL', 60); + +$serverStats = getCachedJson(__DIR__ . '/var/cache/server_status.json', MULTI_STATUS_CACHE_TTL, function () use ($servers) { + $urls = array(); + foreach ($servers as $id => $server) { + $urls[$id] = $server['status']; + } + + $raw = fetchJsonFromServers($urls); + + $stats = array(); + foreach ($raw as $id => $data) { + $stats[$id] = normalizeServerStatus($data); + } + + return $stats; +}); + +$serverNewsboxes = getCachedJson(__DIR__ . '/var/cache/server_newsbox.json', MULTI_NEWSBOX_CACHE_TTL, function () use ($servers) { + $urls = array(); + foreach ($servers as $id => $server) { + $urls[$id] = $server['newsbox']; + } + + $raw = fetchJsonFromServers($urls); + + $newsboxes = array(); + foreach ($raw as $id => $data) { + $newsboxes[$id] = normalizeServerNewsbox($data); + } + + return $newsboxes; +}); + +foreach ($servers as $serverId => $server) { + $servers[$serverId]['stats'] = isset($serverStats[$serverId]) + ? $serverStats[$serverId] + : normalizeServerStatus(null); + + $servers[$serverId]['newsbox'] = isset($serverNewsboxes[$serverId]) + ? $serverNewsboxes[$serverId] + : normalizeServerNewsbox(null); +} + +/* + * Pastreaza variabilele vechi pentru restul paginii legacy. + * Contorul din lobby de mai jos foloseste suma tuturor worlds-urilor. + */ +$users = 0; +$active = 0; +$online = 0; + +foreach ($servers as $server) { + $users += $server['stats']['players']; + $active += $server['stats']['active']; + $online += $server['stats']['online']; +} +?> + + + + <?php echo SERVER_NAME; ?> + + + + + + + + + + + + + +
+
+
+ + +
+ + + +
+ + Travian 4 + +
+ +
+ + +
+
+
+
+
+

+

+

+
+
+ + + + + + + + + + + + + + + +
:
:
:
+
+
+

:

+
    +
  • +
  • +
  • +
+
+
+
+
+

+ +
+
    +
  • Screenshot
  • +
  • Screenshot
  • +
  • Screenshot
  • +
  • Screenshot
  • +
  • Screenshot
  • +
  • Screenshot
  • +
  • Screenshot
  • +
+
+
+
+

+
+
+
+
+
+
+

Available Worlds

+
+ +
+

+
+
+ : + +
+
+ : + +
+
+ : + +
+
+ : + +
+
+ : + +
+
+ : + +
+
+ : + +
+
+ : + +
+
+ : + +
+
+ : + +
+
+
+ : + +
+
+ +
+
+
+ +
+
+
+
+

+ Close +
    + +
  • + + <?php echo htmlspecialchars($server['name'], ENT_QUOTES, 'UTF-8'); ?> + +
    :
    +
    :
    +
    +
    +
  • + +
+ +
+
+ +
+
+
+

+ Close +
    + +
  • + + <?php echo htmlspecialchars($server['name'], ENT_QUOTES, 'UTF-8'); ?> + +
    :
    +
    :
    +
    +
    +
  • + +
+ +
+
+
+
+
+ Close +

+
+ +
+
+
+
+
+

+ Close +
+

+ Screenshot +
+
+ + + +
+
+ + + diff --git a/Multi-Instance Server/login.php b/Multi-Instance Server/login.php new file mode 100644 index 00000000..7a57caff --- /dev/null +++ b/Multi-Instance Server/login.php @@ -0,0 +1,264 @@ + + + + + <?php echo SERVER_NAME; ?> - Login + + + + + + + + + + + + + + + + + +
+
+
+ +
+ + + +
+ +
+ +
+
+ + +
+ + +
+ +