Implemented packet compression.
ChunkData packet needs this.
This commit is contained in:
parent
da28c70def
commit
09ff17b71e
@ -8,6 +8,7 @@
|
||||
#include "Globals.h"
|
||||
#include "ChunkDataSerializer.h"
|
||||
#include "zlib/zlib.h"
|
||||
#include "ByteBuffer.h"
|
||||
|
||||
|
||||
|
||||
@ -30,7 +31,7 @@ cChunkDataSerializer::cChunkDataSerializer(
|
||||
|
||||
|
||||
|
||||
const AString & cChunkDataSerializer::Serialize(int a_Version)
|
||||
const AString & cChunkDataSerializer::Serialize(int a_Version, int a_ChunkX, int a_ChunkZ)
|
||||
{
|
||||
Serializations::const_iterator itr = m_Serializations.find(a_Version);
|
||||
if (itr != m_Serializations.end())
|
||||
@ -43,7 +44,7 @@ const AString & cChunkDataSerializer::Serialize(int a_Version)
|
||||
{
|
||||
case RELEASE_1_2_5: Serialize29(data); break;
|
||||
case RELEASE_1_3_2: Serialize39(data); break;
|
||||
case RELEASE_1_8_0: Serialize80(data); break;
|
||||
case RELEASE_1_8_0: Serialize80(data, a_ChunkX, a_ChunkZ); break;
|
||||
// TODO: Other protocol versions may serialize the data differently; implement here
|
||||
|
||||
default:
|
||||
@ -176,45 +177,87 @@ void cChunkDataSerializer::Serialize39(AString & a_Data)
|
||||
|
||||
|
||||
|
||||
void cChunkDataSerializer::Serialize80(AString & a_Data)
|
||||
void cChunkDataSerializer::Serialize80(AString & a_Data, int a_ChunkX, int a_ChunkZ)
|
||||
{
|
||||
// TODO: Do not copy data and then compress it; rather, compress partial blocks of data (zlib *can* stream)
|
||||
|
||||
// Blocktypes converter (1.8 included the meta into the blocktype):
|
||||
unsigned short Blocks[ARRAYCOUNT(m_BlockTypes)];
|
||||
/*unsigned short Blocks[ARRAYCOUNT(m_BlockTypes)];
|
||||
for (size_t Index = 0; Index < cChunkDef::NumBlocks; Index++)
|
||||
{
|
||||
BLOCKTYPE BlockType = m_BlockTypes[Index];
|
||||
NIBBLETYPE BlockMeta = m_BlockMetas[Index / 2] >> ((Index & 1) * 4) & 0x0f;
|
||||
Blocks[Index] = ((unsigned short)BlockType << 4) | ((unsigned short)BlockMeta);
|
||||
}
|
||||
}*/
|
||||
|
||||
const int BiomeDataSize = cChunkDef::Width * cChunkDef::Width;
|
||||
const int BlockLightOffset = sizeof(Blocks);
|
||||
const int MetadataOffset = sizeof(m_BlockTypes);
|
||||
const int BlockLightOffset = MetadataOffset + sizeof(m_BlockMetas);
|
||||
const int SkyLightOffset = BlockLightOffset + sizeof(m_BlockLight);
|
||||
const int BiomeOffset = SkyLightOffset + sizeof(m_BlockSkyLight);
|
||||
const int DataSize = BiomeOffset + BiomeDataSize;
|
||||
|
||||
// Temporary buffer for the composed data:
|
||||
char AllData [DataSize];
|
||||
memcpy(AllData, Blocks, sizeof(Blocks));
|
||||
memcpy(AllData, m_BlockTypes, sizeof(m_BlockTypes));
|
||||
memcpy(AllData + MetadataOffset, m_BlockMetas, sizeof(m_BlockMetas));
|
||||
memcpy(AllData + BlockLightOffset, m_BlockLight, sizeof(m_BlockLight));
|
||||
memcpy(AllData + SkyLightOffset, m_BlockSkyLight, sizeof(m_BlockSkyLight));
|
||||
memcpy(AllData + BiomeOffset, m_BiomeData, BiomeDataSize);
|
||||
|
||||
// Put all those data into a_Data:
|
||||
a_Data.push_back('\x01'); // "Ground-up continuous", or rather, "biome data present" flag
|
||||
cByteBuffer Packet(512 KiB);
|
||||
Packet.WriteVarInt(0x21); // Packet id (Chunk Data packet)
|
||||
Packet.WriteBEInt(a_ChunkX);
|
||||
Packet.WriteBEInt(a_ChunkZ);
|
||||
Packet.WriteBool(true); // "Ground-up continuous", or rather, "biome data present" flag
|
||||
Packet.WriteBEShort(0xffff); // We're aways sending the full chunk with no additional data, so the bitmap is 0xffff
|
||||
Packet.WriteVarInt(DataSize); // Chunk size
|
||||
Packet.WriteBuf(AllData, DataSize); // Chunk data
|
||||
|
||||
// Two bitmaps; we're aways sending the full chunk with no additional data, so the bitmaps are 0xffff and 0, respectively
|
||||
// Also, no endian flipping is needed because of the const values
|
||||
unsigned short BitMap = 0xffff;
|
||||
a_Data.append((const char *)&BitMap, sizeof(unsigned short));
|
||||
AString PacketData;
|
||||
Packet.ReadAll(PacketData);
|
||||
Packet.CommitRead();
|
||||
|
||||
// Write chunk size:
|
||||
UInt32 ChunkSize = htonl((UInt32)DataSize);
|
||||
a_Data.append((const char *)&ChunkSize, 4);
|
||||
cByteBuffer NumberBuffer(20);
|
||||
if (PacketData.size() >= 256)
|
||||
{
|
||||
AString PostData;
|
||||
NumberBuffer.WriteVarInt(PacketData.size());
|
||||
NumberBuffer.ReadAll(PostData);
|
||||
NumberBuffer.CommitRead();
|
||||
|
||||
a_Data.append(AllData, DataSize); // Chunk data
|
||||
// Compress the data:
|
||||
const uLongf CompressedMaxSize = 200000;
|
||||
char CompressedData[CompressedMaxSize];
|
||||
|
||||
uLongf CompressedSize = compressBound(PacketData.size());
|
||||
// Run-time check that our compile-time guess about CompressedMaxSize was enough:
|
||||
ASSERT(CompressedSize <= CompressedMaxSize);
|
||||
compress2((Bytef*)CompressedData, &CompressedSize, (const Bytef*)PacketData.data(), PacketData.size(), Z_DEFAULT_COMPRESSION);
|
||||
|
||||
NumberBuffer.WriteVarInt(CompressedSize + PostData.size());
|
||||
NumberBuffer.WriteVarInt(PacketData.size());
|
||||
NumberBuffer.ReadAll(PostData);
|
||||
NumberBuffer.CommitRead();
|
||||
|
||||
a_Data.clear();
|
||||
a_Data.resize(PostData.size() + CompressedSize);
|
||||
a_Data.append(PostData.data(), PostData.size());
|
||||
a_Data.append(CompressedData, CompressedSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
AString PostData;
|
||||
NumberBuffer.WriteVarInt(Packet.GetUsedSpace() + 1);
|
||||
NumberBuffer.WriteVarInt(0);
|
||||
NumberBuffer.ReadAll(PostData);
|
||||
NumberBuffer.CommitRead();
|
||||
|
||||
a_Data.clear();
|
||||
a_Data.resize(PostData.size() + PacketData.size());
|
||||
a_Data.append(PostData.data(), PostData.size());
|
||||
a_Data.append(PacketData.data(), PacketData.size());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -24,7 +24,7 @@ protected:
|
||||
|
||||
void Serialize29(AString & a_Data); // Release 1.2.4 and 1.2.5
|
||||
void Serialize39(AString & a_Data); // Release 1.3.1 to 1.7.10
|
||||
void Serialize80(AString & a_Data); // Release 1.8
|
||||
void Serialize80(AString & a_Data, int a_ChunkX, int a_ChunkZ); // Release 1.8
|
||||
|
||||
public:
|
||||
enum
|
||||
@ -42,7 +42,7 @@ public:
|
||||
const unsigned char * a_BiomeData
|
||||
);
|
||||
|
||||
const AString & Serialize(int a_Version); // Returns one of the internal m_Serializations[]
|
||||
const AString & Serialize(int a_Version, int a_ChunkX, int a_ChunkZ); // Returns one of the internal m_Serializations[]
|
||||
} ;
|
||||
|
||||
|
||||
|
@ -262,7 +262,7 @@ void cProtocol125::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerialize
|
||||
SendPreChunk(a_ChunkX, a_ChunkZ, true);
|
||||
|
||||
// Send the chunk data:
|
||||
AString Serialized = a_Serializer.Serialize(cChunkDataSerializer::RELEASE_1_2_5);
|
||||
AString Serialized = a_Serializer.Serialize(cChunkDataSerializer::RELEASE_1_2_5, a_ChunkX, a_ChunkZ);
|
||||
WriteByte(PACKET_MAP_CHUNK);
|
||||
WriteInt (a_ChunkX);
|
||||
WriteInt (a_ChunkZ);
|
||||
|
@ -176,7 +176,7 @@ void cProtocol132::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerialize
|
||||
// Pre-chunk not used in 1.3.2. Finally.
|
||||
|
||||
// Send the chunk data:
|
||||
AString Serialized = a_Serializer.Serialize(cChunkDataSerializer::RELEASE_1_3_2);
|
||||
AString Serialized = a_Serializer.Serialize(cChunkDataSerializer::RELEASE_1_3_2, a_ChunkX, a_ChunkZ);
|
||||
WriteByte(PACKET_CHUNK_DATA);
|
||||
WriteInt (a_ChunkX);
|
||||
WriteInt (a_ChunkZ);
|
||||
|
@ -346,7 +346,7 @@ void cProtocol172::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerialize
|
||||
|
||||
// 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_3_2);
|
||||
const AString & ChunkData = a_Serializer.Serialize(cChunkDataSerializer::RELEASE_1_3_2, a_ChunkX, a_ChunkZ);
|
||||
|
||||
cPacketizer Pkt(*this, 0x21); // Chunk Data packet
|
||||
Pkt.WriteInt(a_ChunkX);
|
||||
@ -1533,6 +1533,17 @@ void cProtocol172::AddReceivedData(const char * a_Data, size_t a_Size)
|
||||
// Write one NUL extra, so that we can detect over-reads
|
||||
bb.Write("\0", 1);
|
||||
|
||||
// 1.8 - Compressed packets
|
||||
if (m_State == 3)
|
||||
{
|
||||
UInt32 CompressedSize;
|
||||
if (!bb.ReadVarInt(CompressedSize))
|
||||
{
|
||||
// Not enough data
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 PacketType;
|
||||
if (!bb.ReadVarInt(PacketType))
|
||||
{
|
||||
@ -2511,10 +2522,23 @@ cProtocol172::cPacketizer::~cPacketizer()
|
||||
|
||||
// Send the packet length
|
||||
UInt32 PacketLen = (UInt32)m_Out.GetUsedSpace();
|
||||
if (m_Protocol.m_State == 3)
|
||||
{
|
||||
PacketLen += 1;
|
||||
}
|
||||
|
||||
m_Protocol.m_OutPacketLenBuffer.WriteVarInt(PacketLen);
|
||||
m_Protocol.m_OutPacketLenBuffer.ReadAll(DataToSend);
|
||||
m_Protocol.SendData(DataToSend.data(), DataToSend.size());
|
||||
m_Protocol.m_OutPacketLenBuffer.CommitRead();
|
||||
|
||||
if (m_Protocol.m_State == 3)
|
||||
{
|
||||
m_Protocol.m_OutPacketLenBuffer.WriteVarInt(0);
|
||||
m_Protocol.m_OutPacketLenBuffer.ReadAll(DataToSend);
|
||||
m_Protocol.SendData(DataToSend.data(), DataToSend.size());
|
||||
m_Protocol.m_OutPacketLenBuffer.CommitRead();
|
||||
}
|
||||
|
||||
// Send the packet data:
|
||||
m_Out.ReadAll(DataToSend);
|
||||
|
@ -13,6 +13,7 @@ Implements the 1.8.x protocol classes:
|
||||
#include "json/json.h"
|
||||
#include "ChunkDataSerializer.h"
|
||||
#include "Protocol18x.h"
|
||||
#include "zlib/zlib.h"
|
||||
|
||||
#include "../ClientHandle.h"
|
||||
#include "../CompositeChat.h"
|
||||
@ -21,7 +22,7 @@ Implements the 1.8.x protocol classes:
|
||||
#include "../World.h"
|
||||
|
||||
#include "../Entities/Player.h"
|
||||
#include "Entities/Painting.h"
|
||||
#include "../Entities/Painting.h"
|
||||
|
||||
|
||||
|
||||
@ -57,23 +58,38 @@ cProtocol180::cProtocol180(cClientHandle * a_Client, const AString & a_ServerAdd
|
||||
|
||||
|
||||
|
||||
void cProtocol180::SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x28); // Effect packet
|
||||
Pkt.WriteInt(a_EffectID);
|
||||
Pkt.WritePosition(Vector3i(a_SrcX, a_SrcY, a_SrcZ));
|
||||
Pkt.WriteInt(a_Data);
|
||||
Pkt.WriteBool(false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol180::SendLoginSuccess(void)
|
||||
{
|
||||
ASSERT(m_State == 2); // State: login?
|
||||
|
||||
// Disable compression:
|
||||
// Enable compression:
|
||||
{
|
||||
cPacketizer Pkt(*this, 0x03); // Set compression packet
|
||||
Pkt.WriteVarInt(-1);
|
||||
Pkt.WriteVarInt(256);
|
||||
}
|
||||
|
||||
m_State = 3; // State = Game
|
||||
|
||||
{
|
||||
cPacketizer Pkt(*this, 0x02); // Login success packet
|
||||
Pkt.WriteString(cMojangAPI::MakeUUIDDashed(m_Client->GetUUID()));
|
||||
Pkt.WriteString(m_Client->GetUsername());
|
||||
}
|
||||
|
||||
m_State = 3; // State = Game
|
||||
}
|
||||
|
||||
|
||||
@ -409,12 +425,10 @@ void cProtocol180::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerialize
|
||||
|
||||
// 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);
|
||||
const AString & ChunkData = a_Serializer.Serialize(cChunkDataSerializer::RELEASE_1_8_0, a_ChunkX, a_ChunkZ);
|
||||
|
||||
cPacketizer Pkt(*this, 0x21); // Chunk Data packet
|
||||
Pkt.WriteInt(a_ChunkX);
|
||||
Pkt.WriteInt(a_ChunkZ);
|
||||
Pkt.WriteBuf(ChunkData.data(), ChunkData.size());
|
||||
cCSLock Lock(m_CSPacket);
|
||||
SendData(ChunkData.data(), ChunkData.size());
|
||||
}
|
||||
|
||||
|
||||
|
@ -54,6 +54,7 @@ public:
|
||||
|
||||
cProtocol180(cClientHandle * a_Client, const AString & a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State);
|
||||
|
||||
virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override;
|
||||
virtual void SendLoginSuccess (void) override;
|
||||
virtual void SendPlayerAbilities (void) override {}
|
||||
virtual void SendWindowClose (const cWindow & a_Window) override {}
|
||||
|
Loading…
Reference in New Issue
Block a user