1
0

Added temporary block type mapping for 1.13+ protocols.

This commit is contained in:
Mattes D 2020-01-03 17:31:13 +01:00
parent e234fbdafe
commit 4aef80b47e
16 changed files with 375 additions and 76 deletions

View File

@ -1,6 +1,7 @@
Cuberite
Plugins
Prefabs
Protocol
webadmin
BACKERS
brewing.txt

View File

@ -2,6 +2,7 @@ Cuberite.exe
*.dll
Plugins
Prefabs
Protocol
webadmin
BACKERS
brewing.txt

View File

@ -10,7 +10,7 @@ CommonPrefix minecraft:
1 4 polished_diorite
1 5 andesite
1 6 polished_andesite
2 0 grass_block
2 0 grass_block snowy false
3 0 dirt
3 1 coarse_dirt
3 2 podzol
@ -38,14 +38,26 @@ CommonPrefix minecraft:
14 0 gold_ore
15 0 iron_ore
16 0 coal_ore
17 0 oak_log
17 1 spruce_log
17 2 birch_log
17 3 jungle_log
18 0 oak_leaves
18 1 spruce_leaves
18 2 birch_leaves
18 3 jungle_leaves
17 0 oak_log axis y
17 1 spruce_log axis y
17 2 birch_log axis y
17 3 jungle_log axis y
17 4 oak_log axis x
17 5 spruce_log axis x
17 6 birch_log axis x
17 7 jungle_log axis x
17 8 oak_log axis z
17 9 spruce_log axis z
17 10 birch_log axis z
17 11 jungle_log axis z
17 12 oak_wood axis y
17 13 spruce_wood axis y
17 14 birch_wood axis y
17 15 jungle_wood axis y
18 0 oak_leaves persistent false distance 7
18 1 spruce_leaves persistent false distance 7
18 2 birch_leaves persistent false distance 7
18 3 jungle_leaves persistent false distance 7
19 0 sponge
19 1 wet_sponge
20 0 glass

View File

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

View File

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

View File

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

View File

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

View File

@ -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)
{
}

View File

@ -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);
};

View File

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

View File

@ -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());
}

View File

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

View File

@ -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());

View File

@ -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());

View File

@ -40,6 +40,7 @@
#include "Logger.h"
#include "ClientHandle.h"
#include "BlockTypePalette.h"
#include "Protocol/ProtocolPalettes.h"
@ -193,23 +194,7 @@ void cRoot::Start(std::unique_ptr<cSettingsRepositoryInterface> a_OverridesRepo)
// cClientHandle::FASTBREAK_PERCENTAGE = settingsRepo->GetValueSetI("AntiCheat", "FastBreakPercentage", 97) / 100.0f;
cClientHandle::FASTBREAK_PERCENTAGE = 0; // AntiCheat disabled due to bugs. We will enabled it once they are fixed. See #3506.
// Load the UpgradeBlockTypePalette:
LOG("Loading UpgradeBlockTypePalette...");
try
{
auto paletteStr = cFile::ReadWholeFile("Protocol/UpgradeBlockTypePalette.txt");
if (paletteStr.empty())
{
throw std::runtime_error("File is empty");
}
m_UpgradeBlockTypePalette.reset(new BlockTypePalette);
m_UpgradeBlockTypePalette->loadFromString(paletteStr);
}
catch (const std::exception & exc)
{
LOGERROR("Failed to load the Upgrade block type palette from Protocol/UpgradeBlockTypePalette.txt: %s\nAborting", exc.what());
throw;
}
LoadPalettes(settingsRepo->GetValueSet("Folders", "ProtocolPalettes", "Protocol"));
m_MojangAPI = new cMojangAPI;
bool ShouldAuthenticate = settingsRepo->GetValueSetB("Authentication", "Authenticate", true);
@ -416,6 +401,48 @@ void cRoot::LoadGlobalSettings()
void cRoot::LoadPalettes(const AString & aProtocolFolder)
{
LOG("Loading UpgradeBlockTypePalette...");
try
{
auto paletteStr = cFile::ReadWholeFile(aProtocolFolder + cFile::PathSeparator() + "UpgradeBlockTypePalette.txt");
if (paletteStr.empty())
{
throw std::runtime_error("File is empty");
}
m_UpgradeBlockTypePalette.reset(new BlockTypePalette);
m_UpgradeBlockTypePalette->loadFromString(paletteStr);
}
catch (const std::exception & exc)
{
LOGERROR("Failed to load the Upgrade block type palette from %s/UpgradeBlockTypePalette.txt: %s\nAborting",
aProtocolFolder, exc.what()
);
throw;
}
// Note: This can take a lot of time in MSVC debug builds
// If impatient, edit the settings.ini: [Folders] ProtocolPalettes=DummyDir; copy only one palette to DummyDir
LOG("Loading per-protocol palettes...");
m_ProtocolPalettes.reset(new ProtocolPalettes);
m_ProtocolPalettes->load(aProtocolFolder);
auto versions = m_ProtocolPalettes->protocolVersions();
if (versions.empty())
{
LOGWARNING("No per-protocol palettes were loaded");
}
else
{
std::sort(versions.begin(), versions.end());
LOG("Loaded palettes for protocol versions: %s", StringJoin(versions, ", "));
}
}
void cRoot::LoadWorlds(cDeadlockDetect & a_dd, cSettingsRepositoryInterface & a_Settings, bool a_IsNewIniFile)
{
if (a_IsNewIniFile)

View File

@ -29,6 +29,7 @@ class cSettingsRepositoryInterface;
class cDeadlockDetect;
class cUUID;
class BlockTypePalette;
class ProtocolPalettes;
using cPlayerListCallback = cFunctionRef<bool(cPlayer &)>;
using cWorldListCallback = cFunctionRef<bool(cWorld &)>;
@ -96,6 +97,9 @@ public:
/** Returns the block type palette used for upgrading blocks from pre-1.13 data. */
const BlockTypePalette & GetUpgradeBlockTypePalette() const { return *m_UpgradeBlockTypePalette; }
/** Returns the per-protocol palettes manager. */
ProtocolPalettes & GetProtocolPalettes() const { return *m_ProtocolPalettes; }
/** Returns the number of ticks for how long the item would fuel a furnace. Returns zero if not a fuel */
static int GetFurnaceFuelBurnTime(const cItem & a_Fuel); // tolua_export
@ -241,9 +245,16 @@ private:
/** The upgrade palette for pre-1.13 blocks. */
std::unique_ptr<BlockTypePalette> m_UpgradeBlockTypePalette;
/** The per-protocol palettes manager. */
std::unique_ptr<ProtocolPalettes> m_ProtocolPalettes;
void LoadGlobalSettings();
/** Loads the upgrade palette and the per-protocol palettes.
The aProtocolFolder is the path to the folder containing the per-protocol palettes. */
void LoadPalettes(const AString & aProtocolFolder);
/** Loads the worlds from settings.ini, creates the worldmap */
void LoadWorlds(cDeadlockDetect & a_dd, cSettingsRepositoryInterface & a_Settings, bool a_IsNewIniFile);