diff options
Diffstat (limited to 'internal/engine/tick.go')
| -rw-r--r-- | internal/engine/tick.go | 21 |
1 files changed, 20 insertions, 1 deletions
diff --git a/internal/engine/tick.go b/internal/engine/tick.go index ff1bace..251373c 100644 --- a/internal/engine/tick.go +++ b/internal/engine/tick.go @@ -2,6 +2,7 @@ package engine import ( "math/rand" + "sort" "sync" "time" ) @@ -85,6 +86,17 @@ func (e *Engine) Stop() { } } +// processTick fires every due subscriber for the current engine tick. +// +// Subscribers are invoked in ascending subscription-ID order, i.e. the order in +// which they were registered with Subscribe. IDs are allocated monotonically +// (e.nextID++), so subscription order is a stable, deterministic sequence: +// the bootstrap master subscriber (cmd/thoi/main.go) subscribes at startup as +// ID 1 and therefore always fires first each tick, followed by each +// subsequently-registered tick (combat rounds, aggro rolls, scheduled respawns, +// etc.) in the order they registered. This guarantees predictable per-tick +// ordering across runs — critical for features whose behaviour depends on the +// relative ordering of combat resolution vs. movement vs. aggro checks. func (e *Engine) processTick() { e.mu.Lock() snapshot := make(map[uint64]*subscriber, len(e.subscribers)) @@ -93,7 +105,14 @@ func (e *Engine) processTick() { } e.mu.Unlock() - for id, sub := range snapshot { + ids := make([]uint64, 0, len(snapshot)) + for id := range snapshot { + ids = append(ids, id) + } + sort.Slice(ids, func(i, j int) bool { return ids[i] < ids[j] }) + + for _, id := range ids { + sub := snapshot[id] sub.ticks++ if sub.ticks >= sub.interval { sub.ticks = 0 |
