Achievements Service - UQcsse3200/2026-studio-4 GitHub Wiki
Achievements Service
Part of Achievements ยท Achievements Test Plan
AchievementService (com.csse3200.game.services) is the single registry for all Achievement objects. It receives AchievementContext updates from reporter components, dispatches unlock events, and exposes state for the UI and the save system.
It is accessed through ServiceLocator:
ServiceLocator.registerAchievementService(service); // at game setup
ServiceLocator.getAchievementService(); // may be null, so null-check it
ServiceLocator.clear(); // resets it to null
API
| Method | Description |
|---|---|
register(Achievement) |
Adds an achievement. Called once per achievement at setup. |
update(AchievementContext) |
Offers the context to every registered achievement. Each one that unlocks triggers achievementUnlocked. |
getEvents() |
Returns the service's EventHandler. |
getAchievements() |
The live (mutable) list of achievements. Use it for display, not modification. |
getUnlockedAchievementNames() |
Names of all unlocked achievements. Used for saving. |
getAchievementProgress() |
Map of name to progress. Used for saving and progress bars. |
getAchievementDescriptions() |
Map of name to description. |
restoreState(unlockedNames, savedProgress) |
Restores unlock flag and progress for every registered achievement, matched by name. |
Events
| Event | Payload | Listener |
|---|---|---|
achievementUnlocked |
String (achievement name) |
AchievementDisplay. Add your own to react to unlocks. |
ServiceLocator.getAchievementService()
.getEvents()
.addListener("achievementUnlocked", (String name) -> logger.info("Got {}", name));
Persistence
Save: write getUnlockedAchievementNames() and getAchievementProgress() to the save data. The save mapper is source/core/src/main/com/csse3200/game/files/GameSaveMapper.java.
Load: after all achievements are registered, call restoreState(names, progress).
- A null list or map is treated as empty.
- Achievements not in the saved list are locked.
- Achievements missing from the saved progress get 0.
- Matching is by name, so achievement names must be stable.
Behaviour notes
updateloops over every achievement on every event, which is cheap at the current ~50 achievements.- Unlock dispatch is synchronous on the calling thread, so keep
achievementUnlockedlisteners light. - Don't call
registerinside anachievementUnlockedlistener, because the list is being iterated. - An
Achievementignores updates once unlocked and returnstruefromupdateonly on the unlocking call, so listeners fire once per achievement. restoreStaterestores only the flag and progress. State captured inside a condition lambda (for example theenemySetseen-set) is not restored.