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
- Achievement in
achievementsTabelle einfügen:
INSERT INTO achievements (name, description, category, condition_type, condition_value, icon, points)
VALUES ('Neues Achievement', 'Beschreibung', 'consistency', 'runs_count', 5, '🏆', 25);
- Logik in entsprechenden PostgreSQL Funktionen erweitern
- 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