104 lines
5.4 KiB
Java
104 lines
5.4 KiB
Java
package com.example.mindflux.service;
|
|
|
|
import com.example.mindflux.model.Achievement;
|
|
import com.example.mindflux.repository.AchievementRepository;
|
|
import com.example.mindflux.repository.GameScoreRepository;
|
|
import org.springframework.stereotype.Service;
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.LinkedHashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
import java.util.stream.Collectors;
|
|
|
|
@Service
|
|
public class AchievementServiceImpl implements AchievementService {
|
|
|
|
/** Katalog aller Achievements (Titel -> Beschreibung), in Anzeige-Reihenfolge. */
|
|
static final Map<String, String> CATALOG = new LinkedHashMap<>();
|
|
static {
|
|
CATALOG.put("Erster Sieg", "Schließe dein erstes Spiel ab.");
|
|
CATALOG.put("1000er-Club", "Erziele 1000 Punkte in einer einzigen Runde.");
|
|
CATALOG.put("Highscore-Jäger", "Verbessere deinen eigenen Highscore.");
|
|
CATALOG.put("Dauerbrenner", "Spiele dasselbe Spiel zehnmal.");
|
|
CATALOG.put("Punktesammler", "Sammle insgesamt 5000 Punkte.");
|
|
CATALOG.put("Allrounder", "Spiele vier verschiedene Spiele.");
|
|
CATALOG.put("Gedächtnis-Impuls", "Schließe eine MindMatch-Runde mit Punkten ab.");
|
|
CATALOG.put("Quiz-Kapitän", "Schließe eine TechTacular-Runde mit Punkten ab.");
|
|
CATALOG.put("Werkbank aktiv", "Schließe eine DevLab-Runde mit Punkten ab.");
|
|
CATALOG.put("Syntax-Spur", "Schließe eine SyntaxSaga-Runde mit Punkten ab.");
|
|
CATALOG.put("Fluchtprotokoll", "Schließe eine SystemEscape-Runde mit Punkten ab.");
|
|
CATALOG.put("Erste Fallakte", "Schließe eine BugHunter-Akte mit Punkten ab.");
|
|
CATALOG.put("Leitstand-Einsatz", "Schließe eine ServiceClash-Schicht mit Punkten ab.");
|
|
CATALOG.put("Incident Commander", "Löse eine ServiceClash-Schicht ohne Fehler oder Aufdecken.");
|
|
CATALOG.put("Netzwerk-Neustart", "Schließe eine NetWorker-Welt mit Punkten ab.");
|
|
}
|
|
|
|
private final AchievementRepository achievementRepository;
|
|
private final GameScoreRepository gameScoreRepository;
|
|
|
|
public AchievementServiceImpl(AchievementRepository achievementRepository,
|
|
GameScoreRepository gameScoreRepository) {
|
|
this.achievementRepository = achievementRepository;
|
|
this.gameScoreRepository = gameScoreRepository;
|
|
}
|
|
|
|
@Override
|
|
public List<Achievement> getAchievementsForUser(String username) {
|
|
List<Achievement> earned = achievementRepository.findByUsername(username);
|
|
Map<String, Achievement> earnedByTitle = earned.stream()
|
|
.collect(Collectors.toMap(Achievement::getTitle, a -> a, (a, b) -> a));
|
|
|
|
List<Achievement> result = new ArrayList<>();
|
|
// Katalog in fester Reihenfolge: verdient mit Datum, sonst als gesperrte Karte.
|
|
CATALOG.forEach((title, description) -> {
|
|
Achievement achievement = earnedByTitle.remove(title);
|
|
result.add(achievement != null ? achievement
|
|
: new Achievement(title, description, null, false));
|
|
});
|
|
// Ältere/zusätzliche verdiente Achievements außerhalb des Katalogs behalten.
|
|
result.addAll(earnedByTitle.values());
|
|
return result;
|
|
}
|
|
|
|
@Override
|
|
@Transactional
|
|
public void checkAndAward(String username, String game, int score, boolean newHighscore, long playsInGame) {
|
|
Set<String> existing = achievementRepository.findByUsername(username).stream()
|
|
.map(Achievement::getTitle)
|
|
.collect(Collectors.toSet());
|
|
|
|
award(existing, username, "Erster Sieg",
|
|
gameScoreRepository.countByUsername(username) >= 1);
|
|
award(existing, username, "1000er-Club", score >= 1000);
|
|
award(existing, username, "Highscore-Jäger", newHighscore && playsInGame > 1);
|
|
award(existing, username, "Dauerbrenner", playsInGame >= 10);
|
|
award(existing, username, "Punktesammler",
|
|
gameScoreRepository.sumScoreByUsername(username) >= 5000);
|
|
award(existing, username, "Allrounder",
|
|
gameScoreRepository.countDistinctGamesByUsername(username) >= 4);
|
|
String gameAchievement = Map.of(
|
|
"mindmatch", "Gedächtnis-Impuls", "techtacular", "Quiz-Kapitän", "devlab", "Werkbank aktiv",
|
|
"syntax-saga", "Syntax-Spur", "codeescape", "Fluchtprotokoll", "bughunter", "Erste Fallakte",
|
|
"serviceclash", "Leitstand-Einsatz", "networker", "Netzwerk-Neustart").get(game);
|
|
if (gameAchievement != null) award(existing, username, gameAchievement, score > 0);
|
|
}
|
|
|
|
@Override @Transactional
|
|
public void awardSpecial(String username, String title, String description) {
|
|
Set<String> existing = achievementRepository.findByUsername(username).stream().map(Achievement::getTitle).collect(Collectors.toSet());
|
|
if (!existing.contains(title)) { Achievement achievement = new Achievement(title, description, null, true); achievement.setUsername(username); achievementRepository.save(achievement); }
|
|
}
|
|
|
|
private void award(Set<String> existing, String username, String title, boolean condition) {
|
|
if (!condition || existing.contains(title)) {
|
|
return;
|
|
}
|
|
Achievement achievement = new Achievement(title, CATALOG.get(title), null, true);
|
|
achievement.setUsername(username);
|
|
achievementRepository.save(achievement);
|
|
}
|
|
}
|