Class: Doom::Net::DesyncMonitor
- Inherits:
-
Object
- Object
- Doom::Net::DesyncMonitor
- Defined in:
- lib/doom/net/desync_monitor.rb
Overview
Watches for lockstep divergence.
Each peer fingerprints its world every CHECK_INTERVAL tics and broadcasts the result. When two peers report different fingerprints for the same tic, their simulations have already diverged and every tic after it is meaningless. The job here is to say so at the tic it happened, with enough detail to diagnose it, instead of letting the games drift apart while both players wonder why the other is shooting at nothing.
Peers exchange per-section hashes, not just the folded one: five extra numbers a second is nothing on the wire, and it turns "something diverged" into "the monsters diverged", which is the difference between an alarming report and a useful one.
Reports can arrive before or after the local check for the same tic, so both directions are buffered and compared whenever a pair completes.
Defined Under Namespace
Classes: Desync
Constant Summary collapse
- CHECK_INTERVAL =
One second at DOOM's tic rate
35- HISTORY_TICS =
Keep ~10s; enough to pair up late reports
350
Instance Attribute Summary collapse
-
#desyncs ⇒ Object
readonly
Returns the value of attribute desyncs.
Instance Method Summary collapse
- #check_due?(tic) ⇒ Boolean
- #desynced? ⇒ Boolean
-
#initialize(interval: CHECK_INTERVAL, &on_desync) ⇒ DesyncMonitor
constructor
on_desyncis called with a Desync the moment one is detected. -
#record(tic, world) ⇒ Object
Fingerprint the world if this tic is a checkpoint.
-
#remote_report(tic, peer_id, sections) ⇒ Object
Section hashes received from another peer.
Constructor Details
#initialize(interval: CHECK_INTERVAL, &on_desync) ⇒ DesyncMonitor
on_desync is called with a Desync the moment one is detected.
36 37 38 39 40 41 42 |
# File 'lib/doom/net/desync_monitor.rb', line 36 def initialize(interval: CHECK_INTERVAL, &on_desync) @interval = interval @on_desync = on_desync @local = {} # tic => section hashes @remote = {} # tic => { peer_id => section hashes } @desyncs = [] end |
Instance Attribute Details
#desyncs ⇒ Object (readonly)
Returns the value of attribute desyncs.
33 34 35 |
# File 'lib/doom/net/desync_monitor.rb', line 33 def desyncs @desyncs end |
Instance Method Details
#check_due?(tic) ⇒ Boolean
44 45 46 |
# File 'lib/doom/net/desync_monitor.rb', line 44 def check_due?(tic) (tic % @interval).zero? end |
#desynced? ⇒ Boolean
66 67 68 |
# File 'lib/doom/net/desync_monitor.rb', line 66 def desynced? !@desyncs.empty? end |
#record(tic, world) ⇒ Object
Fingerprint the world if this tic is a checkpoint. Returns the section hashes to broadcast, or nil on a tic that is not checked.
50 51 52 53 54 55 56 57 58 |
# File 'lib/doom/net/desync_monitor.rb', line 50 def record(tic, world) return nil unless check_due?(tic) sections = world.state_hash_sections @local[tic] = sections compare(tic) prune(tic) sections end |
#remote_report(tic, peer_id, sections) ⇒ Object
Section hashes received from another peer.
61 62 63 64 |
# File 'lib/doom/net/desync_monitor.rb', line 61 def remote_report(tic, peer_id, sections) (@remote[tic] ||= {})[peer_id] = sections compare(tic) end |