Add Water and Wilderness info overlays#3615
Add Water and Wilderness info overlays#3615camclark wants to merge 3 commits intoopenfrontio:mainfrom
Conversation
WalkthroughAdded a water info overlay to PlayerInfoOverlay with two new localization keys; new boolean flags track water/wilderness state, maybeShow detects terrain and sets flags, hide resets them, and tests validate behaviors and render translations. Changes
Sequence DiagramsequenceDiagram
participant User
participant PlayerInfoOverlay
participant Game as TileService
participant Translator
participant Renderer
User->>PlayerInfoOverlay: hover(x,y)
activate PlayerInfoOverlay
PlayerInfoOverlay->>Game: query tile at (x,y)
activate Game
alt tile is water
Game-->>PlayerInfoOverlay: tile = water
PlayerInfoOverlay->>PlayerInfoOverlay: set isWater = true
PlayerInfoOverlay->>Game: find nearby ships
Game-->>PlayerInfoOverlay: ships or none
else tile is land
Game-->>PlayerInfoOverlay: tile = land (owned/unowned)
PlayerInfoOverlay->>PlayerInfoOverlay: set isWilderness or set player/unit
end
deactivate Game
PlayerInfoOverlay->>Translator: translateText(water_title or wilderness_title)
activate Translator
Translator-->>PlayerInfoOverlay: localized title
deactivate Translator
PlayerInfoOverlay->>Renderer: render overlay with conditional title and info
activate Renderer
Renderer-->>User: display overlay
deactivate Renderer
deactivate PlayerInfoOverlay
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/client/graphics/layers/PlayerInfoOverlay.ts (1)
137-143:⚠️ Potential issue | 🟡 MinorClear
playerProfileon hide and guard async profile updates.
playerProfileis not reset inhide(), and asyncprofile()responses can land after cursor moved, leaving stale relation data in subsequent renders.💡 Suggested fix
export class PlayerInfoOverlay extends LitElement implements Layer { + private profileRequestId = 0; + public hide() { + this.profileRequestId++; this.setVisible(false); this.unit = null; this.player = null; + this.playerProfile = null; this.isWater = false; this.isWilderness = false; } public maybeShow(x: number, y: number) { this.hide(); @@ if (owner && owner.isPlayer()) { this.player = owner as PlayerView; - this.player.profile().then((p) => { - this.playerProfile = p; - }); + const requestId = this.profileRequestId; + this.player.profile().then((p) => { + if (this.profileRequestId === requestId) { + this.playerProfile = p; + } + }); this.setVisible(true);Also applies to: 159-161
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/client/graphics/layers/PlayerInfoOverlay.ts` around lines 137 - 143, The hide() method currently resets unit, player, isWater and isWilderness but does not clear playerProfile, so add clearing of this.playerProfile inside hide() (alongside setVisible(false), this.unit = null, this.player = null, etc.). Also guard asynchronous profile updates in the profile() handler (or wherever the async fetch resolves) by validating that the response still pertains to the current cursor target before assigning this.playerProfile (e.g., compare the response's playerId/unitId to this.player/this.unit or check this.visible), so late responses cannot overwrite state for a different hovered unit. Ensure both the hide() change and the guard in the async resolution are implemented.
🧹 Nitpick comments (1)
tests/client/graphics/layers/PlayerInfoOverlay.test.ts (1)
85-191: Nice state coverage; add one render-level assertion for title keys.Current tests prove state transitions, but they don’t directly verify that render uses
player_info_overlay.water_title/player_info_overlay.wilderness_title.✅ Minimal test extension
+import { translateText } from "../../../../src/client/Utils"; @@ describe("maybeShow", () => { @@ + test("render uses water title translation key", () => { + const { overlay } = makeOverlay(); + overlay.maybeShow(100, 100); + overlay.render(); + expect(translateText).toHaveBeenCalledWith( + "player_info_overlay.water_title", + ); + }); + + test("render uses wilderness title translation key", () => { + const { overlay } = makeOverlay({ + isLand: vi.fn(() => true), + }); + overlay.maybeShow(100, 100); + overlay.render(); + expect(translateText).toHaveBeenCalledWith( + "player_info_overlay.wilderness_title", + ); + });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/client/graphics/layers/PlayerInfoOverlay.test.ts` around lines 85 - 191, Add a small render-level assertion after existing state checks to ensure the component actually uses the translation keys: after calling overlay.maybeShow(...) (from makeOverlay) assert the rendered output/text/DOM contains the literal keys "player_info_overlay.water_title" when (overlay as any).isWater is true and "player_info_overlay.wilderness_title" when (overlay as any).isWilderness is true; keep these as short additional expectations in the existing tests that verify water and wilderness behavior so you validate rendering as well as state.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@src/client/graphics/layers/PlayerInfoOverlay.ts`:
- Around line 137-143: The hide() method currently resets unit, player, isWater
and isWilderness but does not clear playerProfile, so add clearing of
this.playerProfile inside hide() (alongside setVisible(false), this.unit = null,
this.player = null, etc.). Also guard asynchronous profile updates in the
profile() handler (or wherever the async fetch resolves) by validating that the
response still pertains to the current cursor target before assigning
this.playerProfile (e.g., compare the response's playerId/unitId to
this.player/this.unit or check this.visible), so late responses cannot overwrite
state for a different hovered unit. Ensure both the hide() change and the guard
in the async resolution are implemented.
---
Nitpick comments:
In `@tests/client/graphics/layers/PlayerInfoOverlay.test.ts`:
- Around line 85-191: Add a small render-level assertion after existing state
checks to ensure the component actually uses the translation keys: after calling
overlay.maybeShow(...) (from makeOverlay) assert the rendered output/text/DOM
contains the literal keys "player_info_overlay.water_title" when (overlay as
any).isWater is true and "player_info_overlay.wilderness_title" when (overlay as
any).isWilderness is true; keep these as short additional expectations in the
existing tests that verify water and wilderness behavior so you validate
rendering as well as state.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 1b40c707-5dab-48df-9578-feed697cf657
📒 Files selected for processing (3)
resources/lang/en.jsonsrc/client/graphics/layers/PlayerInfoOverlay.tstests/client/graphics/layers/PlayerInfoOverlay.test.ts
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/client/graphics/layers/PlayerInfoOverlay.ts (1)
163-179: Tiny cleanup: the secondisLandcheck is redundant.Since the previous branch already handles
!this.game.isLand(tile), theelse if (this.game.isLand(tile))can simply beelse. Keeps the branching easier to follow.♻️ Proposed simplification
- } else if (!this.game.isLand(tile)) { + } else if (!this.game.isLand(tile)) { this.isWater = true; - const units = this.game .units(UnitType.Warship, UnitType.TradeShip, UnitType.TransportShip) .filter((u) => euclideanDistWorld(worldCoord, u.tile(), this.game) < 50) .sort(distSortUnitWorld(worldCoord, this.game)); if (units.length > 0) { this.unit = units[0]; } - this.setVisible(true); - } else if (this.game.isLand(tile)) { + } else { this.isWilderness = true; this.setVisible(true); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/client/graphics/layers/PlayerInfoOverlay.ts` around lines 163 - 179, The second branch explicitly re-checks this.game.isLand(tile) after an earlier else if (!this.game.isLand(tile)) — replace the redundant "else if (this.game.isLand(tile))" with a plain "else" to simplify branching while preserving behavior: keep the assignments this.isWilderness = true and this.setVisible(true) in that else, and leave the preceding water-handling branch (setting this.isWater, computing units via euclideanDistWorld and distSortUnitWorld, and assigning this.unit) unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@src/client/graphics/layers/PlayerInfoOverlay.ts`:
- Around line 163-179: The second branch explicitly re-checks
this.game.isLand(tile) after an earlier else if (!this.game.isLand(tile)) —
replace the redundant "else if (this.game.isLand(tile))" with a plain "else" to
simplify branching while preserving behavior: keep the assignments
this.isWilderness = true and this.setVisible(true) in that else, and leave the
preceding water-handling branch (setting this.isWater, computing units via
euclideanDistWorld and distSortUnitWorld, and assigning this.unit) unchanged.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: a45a204b-ada8-40eb-9623-6a629c45dfca
📒 Files selected for processing (2)
resources/lang/en.jsonsrc/client/graphics/layers/PlayerInfoOverlay.ts
✅ Files skipped from review due to trivial changes (1)
- resources/lang/en.json
Description:
Resolves #3011
Test plan
npm testpasses (all existing + 6 new tests)