summaryrefslogtreecommitdiff
path: root/server.lua
diff options
context:
space:
mode:
authorLizzy Fleckenstein <lizzy@vlhl.dev>2026-06-03 22:31:42 +0200
committerLizzy Fleckenstein <lizzy@vlhl.dev>2026-06-03 23:30:17 +0200
commit341af788ffb60b1066f7735c10a2ef8480ec0aa9 (patch)
treeb1acbfe48184a263098e6146922730dd7ece8808 /server.lua
parenta42c94e103ecf7cb365a8888c3f5afc785def284 (diff)
downloadr6p-main.tar.xz
add player selectionHEADmain
Diffstat (limited to 'server.lua')
-rw-r--r--server.lua150
1 files changed, 144 insertions, 6 deletions
diff --git a/server.lua b/server.lua
index 5d1ddd4..9cda5a4 100644
--- a/server.lua
+++ b/server.lua
@@ -2,19 +2,108 @@ local enet = require("enet")
local socket = require("socket")
local util = require("util")
local common = require("common")
+local save_file = require("save_file")
local server = {}
-function server.create(match_addr)
+local function migrate_save(save)
+ save.players = save.players or {}
+end
+
+local function save_data(srv)
+ -- TODO: handle failure
+ save_file.write(srv.save_file, srv.data)
+end
+
+local function get_player(srv, name)
+ for _, player in ipairs(srv.data.players) do
+ if player.name == name then
+ return player
+ end
+ end
+end
+
+local function get_players(srv)
+ local players = {}
+ for _, player in ipairs(srv.data.players) do
+ table.insert(players, {
+ name = player.name,
+ active = srv.players[player.name] ~= nil,
+ })
+ end
+ return players
+end
+
+local function get_info_pkt(srv)
+ return util.json_enc({
+ type = "client_info",
+ players = get_players(srv),
+ })
+end
+
+local function broadcast_info(srv)
+ local pkt = get_info_pkt(srv)
+ for _, clt in pairs(srv.clients) do
+ clt.peer:send(pkt)
+ end
+end
+
+local function create_player(srv, name)
+ local player = { name = name }
+ table.insert(srv.data.players, player)
+ print("[server] created player " .. name)
+ save_data(srv)
+ return player
+end
+
+local function disconnect(srv, clt)
+ srv.clients[clt.peer] = nil
+ if clt.player then
+ srv.players[clt.player.name] = nil
+ end
+ broadcast_info(srv)
+end
+
+local function select_player(srv, clt, pkt)
+ if #pkt.name > 128 then
+ return "name_too_long"
+ end
+ if srv.players[pkt.name] then
+ return nil, "already_active"
+ end
+ local player = get_player(srv, pkt.name)
+ if pkt.create and player then
+ return nil, "already_exists"
+ end
+ if not pkt.create and not player then
+ return nil, "not_exists"
+ end
+
+ if pkt.create then
+ player = create_player(srv, pkt.name)
+ end
+ return player
+end
+
+function server.create(filename, match_addr)
local srv = {}
srv.host = enet.host_create()
srv.secret = util.rand_string(common.secret_len)
srv.clients = {}
+ srv.players = {}
srv.match = srv.host:connect(match_addr or common.default_match_addr)
srv.match_req = socket.gettime()
+ local save, err = save_file.read(filename)
+ if err then
+ return nil, err
+ end
+ srv.save_file = filename
+ srv.data = save
+ migrate_save(save)
+
return srv
end
@@ -57,14 +146,54 @@ local function handle_client(srv, peer, pkt)
if secret == srv.secret then
print("[server] auth success " .. tostring(peer))
- srv.clients[peer] = { peer = peer }
- peer:send(util.json_enc({ type = "client_hi" }))
+ local clt = { peer = peer }
+ srv.clients[peer] = clt
+ util.send(peer, {
+ type = "client_hi",
+ })
+ peer:send(get_info_pkt(srv))
else
print("[server] auth failure " .. tostring(peer))
- peer:send(util.json_enc({ type = "client_reject" }))
+ util.send(peer, { type = "client_reject" })
peer:disconnect_later()
end
end
+
+ local clt = srv.clients[peer]
+ if not clt then
+ print("[server] dropping unauthenicated packet from " .. tostring(peer))
+ return
+ end
+
+ if pkt.type == "server_player" then
+ if clt.player then
+ print("[server] dropping server_player from already authenticated player")
+ return
+ end
+
+ if type(pkt.name) ~= "string" or type(pkt.create) ~= "boolean" then
+ print("[server] server_player: invalid packet")
+ return
+ end
+
+ local player, err = select_player(srv, clt, pkt)
+ if err then
+ print("[server] failed to select player " .. tostring(clt.peer))
+ util.send(clt.peer, {
+ type = "client_player_fail",
+ error = err,
+ })
+ else
+ print("[server] select player " .. tostring(clt.peer) .. ": " .. player.name)
+ srv.players[player.name] = clt
+ clt.player = player
+ util.send(clt.peer, {
+ type = "client_player",
+ name = player.name,
+ })
+ broadcast_info(srv)
+ end
+ end
end
function server.update(srv)
@@ -81,7 +210,7 @@ function server.update(srv)
end
elseif event.type == "connect" then
if event.peer == srv.match then
- srv.match:send(util.json_enc({ type = "match_register" }))
+ util.send(srv.match, { type = "match_register" })
end
print("[server] connect " .. tostring(event.peer))
elseif event.type == "disconnect" then
@@ -89,7 +218,10 @@ function server.update(srv)
if event.peer == srv.match then
-- TODO
else
- srv.clients[event.peer] = nil
+ local clt = srv.clients[event.peer]
+ if clt then
+ disconnect(srv, clt)
+ end
end
end
event = srv.host:service()
@@ -107,6 +239,12 @@ function server.match_status(srv)
end
function server.close(srv)
+ save_data(srv)
+ local peers = srv.host:peer_count()
+ for i = 1, peers do
+ srv.host:get_peer(i):disconnect()
+ end
+ srv.host:flush()
srv.host:destroy()
end