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
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 :
+
+
+
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(); ?>
-