Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--assets/opensb/scripts/opensb/servercommands/servercommands.lua80
-rw-r--r--assets/opensb/universe_server.config.patch7
-rw-r--r--source/game/StarChatTypes.cpp26
-rw-r--r--source/game/StarChatTypes.hpp4
-rw-r--r--source/game/StarNetPackets.cpp162
-rw-r--r--source/game/StarNetPackets.hpp37
6 files changed, 289 insertions, 27 deletions
diff --git a/assets/opensb/scripts/opensb/servercommands/servercommands.lua b/assets/opensb/scripts/opensb/servercommands/servercommands.lua
new file mode 100644
index 0000000..ca30435
--- /dev/null
+++ b/assets/opensb/scripts/opensb/servercommands/servercommands.lua
@@ -0,0 +1,80 @@
+local commands = {}
+local logHelp = "Available OpenStarbound server commands:\n"
+local userHelp = logHelp .. "^cyan;"
+local adminHelp = userHelp
+
+local function cmd(name, description, permission, func)
+ local first = next(commands) == nil
+ logHelp = logHelp .. (first and name or ", " .. name)
+ userHelp = userHelp .. (first and name or ", ^cyan;" .. name)
+ adminHelp = adminHelp .. (first and name or ", ^cyan;" .. name)
+
+ local keyName = name:lower()
+ if permission == "tell" then
+ commands[keyName] = function(connectionId, ...)
+ return func(universe.isAdmin(connectionId), connectionId, ...)
+ end
+ elseif permission == "admin" then
+ commands[keyName] = function(connectionId, ...)
+ local error = CommandProcessor.adminCheck(connectionId, description:sub(1, 1):lower() .. description:sub(2))
+ if error then
+ return error
+ else
+ return func(connectionId, ...)
+ end
+ end
+ elseif permission == "user" then
+ commands[keyName] = func
+ else
+ error(string.format("Command '%s' has invalid permission", name))
+ end
+end
+
+cmd("openhelp", "Get help", "tell", function(isAdmin, connectionId)
+ return isAdmin and adminHelp or userHelp
+end)
+
+do
+
+local objects = nil
+cmd("packetTest", "Do science", "admin", function(connectionId)
+ if not objects then
+ objects = {}
+ local paths = root.assetsByExtension("object")
+ for i, v in pairs(paths) do
+ local json = root.assetJson(v)
+ objects[i] = {json.objectName, json.shortdescription or json.objectName}
+ end
+ end
+ local item = objects[math.random(#objects)]
+ universe.sendPacket(connectionId, "GiveItem", {
+ item = {name = item[1], count = 1}
+ })
+
+ return "Can I interest you in a ^cyan;" .. item[2] .. "^reset;?"
+end)
+
+end
+
+local _init = type(init) == "function" and init
+function init(...)
+ sb.logInfo("%s", logHelp)
+ if _init then return _init(...) end
+end
+
+local _command = type(command) == "function" and command
+function command(commandName, connectionId, args)
+ local ret = _command and _command(commandName, connectionId, args)
+ if ret then return ret end
+
+ local command = commands[commandName:lower()]
+ if command then
+ local success, ret = pcall(command, connectionId, table.unpack(args))
+ if not success then
+ sb.logError("Error in OpenStarbound server command /%s: %s", commandName, ret)
+ return "command error: " .. ret
+ else
+ return ret
+ end
+ end
+end \ No newline at end of file
diff --git a/assets/opensb/universe_server.config.patch b/assets/opensb/universe_server.config.patch
new file mode 100644
index 0000000..55d39cc
--- /dev/null
+++ b/assets/opensb/universe_server.config.patch
@@ -0,0 +1,7 @@
+[
+ {
+ "op" : "add",
+ "path" : "/commandProcessorScripts/-",
+ "value" : "/scripts/opensb/servercommands/servercommands.lua"
+ }
+] \ No newline at end of file
diff --git a/source/game/StarChatTypes.cpp b/source/game/StarChatTypes.cpp
index ae4cd01..a717be3 100644
--- a/source/game/StarChatTypes.cpp
+++ b/source/game/StarChatTypes.cpp
@@ -46,6 +46,32 @@ ChatReceivedMessage::ChatReceivedMessage(MessageContext context, ConnectionId fr
ChatReceivedMessage::ChatReceivedMessage(MessageContext context, ConnectionId fromConnection, String const& fromNick, String const& text, String const& portrait)
: context(context), fromConnection(fromConnection), fromNick(fromNick), portrait(portrait), text(text) {}
+ChatReceivedMessage::ChatReceivedMessage(Json const& json) : ChatReceivedMessage() {
+ auto jContext = json.get("context");
+ context = MessageContext(
+ MessageContextModeNames.getLeft(jContext.getString("mode")),
+ jContext.getString("channelName", "")
+ );
+ fromConnection = json.getUInt("fromConnection", 0);
+ fromNick = json.getString("fromNick", "");
+ portrait = json.getString("portrait", "");
+ text = json.getString("text");
+}
+
+Json ChatReceivedMessage::toJson() const {
+ return JsonObject{
+ {"context", JsonObject{
+ {"mode", MessageContextModeNames.getRight(context.mode)},
+ {"channelName", context.channelName.empty() ? Json() : Json(context.channelName)}
+ }},
+ {"fromConnection", fromConnection},
+ {"fromNick", fromNick.empty() ? Json() : fromNick},
+ {"portrait", portrait.empty() ? Json() : portrait},
+ {"text", text}
+ };
+}
+
+
DataStream& operator>>(DataStream& ds, ChatReceivedMessage& receivedMessage) {
ds.read(receivedMessage.context);
ds.read(receivedMessage.fromConnection);
diff --git a/source/game/StarChatTypes.hpp b/source/game/StarChatTypes.hpp
index 376ec6d..3feb413 100644
--- a/source/game/StarChatTypes.hpp
+++ b/source/game/StarChatTypes.hpp
@@ -2,6 +2,7 @@
#include "StarDataStream.hpp"
#include "StarGameTypes.hpp"
+#include "StarJson.hpp"
namespace Star {
@@ -43,6 +44,9 @@ struct ChatReceivedMessage {
ChatReceivedMessage();
ChatReceivedMessage(MessageContext context, ConnectionId fromConnection, String const& fromNick, String const& text);
ChatReceivedMessage(MessageContext context, ConnectionId fromConnection, String const& fromNick, String const& text, String const& portrait);
+ ChatReceivedMessage(Json const& json);
+
+ Json toJson() const;
MessageContext context;
diff --git a/source/game/StarNetPackets.cpp b/source/game/StarNetPackets.cpp
index 140845a..fd127a2 100644
--- a/source/game/StarNetPackets.cpp
+++ b/source/game/StarNetPackets.cpp
@@ -1,5 +1,6 @@
#include "StarNetPackets.hpp"
#include "StarDataStreamExtra.hpp"
+#include "StarJsonExtra.hpp"
namespace Star {
@@ -79,17 +80,13 @@ EnumMap<PacketType> const PacketTypeNames{
Packet::~Packet() {}
-void Packet::readLegacy(DataStream& ds) {
- read(ds);
-}
-void Packet::writeLegacy(DataStream& ds) const {
- write(ds);
-}
+void Packet::readLegacy(DataStream& ds) { read(ds); }
+void Packet::writeLegacy(DataStream& ds) const { write(ds); }
+void Packet::readJson(Json const& json) {}
+Json Packet::writeJson() const { return JsonObject{}; }
-PacketCompressionMode Packet::compressionMode() const
- { return m_compressionMode; }
-void Packet::setCompressionMode(PacketCompressionMode compressionMode)
- { m_compressionMode = compressionMode; }
+PacketCompressionMode Packet::compressionMode() const { return m_compressionMode; }
+void Packet::setCompressionMode(PacketCompressionMode compressionMode) { m_compressionMode = compressionMode; }
PacketPtr createPacket(PacketType type) {
switch (type) {
@@ -168,22 +165,12 @@ PacketPtr createPacket(PacketType type) {
}
PacketPtr createPacket(PacketType type, Maybe<Json> const& args) {
- if (!args)
- return createPacket(type);
+ auto packet = createPacket(type);
- switch (type) {
- case PacketType::Pause: return make_shared<PausePacket>(args->getBool("pause"), args->getFloat("timescale", 1.0f));
- case PacketType::ServerInfo: return make_shared<ServerInfoPacket>(args->getUInt("players"), args->getUInt("maxPlayers"));
- case PacketType::GiveItem: return make_shared<GiveItemPacket>(ItemDescriptor(args->getObject("ItemDescriptor")));
- case PacketType::UpdateTileProtection: return make_shared<UpdateTileProtectionPacket>(args->getUInt("dungeonId"), args->getBool("protected"));
- case PacketType::SetDungeonGravity: return make_shared<SetDungeonGravityPacket>(args->getUInt("dungeonId"), args->getFloat("gravity"));
- case PacketType::SetDungeonBreathable: return make_shared<SetDungeonBreathablePacket>(args->getUInt("dungeonId"), args->getBool("breathable"));
- case PacketType::SetPlayerStart: return make_shared<SetPlayerStartPacket>(Vec2F{args->getArray("position")[0].toFloat(), args->getArray("position")[1].toFloat()}, args->getBool("respawnInWorld"));
- case PacketType::EntityMessage: return make_shared<EntityMessagePacket>(EntityId(args->getInt("entityId")), args->getString("message"), args->get("JsonArray").toArray(), Uuid(args->getString("Uuid")));
- case PacketType::UpdateWorldProperties: return make_shared<UpdateWorldPropertiesPacket>(args->getObject("updatedProperties"));
- default:
- throw StarPacketException(strf("Unrecognized packet type {}", (unsigned int)type));
- }
+ if (args && !args->isNull())
+ packet->readJson(*args);
+
+ return packet;
}
ProtocolRequestPacket::ProtocolRequestPacket()
@@ -265,6 +252,16 @@ void ChatReceivePacket::write(DataStream& ds) const {
ds.write(receivedMessage);
}
+void ChatReceivePacket::readJson(Json const& json) {
+ receivedMessage = ChatReceivedMessage(json.get("receivedMessage"));
+}
+
+Json ChatReceivePacket::writeJson() const {
+ return JsonObject{
+ {"receivedMessage", receivedMessage.toJson()}
+ };
+}
+
UniverseTimeUpdatePacket::UniverseTimeUpdatePacket() {
universeTime = 0;
}
@@ -344,6 +341,18 @@ void PausePacket::write(DataStream& ds) const {
ds.write(timescale);
}
+void PausePacket::readJson(Json const& json) {
+ pause = json.getBool("pause");
+ timescale = json.getFloat("timescale", 1.0f);
+}
+
+Json PausePacket::writeJson() const {
+ return JsonObject{
+ {"pause", pause},
+ {"timescale", timescale}
+ };
+}
+
ServerInfoPacket::ServerInfoPacket() {}
ServerInfoPacket::ServerInfoPacket(uint16_t players, uint16_t maxPlayers) :
@@ -362,6 +371,18 @@ void ServerInfoPacket::write(DataStream& ds) const
ds.write(maxPlayers);
}
+void ServerInfoPacket::readJson(Json const& json) {
+ players = json.getUInt("players");
+ maxPlayers = json.getUInt("maxPlayers");
+}
+
+Json ServerInfoPacket::writeJson() const {
+ return JsonObject{
+ {"players", players},
+ {"maxPlayers", maxPlayers}
+ };
+}
+
ClientConnectPacket::ClientConnectPacket() {}
ClientConnectPacket::ClientConnectPacket(ByteArray assetsDigest, bool allowAssetsMismatch, Uuid playerUuid,
@@ -676,6 +697,16 @@ void GiveItemPacket::write(DataStream& ds) const {
ds.write(item);
}
+void GiveItemPacket::readJson(Json const& json) {
+ item = ItemDescriptor(json.get("item"));
+}
+
+Json GiveItemPacket::writeJson() const {
+ return JsonObject{
+ {"item", item.toJson()}
+ };
+}
+
EnvironmentUpdatePacket::EnvironmentUpdatePacket() {}
EnvironmentUpdatePacket::EnvironmentUpdatePacket(ByteArray skyDelta, ByteArray weatherDelta)
@@ -1019,6 +1050,28 @@ void EntityMessagePacket::write(DataStream& ds) const {
ds.write(fromConnection);
}
+void EntityMessagePacket::readJson(Json const& json) {
+ auto jEntityId = json.get("entityId");
+ if (jEntityId.canConvert(Json::Type::Int))
+ entityId = (EntityId)jEntityId.toInt();
+ else
+ entityId = jEntityId.toString();
+ message = json.getString("message");
+ args = json.getArray("args");
+ uuid = Uuid(json.getString("uuid"));
+ fromConnection = json.getUInt("fromConnection");
+}
+
+Json EntityMessagePacket::writeJson() const {
+ return JsonObject{
+ {"entityId", entityId.is<EntityId>() ? Json(entityId.get<EntityId>()) : Json(entityId.get<String>())},
+ {"message", message},
+ {"args", args},
+ {"uuid", uuid.hex()},
+ {"fromConnection", fromConnection}
+ };
+}
+
EntityMessageResponsePacket::EntityMessageResponsePacket() {}
EntityMessageResponsePacket::EntityMessageResponsePacket(Either<String, Json> response, Uuid uuid)
@@ -1047,6 +1100,17 @@ void UpdateWorldPropertiesPacket::write(DataStream& ds) const {
ds.writeMapContainer(updatedProperties);
}
+
+void UpdateWorldPropertiesPacket::readJson(Json const& json) {
+ updatedProperties = json.getObject("updatedProperties");
+}
+
+Json UpdateWorldPropertiesPacket::writeJson() const {
+ return JsonObject{
+ {"updatedProperties", updatedProperties},
+ };
+}
+
UpdateTileProtectionPacket::UpdateTileProtectionPacket() {}
UpdateTileProtectionPacket::UpdateTileProtectionPacket(DungeonId dungeonId, bool isProtected)
@@ -1062,6 +1126,18 @@ void UpdateTileProtectionPacket::write(DataStream& ds) const {
ds.write(isProtected);
}
+void UpdateTileProtectionPacket::readJson(Json const& json) {
+ dungeonId = json.getUInt("dungeonId");
+ isProtected = json.getBool("isProtected");
+}
+
+Json UpdateTileProtectionPacket::writeJson() const {
+ return JsonObject{
+ {"dungeonId", dungeonId},
+ {"isProtected", isProtected}
+ };
+}
+
SetDungeonGravityPacket::SetDungeonGravityPacket() {}
SetDungeonGravityPacket::SetDungeonGravityPacket(DungeonId dungeonId, Maybe<float> gravity)
@@ -1077,6 +1153,18 @@ void SetDungeonGravityPacket::write(DataStream& ds) const {
ds.write(gravity);
}
+void SetDungeonGravityPacket::readJson(Json const& json) {
+ dungeonId = json.getUInt("dungeonId");
+ gravity = json.optFloat("gravity");
+}
+
+Json SetDungeonGravityPacket::writeJson() const {
+ return JsonObject{
+ {"dungeonId", dungeonId},
+ {"gravity", jsonFromMaybe<float>(gravity)}
+ };
+}
+
SetDungeonBreathablePacket::SetDungeonBreathablePacket() {}
SetDungeonBreathablePacket::SetDungeonBreathablePacket(DungeonId dungeonId, Maybe<bool> breathable)
@@ -1092,6 +1180,18 @@ void SetDungeonBreathablePacket::write(DataStream& ds) const {
ds.write(breathable);
}
+void SetDungeonBreathablePacket::readJson(Json const& json) {
+ dungeonId = json.getUInt("dungeonId");
+ breathable = json.optBool("breathable");
+}
+
+Json SetDungeonBreathablePacket::writeJson() const {
+ return JsonObject{
+ {"dungeonId", dungeonId},
+ {"breathable", jsonFromMaybe<bool>(breathable)}
+ };
+}
+
SetPlayerStartPacket::SetPlayerStartPacket() {}
SetPlayerStartPacket::SetPlayerStartPacket(Vec2F playerStart, bool respawnInWorld) : playerStart(playerStart), respawnInWorld(respawnInWorld) {}
@@ -1106,6 +1206,18 @@ void SetPlayerStartPacket::write(DataStream& ds) const {
ds.write(respawnInWorld);
}
+void SetPlayerStartPacket::readJson(Json const& json) {
+ playerStart = jsonToVec2F(json.get("playerStart"));
+ respawnInWorld = json.getBool("respawnInWorld");
+}
+
+Json SetPlayerStartPacket::writeJson() const {
+ return JsonObject{
+ {"playerStart", jsonFromVec2F(playerStart)},
+ {"respawnInWorld", respawnInWorld}
+ };
+}
+
FindUniqueEntityResponsePacket::FindUniqueEntityResponsePacket() {}
FindUniqueEntityResponsePacket::FindUniqueEntityResponsePacket(String uniqueEntityId, Maybe<Vec2F> entityPosition)
diff --git a/source/game/StarNetPackets.hpp b/source/game/StarNetPackets.hpp
index 7c76037..71ab09f 100644
--- a/source/game/StarNetPackets.hpp
+++ b/source/game/StarNetPackets.hpp
@@ -132,6 +132,9 @@ struct Packet {
virtual void writeLegacy(DataStream& ds) const;
virtual void write(DataStream& ds) const = 0;
+ virtual void readJson(Json const& json);
+ virtual Json writeJson() const;
+
PacketCompressionMode compressionMode() const;
void setCompressionMode(PacketCompressionMode compressionMode);
@@ -216,6 +219,9 @@ struct ChatReceivePacket : PacketBase<PacketType::ChatReceive> {
void read(DataStream& ds) override;
void write(DataStream& ds) const override;
+ void readJson(Json const& json) override;
+ Json writeJson() const override;
+
ChatReceivedMessage receivedMessage;
};
@@ -271,8 +277,11 @@ struct PausePacket : PacketBase<PacketType::Pause> {
void writeLegacy(DataStream& ds) const override;
void write(DataStream& ds) const override;
- bool pause;
- float timescale;
+ void readJson(Json const& json) override;
+ Json writeJson() const override;
+
+ bool pause = false;
+ float timescale = 1.0f;
};
struct ServerInfoPacket : PacketBase<PacketType::ServerInfo> {
@@ -282,6 +291,9 @@ struct ServerInfoPacket : PacketBase<PacketType::ServerInfo> {
void read(DataStream& ds) override;
void write(DataStream& ds) const override;
+ void readJson(Json const& json) override;
+ Json writeJson() const override;
+
uint16_t players;
uint16_t maxPlayers;
};
@@ -505,6 +517,9 @@ struct GiveItemPacket : PacketBase<PacketType::GiveItem> {
void read(DataStream& ds) override;
void write(DataStream& ds) const override;
+ void readJson(Json const& json) override;
+ Json writeJson() const override;
+
ItemDescriptor item;
};
@@ -526,6 +541,9 @@ struct UpdateTileProtectionPacket : PacketBase<PacketType::UpdateTileProtection>
void read(DataStream& ds) override;
void write(DataStream& ds) const override;
+ void readJson(Json const& json) override;
+ Json writeJson() const override;
+
DungeonId dungeonId;
bool isProtected;
};
@@ -537,6 +555,9 @@ struct SetDungeonGravityPacket : PacketBase<PacketType::SetDungeonGravity> {
void read(DataStream& ds) override;
void write(DataStream& ds) const override;
+ void readJson(Json const& json) override;
+ Json writeJson() const override;
+
DungeonId dungeonId;
Maybe<float> gravity;
};
@@ -548,6 +569,9 @@ struct SetDungeonBreathablePacket : PacketBase<PacketType::SetDungeonBreathable>
void read(DataStream& ds) override;
void write(DataStream& ds) const override;
+ void readJson(Json const& json) override;
+ Json writeJson() const override;
+
DungeonId dungeonId;
Maybe<bool> breathable;
};
@@ -559,6 +583,9 @@ struct SetPlayerStartPacket : PacketBase<PacketType::SetPlayerStart> {
void read(DataStream& ds) override;
void write(DataStream& ds) const override;
+ void readJson(Json const& json) override;
+ Json writeJson() const override;
+
Vec2F playerStart;
bool respawnInWorld;
};
@@ -795,6 +822,9 @@ struct EntityMessagePacket : PacketBase<PacketType::EntityMessage> {
void read(DataStream& ds) override;
void write(DataStream& ds) const override;
+ void readJson(Json const& json) override;
+ Json writeJson() const override;
+
Variant<EntityId, String> entityId;
String message;
JsonArray args;
@@ -820,6 +850,9 @@ struct UpdateWorldPropertiesPacket : PacketBase<PacketType::UpdateWorldPropertie
void read(DataStream& ds) override;
void write(DataStream& ds) const override;
+ void readJson(Json const& json) override;
+ Json writeJson() const override;
+
JsonObject updatedProperties;
};