Files
Ninjaserver/wiki/Achievement-System.md
2025-09-23 14:13:24 +02:00

12 KiB

🏆 Achievement System

Umfassende Dokumentation des Achievement-Systems für das Ninja Cross Parkour System.

📊 System-Übersicht

Das Achievement-System besteht aus:

  • 32 verschiedene Achievements in 4 Kategorien
  • Automatische tägliche Vergabe am Ende des Tages
  • REST API Endpoints für Frontend-Integration
  • PostgreSQL Funktionen für effiziente Verarbeitung

🎯 Achievement-Kategorien

1. Konsistenz-basierte Achievements

  • Erste Schritte 👶 - Erste Zeit aufgezeichnet (5 Punkte)
  • Durchhalter 💪 - 3 Versuche an einem Tag (10 Punkte)
  • Fleißig 🔥 - 5 Versuche an einem Tag (15 Punkte)
  • Besessen 😤 - 10 Versuche an einem Tag (25 Punkte)
  • Regelmäßig 📅 - 5 verschiedene Tage gespielt (20 Punkte)
  • Stammgast - 10 verschiedene Tage gespielt (30 Punkte)
  • Treue 💎 - 20 verschiedene Tage gespielt (50 Punkte)
  • Veteran 🏆 - 50 verschiedene Tage gespielt (100 Punkte)

2. Verbesserungs-basierte Achievements

  • Fortschritt 📈 - Persönliche Bestzeit um 5 Sekunden verbessert (15 Punkte)
  • Durchbruch - Persönliche Bestzeit um 10 Sekunden verbessert (25 Punkte)
  • Transformation 🔄 - Persönliche Bestzeit um 15 Sekunden verbessert (40 Punkte)
  • Perfektionist - Persönliche Bestzeit um 20 Sekunden verbessert (60 Punkte)

3. Saisonale Achievements

  • Wochenend-Krieger 🏁 - Am Wochenende gespielt (10 Punkte)
  • Nachmittags-Sportler ☀️ - Zwischen 14-18 Uhr gespielt (10 Punkte)
  • Frühaufsteher 🌅 - Vor 10 Uhr gespielt (15 Punkte)
  • Abend-Sportler 🌙 - Nach 18 Uhr gespielt (10 Punkte)

4. Monatliche Achievements

  • Januar-Krieger ❄️ bis Dezember-Dynamo 🎄 (je 20 Punkte)

5. Jahreszeiten-Achievements

  • Frühjahrs-Fighter 🌱 - Im Frühling gespielt (30 Punkte)
  • Sommer-Sportler ☀️ - Im Sommer gespielt (30 Punkte)
  • Herbst-Held 🍂 - Im Herbst gespielt (30 Punkte)
  • Winter-Warrior ❄️ - Im Winter gespielt (30 Punkte)

🗄️ Datenbank-Schema

Tabelle: achievements

- id (uuid, PK)
- name (varchar) - Achievement-Name
- description (text) - Beschreibung
- category (varchar) - Kategorie
- condition_type (varchar) - Bedingungstyp
- condition_value (integer) - Bedingungswert
- icon (varchar) - Emoji-Icon
- points (integer) - Punkte
- is_active (boolean) - Aktiv
- created_at (timestamp)

Tabelle: player_achievements

- id (uuid, PK)
- player_id (uuid, FK) - Verweis auf players.id
- achievement_id (uuid, FK) - Verweis auf achievements.id
- earned_at (timestamp) - Wann erreicht
- progress (integer) - Fortschritt
- is_completed (boolean) - Abgeschlossen
- created_at (timestamp)

🔧 PostgreSQL Funktionen

check_consistency_achievements(player_uuid)

Überprüft alle Konsistenz-basierten Achievements für einen Spieler.

Logik:

  • Zählt Gesamtläufe des Spielers
  • Zählt Läufe pro Tag
  • Zählt verschiedene Spieltage
  • Vergibt entsprechende Achievements

check_improvement_achievements(player_uuid)

Überprüft alle Verbesserungs-basierten Achievements für einen Spieler.

Logik:

  • Ermittelt persönliche Bestzeit
  • Berechnet Verbesserung seit erster Zeit
  • Vergibt entsprechende Achievements

check_seasonal_achievements(player_uuid)

Überprüft alle saisonalen und monatlichen Achievements für einen Spieler.

Logik:

  • Prüft Wochentag (Wochenende)
  • Prüft Tageszeit (morgens, nachmittags, abends)
  • Prüft Monat (Januar bis Dezember)
  • Prüft Jahreszeit (Frühling, Sommer, Herbst, Winter)

check_all_achievements(player_uuid)

Führt alle Achievement-Überprüfungen für einen Spieler aus.

