class ServerConnection

An instance of this class is created by ServerPort whenever an incoming connection is accepted.

Attributes

authenticated[R]
id[R]
player_id[RW]
player_name[R]

Public Class Methods

new(port, game, server, id, remote_addr) click to toggle source
# File lib/game_2d/server_connection.rb, line 14
def initialize(port, game, server, id, remote_addr)
  @port, @game, @server, @id, @remote_addr = port, game, server, id, remote_addr
  puts "ServerConnection: New connection #{id} from #{remote_addr}"
  @authenticated = false
end

Public Instance Methods

add_npc(npc, at_tick) click to toggle source
# File lib/game_2d/server_connection.rb, line 81
def add_npc(npc, at_tick)
  send_record :add_npcs => [ npc ], :at_tick => at_tick
end
add_player(player, at_tick) click to toggle source
# File lib/game_2d/server_connection.rb, line 85
def add_player(player, at_tick)
  send_record :add_players => [ player ], :at_tick => at_tick
end
answer_handshake(handshake) click to toggle source
# File lib/game_2d/server_connection.rb, line 24
def answer_handshake(handshake)
  if authenticated?
    warn "#{self} cannot re-handshake"
    disconnect!
    return
  end
  @player_name = handshake[:player_name]
  dh_public_key = handshake[:dh_public_key]
  client_public_key = handshake[:client_public_key]
  dh = OpenSSL::PKey::DH.new(dh_public_key)
  dh.generate_key!
  self.key = dh.compute_key(OpenSSL::BN.new client_public_key)
  response = {
    :server_public_key => dh.pub_key.to_s
  }
  send_record response, true # answer reliably
end
answer_login(b64_password_hash, b64_iv) click to toggle source
# File lib/game_2d/server_connection.rb, line 42
def answer_login(b64_password_hash, b64_iv)
  if authenticated?
    warn "#{self} cannot re-login"
    disconnect!
    return
  end
  password_hash = decrypt(
    strict_decode64(b64_password_hash),
    strict_decode64(b64_iv))
  player_data = @game.player_data(@player_name)
  if player_data
    unless password_hash == player_data[:password_hash]
      warn "Wrong password for #{@player_name} (#{password_hash} != #{player_data[:password_hash]})"
      disconnect!
      return
    end
  else # new player
    @game.store_player_data @player_name, :password_hash => password_hash
  end
  @authenticated = true

  @port.register_player @player_name, self
  player = @game.add_player(@player_name)
  @player_id = player.registry_id
  puts "#{player} logs in from #{@remote_addr} at <#{@game.tick}>"

  # We don't send the registry here.  The Game will do it after
  # all logins have been processed and the update has completed.
  # Otherwise, we're sending an incomplete frame.
end
answer_ping(ping) click to toggle source
# File lib/game_2d/server_connection.rb, line 77
def answer_ping(ping)
  send_record :pong => ping
end
authenticated?() click to toggle source
# File lib/game_2d/server_connection.rb, line 22
def authenticated?; @authenticated; end
close() click to toggle source
# File lib/game_2d/server_connection.rb, line 102
def close
  @game.send_player_gone player
end
debug_packet(direction, hash) click to toggle source
# File lib/game_2d/server_connection.rb, line 136
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
delete_entity(entity, at_tick) click to toggle source
# File lib/game_2d/server_connection.rb, line 89
def delete_entity(entity, at_tick)
  send_record :delete_entities => [ entity.registry_id ], :at_tick => at_tick
end
disconnect!() click to toggle source
# File lib/game_2d/server_connection.rb, line 143
def disconnect!
  @server.disconnect_client(@id)
end
on_packet(data, channel) click to toggle source
# File lib/game_2d/server_connection.rb, line 106
def on_packet(data, channel)
  hash = JSON.parse(data).fix_keys
  debug_packet('Received', hash)
  if handshake = hash.delete(:handshake)
    answer_handshake(handshake)
  elsif password_hash = hash.delete(:password_hash)
    answer_login(password_hash, hash.delete(:iv))
  elsif ping = hash.delete(:ping)
    answer_ping ping
  elsif !authenticated?
    warn "Ignoring #{hash.inspect}, not authenticated"
  elsif hash.delete(:save)
    @game.save
  else
    hash[:player_name] = @player_name
    hash[:player_id] = @player_id
    @game.add_player_action hash
    # TODO: Validate
    @port.broadcast_player_action hash, channel
  end
end
player() click to toggle source
# File lib/game_2d/server_connection.rb, line 73
def player
  @game[@player_id]
end
send_record(hash, reliable=false, channel=0) click to toggle source
# File lib/game_2d/server_connection.rb, line 128
def send_record(hash, reliable=false, channel=0)
  debug_packet('Sending', hash)
  send_str = hash.to_json
  # Send data to the client (client ID, data, reliable or not, channel ID)
  @server.send_packet(@id, send_str, reliable, channel)
  @server.flush
end
to_s() click to toggle source
# File lib/game_2d/server_connection.rb, line 147
def to_s
  "#{@player_name || '??'} ##{@id} from #{@remote_addr}"
end
update_entities(entities, at_tick) click to toggle source
# File lib/game_2d/server_connection.rb, line 93
def update_entities(entities, at_tick)
  send_record :update_entities => entities, :at_tick => at_tick
end
update_score(player, at_tick) click to toggle source

Not called yet…

# File lib/game_2d/server_connection.rb, line 98
def update_score(player, at_tick)
  send_record :update_score => { player.player_name => player.score }, :at_tick => at_tick
end