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/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'];
+}
+?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ | : |
+ |
+
+
+ | : |
+ |
+
+
+ | : |
+ |
+
+
+
+
+
+
+
+
+
+

+

+
+
+
+
+
+
+
Available Worlds
+
+
+
+
+
+
+ :
+
+
+
+ :
+
+
+
+ :
+
+
+
+ :
+
+
+
+ :
+
+
+
+ :
+
+
+
+ :
+
+
+
+ :
+
+
+
+ :
+
+
+
+ :
+
+
+
+
+ :
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+
+
+ -
+
+
+
+ :
+ :
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+
+
+ -
+
+
+
+ :
+ :
+
+
+
+
+
+
+
+
+
+
+
+

+
+
+
+
+
+
+
+
+
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 @@
+
+
+
+
+
- Login
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+