mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-26 09:33:02 +01:00
feat(achievement): add rank-up notifications (#165)
RE'd putDisplayed_achievement from ZZ client DLL via Ghidra: the packet sends opcode + 1 zero byte with no achievement ID, acting as a blanket "I saw everything" signal. Server changes: - Track per-character last-displayed levels in new displayed_levels column (migration 0008) - GetAchievement compares current vs displayed levels per entry - DisplayedAchievement snapshots current levels to clear notifications - Repo, service, mock, and 3 new service tests Protbot changes: - New --action achievement: fetches achievements, shows rank-up markers, sends DISPLAYED_ACHIEVEMENT, re-fetches to verify notifications clear - Packet builders for GET/ADD/DISPLAYED_ACHIEVEMENT
This commit is contained in:
@@ -23,6 +23,7 @@ const achievementEntryCount = uint8(33)
|
||||
type AchievementSummary struct {
|
||||
Points uint32
|
||||
Achievements [33]Achievement
|
||||
Notify [33]bool
|
||||
}
|
||||
|
||||
// GetAll ensures the achievement record exists, fetches all scores, and computes
|
||||
@@ -38,15 +39,49 @@ func (svc *AchievementService) GetAll(charID uint32) (*AchievementSummary, error
|
||||
return nil, err
|
||||
}
|
||||
|
||||
displayed, err := svc.achievementRepo.GetDisplayedLevels(charID)
|
||||
if err != nil {
|
||||
svc.logger.Debug("No displayed levels found, all rank-ups will notify", zap.Error(err))
|
||||
}
|
||||
|
||||
var summary AchievementSummary
|
||||
for id := uint8(0); id < achievementEntryCount; id++ {
|
||||
ach := GetAchData(id, scores[id])
|
||||
summary.Points += ach.Value
|
||||
summary.Achievements[id] = ach
|
||||
|
||||
// Notify if current level exceeds the last-displayed level.
|
||||
if ach.Level > 0 {
|
||||
if displayed == nil || int(id) >= len(displayed) {
|
||||
summary.Notify[id] = true
|
||||
} else if ach.Level > displayed[id] {
|
||||
summary.Notify[id] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
return &summary, nil
|
||||
}
|
||||
|
||||
// MarkDisplayed snapshots the current achievement levels so that future
|
||||
// GET_ACHIEVEMENT responses only notify on new rank-ups since this point.
|
||||
func (svc *AchievementService) MarkDisplayed(charID uint32) error {
|
||||
if err := svc.achievementRepo.EnsureExists(charID); err != nil {
|
||||
svc.logger.Error("Failed to ensure achievements record", zap.Error(err))
|
||||
}
|
||||
|
||||
scores, err := svc.achievementRepo.GetAllScores(charID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
levels := make([]byte, achievementEntryCount)
|
||||
for id := uint8(0); id < achievementEntryCount; id++ {
|
||||
ach := GetAchData(id, scores[id])
|
||||
levels[id] = ach.Level
|
||||
}
|
||||
return svc.achievementRepo.SaveDisplayedLevels(charID, levels)
|
||||
}
|
||||
|
||||
// Increment validates the achievement ID, ensures the record exists, and bumps
|
||||
// the score for the given achievement category.
|
||||
func (svc *AchievementService) Increment(charID uint32, achievementID uint8) error {
|
||||
|
||||
Reference in New Issue
Block a user