Skip to content

Add Water and Wilderness info overlays#3615

Open
camclark wants to merge 3 commits intoopenfrontio:mainfrom
camclark:feature/water-wilderness-info-overlay
Open

Add Water and Wilderness info overlays#3615
camclark wants to merge 3 commits intoopenfrontio:mainfrom
camclark:feature/water-wilderness-info-overlay

Conversation

@camclark
Copy link
Copy Markdown
Contributor

@camclark camclark commented Apr 8, 2026

Description:

  • Show a Water label in the PlayerInfoOverlay when hovering over water tiles, with ship info displayed alongside when ships are nearby
CleanShot 2026-04-08 at 22 43 43@2x CleanShot 2026-04-08 at 22 42 54@2x CleanShot 2026-04-08 at 22 43 43@2x
  • Show a Wilderness label when hovering over unowned land tiles
CleanShot 2026-04-08 at 22 41 19@2x
  • Add translation keys for both labels in en.json
  • Add tests covering all overlay states (water, water+ship, player-owned, wilderness, invalid coords, hide reset)

Resolves #3011

Test plan

  • npm test passes (all existing + 6 new tests)
  • Hover over water tiles → "Water" label appears
  • Hover over water near a ship → "Water" label + ship info appears
  • Hover over unowned land → "Wilderness" label appears
  • Hover over player territory → player info appears (no water/wilderness label)
  • Moving cursor between tile types transitions correctly

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 8, 2026

Walkthrough

Added 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

Cohort / File(s) Summary
Translations
resources/lang/en.json
Add player_info_overlay object with water_title and wilderness_title.
Overlay Logic
src/client/graphics/layers/PlayerInfoOverlay.ts
Introduce isWater and isWilderness flags; update maybeShow(x,y) to detect non-land vs land, set flags, always enable overlay on non-land, reset flags in hide(), and conditionally render water/wilderness titles via translateText(...).
Tests
tests/client/graphics/layers/PlayerInfoOverlay.test.ts
New Vitest suite covering invalid coords, water tiles (with/without nearby ships), player-owned tiles, unowned land (wilderness), render translation calls for water/wilderness, and hide() state reset.

Sequence Diagram

sequenceDiagram
    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
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🌊 Hover blue, a quiet title appears,
🌿 Tread the grass, the wilderness draws near,
Flags reset, tests agree, the overlay shows,
Small changes sing where the cursor goes,
A tiny tide that makes the UI clear.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Linked Issues check ❓ Inconclusive The PR addresses the primary objective from #3011 by adding Water and Wilderness info overlays [#3011]. However, it does not implement the secondary objectives of adding collapse/expand icons or replacing Hide/Show buttons. Clarify whether this PR is intended as a partial implementation of #3011, or if collapse/expand icons and Hide/Show button replacements are deferred to a future PR.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main changes: adding Water and Wilderness info overlays to the player info overlay system.
Description check ✅ Passed The description is well-related to the changeset, providing clear context about Water and Wilderness labels, translations, and comprehensive test coverage.
Out of Scope Changes check ✅ Passed All code changes are directly related to implementing Water and Wilderness overlays. No unrelated modifications to localization, component logic, or tests were detected.

✏️ 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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 | 🟡 Minor

Clear playerProfile on hide and guard async profile updates.

playerProfile is not reset in hide(), and async profile() 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

📥 Commits

Reviewing files that changed from the base of the PR and between 38222bf and 27a3ac3.

📒 Files selected for processing (3)
  • resources/lang/en.json
  • src/client/graphics/layers/PlayerInfoOverlay.ts
  • tests/client/graphics/layers/PlayerInfoOverlay.test.ts

coderabbitai[bot]
coderabbitai bot previously approved these changes Apr 8, 2026
@github-project-automation github-project-automation bot moved this from Triage to Final Review in OpenFront Release Management Apr 8, 2026
@camclark camclark requested a review from a team as a code owner April 19, 2026 23:35
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/client/graphics/layers/PlayerInfoOverlay.ts (1)

163-179: Tiny cleanup: the second isLand check is redundant.

Since the previous branch already handles !this.game.isLand(tile), the else if (this.game.isLand(tile)) can simply be else. 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

📥 Commits

Reviewing files that changed from the base of the PR and between af0e555 and 43b8643.

📒 Files selected for processing (2)
  • resources/lang/en.json
  • src/client/graphics/layers/PlayerInfoOverlay.ts
✅ Files skipped from review due to trivial changes (1)
  • resources/lang/en.json

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Final Review

Development

Successfully merging this pull request may close these issues.

Add collapse/expand button and Water info overlay

1 participant