feat: implement thread-safe render queue decoupling events from rendering #327

Merged
freemo merged 1 commit from feature/m2-render-queue into master 2026-03-16 20:49:57 +00:00
Owner

Summary

Implements issue #301: Thread-safe RenderQueue for decoupling event production (game thread) from event consumption (render thread).

Changes

  • New RenderQueue class (lib/aethyr/core/render/render_queue.rb)
    • Thread-safe enqueue/drain operations using Mutex synchronization
    • Configurable max queue size (default 1000) with drop-oldest overflow strategy
    • Statistics tracking: total enqueued, drained, and overflowed counts
    • Monitoring methods: size, empty?, stats
    • Reset functionality for clearing queue and resetting stats

Usage Example

# Create queue with custom max size
queue = RenderQueue.new(max_size: 500)

# Game thread (via EventProjection)
queue.enqueue(RenderOp.text_append(window: :main, text: "A goblin enters."))
queue.enqueue(RenderOp.bar_update(window: :status, bar: :hp, value: 85, max: 100))

# Render thread (each frame at 20 FPS)
ops = queue.drain
ops.each { |op| pipeline.process(op) }

Testing

  • Unit Tests: 25 scenarios, 99 steps covering:

    • Single-threaded enqueue/drain, FIFO ordering
    • Overflow with drop-oldest, concurrent multi-threaded access
    • Drain atomicity, burst handling, queue monitoring
  • Integration Tests: 3 scenarios covering:

    • Multiple producers + single consumer
    • High burst + continuous drain recovery
    • Mixed RenderOp types end-to-end

Additional Fixes

Fixed pre-existing ambiguous step definitions in guid_steps.rb and ui_event_subscriber_steps.rb by making step patterns unique.

Closes #301
Depends on #299 (UIEventSubscriber)

## Summary Implements issue #301: Thread-safe RenderQueue for decoupling event production (game thread) from event consumption (render thread). ## Changes - **New `RenderQueue` class** (`lib/aethyr/core/render/render_queue.rb`) - Thread-safe enqueue/drain operations using Mutex synchronization - Configurable max queue size (default 1000) with drop-oldest overflow strategy - Statistics tracking: total enqueued, drained, and overflowed counts - Monitoring methods: `size`, `empty?`, `stats` - Reset functionality for clearing queue and resetting stats ## Usage Example ```ruby # Create queue with custom max size queue = RenderQueue.new(max_size: 500) # Game thread (via EventProjection) queue.enqueue(RenderOp.text_append(window: :main, text: "A goblin enters.")) queue.enqueue(RenderOp.bar_update(window: :status, bar: :hp, value: 85, max: 100)) # Render thread (each frame at 20 FPS) ops = queue.drain ops.each { |op| pipeline.process(op) } ``` ## Testing - **Unit Tests**: 25 scenarios, 99 steps covering: - Single-threaded enqueue/drain, FIFO ordering - Overflow with drop-oldest, concurrent multi-threaded access - Drain atomicity, burst handling, queue monitoring - **Integration Tests**: 3 scenarios covering: - Multiple producers + single consumer - High burst + continuous drain recovery - Mixed RenderOp types end-to-end ## Additional Fixes Fixed pre-existing ambiguous step definitions in `guid_steps.rb` and `ui_event_subscriber_steps.rb` by making step patterns unique. ## Related Issues Closes #301 Depends on #299 (UIEventSubscriber)
Implements the RenderOp value object class for the UI render pipeline as
specified in issue #304. RenderOps are immutable value objects that describe
rendering instructions without specifying how they should be rendered.

Key features:
- Immutable value objects (frozen after creation) with type, window, and data
- Seven core RenderOp types: text_append, map_refresh, bar_update,
  prompt_update, window_clear, overlay_show, overlay_hide
- Factory methods for convenient construction: RenderOp.text_append(),
  RenderOp.bar_update(), etc.
- Data validation per type (required fields are enforced)
- Equality comparison support (== and hash for use as hash keys)
- to_h serialization for logging and debugging
- Comprehensive YARD documentation

Testing:
- 36 Cucumber scenarios covering all factory methods, immutability,
  validation, equality, and type constants
- 3 integration scenarios for realistic usage patterns

ISSUES CLOSED: #304
freemo force-pushed feature/m2-render-queue from e1a77e2ab3 to f77003d1ee 2026-03-16 16:58:30 +00:00 Compare
freemo force-pushed feature/m2-render-queue from f77003d1ee to 86e3eaa567 2026-03-16 17:33:11 +00:00 Compare
freemo force-pushed feature/m2-render-queue from 86e3eaa567 to 347425a8b7 2026-03-16 20:49:39 +00:00 Compare
freemo merged commit 347425a8b7 into master 2026-03-16 20:49:57 +00:00
freemo deleted branch feature/m2-render-queue 2026-03-16 20:49:57 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: aethyr/Aethyr#327
No description provided.