Skip to main content
Implementace v src/Core/Achievements/. Engine je čisté Strategy pattern — každý achievement = jeden checker.

Komponenty

AchievementGranter      ←  orchestrace (grant / revoke / reconcile)
AchievementCheckerInterface  ←  kontrakt pro checkery
AchievementCheckJob     ←  cron entry (hodinově)
Checkers/               ←  konkrétní checkery (1 soubor / 1 achievement)

Interface

namespace App\Core\Achievements;

interface AchievementCheckerInterface {
    public function getAchievementId(): string;
    public function check(string $userId): bool;
}
getAchievementId() vrací UUID achievementu (musí existovat v tabulce achievements). check() vrátí true, pokud uživatel splňuje podmínku.

Granter

class AchievementGranter {
    public function grantIfEarned(string $userId, AchievementCheckerInterface $checker): void;
    public function reconcile(string $userId, array $checkers): void;
}
  • grantIfEarned — přidá záznam do user_achievements, pokud jí ještě uživatel nemá a check() vrátí true.
  • reconcile — 2-way sync: může i revokovat (pokud checker přestane být splněný a achievement to umožňuje).
Většina achievementů je „one-way” — jednou získáno, neztratíte. Některé (např. Steam Linked) reconcile mažou, pokud Steam odpojíte.

Existující checkery

Soubor → odpovídající achievement:
CheckerCo kontroluje
SteamLinkedCheckerusers.steamid != NULL
AnthemUploadedCheckerExistuje user_anthems
FactionFoundedCheckerUživatel je created_by aspoň jedné frakce
FactionLeftCheckerZáznam v user_activities typu faction.left
FactionInviteAcceptedCheckerZáznam v user_activities typu faction.invite.accepted
FactionLeadershipTransferredCheckeruser_activities typu faction.leadership.transferred
NeutralSurvivorCheckerUživatel není v žádné frakci > X dní
CharacterAgeCheckerPostava má age >= X
EarlyDeathCheckerPostava death_at - created_at < 24h
PeacefulDeathCheckerPostava zemřela mimo PvP (death_cause analyse)
SelfKillCheckerDeath cause obsahuje sebevražedný klíč
MoralityStreakCheckerX postav za sebou stejné morálky
JournalCountCheckerPočet zápisů >= N
HoursPlayedCheckerSuma hodin z relay >= X
BeanKingCheckerBeans balance >= X

Cron AchievementCheckJob

public function execute(bool $dryRun): void {
    $users = $this->userFacade->getActiveUsers();
    $checkers = $this->registry->getAll();

    foreach ($users as $user) {
        foreach ($checkers as $checker) {
            $this->granter->grantIfEarned($user->id, $checker);
        }
    }
}

Přidání nového checkeru

1

Definujte achievement

Insert row do achievements (přes POST /api/v1/achievements nebo SQL).
2

Implementujte checker

Třída v src/Core/Achievements/Checkers/MyChecker.php. Implementujte getAchievementId() (vraťte UUID) a check($userId).
3

Zaregistrujte checker

V JobRegistry / CheckerRegistry přidejte instanci.
4

Otestujte v dry-run

php cron.php?...&job=AchievementCheckJob&dry_run=1 ukáže, kdo by dostal.

Notifikace

Po udělení vznikne notifikace achievement.granted s polem announced: false. Po prvním view (UI) se nastaví na true, aby se neukazovala znovu.