Class: Lich::Gemstone::Combat::AsyncProcessor

Inherits:
Object
  • Object
show all
Defined in:
documented/gemstone/combat/async_processor.rb

Overview

Single-threaded async combat processor that handles combat chunks in arrival order.

Chunks are enqueued via #process_async from the game stream thread (O(1), non-blocking) and consumed sequentially by a dedicated worker thread. This guarantees that status updates, UCS changes, and damage events are processed in order, and ensures creature instances are only mutated from one thread.

The worker thread is automatically respawned if it dies (e.g., when the parent script exits), since it can be spawned from a script thread but must survive the script's lifetime to process events from the downstream hook.

Instance Method Summary collapse

Constructor Details

#initialize(_max_threads = 1) ⇒ AsyncProcessor

max_threads retained for call-site compatibility; processing is intentionally single-threaded to preserve event ordering.



37
38
39
40
41
42
43
# File 'documented/gemstone/combat/async_processor.rb', line 37

def initialize(_max_threads = 1)
  @queue = Queue.new
  @processing = false
  @chunks_processed = 0
  @spawn_mutex = Mutex.new
  ensure_worker
end

Instance Method Details

#process_async(chunk) ⇒ Object

Enqueue a chunk; O(1), never blocks the game stream.

Also revives the worker if it died: a worker spawned from a script context (enable! via autostart/;e) belongs to that script's thread group and is killed when the script exits. process_async runs on the downstream-hook (game) thread, so a worker respawned here survives script death.



52
53
54
55
56
57
# File 'documented/gemstone/combat/async_processor.rb', line 52

def process_async(chunk)
  return if chunk.empty?
  @queue.push(chunk)
  ensure_worker
  nil
end

#shutdown ⇒ Object

Drain remaining work and stop the worker.



60
61
62
63
64
65
66
67
68
69
70
# File 'documented/gemstone/combat/async_processor.rb', line 60

def shutdown
  respond "[Combat] Waiting for #{@queue.size} queued chunks..." if Tracker.debug?(:verbose)
  @queue.push(:shutdown)
  @worker.join

  # Force GC after shutdown to help with memory fragmentation.
  # Compaction is routed through Lich::Util::GtkCompaction, which
  # keeps it safe to use alongside gtk3.
  GC.start
  Lich::Util::GtkCompaction.safe_compact!
end

#stats ⇒ Hash

Returns the current state of the async processor.

Examples:

processor.stats #=> { active: 1, queued: 0, total: 42, worker_alive: true }

Returns:

  • (Hash) —

    a hash with keys:

    • :active [Integer] 1 if currently processing a chunk, 0 otherwise
    • :queued [Integer] number of chunks waiting in the queue
    • :total [Integer] total chunks processed since initialization
    • :worker_alive [Boolean] true if the worker thread is running


81
82
83
84
85
86
87
88
# File 'documented/gemstone/combat/async_processor.rb', line 81

def stats
  {
    active: @processing ? 1 : 0,
    queued: @queue.size,
    total: @chunks_processed,
    worker_alive: !@worker.nil? && @worker.alive?
  }
end