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

  • update loops over every achievement on every event, which is cheap at the current ~50 achievements.
  • Unlock dispatch is synchronous on the calling thread, so keep achievementUnlocked listeners light.
  • Don't call register inside an achievementUnlocked listener, because the list is being iterated.
  • An Achievement ignores updates once unlocked and returns true from update only on the unlocking call, so listeners fire once per achievement.
  • restoreState restores only the flag and progress. State captured inside a condition lambda (for example the enemySet seen-set) is not restored.