diff --git a/mc-player-history.php b/mc-player-history.php index 2d11557..8964237 100644 --- a/mc-player-history.php +++ b/mc-player-history.php @@ -2,8 +2,8 @@ /* Plugin Name: MC Player History Description: Spielerverlauf deines Minecraft Servers. -Version: 1.1.0 -Author: Dein Name +Version: 1.1.1 +Author: M_Viper */ if ( ! defined( 'ABSPATH' ) ) { @@ -119,10 +119,33 @@ function mcph_sync_from_statusapi() { foreach ( $players as $p ) { $name = isset( $p->name ) ? sanitize_text_field( $p->name ) : ''; $prefix = isset( $p->prefix ) ? sanitize_text_field( $p->prefix ) : ''; - $uuid = 'legacy-' . md5( strtolower( trim( $name ) ) ); + // UUID aus API übernehmen, falls vorhanden, sonst legacy-Hash + if ( isset( $p->uuid ) && !empty( $p->uuid ) ) { + $uuid = sanitize_text_field( $p->uuid ); + } else { + $uuid = 'legacy-' . md5( strtolower( trim( $name ) ) ); + } if ( empty( $name ) ) continue; + // Prüfe ob Spieler bereits existiert (nach UUID ODER Username) $exists = $wpdb->get_var( $wpdb->prepare( "SELECT id FROM $table_name WHERE uuid = %s", $uuid ) ); + + // Falls nicht per UUID gefunden, prüfe nach Username (für Migration alter Einträge) + if ( ! $exists ) { + $old_entry = $wpdb->get_row( $wpdb->prepare( "SELECT id, uuid FROM $table_name WHERE username = %s", $name ) ); + if ( $old_entry ) { + // Alter Eintrag gefunden - UUID aktualisieren statt neuen Eintrag + $wpdb->update( + $table_name, + array( 'uuid' => $uuid, 'prefix' => $prefix, 'last_seen' => current_time( 'mysql' ), 'is_online' => 1 ), + array( 'id' => $old_entry->id ), + array( '%s', '%s', '%s', '%d' ), + array( '%d' ) + ); + continue; + } + } + $now = current_time( 'mysql' ); if ( $exists ) { @@ -181,7 +204,12 @@ function mcph_generate_player_html( $limit = 500, $only_online = false, $is_ajax $has_live_data = true; foreach ( $api_response as $p ) { if ( isset( $p->name ) ) { - $uuid = 'legacy-' . md5( strtolower( trim( $p->name ) ) ); + // UUID aus API übernehmen, falls vorhanden, sonst legacy-Hash + if ( isset( $p->uuid ) && !empty( $p->uuid ) ) { + $uuid = sanitize_text_field( $p->uuid ); + } else { + $uuid = 'legacy-' . md5( strtolower( trim( $p->name ) ) ); + } $live_online_uuids[ $uuid ] = true; } } @@ -218,7 +246,18 @@ function mcph_generate_player_html( $limit = 500, $only_online = false, $is_ajax $username = esc_html( $row->username ); $prefix = mcph_parse_minecraft_colors( $row->prefix ); - $avatar = 'https://minotar.net/avatar/' . $username . '/80'; + + // Avatar-Logik: Moderne 3D-Köpfe (alle in gleiche Richtung) + $avatar = ''; + if ( strpos( $username, '.' ) !== false || ( isset($row->uuid) && strpos($row->uuid, 'xuid') === 0 ) ) { + // Bedrock: mc-heads.net mit 3D Head + $avatar = isset($row->uuid) && !empty($row->uuid) + ? 'https://mc-heads.net/head/' . esc_attr($row->uuid) . '/100' + : 'https://mc-heads.net/head/' . $username . '/100'; + } else { + // Java: mc-heads.net mit 3D Head (gleiche Richtung wie Bedrock) + $avatar = 'https://mc-heads.net/head/' . $username . '/100'; + } $anim_style = ''; if ( ! $is_ajax ) { @@ -235,7 +274,7 @@ function mcph_generate_player_html( $limit = 500, $only_online = false, $is_ajax // STRUKTUR: Bild -> Prefix -> Name -> Spacer -> Status echo '
'; - echo '' . $username . ''; + echo '' . $username . ''; echo '
'; @@ -275,6 +314,33 @@ function mcph_settings_init() { register_setting( 'mcph_plugin_options', 'mcph_statusapi_url' ); } function mcph_options_page() { + // Duplikate bereinigen + if ( isset( $_POST['mcph_cleanup_duplicates'] ) && check_admin_referer( 'mcph_cleanup_action' ) ) { + global $wpdb; + $table_name = $wpdb->prefix . 'mc_players'; + + // Finde Duplikate (gleicher Username, verschiedene UUIDs) + $duplicates = $wpdb->get_results( + "SELECT username, COUNT(*) as count, GROUP_CONCAT(id ORDER BY last_seen DESC) as ids + FROM $table_name + GROUP BY username + HAVING count > 1" + ); + + $cleaned = 0; + foreach ( $duplicates as $dup ) { + $ids = explode( ',', $dup->ids ); + // Behalte den neuesten (ersten), lösche die anderen + array_shift( $ids ); + foreach ( $ids as $id ) { + $wpdb->delete( $table_name, array( 'id' => $id ), array( '%d' ) ); + $cleaned++; + } + } + + echo '

' . $cleaned . ' Duplikate wurden entfernt.

'; + } + if ( isset( $_POST['mcph_manual_sync'] ) && check_admin_referer( 'mcph_manual_sync_action' ) ) { mcph_sync_from_statusapi(); delete_transient( 'mcph_api_cache_data' ); @@ -296,6 +362,14 @@ function mcph_options_page() { + +

Duplikate bereinigen

+
+ +

Entfernt doppelte Spieler-Einträge aus der Datenbank.

+ +
+

Manueller Sync

@@ -379,34 +453,41 @@ function mcph_shortcode( $atts ) { display: flex; flex-direction: column; align-items: center; - gap: 8px; /* Weniger Abstand dazwischen */ + gap: 8px; padding: 20px 10px; - background: #fff; - border: 1px solid #eee; - border-radius: 8px; - transition: all 0.3s ease; + background: linear-gradient(145deg, #ffffff 0%, #f8f9fa 100%); + border: 1px solid #e0e0e0; + border-radius: 12px; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); cursor: default; - position: relative; /* Fallback */ + position: relative; + box-shadow: 0 2px 8px rgba(0,0,0,0.08); } .mc-player-card:hover { - transform: translateY(-5px); - box-shadow: 0 10px 20px rgba(0,0,0,0.1); - border-color: #ddd; + transform: translateY(-8px) scale(1.02); + box-shadow: 0 12px 24px rgba(0,0,0,0.15); + border-color: #667eea; + background: linear-gradient(145deg, #ffffff 0%, #f0f2ff 100%); } .mc-avatar { - border-radius: 4px; - border: 3px solid #ddd; - background: #fff; - width: 60px; - height: 60px; - transition: border-color 0.3s; + border-radius: 8px; + border: 3px solid #e0e0e0; + background: transparent; + width: 80px; + height: 80px; + transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); flex-shrink: 0; + box-shadow: 0 4px 12px rgba(0,0,0,0.15); + object-fit: contain; + padding: 0; } .mc-player-card:hover .mc-avatar { - border-color: #bbb; + border-color: #667eea; + transform: scale(1.15) rotateY(10deg); + box-shadow: 0 8px 20px rgba(102, 126, 234, 0.4); } /* INFOS BEREICH */ @@ -415,10 +496,10 @@ function mcph_shortcode( $atts ) { flex-direction: column; align-items: center; width: 100%; - flex-grow: 1; /* Füllt den Rest der Karte */ - position: relative; /* Referenz für absoluten Status */ - padding-bottom: 35px; /* Platz für Status unten */ - justify-content: flex-start; /* Oben ausrichten */ + flex-grow: 1; + position: relative; + padding-bottom: 35px; + justify-content: flex-start; } /* 1. PREFIX */ @@ -429,22 +510,24 @@ function mcph_shortcode( $atts ) { text-align: center; margin-bottom: 4px; line-height: 1.2; + text-shadow: 0 1px 2px rgba(0,0,0,0.1); } /* 2. NAME */ .mc-name { font-weight: bold; font-size: 1.1em; - color: #333; + color: #2d3748; word-break: break-word; display: block; width: 100%; text-align: center; + text-shadow: 0 1px 2px rgba(0,0,0,0.05); } /* 3. SPACER */ .mc-spacer { - flex-grow: 1; /* Nimmt ALLEN leeren Platz zwischen Name und Status ein */ + flex-grow: 1; } /* 4. STATUS (UNTEN) */ @@ -460,20 +543,42 @@ function mcph_shortcode( $atts ) { .mc-status { display: inline-block; - padding: 4px 12px; + padding: 5px 14px; border-radius: 20px; font-size: 0.8em; font-weight: 600; + transition: all 0.3s ease; + } + + .mc-online { + background: linear-gradient(135deg, #d4f8e8 0%, #b8f2d9 100%); + color: #0a7340; + border: 1px solid #81e6b8; + box-shadow: 0 2px 4px rgba(10, 115, 64, 0.1); + } + + .mc-offline { + background: linear-gradient(135deg, #fff5f5 0%, #ffe5e5 100%); + color: #c53030; + border: 1px solid #fbb6b6; + box-shadow: 0 2px 4px rgba(197, 48, 48, 0.1); + } + + .mc-player-card:hover .mc-status { + transform: scale(1.05); } - .mc-online { background-color: #e6fffa; color: #28a745; border: 1px solid #b2f5ea; } - .mc-offline { background-color: #fff5f5; color: #e53e3e; border: 1px solid #feb2b2; } .mc-update-time { - font-size: 0.8em; - color: #999; + font-size: 0.85em; + color: #718096; text-align: center; - margin-top: 15px; + margin-top: 20px; font-style: italic; + padding: 8px; + background: rgba(102, 126, 234, 0.05); + border-radius: 6px; + display: inline-block; + width: 100%; } @media (min-width: 1200px) { @@ -481,10 +586,20 @@ function mcph_shortcode( $atts ) { } @media (max-width: 600px) { - .mc-grid { grid-template-columns: repeat(2, 1fr); gap: 10px; } - .mc-avatar { width: 50px; height: 50px; } - .mc-name { font-size: 1em; } - .mc-player-card { padding: 10px 5px; } + .mc-grid { + grid-template-columns: repeat(2, 1fr); + gap: 12px; + } + .mc-avatar { + width: 70px; + height: 70px; + } + .mc-name { + font-size: 1em; + } + .mc-player-card { + padding: 15px 8px; + } } ';