mirror of
https://github.com/cyberarm/i-mic-fps.git
synced 2025-12-16 08:02:36 +00:00
Cleanup, moved Map lifecycle into Director, added renderer_info command
This commit is contained in:
@@ -2,6 +2,7 @@ module CyberarmEngine
|
||||
module Networking
|
||||
class Connection
|
||||
attr_reader :hostname, :port, :peer
|
||||
|
||||
def initialize(hostname:, port:, channels: 3)
|
||||
@hostname = hostname
|
||||
@port = port
|
||||
@@ -26,7 +27,7 @@ module CyberarmEngine
|
||||
|
||||
# Functions #
|
||||
def send_packet(message:, reliable: false, channel: 0)
|
||||
@peer.write_queue << PacketHandler.create_raw_packet(peer: @peer, message: message, reliable: reliable, channel: channel)
|
||||
@peer.write_queue << PacketHandler.create_raw_packet(peer: @peer, message: message, reliable: reliable, channel: channel)
|
||||
end
|
||||
|
||||
def connect(timeout: Protocol::TIMEOUT_PERIOD)
|
||||
|
||||
@@ -32,9 +32,9 @@ module CyberarmEngine
|
||||
when Protocol::CONTROL_CONNECT # TOSERVER only
|
||||
if (peer_id = host.available_peer_id)
|
||||
peer.id = peer_id
|
||||
host.clients << peer
|
||||
host.peers << peer
|
||||
peer.write_queue << create_control_packet(peer: peer, control_type: Protocol::CONTROL_SET_PEER_ID, message: [peer_id].pack("n"))
|
||||
host.client_connected(peer: peer)
|
||||
host.peer_connected(peer: peer)
|
||||
else
|
||||
host.write(
|
||||
peer: peer,
|
||||
@@ -52,7 +52,7 @@ module CyberarmEngine
|
||||
|
||||
when Protocol::CONTROL_DISCONNECT
|
||||
if host.is_a?(Server)
|
||||
host.client_disconnected(peer: peer)
|
||||
host.peer_disconnected(peer: peer)
|
||||
else
|
||||
host.disconnected(reason: pkt.message)
|
||||
end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
module CyberarmEngine
|
||||
module Networking
|
||||
class Server
|
||||
attr_reader :hostname, :port, :max_clients
|
||||
attr_reader :hostname, :port, :max_peers, :peers
|
||||
attr_accessor :total_packets_sent, :total_packets_received,
|
||||
:total_data_sent, :total_data_received,
|
||||
:last_read_time, :last_write_time
|
||||
@@ -9,12 +9,12 @@ module CyberarmEngine
|
||||
def initialize(
|
||||
hostname: CyberarmEngine::Networking::DEFAULT_SERVER_HOSTNAME,
|
||||
port: CyberarmEngine::Networking::DEFAULT_SERVER_PORT,
|
||||
max_clients: CyberarmEngine::Networking::DEFAULT_PEER_LIMIT,
|
||||
max_peers: CyberarmEngine::Networking::DEFAULT_PEER_LIMIT,
|
||||
channels: 3
|
||||
)
|
||||
@hostname = hostname
|
||||
@port = port
|
||||
@max_clients = max_clients + 2
|
||||
@max_peers = max_peers + 2
|
||||
|
||||
@channels = Array(0..channels).map { |id| Channel.new(id: id, mode: :default) }
|
||||
@peers = []
|
||||
@@ -28,35 +28,26 @@ module CyberarmEngine
|
||||
@total_data_received = 0
|
||||
end
|
||||
|
||||
# Helpers #
|
||||
def connected_clients
|
||||
@peers.size
|
||||
end
|
||||
|
||||
def clients
|
||||
@peers
|
||||
end
|
||||
|
||||
# Callbacks #
|
||||
|
||||
# Called when client connects
|
||||
def client_connected(peer:)
|
||||
# Called when peer connects
|
||||
def peer_connected(peer:)
|
||||
end
|
||||
|
||||
# Called when client times out or explicitly disconnects
|
||||
def client_disconnected(peer:, reason:)
|
||||
# Called when peer times out or explicitly disconnects
|
||||
def peer_disconnected(peer:, reason:)
|
||||
end
|
||||
|
||||
### REMOVE? ###
|
||||
# Called when client was not sending heartbeats or regular packets for a
|
||||
# Called when peer was not sending heartbeats or regular packets for a
|
||||
# period of time, but was not logically disconnected and removed, and started
|
||||
# send packets again.
|
||||
#
|
||||
# TLDR: Client was temporarily unreachable but did not timeout.
|
||||
def client_reconnected(peer:)
|
||||
# TLDR: peer was temporarily unreachable but did not timeout.
|
||||
def peer_reconnected(peer:)
|
||||
end
|
||||
|
||||
# Called when a (logical) packet is received from client
|
||||
# Called when a (logical) packet is received from peer
|
||||
def packet_received(peer:, message:, channel:)
|
||||
end
|
||||
|
||||
@@ -84,7 +75,7 @@ module CyberarmEngine
|
||||
end
|
||||
|
||||
# Disconnect peer
|
||||
def disconnect_client(peer:, reason: "")
|
||||
def disconnect_peer(peer:, reason: "")
|
||||
if (peer = @peers[peer])
|
||||
packet = PacketHandler.create_disconnect_packet(peer.id, reason)
|
||||
peer.write_now!(packet)
|
||||
@@ -110,7 +101,7 @@ module CyberarmEngine
|
||||
message: message
|
||||
)
|
||||
)
|
||||
client_disconnected(peer: peer, reason: message)
|
||||
peer_disconnected(peer: peer, reason: message)
|
||||
@peers.delete(peer)
|
||||
next
|
||||
end
|
||||
@@ -135,7 +126,7 @@ module CyberarmEngine
|
||||
|
||||
def available_peer_id
|
||||
peer_ids = @peers.map(&:id)
|
||||
ids = (2..@max_clients).to_a - peer_ids
|
||||
ids = (2..@max_peers).to_a - peer_ids
|
||||
|
||||
ids.size.positive? ? ids.first : nil
|
||||
end
|
||||
@@ -157,7 +148,7 @@ module CyberarmEngine
|
||||
packet: PacketHandler.create_control_packet(
|
||||
peer: peer,
|
||||
control_type: Protocol::CONTROL_DISCONNECT,
|
||||
message: "ERROR: client not connected"
|
||||
message: "ERROR: peer not connected"
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
@@ -1,29 +1,36 @@
|
||||
class IMICFPS
|
||||
module Networking
|
||||
class Director
|
||||
attr_reader :address, :port, :tick_rate, :storage, :map
|
||||
def initialize(address: DEFAULT_SERVER_HOST, port: DEFAULT_SERVER_PORT, tick_rate: 2)
|
||||
@address = address
|
||||
@port = port
|
||||
attr_reader :tick_rate, :storage, :map, :server, :connection
|
||||
|
||||
def initialize(tick_rate: 15)
|
||||
@tick_rate = (1000.0 / tick_rate) / 1000.0
|
||||
|
||||
@server = Server.new(address: @address, port: @port, max_peers: DEFAULT_PEER_LIMIT)
|
||||
@server.bind
|
||||
|
||||
@last_tick_time = Networking.milliseconds
|
||||
@last_tick_time = CyberarmEngine::Networking.milliseconds
|
||||
@directing = true
|
||||
@storage = {}
|
||||
@map = nil
|
||||
end
|
||||
|
||||
def host_server(hostname: CyberarmEngine::Networking::DEFAULT_SERVER_HOSTNAME, port: CyberarmEngine::Networking::DEFAULT_SERVER_PORT, max_peers: CyberarmEngine::Networking::DEFAULT_PEER_LIMIT)
|
||||
@server = Server.new(hostname: hostname, port: port, max_peers: max_peers)
|
||||
@server.bind
|
||||
end
|
||||
|
||||
def connect(hostname:, port: CyberarmEngine::Networking::DEFAULT_SERVER_PORT)
|
||||
@connection = Connection.new(hostname: hostname, port: port)
|
||||
@connection.connect
|
||||
end
|
||||
|
||||
def load_map(map_parser:)
|
||||
# TODO: send map_change to clients
|
||||
@map = Map.new(map_parser: map_parser)
|
||||
@map.setup
|
||||
end
|
||||
|
||||
def run
|
||||
Thread.start do |thread|
|
||||
while(@directing)
|
||||
Thread.start do
|
||||
while @directing
|
||||
dt = milliseconds - @last_tick_time
|
||||
|
||||
tick(dt)
|
||||
@@ -35,18 +42,20 @@ class IMICFPS
|
||||
end
|
||||
|
||||
def tick(delta_time)
|
||||
if @map
|
||||
Publisher.instance.publish(:tick, delta_time * 1000.0)
|
||||
return unless @map
|
||||
|
||||
@map.update
|
||||
@server.update
|
||||
end
|
||||
Publisher.instance.publish(:tick, delta_time * 1000.0)
|
||||
|
||||
@map.update
|
||||
@server&.update
|
||||
@connection&.update
|
||||
end
|
||||
|
||||
def shutdown
|
||||
@directing = false
|
||||
@server.close
|
||||
@server&.close
|
||||
@connection&.close
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
class IMICFPS
|
||||
module Networking
|
||||
class Peer
|
||||
attr_reader :id, :address, :port, :packet_read_queue, :packet_write_queue
|
||||
attr_accessor :total_packets_sent, :total_packets_received, :total_data_sent, :total_data_received, :last_read_time, :last_write_time
|
||||
def initialize(id:, address:, port:)
|
||||
@id = id
|
||||
@address, @port = address, port
|
||||
|
||||
@packet_write_queue = []
|
||||
@packet_read_queue = []
|
||||
|
||||
@last_read_time = Networking.milliseconds
|
||||
@last_write_time = Networking.milliseconds
|
||||
|
||||
@total_packets_sent = 0
|
||||
@total_packets_received = 0
|
||||
@total_data_sent = 0
|
||||
@total_data_received = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,135 +1,14 @@
|
||||
class IMICFPS
|
||||
module Networking
|
||||
class Server
|
||||
attr_reader :address, :port, :max_peers, :peers
|
||||
attr_accessor :total_packets_sent, :total_packets_received, :total_data_sent, :total_data_received, :last_read_time, :last_write_time
|
||||
def initialize(address:, port:, max_peers:)
|
||||
@address = address
|
||||
@port = port
|
||||
@max_peers = max_peers
|
||||
|
||||
@peers = Array.new(@max_peers + 1, nil)
|
||||
|
||||
@read_buffer = ReadBuffer.new
|
||||
|
||||
@last_read_time = Networking.milliseconds
|
||||
@last_write_time = Networking.milliseconds
|
||||
|
||||
@total_packets_sent = 0
|
||||
@total_packets_received = 0
|
||||
@total_data_sent = 0
|
||||
@total_data_received = 0
|
||||
class Server < CyberarmEngine::Networking::Server
|
||||
def connected(peer:)
|
||||
end
|
||||
|
||||
# Peer ID 0 is reserved for unconnected peers to pass packet validation
|
||||
def create_peer(address:, port:)
|
||||
@peers.each_with_index do |peer, i|
|
||||
unless peer
|
||||
new_peer = Peer.new(id: i + 1, address: address, port: port)
|
||||
@peers[i + 1] = new_peer
|
||||
|
||||
return new_peer
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
def disconnected(peer:, reason:)
|
||||
end
|
||||
|
||||
def get_peer(peer_id)
|
||||
@peers[peer_id]
|
||||
end
|
||||
|
||||
def remove_peer(peer_id)
|
||||
@peers[peer_id] = nil
|
||||
end
|
||||
|
||||
def bind
|
||||
@socket = UDPSocket.new
|
||||
@socket.bind(@address, @port)
|
||||
end
|
||||
|
||||
def send_packet( peer_id, packet )
|
||||
if peer = get_peer(peer_id)
|
||||
packets = Packet.splinter(packet)
|
||||
|
||||
packets.each { |pkt| peer.packet_write_queue.push(pkt) }
|
||||
end
|
||||
end
|
||||
|
||||
def broadcast_packet(packet)
|
||||
@peers.each do |peer|
|
||||
next unless peer
|
||||
|
||||
send_packet(peer.id, packet)
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
while(read)
|
||||
end
|
||||
|
||||
@peers.each do |peer|
|
||||
next unless peer
|
||||
|
||||
peer.packet_write_queue.each do |packet|
|
||||
write(peer, packet)
|
||||
peer.packet_write_queue.delete(packet)
|
||||
end
|
||||
end
|
||||
|
||||
# "deliver" packets to peers, record stats to peers
|
||||
@read_buffer.reconstruct_packets.each do |packet, addr_info|
|
||||
peer = nil
|
||||
|
||||
# initial connection
|
||||
if packet.peer_id == 0 && packet.type == Protocol::CONNECT
|
||||
peer = create_peer(address: addr_info[2], port: addr_info[1])
|
||||
send_packet(
|
||||
peer.id,
|
||||
Packet.new(
|
||||
peer_id: 0,
|
||||
sequence: 0,
|
||||
type: Protocol::VERIFY_CONNECT,
|
||||
payload: [peer.id].pack("C")
|
||||
)
|
||||
)
|
||||
else
|
||||
peer = get_peer(packet.peer_id)
|
||||
end
|
||||
end
|
||||
|
||||
# broadcast_packet(Packet.new(peer_id: 0, sequence: 0, type: Protocol::HEARTBEAT, payload: [Networking.milliseconds].pack("G")))
|
||||
end
|
||||
|
||||
def close
|
||||
@socket.close if @socket
|
||||
end
|
||||
|
||||
private
|
||||
def read
|
||||
data, addr = @socket.recvfrom_nonblock(Protocol::MAX_PACKET_SIZE)
|
||||
@read_buffer.add(data, addr )
|
||||
|
||||
@total_packets_received += 1
|
||||
@total_data_received += data.length
|
||||
@last_read_time = Networking.milliseconds
|
||||
return true
|
||||
rescue IO::WaitReadable
|
||||
return false
|
||||
end
|
||||
|
||||
def write(peer, packet)
|
||||
raw = packet.encode
|
||||
@socket.send( raw, 0, peer.address, peer.port )
|
||||
|
||||
@total_packets_sent += 1
|
||||
@total_data_sent += raw.length
|
||||
@last_write_time = Networking.milliseconds
|
||||
|
||||
peer.total_packets_sent += 1
|
||||
peer.total_data_sent += raw.length
|
||||
peer.last_write_time = Networking.milliseconds
|
||||
def packet_received(peer:, message:, channel:)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user