Diverse änderungen am Push system

This commit is contained in:
2025-09-16 21:00:12 +02:00
parent 69e3985af3
commit b2fc63e2d0
7 changed files with 992 additions and 164 deletions

View File

@@ -89,7 +89,17 @@ class AchievementSystem {
});
});
console.log(`📋 ${result.rows.length} Achievements für Spieler ${playerId} geladen`);
// Count unique achievements and duplicates
const uniqueAchievements = new Set(result.rows.map(row => row.achievement_id));
const totalCount = result.rows.length;
const uniqueCount = uniqueAchievements.size;
const duplicateCount = totalCount - uniqueCount;
if (duplicateCount > 0) {
console.log(`📋 ${totalCount} Achievements für Spieler ${playerId} geladen (${uniqueCount} eindeutige, ${duplicateCount} doppelt)`);
} else {
console.log(`📋 ${totalCount} Achievements für Spieler ${playerId} geladen`);
}
return true;
} catch (error) {
console.error(`❌ Fehler beim Laden der Spieler-Achievements für ${playerId}:`, error);
@@ -535,106 +545,138 @@ class AchievementSystem {
}
/**
* Prüft Tageskönig Achievement
* Prüft Tageskönig Achievement pro Standort
*/
async checkDailyBest(playerId, currentDate, newAchievements) {
const achievement = Array.from(this.achievements.values())
.find(a => a.category === 'best_time' && a.condition_type === 'daily_best');
.find(a => a.category === 'time' && a.condition_type === 'best_time_daily_location');
if (!achievement) return;
// Prüfe ob das Achievement heute bereits vergeben wurde
const alreadyEarnedToday = await pool.query(`
SELECT COUNT(*) as count
FROM player_achievements pa
WHERE pa.player_id = $1
AND pa.achievement_id = $2
AND DATE(pa.earned_at AT TIME ZONE 'Europe/Berlin') = CURRENT_DATE
`, [playerId, achievement.id]);
if (parseInt(alreadyEarnedToday.rows[0].count) > 0) return;
// Hole beste Zeit des Spielers heute
const playerResult = await pool.query(`
SELECT MIN(recorded_time) as best_time
// Hole alle Standorte, an denen der Spieler heute gespielt hat
const locationsResult = await pool.query(`
SELECT DISTINCT t.location_id, l.name as location_name
FROM times t
INNER JOIN locations l ON t.location_id = l.id
WHERE t.player_id = $1
AND DATE(t.created_at AT TIME ZONE 'Europe/Berlin') = $2
`, [playerId, currentDate]);
// Hole beste Zeit des Tages
const dailyResult = await pool.query(`
SELECT MIN(recorded_time) as best_time
FROM times t
WHERE DATE(t.created_at AT TIME ZONE 'Europe/Berlin') = $1
`, [currentDate]);
for (const location of locationsResult.rows) {
// Prüfe ob das Achievement heute bereits für diesen Standort vergeben wurde
const alreadyEarnedToday = await pool.query(`
SELECT COUNT(*) as count
FROM player_achievements pa
WHERE pa.player_id = $1
AND pa.achievement_id = $2
AND pa.location_id = $3
AND DATE(pa.earned_at AT TIME ZONE 'Europe/Berlin') = CURRENT_DATE
`, [playerId, achievement.id, location.location_id]);
if (parseInt(alreadyEarnedToday.rows[0].count) > 0) continue;
const playerBest = playerResult.rows[0].best_time;
const dailyBest = dailyResult.rows[0].best_time;
// Hole beste Zeit des Spielers heute an diesem Standort
const playerResult = await pool.query(`
SELECT MIN(recorded_time) as best_time
FROM times t
WHERE t.player_id = $1
AND t.location_id = $2
AND DATE(t.created_at AT TIME ZONE 'Europe/Berlin') = $3
`, [playerId, location.location_id, currentDate]);
if (playerBest && dailyBest && playerBest === dailyBest) {
await this.awardAchievement(playerId, achievement, 1, newAchievements);
// Hole beste Zeit des Tages an diesem Standort
const dailyResult = await pool.query(`
SELECT MIN(recorded_time) as best_time
FROM times t
WHERE t.location_id = $1
AND DATE(t.created_at AT TIME ZONE 'Europe/Berlin') = $2
`, [location.location_id, currentDate]);
const playerBest = playerResult.rows[0].best_time;
const dailyBest = dailyResult.rows[0].best_time;
if (playerBest && dailyBest && playerBest === dailyBest) {
await this.awardAchievement(playerId, achievement, 1, newAchievements, location.location_id);
console.log(`🏆 Tageskönig Achievement vergeben für Standort: ${location.location_name}`);
}
}
}
/**
* Prüft Wochenchampion Achievement
* Prüft Wochenchampion Achievement pro Standort
*/
async checkWeeklyBest(playerId, currentDate, newAchievements) {
const achievement = Array.from(this.achievements.values())
.find(a => a.category === 'best_time' && a.condition_type === 'weekly_best');
.find(a => a.category === 'time' && a.condition_type === 'best_time_weekly_location');
if (!achievement) return;
// Prüfe ob das Achievement diese Woche bereits vergeben wurde
// Berechne Woche
const currentDateObj = new Date(currentDate);
const dayOfWeek = currentDateObj.getDay();
const weekStart = new Date(currentDateObj);
weekStart.setDate(currentDateObj.getDate() - (dayOfWeek === 0 ? 6 : dayOfWeek - 1));
const weekStartStr = weekStart.toISOString().split('T')[0];
const alreadyEarnedThisWeek = await pool.query(`
SELECT COUNT(*) as count
FROM player_achievements pa
WHERE pa.player_id = $1
AND pa.achievement_id = $2
AND DATE(pa.earned_at AT TIME ZONE 'Europe/Berlin') >= $3
AND DATE(pa.earned_at AT TIME ZONE 'Europe/Berlin') <= $4
`, [playerId, achievement.id, weekStartStr, currentDate]);
if (parseInt(alreadyEarnedThisWeek.rows[0].count) > 0) return;
// Hole beste Zeit des Spielers diese Woche
const playerResult = await pool.query(`
SELECT MIN(recorded_time) as best_time
// Hole alle Standorte, an denen der Spieler diese Woche gespielt hat
const locationsResult = await pool.query(`
SELECT DISTINCT t.location_id, l.name as location_name
FROM times t
INNER JOIN locations l ON t.location_id = l.id
WHERE t.player_id = $1
AND DATE(t.created_at AT TIME ZONE 'Europe/Berlin') >= $2
AND DATE(t.created_at AT TIME ZONE 'Europe/Berlin') <= $3
`, [playerId, weekStartStr, currentDate]);
// Hole beste Zeit der Woche
const weeklyResult = await pool.query(`
SELECT MIN(recorded_time) as best_time
FROM times t
WHERE DATE(t.created_at AT TIME ZONE 'Europe/Berlin') >= $1
AND DATE(t.created_at AT TIME ZONE 'Europe/Berlin') <= $2
`, [weekStartStr, currentDate]);
for (const location of locationsResult.rows) {
// Prüfe ob das Achievement diese Woche bereits für diesen Standort vergeben wurde
const alreadyEarnedThisWeek = await pool.query(`
SELECT COUNT(*) as count
FROM player_achievements pa
WHERE pa.player_id = $1
AND pa.achievement_id = $2
AND pa.location_id = $3
AND DATE(pa.earned_at AT TIME ZONE 'Europe/Berlin') >= $4
AND DATE(pa.earned_at AT TIME ZONE 'Europe/Berlin') <= $5
`, [playerId, achievement.id, location.location_id, weekStartStr, currentDate]);
if (parseInt(alreadyEarnedThisWeek.rows[0].count) > 0) continue;
const playerBest = playerResult.rows[0].best_time;
const weeklyBest = weeklyResult.rows[0].best_time;
// Hole beste Zeit des Spielers diese Woche an diesem Standort
const playerResult = await pool.query(`
SELECT MIN(recorded_time) as best_time
FROM times t
WHERE t.player_id = $1
AND t.location_id = $2
AND DATE(t.created_at AT TIME ZONE 'Europe/Berlin') >= $3
AND DATE(t.created_at AT TIME ZONE 'Europe/Berlin') <= $4
`, [playerId, location.location_id, weekStartStr, currentDate]);
if (playerBest && weeklyBest && playerBest === weeklyBest) {
await this.awardAchievement(playerId, achievement, 1, newAchievements);
// Hole beste Zeit der Woche an diesem Standort
const weeklyResult = await pool.query(`
SELECT MIN(recorded_time) as best_time
FROM times t
WHERE t.location_id = $1
AND DATE(t.created_at AT TIME ZONE 'Europe/Berlin') >= $2
AND DATE(t.created_at AT TIME ZONE 'Europe/Berlin') <= $3
`, [location.location_id, weekStartStr, currentDate]);
const playerBest = playerResult.rows[0].best_time;
const weeklyBest = weeklyResult.rows[0].best_time;
if (playerBest && weeklyBest && playerBest === weeklyBest) {
await this.awardAchievement(playerId, achievement, 1, newAchievements, location.location_id);
console.log(`🏆 Wochenchampion Achievement vergeben für Standort: ${location.location_name}`);
}
}
}
/**
* Prüft Monatsmeister Achievement
* Prüft Monatsmeister Achievement pro Standort
*/
async checkMonthlyBest(playerId, currentDate, newAchievements) {
const achievement = Array.from(this.achievements.values())
.find(a => a.category === 'best_time' && a.condition_type === 'monthly_best');
.find(a => a.category === 'time' && a.condition_type === 'best_time_monthly_location');
if (!achievement) return;
@@ -642,41 +684,57 @@ class AchievementSystem {
const currentDateObj = new Date(currentDate);
const monthStart = new Date(currentDateObj.getFullYear(), currentDateObj.getMonth(), 1);
const monthStartStr = monthStart.toISOString().split('T')[0];
// Prüfe ob das Achievement diesen Monat bereits vergeben wurde
const alreadyEarnedThisMonth = await pool.query(`
SELECT COUNT(*) as count
FROM player_achievements pa
WHERE pa.player_id = $1
AND pa.achievement_id = $2
AND DATE(pa.earned_at AT TIME ZONE 'Europe/Berlin') >= $3
AND DATE(pa.earned_at AT TIME ZONE 'Europe/Berlin') <= $4
`, [playerId, achievement.id, monthStartStr, currentDate]);
if (parseInt(alreadyEarnedThisMonth.rows[0].count) > 0) return;
// Hole beste Zeit des Spielers diesen Monat
const playerResult = await pool.query(`
SELECT MIN(recorded_time) as best_time
// Hole alle Standorte, an denen der Spieler diesen Monat gespielt hat
const locationsResult = await pool.query(`
SELECT DISTINCT t.location_id, l.name as location_name
FROM times t
INNER JOIN locations l ON t.location_id = l.id
WHERE t.player_id = $1
AND DATE(t.created_at AT TIME ZONE 'Europe/Berlin') >= $2
AND DATE(t.created_at AT TIME ZONE 'Europe/Berlin') <= $3
`, [playerId, monthStartStr, currentDate]);
// Hole beste Zeit des Monats
const monthlyResult = await pool.query(`
SELECT MIN(recorded_time) as best_time
FROM times t
WHERE DATE(t.created_at AT TIME ZONE 'Europe/Berlin') >= $1
AND DATE(t.created_at AT TIME ZONE 'Europe/Berlin') <= $2
`, [monthStartStr, currentDate]);
for (const location of locationsResult.rows) {
// Prüfe ob das Achievement diesen Monat bereits für diesen Standort vergeben wurde
const alreadyEarnedThisMonth = await pool.query(`
SELECT COUNT(*) as count
FROM player_achievements pa
WHERE pa.player_id = $1
AND pa.achievement_id = $2
AND pa.location_id = $3
AND DATE(pa.earned_at AT TIME ZONE 'Europe/Berlin') >= $4
AND DATE(pa.earned_at AT TIME ZONE 'Europe/Berlin') <= $5
`, [playerId, achievement.id, location.location_id, monthStartStr, currentDate]);
if (parseInt(alreadyEarnedThisMonth.rows[0].count) > 0) continue;
const playerBest = playerResult.rows[0].best_time;
const monthlyBest = monthlyResult.rows[0].best_time;
// Hole beste Zeit des Spielers diesen Monat an diesem Standort
const playerResult = await pool.query(`
SELECT MIN(recorded_time) as best_time
FROM times t
WHERE t.player_id = $1
AND t.location_id = $2
AND DATE(t.created_at AT TIME ZONE 'Europe/Berlin') >= $3
AND DATE(t.created_at AT TIME ZONE 'Europe/Berlin') <= $4
`, [playerId, location.location_id, monthStartStr, currentDate]);
if (playerBest && monthlyBest && playerBest === monthlyBest) {
await this.awardAchievement(playerId, achievement, 1, newAchievements);
// Hole beste Zeit des Monats an diesem Standort
const monthlyResult = await pool.query(`
SELECT MIN(recorded_time) as best_time
FROM times t
WHERE t.location_id = $1
AND DATE(t.created_at AT TIME ZONE 'Europe/Berlin') >= $2
AND DATE(t.created_at AT TIME ZONE 'Europe/Berlin') <= $3
`, [location.location_id, monthStartStr, currentDate]);
const playerBest = playerResult.rows[0].best_time;
const monthlyBest = monthlyResult.rows[0].best_time;
if (playerBest && monthlyBest && playerBest === monthlyBest) {
await this.awardAchievement(playerId, achievement, 1, newAchievements, location.location_id);
console.log(`🏆 Monatsmeister Achievement vergeben für Standort: ${location.location_name}`);
}
}
}
@@ -684,12 +742,12 @@ class AchievementSystem {
* Vergibt ein Achievement an einen Spieler
* Erstellt immer einen neuen Eintrag (keine Updates mehr)
*/
async awardAchievement(playerId, achievement, progress, newAchievements) {
async awardAchievement(playerId, achievement, progress, newAchievements, locationId = null) {
try {
await pool.query(`
INSERT INTO player_achievements (player_id, achievement_id, progress, is_completed, earned_at)
VALUES ($1, $2, $3, true, NOW())
`, [playerId, achievement.id, progress]);
INSERT INTO player_achievements (player_id, achievement_id, progress, is_completed, earned_at, location_id)
VALUES ($1, $2, $3, true, NOW(), $4)
`, [playerId, achievement.id, progress, locationId]);
newAchievements.push({
id: achievement.id,
@@ -697,10 +755,12 @@ class AchievementSystem {
description: achievement.description,
icon: achievement.icon,
points: achievement.points,
progress: progress
progress: progress,
locationId: locationId
});
console.log(`🏆 Achievement vergeben: ${achievement.icon} ${achievement.name} (+${achievement.points} Punkte)`);
const locationText = locationId ? ` (Standort: ${locationId})` : '';
console.log(`🏆 Achievement vergeben: ${achievement.icon} ${achievement.name} (+${achievement.points} Punkte)${locationText}`);
} catch (error) {
console.error(`❌ Fehler beim Vergeben des Achievements ${achievement.name}:`, error);
}