From 9e198c3ee2e8096b64b525b2759f5816dd46e565 Mon Sep 17 00:00:00 2001 From: M_Viper Date: Sun, 23 Nov 2025 10:10:06 +0000 Subject: [PATCH] minecraft-server-status.php aktualisiert --- minecraft-server-status.php | 861 +++++++++++++++++++++++------------- 1 file changed, 559 insertions(+), 302 deletions(-) diff --git a/minecraft-server-status.php b/minecraft-server-status.php index 62a9d95..dca11e8 100644 --- a/minecraft-server-status.php +++ b/minecraft-server-status.php @@ -1,14 +1,18 @@ admin_url('admin-ajax.php'), 'refresh_interval' => max(10, intval(get_option('mcss_cache_ttl', 15))) * 1000 ]); }); -/* ---------------- Settings registrieren ---------------- */ +/* ---------------- Settings ---------------- */ add_action('admin_menu', function(){ add_options_page('Minecraft Server', 'Minecraft Server', 'manage_options', 'mcss-settings', 'mcss_settings_page'); }); add_action('admin_init', function(){ - register_setting('mcss_settings_group', 'mcss_host', ['sanitize_callback'=>'sanitize_text_field']); - register_setting('mcss_settings_group', 'mcss_rcon_port', ['sanitize_callback'=>'intval']); - register_setting('mcss_settings_group', 'mcss_rcon_pass', ['sanitize_callback'=>'sanitize_text_field']); - register_setting('mcss_settings_group', 'mcss_cache_ttl', ['sanitize_callback'=>'intval']); - register_setting('mcss_settings_group', 'mcss_show_motd', ['sanitize_callback'=>'boolval']); - register_setting('mcss_settings_group', 'mcss_ranks_json', ['sanitize_callback'=>'mcss_sanitize_ranks']); - register_setting('mcss_settings_group', 'mcss_server_logo_id', ['sanitize_callback'=>'absint']); - register_setting('mcss_settings_group', 'mcss_server_logo_url', ['sanitize_callback'=>'esc_url_raw']); - register_setting('mcss_settings_group', 'mcss_custom_text', ['sanitize_callback'=>'wp_kses_post']); - register_setting('mcss_settings_group', 'mcss_ip_color', ['default' => '#1f2937', 'sanitize_callback' => 'sanitize_hex_color']); - register_setting('mcss_settings_group', 'mcss_ct_color', ['default' => '#1e293b', 'sanitize_callback' => 'sanitize_hex_color']); - register_setting('mcss_settings_group', 'mcss_ip_size', ['default' => '1.5em', 'sanitize_callback' => 'sanitize_text_field']); - register_setting('mcss_settings_group', 'mcss_ct_size', ['default' => '1.05em', 'sanitize_callback' => 'sanitize_text_field']); - register_setting('mcss_settings_group', 'mcss_hide_port', ['default' => true, 'sanitize_callback' => 'rest_sanitize_boolean']); - register_setting('mcss_settings_group', 'mcss_player_port', ['default' => '', 'sanitize_callback' => 'sanitize_text_field']); + register_setting('mcss_settings_group', 'mcss_servers', ['sanitize_callback'=>'mcss_sanitize_servers']); }); -/* Sanitize Ranks */ +function mcss_sanitize_servers($input) { + if (!is_array($input)) return []; + $clean = []; + foreach ($input as $srv) { + if (!is_array($srv)) continue; + $clean[] = [ + 'id' => sanitize_key($srv['id'] ?? 'srv_'.wp_rand()), + 'name' => sanitize_text_field($srv['name'] ?? 'Server'), + 'host' => sanitize_text_field($srv['host'] ?? ''), + 'query_port' => absint($srv['query_port'] ?? 25565), + 'rcon_port' => absint($srv['rcon_port'] ?? 25575), + 'rcon_pass' => sanitize_text_field($srv['rcon_pass'] ?? ''), + 'player_port' => sanitize_text_field($srv['player_port'] ?? ''), + 'hide_port' => !empty($srv['hide_port']), + 'show_motd' => !empty($srv['show_motd']), + 'cache_ttl' => max(5, absint($srv['cache_ttl'] ?? 15)), + 'logo_id' => absint($srv['logo_id'] ?? 0), + 'logo_url' => esc_url_raw($srv['logo_url'] ?? ''), + 'custom_text' => wp_kses_post($srv['custom_text'] ?? ''), + 'ip_color' => sanitize_hex_color($srv['ip_color'] ?? '#1f2937'), + 'ct_color' => sanitize_hex_color($srv['ct_color'] ?? '#1e293b'), + 'ip_size' => sanitize_text_field($srv['ip_size'] ?? '1.5em'), + 'ct_size' => sanitize_text_field($srv['ct_size'] ?? '1.05em'), + 'name_color' => sanitize_hex_color($srv['name_color'] ?? '#1e293b'), + 'name_size' => sanitize_text_field($srv['name_size'] ?? '1.8em'), + 'maintenance_mode' => !empty($srv['maintenance_mode']), + 'maintenance_message' => wp_kses_post($srv['maintenance_message'] ?? 'Der Server befindet sich derzeit im Wartungsmodus. Wir sind bald wieder für dich da!'), + 'ranks_json' => mcss_sanitize_ranks($srv['ranks_json'] ?? '[]'), + ]; + } + return $clean; +} + function mcss_sanitize_ranks($input) { $decoded = json_decode($input, true); if (!is_array($decoded)) return '[]'; @@ -77,20 +99,16 @@ function mcss_sanitize_ranks($input) { return wp_json_encode($out); } -/* Settings Page */ +/* ---------------- Settings Page ---------------- */ function mcss_settings_page() { - $logo_id = get_option('mcss_server_logo_id', 0); - $logo_url = get_option('mcss_server_logo_url', ''); - $current_logo = $logo_id ? wp_get_attachment_image_url($logo_id, 'medium') : $logo_url; - if (!$current_logo) $current_logo = MCSS_URL . 'img/default-server-logo.png'; - $custom_text = get_option('mcss_custom_text', ''); - $ip_color = get_option('mcss_ip_color', '#1f2937'); - $ct_color = get_option('mcss_ct_color', '#1e293b'); - $ip_size = get_option('mcss_ip_size', '1.5em'); - $ct_size = get_option('mcss_ct_size', '1.05em'); - $hide_port = get_option('mcss_hide_port', true); - $player_port = get_option('mcss_player_port', ''); - + $servers = get_option('mcss_servers', []); + if (empty($servers)) { + $servers = [[ + 'id' => 'default', 'name' => 'Hauptserver', 'host' => '', 'query_port' => 25565, + 'rcon_port' => 25575, 'cache_ttl' => 15, 'hide_port' => true, 'show_motd' => true + ]]; + } + $font_sizes = [ '0.7em' => 'Sehr klein','0.85em' => 'Klein','1em' => 'Normal','1.2em' => 'Etwas größer', '1.4em' => 'Groß','1.5em' => 'Sehr groß (Standard)','1.7em' => 'Extra groß','2em' => 'Riesig', @@ -101,108 +119,282 @@ function mcss_settings_page() {

Minecraft Server Einstellungen

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Server Host
RCON Port
RCON Passwort
Cache TTL (Sekunden)
MOTD anzeigen? />
- -

Wird nicht angezeigt, aber beim Klick mitkopiert.
Leer = kein Port wird kopiert.

-
Port in Adresse ausblenden? />
-
- -
- - - - -
- -

HTML + Emojis erlaubt.

-
IP-Adresse – Schrift - - - - -
Zusatztext – Schrift - - - - -
- -

Ränge (LuckPerms Zuordnung)

-

Die Ränge werden automatisch über LuckPerms per RCON abgerufen.

-
- - +
+ $srv): mcss_render_server_row($srv, $i, $font_sizes); endforeach; ?> +
+

Tools

RCON testen

- -
+ +
'Host oder Passwort nicht gesetzt']; - $rcon = new Rcon($host, $port, $pass, 3); +function mcss_render_server_row($srv, $i, $font_sizes) { + $logo_id = $srv['logo_id'] ?? 0; + $logo_url = $srv['logo_url'] ?? ''; + $current_logo = $logo_id ? wp_get_attachment_image_url($logo_id, 'medium') : $logo_url; + if (!$current_logo) $current_logo = MCSS_URL . 'img/default-server-logo.png'; + ?> +
+ +

Server :

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Name (intern)
Name – Schrift + + + + +
Server Host
RCON Port
RCON Passwort
Cache TTL (Sekunden)
MOTD anzeigen? />
+ +

Wird nicht angezeigt, aber beim Klick mitkopiert.
Leer = kein Port wird kopiert.

+
Port in Adresse ausblenden? />
+
+ +
+ + + + +
+ +

HTML + Emojis erlaubt.

+
IP-Adresse – Schrift + + + + +
Zusatztext – Schrift + + + + +
+ /> + +

Wenn aktiviert, wird eine Wartungsnachricht anstelle der Server-Informationen angezeigt.

+
+ +

HTML + Emojis erlaubt. Diese Nachricht wird angezeigt, wenn der Wartungsmodus aktiv ist.

+
+ +

Ränge (LuckPerms Zuordnung)

+

Die Ränge werden automatisch über LuckPerms per RCON abgerufen.

+
+ + + +
+ 'Host oder Passwort nicht gesetzt']; + $rcon = new Rcon($srv['host'], $srv['rcon_port'], $srv['rcon_pass'], 3); $out = ['connected' => false]; if ($rcon->connect()) { $out['connected'] = true; @@ -234,18 +426,13 @@ function mcss_normalize_version($raw) { return trim($raw); } -/* ---------------- LuckPerms helper ---------------- */ -function mcss_fetch_luckperms_groups() { - $host = get_option('mcss_host', ''); - $port = intval(get_option('mcss_rcon_port', 25575)); - $pass = get_option('mcss_rcon_pass', ''); - if (empty($host) || empty($pass)) return []; - - $cache_key = 'mcss_lp_groups_' . md5($host . ':' . $port); +function mcss_fetch_luckperms_groups($srv) { + if (empty($srv['host']) || empty($srv['rcon_pass'])) return []; + $cache_key = 'mcss_lp_groups_' . md5($srv['host'].':'.$srv['rcon_port']); $cached = get_transient($cache_key); if ($cached !== false) return $cached; - $rcon = new Rcon($host, $port, $pass, 3); + $rcon = new Rcon($srv['host'], $srv['rcon_port'], $srv['rcon_pass'], 3); if (!$rcon->connect()) return []; $groups = []; @@ -269,7 +456,6 @@ function mcss_fetch_luckperms_groups() { foreach ($names as $n) if ($n !== '') $groups[] = $n; } } - $groups = array_values(array_unique(array_filter($groups))); $group_infos = []; @@ -284,10 +470,8 @@ function mcss_fetch_luckperms_groups() { } $color = '#6c5ce7'; if ($prefix) { $c = mcss_color_from_prefix($prefix); if ($c) $color = $c; } - $group_infos[] = ['group'=>$g,'weight'=>$weight,'prefix'=>$prefix,'color'=>$color]; } - $rcon->disconnect(); usort($group_infos, fn($a,$b) => $b['weight'] <=> $a['weight']); @@ -295,7 +479,6 @@ function mcss_fetch_luckperms_groups() { foreach ($group_infos as $gi) { $ranks[] = ['name'=>$gi['group'],'groups'=>$gi['group'],'color'=>$gi['color'],'prefix'=>$gi['prefix']]; } - set_transient($cache_key, $ranks, 12 * HOUR_IN_SECONDS); return $ranks; } @@ -313,31 +496,24 @@ function mcss_color_from_prefix($prefix) { return null; } -/* ---------------- UUID-Resolver & Avatar ---------------- */ function mcss_get_uuid_from_name($name) { if (empty($name) || !preg_match('/^[a-zA-Z0-9_]{3,16}$/', $name)) return false; $key = 'mcss_uuid_' . strtolower($name); $cached = get_transient($key); if ($cached !== false && $cached !== 'invalid') return $cached; - $response = wp_remote_get("https://api.mojang.com/users/profiles/minecraft/" . rawurlencode($name), [ - 'timeout' => 6, - 'user-agent' => 'MCSS-Plugin/1.9' - ]); - + $response = wp_remote_get("https://api.mojang.com/users/profiles/minecraft/" . rawurlencode($name), ['timeout'=>6]); if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) { set_transient($key, 'invalid', 60); return false; } - $body = json_decode(wp_remote_retrieve_body($response), true); if (empty($body['id'])) { - set_transient($key, 'invalid', 24 * HOUR_IN_SECONDS); + set_transient($key, 'invalid', 86400); return false; } - $uuid = $body['id']; - set_transient($key, $uuid, 30 * DAY_IN_SECONDS); + set_transient($key, $uuid, 30*DAY_IN_SECONDS); return $uuid; } @@ -347,55 +523,64 @@ function mcss_avatar($input, $size = 64) { $uuid = preg_replace('/-/', '', $input); } else { $uuid = mcss_get_uuid_from_name($input); - if (!$uuid) { - return "https://mc-heads.net/avatar/" . rawurlencode($input) . "/{$size}"; - } + if (!$uuid) return "https://mc-heads.net/avatar/" . rawurlencode($input) . "/{$size}"; } return "https://mc-heads.net/avatar/{$uuid}/{$size}"; } -/* ---------------- Hauptfunktion – PREFIX ALS RANG! ---------------- */ -add_action('wp_ajax_nopriv_mcss_fetch', 'mcss_ajax_fetch'); -add_action('wp_ajax_mcss_fetch', 'mcss_ajax_fetch'); -function mcss_ajax_fetch() { - wp_send_json(mcss_fetch_server_with_ranks()); +/* ---------------- FUNKTION FÜR PING-MESSUNG ---------------- */ +function mcss_ping_server($host, $port = 25565, $timeout = 2) { + $startTime = microtime(true); + + // Versuche, eine TCP-Verbindung zum Server herzustellen + $socket = @fsockopen($host, $port, $errno, $errstr, $timeout); + + if (!$socket) { + return false; // Server ist nicht erreichbar + } + + // Schließe die Verbindung + fclose($socket); + + // Berechne die Ping-Zeit in Millisekunden + $endTime = microtime(true); + $ping = round(($endTime - $startTime) * 1000); + + return $ping; } -function mcss_fetch_server_with_ranks() { - $host = get_option('mcss_host', ''); - if (empty($host)) return ['online'=>false,'players'=>[],'address'=>'','version'=>'Unbekannt','ping'=>0,'motd'=>'','last_update'=>time()]; +/* ---------------- Fetch & AJAX ---------------- */ +add_action('wp_ajax_mcss_fetch', 'mcss_ajax_fetch'); +add_action('wp_ajax_nopriv_mcss_fetch', 'mcss_ajax_fetch'); - $port = intval(get_option('mcss_rcon_port', 25575)); - $pass = get_option('mcss_rcon_pass', ''); - $ttl = max(5, intval(get_option('mcss_cache_ttl', 15))); - $show_motd = (bool)get_option('mcss_show_motd', true); +function mcss_ajax_fetch() { + $id = sanitize_text_field($_POST['server_id'] ?? ''); + $servers = get_option('mcss_servers', []); + foreach ($servers as $srv) { + if (($srv['id'] ?? '') === $id) { + wp_send_json(mcss_fetch_server_with_ranks($srv)); + } + } + wp_send_json(['online'=>false,'players'=>[],'address'=>'','version'=>'Unbekannt','ping'=>0,'motd'=>'']); +} - $transient_key = 'mcss_data_' . md5($host . ':' . $port); - $cached = get_transient($transient_key); +function mcss_fetch_server_with_ranks($srv) { + $cache_key = 'mcss_data_' . md5($srv['host'].':'.$srv['rcon_port']); + $cached = get_transient($cache_key); if ($cached !== false) { - $cached['last_update'] = get_option($transient_key . '_time', time()); + $cached['last_update'] = get_option($cache_key.'_time', time()); return $cached; } - $result = [ - 'online' => false, - 'players' => [], - 'address' => $host . ':' . $port, - 'version' => 'Unbekannt', - 'ping' => 0, - 'motd' => '', - 'last_update' => time() - ]; - + $result = ['online'=>false,'players'=>[],'address'=>$srv['host'].':'.$srv['rcon_port'],'version'=>'Unbekannt','ping'=>0,'motd'=>'','last_update'=>time()]; $raw_players = []; - if (!empty($pass)) { - $rcon = new Rcon($host, $port, $pass, 3); + if (!empty($srv['rcon_pass'])) { + $rcon = new Rcon($srv['host'], $srv['rcon_port'], $srv['rcon_pass'], 3); if ($rcon->connect()) { $list_raw = $rcon->sendCommand('list'); if (preg_match('/: (.*)$/', $list_raw, $m)) { - $list = trim($m[1]); - $entries = array_filter(array_map('trim', explode(',', $list))); + $entries = array_filter(array_map('trim', explode(',', $m[1]))); foreach ($entries as $entry) { if (preg_match('/\s+([a-zA-Z0-9_]{3,16})$/', $entry, $n)) { $clean_name = $n[1]; @@ -413,15 +598,13 @@ function mcss_fetch_server_with_ranks() { $rcon->disconnect(); } } - - $api_host = $port !== 25565 ? $host . ':' . $port : $host; - $resp = wp_remote_get('https://api.mcsrvstat.us/2/' . rawurlencode($api_host), ['timeout'=>7]); + $api_host = $srv['query_port'] != 25565 ? $srv['host'].':'.$srv['query_port'] : $srv['host']; + $resp = wp_remote_get('https://api.mcsrvstat.us/2/'.rawurlencode($api_host), ['timeout'=>7]); if (!is_wp_error($resp) && wp_remote_retrieve_response_code($resp)==200) { $body = json_decode(wp_remote_retrieve_body($resp), true); if (!empty($body['online'])) { $result['online'] = true; if (empty($raw_players) && !empty($body['players']['list']) && is_array($body['players']['list'])) { - $raw_players = []; foreach ($body['players']['list'] as $pl) { if (!is_array($pl)) continue; $name = $pl['name'] ?? ''; @@ -434,34 +617,41 @@ function mcss_fetch_server_with_ranks() { $candidate = $body['version'] ?? $body['software'] ?? ''; if ($candidate) $result['version'] = mcss_normalize_version($candidate); } - $result['ping'] = intval($body['debug']['ping'] ?? $body['ping'] ?? 0); - if ($show_motd && !empty($body['motd']['clean'])) { + if (!empty($srv['show_motd']) && !empty($body['motd']['clean'])) { $motd = is_array($body['motd']['clean']) ? implode(' ', $body['motd']['clean']) : $body['motd']['clean']; $result['motd'] = $motd; } } } - - $lp_groups = mcss_fetch_luckperms_groups(); - + + // PING-MESSUNG + $ping_port = !empty($srv['player_port']) ? $srv['player_port'] : $srv['query_port']; + $ping_result = mcss_ping_server($srv['host'], $ping_port, 2); + if ($ping_result !== false) { + $result['ping'] = $ping_result; + } else { + // Wenn Ping-Messung fehlschlägt, versuche den Ping aus der API zu verwenden + if (!empty($body['debug']['ping'])) { + $result['ping'] = intval($body['debug']['ping']); + } elseif (!empty($body['ping'])) { + $result['ping'] = intval($body['ping']); + } + } + + $lp_groups = mcss_fetch_luckperms_groups($srv); $players_info = []; foreach ($raw_players as $p) { $name = $p['name']; $uuid = $p['uuid'] ?? mcss_get_uuid_from_name($name); - $raw_entry = $p['raw_entry'] ?? $name; - // PREFIX extrahieren (z. B. "[Owner] M_Viper" → "[Owner]") $prefix = ''; if (preg_match('/^(\[[^\]]+\])/', $raw_entry, $m)) { $prefix = $m[1]; } - // Rang = Prefix oder "Spieler" $rank = $prefix ?: 'Spieler'; - $color = '#94a3b8'; // Default Spieler-Farbe - - // Farbe aus LuckPerms holen + $color = '#94a3b8'; foreach ($lp_groups as $g) { if ($g['prefix'] && stripos($prefix, $g['prefix']) !== false) { $color = $g['color']; @@ -470,123 +660,177 @@ function mcss_fetch_server_with_ranks() { } $players_info[] = [ - 'name' => $name, + 'name' => $name, 'avatar' => mcss_avatar($uuid ?: $name, 64), - 'rank' => $rank, - 'color' => $color, + 'rank' => $rank, + 'color' => $color, ]; } $result['players'] = $players_info; $result['version'] = preg_replace('/^\s*v/i', '', trim($result['version'])); - - set_transient($transient_key, $result, $ttl); - update_option($transient_key . '_time', time()); + set_transient($cache_key, $result, $srv['cache_ttl']); + update_option($cache_key.'_time', time()); return $result; } -/* ---------------- Player rank detection (vereinfacht) ---------------- */ -function mcss_get_player_rank($player, $ranks_map = []) { - return ['rank' => 'Spieler', 'color' => '#94a3b8']; -} - /* ---------------- Shortcode ---------------- */ add_shortcode('minecraft_status', 'mcss_server_card_shortcode'); add_shortcode('minecraft_server_detail', 'mcss_server_card_shortcode'); function mcss_server_card_shortcode($atts = []) { - $data = mcss_fetch_server_with_ranks(); + $atts = shortcode_atts(['id' => ''], $atts); + if (empty($atts['id'])) return 'Fehler: id fehlt'; - $logo_id = get_option('mcss_server_logo_id', 0); - $logo_url = get_option('mcss_server_logo_url', ''); - $logo = $logo_id ? wp_get_attachment_image_url($logo_id, 'full') : ($logo_url ?: ($atts['logo'] ?? MCSS_URL . 'img/default-server-logo.png')); - - $custom_text = wp_kses_post(get_option('mcss_custom_text', '')); - $ip_color = get_option('mcss_ip_color', '#1f2937'); - $ip_size = get_option('mcss_ip_size', '1.5em'); - $ct_color = get_option('mcss_ct_color', '#1e293b'); - $ct_size = get_option('mcss_ct_size', '1.05em'); - - $host = get_option('mcss_host', ''); - $player_port = trim(get_option('mcss_player_port', '')); - $hide_port = (bool)get_option('mcss_hide_port', true); - - $display_address = $host; - if (!$hide_port && $player_port !== '') { - $display_address .= ':' . $player_port; + $servers = get_option('mcss_servers', []); + $srv = null; + foreach ($servers as $s) { + if (($s['id'] ?? '') === $atts['id'] || ($s['name'] ?? '') === $atts['id']) { + $srv = $s; break; + } } + if (!$srv) return '

Server nicht gefunden

'; - $copy_address = $host . ($player_port !== '' ? ':' . $player_port : ''); - - $user_defined_ranks = json_decode(get_option('mcss_ranks_json','[]'), true); - $lp_present = is_array($user_defined_ranks) && count($user_defined_ranks) > 0; - $top_rank_name = $lp_present ? ($user_defined_ranks[0]['name'] ?? 'Spieler') : 'Spieler'; - - $uid = md5($host . '|' . $player_port); - - ob_start(); ?> -
-
Adresse kopiert!
- -
-
- Logo + // Prüfen, ob der Wartungsmodus aktiviert ist + $maintenance_mode = !empty($srv['maintenance_mode']); + $maintenance_message = $srv['maintenance_message'] ?? 'Der Server befindet sich derzeit im Wartungsmodus. Wir sind bald wieder für dich da!'; + + // Wenn Wartungsmodus aktiv ist, nur die Wartungsansicht anzeigen + if ($maintenance_mode) { + $uid = md5($srv['host'] . '|' . ($srv['player_port'] ?? '')); + $logo = $srv['logo_id'] ? wp_get_attachment_image_url($srv['logo_id'], 'full') : ($srv['logo_url'] ?: MCSS_URL.'img/default-server-logo.png'); + + ob_start(); ?> + + +
+
+ Logo
+

- - - - - + + Wartungsmodus
- - -
- - - - - -
- - -
- -
-
Version:
- - -
Rang:
- -
Spieler:
- - -
Ping: ms
-
- -
-
- Spieler online: -
-
- - -
- <?php echo esc_attr($p['name']); ?> -
-
-
- - -
Keine Spieler online
- +
+
Wartungshinweis:
+
+
+

Wir arbeiten daran, den Server so schnell wie möglich wieder verfügbar zu machen. Vielen Dank für deine Geduld!

-
+ + + +
+
Adresse kopiert!
+ +
+ Logo +
+ +

+
+ + + + + +
+ +
+ + +
+ +
+
+
+
Version:
+ +
Spieler:
+ +
Rang:
+ +
Ping: ms
+
+
+
Spieler online:
+
+ +
+ <?php echo esc_attr($p['name']); ?> +
+
+
+ +
Keine Spieler online
+ +
+
+