🚀 API Endpoints

GET /api/achievements

Alle verfügbaren Achievements abrufen.

Response:

{
  "success": true,
  "data": [
    {
      "id": "uuid",
      "name": "Erste Schritte",
      "description": "Absolviere deinen ersten Lauf",
      "category": "consistency",
      "condition_type": "runs_count",
      "condition_value": 1,
      "icon": "👶",
      "points": 5,
      "is_active": true
    }
  ]
}

GET /api/achievements/player/:playerId

Achievements eines bestimmten Spielers abrufen.

Response:

{
  "success": true,
  "data": [
    {
      "id": "uuid",
      "achievement_id": "uuid",
      "name": "Erste Schritte",
      "description": "Absolviere deinen ersten Lauf",
      "icon": "👶",
      "points": 5,
      "progress": 1,
      "is_completed": true,
      "earned_at": "2024-01-01T00:00:00Z"
    }
  ]
}

GET /api/achievements/player/:playerId/stats

Achievement-Statistiken eines Spielers abrufen.

Response:

{
  "success": true,
  "data": {
    "total_achievements": 32,
    "completed_achievements": 5,
    "total_points": 150,
    "earned_points": 75,
    "completion_percentage": 15.6
  }
}

POST /api/achievements/check/:playerId

Achievements für einen Spieler manuell überprüfen.

Request:

{
  "achievement_id": "uuid"
}

POST /api/achievements/daily-check

Tägliche Achievement-Überprüfung für alle Spieler ausführen.

Response:

{
  "success": true,
  "message": "Daily achievement check completed",
  "players_checked": 150,
  "achievements_awarded": 25
}

GET /api/achievements/leaderboard?limit=10

Bestenliste der Spieler nach Achievement-Punkten.

Response:

{
  "success": true,
  "data": [
    {
      "player_id": "uuid",
      "firstname": "Max",
      "lastname": "Mustermann",
      "total_points": 500,
      "completed_achievements": 15,
      "rank": 1
    }
  ]
}

📅 Automatisierung

Tägliches Script

# Manuell ausführen
node scripts/daily_achievements.js

# Cron-Job einrichten
node scripts/setup_cron.js setup

# Cron-Job Status prüfen
node scripts/setup_cron.js status

# Cron-Job entfernen
node scripts/setup_cron.js remove

Cron-Schedule

  • Zeit: Täglich um 23:59 Uhr
  • Log: /var/log/ninjaserver_achievements.log

Script-Details

// scripts/daily_achievements.js
const { checkAllAchievements } = require('../models/Achievement');

async function dailyCheck() {
  try {
    // Alle Spieler abrufen
    const players = await getAllPlayers();
    
    let totalAwarded = 0;
    
    for (const player of players) {
      const awarded = await checkAllAchievements(player.id);
      totalAwarded += awarded;
    }
    
    console.log(`Daily check completed: ${totalAwarded} achievements awarded`);
  } catch (error) {
    console.error('Daily check failed:', error);
  }
}

🎮 Frontend-Integration

Beispiel: Achievement-Liste laden

async function loadAchievements(playerId) {
  try {
    const response = await fetch(`/api/achievements/player/${playerId}`);
    const data = await response.json();
    
    if (data.success) {
      data.data.forEach(achievement => {
        const status = achievement.is_completed ? '✅' : '❌';
        console.log(`${achievement.icon} ${achievement.name}: ${status}`);
      });
    }
  } catch (error) {
    console.error('Error loading achievements:', error);
  }
}

Beispiel: Statistiken anzeigen

async function loadStats(playerId) {
  try {
    const response = await fetch(`/api/achievements/player/${playerId}/stats`);
    const data = await response.json();
    
    if (data.success) {
      const stats = data.data;
      document.getElementById('total-points').textContent = stats.total_points;
      document.getElementById('completed').textContent = 
        `${stats.completed_achievements}/${stats.total_achievements}`;
      document.getElementById('percentage').textContent = 
        `${stats.completion_percentage}%`;
    }
  } catch (error) {
    console.error('Error loading stats:', error);
  }
}

Beispiel: Achievement-Animation

function showAchievementNotification(achievement) {
  const notification = document.createElement('div');
  notification.className = 'achievement-notification';
  notification.innerHTML = `
    <div class="achievement-icon">${achievement.icon}</div>
    <div class="achievement-text">
      <h3>${achievement.name}</h3>
      <p>${achievement.description}</p>
      <span class="points">+${achievement.points} Punkte</span>
    </div>
  `;
  
  document.body.appendChild(notification);
  
  // Animation
  setTimeout(() => {
    notification.classList.add('show');
  }, 100);
  
  // Entfernen nach 5 Sekunden
  setTimeout(() => {
    notification.remove();
  }, 5000);
}

