class ClientConnection
The client creates one of these. It is then used for all communication with the server.
Constants
- ACTION_DELAY
We tell the server to execute all actions this many ticks in the future, to give the message time to propagate around the fleet
Attributes
engine[RW]
player_name[R]
Public Class Methods
new(host, port, game, player_name, key_size, timeout=2000)
click to toggle source
# File lib/game_2d/client_connection.rb, line 23 def initialize(host, port, game, player_name, key_size, timeout=2000) # remote host address, remote host port, channels, download bandwidth, upload bandwidth @socket = _create_connection(host, port, 2, 0, 0) @host, @port, @game, @player_name, @key_size, @timeout = host, port, game, player_name, key_size, timeout @socket.on_connection(method(:on_connect)) @socket.on_disconnection(method(:on_close)) @socket.on_packet_receive(method(:on_packet)) @dh = @password_hash = nil end
Public Instance Methods
_create_connection(*args)
click to toggle source
# File lib/game_2d/client_connection.rb, line 50 def _create_connection(*args) ENet::Connection.new(*args) end
debug_packet(direction, hash)
click to toggle source
# File lib/game_2d/client_connection.rb, line 176 def debug_packet(direction, hash) return unless $debug_traffic at_tick = hash[:at_tick] || 'NO TICK' keys = hash.keys - [:at_tick] puts "#{direction} #{keys.join(', ')} <#{at_tick}>" end
disconnect()
click to toggle source
# File lib/game_2d/client_connection.rb, line 188 def disconnect; @socket.disconnect(200) if online?; end
login(server_public_key)
click to toggle source
# File lib/game_2d/client_connection.rb, line 63 def login(server_public_key) self.key = @dh.compute_key(OpenSSL::BN.new server_public_key) data, iv = encrypt(@password_hash) @password_hash = nil send_record( :password_hash => strict_encode64(data), :iv => strict_encode64(iv) ) end
on_close()
click to toggle source
# File lib/game_2d/client_connection.rb, line 73 def on_close puts "Client disconnected by server" @game.shutdown end
on_connect()
click to toggle source
# File lib/game_2d/client_connection.rb, line 54 def on_connect @game.display_message "Connected, logging in" send_record( { :handshake => { :player_name => @player_name, :dh_public_key => @dh.public_key.to_pem, :client_public_key => @dh.pub_key.to_s } }, true) # send handshake reliably end
on_packet(data, channel)
click to toggle source
# File lib/game_2d/client_connection.rb, line 78 def on_packet(data, channel) hash = JSON.parse(data).fix_keys debug_packet('Received', hash) if pong = hash.delete(:pong) stop = Time.now.to_f puts "Ping took #{stop - pong[:start]} seconds" end if server_public_key = hash.delete(:server_public_key) login(server_public_key) return end # Leave :at_tick intact; add_delta will reuse it fail "No at_tick in #{hash.inspect}" unless at_tick = hash[:at_tick] if world = hash.delete(:world) @game.clear_message @engine.establish_world(world, at_tick) end you_are = hash.delete :you_are registry, highest_id = hash.delete(:registry), hash.delete(:highest_id) delta_keys = [ :add_players, :add_npcs, :delete_entities, :update_entities, :update_score, :move ] @engine.add_delta(hash) if delta_keys.any? {|k| hash.has_key? k} if you_are # The 'world' response includes deltas for add_players and add_npcs # Need to process those first, as one of the players is us @engine.apply_deltas(at_tick) if world @game.player_id = you_are end @engine.sync_registry(registry, highest_id, at_tick) if registry end
online?()
click to toggle source
# File lib/game_2d/client_connection.rb, line 187 def online?; @socket.online?; end
send_actions_at()
click to toggle source
# File lib/game_2d/client_connection.rb, line 119 def send_actions_at @engine.tick + ACTION_DELAY end
send_create_npc(npc)
click to toggle source
# File lib/game_2d/client_connection.rb, line 132 def send_create_npc(npc) return unless online? # :on_* hooks are for our own use; we don't send them remote_npc = npc.reject {|k,v| k.to_s.start_with? 'on_'} send_record :at_tick => send_actions_at, :add_npcs => [ remote_npc ] @engine.add_delta :at_tick => send_actions_at, :add_npcs => [ npc ] end
send_delete_entity(entity)
click to toggle source
# File lib/game_2d/client_connection.rb, line 147 def send_delete_entity(entity) return unless online? delta = { :delete_entities => [entity.registry_id], :at_tick => send_actions_at } send_record delta @engine.add_delta delta end
send_move(player_id, move, args={})
click to toggle source
# File lib/game_2d/client_connection.rb, line 123 def send_move(player_id, move, args={}) return unless move && online? args[:move] = move.to_s delta = { :at_tick => send_actions_at, :move => args } send_record delta delta[:player_id] = player_id @engine.add_delta delta end
send_ping()
click to toggle source
# File lib/game_2d/client_connection.rb, line 165 def send_ping send_record :ping => { :start => Time.now.to_f } end
send_record(data, reliable=false)
click to toggle source
# File lib/game_2d/client_connection.rb, line 169 def send_record(data, reliable=false) return unless online? debug_packet('Sending', data) @socket.send_packet(data.to_json, reliable, 0) @socket.flush end
send_save()
click to toggle source
# File lib/game_2d/client_connection.rb, line 161 def send_save send_record :save => true end
send_snap_to_grid(entity)
click to toggle source
# File lib/game_2d/client_connection.rb, line 154 def send_snap_to_grid(entity) return unless online? && entity delta = { :at_tick => send_actions_at, :snap_to_grid => entity.registry_id } send_record delta @engine.add_delta delta end
send_update_entity(entity)
click to toggle source
# File lib/game_2d/client_connection.rb, line 140 def send_update_entity(entity) return unless online? delta = { :update_entities => [entity], :at_tick => send_actions_at } send_record delta @engine.add_delta delta end
start(password_hash)
click to toggle source
# File lib/game_2d/client_connection.rb, line 36 def start(password_hash) @password_hash = password_hash Thread.new do @game.display_message! "Establishing encryption (#{@key_size}-bit)..." @dh = OpenSSL::PKey::DH.new(@key_size) # Connect to server and kick off handshaking # We will create our player object only after we've been accepted by the server # and told our starting position @game.display_message! "Connecting to #{@host}:#{@port} as #{@player_name}" @socket.connect(@timeout) end end
update()
click to toggle source
# File lib/game_2d/client_connection.rb, line 183 def update @socket.update(0) # non-blocking end