summaryrefslogtreecommitdiffstats
path: root/src/Protocol
diff options
context:
space:
mode:
authorMattes D <github@xoft.cz>2020-01-03 17:31:13 +0100
committerMattes D <github@xoft.cz>2020-01-07 06:53:17 +0100
commit4aef80b47eb6941d7fc41e57efe147af0ece1f9b (patch)
tree4aeb7c9e8e4aa3ae2ceed1cc60155d868852c5cd /src/Protocol
parentStringUtils: Added note to StringsConcat about StringJoin. (diff)
downloadcuberite-4aef80b47eb6941d7fc41e57efe147af0ece1f9b.tar
cuberite-4aef80b47eb6941d7fc41e57efe147af0ece1f9b.tar.gz
cuberite-4aef80b47eb6941d7fc41e57efe147af0ece1f9b.tar.bz2
cuberite-4aef80b47eb6941d7fc41e57efe147af0ece1f9b.tar.lz
cuberite-4aef80b47eb6941d7fc41e57efe147af0ece1f9b.tar.xz
cuberite-4aef80b47eb6941d7fc41e57efe147af0ece1f9b.tar.zst
cuberite-4aef80b47eb6941d7fc41e57efe147af0ece1f9b.zip
Diffstat (limited to 'src/Protocol')
-rw-r--r--src/Protocol/CMakeLists.txt2
-rw-r--r--src/Protocol/ChunkDataSerializer.cpp33
-rw-r--r--src/Protocol/ChunkDataSerializer.h54
-rw-r--r--src/Protocol/Protocol.h5
-rw-r--r--src/Protocol/ProtocolPalettes.cpp107
-rw-r--r--src/Protocol/ProtocolPalettes.h63
-rw-r--r--src/Protocol/ProtocolRecognizer.cpp19
-rw-r--r--src/Protocol/Protocol_1_13.cpp35
-rw-r--r--src/Protocol/Protocol_1_13.h23
-rw-r--r--src/Protocol/Protocol_1_8.cpp2
-rw-r--r--src/Protocol/Protocol_1_9.cpp4
11 files changed, 297 insertions, 50 deletions
diff --git a/src/Protocol/CMakeLists.txt b/src/Protocol/CMakeLists.txt
index 3e8d65b94..f2169ce86 100644
--- a/src/Protocol/CMakeLists.txt
+++ b/src/Protocol/CMakeLists.txt
@@ -12,6 +12,7 @@ SET (SRCS
Protocol_1_11.cpp
Protocol_1_12.cpp
Protocol_1_13.cpp
+ ProtocolPalettes.cpp
ProtocolRecognizer.cpp
)
@@ -28,6 +29,7 @@ SET (HDRS
Protocol_1_11.h
Protocol_1_12.h
Protocol_1_13.h
+ ProtocolPalettes.h
ProtocolRecognizer.h
)
diff --git a/src/Protocol/ChunkDataSerializer.cpp b/src/Protocol/ChunkDataSerializer.cpp
index 23d5b19ae..ea688ebd8 100644
--- a/src/Protocol/ChunkDataSerializer.cpp
+++ b/src/Protocol/ChunkDataSerializer.cpp
@@ -1,10 +1,3 @@
-
-// ChunkDataSerializer.cpp
-
-// Implements the cChunkDataSerializer class representing the object that can:
-// - serialize chunk data to different protocol versions
-// - cache such serialized data for multiple clients
-
#include "Globals.h"
#include "ChunkDataSerializer.h"
#include "zlib/zlib.h"
@@ -52,7 +45,7 @@ cChunkDataSerializer::cChunkDataSerializer(
-const AString & cChunkDataSerializer::Serialize(int a_Version, int a_ChunkX, int a_ChunkZ)
+const AString & cChunkDataSerializer::Serialize(int a_Version, int a_ChunkX, int a_ChunkZ, const std::map<UInt32, UInt32> & a_BlockTypeMap)
{
Serializations::const_iterator itr = m_Serializations.find(a_Version);
if (itr != m_Serializations.end())
@@ -63,11 +56,10 @@ const AString & cChunkDataSerializer::Serialize(int a_Version, int a_ChunkX, int
AString data;
switch (a_Version)
{
- case RELEASE_1_8_0: Serialize47(data, a_ChunkX, a_ChunkZ); break;
+ case RELEASE_1_8_0: Serialize47 (data, a_ChunkX, a_ChunkZ); break;
case RELEASE_1_9_0: Serialize107(data, a_ChunkX, a_ChunkZ); break;
case RELEASE_1_9_4: Serialize110(data, a_ChunkX, a_ChunkZ); break;
- case RELEASE_1_13: Serialize393(data, a_ChunkX, a_ChunkZ); break;
- // TODO: Other protocol versions may serialize the data differently; implement here
+ case RELEASE_1_13: Serialize393(data, a_ChunkX, a_ChunkZ, a_BlockTypeMap); break;
default:
{
@@ -442,10 +434,12 @@ void cChunkDataSerializer::Serialize110(AString & a_Data, int a_ChunkX, int a_Ch
-void cChunkDataSerializer::Serialize393(AString & a_Data, int a_ChunkX, int a_ChunkZ)
+void cChunkDataSerializer::Serialize393(AString & a_Data, int a_ChunkX, int a_ChunkZ, const std::map<UInt32, UInt32> & a_BlockTypeMap)
{
// This function returns the fully compressed packet (including packet size), not the raw packet!
+ ASSERT(!a_BlockTypeMap.empty()); // We need a protocol-specific translation map
+
// Create the packet:
cByteBuffer Packet(512 KiB);
Packet.WriteVarInt32(0x22); // Packet id (Chunk Data packet)
@@ -489,17 +483,10 @@ void cChunkDataSerializer::Serialize393(AString & a_Data, int a_ChunkX, int a_Ch
for (size_t Index = 0; Index < cChunkData::SectionBlockCount; Index++)
{
- UInt64 Value = a_Section.m_BlockTypes[Index];
- /*
- if (Index % 2 == 0)
- {
- Value |= a_Section.m_BlockMetas[Index / 2] & 0x0f;
- }
- else
- {
- Value |= a_Section.m_BlockMetas[Index / 2] >> 4;
- }
- */
+ UInt32 blockType = a_Section.m_BlockTypes[Index];
+ UInt32 blockMeta = (a_Section.m_BlockMetas[Index / 2] >> ((Index % 2) * 4)) & 0x0f;
+ auto itr = a_BlockTypeMap.find(blockType * 16 | blockMeta);
+ UInt64 Value = (itr == a_BlockTypeMap.end()) ? 0 :itr->second;
Value &= Mask; // It shouldn't go out of bounds, but it's still worth being careful
// Painful part where we write data into the long array. Based off of the normal code.
diff --git a/src/Protocol/ChunkDataSerializer.h b/src/Protocol/ChunkDataSerializer.h
index 7011d3e15..a77935258 100644
--- a/src/Protocol/ChunkDataSerializer.h
+++ b/src/Protocol/ChunkDataSerializer.h
@@ -1,31 +1,16 @@
-
-// ChunkDataSerializer.h
-
-// Interfaces to the cChunkDataSerializer class representing the object that can:
-// - serialize chunk data to different protocol versions
-// - cache such serialized data for multiple clients
+#pragma once
#include "../ChunkData.h"
+
+/** Serializes one chunk's data to (possibly multiple) protocol versions.
+Caches the serialized data for as long as this object lives, so that the same data can be sent to
+other clients using the same protocol. */
class cChunkDataSerializer
{
-protected:
- const cChunkData & m_Data;
- const unsigned char * m_BiomeData;
- const eDimension m_Dimension;
-
- typedef std::map<int, AString> Serializations;
-
- Serializations m_Serializations;
-
- void Serialize47 (AString & a_Data, int a_ChunkX, int a_ChunkZ); // Release 1.8
- void Serialize107(AString & a_Data, int a_ChunkX, int a_ChunkZ); // Release 1.9
- void Serialize110(AString & a_Data, int a_ChunkX, int a_ChunkZ); // Release 1.9.4
- void Serialize393(AString & a_Data, int a_ChunkX, int a_ChunkZ); // Release 1.13
-
public:
enum
{
@@ -41,7 +26,34 @@ public:
const eDimension a_Dimension
);
- const AString & Serialize(int a_Version, int a_ChunkX, int a_ChunkZ); // Returns one of the internal m_Serializations[]
+ /** Serializes the contained chunk data into the specified protocol version.
+ TEMPORARY: a_BlockTypeMap is used for the 1.13+ protocols to map from BLOCKTYPE#META to NetBlockID.
+ a_BlockTypeMap is ignored for pre-1.13 protocols. */
+ const AString & Serialize(int a_Version, int a_ChunkX, int a_ChunkZ, const std::map<UInt32, UInt32> & a_BlockTypeMap);
+
+
+protected:
+
+ using Serializations = std::map<int, AString>;
+
+
+ /** The data read from the chunk, to be serialized. */
+ const cChunkData & m_Data;
+
+ /** The biomes in the chunk, to be serialized. */
+ const unsigned char * m_BiomeData;
+
+ /** The dimension where the chunk resides. */
+ const eDimension m_Dimension;
+
+ /** The per-protocol serialized data, cached for reuse for other clients. */
+ Serializations m_Serializations;
+
+
+ void Serialize47 (AString & a_Data, int a_ChunkX, int a_ChunkZ); // Release 1.8
+ void Serialize107(AString & a_Data, int a_ChunkX, int a_ChunkZ); // Release 1.9
+ void Serialize110(AString & a_Data, int a_ChunkX, int a_ChunkZ); // Release 1.9.4
+ void Serialize393(AString & a_Data, int a_ChunkX, int a_ChunkZ, const std::map<UInt32, UInt32> & a_BlockTypeMap); // Release 1.13
} ;
diff --git a/src/Protocol/Protocol.h b/src/Protocol/Protocol.h
index 8707c3326..c71b295ad 100644
--- a/src/Protocol/Protocol.h
+++ b/src/Protocol/Protocol.h
@@ -57,6 +57,11 @@ public:
virtual ~cProtocol() {}
+ /** Called after construction so that the protocol class can initialize itself.
+ Throws a std::exception descendant on failure; the client is kicked
+ with the exception's message as a result. */
+ virtual void Initialize(cClientHandle & a_Client) {}
+
/** Logical types of outgoing packets.
These values get translated to on-wire packet IDs in GetPacketID(), specific for each protocol.
This is mainly useful for protocol sub-versions that re-number the packets while using mostly the same packet layout. */
diff --git a/src/Protocol/ProtocolPalettes.cpp b/src/Protocol/ProtocolPalettes.cpp
new file mode 100644
index 000000000..2dc0857a9
--- /dev/null
+++ b/src/Protocol/ProtocolPalettes.cpp
@@ -0,0 +1,107 @@
+#include "Globals.h"
+#include "ProtocolPalettes.h"
+#include "../BlockTypePalette.h"
+
+
+
+
+
+void ProtocolPalettes::load(const AString & aProtocolFolder)
+{
+ auto contents = cFile::GetFolderContents(aProtocolFolder);
+ for (const auto & c: contents)
+ {
+ auto fullName = aProtocolFolder + cFile::PathSeparator() + c;
+ if (cFile::IsFolder(fullName))
+ {
+ loadSingleVersion(c, fullName);
+ }
+ }
+}
+
+
+
+
+
+std::shared_ptr<const BlockTypePalette> ProtocolPalettes::blockTypePalette(const AString & aProtocolVersion) const
+{
+ cCSLock lock(mCS);
+ auto itr = mPalettes.find(aProtocolVersion);
+ if (itr == mPalettes.end())
+ {
+ return nullptr;
+ }
+ return itr->second.mBlockTypePalette;
+}
+
+
+
+
+
+std::vector<AString> ProtocolPalettes::protocolVersions() const
+{
+ cCSLock lock(mCS);
+
+ std::vector<AString> res;
+ for (const auto & p: mPalettes)
+ {
+ res.push_back(p.first);
+ }
+ return res;
+}
+
+
+
+
+
+void ProtocolPalettes::loadSingleVersion(const AString & aProtocolVersion, const AString & aFolder)
+{
+ // Get the file list, sort by name
+ auto contents = cFile::GetFolderContents(aFolder);
+ std::sort(contents.begin(), contents.end());
+
+ // Load files into the palettes:
+ cCSLock lock(mCS);
+ auto & pal = mPalettes[aProtocolVersion];
+ for (const auto & c: contents)
+ {
+ if (c.length() < 8)
+ {
+ // Name too short, can't have the ".btp.txt" etc. suffix
+ continue;
+ }
+ auto fnam = aFolder + cFile::PathSeparator() + c;
+ if (!cFile::IsFile(fnam))
+ {
+ continue;
+ }
+ auto fileType = c.substr(c.length() - 8);
+ if ((fileType == ".btp.txt") || (c == "blocks.json"))
+ {
+ try
+ {
+ pal.mBlockTypePalette->loadFromString(cFile::ReadWholeFile(fnam));
+ }
+ catch (...)
+ {
+ // Ignore silently
+ }
+ }
+ else if ((fileType == ".itp.txt") || (c == "items.json"))
+ {
+ // TODO: Load item type palette
+ }
+ }
+}
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// ProtocolPalettes::Palettes:
+
+ProtocolPalettes::Palettes::Palettes():
+ mBlockTypePalette(new BlockTypePalette)
+{
+}
diff --git a/src/Protocol/ProtocolPalettes.h b/src/Protocol/ProtocolPalettes.h
new file mode 100644
index 000000000..fad093a04
--- /dev/null
+++ b/src/Protocol/ProtocolPalettes.h
@@ -0,0 +1,63 @@
+#pragma once
+
+#include "../OSSupport/CriticalSection.h"
+
+
+
+
+
+// fwd:
+class BlockTypePalette;
+
+
+
+
+
+/** Loads the protocol-specific palettes on startup and provides them to the individual protocol
+instances when they are created.
+Uses the data in the $/Server/Protocol folder. Each protocol version has a subfolder there,
+containing possibly multiple palette files. All the files are loaded in sequence (alpha-sorted),
+into the palette corresponding to the file's extension (*.btp.txt -> BlockTypePalette).
+Provides thread safety for the data properly. */
+class ProtocolPalettes
+{
+public:
+
+ /** Loads all the per-protocol palettes.
+ aProtocolFolder is the folder that contains a subfolder for each protocol version;
+ each subfolder contains the protocol-specific palettes (as in $/Server/Protocol)
+ If a protocol version is already loaded, yet present in the folder, the newly loaded data is merged
+ into the current data.
+ Always succeeds (even when there are no palettes). */
+ void load(const AString & aProtocolFolder);
+
+ /** Returns the BlockTypePalette for the specified protocol.
+ Returns nullptr if no such palette has been loaded. */
+ std::shared_ptr<const BlockTypePalette> blockTypePalette(const AString & aProtocolVersion) const;
+
+ /** Returns the version names of all protocols that have been loaded. */
+ std::vector<AString> protocolVersions() const;
+
+
+protected:
+
+ /** Container for all palettes for a single protocol. */
+ struct Palettes
+ {
+ std::shared_ptr<BlockTypePalette> mBlockTypePalette;
+ // TODO: ItemTypePalette
+
+ Palettes();
+ };
+
+
+ /** The CS protecting all members against multithreaded access. */
+ mutable cCriticalSection mCS;
+
+ /** The map of protocol version -> all its palettes. */
+ std::map<AString, Palettes> mPalettes;
+
+
+ /** Loads all the palettes from the specified folder into mPalettes under the aProtocolVersion key. */
+ void loadSingleVersion(const AString & aProtocolVersion, const AString & aFolder);
+};
diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp
index 6ad0a095d..17b42dae9 100644
--- a/src/Protocol/ProtocolRecognizer.cpp
+++ b/src/Protocol/ProtocolRecognizer.cpp
@@ -1038,7 +1038,24 @@ bool cProtocolRecognizer::TryRecognizeProtocol(void)
// Not enough bytes for the packet, keep waiting
return false;
}
- return TryRecognizeLengthedProtocol(PacketLen - ReadSoFar);
+ if (!TryRecognizeLengthedProtocol(PacketLen - ReadSoFar))
+ {
+ return false;
+ }
+
+ // The protocol has been recognized, initialize it:
+ ASSERT(m_Protocol != nullptr);
+ try
+ {
+ m_Protocol->Initialize(*m_Client);
+ }
+ catch (const std::exception & exc)
+ {
+ m_Client->Kick(exc.what());
+ m_Protocol.reset();
+ return false;
+ }
+ return true;
}
diff --git a/src/Protocol/Protocol_1_13.cpp b/src/Protocol/Protocol_1_13.cpp
index f84e8d1bd..e2cd72693 100644
--- a/src/Protocol/Protocol_1_13.cpp
+++ b/src/Protocol/Protocol_1_13.cpp
@@ -11,6 +11,7 @@ Implements the 1.13 protocol classes:
#include "ProtocolRecognizer.h"
#include "ChunkDataSerializer.h"
#include "Packetizer.h"
+#include "ProtocolPalettes.h"
#include "../Entities/Boat.h"
#include "../Entities/Minecart.h"
@@ -21,9 +22,11 @@ Implements the 1.13 protocol classes:
#include "../Entities/FireworkEntity.h"
#include "../Entities/SplashPotionEntity.h"
+#include "../BlockTypePalette.h"
+#include "../ClientHandle.h"
#include "../Root.h"
#include "../Server.h"
-#include "../ClientHandle.h"
+
#include "../Bindings/PluginManager.h"
@@ -69,6 +72,25 @@ cProtocol_1_13::cProtocol_1_13(cClientHandle * a_Client, const AString & a_Serve
+void cProtocol_1_13::Initialize(cClientHandle & a_Client)
+{
+ // Get the palettes; fail if not available:
+ auto paletteVersion = this->GetPaletteVersion();
+ m_BlockTypePalette = cRoot::Get()->GetProtocolPalettes().blockTypePalette(paletteVersion);
+ if (m_BlockTypePalette == nullptr)
+ {
+ throw std::runtime_error(Printf("This server doesn't support protocol %s.", paletteVersion));
+ }
+
+ // Process the palette into the temporary BLOCKTYPE -> NetBlockID map:
+ auto upg = cRoot::Get()->GetUpgradeBlockTypePalette();
+ m_BlockTypeMap = m_BlockTypePalette->createTransformMapWithFallback(upg, 0);
+}
+
+
+
+
+
UInt32 cProtocol_1_13::GetPacketID(ePacketType a_PacketType)
{
switch (a_PacketType)
@@ -132,6 +154,15 @@ UInt32 cProtocol_1_13::GetPacketID(ePacketType a_PacketType)
+AString cProtocol_1_13::GetPaletteVersion() const
+{
+ return "1.13";
+}
+
+
+
+
+
bool cProtocol_1_13::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType)
{
if (m_State != 3)
@@ -292,7 +323,7 @@ void cProtocol_1_13::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSeriali
{
ASSERT(m_State == 3); // In game mode?
- const AString & ChunkData = a_Serializer.Serialize(cChunkDataSerializer::RELEASE_1_13, a_ChunkX, a_ChunkZ);
+ const AString & ChunkData = a_Serializer.Serialize(cChunkDataSerializer::RELEASE_1_13, a_ChunkX, a_ChunkZ, m_BlockTypeMap);
cCSLock Lock(m_CSPacket);
SendData(ChunkData.data(), ChunkData.size());
}
diff --git a/src/Protocol/Protocol_1_13.h b/src/Protocol/Protocol_1_13.h
index 6eace0567..34827501c 100644
--- a/src/Protocol/Protocol_1_13.h
+++ b/src/Protocol/Protocol_1_13.h
@@ -20,6 +20,13 @@ Declares the 1.13 protocol classes:
+// fwd:
+class BlockTypePalette;
+
+
+
+
+
class cProtocol_1_13 :
public cProtocol_1_12_2
{
@@ -28,8 +35,24 @@ class cProtocol_1_13 :
public:
cProtocol_1_13(cClientHandle * a_Client, const AString & a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State);
+ virtual void Initialize(cClientHandle & a_Client) override;
+
+
protected:
+ /** The palette used to transform internal block type palette into the protocol-specific ID. */
+ std::shared_ptr<const BlockTypePalette> m_BlockTypePalette;
+
+ /** Temporary hack for initial 1.13+ support while keeping BLOCKTYPE data:
+ Map of the BLOCKTYPE#META to the protocol-specific NetBlockID. */
+ std::map<UInt32, UInt32> m_BlockTypeMap;
+
+
+ /** Returns the string identifying the palettes' version, such as "1.13" or "1.14.4".
+ The palettes for that version are loaded into m_BlockTypePalette and m_ItemTypePalette. */
+ virtual AString GetPaletteVersion() const;
+
+ // Outgoing packet type translation:
virtual UInt32 GetPacketID(ePacketType a_PacketType) override;
// Packet receiving:
diff --git a/src/Protocol/Protocol_1_8.cpp b/src/Protocol/Protocol_1_8.cpp
index 72fbb4678..00eaf4284 100644
--- a/src/Protocol/Protocol_1_8.cpp
+++ b/src/Protocol/Protocol_1_8.cpp
@@ -307,7 +307,7 @@ void cProtocol_1_8_0::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerial
// Serialize first, before creating the Packetizer (the packetizer locks a CS)
// This contains the flags and bitmasks, too
- const AString & ChunkData = a_Serializer.Serialize(cChunkDataSerializer::RELEASE_1_8_0, a_ChunkX, a_ChunkZ);
+ const AString & ChunkData = a_Serializer.Serialize(cChunkDataSerializer::RELEASE_1_8_0, a_ChunkX, a_ChunkZ, {});
cCSLock Lock(m_CSPacket);
SendData(ChunkData.data(), ChunkData.size());
diff --git a/src/Protocol/Protocol_1_9.cpp b/src/Protocol/Protocol_1_9.cpp
index 4bf358567..fa5215102 100644
--- a/src/Protocol/Protocol_1_9.cpp
+++ b/src/Protocol/Protocol_1_9.cpp
@@ -351,7 +351,7 @@ void cProtocol_1_9_0::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerial
// Serialize first, before creating the Packetizer (the packetizer locks a CS)
// This contains the flags and bitmasks, too
- const AString & ChunkData = a_Serializer.Serialize(cChunkDataSerializer::RELEASE_1_9_0, a_ChunkX, a_ChunkZ);
+ const AString & ChunkData = a_Serializer.Serialize(cChunkDataSerializer::RELEASE_1_9_0, a_ChunkX, a_ChunkZ, {});
cCSLock Lock(m_CSPacket);
SendData(ChunkData.data(), ChunkData.size());
@@ -4513,7 +4513,7 @@ void cProtocol_1_9_4::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerial
// Serialize first, before creating the Packetizer (the packetizer locks a CS)
// This contains the flags and bitmasks, too
- const AString & ChunkData = a_Serializer.Serialize(cChunkDataSerializer::RELEASE_1_9_4, a_ChunkX, a_ChunkZ);
+ const AString & ChunkData = a_Serializer.Serialize(cChunkDataSerializer::RELEASE_1_9_4, a_ChunkX, a_ChunkZ, {});
cCSLock Lock(m_CSPacket);
SendData(ChunkData.data(), ChunkData.size());