Serialization API, Server -> Clients messaging.
- Added zepha.serialize & zepha.deserialize. Said methods are automatically used when message-passing. - Revised dump() to have better formatting and configurable spacing :)master
parent
7618269434
commit
9466d7692a
|
@ -9,6 +9,7 @@ runfile(_PATH .. "modules/after")
|
|||
runfile(_PATH .. "modules/vector")
|
||||
runfile(_PATH .. "modules/entity")
|
||||
runfile(_PATH .. "modules/callbacks")
|
||||
runfile(_PATH .. "modules/serialization")
|
||||
|
||||
-- Register base models (if not on main menu)
|
||||
if zepha.client or zepha.server then runfile(_PATH .. "game/init") end
|
|
@ -1,56 +1,47 @@
|
|||
-- Zepha Dump Function
|
||||
-- Version 1.0
|
||||
|
||||
-- dumpTbl [private]
|
||||
-- Recursive function to print the contents of a table.
|
||||
local function dumpTbl(tbl, indent, scannedTables)
|
||||
if not scannedTables then scannedTables = {} end
|
||||
if not indent then indent = 0 end
|
||||
--
|
||||
-- Pretty-prints a lua value, properly displaying tables
|
||||
-- with indentation, table collapsing, and more.
|
||||
--
|
||||
-- @param {any} val - The lua value to print.
|
||||
-- @param {number | nil | false} nl - Controls the table expansion behavior. If left unspecified,
|
||||
-- tables will expand if they contain more than 3 keys. If set to a number n,
|
||||
-- tables will expand if they contain more than n keys, if set to false, tables will never expand.
|
||||
-- @param {number | nil} idn - Internal value, do not assign manually.
|
||||
--
|
||||
|
||||
scannedTables[tbl] = true
|
||||
_G["format"] = function(val, nl, idn)
|
||||
idn = idn or 0
|
||||
if nl == nil then nl = 3 end
|
||||
|
||||
for k, v in pairs(tbl) do
|
||||
if type(k) == "number" then
|
||||
k = "[" .. k .. "]"
|
||||
if type(val) == "function" or type(val) == "userdata" or type(val) == "thread" then return tostring(val) end
|
||||
if type(val) == "string" then return '"' .. val .. '"' end
|
||||
if type(val) == "nil" then return 'nil' end
|
||||
if type(val) == "table" then
|
||||
local strings = {}
|
||||
|
||||
local num_keys = 0
|
||||
for _ in pairs(val) do num_keys = num_keys + 1 end
|
||||
|
||||
local use_nl = nl == true and true or (type(nl) == 'number' and num_keys >= nl)
|
||||
local new_idn = use_nl and idn + 1 or idn
|
||||
local delim = use_nl and '\n' or ' '
|
||||
|
||||
for k, v in pairs(val) do
|
||||
table.insert(strings, format(k, nl, new_idn) .. ' = ' .. format(v, nl, new_idn))
|
||||
end
|
||||
|
||||
local indentString = string.rep(" ", indent)
|
||||
local formatting = indentString .. k .. " = "
|
||||
local outer_idn = ''
|
||||
if use_nl and idn then for i = 1, idn do outer_idn = outer_idn .. '\t' end end
|
||||
local inner_idn = use_nl and outer_idn .. '\t' or ''
|
||||
|
||||
if type(v) == "function" then
|
||||
v = "<function>"
|
||||
elseif type(v) == "userdata" then
|
||||
v = "<userdata>"
|
||||
elseif type(v) == "string" then
|
||||
v = '"' .. v .. '"'
|
||||
elseif type(v) == "boolean" then
|
||||
v = tostring(v)
|
||||
end
|
||||
|
||||
if type(v) == "table" then
|
||||
if scannedTables[v] ~= nil then
|
||||
print(formatting .. "<circular>")
|
||||
else
|
||||
print(formatting .. "{")
|
||||
dumpTbl(v, indent + 1, scannedTables)
|
||||
print(indentString .. "}")
|
||||
end
|
||||
else
|
||||
print(formatting .. v)
|
||||
end
|
||||
return '{' .. delim .. inner_idn .. table.concat(strings, ',' .. delim .. inner_idn) .. delim .. outer_idn .. '}'
|
||||
end
|
||||
return val
|
||||
end
|
||||
|
||||
-- dump
|
||||
-- Prints a human readable form of a value.
|
||||
_G["dump"] = function(val)
|
||||
if type(val) == "table" then
|
||||
print("{")
|
||||
dumpTbl(val, 1)
|
||||
print("}")
|
||||
return
|
||||
end
|
||||
if type(val) == "string" then print('"'..val..'"') return end
|
||||
print(val)
|
||||
return
|
||||
_G["dump"] = function(val, nl)
|
||||
print(format(val, nl))
|
||||
end
|
|
@ -0,0 +1,99 @@
|
|||
zepha.serialize = function(data)
|
||||
local data_type = type(data)
|
||||
|
||||
if data_type == 'table' then
|
||||
local values = {}
|
||||
for k, v in pairs(data) do
|
||||
table.insert(values, zepha.serialize(k) .. ' = ' .. zepha.serialize(v))
|
||||
end
|
||||
return '{ ' .. table.concat(values, ', ') .. ' }'
|
||||
end
|
||||
|
||||
if data_type == 'number' then return tostring(data) end
|
||||
if data_type == 'string' then return '"' .. data:gsub('"', '\"') .. '"' end
|
||||
if data_type == 'boolean' then return data and 'true' or 'false' end
|
||||
|
||||
if data_type ~= 'nil' then print('[ERR] Invalid serialization type: ' .. data_type) end
|
||||
return 'nil'
|
||||
end
|
||||
|
||||
local function trim(str)
|
||||
return str:match('^%s*(.-)%s*$')
|
||||
end
|
||||
|
||||
local function split(input, sep, op)
|
||||
if sep == nil then sep = "%s" end
|
||||
local t = {}
|
||||
for str in string.gmatch(input, '([^'..sep..']+)') do
|
||||
table.insert(t, op and op(str) or str) end
|
||||
return t
|
||||
end
|
||||
|
||||
local function find_match(str, a, b, off)
|
||||
local pattern = '[' .. a .. b .. ']'
|
||||
if not off then off = 1 end
|
||||
local nest = 0
|
||||
local found = str:find(pattern, off)
|
||||
while found do
|
||||
if str:sub(found, found) == a then nest = nest + 1
|
||||
else nest = nest - 1 end
|
||||
off = found + 1
|
||||
if nest == 0 then return found
|
||||
elseif nest < 0 then return nil end
|
||||
found = str:find(pattern, off)
|
||||
end
|
||||
end
|
||||
|
||||
zepha.deserialize = function(str)
|
||||
str = trim(str)
|
||||
|
||||
if str:sub(1, 1) == '{' then
|
||||
local tbl = {}
|
||||
str = trim(str:sub(2, #str - 1))
|
||||
|
||||
while #str > 0 do
|
||||
local sep, key, val
|
||||
|
||||
if str:sub(1, 1) == ',' then
|
||||
str = trim(str:sub(2))
|
||||
end
|
||||
|
||||
if str:sub(1, 1) == '{' then
|
||||
-- Handling a table key
|
||||
local e = find_match(str, '{', '}')
|
||||
local tbl_key = str:sub(1, e)
|
||||
key = zepha.deserialize(tbl_key)
|
||||
str = trim(str:sub(str:find('=', e + 1) + 1))
|
||||
else
|
||||
-- Handling a normal key
|
||||
local end_ind = str:find('=')
|
||||
key = zepha.deserialize(str:sub(1, end_ind - 1))
|
||||
str = trim(str:sub(end_ind + 1))
|
||||
end
|
||||
|
||||
if str:sub(1, 1) == '{' then
|
||||
-- Handling a table value
|
||||
local e = find_match(str, '{', '}')
|
||||
local tbl_val = str:sub(1, e)
|
||||
val = zepha.deserialize(tbl_val)
|
||||
str = trim(str:sub(e + 1))
|
||||
else
|
||||
-- Handling a normal value
|
||||
local end_ind = str:find(',')
|
||||
val = zepha.deserialize(str:sub(1, (end_ind or #str + 1) - 1))
|
||||
str = trim(str:sub(end_ind or #str + 1))
|
||||
end
|
||||
|
||||
tbl[key] = val
|
||||
end
|
||||
|
||||
return tbl
|
||||
end
|
||||
|
||||
if str:find('^"') then return str:sub(2, #str - 1) end
|
||||
if str:find('^true') then return true end
|
||||
if str:find('^false') then return false end
|
||||
if str:find('^nil') then return nil end
|
||||
|
||||
return tonumber(str)
|
||||
end
|
|
@ -66,17 +66,21 @@ void ClientNetworkInterpreter::receivedPacket(std::unique_ptr<PacketView> p) {
|
|||
<< ". Is the server on a different protocol version?" << Log::endl;
|
||||
break;
|
||||
|
||||
case Packet::Type::SERVER_INFO:serverSideChunkGens = p->d.read<unsigned int>();
|
||||
case Packet::Type::SERVER_INFO:
|
||||
serverSideChunkGens = p->d.read<unsigned int>();
|
||||
break;
|
||||
|
||||
case Packet::Type::THIS_PLAYER_INFO:world.getPlayer()->handleAssertion(p->d);
|
||||
case Packet::Type::THIS_PLAYER_INFO:
|
||||
world.getPlayer()->handleAssertion(p->d);
|
||||
break;
|
||||
|
||||
case Packet::Type::PLAYER_ENT_INFO:world.handlePlayerEntPacket(std::move(p));
|
||||
case Packet::Type::PLAYER_ENT_INFO:
|
||||
world.handlePlayerEntPacket(std::move(p));
|
||||
break;
|
||||
|
||||
case Packet::Type::CHUNK:
|
||||
case Packet::Type::MAPBLOCK:world.handleWorldPacket(std::move(p));
|
||||
case Packet::Type::MAPBLOCK:
|
||||
world.handleWorldPacket(std::move(p));
|
||||
break;
|
||||
|
||||
case Packet::Type::BLOCK_SET: {
|
||||
|
@ -86,13 +90,16 @@ void ClientNetworkInterpreter::receivedPacket(std::unique_ptr<PacketView> p) {
|
|||
break;
|
||||
}
|
||||
|
||||
case Packet::Type::ENTITY_INFO:world.getActiveDimension().l()->serverEntitiesInfo(p->d);
|
||||
case Packet::Type::ENTITY_INFO:
|
||||
world.getActiveDimension().l()->serverEntitiesInfo(p->d);
|
||||
break;
|
||||
|
||||
case Packet::Type::ENTITY_REMOVED:world.getActiveDimension().l()->serverEntitiesRemoved(p->d);
|
||||
case Packet::Type::ENTITY_REMOVED:
|
||||
world.getActiveDimension().l()->serverEntitiesRemoved(p->d);
|
||||
break;
|
||||
|
||||
case Packet::Type::INV_DATA:onInvPacket(std::move(p));
|
||||
case Packet::Type::INV_DATA:
|
||||
onInvPacket(std::move(p));
|
||||
break;
|
||||
|
||||
case Packet::Type::INV_INVALID: {
|
||||
|
@ -100,6 +107,12 @@ void ClientNetworkInterpreter::receivedPacket(std::unique_ptr<PacketView> p) {
|
|||
std::string list = p->d.read<std::string>();
|
||||
throw std::runtime_error("Invalid inventory " + source + ":" + list + " was request by client.");
|
||||
}
|
||||
case Packet::Type::MOD_MESSAGE: {
|
||||
std::string channel = p->d.read<std::string>();
|
||||
std::string message = p->d.read<std::string>();
|
||||
world.handleModMessage(channel, message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,15 +13,10 @@
|
|||
#include "client/conn/ServerConnection.h"
|
||||
|
||||
class Model;
|
||||
|
||||
class Target;
|
||||
|
||||
class LocalWorld;
|
||||
|
||||
class PacketView;
|
||||
|
||||
class LocalPlayer;
|
||||
|
||||
class LocalSubgame;
|
||||
|
||||
enum class NetPlayerField;
|
||||
|
|
|
@ -7,6 +7,6 @@ void Api::Module::Message::bind() {
|
|||
core.set_function("send_message", Util::bind_this(this, &Message::send_message));
|
||||
}
|
||||
|
||||
void Api::Module::Message::send_message(const std::string& channel, const std::string& message) {
|
||||
world.sendMessage(channel, message);
|
||||
void Api::Module::Message::send_message(const std::string& channel, sol::object message) {
|
||||
world.sendMessage(channel, core["serialize"](message));
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace Api::Module {
|
|||
void bind() override;
|
||||
|
||||
protected:
|
||||
void send_message(const std::string& channel, const std::string& message);
|
||||
void send_message(const std::string& channel, sol::object message);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -162,7 +162,7 @@ void Server::playerPacketReceived(PacketView& p, PlayerPtr player) {
|
|||
case Packet::Type::MOD_MESSAGE:
|
||||
p.d.read<std::string>(source).read<std::string>(list);
|
||||
game->getParser().safe_function(game->getParser().core["trigger"], "message",
|
||||
source, list, Api::Usertype::ServerPlayer(player));
|
||||
source, game->getParser().safe_function(game->getParser().core["deserialize"], list));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,6 +71,11 @@ void LocalWorld::handlePlayerEntPacket(std::unique_ptr<PacketView> p) {
|
|||
// getActiveDimension().playerEntities.emplace_back(p->d.read<glm::vec3>(), id, playerModel);
|
||||
}
|
||||
|
||||
void LocalWorld::handleModMessage(const std::string& channel, const std::string& message) {
|
||||
game->getParser().safe_function(game->getParser().core["trigger"], "message",
|
||||
channel, game->getParser().safe_function(game->getParser().core["deserialize"], message));
|
||||
}
|
||||
|
||||
void LocalWorld::commitChunk(std::shared_ptr<Chunk> c) {
|
||||
activeDimension->setChunk(std::move(c));
|
||||
}
|
||||
|
|
|
@ -35,6 +35,8 @@ public:
|
|||
|
||||
void handlePlayerEntPacket(std::unique_ptr<PacketView> p);
|
||||
|
||||
void handleModMessage(const std::string& channel, const std::string& message);
|
||||
|
||||
void commitChunk(std::shared_ptr<Chunk> chunk);
|
||||
|
||||
virtual void sendMessage(const std::string& channel, const std::string& message) override;
|
||||
|
|
|
@ -240,5 +240,7 @@ void ServerWorld::sendChunksToPlayer(ServerPlayer& client) {
|
|||
}
|
||||
|
||||
void ServerWorld::sendMessage(const std::string& channel, const std::string& message) {
|
||||
std::cout << channel << ":" << message << std::endl;
|
||||
auto p = Serializer().append(channel).append(message).packet(Packet::Type::MOD_MESSAGE);
|
||||
for (auto& player : clients.players)
|
||||
p.sendTo(player->getPeer(), Packet::Channel::ENTITY);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
health.damage_player = function(player, damage)
|
||||
local health = health.health_values[player.id]
|
||||
health.health = health.health - damage
|
||||
health.buffer = damage
|
||||
|
||||
zepha.send_message("@auri:health:damage", health)
|
||||
end
|
|
@ -0,0 +1,11 @@
|
|||
health.health_values = {}
|
||||
|
||||
if zepha.server then
|
||||
zepha.bind('player_join', function(player)
|
||||
health.health_values[player.id] = { health = 20, buffer = 0 }
|
||||
end)
|
||||
else
|
||||
zepha.bind('message', function(channel, message)
|
||||
dump(message)
|
||||
end)
|
||||
end
|
|
@ -1,7 +1,10 @@
|
|||
local api = {}
|
||||
_G['health'] = api
|
||||
|
||||
runfile(_PATH .. 'api')
|
||||
runfile(_PATH .. 'core')
|
||||
|
||||
if zepha.client then
|
||||
runfile(_PATH .. "interface")
|
||||
runfile(_PATH .. 'interface')
|
||||
api.default_render(true)
|
||||
end
|
|
@ -1,4 +1,4 @@
|
|||
local friendly = false
|
||||
local ATTACK_INTERVAL = 1
|
||||
|
||||
zepha.register_entity("zeus:default:rabbit", {
|
||||
display = "model",
|
||||
|
@ -21,8 +21,14 @@ zepha.register_entity("zeus:default:rabbit", {
|
|||
|
||||
self.object.anims:set_anim("run")
|
||||
self.object.anims:play()
|
||||
|
||||
self.attack_timer = 0
|
||||
end,
|
||||
on_update = function(self, delta)
|
||||
if self.attack_timer > 0 then
|
||||
self.attack_timer = math.max(self.attack_timer - delta, 0)
|
||||
end
|
||||
|
||||
local closest_player = nil
|
||||
for _, player in pairs(zepha.players) do
|
||||
if not closest_player or vector.dist(self.object.pos, player.pos)
|
||||
|
@ -32,9 +38,13 @@ zepha.register_entity("zeus:default:rabbit", {
|
|||
end
|
||||
|
||||
if not closest_player then return end
|
||||
|
||||
local offset = closest_player.pos - self.object.pos
|
||||
local dist = offset:length()
|
||||
if dist > 16 then return end
|
||||
if dist > 16 then
|
||||
self.attack_timer = ATTACK_INTERVAL
|
||||
return
|
||||
end
|
||||
|
||||
if dist > 0.5 then
|
||||
local dir = offset:unit()
|
||||
|
@ -54,7 +64,11 @@ zepha.register_entity("zeus:default:rabbit", {
|
|||
3 * math.cos(math.rad(self.object.yaw + 90))
|
||||
}
|
||||
else
|
||||
self.object.vel = V{}
|
||||
self.object.vel = V {}
|
||||
if self.attack_timer == 0 then
|
||||
health.damage_player(closest_player, 1)
|
||||
self.attack_timer = ATTACK_INTERVAL
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
Loading…
Reference in New Issue