Skip to content

attack overlay#3996

Draft
evanpelle wants to merge 1 commit into
mainfrom
attack-overlay
Draft

attack overlay#3996
evanpelle wants to merge 1 commit into
mainfrom
attack-overlay

Conversation

@evanpelle
Copy link
Copy Markdown
Collaborator

If this PR fixes an issue, link it below. If not, delete these two lines.
Resolves #(issue number)

Description:

Describe the PR.

Please complete the following:

  • I have added screenshots for all UI updates
  • I process any text displayed to the user through translateText() and I've added it to the en.json file
  • I have added relevant tests to the test directory
  • I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced

Please put your Discord username so you can be contacted if a bug or regression is found:

DISCORD_USERNAME

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 23, 2026

Review Change Stack

Walkthrough

This PR migrates attacking troop cluster labels from DOM-based rendering to WebGL. A new AttackingTroopsController fetches clustered attack positions, interpolates smooth label movement via slot animation state, and feeds AttackTroopLabel objects to WorldTextPass for GPU rendering. Supporting infrastructure in GameView, Renderer, and WorldTextPass pipe the data through the graphics pipeline.

Changes

Attack Troop Labels Migration to WebGL

Layer / File(s) Summary
Slot-based position animation model
src/client/controllers/AttackingTroopsController.ts
Introduces Slot structure to track interpolated label positions (current, source, destination, start time), defines per-attack AttackEntry state, and implements alignClusterOrder to minimize label movement distance when cluster order changes.
AttackingTroopsController core implementation
src/client/controllers/AttackingTroopsController.ts
Main controller subscribes to AlternateViewEvent, maintains per-attack state, requests clustered front-line positions once per tick from myPlayer.attackClusteredPositions(), reconciles positions with prior slots for smooth interpolation, and drives per-frame label updates via pushLabels to WebGL.
WebGL rendering infrastructure for attack labels
src/client/render/gl/GameView.ts, src/client/render/gl/Renderer.ts, src/client/render/gl/passes/WorldTextPass.ts
Extends GameView and Renderer with setAttackTroopLabels() methods that forward to WorldTextPass; WorldTextPass adds AttackTroopLabel interface and storage, accepts zoom in tick() for screen-relative scaling, and generates GPU instances with zoom-compensated label size.
GameRenderer layer registration
src/client/hud/GameRenderer.ts
Swaps attacking-troops layer from AttackingTroopsOverlay to AttackingTroopsController with shared game, event bus, settings, and view dependencies.
Test migration to new Slot model
tests/client/graphics/layers/AttackingTroopsOverlay.test.ts
Imports Slot and alignClusterOrder from new controller, adds slot() helper for test construction, removes computeLabelScale tests, and revalidates alignClusterOrder against Slot-based arrays.

Sequence Diagram(s)

sequenceDiagram
  participant RAF as RequestAnimationFrame
  participant Controller as AttackingTroopsController
  participant Worker as myPlayer
  participant WebGL as WebGLGameView
  participant Pass as WorldTextPass
  
  Controller->>Controller: tick() every 200ms
  Controller->>Worker: attackClusteredPositions()
  Worker-->>Controller: ClusteredCell[] response
  Controller->>Controller: reconcileSlots() interpolate
  Note over Controller: Smooth animation via Slot
  
  RAF->>Controller: pushLabels() every frame
  Controller->>WebGL: setAttackTroopLabels(AttackTroopLabel[])
  WebGL->>Pass: setAttackTroopLabels()
  Note over Pass: Generate GPU instances<br/>with zoom-scaled size
  Pass-->>RAF: Render to screen
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly Related PRs

  • openfrontio/OpenFrontIO#3989: Earlier WorldTextPass and Renderer refactor that introduced ghost-cost labels; both PRs modify the same render-pass infrastructure and label pipeline.

Suggested Labels

UI/UX, Feature

Poem