🔍 Monitoring

Logs überwachen

# Live-Logs anzeigen
tail -f /var/log/ninjaserver_achievements.log

# Letzte Ausführung prüfen
grep "Daily achievement check completed" /var/log/ninjaserver_achievements.log | tail -1

# Fehler-Logs anzeigen
grep "ERROR" /var/log/ninjaserver_achievements.log

Datenbank-Status prüfen

-- Achievement-Statistiken
SELECT 
    COUNT(*) as total_achievements,
    COUNT(CASE WHEN is_active = true THEN 1 END) as active_achievements
FROM achievements;

-- Spieler-Statistiken
SELECT 
    COUNT(DISTINCT player_id) as players_with_achievements,
    COUNT(*) as total_earned_achievements
FROM player_achievements 
WHERE is_completed = true;

-- Top-Spieler
SELECT 
    p.firstname,
    p.lastname,
    COUNT(pa.id) as achievements,
    SUM(a.points) as total_points
FROM players p
JOIN player_achievements pa ON p.id = pa.player_id
JOIN achievements a ON pa.achievement_id = a.id
WHERE pa.is_completed = true
GROUP BY p.id, p.firstname, p.lastname
ORDER BY total_points DESC
LIMIT 10;

🛠️ Wartung

Neue Achievements hinzufügen

  1. Achievement in achievements Tabelle einfügen:
INSERT INTO achievements (name, description, category, condition_type, condition_value, icon, points)
VALUES ('Neues Achievement', 'Beschreibung', 'consistency', 'runs_count', 5, '🏆', 25);
  1. Logik in entsprechenden PostgreSQL Funktionen erweitern
  2. API Endpoints testen

Achievement deaktivieren

UPDATE achievements SET is_active = false WHERE name = 'Achievement-Name';

Daten zurücksetzen

-- Alle Spieler-Achievements löschen
DELETE FROM player_achievements;

-- Achievement-Statistiken zurücksetzen
UPDATE achievements SET created_at = NOW();

Achievement-Import/Export

# Export
pg_dump -t achievements -t player_achievements ninjaserver > achievements_backup.sql

# Import
psql ninjaserver < achievements_backup.sql

📈 Performance

Indizierung

-- Performance-Indizes
CREATE INDEX CONCURRENTLY idx_player_achievements_player_id 
ON player_achievements(player_id);

CREATE INDEX CONCURRENTLY idx_player_achievements_achievement_id 
ON player_achievements(achievement_id);

CREATE INDEX CONCURRENTLY idx_player_achievements_completed 
ON player_achievements(is_completed) WHERE is_completed = true;

Batch-Processing

  • Effiziente Verarbeitung aller Spieler in einem Durchgang
  • Transaktionale Sicherheit für Datenkonsistenz
  • Fehlerbehandlung für einzelne Spieler

Caching

  • Achievement-Definitionen werden gecacht
  • Spieler-Statistiken werden bei Änderungen neu berechnet
  • Leaderboard wird periodisch aktualisiert

Zeitzone-Behandlung

  • Korrekte Zeitzone (Europe/Berlin) für alle Zeitberechnungen
  • Saisonale Achievements berücksichtigen lokale Zeit
  • Tägliche Prüfung erfolgt zur richtigen Zeit

🔒 Sicherheit

API-Schutz

  • Alle Endpoints über bestehende Authentifizierung
  • Admin-Endpoints erfordern erweiterte Berechtigung
  • Rate Limiting für häufige Anfragen

SQL-Injection

  • Parametrisierte Queries in allen Funktionen
  • Input-Validierung vor Datenbankzugriff
  • Escape-Funktionen für dynamische Inhalte

Datenvalidierung

  • Eingabe-Validierung in allen API-Endpoints
  • Typ-Überprüfung für alle Parameter
  • Bereichs-Validierung für numerische Werte

Fehlerbehandlung

  • Umfassende Error-Handling in allen Funktionen
  • Logging aller Fehler und Warnungen
  • Graceful Degradation bei Systemfehlern

🎯 Best Practices

Achievement-Design

  • Klare Bedingungen für alle Achievements
  • Angemessene Punkte basierend auf Schwierigkeit
  • Motivierende Beschreibungen für Spieler

Performance-Optimierung

  • Batch-Processing für große Datenmengen
  • Indizierung für häufige Abfragen
  • Caching für statische Daten

Wartbarkeit

  • Modulare Struktur für einfache Erweiterungen
  • Dokumentation aller Funktionen
  • Tests für kritische Komponenten

Erstellt am: $(date)
Version: 1.0.0
Autor: Ninja Cross Parkour System