From 5120219ae2344c4247e0badd0f3663347abfa338 Mon Sep 17 00:00:00 2001 From: CAtlas0784 Date: Sun, 18 Oct 2026 22:40:03 +0700 Subject: [PATCH] fix: recover battle damage from statistics --- internal/common/battle_report.go | 41 +++++++++++++++++++++++-- internal/common/battle_report_test.go | 44 +++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 3 deletions(-) diff --git a/internal/common/battle_report.go b/internal/common/battle_report.go index c325911..2d11724 100644 --- a/internal/common/battle_report.go +++ b/internal/common/battle_report.go @@ -90,15 +90,46 @@ func BattleReportFromStatistics(stt *goproto.BattleStatistics, battleID uint32, Monsters: make([]*BattleMonsterReport, 0, len(stt.MonsterList)), } + // The 4.6.53 schema exposes OKFALMGFHMA entries with avatar_id and damage, + // but the enclosing message and several fields remain obfuscated. Treating + // these as per-avatar damage records is an inference that still needs a raw + // Client capture; use them only when the clear aggregate is zero. + damageByAvatar := make(map[uint32]float64) + var damageEventTotal float64 + for _, event := range stt.OKFALMGFHMA { + if event == nil || event.AvatarId == 0 || event.Damage <= 0 { + continue + } + damageByAvatar[event.AvatarId] += event.Damage + damageEventTotal += event.Damage + } + var teamDmg, teamHeal, teamShield float64 for _, a := range stt.BattleAvatarList { if a == nil { continue } - teamDmg += a.TotalDamage + damage := a.TotalDamage + if damage == 0 { + damage = damageByAvatar[a.Id] + } + teamDmg += damage teamHeal += a.TotalHeal teamShield += a.TotalShield } + // If neither avatar aggregate source contains damage, enemy damage-taken + // stats still provide a reliable team total. They cannot identify which + // avatar dealt each hit, so per-avatar shares remain unavailable in that case. + if teamDmg == 0 && damageEventTotal > 0 { + teamDmg = damageEventTotal + } + if teamDmg == 0 { + for _, m := range stt.MonsterList { + if m != nil && m.TotalDamageTaken > 0 { + teamDmg += m.TotalDamageTaken + } + } + } report.TeamTotalDamage = teamDmg report.TeamTotalHeal = teamHeal report.TeamTotalShield = teamShield @@ -107,15 +138,19 @@ func BattleReportFromStatistics(stt *goproto.BattleStatistics, battleID uint32, if a == nil { continue } + damage := a.TotalDamage + if damage == 0 { + damage = damageByAvatar[a.Id] + } var dmgPercent float64 if teamDmg > 0 { - dmgPercent = (a.TotalDamage / teamDmg) * 100.0 + dmgPercent = (damage / teamDmg) * 100.0 } ar := &BattleAvatarReport{ AvatarID: a.Id, AvatarLevel: a.AvatarLevel, AvatarRank: a.AvatarRank, - TotalDamage: a.TotalDamage, + TotalDamage: damage, DamagePercent: dmgPercent, TotalDamageTaken: a.TotalDamageTaken, TotalHeal: a.TotalHeal, diff --git a/internal/common/battle_report_test.go b/internal/common/battle_report_test.go index ac407a8..8692662 100644 --- a/internal/common/battle_report_test.go +++ b/internal/common/battle_report_test.go @@ -101,3 +101,47 @@ func TestBattleReportSerialization(t *testing.T) { t.Fatal("expected error after clearing report, got nil") } } + +func TestBattleReportUsesAvatarDamageEventsWhenAvatarTotalsAreZero(t *testing.T) { + stt := &goproto.BattleStatistics{ + BattleAvatarList: []*goproto.AvatarBattleInfo{ + {Id: 1503}, + {Id: 1511}, + }, + OKFALMGFHMA: []*goproto.HDKEPPDIDIH{ + {AvatarId: 1503, Damage: 720}, + {AvatarId: 1503, Damage: 180}, + {AvatarId: 1511, Damage: 100}, + }, + MonsterList: []*goproto.MonsterBattleInfo{{TotalDamageTaken: 1000}}, + } + + report := BattleReportFromStatistics(stt, 1, 1052106, "WIN") + if report.TeamTotalDamage != 1000 { + t.Fatalf("expected event-derived team damage 1000, got %f", report.TeamTotalDamage) + } + if report.Avatars[0].TotalDamage != 900 || report.Avatars[0].DamagePercent != 90 { + t.Fatalf("unexpected avatar 1503 report: %+v", report.Avatars[0]) + } + if report.Avatars[1].TotalDamage != 100 || report.Avatars[1].DamagePercent != 10 { + t.Fatalf("unexpected avatar 1511 report: %+v", report.Avatars[1]) + } +} + +func TestBattleReportFallsBackToMonsterDamageTakenForTeamTotal(t *testing.T) { + stt := &goproto.BattleStatistics{ + BattleAvatarList: []*goproto.AvatarBattleInfo{{Id: 1503}}, + MonsterList: []*goproto.MonsterBattleInfo{ + {TotalDamageTaken: 250}, + {TotalDamageTaken: 750}, + }, + } + + report := BattleReportFromStatistics(stt, 1, 1052106, "WIN") + if report.TeamTotalDamage != 1000 { + t.Fatalf("expected monster-derived team damage 1000, got %f", report.TeamTotalDamage) + } + if report.Avatars[0].DamagePercent != 0 { + t.Fatalf("cannot infer avatar share from monster totals, got %f", report.Avatars[0].DamagePercent) + } +}