Compare commits

...

21 Commits

Author SHA1 Message Date
Pascal Abresch 98b3b98095 move some utils to server 2022-01-09 10:46:42 +01:00
Pascal Abresch 1993e403d1 add flying 2022-01-09 10:18:36 +01:00
Diego Esaa 1ba6352ef2 Fix broken server names
Prior to this commit, some of the player's names would have 'rqcid' prefixed
to them.
2022-01-08 21:46:53 +01:00
Diego Esaa dc24f21852 add backwards compatibility for unpack() 2022-01-08 21:46:24 +01:00
Pascal Abresch 0b64538d65 Add chat support 2022-01-08 20:57:18 +01:00
Pascal Abresch 9b55a97af7 add player name 2022-01-08 17:33:50 +01:00
Pascal Abresch 80ed7a8738 replace default port 2022-01-08 12:07:07 +01:00
Pascal Abresch 2841687bbe add texture delete command 2022-01-08 12:06:53 +01:00
Pascal Abresch d71a8b9138 add drawing support (kinda slow though) 2022-01-07 23:15:16 +01:00
Pascal Abresch 6cd8162cb4 add license 2022-01-04 20:11:40 +01:00
Pascal Abresch 0f3c555149 Tell other clients about leaving clients 2022-01-04 18:54:59 +01:00
Pascal Abresch 1cbe3a1c64 remove some logging 2022-01-04 18:54:39 +01:00
Pascal Abresch 1d4e5a49aa Readme added 2022-01-04 13:26:51 +01:00
Pascal Abresch 0a72496656 Add physics ping pong 2022-01-03 18:57:00 +01:00
Pascal Abresch 3fce81d7bf advertise other clients 2022-01-02 21:24:34 +01:00
Pascal Abresch 34e6674826 disable some debug output 2022-01-02 19:19:54 +01:00
Pascal Abresch 3225b11deb usefull commit message 2022-01-02 18:40:30 +01:00
Pascal Abresch d686d0a719 update main.lua 2022-01-02 17:20:32 +01:00
Pascal Abresch 1aab95b15c reworked rpc 2022-01-02 17:20:24 +01:00
Pascal Abresch 126968ea6e add players.lua 2022-01-02 15:17:36 +01:00
Pascal Abresch 22a647482f send clientid 2022-01-02 15:17:14 +01:00
10 changed files with 265 additions and 57 deletions

5
License Normal file
View File

@ -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.

13
Readme.md Normal file
View File

@ -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

17
chat.lua Normal file
View File

@ -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

1
compat.lua Normal file
View File

@ -0,0 +1 @@
table.unpack = table.unpack or unpack

29
drawing.lua Normal file
View File

@ -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

View File

@ -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::

View File

@ -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

18
players.lua Normal file
View File

@ -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
View File

@ -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

View File

@ -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