Class: Doom::Net::Client
- Inherits:
-
Object
- Object
- Doom::Net::Client
- Defined in:
- lib/doom/net/client.rb
Overview
The client half of the authoritative-server game. Talks only to the server (outbound UDP, so NAT is a non-issue), joins by restoring a snapshot of the live world, then follows the server's finalized frame stream -- applying joins, leaves and commands in tic order -- so its world stays byte-identical to the server's. It runs no simulation of its own and never predicts: the local player sees their own input after the round trip to the server and back, which is the price of a model where a dead phone can't stall anyone.
Everything is polled, never blocking, so the game keeps rendering while a join is still in flight or a resync is underway.
A join is a small state machine: HELLO -> WELCOME (who you are, which map) -> SNAPSHOT chunks (the world) -> playing. HELLO is resent until WELCOME arrives; if the snapshot never completes, or the frame stream leaves a gap too old for the server's redundancy to fill, the client asks again and the server sends a fresh snapshot at the current tic.
Constant Summary collapse
- HELLO_RESEND_SECONDS =
0.25
- SYNC_TIMEOUT_SECONDS =
No completed snapshot this long -> ask again
1.5- RESYNC_GAP_TICS =
If the newest frame we've heard of is this far past the one we still need, the missing one has aged out of the server's resend window and is gone for good -- only a fresh snapshot recovers us.
12
Instance Attribute Summary collapse
-
#local_id ⇒ Object
readonly
Returns the value of attribute local_id.
-
#synced_tic ⇒ Object
readonly
Returns the value of attribute synced_tic.
-
#world ⇒ Object
readonly
Returns the value of attribute world.
Instance Method Summary collapse
-
#connected? ⇒ Boolean
WELCOME received.
-
#initialize(host:, port:, sprites:, load_map:, sound: nil, clock: -> { Time.now }, transport: nil) ⇒ Client
constructor
load_mapis a callable name -> Map::MapData; the client learns which map from WELCOME and has no other way to reach the WAD. - #local_port ⇒ Object
-
#playing? ⇒ Boolean
snapshot restored, following frames.
-
#poll ⇒ Object
Pump the network: chase the join if not yet playing, then drain and apply whatever has arrived.
- #quit ⇒ Object
-
#send_input(pairs) ⇒ Object
Send this frame's input for future tics.
Constructor Details
#initialize(host:, port:, sprites:, load_map:, sound: nil, clock: -> { Time.now }, transport: nil) ⇒ Client
load_map is a callable name -> Map::MapData; the client learns which
map from WELCOME and has no other way to reach the WAD.
34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/doom/net/client.rb', line 34 def initialize(host:, port:, sprites:, load_map:, sound: nil, clock: -> { Time.now }, transport: nil) @host = host @port = port @sprites = sprites @load_map = load_map @sound = sound @clock = clock @transport = transport || Transport.new reset_join @last_hello_at = nil end |
Instance Attribute Details
#local_id ⇒ Object (readonly)
Returns the value of attribute local_id.
30 31 32 |
# File 'lib/doom/net/client.rb', line 30 def local_id @local_id end |
#synced_tic ⇒ Object (readonly)
Returns the value of attribute synced_tic.
30 31 32 |
# File 'lib/doom/net/client.rb', line 30 def synced_tic @synced_tic end |
#world ⇒ Object (readonly)
Returns the value of attribute world.
30 31 32 |
# File 'lib/doom/net/client.rb', line 30 def world @world end |
Instance Method Details
#connected? ⇒ Boolean
WELCOME received
48 |
# File 'lib/doom/net/client.rb', line 48 def connected? = !@local_id.nil? # WELCOME received |
#local_port ⇒ Object
47 |
# File 'lib/doom/net/client.rb', line 47 def local_port = @transport.local_port |
#playing? ⇒ Boolean
snapshot restored, following frames
49 |
# File 'lib/doom/net/client.rb', line 49 def = !@world.nil? # snapshot restored, following frames |
#poll ⇒ Object
Pump the network: chase the join if not yet playing, then drain and apply whatever has arrived. Safe every frame.
53 54 55 56 57 |
# File 'lib/doom/net/client.rb', line 53 def poll send_hello_if_due @transport.poll.each { |msg, _host, _port| handle(msg) } resync_if_stuck end |
#quit ⇒ Object
67 68 69 70 |
# File 'lib/doom/net/client.rb', line 67 def quit send_packet(Protocol.encode_quit(@local_id)) if @local_id && !@transport.closed? @transport.close end |
#send_input(pairs) ⇒ Object
Send this frame's input for future tics. pairs is [[tic, Ticcmd], ...];
recent inputs are repeated by the caller so a lost packet is covered.
61 62 63 64 65 |
# File 'lib/doom/net/client.rb', line 61 def send_input(pairs) return unless @local_id send_packet(Protocol.encode_input(@local_id, pairs)) end |