🏷️ Troops once danced in DOM so light,
Now they render, GPU bright—
Smooth slots glide across the screen,
Cleanest cluster flow I've seen.
WebGL whispers: welcome here, ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (2 warnings, 1 inconclusive)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is only a placeholder template with uncompleted checklist items and no actual implementation details, objectives, or description of the changes made. Replace the template with a concrete description explaining the migration from DOM-based overlay to WebGL controller, including rationale and any breaking changes.
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.
Title check ❓ Inconclusive The title 'attack overlay' is vague and generic, using non-descriptive terms that don't convey the actual scope of changes, which involve replacing a DOM-based overlay with a WebGL-based controller. Use a more descriptive title like 'Replace AttackingTroopsOverlay with WebGL-based AttackingTroopsController' to clearly communicate the main architectural change.
✅ Passed checks (2 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/client/render/gl/passes/WorldTextPass.ts`:
- Around line 47-54: Move the hardcoded attack-label tuning values
(ATTACK_LABEL_SCREEN_SCALE, ATTACK_LABEL_OUTLINE_WIDTH and the other constants
used in WorldTextPass methods) into RenderSettings and read them from the
existing RenderSettings instance instead of using literals in WorldTextPass; add
corresponding keys and sane defaults to render-settings.json and the
RenderSettings type/interface, then replace uses of ATTACK_LABEL_SCREEN_SCALE,
ATTACK_LABEL_OUTLINE_WIDTH and the other pass constants inside the WorldTextPass
class (and any methods referencing them) with lookups like
renderSettings.attackLabelScreenScale / attackLabelOutlineWidth so the pass uses
configuration-driven values.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a4d82013-e76d-4597-a84d-383c95f34691

📥 Commits

Reviewing files that changed from the base of the PR and between 14f2e36 and 43bd112.

⛔ Files ignored due to path filters (1)
  • src/client/render/gl/shaders/world-text/world-text.frag.glsl is excluded by !**/*.glsl
📒 Files selected for processing (7)
  • src/client/controllers/AttackingTroopsController.ts
  • src/client/hud/GameRenderer.ts
  • src/client/hud/layers/AttackingTroopsOverlay.ts
  • src/client/render/gl/GameView.ts
  • src/client/render/gl/Renderer.ts
  • src/client/render/gl/passes/WorldTextPass.ts
  • tests/client/graphics/layers/AttackingTroopsOverlay.test.ts
💤 Files with no reviewable changes (1)
  • src/client/hud/layers/AttackingTroopsOverlay.ts

Comment on lines +47 to 54
/**
* Screen-relative em scale for attack troop labels. Pre-divided by the current
* zoom each frame so the on-screen label size stays constant regardless of
* how far the camera is zoomed.
*/
const ATTACK_LABEL_SCREEN_SCALE = 34.0;
const ATTACK_LABEL_OUTLINE_WIDTH = 1.2;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Move attack-label tuning values into RenderSettings.

Line 52, Line 53, Line 445, and Line 469 hardcode pass tuning values inside the pass. These should come from render-settings.json via RenderSettings.

♻️ Proposed refactor
-const ATTACK_LABEL_SCREEN_SCALE = 34.0;
-const ATTACK_LABEL_OUTLINE_WIDTH = 1.2;
-    const attackScale = ATTACK_LABEL_SCREEN_SCALE / Math.max(zoom, 0.0001);
+    const attackScale =
+      this.settings.worldText.attackLabelScreenScale / Math.max(zoom, 0.0001);
...
-        this.instanceData[off + 9] = ATTACK_LABEL_OUTLINE_WIDTH;
+        this.instanceData[off + 9] =
+          this.settings.worldText.attackLabelOutlineWidth;

As per coding guidelines, "All per-pass tuning constants must be defined in render-settings.json and accessed through RenderSettings, not hardcoded in pass classes."

Also applies to: 445-469

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/client/render/gl/passes/WorldTextPass.ts` around lines 47 - 54, Move the
hardcoded attack-label tuning values (ATTACK_LABEL_SCREEN_SCALE,
ATTACK_LABEL_OUTLINE_WIDTH and the other constants used in WorldTextPass
methods) into RenderSettings and read them from the existing RenderSettings
instance instead of using literals in WorldTextPass; add corresponding keys and
sane defaults to render-settings.json and the RenderSettings type/interface,
then replace uses of ATTACK_LABEL_SCREEN_SCALE, ATTACK_LABEL_OUTLINE_WIDTH and
the other pass constants inside the WorldTextPass class (and any methods
referencing them) with lookups like renderSettings.attackLabelScreenScale /
attackLabelOutlineWidth so the pass uses configuration-driven values.

@github-project-automation github-project-automation Bot moved this from Triage to Development in OpenFront Release Management May 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Development

Development

Successfully merging this pull request may close these issues.

1 participant