[docs/network-protocol.md] Added.

master
Quentin Bazin 2020-06-19 17:18:18 +02:00
parent 7e9d26b92b
commit cc85f5f050
14 changed files with 345 additions and 73 deletions

View File

@ -33,7 +33,7 @@ The long-term goal of this project is to provide a viable alternative to Minecra
- [Mod API](https://openminer.readthedocs.io/en/latest/lua-api-mod/)
- [GUI API](https://openminer.readthedocs.io/en/latest/lua-api-gui/)
- [C++ classes in Lua](https://openminer.readthedocs.io/en/latest/lua-api-cpp/)
- [Network Protocol](https://github.com/Unarelith/OpenMiner/wiki/Network-Protocol)
- [Network Protocol](https://openminer.readthedocs.io/en/latest/network-protocol/)
## Keys

View File

@ -20,3 +20,7 @@
- [Progress bar](lua-api-gui-progress-bar.md)
- [Scroll bar](lua-api-gui-scroll-bar.md)
# Misc
- [Network Protocol](network-protocol.md)

282
docs/network-protocol.md Normal file
View File

@ -0,0 +1,282 @@
# Network Protocol
**Note:** All packets are sent using TCP only.
## Integer types
Integer types are represented with `s8`/`s16`/`s32`/`s64` and `u8`/`u16`/`u32`/`u64`.
The `s`/`u` means `signed`/`unsigned` and the number is the size of the type in bits.
## Login
### Clientbound
#### ClientOk
Packet sent from a server to accept a connection.
| Field name | Field type | Notes |
| ------------- | ---------- | ---------------------------------------------------- |
| Client ID | u16 | ID assigned by the server for this client |
| Singleplayer? | bool | Whether or not the server runs a singleplayer game |
#### ClientRefused
Packet sent from a server to refuse a connection.
_This packet has no field._
### Serverbound
#### ClientConnect
Packet sent from a client attempting to connect.
_This packet has no field._
#### ClientDisconnect
Packet sent from a client attempting to disconnect.
_This packet has no field._
## Game
### Clientbound
#### ServerClosed
| Field name | Field type | Notes |
| ------------- | ----------- | ---------------------------------------------------- |
| Message | std::string | Why the server has been closed |
#### ChunkData
| Field name | Field type | Notes |
| ------------- | ----------- | ---------------------------------------------------- |
| Chunk X | s32 | Chunk X coordinate |
| Chunk Y | s32 | Chunk Y coordinate |
| Chunk Z | s32 | Chunk Z coordinate |
| Array | | |
| - Block data | u32 | Block ID and data |
| - Light value | u8 | Sunlight and torchlight values |
#### PlayerInvUpdate (clientbound)
| Field name | Field type | Notes |
| ------------- | ----------- | ---------------------------------------------------- |
| ID | u16 | Player ID |
| Inventory | Inventory | Player inventory |
#### PlayerPosUpdate (clientbound)
| Field name | Field type | Notes |
| -------------- | ----------- | ---------------------------------------------------- |
| ID | u16 | Player ID |
| Player X | double | Player X coordinate |
| Player Y | double | Player Y coordinate |
| Player Z | double | Player Z coordinate |
| Teleportation? | bool | Whether or not this update is a teleportation |
#### PlayerSpawn
| Field name | Field type | Notes |
| -------------- | ----------- | ---------------------------------------------------- |
| ID | u16 | Player ID |
| Player X | double | Player X coordinate |
| Player Y | double | Player Y coordinate |
| Player Z | double | Player Z coordinate |
#### PlayerChangeDimension
| Field name | Field type | Notes |
| ------------- | ----------- | ---------------------------------------------------- |
| ID | u16 | Player ID |
| Spawn X | s32 | Spawn X coordinate in the new dimension |
| Spawn Y | s32 | Spawn Y coordinate in the new dimension |
| Spawn Z | s32 | Spawn Z coordinate in the new dimension |
| Dimension | u16 | New dimension ID |
#### BlockUpdate
| Field name | Field type | Notes |
| ------------- | ----------- | ---------------------------------------------------- |
| Block X | s32 | Block X coordinate |
| Block Y | s32 | Block Y coordinate |
| Block Z | s32 | Block Z coordinate |
| Block ID | u32 | Block ID and data |
#### BlockGUIData
| Field name | Field type | Notes |
| ------------- | ----------- | ---------------------------------------------------- |
| Width | u16 | Width of the GUI |
| Height | u16 | Height of the GUI |
| Centered? | bool | Whether or not the GUI is centered on the screen |
| Widget defs | Array | List of widget definitions (see LuaGUI::show) |
#### BlockInvUpdate (clientbound)
| Field name | Field type | Notes |
| ------------- | ----------- | ---------------------------------------------------- |
| Block X | s32 | Block X coordinate |
| Block Y | s32 | Block Y coordinate |
| Block Z | s32 | Block Z coordinate |
| Inventory | Inventory | Block inventory |
#### BlockDataUpdate
| Field name | Field type | Notes |
| -------------- | ------------- | ----------------------------------------------------- |
| Block X | s32 | Block X coordinate |
| Block Y | s32 | Block Y coordinate |
| Block Z | s32 | Block Z coordinate |
| Metadata | BlockMetadata | Block metadata |
| Use alt tiles? | bool | Whether or not the block should use alternative tiles |
#### RegistryData
| Field name | Field type | Notes |
| -------------- | ------------- | ----------------------------------------------------- |
| Registry | Registry | Registry |
#### ChatMessage (clientbound)
| Field name | Field type | Notes |
| ------------- | ----------- | ---------------------------------------------------- |
| ID | u16 | Player ID (`0` means it's a server message) |
| Message | std::string | Message sent by the client |
#### EntitySpawn
| Field name | Field type | Notes |
| ------------- | ------------ | ---------------------------------------------------- |
| ID | entt::entity | Entity ID |
#### EntityDespawn
| Field name | Field type | Notes |
| ------------- | ------------ | ---------------------------------------------------- |
| ID | entt::entity | Entity ID |
#### EntityPosition
| Field name | Field type | Notes |
| ------------- | ------------ | ---------------------------------------------------- |
| ID | entt::entity | Entity ID |
| Entity X | double | Entity X coordinate |
| Entity Y | double | Entity Y coordinate |
| Entity Z | double | Entity Z coordinate |
#### EntityRotation
| Field name | Field type | Notes |
| --------------- | ------------ | ---------------------------------------------------- |
| ID | entt::entity | Entity ID |
| Rotation | glm::quat4 | Entity rotation quaternion |
#### EntityAnimation
| Field name | Field type | Notes |
| ------------- | ------------------ | ---------------------------------------------------- |
| ID | entt::entity | Entity ID |
| Animation | AnimationComponent | Entity animation data |
#### EntityDrawableDef
| Field name | Field type | Notes |
| ------------- | ------------------ | ---------------------------------------------------- |
| ID | entt::entity | Entity ID |
| Drawable def | DrawableDef | Entity drawable component definition |
### Serverbound
#### ChunkRequest
| Field name | Field type | Notes |
| ------------- | ----------- | ---------------------------------------------------- |
| Chunk X | s32 | Chunk X coordinate |
| Chunk Y | s32 | Chunk Y coordinate |
| Chunk Z | s32 | Chunk Z coordinate |
#### PlayerPlaceBlock
| Field name | Field type | Notes |
| ------------- | ----------- | ---------------------------------------------------- |
| Block X | s32 | Block X coordinate |
| Block Y | s32 | Block Y coordinate |
| Block Z | s32 | Block Z coordinate |
| Block ID | u32 | Block ID and data |
#### PlayerDigBlock
| Field name | Field type | Notes |
| ------------- | ----------- | ---------------------------------------------------- |
| Block X | s32 | Block X coordinate |
| Block Y | s32 | Block Y coordinate |
| Block Z | s32 | Block Z coordinate |
#### PlayerInvUpdate (serverbound)
| Field name | Field type | Notes |
| ------------- | ----------- | ---------------------------------------------------- |
| Inventory | Inventory | Player inventory |
#### PlayerPosUpdate (serverbound)
| Field name | Field type | Notes |
| ------------- | ----------- | ---------------------------------------------------- |
| Player X | double | Player X coordinate |
| Player Y | double | Player Y coordinate |
| Player Z | double | Player Z coordinate |
#### PlayerRotUpdate
| Field name | Field type | Notes |
| ------------- | ----------- | ---------------------------------------------------- |
| Camera Yaw | float | Horizontal camera view angle |
| Camera Pitch | float | Vertical camera view angle |
#### PlayerHeldItemChanged
| Field name | Field type | Notes |
| ------------- | ----------- | ---------------------------------------------------- |
| Hotbar slot | u8 | ID of the current hotbar slot |
| Item ID | u16 | Current item ID (to check match with server) |
#### BlockActivated
| Field name | Field type | Notes |
| ------------- | ----------- | ---------------------------------------------------- |
| Block X | s32 | Block X coordinate |
| Block Y | s32 | Block Y coordinate |
| Block Z | s32 | Block Z coordinate |
| Screen width | u16 | Client screen width |
| Screen height | u16 | Client screen height |
| GUI scale | u8 | Client GUI scale |
#### BlockInvUpdate (serverbound)
| Field name | Field type | Notes |
| ------------- | ----------- | ---------------------------------------------------- |
| Block X | s32 | Block X coordinate |
| Block Y | s32 | Block Y coordinate |
| Block Z | s32 | Block Z coordinate |
| Inventory | Inventory | Block inventory |
#### ChatMessage (serverbound)
| Field name | Field type | Notes |
| ------------- | ----------- | ---------------------------------------------------- |
| Message | std::string | Message sent by the client |
#### KeyPressed
| Field name | Field type | Notes |
| ------------- | ----------- | ---------------------------------------------------- |
| Key ID | u16 | Key ID in the registry |
| Screen width | u16 | Client screen width |
| Screen height | u16 | Client screen height |
| GUI scale | u8 | Client GUI scale |

5
docs/script.js Normal file
View File

@ -0,0 +1,5 @@
document.addEventListener("DOMContentLoaded", function() {
document.querySelectorAll("table").forEach(function(table) {
table.classList.add("docutils");
});
});

View File

@ -24,6 +24,8 @@ nav:
- 'Inventory widget': 'lua-api-gui-inventory.md'
- 'Progress bar': 'lua-api-gui-progress-bar.md'
- 'Scroll bar': 'lua-api-gui-scroll-bar.md'
- 'Misc':
- 'Network Protocol': 'network-protocol.md'
theme:
name: readthedocs
@ -31,3 +33,6 @@ theme:
hljs_languages:
- lua
extra_javascript:
- script.js

View File

@ -1 +1 @@
mkdocs==1.1
mkdocs==1.1.2

View File

@ -40,7 +40,7 @@ void Client::connect(sf::IpAddress serverAddress, u16 serverPort) {
throw ClientConnectException("Network error: Unable to connect to server " + serverAddress.toString() + ":" + std::to_string(serverPort));
Network::Packet packet;
packet << Network::Command::ClientConnect << sf::IpAddress::getLocalAddress().toString();
packet << Network::Command::ClientConnect;
m_tcpSocket->send(packet);
Network::Packet answer;

View File

@ -46,8 +46,6 @@
void ClientCommandHandler::sendPlayerInvUpdate() {
Network::Packet invPacket;
invPacket << Network::Command::PlayerInvUpdate;
// FIXME: Sending client id shouldn't be necessary when sending this packet from client
invPacket << m_client.id();
invPacket << m_player.inventory();
m_client.send(invPacket);
}
@ -55,20 +53,15 @@ void ClientCommandHandler::sendPlayerInvUpdate() {
void ClientCommandHandler::sendPlayerPosUpdate() {
Network::Packet packet;
packet << Network::Command::PlayerPosUpdate;
// FIXME: Sending client id shouldn't be necessary when sending this packet from client
packet << m_client.id();
packet << m_player.x();
packet << m_player.y();
packet << m_player.z();
packet << false;
m_client.send(packet);
}
void ClientCommandHandler::sendPlayerRotUpdate() {
Network::Packet packet;
packet << Network::Command::PlayerRotUpdate;
// FIXME: Sending client id shouldn't be necessary when sending this packet from client
packet << m_client.id();
packet << m_player.cameraYaw();
packet << m_player.cameraPitch();
m_client.send(packet);
@ -124,8 +117,6 @@ void ClientCommandHandler::sendChunkRequest(s32 chunkX, s32 chunkY, s32 chunkZ)
void ClientCommandHandler::sendChatMessage(const std::string &message) {
Network::Packet packet;
packet << Network::Command::ChatMessage;
// FIXME: Sending client id shouldn't be necessary
packet << m_client.id();
packet << message;
m_client.send(packet);
}
@ -133,7 +124,7 @@ void ClientCommandHandler::sendChatMessage(const std::string &message) {
void ClientCommandHandler::sendKeyPressed(u16 keyID) {
Network::Packet packet;
packet << Network::Command::KeyPressed << keyID
<< Config::screenWidth << Config::screenHeight << Config::guiScale;
<< u16(Config::screenWidth) << u16(Config::screenHeight) << u8(Config::guiScale);
m_client.send(packet);
}

View File

@ -29,56 +29,57 @@
#include "CompressedPacket.hpp"
// Please update 'docs/network-protocol.md' if you change this
namespace Network {
using Packet = CompressedPacket;
enum class Command {
// Client commands
ClientConnect = 0x00, // <TCP> [NetworkCommand] (from Client only)
ClientDisconnect = 0x01, // <TCP> [NetworkCommand] (from Client only)
ClientOk = 0x02, // <TCP> [NetworkCommand][u16 client id][bool isSingleplayer] (from Server only)
ClientRefused = 0x03, // <TCP> [NetworkCommand] (from Server only)
ClientConnect = 0x00,
ClientDisconnect = 0x01,
ClientOk = 0x02,
ClientRefused = 0x03,
// Server commands
ServerClosed = 0x04, // <TCP> [NetworkCommand][string message] (from Server only)
ServerClosed = 0x04,
// Chunk commands
ChunkData = 0x05, // <TCP> [NetworkCommand][s32 cx, cy, cz][u32...] (from Server only)
ChunkRequest = 0x06, // <TCP> [NetworkCommand][s32 cx, cy, cz] (from Client only)
ChunkData = 0x05,
ChunkRequest = 0x06,
// Player commands
PlayerPlaceBlock = 0x07, // <TCP> [NetworkCommand][s32 x, y, z][u32 block] (from Client only)
PlayerDigBlock = 0x08, // <TCP> [NetworkCommand][s32 x, y, z] (from Client only)
PlayerInvUpdate = 0x09, // <TCP> [NetworkCommand][u16 client id][[std::string item][u16 amount][u8 x, y]...] (both) [FIXME]
PlayerPosUpdate = 0x0a, // <TCP> [NetworkCommand][u16 client id][s32 x, y, z][bool isTeleportation] (both) // FIXME
PlayerRotUpdate = 0x0b, // <TCP> [NetworkCommand][u16 client id][float yaw][float pitch] (from Client only)
PlayerSpawn = 0x0c, // <TCP> [NetworkCommand][u16 client id][s32 x, y, z] (from Server only)
PlayerChangeDimension = 0x0d, // <TCP> [NetworkCommand][u16 client id][s32 x, y, z][u16 dimension] (from Server only)
PlayerHeldItemChanged = 0x0e, // <TCP> [NetworkCommand][u8 hotbar slot][u16 item id (to check match with server)] (from Client only)
PlayerPlaceBlock = 0x07,
PlayerDigBlock = 0x08,
PlayerInvUpdate = 0x09,
PlayerPosUpdate = 0x0a,
PlayerRotUpdate = 0x0b,
PlayerSpawn = 0x0c,
PlayerChangeDimension = 0x0d,
PlayerHeldItemChanged = 0x0e,
// Block commands
BlockUpdate = 0x0f, // <TCP> [NetworkCommand][s32 x, y, z][u32 block] (from Server only)
BlockActivated = 0x10, // <TCP> [NetworkCommand][s32 x, y, z][u16 screenWidth, screenHeight][u8 guiScale] (from Client only)
BlockGUIData = 0x11, // <TCP> [NetworkCommand][LuaGUIData data] (from Server only)
BlockInvUpdate = 0x12, // <TCP> [NetworkCommand][s32 x, y, z][[std::string item][u16 amount][u8 x, y]...] (both) [FIXME]
BlockDataUpdate = 0x13, // <TCP> [NetworkCommand][s32 x, y, z][u64 data] (both) [FIXME]
BlockUpdate = 0x0f,
BlockActivated = 0x10,
BlockGUIData = 0x11,
BlockInvUpdate = 0x12,
BlockDataUpdate = 0x13,
// Registry commands
RegistryData = 0x14, // <TCP> [NetworkCommand][Block block] (from Server only)
RegistryData = 0x14,
// Chat commands
ChatMessage = 0x15, // <TCP> [NetworkCommand][u16 client id][std::string message] (both)
ChatMessage = 0x15,
// Entity commands
EntitySpawn = 0x16, // <TCP> [NetworkCommand][u32 entity id] (from Server only)
EntityDespawn = 0x17, // <TCP> [NetworkCommand][u32 entity id] (from Server only)
EntityPosition = 0x18, // <TCP> [NetworkCommand][u32 entity id][double x, double y, double z] (from Server only)
EntityRotation = 0x19, // <TCP> [NetworkCommand][u32 entity id][float w, float x, float y, float z] (from Server only)
EntityAnimation = 0x1a, // <TCP> [NetworkCommand][u32 entity id][AnimationComponent anim] (from Server only)
EntityDrawableDef = 0x1b, // <TCP> [NetworkCommand][u32 entity id][DrawableDef def] (from Server only)
EntitySpawn = 0x16,
EntityDespawn = 0x17,
EntityPosition = 0x18,
EntityRotation = 0x19,
EntityAnimation = 0x1a,
EntityDrawableDef = 0x1b,
// Key commands
KeyPressed = 0x1c, // <TCP> [NetworkCommand][u16 key id][u16 screenWidth, screenHeight][u8 guiScale] (from Client only)
KeyPressed = 0x1c,
};
std::string commandToString(Command command);

View File

@ -35,14 +35,12 @@
class ClientInfo {
public:
ClientInfo(u16 _id, sf::IpAddress _address, const std::shared_ptr<sf::TcpSocket> &socket)
: id(_id), address(_address), tcpSocket(socket) {}
ClientInfo(u16 _id, const std::shared_ptr<sf::TcpSocket> &socket)
: id(_id), tcpSocket(socket) {}
u16 id;
bool isReady = false;
sf::IpAddress address;
u32 previousKeyTimestamp = 0;
std::shared_ptr<sf::TcpSocket> tcpSocket;

View File

@ -60,10 +60,7 @@ void Server::handleNewConnections() {
if (command != Network::Command::ClientConnect)
gkError() << "Network error: Expected 'ClientConnect' packet for new clients.";
else if (m_info.clients().size() < ServerConfig::maxPlayers) {
std::string address;
packet >> address;
ClientInfo &client = m_info.addClient(address, clientSocket);
ClientInfo &client = m_info.addClient(clientSocket);
m_selector.add(*client.tcpSocket);
Network::Packet outPacket;

View File

@ -212,14 +212,9 @@ void ServerCommandHandler::setupCallbacks() {
});
m_server.setCommandCallback(Network::Command::PlayerInvUpdate, [this](ClientInfo &client, Network::Packet &packet) {
u16 clientId;
packet >> clientId;
ServerPlayer *player = m_players.getPlayer(clientId);
ServerPlayer *player = m_players.getPlayer(client.id);
if (player) {
if (clientId == client.id) {
packet >> player->inventory();
}
packet >> player->inventory();
}
else
gkError() << ("Failed to update inventory of player " + std::to_string(client.id) + ": Player not found").c_str();
@ -227,28 +222,23 @@ void ServerCommandHandler::setupCallbacks() {
m_server.setCommandCallback(Network::Command::PlayerPosUpdate, [this](ClientInfo &client, Network::Packet &packet) {
double x, y, z;
u16 clientId;
packet >> clientId;
packet >> x >> y >> z;
ServerPlayer *player = m_players.getPlayer(clientId);
ServerPlayer *player = m_players.getPlayer(client.id);
if (player) {
if (clientId == client.id)
player->setPosition(x, y, z);
player->setPosition(x, y, z);
}
else
gkError() << ("Failed to update position of player " + std::to_string(client.id) + ": Player not found").c_str();
});
m_server.setCommandCallback(Network::Command::PlayerRotUpdate, [this](ClientInfo &client, Network::Packet &packet) {
u16 clientId;
float yaw, pitch;
packet >> clientId >> yaw >> pitch;
packet >> yaw >> pitch;
ServerPlayer *player = m_players.getPlayer(client.id);
if (player) {
if (clientId == client.id)
player->setRotation(yaw, pitch);
player->setRotation(yaw, pitch);
}
else
gkError() << ("Failed to update rotation of player " + std::to_string(client.id) + ": Player not found").c_str();
@ -354,15 +344,14 @@ void ServerCommandHandler::setupCallbacks() {
});
m_server.setCommandCallback(Network::Command::ChatMessage, [this](ClientInfo &client, Network::Packet &packet) {
u16 clientID;
std::string message;
packet >> clientID >> message;
packet >> message;
if (message[0] != '/' || (message.length() > 1 && message[1] == '/')) {
if (message[0] == '/' && message.length() > 1 && message[1] == '/')
sendChatMessage(clientID, message.substr(1));
sendChatMessage(client.id, message.substr(1));
else
sendChatMessage(clientID, message);
sendChatMessage(client.id, message);
}
else {
m_chatCommandHandler.parseCommand(message.substr(1), client);

View File

@ -26,8 +26,8 @@
*/
#include "ServerInfo.hpp"
ClientInfo &ServerInfo::addClient(sf::IpAddress address, const std::shared_ptr<sf::TcpSocket> &socket) {
m_clients.emplace_back(m_clients.size() + 1, address, socket);
ClientInfo &ServerInfo::addClient(const std::shared_ptr<sf::TcpSocket> &socket) {
m_clients.emplace_back(m_clients.size() + 1, socket);
return m_clients.back();
}

View File

@ -36,7 +36,7 @@
class ServerInfo {
public:
ClientInfo &addClient(sf::IpAddress address, const std::shared_ptr<sf::TcpSocket> &socket);
ClientInfo &addClient(const std::shared_ptr<sf::TcpSocket> &socket);
ClientInfo *getClient(u16 id);
void removeClient(u16 id);