Compare commits
21 Commits
a3d4c7aa44
...
98b3b98095
Author | SHA1 | Date |
---|---|---|
Pascal Abresch | 98b3b98095 | |
Pascal Abresch | 1993e403d1 | |
Diego Esaa | 1ba6352ef2 | |
Diego Esaa | dc24f21852 | |
Pascal Abresch | 0b64538d65 | |
Pascal Abresch | 9b55a97af7 | |
Pascal Abresch | 80ed7a8738 | |
Pascal Abresch | 2841687bbe | |
Pascal Abresch | d71a8b9138 | |
Pascal Abresch | 6cd8162cb4 | |
Pascal Abresch | 0f3c555149 | |
Pascal Abresch | 1cbe3a1c64 | |
Pascal Abresch | 1d4e5a49aa | |
Pascal Abresch | 0a72496656 | |
Pascal Abresch | 3fce81d7bf | |
Pascal Abresch | 34e6674826 | |
Pascal Abresch | 3225b11deb | |
Pascal Abresch | d686d0a719 | |
Pascal Abresch | 1aab95b15c | |
Pascal Abresch | 126968ea6e | |
Pascal Abresch | 22a647482f |
|
@ -0,0 +1,5 @@
|
|||
Copyright (C) 2022 by Pascal R. G. Abresch <nep@packageloss.eu>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
@ -0,0 +1,13 @@
|
|||
This is the server for [Poppy](https://git.gryphno.de/nephele/poppy-client)
|
||||
|
||||
If you already cloned the client there is no need to clone the server, it is included as a submodule (and the client uses some server code aswell)
|
||||
|
||||
# Implementation status
|
||||
* Basic sessions
|
||||
* Physics sync
|
||||
|
||||
# Not implemented
|
||||
* Chat
|
||||
* Sync drawing, commision textures (store their hashes, store their imagedata for clients that need it)
|
||||
* Timeout clients that haven't responded to a ping for quite some time
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
local constants = require("constants")
|
||||
local util = require("utils")
|
||||
local rpc = require("rpc")
|
||||
|
||||
return function(commands)
|
||||
commands.chat = {}
|
||||
function commands.chat.send(clientID, args)
|
||||
assert(clients[clientID])
|
||||
print("Chat " .. clients[clientID].name .. ": " .. args)
|
||||
for i, player in pairs(clients) do
|
||||
if i ~= clientiD then
|
||||
local payload = util.unit("poppyV001", clientID, "chat", "send") .. constants.US .. args
|
||||
server:sendto(payload, player.ip, player.port)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1 @@
|
|||
table.unpack = table.unpack or unpack
|
|
@ -0,0 +1,29 @@
|
|||
local constants = require("constants")
|
||||
local util = require("utils")
|
||||
local rpc = require("rpc")
|
||||
|
||||
return function(commands)
|
||||
if not commands.drawing then commands.drawing = {} end
|
||||
commands.drawing.texture = { }
|
||||
function commands.drawing.texture.draw(clientID, args)
|
||||
assert(clients[clientID])
|
||||
for i, player in pairs(clients) do
|
||||
if i ~= clientiD then
|
||||
local payload = util.unit("poppyV001", clientID, "drawing", "texture", "draw") .. constants.US .. args
|
||||
server:sendto(payload, player.ip, player.port)
|
||||
end
|
||||
end
|
||||
end
|
||||
function commands.drawing.texture.delete(clientID, args)
|
||||
assert(clients[clientID])
|
||||
for i, player in pairs(clients) do
|
||||
if i ~= clientiD then
|
||||
local payload = util.unit("poppyV001", clientID, "drawing", "texture", "delete") .. constants.US .. args
|
||||
server:sendto(payload, player.ip, player.port)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
end
|
54
main.lua
54
main.lua
|
@ -3,50 +3,74 @@ print("Startup!")
|
|||
local constants = require("constants")
|
||||
local rpc = require("rpc")
|
||||
local socket = require("socket")
|
||||
local util = require("utils")
|
||||
|
||||
local v1_message = {}
|
||||
require("players")(v1_message)
|
||||
require("physics")(v1_message)
|
||||
require("world")(v1_message)
|
||||
require("drawing")(v1_message)
|
||||
require("chat")(v1_message)
|
||||
|
||||
local server = assert(socket.udp())
|
||||
server = assert(socket.udp())
|
||||
local ip, port = nil, nil
|
||||
|
||||
local clientCount = 0
|
||||
local clients = {}
|
||||
clients = {}
|
||||
|
||||
server:settimeout(nil)
|
||||
assert(server:setsockname("*", 42069))
|
||||
assert(server:setsockname("*", 11150))
|
||||
if not server or not socket then error("failed to listen on socket") end
|
||||
|
||||
while true do
|
||||
::nw_next::
|
||||
print("iteration start")
|
||||
local data
|
||||
data, ip, port = server:receivefrom()
|
||||
print("received data from " .. ip)
|
||||
if not data then
|
||||
local err_code = ip
|
||||
print(err_code)
|
||||
goto nw_next
|
||||
end
|
||||
|
||||
for _, req in ipairs(rpc.parse_multiple(data)) do
|
||||
if req.clientid == 0 then
|
||||
count = count + 1
|
||||
response = "rq" .. constants.US .. "cid" .. constants.US .. count
|
||||
clients[count] = { ip = ip, port = port }
|
||||
local result = rpc.validate(data)
|
||||
|
||||
if not result.errorMsg then
|
||||
--print(util.resolve(result.record))
|
||||
local response = rpc.execute(v1_message, clientID, result.record)
|
||||
|
||||
if result.clientID == "0" then
|
||||
clientCount = clientCount + 1
|
||||
print(result.record)
|
||||
local name = string.sub(result.record, 8)
|
||||
print(name)
|
||||
local c_response = util.unit("poppyV001", "0", "rq", "cid", clientCount, name)
|
||||
clients[clientCount ..""] = { ip = ip, port = port, name = name }
|
||||
server:sendto(c_response, ip, port)
|
||||
print("New client connected. Granting id: [" .. clientCount .. "] IP: " .. ip .. " Port:" .. port)
|
||||
for i, client in pairs(clients) do
|
||||
if i ~= clientCount .."" then
|
||||
print("Introducing client[" .. i .. "] and client[" .. clientCount.."]")
|
||||
-- to Existing client
|
||||
local payload = util.unit("poppyV001", clientCount, "player", "join", name)
|
||||
print("Payload1 : " ..payload)
|
||||
server:sendto(payload, client.ip, client.port)
|
||||
-- to New client
|
||||
local payload = util.unit("poppyV001", i, "player", "join", client.name)
|
||||
print("Payload2 : " ..payload)
|
||||
server:sendto(payload, ip, port)
|
||||
end
|
||||
end
|
||||
response = false
|
||||
end
|
||||
|
||||
local response = rpc.eval(v1_message, req)
|
||||
|
||||
if response then
|
||||
--print("Response was: ".. response)
|
||||
local payload = "poppyV001" .. constants.US .. "0" .. constants.US .. response
|
||||
print("sending response to " .. ip .. ":" .. port .. " " .. payload)
|
||||
--print("sending response to " .. ip .. ":" .. port .. " " .. payload)
|
||||
assert(server:sendto(payload, ip, port))
|
||||
else
|
||||
print(req .. " had no return value!")
|
||||
end
|
||||
end
|
||||
print("iteration over")
|
||||
--print("iteration over")
|
||||
end
|
||||
::nw_break::
|
||||
|
|
36
physics.lua
36
physics.lua
|
@ -1,16 +1,19 @@
|
|||
local constants = require("constants")
|
||||
local util = require("utils")
|
||||
local rpc = require("rpc")
|
||||
require("compat")
|
||||
|
||||
return function(commands)
|
||||
commands.move = {}
|
||||
function commands.move.update(clientID, x, y, speedx, speedy)
|
||||
if not players[clientID] then print("move.update: invalid clientid") end
|
||||
function commands.move.update(clientID, args)
|
||||
if not clients[clientID] then rpc.print("move.update: invalid clientid [" .. clientID .. "]") return end
|
||||
local x, y, speedx, speedy = table.unpack(util.resolve(args))
|
||||
clients[clientID].x = x
|
||||
clients[clientID].y = y
|
||||
clients[clientID].speedx = speedx
|
||||
clients[clientID].speedy = speedy
|
||||
|
||||
for i, player in pairs(players) do
|
||||
for i, player in pairs(clients) do
|
||||
if i ~= clientID then
|
||||
local payload = util.unit("poppyV001", clientID,
|
||||
"move", "update", x, y, speedx, speedy)
|
||||
|
@ -18,4 +21,31 @@ return function(commands)
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
function commands.move.flying(clientID, args)
|
||||
for i, player in pairs(clients) do
|
||||
local payload = util.unit("poppyV001", clientID,
|
||||
"move", "flying", args)
|
||||
server:sendto(payload, player.ip, player.port)
|
||||
end
|
||||
end
|
||||
|
||||
commands.drawing = {}
|
||||
commands.drawing.physics = { }
|
||||
function commands.drawing.physics.delete(clientID, args)
|
||||
assert(clients[clientID])
|
||||
for i, player in pairs(clients) do
|
||||
local payload = util.unit("poppyV001", clientID, "drawing", "physics", "delete") .. constants.US .. args
|
||||
server:sendto(payload, player.ip, player.port)
|
||||
end
|
||||
end
|
||||
|
||||
function commands.drawing.physics.draw(clientID, args)
|
||||
assert(clients[clientID])
|
||||
for i, player in pairs(clients) do
|
||||
local payload = util.unit("poppyV001", clientID, "drawing", "physics", "draw") .. constants.US .. args
|
||||
server:sendto(payload, player.ip, player.port)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
local util = require("utils")
|
||||
|
||||
return function(commands)
|
||||
commands.rq = commands.rq or {}
|
||||
|
||||
function commands.rq.cid() return false end
|
||||
commands.player = {}
|
||||
|
||||
function commands.player.leave(clientID)
|
||||
clients[clientID] = nil
|
||||
for i, player in pairs(clients) do
|
||||
local payload = util.unit("poppyV001", clientID,
|
||||
"player", "leave")
|
||||
server:sendto(payload, player.ip, player.port)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
99
rpc.lua
99
rpc.lua
|
@ -2,52 +2,75 @@ local rpc = {
|
|||
PROTOCOL_VERSION = "001"
|
||||
}
|
||||
|
||||
function rpc.parse(msg)
|
||||
local fields = {}
|
||||
for field in msg:gmatch("[^\31]+") do
|
||||
fields[#fields + 1] = field
|
||||
end
|
||||
|
||||
local prot_version = fields[1]:match("^poppyV(%d+)")
|
||||
if not prot_version then error("invalid protocol version") end
|
||||
if prot_version ~= rpc.PROTOCOL_VERSION then error("unsupported protocol version " .. prot_version) end
|
||||
|
||||
local client_id = fields[2]:match("^(%d+)")
|
||||
if not client_id then error("invalid message, missing client id") end
|
||||
|
||||
return {
|
||||
version = prot_version,
|
||||
client_id = client_id,
|
||||
request = {unpack(fields, 3, #fields)}
|
||||
}
|
||||
function rpc.clean(record)
|
||||
assert(type(record) == "string")
|
||||
return record:gsub("\31", "")
|
||||
end
|
||||
|
||||
function rpc.parse_multiple(msg)
|
||||
local requests = {}
|
||||
for record in msg:gmatch("[^\30]+") do
|
||||
table.insert(requests, rpc.parse(record))
|
||||
end
|
||||
return requests
|
||||
function rpc.print(record)
|
||||
local cleaned, _ = record:gsub("\31","|")
|
||||
--print(cleaned)
|
||||
end
|
||||
|
||||
function rpc.eval(command_table, rpc_request)
|
||||
local rpc_function = command_table
|
||||
local rpc_args = {}
|
||||
for i, cmd in ipairs(rpc_request.request) do
|
||||
if type(rpc_function) ~= "function" and rpc_function[cmd] then
|
||||
rpc_function = rpc_function[cmd]
|
||||
else
|
||||
rpc_args = {rpc.clientid, unpack(rpc_request.request, i, #rpc_request.request)}
|
||||
break
|
||||
|
||||
function rpc.validate(record)
|
||||
rpc.print("Starting validation")
|
||||
local errorMsg = false
|
||||
local count
|
||||
record, count = record:gsub("^poppyV" .. rpc.PROTOCOL_VERSION .."\31","")
|
||||
if not count == 1 then
|
||||
errorMsg = "unsupported version or message!"
|
||||
record = nil
|
||||
end
|
||||
rpc.print("record is now ".. record)
|
||||
|
||||
clientID, count = record:match("^%d-\31")
|
||||
clientID = rpc.clean(clientID)
|
||||
if not clientID then
|
||||
errorMsg = "No clientID found!"
|
||||
record = nil
|
||||
else
|
||||
record, count = record:gsub("^%d-\31","")
|
||||
if count ~= 1 then
|
||||
error("Failed to remove clientiD?")
|
||||
end
|
||||
end
|
||||
rpc.print("record is now " .. record)
|
||||
rpc.print("match clientID: " .. clientID)
|
||||
rpc.print("ended validation")
|
||||
return {
|
||||
errorMsg = errorMsg,
|
||||
clientID = clientID,
|
||||
version = rpc.PROTOCOL_VERSION,
|
||||
record = record }
|
||||
end
|
||||
|
||||
if type(rpc_function) ~= "function" then
|
||||
error("received unknown command: " .. table.concat(rpc_request.request, ", "))
|
||||
rpc_function = nil
|
||||
|
||||
function rpc.execute(commands, clientID, record)
|
||||
assert(type(commands) == "table")
|
||||
assert(type(record) == "string")
|
||||
rpc.print("exexute: " .. record)
|
||||
local command = record:match("^.-\31")
|
||||
if command then command = rpc.clean(command) end
|
||||
record = record:gsub("^.-\31","")
|
||||
--if not command then error("Failed to match a command?") end
|
||||
|
||||
if type(commands[command]) == "table" then
|
||||
rpc.print(">" .. command)
|
||||
return rpc.execute(commands[command], clientID, record)
|
||||
else
|
||||
if type(commands[command]) == "function" then
|
||||
rpc.print("executing " .. command .. " with " .. record)
|
||||
return commands[command](clientID, record)
|
||||
else
|
||||
if type(commands[record] == "function") then
|
||||
rpc.print("executing no arguments:" .. record)
|
||||
return commands[record](clientID)
|
||||
else
|
||||
error("How did we get here? ... type is :" .. type(commands[command]))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return rpc_function(unpack(rpc_args))
|
||||
end
|
||||
|
||||
return rpc
|
||||
|
|
50
utils.lua
50
utils.lua
|
@ -4,8 +4,56 @@ function tempTable.unit(...)
|
|||
local string = args[1]
|
||||
for i=2, #args do
|
||||
--print(type(string) .. "with" .. type(args[i]))
|
||||
string = string .. unitSeperator .. args[i]
|
||||
string = string .. string.char(31) .. args[i]
|
||||
end
|
||||
return string
|
||||
end
|
||||
|
||||
|
||||
function tempTable.resolve(record)
|
||||
local tTable = {}
|
||||
for entry in record:gmatch("[^\31]+") do
|
||||
table.insert(tTable, entry)
|
||||
end
|
||||
return tTable
|
||||
end
|
||||
|
||||
function tempTable.clean(record)
|
||||
assert(type(record) == "string")
|
||||
return record:gsub("\31", "")
|
||||
end
|
||||
|
||||
|
||||
function tempTable.pprint(record)
|
||||
local cleaned, _ = record:gsub("\31","|")
|
||||
print(cleaned)
|
||||
end
|
||||
|
||||
|
||||
function tempTable.nextIntRecord(record)
|
||||
local nextR = tempTable.clean(record:match("^.-\31"))
|
||||
record = record:gsub("^.-\31","")
|
||||
return tonumber(nextR), record
|
||||
end
|
||||
|
||||
|
||||
function tempTable.nextStringRecord(record)
|
||||
local nextR = tempTable.clean(record:match("^.-\31"))
|
||||
record = record:gsub("^.-\31","")
|
||||
return nextR, record
|
||||
end
|
||||
|
||||
|
||||
function tempTable.getIntRecords(number, record)
|
||||
local tTable = {}
|
||||
local nextR
|
||||
for i = 1, number -1 do
|
||||
nextR, record = nextIntRecord(record)
|
||||
table.insert(tTable, nextR)
|
||||
end
|
||||
local last = tempTable.clean(record:gsub("^.-\31",""))
|
||||
print("Tonumbering " .. last)
|
||||
table.insert(tTable, tonumber(last))
|
||||
return unpack(tTable)
|
||||
end
|
||||
return tempTable
|
||||
|
|
Loading…
Reference in New Issue