mirror of
https://github.com/prosolis/gogobee.git
synced 2026-07-16 08:52:42 +00:00
Adv 2.0 daily report: migrate to D&D-native render + unified activity source
Two longstanding warts surfaced when the user inspected today's TwinBee
daily report:
1. Active players were rendering "Acted today — no log recorded." The
adventure_activity_log path only captures !rest now; harvest/zone/
expedition action logging was lost during Phase R/L migration. The
stale HasActedToday() check fired on fossil harvest_actions_used
counters that nothing modern increments.
2. Per-player headline still rendered legacy four-skill line ("Combat
Lv.X | Mining Lv.Y | Forage Lv.Z | Fishing Lv.W"). No D&D level,
race, class, or HP — discoverability gap for the layer that's now
canonical.
Fix both:
- adventure_activity_unified.go: new loadAdvDailyActivity(date) unions
dnd_zone_run (zone runs touched today) + dnd_expedition_log
(expedition activity rolled up per expedition) + legacy
adventure_activity_log (mostly !rest). One source of truth.
- adventure_render.go: AdvPlayerDaySummary gains HasDnDChar/DnDLevel/
DnDRace/DnDClass/HPCurrent/HPMax. New advPlayerHeadline helper
renders "Lv.N Race Class — HP cur/max" when a dnd_character row
exists, falls back to the legacy four-skill line plus an inline
"(no D&D sheet — run !setup)" nudge for accounts that haven't
completed setup yet. titleizeDnDToken("half_elf") → "Half-Elf".
- adventure_scheduler.go: postDailySummary swaps loadAdvLogsForDate
for loadAdvDailyActivity. IsResting now derives from "len(acts)==0"
rather than the fossil HasActedToday() counter check, so dead
harvest_actions_used bytes can't trip the active-player branch.
- proddb_daily_report_test.go: renders the report against a copy of
data/gogobee.db and prints it for visual confirmation. Verified
output for 2026-05-09 shows real zone-run outcomes (Withdrew from
Sunken Temple at room 1/6, etc.) instead of the previous "no log
recorded" placeholder.
go vet + go test ./... clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
101
internal/plugin/proddb_daily_report_test.go
Normal file
101
internal/plugin/proddb_daily_report_test.go
Normal file
@@ -0,0 +1,101 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"gogobee/internal/db"
|
||||
)
|
||||
|
||||
// TestProdDB_DailyReportPreview renders the Adv 2.0 daily summary against a
|
||||
// copy of the prod DB and prints it. Manual smoke for the D&D-aware
|
||||
// renderer.
|
||||
func TestProdDB_DailyReportPreview(t *testing.T) {
|
||||
src := "/home/reala-misaki/git/gogobee/data/gogobee.db"
|
||||
if _, err := os.Stat(src); err != nil {
|
||||
t.Skip("prod db not present")
|
||||
}
|
||||
dir := t.TempDir()
|
||||
dst := filepath.Join(dir, "gogobee.db")
|
||||
copyTestFile(t, src, dst)
|
||||
|
||||
db.Close()
|
||||
if err := db.Init(dir); err != nil {
|
||||
t.Fatalf("db.Init: %v", err)
|
||||
}
|
||||
t.Cleanup(db.Close)
|
||||
|
||||
bootstrapPlayerMetaFromLegacy()
|
||||
|
||||
chars, err := loadAllAdvCharacters()
|
||||
if err != nil {
|
||||
t.Fatalf("loadAllAdvCharacters: %v", err)
|
||||
}
|
||||
|
||||
// Use the most recent activity date in the DB so we render against real
|
||||
// data instead of an empty "today".
|
||||
now := time.Now().UTC()
|
||||
dateKey := now.Format("2006-01-02")
|
||||
if acts, _ := loadAdvDailyActivity(dateKey); len(acts) == 0 {
|
||||
// No activity today; walk back up to 7 days for a date that has rows.
|
||||
for i := 1; i <= 7; i++ {
|
||||
cand := now.AddDate(0, 0, -i).Format("2006-01-02")
|
||||
if acts, _ := loadAdvDailyActivity(cand); len(acts) > 0 {
|
||||
dateKey = cand
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
t.Logf("rendering report for date=%s", dateKey)
|
||||
|
||||
todayActs, _ := loadAdvDailyActivity(dateKey)
|
||||
activityMap := make(map[string][]AdvDailyActivity)
|
||||
for uid, e := range todayActs {
|
||||
activityMap[string(uid)] = e
|
||||
}
|
||||
|
||||
var players []AdvPlayerDaySummary
|
||||
for _, c := range chars {
|
||||
dispName, _ := loadDisplayName(c.UserID)
|
||||
ps := AdvPlayerDaySummary{
|
||||
DisplayName: dispName,
|
||||
Level: c.CombatLevel,
|
||||
MiningSkill: c.MiningSkill,
|
||||
ForagingSkill: c.ForagingSkill,
|
||||
FishingSkill: c.FishingSkill,
|
||||
}
|
||||
if dnd, _ := LoadDnDCharacter(c.UserID); dnd != nil {
|
||||
ps.HasDnDChar = true
|
||||
ps.DnDLevel = dnd.Level
|
||||
ps.DnDRace = string(dnd.Race)
|
||||
ps.DnDClass = string(dnd.Class)
|
||||
ps.HPCurrent = dnd.HPCurrent
|
||||
ps.HPMax = dnd.HPMax
|
||||
}
|
||||
|
||||
acts := activityMap[string(c.UserID)]
|
||||
if !c.Alive {
|
||||
ps.IsDead = true
|
||||
ps.DeathSource = c.DeathSource
|
||||
ps.DeathLocation = c.DeathLocation
|
||||
if c.DeadUntil != nil {
|
||||
ps.DeadUntil = c.DeadUntil.Format("15:04") + " UTC"
|
||||
}
|
||||
} else if len(acts) == 0 {
|
||||
ps.IsResting = true
|
||||
ps.SummaryLine = "Stayed in town. The world's still here tomorrow."
|
||||
} else {
|
||||
last := acts[len(acts)-1]
|
||||
ps.Activity = last.Activity
|
||||
ps.Location = last.Location
|
||||
ps.Outcome = last.Outcome
|
||||
ps.SummaryLine = last.Summary
|
||||
}
|
||||
players = append(players, ps)
|
||||
}
|
||||
|
||||
out := renderAdvDailySummary(dateKey, nil, TwinBeeRewardSummary{}, players, "")
|
||||
t.Logf("\n%s", out)
|
||||
}
|
||||
Reference in New Issue
Block a user