877 lines
46 KiB
PHP
877 lines
46 KiB
PHP
<?php
|
||
/*
|
||
* Plugin Name: Minecraft BungeeCord Status – Network Edition
|
||
* Description: Der ultimative Live-Status für dein BungeeCord Netzwerk (Border None Fix).
|
||
* Tags: minecraft, bungeecord, server status, player list
|
||
* Version: 3.6.1
|
||
* Author: M_Viper
|
||
* Requires at least: 6.0
|
||
* Requires PHP: 7.4
|
||
*/
|
||
|
||
if (!defined('ABSPATH')) exit;
|
||
|
||
define('MCSS_DIR', plugin_dir_path(__FILE__));
|
||
define('MCSS_URL', plugin_dir_url(__FILE__));
|
||
|
||
require_once MCSS_DIR . 'rcon/Rcon.php';
|
||
|
||
/* ---------------- HELPER: MINECRAFT COLORS ---------------- */
|
||
function mcss_format_minecraft_colors($text) {
|
||
if (empty($text)) return '';
|
||
|
||
// Minecraft Color Map
|
||
$color_map = [
|
||
'0' => '#000000', // Black
|
||
'1' => '#0000AA', // Dark Blue
|
||
'2' => '#00AA00', // Dark Green
|
||
'3' => '#00AAAA', // Dark Aqua
|
||
'4' => '#AA0000', // Dark Red
|
||
'5' => '#AA00AA', // Dark Purple
|
||
'6' => '#FFAA00', // Gold
|
||
'7' => '#AAAAAA', // Gray
|
||
'8' => '#555555', // Dark Gray
|
||
'9' => '#5555FF', // Blue
|
||
'a' => '#55FF55', // Green
|
||
'b' => '#55FFFF', // Aqua
|
||
'c' => '#FF5555', // Red
|
||
'd' => '#FF55FF', // Light Purple
|
||
'e' => '#FFFF55', // Yellow
|
||
'f' => '#FFFFFF' // White
|
||
];
|
||
|
||
// Base Wrapper
|
||
$formatted = '<span style="color:#AAAAAA;">'; // Standard Grau
|
||
|
||
// Ersetze Farben: &c -> </span><span style="color:#HEX">
|
||
foreach ($color_map as $char => $hex) {
|
||
$text = str_replace("&" . $char, "</span><span style=\"color:$hex;\">", $text);
|
||
}
|
||
|
||
// Formatierungen
|
||
$text = str_replace("&l", "</span><span style=\"font-weight:bold;\">", $text); // Bold
|
||
$text = str_replace("&o", "</span><span style=\"font-style:italic;\">", $text); // Italic
|
||
$text = str_replace("&n", "</span><span style=\"text-decoration:underline;\">", $text); // Underline
|
||
$text = str_replace("&m", "</span><span style=\"text-decoration:line-through;\">", $text); // Strikethrough
|
||
$text = str_replace("&r", "</span><span style=\"color:#AAAAAA;\">", $text); // Reset to Gray
|
||
|
||
$formatted .= $text . '</span>';
|
||
return $formatted;
|
||
}
|
||
|
||
/* ---------------- AUTO UPDATE (MCSS) ---------------- */
|
||
if ( ! class_exists( 'MCSS_Auto_Update' ) ) {
|
||
class MCSS_Auto_Update {
|
||
|
||
private $plugin_file;
|
||
private $repo_owner = 'M_Viper';
|
||
private $repo_name = 'Minecraft-BungeeCord-Status';
|
||
private $api_url;
|
||
private $transient_key;
|
||
|
||
public function __construct( $plugin_file ) {
|
||
$this->plugin_file = $plugin_file;
|
||
$this->api_url = 'https://git.viper.ipv64.net/api/v1/repos/' . rawurlencode( $this->repo_owner ) . '/' . rawurlencode( $this->repo_name ) . '/releases';
|
||
$this->transient_key = 'mcss_update_check_' . md5( $this->repo_owner . '/' . $this->repo_name );
|
||
|
||
if ( is_admin() ) {
|
||
add_action( 'admin_init', array( $this, 'check_for_update' ) );
|
||
}
|
||
}
|
||
|
||
public function check_for_update() {
|
||
if ( ! function_exists( 'get_file_data' ) ) {
|
||
require_once ABSPATH . 'wp-admin/includes/plugin.php';
|
||
}
|
||
|
||
$current = get_file_data( $this->plugin_file, array( 'Version' => 'Version' ), 'plugin' );
|
||
$current_version = isset( $current['Version'] ) ? $current['Version'] : '0.0.0';
|
||
|
||
$latest = $this->get_latest_release_info();
|
||
|
||
if ( $latest && ! empty( $latest['version'] ) && ! empty( $latest['url'] ) ) {
|
||
if ( version_compare( $latest['version'], $current_version, '>' ) ) {
|
||
add_action( 'admin_notices', function() use ( $latest, $current_version ) {
|
||
?>
|
||
<div class="notice notice-warning is-dismissible">
|
||
<p>
|
||
<strong>Minecraft BungeeCord Status – Update verfügbar</strong><br>
|
||
Neue Version: <strong><?php echo esc_html( $latest['version'] ); ?></strong><br>
|
||
Installiert: <strong><?php echo esc_html( $current_version ); ?></strong><br>
|
||
<a href="<?php echo esc_url( $latest['url'] ); ?>" class="button button-primary" target="_blank" rel="noreferrer noopener">Direkter Download (ZIP)</a>
|
||
<a href="<?php echo esc_url( 'https://git.viper.ipv64.net/' . rawurlencode( $this->repo_owner ) . '/' . rawurlencode( $this->repo_name ) . '/releases' ); ?>" class="button" target="_blank" style="margin-left:8px;" rel="noreferrer noopener">Releases ansehen</a>
|
||
</p>
|
||
</div>
|
||
<?php
|
||
} );
|
||
}
|
||
}
|
||
}
|
||
|
||
private function get_latest_release_info() {
|
||
$cached = get_transient( $this->transient_key );
|
||
if ( false !== $cached && is_array( $cached ) && ! empty( $cached['version'] ) ) {
|
||
return $cached;
|
||
}
|
||
|
||
$result = false;
|
||
|
||
$response = wp_remote_get( $this->api_url, array(
|
||
'timeout' => 8,
|
||
'headers' => array(
|
||
'Accept' => 'application/json',
|
||
'User-Agent' => 'MCSS-Update-Checker/1.0',
|
||
),
|
||
) );
|
||
|
||
if ( is_wp_error( $response ) ) {
|
||
set_transient( $this->transient_key, array( 'version' => '', 'url' => '' ), HOUR_IN_SECONDS );
|
||
return false;
|
||
}
|
||
|
||
$code = wp_remote_retrieve_response_code( $response );
|
||
if ( 200 !== (int) $code ) {
|
||
set_transient( $this->transient_key, array( 'version' => '', 'url' => '' ), HOUR_IN_SECONDS );
|
||
return false;
|
||
}
|
||
|
||
$body = wp_remote_retrieve_body( $response );
|
||
$json = json_decode( $body, true );
|
||
|
||
if ( ! is_array( $json ) || empty( $json ) ) {
|
||
set_transient( $this->transient_key, array( 'version' => '', 'url' => '' ), HOUR_IN_SECONDS );
|
||
return false;
|
||
}
|
||
|
||
foreach ( $json as $release ) {
|
||
$tag = '';
|
||
if ( ! empty( $release['tag_name'] ) ) {
|
||
$tag = ltrim( (string) $release['tag_name'], 'vV' );
|
||
} elseif ( ! empty( $release['name'] ) ) {
|
||
$tag = ltrim( (string) $release['name'], 'vV' );
|
||
}
|
||
|
||
if ( ! empty( $release['assets'] ) && is_array( $release['assets'] ) ) {
|
||
foreach ( $release['assets'] as $asset ) {
|
||
if ( empty( $asset['name'] ) || empty( $asset['browser_download_url'] ) ) {
|
||
continue;
|
||
}
|
||
|
||
if ( strtolower( $asset['name'] ) === 'minecraft-bungeecord-status.zip' ) {
|
||
$version = $tag ?: $this->extract_version_from_string( $asset['name'] . ' ' . ( $release['name'] ?? '' ) );
|
||
if ( $version ) {
|
||
$result = array(
|
||
'version' => $version,
|
||
'url' => $asset['browser_download_url'],
|
||
);
|
||
break 2;
|
||
} else {
|
||
$result = array(
|
||
'version' => ( $tag ?: (string) ( $release['name'] ?? '' ) ),
|
||
'url' => $asset['browser_download_url'],
|
||
);
|
||
break 2;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if ( $result ) {
|
||
set_transient( $this->transient_key, $result, 12 * HOUR_IN_SECONDS );
|
||
return $result;
|
||
}
|
||
|
||
set_transient( $this->transient_key, array( 'version' => '', 'url' => '' ), 6 * HOUR_IN_SECONDS );
|
||
return false;
|
||
}
|
||
|
||
private function extract_version_from_string( $str ) {
|
||
if ( preg_match( '/([0-9]+\.[0-9]+(?:\.[0-9]+)?)/', $str, $m ) ) {
|
||
return $m[1];
|
||
}
|
||
return '';
|
||
}
|
||
}
|
||
|
||
new MCSS_Auto_Update( __FILE__ );
|
||
}
|
||
|
||
/* ---------------- Assets ---------------- */
|
||
add_action('admin_enqueue_scripts', function($hook){
|
||
global $pagenow;
|
||
if ($pagenow === 'admin.php' && isset($_GET['page']) && $_GET['page'] === 'mcss-settings') {
|
||
wp_enqueue_media();
|
||
wp_enqueue_style('wp-color-picker');
|
||
wp_enqueue_script('wp-color-picker');
|
||
wp_enqueue_script('jquery-ui-datepicker');
|
||
wp_enqueue_style('jquery-ui-css', 'https://code.jquery.com/ui/1.13.2/themes/base/jquery-ui.min.css');
|
||
wp_enqueue_script('mcss-admin-js', MCSS_URL . 'js/admin.js', ['jquery', 'wp-color-picker', 'jquery-ui-datepicker'], '1.0.0', true);
|
||
}
|
||
});
|
||
|
||
add_action('wp_enqueue_scripts', function(){
|
||
wp_enqueue_style('mcss-style', MCSS_URL . 'css/style.css', [], '3.8.1');
|
||
wp_enqueue_script('mcss-frontend-js', MCSS_URL . 'js/mcss-frontend.js', ['jquery'], '3.8.1', true);
|
||
});
|
||
|
||
/* ---------------- Settings ---------------- */
|
||
add_action('admin_menu', function(){
|
||
add_menu_page(
|
||
'BungeeCord Einstellungen',
|
||
'BungeeCord Status',
|
||
'manage_options',
|
||
'mcss-settings',
|
||
'mcss_settings_page',
|
||
'dashicons-networking',
|
||
100
|
||
);
|
||
});
|
||
|
||
add_action('admin_init', function(){
|
||
register_setting('mcss_settings_group', 'mcss_servers', ['sanitize_callback'=>'mcss_sanitize_servers']);
|
||
});
|
||
|
||
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'] ?? 'BungeeCord'),
|
||
'host' => sanitize_text_field($srv['host'] ?? ''),
|
||
'rcon_port' => absint($srv['rcon_port'] ?? 25577),
|
||
'rcon_pass' => sanitize_text_field($srv['rcon_pass'] ?? ''),
|
||
'player_port' => sanitize_text_field($srv['player_port'] ?? '9191'),
|
||
'player_port_copy' => sanitize_text_field($srv['player_port_copy'] ?? ''),
|
||
'copy_address' => sanitize_text_field($srv['copy_address'] ?? ''),
|
||
'hide_port' => !empty($srv['hide_port']),
|
||
'show_motd' => !empty($srv['show_motd']),
|
||
'cache_ttl' => max(2, absint($srv['cache_ttl'] ?? 10)),
|
||
'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'] ?? '#333333'),
|
||
'name_size' => sanitize_text_field($srv['name_size'] ?? '1.8em'),
|
||
'maintenance_mode' => !empty($srv['maintenance_mode']),
|
||
'maintenance_message' => wp_kses_post($srv['maintenance_message'] ?? 'Wartung'),
|
||
'announcement_enabled' => !empty($srv['announcement_enabled']),
|
||
'announcement_text' => wp_kses_post($srv['announcement_text'] ?? ''),
|
||
'announcement_start' => sanitize_text_field($srv['announcement_start'] ?? ''),
|
||
'announcement_end' => sanitize_text_field($srv['announcement_end'] ?? ''),
|
||
'announcement_type' => sanitize_text_field($srv['announcement_type'] ?? 'info'),
|
||
'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 '[]';
|
||
$out = [];
|
||
foreach ($decoded as $r) {
|
||
if (!is_array($r) || empty($r['name'])) continue;
|
||
$out[] = ['name'=>sanitize_text_field($r['name']), 'color'=>sanitize_text_field($r['color']??'#6c5ce7')];
|
||
}
|
||
return wp_json_encode($out);
|
||
}
|
||
|
||
/* ---------------- Helper Functions ---------------- */
|
||
function mcss_should_show_announcement($srv) {
|
||
if (empty($srv['announcement_enabled'])) return false;
|
||
if (empty($srv['announcement_text'])) return false;
|
||
if (empty($srv['announcement_start'])) return true;
|
||
|
||
$current_time = current_time('timestamp');
|
||
$start_time = strtotime($srv['announcement_start']);
|
||
if ($start_time > $current_time) return false;
|
||
|
||
if (empty($srv['announcement_end'])) return true;
|
||
|
||
$end_time = strtotime($srv['announcement_end']);
|
||
return $end_time >= $current_time;
|
||
}
|
||
|
||
function mcss_get_announcement_style($type) {
|
||
switch ($type) {
|
||
case 'warning': return ['bg' => '#fef3c7','border' => '#fbbf24','text' => '#92400e','icon' => '⚠️'];
|
||
case 'success': return ['bg' => '#d1fae5','border' => '#10b981','text' => '#065f46','icon' => '✅'];
|
||
case 'error': return ['bg' => '#fee2e2','border' => '#ef4444','text' => '#991b1b','icon' => '❌'];
|
||
case 'info': default: return ['bg' => '#dbeafe','border' => '#3b82f6','text' => '#1e40af','icon' => 'ℹ️'];
|
||
}
|
||
}
|
||
|
||
/* ---------------- Backend Page ---------------- */
|
||
function mcss_settings_page() {
|
||
$servers = get_option('mcss_servers', []);
|
||
if (empty($servers)) {
|
||
$servers = [['id'=>'default', 'name'=>'Mein Netzwerk', 'host'=>'127.0.0.1', 'player_port'=>'9191', 'cache_ttl'=>10, '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ß','1.7em'=>'Extra groß','2em'=>'Riesig',
|
||
'2.5em'=>'Enorm','3em'=>'Gigantisch',
|
||
];
|
||
|
||
$announcement_types = ['info'=>'Info (Blau)','warning'=>'Warnung (Orange)','success'=>'Erfolg (Grün)','error'=>'Fehler (Rot)'];
|
||
|
||
?>
|
||
<div class="wrap">
|
||
<h1>BungeeCord Netzwerk Einstellungen</h1>
|
||
<p style="color:#d97706;background:#fef3c7;padding:10px;border-radius:5px;">
|
||
<strong>Wichtig:</strong> Bitte das Plugin StatusAPI.jar im Bungeecord Installieren.
|
||
</p>
|
||
<form method="post" action="options.php">
|
||
<?php settings_fields('mcss_settings_group'); ?>
|
||
<div id="mcss-servers-repeater">
|
||
<?php foreach ($servers as $i => $srv): mcss_render_row($srv, $i, $font_sizes, $announcement_types); endforeach; ?>
|
||
</div>
|
||
<p><button type="button" class="button button-primary" id="mcss-add-server">+ Netzwerk hinzufügen</button></p>
|
||
<?php submit_button(); ?>
|
||
</form>
|
||
</div>
|
||
|
||
<script>
|
||
jQuery(function($){
|
||
let counter = <?php echo count($servers); ?>;
|
||
|
||
$('#mcss-add-server').on('click', function(e){
|
||
e.preventDefault();
|
||
const newId = 'new_' + counter;
|
||
const newIndex = counter;
|
||
|
||
const newServerHtml = `
|
||
<div class="mcss-server-row" style="border:1px solid #ddd;padding:20px;margin:20px 0;background:#f9f9f9;position:relative;">
|
||
<button type="button" class="notice-dismiss mcss-remove-server" style="position:absolute;top:10px;right:10px;"></button>
|
||
<h3>Netzwerk ${counter+1}: Neues Netzwerk</h3>
|
||
<table class="form-table">
|
||
<tr><th>Name</th><td><input name="mcss_servers[${counter}][name]" value="BungeeCord" class="regular-text"></td></tr>
|
||
<tr>
|
||
<th>Name – Schrift</th>
|
||
<td>
|
||
<label>Farbe:</label>
|
||
<input name="mcss_servers[${counter}][name_color]" type="color" value="#333333" style="width:50px;" />
|
||
<label style="margin-left:10px;">Größe:</label>
|
||
<select name="mcss_servers[${counter}][name_size]" style="width:200px;">
|
||
<?php foreach ($font_sizes as $value => $label): ?>
|
||
<option value="<?php echo esc_attr($value); ?>"><?php echo esc_html($label); ?></option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
</td>
|
||
</tr>
|
||
<tr><th>Host (IP)</th><td><input name="mcss_servers[${counter}][host]" value="127.0.0.1" class="regular-text"></td></tr>
|
||
<tr><th>API Port (StatusAPI)</th><td><input name="mcss_servers[${counter}][player_port]" value="9191" class="regular-text"></td></tr>
|
||
<tr><th>Spielerport (für IP-Anzeige)</th><td><input name="mcss_servers[${counter}][player_port_copy]" value="" class="regular-text" placeholder="z.B. 25577" /></td></tr>
|
||
<tr><th>Cache TTL</th><td><input name="mcss_servers[${counter}][cache_ttl]" value="10" class="small-text"></td></tr>
|
||
<tr><th>Kopier-Adresse</th><td><input name="mcss_servers[${counter}][copy_address]" value="" class="regular-text"></td></tr>
|
||
<tr><th>Logo URL</th><td><input name="mcss_servers[${counter}][logo_url]" value="" class="regular-text"></td></tr>
|
||
<tr><th>Zusatztext</th><td><input name="mcss_servers[${counter}][custom_text]" value="" class="large-text"></td></tr>
|
||
<tr>
|
||
<th>Zusatztext – Schrift</th>
|
||
<td>
|
||
<label>Farbe:</label>
|
||
<input name="mcss_servers[${counter}][ct_color]" type="color" value="#555555" style="width:50px;" />
|
||
<label style="margin-left:10px;">Größe:</label>
|
||
<select name="mcss_servers[${counter}][ct_size]" style="width:200px;">
|
||
<?php foreach ($font_sizes as $value => $label): ?>
|
||
<option value="<?php echo esc_attr($value); ?>"><?php echo esc_html($label); ?></option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
</td>
|
||
</tr>
|
||
<tr><th><strong>Wartungsmodus</strong></th><td><input name="mcss_servers[${counter}][maintenance_mode]" type="checkbox" value="1" /></td></tr>
|
||
<tr><th>Wartungsnachricht</th><td><textarea name="mcss_servers[${counter}][maintenance_message]" class="large-text" rows="4">Wartung</textarea></td></tr>
|
||
<tr><th><strong>Ankündigungen</strong></th><td><input name="mcss_servers[${counter}][announcement_enabled]" type="checkbox" value="1" /></td></tr>
|
||
<tr><th>Ankündigungstext</th><td><textarea name="mcss_servers[${counter}][announcement_text]" class="large-text" rows="3"></textarea></td></tr>
|
||
<tr>
|
||
<th>Ankündigungszeitraum</th>
|
||
<td>
|
||
<div style="display:flex;gap:10px;align-items:center;">
|
||
<div style="flex:1;"><label for="mcss_start_${newIndex}">Start:</label><input name="mcss_servers[${counter}][announcement_start]" id="mcss_start_${newIndex}" type="text" class="regular-text mcss-datepicker" placeholder="TT.MM.JJJJ HH:MM" /></div>
|
||
<div style="flex:1;"><label for="mcss_end_${newIndex}">Ende:</label><input name="mcss_servers[${counter}][announcement_end]" id="mcss_end_${newIndex}" type="text" class="regular-text mcss-datepicker" placeholder="TT.MM.JJJJ HH:MM" /></div>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
<tr><th>Ankündigungstyp</th>
|
||
<td>
|
||
<select name="mcss_servers[${counter}][announcement_type]" style="width:200px;">
|
||
<?php foreach ($announcement_types as $value => $label): ?>
|
||
<option value="<?php echo esc_attr($value); ?>"><?php echo esc_html($label); ?></option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
<input type="hidden" name="mcss_servers[${counter}][id]" value="${newId}">
|
||
</div>
|
||
`;
|
||
$('#mcss-servers-repeater').append(newServerHtml);
|
||
|
||
$('.mcss-server-row:last .mcss-datepicker').datepicker({ dateFormat: 'dd.mm.yy', timeFormat: 'HH:mm' });
|
||
$('.mcss-server-row:last input[type="color"]').wpColorPicker();
|
||
counter++;
|
||
});
|
||
$(document).on('click', '.mcss-remove-server', function(){ $(this).closest('.mcss-server-row').remove(); });
|
||
|
||
$('.mcss-datepicker').datepicker({ dateFormat: 'dd.mm.yy', timeFormat: 'HH:mm' });
|
||
$('input[type="color"]').wpColorPicker();
|
||
});
|
||
</script>
|
||
<?php
|
||
}
|
||
|
||
function mcss_render_row($srv, $i, $font_sizes, $announcement_types) {
|
||
?>
|
||
<div class="mcss-server-row" style="border:1px solid #ddd;padding:20px;margin:20px 0;background:#f9f9f9;position:relative;">
|
||
<button type="button" class="notice-dismiss mcss-remove-server" style="position:absolute;top:10px;right:10px;"></button>
|
||
<h3>Netzwerk <?php echo $i+1; ?></h3>
|
||
<table class="form-table">
|
||
<tr><th>Name</th><td><input name="mcss_servers[<?php echo $i; ?>][name]" value="<?php echo esc_attr($srv['name'] ?? ''); ?>" class="regular-text"></td></tr>
|
||
<tr>
|
||
<th>Name – Schrift</th>
|
||
<td>
|
||
<label>Farbe:</label>
|
||
<input name="mcss_servers[<?php echo $i; ?>][name_color]" type="color" value="<?php echo esc_attr($srv['name_color'] ?? '#333333'); ?>" style="width:50px;" />
|
||
<label style="margin-left:10px;">Größe:</label>
|
||
<select name="mcss_servers[<?php echo $i; ?>][name_size]" style="width:200px;">
|
||
<?php foreach ($font_sizes as $value => $label): ?>
|
||
<option value="<?php echo esc_attr($value); ?>" <?php selected($srv['name_size'] ?? '1.8em', $value); ?>><?php echo esc_html($label); ?></option>
|
||
<?php endforeach; ?>
|
||
<option value="<?php echo esc_attr($srv['name_size'] ?? ''); ?>" <?php echo !isset($font_sizes[$srv['name_size'] ?? '']) ? 'selected' : ''; ?>>Benutzerdefiniert (<?php echo esc_html($srv['name_size'] ?? ''); ?>)</option>
|
||
</select>
|
||
</td>
|
||
</tr>
|
||
<tr><th>Host (IP)</th><td><input name="mcss_servers[<?php echo $i; ?>][host]" value="<?php echo esc_attr($srv['host'] ?? '127.0.0.1'); ?>" class="regular-text"></td></tr>
|
||
<tr><th>API Port (StatusAPI)</th><td><input name="mcss_servers[<?php echo $i; ?>][player_port]" value="<?php echo esc_attr($srv['player_port'] ?? '9191'); ?>" class="regular-text"></td></tr>
|
||
<tr><th>Spielerport (für IP-Anzeige)</th><td><input name="mcss_servers[<?php echo $i; ?>][player_port_copy]" value="<?php echo esc_attr($srv['player_port_copy'] ?? ''); ?>" class="regular-text" placeholder="z.B. 25577" /></td></tr>
|
||
<tr><th>Cache TTL</th><td><input name="mcss_servers[<?php echo $i; ?>][cache_ttl]" value="<?php echo esc_attr($srv['cache_ttl'] ?? '10'); ?>" class="small-text"></td></tr>
|
||
<tr><th>Kopier-Adresse</th><td><input name="mcss_servers[<?php echo $i; ?>][copy_address]" value="<?php echo esc_attr($srv['copy_address'] ?? ''); ?>" class="regular-text"></td></tr>
|
||
<tr><th>Logo URL</th><td><input name="mcss_servers[<?php echo $i; ?>][logo_url]" value="<?php echo esc_attr($srv['logo_url'] ?? ''); ?>" class="regular-text"></td></tr>
|
||
<tr><th>Zusatztext</th><td><input name="mcss_servers[<?php echo $i; ?>][custom_text]" value="<?php echo esc_attr($srv['custom_text'] ?? ''); ?>" class="large-text"></td></tr>
|
||
<tr>
|
||
<th>Zusatztext – Schrift</th>
|
||
<td>
|
||
<label>Farbe:</label>
|
||
<input name="mcss_servers[<?php echo $i; ?>][ct_color]" type="color" value="<?php echo esc_attr($srv['ct_color'] ?? '#555555'); ?>" style="width:50px;" />
|
||
<label style="margin-left:10px;">Größe:</label>
|
||
<select name="mcss_servers[<?php echo $i; ?>][ct_size]" style="width:200px;">
|
||
<?php foreach ($font_sizes as $value => $label): ?>
|
||
<option value="<?php echo esc_attr($value); ?>" <?php selected($srv['ct_size'] ?? '1.05em', $value); ?>><?php echo esc_html($label); ?></option>
|
||
<?php endforeach; ?>
|
||
<option value="<?php echo esc_attr($srv['ct_size'] ?? ''); ?>" <?php echo !isset($font_sizes[$srv['ct_size'] ?? '']) ? 'selected' : ''; ?>>Benutzerdefiniert (<?php echo esc_html($srv['ct_size'] ?? ''); ?>)</option>
|
||
</select>
|
||
</td>
|
||
</tr>
|
||
<tr><th><strong>Wartungsmodus</strong></th><td><input name="mcss_servers[<?php echo $i; ?>][maintenance_mode]" type="checkbox" value="1" <?php checked(!empty($srv['maintenance_mode'])); ?> /></td></tr>
|
||
<tr><th>Wartungsnachricht</th><td><textarea name="mcss_servers[<?php echo $i; ?>][maintenance_message]" class="large-text" rows="4"><?php echo esc_textarea($srv['maintenance_message'] ?? 'Wartung'); ?></textarea></td></tr>
|
||
<tr><th><strong>Ankündigungen</strong></th><td><input name="mcss_servers[<?php echo $i; ?>][announcement_enabled]" type="checkbox" value="1" <?php checked(!empty($srv['announcement_enabled'])); ?> /></td></tr>
|
||
<tr><th>Ankündigungstext</th><td><textarea name="mcss_servers[<?php echo $i; ?>][announcement_text]" class="large-text" rows="3"><?php echo esc_textarea($srv['announcement_text'] ?? ''); ?></textarea></td></tr>
|
||
<tr>
|
||
<th>Ankündigungszeitraum</th>
|
||
<td>
|
||
<div style="display:flex;gap:10px;align-items:center;">
|
||
<div style="flex:1;"><label for="mcss_start_<?php echo $i; ?>">Start:</label><input name="mcss_servers[<?php echo $i; ?>][announcement_start]" id="mcss_start_<?php echo $i; ?>" type="text" class="regular-text mcss-datepicker" value="<?php echo esc_attr($srv['announcement_start'] ?? ''); ?>" placeholder="TT.MM.JJJJ HH:MM" /></div>
|
||
<div style="flex:1;"><label for="mcss_end_<?php echo $i; ?>">Ende:</label><input name="mcss_servers[<?php echo $i; ?>][announcement_end]" id="mcss_end_<?php echo $i; ?>" type="text" class="regular-text mcss-datepicker" value="<?php echo esc_attr($srv['announcement_end'] ?? ''); ?>" placeholder="TT.MM.JJJJ HH:MM" /></div>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<th>Ankündigungstyp</th>
|
||
<td>
|
||
<select name="mcss_servers[<?php echo $i; ?>][announcement_type]" style="width:200px;">
|
||
<?php foreach ($announcement_types as $value => $label): ?>
|
||
<option value="<?php echo esc_attr($value); ?>" <?php selected($srv['announcement_type'] ?? 'info', $value); ?>><?php echo esc_html($label); ?></option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
<input type="hidden" name="mcss_servers[<?php echo $i; ?>][id]" value="<?php echo esc_attr($srv['id'] ?? ''); ?>">
|
||
</div>
|
||
<?php
|
||
}
|
||
|
||
/* ---------------- LOGIC: STATUS API FETCHER ---------------- */
|
||
function mcss_fetch_data_via_api($host, $port, $timeout = 2) {
|
||
$socket = @fsockopen($host, $port, $errno, $errstr, $timeout);
|
||
if (!$socket) return false;
|
||
|
||
$out = "GET / HTTP/1.1\r\n";
|
||
$out .= "Host: " . $host . "\r\n";
|
||
$out .= "Connection: Close\r\n\r\n";
|
||
fwrite($socket, $out);
|
||
|
||
$response = '';
|
||
while (!feof($socket)) {
|
||
$response .= fgets($socket, 128);
|
||
}
|
||
fclose($socket);
|
||
|
||
$parts = explode("\r\n\r\n", $response);
|
||
$body = end($parts);
|
||
$data = json_decode($body, true);
|
||
return $data;
|
||
}
|
||
|
||
function mcss_parse_bungeecord_version($raw_version) {
|
||
if (preg_match('/(\d+\.\d+)/', $raw_version, $matches)) {
|
||
return "1.8 - " . $matches[1];
|
||
}
|
||
return "Unbekannt";
|
||
}
|
||
|
||
function mcss_fetch_server_with_ranks($srv) {
|
||
$cache_key = 'mcss_data_' . md5($srv['host']);
|
||
$cached = get_transient($cache_key);
|
||
if ($cached !== false) return $cached;
|
||
|
||
$host = $srv['host'];
|
||
$port = $srv['player_port'] ?? 9191;
|
||
|
||
$api_data = mcss_fetch_data_via_api($host, $port, 1);
|
||
|
||
if (!$api_data || !isset($api_data['online'])) {
|
||
return ['online'=>false,'players'=>[],'version'=>'Offline','ping'=>9999,'motd'=>'Verbindung fehlgeschlagen'];
|
||
}
|
||
|
||
$players_info = [];
|
||
|
||
foreach ($api_data['players'] as $player_data) {
|
||
if (is_array($player_data)) {
|
||
$name = $player_data['name'];
|
||
$prefix = $player_data['prefix'] ?? '';
|
||
} else {
|
||
// Fallback für alte API
|
||
$name = $player_data;
|
||
$prefix = '';
|
||
}
|
||
|
||
// 1. Prefix mit Farben konvertieren
|
||
$prefix_html = mcss_format_minecraft_colors($prefix);
|
||
|
||
// 2. Namen immer Schwarz darstellen (überschreibt eventuelle Farben aus dem Prefix)
|
||
$name_html = '<span style="color:black;">' . esc_html($name) . '</span>';
|
||
|
||
// 3. Zusammenbauen (Nur Abstand, wenn Prefix existiert)
|
||
if (!empty($prefix_html)) {
|
||
$display_html = $prefix_html . ' ' . $name_html;
|
||
} else {
|
||
$display_html = $name_html;
|
||
}
|
||
|
||
$players_info[] = [
|
||
'name' => $name,
|
||
'avatar' => "https://mc-heads.net/avatar/" . rawurlencode($name) . "/64",
|
||
'prefix' => $prefix,
|
||
'display_html' => $display_html,
|
||
'rank' => $prefix ?: 'Spieler',
|
||
'color' => '#566d8dff',
|
||
];
|
||
}
|
||
|
||
$clean_version = mcss_parse_bungeecord_version($api_data['version'] ?? 'BungeeCord');
|
||
|
||
$result = [
|
||
'online' => true,
|
||
'players' => $players_info,
|
||
'version' => $clean_version,
|
||
'ping' => 1,
|
||
'motd' => is_array($api_data['motd']) ? implode(' ', $api_data['motd']) : $api_data['motd']
|
||
];
|
||
|
||
$fast_cache_ttl = max(2, absint($srv['cache_ttl'] ?? 10));
|
||
set_transient($cache_key, $result, $fast_cache_ttl);
|
||
return $result;
|
||
}
|
||
|
||
/* ---------------- AJAX ---------------- */
|
||
add_action('wp_ajax_mcss_fetch', 'mcss_ajax_fetch');
|
||
add_action('wp_ajax_nopriv_mcss_fetch', 'mcss_ajax_fetch');
|
||
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));
|
||
if (($srv['name'] ?? '') === $id) wp_send_json(mcss_fetch_server_with_ranks($srv));
|
||
}
|
||
wp_send_json(['online'=>false]);
|
||
}
|
||
|
||
/* ---------------- FRONTEND (SHORTCODE) ---------------- */
|
||
add_shortcode('bungeecord_status', 'mcss_shortcode');
|
||
function mcss_shortcode($atts) {
|
||
$atts = shortcode_atts(['id' => ''], $atts);
|
||
if (empty($atts['id'])) return 'Fehler';
|
||
|
||
$servers = get_option('mcss_servers', []);
|
||
$srv = null;
|
||
foreach ($servers as $s) {
|
||
if (($s['id'] ?? '') === $atts['id']) { $srv = $s; break; }
|
||
if (($s['name'] ?? '') === $atts['id']) { $srv = $s; break; }
|
||
}
|
||
if (!$srv) return 'Server nicht gefunden';
|
||
|
||
// MAINTENANCE MODE
|
||
$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!';
|
||
if ($maintenance_mode) {
|
||
$uid = md5($srv['host']);
|
||
$logo = $srv['logo_id'] ? wp_get_attachment_image_url($srv['logo_id'], 'full') : ($srv['logo_url'] ?: MCSS_URL.'img/default-server-logo.png');
|
||
$name_color = $srv['name_color'] ?? '#333333';
|
||
$name_size = $srv['name_size'] ?? '1.8em';
|
||
|
||
ob_start(); ?>
|
||
<style>
|
||
@keyframes pulse {
|
||
0% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(251, 146, 60, 0.7); }
|
||
70% { transform: scale(1); box-shadow: 0 0 0 10px rgba(251, 146, 60, 0); }
|
||
100% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(251, 146, 60, 0); }
|
||
}
|
||
.mcss-status-maintenance { animation: pulse 2s infinite; }
|
||
</style>
|
||
<div id="mcss-widget-<?php echo esc_attr($uid); ?>" style="max-width:650px;margin:30px auto;padding:0; background:#fef3c7;border:none;border-radius:20px; overflow:hidden;box-shadow:0 16px 40px rgba(0,0,0,0.12); font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;">
|
||
|
||
<div style="padding:28px 32px;background:#fef3c7;border-bottom:1px solid #fbbf24;display:flex;align-items:center;gap:20px;">
|
||
<img src="<?php echo esc_url($logo); ?>" alt="Logo" loading="lazy" style="width:60px;height:60px;border-radius:12px;box-shadow:0 8px 20px rgba(0,0,0,0.15);" onerror="this.src='<?php echo MCSS_URL.'img/default-server-logo.png'; ?>'" />
|
||
<div style="flex:1;">
|
||
<h2 style="margin:0 0 8px 0;font-size:<?php echo $name_size; ?>;color:<?php echo $name_color; ?>;font-weight:800;"><?php echo esc_html($srv['name']); ?></h2>
|
||
<div style="display:flex;align-items:center;gap:12px;margin-bottom:8px;">
|
||
<span class="mcss-status-maintenance" style="width:14px;height:14px;border-radius:50%;background:#fb923c;box-shadow:0 0 16px rgba(251, 146, 60, 0.5);"></span>
|
||
<span style="font-weight:600;color:#92400e;font-size:1em;">Wartungsmodus</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div style="padding:24px 32px;background:#fef3c7;">
|
||
<div style="margin-bottom:16px;font-weight:700;color:#92400e;font-size:1.05em;">Wartungshinweis:</div>
|
||
<div style="font-size:1.1em;color:#78350f;line-height:1.6;"><?php echo wp_kses_post($maintenance_message); ?></div>
|
||
<div style="margin-top:20px;font-size:0.9em;color:#92400e;">
|
||
<p>Wir arbeiten daran, den Server so schnell wie möglich wieder verfügbar zu machen. Vielen Dank für deine Geduld!</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<?php return ob_get_clean();
|
||
}
|
||
|
||
// NORMAL MODE
|
||
$data = mcss_fetch_server_with_ranks($srv);
|
||
$uid = md5($srv['host']);
|
||
|
||
$name_color = $srv['name_color'] ?? '#333333';
|
||
$name_size = $srv['name_size'] ?? '1.3em';
|
||
$ct_color = $srv['ct_color'] ?? '#555555';
|
||
$ct_size = $srv['ct_size'] ?? '0.9em';
|
||
$widget_width = "650px";
|
||
$widget_padding = "15px";
|
||
$logo_size = "70px";
|
||
$player_head_size = "32px";
|
||
|
||
$copy_addr = !empty($srv['copy_address']) ? $srv['copy_address'] : $srv['host'];
|
||
if (empty($srv['hide_port']) && !empty($srv['player_port_copy'])) {
|
||
$copy_addr .= ':' . $srv['player_port_copy'];
|
||
}
|
||
|
||
$show_announcement = mcss_should_show_announcement($srv);
|
||
$announcement_text = $srv['announcement_text'] ?? '';
|
||
$announcement_type = $srv['announcement_type'] ?? 'info';
|
||
$announcement_style = mcss_get_announcement_style($announcement_type);
|
||
|
||
ob_start(); ?>
|
||
<style>
|
||
@keyframes pulse { 0% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.7); } 70% { transform: scale(1); box-shadow: 0 0 0 10px rgba(16, 185, 129, 0); } 100% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(16, 185, 129, 0); } }
|
||
.mcss-status-online { animation: pulse 2s infinite; }
|
||
@keyframes slideDown { 0% { transform: translateY(-100%); opacity: 0; } 100% { transform: translateY(0); opacity: 1; } }
|
||
.mcss-announcement { animation: slideDown 0.5s ease-out; }
|
||
</style>
|
||
|
||
<div id="mcss-widget-<?php echo esc_attr($uid); ?>" style="max-width:<?php echo $widget_width; ?>;margin:20px auto;padding:<?php echo $widget_padding; ?>;background:white;border:none;border-radius:10px;box-shadow:0 4px 15px rgba(0,0,0,0.1);font-family:sans-serif;position:relative;">
|
||
|
||
<!-- POPUP / TOAST -->
|
||
<div id="mcss-toast-<?php echo esc_attr($uid); ?>" style="position:absolute;top:10px;right:10px;background:#4CAF50;color:white;padding:8px 16px;border-radius:4px;font-size:0.9em;box-shadow:0 2px 5px rgba(0,0,0,0.2);opacity:0;transition:opacity 0.5s ease;pointer-events:none;z-index:10;">IP kopiert!</div>
|
||
|
||
<!-- BANNER -->
|
||
<?php if ($show_announcement): ?>
|
||
<div class="mcss-announcement" style="padding:12px 20px;background:<?php echo esc_attr($announcement_style['bg']); ?>;border:1px solid <?php echo esc_attr($announcement_style['border']); ?>;border-radius:10px;margin:0 15px 15px 15px;display:flex;align-items:center;gap:12px;">
|
||
<span style="font-size:1.5em;"><?php echo esc_html($announcement_style['icon']); ?></span>
|
||
<div style="flex:1;font-size:1.0em;font-weight:600;color:<?php echo esc_attr($announcement_style['text']); ?>;"><?php echo wp_kses_post($announcement_text); ?></div>
|
||
<button type="button" class="mcss-announcement-close" style="background:none;border:none;color:<?php echo esc_attr($announcement_style['text']); ?>;cursor:pointer;font-size:1.2em;padding:0;line-height:1;" onclick="this.parentElement.style.display='none';">×</button>
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
<!-- HEADER -->
|
||
<div style="display:flex;align-items:center;gap:12px;border-bottom:1px solid #eee;padding-bottom:12px;">
|
||
<img src="<?php echo esc_url($srv['logo_url'] ?: MCSS_URL.'img/default-server-logo.png'); ?>" style="width:<?php echo $logo_size; ?>;height:<?php echo $logo_size; ?>;border-radius:6px;">
|
||
|
||
<div style="flex:1;display:flex;flex-direction:column;gap:6px;">
|
||
|
||
<!-- NAME -->
|
||
<h2 id="mcss-name-<?php echo esc_attr($uid); ?>"
|
||
style="margin:0;font-size:<?php echo $name_size; ?>;color:<?php echo $name_color; ?>;
|
||
cursor:pointer;user-select:none;font-weight:700;"
|
||
title="Klicken um IP zu kopieren">
|
||
<?php echo esc_html($srv['name']); ?>
|
||
</h2>
|
||
|
||
<!-- IP + STATUS -->
|
||
<div style="display:flex;align-items:center;gap:10px;font-size:0.9em;font-weight:600;">
|
||
<span style="color:#374151;" id="mcss-ip-<?php echo esc_attr($uid); ?>">
|
||
<?php echo esc_html($copy_addr); ?>
|
||
</span>
|
||
|
||
<span id="mcss-status-dot-<?php echo esc_attr($uid); ?>"
|
||
class="<?php echo $data['online'] ? 'mcss-status-online' : ''; ?>"
|
||
style="width:10px;height:10px;border-radius:50%;
|
||
background:<?php echo $data['online'] ? '#10b981' : '#ef4444'; ?>;
|
||
box-shadow:0 0 8px <?php echo $data['online'] ? 'rgba(16,185,129,.7)' : 'rgba(239,68,68,.7)'; ?>;">
|
||
</span>
|
||
|
||
<span id="mcss-status-text-<?php echo esc_attr($uid); ?>"
|
||
style="color:<?php echo $data['online'] ? '#10b981' : '#ef4444'; ?>;">
|
||
<?php echo $data['online'] ? 'Online' : 'Offline'; ?>
|
||
</span>
|
||
</div>
|
||
|
||
<!-- ZUSATZTEXT -->
|
||
<?php if (!empty($srv['custom_text'])): ?>
|
||
<div id="mcss-custom-text-<?php echo esc_attr($uid); ?>" style="font-size:<?php echo $ct_size; ?>;color:<?php echo $ct_color; ?>;font-weight:500;">
|
||
<?php echo wp_kses_post($srv['custom_text']); ?>
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<!-- INFO BAR -->
|
||
<div style="display:flex;justify-content:space-between;margin-top:12px;margin-bottom:30px;font-size:0.85em;color:#666;">
|
||
<span>Spieler: <strong id="mcss-player-count-<?php echo esc_attr($uid); ?>"><?php echo count($data['players']); ?></strong></span>
|
||
<span>Version: <strong id="mcss-version-<?php echo esc_attr($uid); ?>"><?php echo esc_html($data['version']); ?></strong></span>
|
||
<span>Ping: <strong id="mcss-ping-<?php echo esc_attr($uid); ?>"><?php echo esc_html($data['ping']); ?> ms</strong></span>
|
||
</div>
|
||
|
||
<!-- PLAYER GRID -->
|
||
<span style="color:#666;margin-bottom:15px;">Spieler:</span>
|
||
<div id="mcss-player-grid-<?php echo esc_attr($uid); ?>" style="display:flex;flex-wrap:wrap;gap:8px;margin-top:8px;color:#666;justify-content:center;">
|
||
|
||
<?php if (!empty($data['players']) && is_array($data['players'])): ?>
|
||
<?php foreach ($data['players'] as $p): ?>
|
||
<div style="text-align:center;">
|
||
<img src="<?php echo esc_url($p['avatar']); ?>" style="width:<?php echo $player_head_size; ?>;height:<?php echo $player_head_size; ?>;border-radius:4px;">
|
||
<div style="font-size:0.75em;"><?php echo $p['display_html']; ?></div>
|
||
</div>
|
||
<?php endforeach; ?>
|
||
<?php else: ?>
|
||
|
||
<div style="width:100%;text-align:center;font-size:0.9em;color:#999;margin-top:4px;">Keine Spieler Online</div>
|
||
<?php endif; ?>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<script>
|
||
(function(){
|
||
// COPY FUNCTION
|
||
function mcss_copy_<?php echo esc_attr($uid); ?>() {
|
||
const text = "<?php echo esc_js($copy_addr); ?>";
|
||
navigator.clipboard.writeText(text).then(function() {
|
||
const toast = document.getElementById('mcss-toast-<?php echo esc_attr($uid); ?>');
|
||
if(toast) {
|
||
toast.style.opacity = '1';
|
||
setTimeout(function() { toast.style.opacity = '0'; }, 3000);
|
||
}
|
||
}).catch(function(err){
|
||
console.error('mcss copy error:', err);
|
||
});
|
||
}
|
||
|
||
const nameEl = document.getElementById('mcss-name-<?php echo esc_attr($uid); ?>');
|
||
if(nameEl) nameEl.addEventListener('click', mcss_copy_<?php echo esc_attr($uid); ?>);
|
||
|
||
document.querySelectorAll('.mcss-announcement-close').forEach(function(btn){
|
||
btn.addEventListener('click', function(e){
|
||
e.preventDefault();
|
||
var banner = this.closest('.mcss-announcement');
|
||
if(banner) {
|
||
banner.style.transition = 'opacity 0.5s ease';
|
||
banner.style.opacity = '0';
|
||
setTimeout(function(){ banner.style.display = 'none'; }, 500);
|
||
}
|
||
});
|
||
});
|
||
|
||
// CACHE REFS
|
||
var statusTextEl = document.getElementById('mcss-status-text-<?php echo esc_js($uid); ?>');
|
||
var statusDotEl = document.getElementById('mcss-status-dot-<?php echo esc_js($uid); ?>');
|
||
var playerCountEl = document.getElementById('mcss-player-count-<?php echo esc_js($uid); ?>');
|
||
var versionEl = document.getElementById('mcss-version-<?php echo esc_js($uid); ?>');
|
||
var pingEl = document.getElementById('mcss-ping-<?php echo esc_js($uid); ?>');
|
||
var playerGridEl = document.getElementById('mcss-player-grid-<?php echo esc_js($uid); ?>');
|
||
|
||
// SAFELY update DOM from API response
|
||
function applyUpdate(d) {
|
||
if (!d) return;
|
||
|
||
// Status text + color
|
||
if (statusTextEl) {
|
||
statusTextEl.textContent = d.online ? 'Online' : 'Offline';
|
||
statusTextEl.style.color = d.online ? '#10b981' : '#ef4444';
|
||
}
|
||
|
||
// Status dot
|
||
if (statusDotEl) {
|
||
statusDotEl.style.background = d.online ? '#10b981' : '#ef4444';
|
||
statusDotEl.style.boxShadow = d.online ? '0 0 8px rgba(16,185,129,.7)' : '0 0 8px rgba(239,68,68,.7)';
|
||
statusDotEl.classList.toggle('mcss-status-online', !!d.online);
|
||
}
|
||
|
||
// Player count
|
||
if (playerCountEl) {
|
||
var count = (d.players && Array.isArray(d.players)) ? d.players.length : 0;
|
||
playerCountEl.textContent = count;
|
||
}
|
||
|
||
// Version + Ping
|
||
if (versionEl) versionEl.textContent = d.version ? d.version : '';
|
||
if (pingEl) pingEl.textContent = (typeof d.ping !== 'undefined') ? d.ping + ' ms' : '';
|
||
|
||
// Player grid
|
||
if (playerGridEl) {
|
||
var html = '';
|
||
if (d.players && Array.isArray(d.players) && d.players.length > 0) {
|
||
d.players.forEach(function(p){
|
||
var content = p.display_html ? p.display_html : p.name;
|
||
html += '<div style="text-align:center;">' +
|
||
'<img src="' + (p.avatar ? p.avatar : '') + '" style="width:<?php echo $player_head_size; ?>;height:<?php echo $player_head_size; ?>;border-radius:4px;">' +
|
||
'<div style="font-size:0.75em;">' + content + '</div>' +
|
||
'</div>';
|
||
});
|
||
} else {
|
||
html = '<div style="width:100%;text-align:center;font-size:0.9em;color:#999;margin-top:4px;">Keine Spieler Online</div>';
|
||
}
|
||
playerGridEl.innerHTML = html;
|
||
}
|
||
}
|
||
|
||
// POLL alle 2s
|
||
setInterval(function(){
|
||
fetch('<?php echo admin_url('admin-ajax.php'); ?>', {
|
||
method: 'POST',
|
||
headers: {'Content-Type':'application/x-www-form-urlencoded'},
|
||
body: 'action=mcss_fetch&server_id=<?php echo esc_js($srv['id']); ?>'
|
||
})
|
||
.then(r => r.json())
|
||
.then(d => { if(d) applyUpdate(d); })
|
||
.catch(err => console.error('mcss_fetch error:', err));
|
||
}, 2000);
|
||
})();
|
||
</script>
|
||
|
||
|
||
<?php return ob_get_clean();
|
||
}
|