152 lines
3.7 KiB
Lua
152 lines
3.7 KiB
Lua
local Multiplayer = {}
|
|
local binser = require("lib.binser")
|
|
local pprint = require("lib.pprint")
|
|
local uid = require("helpers.uid")
|
|
|
|
local RATE_LIMIT = 20
|
|
|
|
local CMD = {
|
|
SPAWN_PLAYER = 1,
|
|
MOVE_PLAYER = 2,
|
|
AIM_PLAYER = 3,
|
|
PLAYER_SHOT = 4,
|
|
}
|
|
|
|
local function removeValue(t, v)
|
|
for i, vv in ipairs(t) do
|
|
if v == vv then
|
|
table.remove(t, i)
|
|
end
|
|
end
|
|
end
|
|
|
|
function Multiplayer:init()
|
|
self.connected_peers = {}
|
|
local host_socket = self.pool.data.host_socket
|
|
for i=1, host_socket:peer_count() do
|
|
local peer = host_socket:get_peer(i)
|
|
if peer:state() == "connected" then
|
|
self:onPeerConnect(peer)
|
|
end
|
|
end
|
|
end
|
|
|
|
function Multiplayer:onPeerConnect(peer)
|
|
table.insert(self.connected_peers, peer:index())
|
|
end
|
|
|
|
function Multiplayer:onPeerDisconnect(peer)
|
|
local peer_index = peer:index()
|
|
removeValue(self.connected_peers, peer_index)
|
|
for _, player in ipairs(self.pool.groups.player.entities) do
|
|
if player.peer_index == peer_index then
|
|
self.pool:removeEntity(player)
|
|
end
|
|
end
|
|
end
|
|
|
|
function Multiplayer:disconnectPeers()
|
|
local host_socket = self.pool.data.host_socket
|
|
for _, index in ipairs(self.connected_peers) do
|
|
local peer = host_socket:get_peer(index)
|
|
peer:disconnect_now()
|
|
self:onPeerDisconnect(peer)
|
|
end
|
|
host_socket:flush()
|
|
end
|
|
|
|
function Multiplayer:sendToPeer(peer, ...)
|
|
peer:send(binser.serialize(...), nil, "unreliable")
|
|
end
|
|
|
|
function Multiplayer:sendToAllPeers(...)
|
|
local payload = binser.serialize(...)
|
|
local host_socket = self.pool.data.host_socket
|
|
for _, index in ipairs(self.connected_peers) do
|
|
local peer = host_socket:get_peer(index)
|
|
peer:send(payload, nil, "unreliable")
|
|
end
|
|
end
|
|
|
|
function Multiplayer:update()
|
|
local host_socket = self.pool.data.host_socket
|
|
local event = host_socket:service()
|
|
if event then
|
|
if event.type == "connect" then
|
|
self:onPeerConnect(event.peer)
|
|
elseif event.type == "disconnect" then
|
|
self:onPeerDisconnect(event.peer)
|
|
elseif event.type == "receive" then
|
|
local parameters = binser.deserialize(event.data)
|
|
self:handlePeerMessage(event.peer, unpack(parameters))
|
|
end
|
|
end
|
|
end
|
|
|
|
function Multiplayer:getPlayerEntityById(id)
|
|
for _, player in ipairs(self.pool.groups.player.entities) do
|
|
if player.id == id then
|
|
return player
|
|
end
|
|
end
|
|
end
|
|
|
|
function Multiplayer:handlePeerMessage(peer, cmd, ...)
|
|
if cmd == CMD.SPAWN_PLAYER then
|
|
local id = ...
|
|
local PlayerSystem = self.pool:getSystem(require("systems.player"))
|
|
local player = PlayerSystem:spawnPlayer()
|
|
player.id = id
|
|
player.peer_index = peer:index()
|
|
elseif cmd == CMD.MOVE_PLAYER then
|
|
local id, move_dir, pos = ...
|
|
local player = self:getPlayerEntityById(id)
|
|
|
|
if player and player.peer_index == peer:index() then
|
|
player.move_dir = move_dir
|
|
player.pos = pos
|
|
end
|
|
elseif cmd == CMD.AIM_PLAYER then
|
|
local id, aim_dir = ...
|
|
local player = self:getPlayerEntityById(id)
|
|
|
|
if player and player.peer_index == peer:index() then
|
|
player.aim_dir = aim_dir
|
|
end
|
|
elseif cmd == CMD.PLAYER_SHOT then
|
|
local id = ...
|
|
local player = self:getPlayerEntityById(id)
|
|
|
|
if player and player.peer_index == peer:index() then
|
|
self.pool:emit("tryShootingBolt", player)
|
|
end
|
|
else
|
|
print("DEBUG INFORMATION:")
|
|
print("Message:")
|
|
pprint{cmd, ...}
|
|
error("Unhandled message from peer")
|
|
end
|
|
end
|
|
|
|
function Multiplayer:addToGroup(group, player)
|
|
if group == "player" and not player.peer_index then
|
|
player.id = uid()
|
|
self:sendToAllPeers(CMD.SPAWN_PLAYER, player.id)
|
|
self.pool:queue(player)
|
|
end
|
|
end
|
|
|
|
function Multiplayer:playerMoved(player)
|
|
self:sendToAllPeers(CMD.MOVE_PLAYER, player.id, player.move_dir, player.pos)
|
|
end
|
|
|
|
function Multiplayer:playerAimed(player)
|
|
self:sendToAllPeers(CMD.AIM_PLAYER, player.id, player.aim_dir)
|
|
end
|
|
|
|
function Multiplayer:playerShot(player)
|
|
self:sendToAllPeers(CMD.PLAYER_SHOT, player.id)
|
|
end
|
|
|
|
return Multiplayer
|