mc-player-history.php aktualisiert

This commit is contained in:
2026-02-09 20:11:27 +00:00
parent 7f5efe273d
commit 65e1921da1

View File

@@ -2,8 +2,8 @@
/* /*
Plugin Name: MC Player History Plugin Name: MC Player History
Description: Spielerverlauf deines Minecraft Servers. Description: Spielerverlauf deines Minecraft Servers.
Version: 1.1.0 Version: 1.1.1
Author: Dein Name Author: M_Viper
*/ */
if ( ! defined( 'ABSPATH' ) ) { if ( ! defined( 'ABSPATH' ) ) {
@@ -119,10 +119,33 @@ function mcph_sync_from_statusapi() {
foreach ( $players as $p ) { foreach ( $players as $p ) {
$name = isset( $p->name ) ? sanitize_text_field( $p->name ) : ''; $name = isset( $p->name ) ? sanitize_text_field( $p->name ) : '';
$prefix = isset( $p->prefix ) ? sanitize_text_field( $p->prefix ) : ''; $prefix = isset( $p->prefix ) ? sanitize_text_field( $p->prefix ) : '';
// 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 ) ) ); $uuid = 'legacy-' . md5( strtolower( trim( $name ) ) );
}
if ( empty( $name ) ) continue; 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 ) ); $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' ); $now = current_time( 'mysql' );
if ( $exists ) { if ( $exists ) {
@@ -181,7 +204,12 @@ function mcph_generate_player_html( $limit = 500, $only_online = false, $is_ajax
$has_live_data = true; $has_live_data = true;
foreach ( $api_response as $p ) { foreach ( $api_response as $p ) {
if ( isset( $p->name ) ) { if ( isset( $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 ) ) ); $uuid = 'legacy-' . md5( strtolower( trim( $p->name ) ) );
}
$live_online_uuids[ $uuid ] = true; $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 ); $username = esc_html( $row->username );
$prefix = mcph_parse_minecraft_colors( $row->prefix ); $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 = ''; $anim_style = '';
if ( ! $is_ajax ) { 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 // STRUKTUR: Bild -> Prefix -> Name -> Spacer -> Status
echo '<div class="mc-player-card" style="' . $anim_style . '">'; echo '<div class="mc-player-card" style="' . $anim_style . '">';
echo '<img src="' . $avatar . '" class="mc-avatar" alt="' . $username . '">'; echo '<img src="' . $avatar . '" class="mc-avatar" alt="' . $username . '" loading="lazy">';
echo '<div class="mc-info-stack">'; echo '<div class="mc-info-stack">';
@@ -275,6 +314,33 @@ function mcph_settings_init() {
register_setting( 'mcph_plugin_options', 'mcph_statusapi_url' ); register_setting( 'mcph_plugin_options', 'mcph_statusapi_url' );
} }
function mcph_options_page() { 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 '<div class="notice notice-success"><p>' . $cleaned . ' Duplikate wurden entfernt.</p></div>';
}
if ( isset( $_POST['mcph_manual_sync'] ) && check_admin_referer( 'mcph_manual_sync_action' ) ) { if ( isset( $_POST['mcph_manual_sync'] ) && check_admin_referer( 'mcph_manual_sync_action' ) ) {
mcph_sync_from_statusapi(); mcph_sync_from_statusapi();
delete_transient( 'mcph_api_cache_data' ); delete_transient( 'mcph_api_cache_data' );
@@ -296,6 +362,14 @@ function mcph_options_page() {
</table> </table>
<?php submit_button(); ?> <?php submit_button(); ?>
</form> </form>
<h2>Duplikate bereinigen</h2>
<form method="post">
<?php wp_nonce_field( 'mcph_cleanup_action' ); ?>
<p class="description">Entfernt doppelte Spieler-Einträge aus der Datenbank.</p>
<input type="submit" name="mcph_cleanup_duplicates" class="button button-secondary" value="Duplikate jetzt entfernen" />
</form>
<h2>Manueller Sync</h2> <h2>Manueller Sync</h2>
<form method="post"> <form method="post">
<?php wp_nonce_field( 'mcph_manual_sync_action' ); ?> <?php wp_nonce_field( 'mcph_manual_sync_action' ); ?>
@@ -379,34 +453,41 @@ function mcph_shortcode( $atts ) {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
gap: 8px; /* Weniger Abstand dazwischen */ gap: 8px;
padding: 20px 10px; padding: 20px 10px;
background: #fff; background: linear-gradient(145deg, #ffffff 0%, #f8f9fa 100%);
border: 1px solid #eee; border: 1px solid #e0e0e0;
border-radius: 8px; border-radius: 12px;
transition: all 0.3s ease; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
cursor: default; cursor: default;
position: relative; /* Fallback */ position: relative;
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
} }
.mc-player-card:hover { .mc-player-card:hover {
transform: translateY(-5px); transform: translateY(-8px) scale(1.02);
box-shadow: 0 10px 20px rgba(0,0,0,0.1); box-shadow: 0 12px 24px rgba(0,0,0,0.15);
border-color: #ddd; border-color: #667eea;
background: linear-gradient(145deg, #ffffff 0%, #f0f2ff 100%);
} }
.mc-avatar { .mc-avatar {
border-radius: 4px; border-radius: 8px;
border: 3px solid #ddd; border: 3px solid #e0e0e0;
background: #fff; background: transparent;
width: 60px; width: 80px;
height: 60px; height: 80px;
transition: border-color 0.3s; transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
flex-shrink: 0; 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 { .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 */ /* INFOS BEREICH */
@@ -415,10 +496,10 @@ function mcph_shortcode( $atts ) {
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
width: 100%; width: 100%;
flex-grow: 1; /* Füllt den Rest der Karte */ flex-grow: 1;
position: relative; /* Referenz für absoluten Status */ position: relative;
padding-bottom: 35px; /* Platz für Status unten */ padding-bottom: 35px;
justify-content: flex-start; /* Oben ausrichten */ justify-content: flex-start;
} }
/* 1. PREFIX */ /* 1. PREFIX */
@@ -429,22 +510,24 @@ function mcph_shortcode( $atts ) {
text-align: center; text-align: center;
margin-bottom: 4px; margin-bottom: 4px;
line-height: 1.2; line-height: 1.2;
text-shadow: 0 1px 2px rgba(0,0,0,0.1);
} }
/* 2. NAME */ /* 2. NAME */
.mc-name { .mc-name {
font-weight: bold; font-weight: bold;
font-size: 1.1em; font-size: 1.1em;
color: #333; color: #2d3748;
word-break: break-word; word-break: break-word;
display: block; display: block;
width: 100%; width: 100%;
text-align: center; text-align: center;
text-shadow: 0 1px 2px rgba(0,0,0,0.05);
} }
/* 3. SPACER */ /* 3. SPACER */
.mc-spacer { .mc-spacer {
flex-grow: 1; /* Nimmt ALLEN leeren Platz zwischen Name und Status ein */ flex-grow: 1;
} }
/* 4. STATUS (UNTEN) */ /* 4. STATUS (UNTEN) */
@@ -460,20 +543,42 @@ function mcph_shortcode( $atts ) {
.mc-status { .mc-status {
display: inline-block; display: inline-block;
padding: 4px 12px; padding: 5px 14px;
border-radius: 20px; border-radius: 20px;
font-size: 0.8em; font-size: 0.8em;
font-weight: 600; 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 { .mc-update-time {
font-size: 0.8em; font-size: 0.85em;
color: #999; color: #718096;
text-align: center; text-align: center;
margin-top: 15px; margin-top: 20px;
font-style: italic; font-style: italic;
padding: 8px;
background: rgba(102, 126, 234, 0.05);
border-radius: 6px;
display: inline-block;
width: 100%;
} }
@media (min-width: 1200px) { @media (min-width: 1200px) {
@@ -481,10 +586,20 @@ function mcph_shortcode( $atts ) {
} }
@media (max-width: 600px) { @media (max-width: 600px) {
.mc-grid { grid-template-columns: repeat(2, 1fr); gap: 10px; } .mc-grid {
.mc-avatar { width: 50px; height: 50px; } grid-template-columns: repeat(2, 1fr);
.mc-name { font-size: 1em; } gap: 12px;
.mc-player-card { padding: 10px 5px; } }
.mc-avatar {
width: 70px;
height: 70px;
}
.mc-name {
font-size: 1em;
}
.mc-player-card {
padding: 15px 8px;
}
} }
</style>'; </style>';