feat: BGE-296 detailed battle reports with resource pillaging#99
feat: BGE-296 detailed battle reports with resource pillaging#99discostu105 merged 2 commits intomasterfrom
Conversation
- Extend BtlResult with TotalAttackerStrengthBefore/TotalDefenderStrengthBefore - Add StealResources() in UnitRepositoryWrite: attacker steals 10% of all non-land resources (capped at 5000 each) on win - Extend BattleResultViewModel with AttackerName, DefenderName, Outcome, UnitsLostByAttacker/Defender, ResourcesPillaged, LandTransferred, WorkersCaptured - Populate full BattleResultViewModel in BattleController.Attack() - Update BattleReportGenerator messages to include pillaged resources and draw outcome - Update EnemyBase.razor to show rich battle breakdown: outcome badge, spoils of war, collapsible unit losses table, kill ratio - Add BattleResourcePillageTest covering pillage on win, no pillage on loss, and strength fields populated Co-Authored-By: Paperclip <noreply@paperclip.ing>
discostu105
left a comment
There was a problem hiding this comment.
PR Review: feat: BGE-296 detailed battle reports with resource pillaging
Verdict: REQUEST_CHANGES
Summary
The core battle mechanics (resource pillaging, unit loss display, strength-before fields) are implemented correctly and all tests pass. However, there are two blocking gaps: a stale TODO comment that actively misleads readers, a missing cap-enforcement test, and an unmet acceptance criterion around notification center depth.
Issues
-
[blocking]
src/BrowserGameEngine.StatefulGameServer/Repositories/Units/UnitRepositoryWrite.cs:297— StaleTODO: apply resourses stolen/lostcomment insideApplyBatteResult.StealResourcesnow fulfills this — leaving the TODO in place tells every future reader that pillage is still unimplemented. Remove it. -
[blocking]
src/BrowserGameEngine.StatefulGameServer.Test/BattleResourcePillageTest.cs— No test for the 5000-per-resource cap. The PR description explicitly calls it out, but all three tests use defender resources ≤ 2000. Add a test with the defender at e.g. 100 000 minerals and assert stolen amount == 5000 (not 10 000). -
[blocking]
src/BrowserGameEngine.StatefulGameServer/BattleReportGenerator.cs:32— Acceptance criterion #3 says "Detailed report stored and viewable in notification center." The bell-icon notification center only gets"Your base was attacked by X!". The full detail (pillaged resources, unit losses) goes to the Messages inbox viamessageRepositoryWrite, not into the push notification. The attacker receives no push notification at all. Either push the detail to the notification center, or clarify the acceptance criterion. -
[nit]
src/BrowserGameEngine.StatefulGameServer.Test/BattleResourcePillageTest.cs:73—TotalDefenderStrengthBefore >= 0allows zero. Since the defender always has units, assert> 0to actually validate the field is populated. -
[nit]
src/BrowserGameEngine.GameModel/BattleResult.cs:23— Missing newline at end of file (trivial fix while the file is open).
Positive Notes
- Thread safety correct:
StealResources→resourceRepositoryWrite.AddResourcesholds its ownlock(_lock)per call, consistent withApplyLandTransfer. [Authorize]at class level +currentUserContext.IsValidchecked before every action — no security issues.BattleResultViewModelbreaking change (removing oldPlayerLostUnits/EnemyLostUnits) is safe — confirmed not referenced anywhere else in the codebase.- Outcome logic (
attackerWon/draw/DefenderWon) is consistent acrossUnitRepositoryWrite,BattleController, andBattleReportGenerator. - Spoils-of-war UI correctly gates display behind non-empty pillage/transfer data.
Build/Test Result
- Build: PASS
- Tests: PASS (167 passed, 0 failed)
|
Architectural review: Approved. What I checked:
Non-blocking notes for the backlog:
Neither blocks merge. Ship it. |
discostu105
left a comment
There was a problem hiding this comment.
PR Review: feat: BGE-296 detailed battle reports with resource pillaging
Verdict: APPROVE ✅ (cannot self-approve — posting as comment)
Summary
Extends battle results with per-unit-type loss breakdowns, 10%-pillage resource stealing on win (capped at 5000 each), outcome badge, and a collapsible unit losses table in the Blazor UI. Notification body enriched with draw outcome, workers captured, and pillaged resources.
Issues
-
[nit]
BattleController.cs:125–128—attackerWon/draw/outcomelogic is duplicated fromBattleReportGenerator. Both are correct, but any future logic change needs to be made in two places. Consider extracting a static helper onBtlResultor a shared utility. -
[nit]
BattleResourcePillageTest.cs:8—private static PlayerId Player2 => PlayerIdFactory.Create("player1")— naming is slightly confusing (field calledPlayer2, ID is"player1"). Not a bug (consistent withTestWorldStateFactory's 0-indexed players), but a comment would help future readers.
Positive Notes
[Authorize]on the controller class pluscurrentUserContext.IsValidcheck inAttack— authorization is correct.StealResourcesfollows the exact same pattern as the pre-existingApplyLandTransfer(callsresourceRepositoryWrite.AddResourcesin the same unlocked code path — not a new threading concern introduced by this PR).BtlResult.ResourcesStolenis initialized to an empty list inBattleBehaviorScoOriginal.CalculateResult(), soStealResources'.Add(...)is safe.gameDef.GetUnitDef(uc.UnitDefId)?.Name ?? uc.UnitDefId.Id— graceful fallback for unknown unit defs.- ViewModel collections initialized with
= new()— no null-ref risk in the Razor template. - Three well-targeted tests: win+pillage, loss+no-pillage, strength fields populated. All use
TestGamedirectly, no controller mocks. - Blazor UI uses Bootstrap classes consistently and the
<details>collapse is a clean UX pattern.
Build/Test Result
- Build: PASS (0 errors, 70 pre-existing warnings)
- Tests: PASS (167 passed, 0 failed)
- Remove stale `// TODO: apply resourses stolen/lost` comment from ApplyBatteResult — StealResources already fulfills this - Add pillage cap test: defender with 100k minerals yields stolen==5000 (not 10k), confirming the 5000-per-resource cap is enforced - Fix TotalDefenderStrengthBefore assertion: `>= 0` → `> 0` - Push rich battle notification to both attacker and defender including outcome label and pillaged resources summary Co-Authored-By: Paperclip <noreply@paperclip.ing>
Review blockers addressed
All 168 tests pass. |
Architect Review — BGE-296 Detailed Battle Reports with Resource PillagingVerdict: Approved ✅ AnalysisLayer compliance: All changes respect the dependency graph. Thread safety: Pillage logic: 10% capped at 5000 per resource, land excluded — straightforward and correctly bounded. Outcome determination duplicated between
Tests: 4 scenarios cover win+pillage, loss+no-pillage, strength fields populated, and cap enforcement. Solid. CI passes (167 tests). Minor note: |
discostu105
left a comment
There was a problem hiding this comment.
PR Review: BGE-296 Detailed Battle Reports with Resource Pillaging
Verdict: APPROVE
Summary
Correctly implements detailed battle reports (per-unit losses, outcome label, strength-before fields) and resource pillaging (10% of non-land resources, capped at 5000 each, attacker-win-only). All logic flows correctly through the stack and all 168 tests pass.
Issues (nits only)
-
[nit]
BattleResourcePillageTest.cs:10— Static field namedPlayer2has valuePlayerIdFactory.Create("player1")— confusing naming. ConsiderSecondPlayerIdwith a clarifying comment. -
[nit]
BattleResourcePillageTest.cs:41— AssertionAssert.Equal(defenderResourcesBefore * 0.10m, stolen["res1"])works because initial value is exactly 1000 (floor is a no-op). Should beAssert.Equal(Math.Floor(defenderResourcesBefore * 0.10m), stolen["res1"])to match the spec. -
[nit]
BattleResultViewModel.cs:13—Outcomeis stringly-typed ("AttackerWon","DefenderWon","Draw"). ABattleOutcomeenum would prevent string drift. -
[nit] No test for the draw outcome (both sides wiped). Low priority but worth adding.
Positive Notes
StealResourcescleanly isolated as a private method, consistent withApplyLandTransferpattern.- Resource writes correctly delegated to
ResourceRepositoryWrite.AddResources(which has its ownlock). BattleReportGeneratornow sends attacker notifications including pillage info — meaningful UX improvement.[Authorize]inherited at controller class level;currentUserContext.IsValidchecked correctly.- Pillage cap test correctly sets up >50000 resources so 10% exceeds the 5000 cap.
Build/Test Result
- Build: PASS
- Tests: PASS (168/168 — 4 new battle pillage tests all pass)
This PR is ready to merge.
Summary
BattleResultViewModelwith outcome, names, unit losses, resources pillaged, land transferred, workers captured, and strength-before valuesEnemyBase.razorwith rich post-battle UI: outcome badge, spoils of war section, collapsible unit losses table, and kill ratioBattleResourcePillageTestcovering pillage-on-win, no-pillage-on-loss, and strength fieldsTest plan
dotnet buildpassesdotnet testpasses (167 tests)Closes BGE-296