summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--source/ChunkDataSerializer.cpp60
-rw-r--r--source/ChunkDataSerializer.h2
-rw-r--r--source/Protocol.h2
-rw-r--r--source/Protocol125.cpp124
-rw-r--r--source/Protocol125.h2
-rw-r--r--source/Protocol132.cpp339
-rw-r--r--source/Protocol132.h40
-rw-r--r--source/ProtocolRecognizer.cpp4
-rw-r--r--source/ProtocolRecognizer.h2
-rw-r--r--source/cChestEntity.cpp2
-rw-r--r--source/cChunk.cpp4
-rw-r--r--source/cChunk.h2
-rw-r--r--source/cChunkMap.cpp4
-rw-r--r--source/cChunkMap.h2
-rw-r--r--source/cClientHandle.cpp4
-rw-r--r--source/cClientHandle.h2
-rw-r--r--source/cNoteEntity.cpp2
-rw-r--r--source/cPiston.cpp4
-rw-r--r--source/cPlayer.cpp2
-rw-r--r--source/cWorld.cpp4
-rw-r--r--source/cWorld.h2
21 files changed, 500 insertions, 109 deletions
diff --git a/source/ChunkDataSerializer.cpp b/source/ChunkDataSerializer.cpp
index 1d798beb2..7af07f331 100644
--- a/source/ChunkDataSerializer.cpp
+++ b/source/ChunkDataSerializer.cpp
@@ -42,6 +42,7 @@ const AString & cChunkDataSerializer::Serialize(int a_Version)
switch (a_Version)
{
case RELEASE_1_2_5: Serialize29(data); break;
+ case RELEASE_1_3_2: Serialize39(data); break;
// TODO: Other protocol versions may serialize the data differently; implement here
default:
@@ -95,7 +96,7 @@ void cChunkDataSerializer::Serialize29(AString & a_Data)
// Now put all those data into a_Data:
// "Ground-up continuous", or rather, "biome data present" flag:
- a_Data.push_back('\xff');
+ a_Data.push_back('\x01');
// 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
@@ -116,3 +117,60 @@ void cChunkDataSerializer::Serialize29(AString & a_Data)
+
+void cChunkDataSerializer::Serialize39(AString & a_Data)
+{
+ // TODO: Do not copy data and then compress it; rather, compress partial blocks of data (zlib *can* stream)
+
+ const int BiomeDataSize = cChunkDef::Width * cChunkDef::Width;
+ 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, 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);
+
+ // Compress the data:
+ // In order not to use allocation, use a fixed-size buffer, with the size
+ // that uses the same calculation as compressBound():
+ const uLongf CompressedMaxSize = DataSize + (DataSize >> 12) + (DataSize >> 14) + (DataSize >> 25) + 16;
+ char CompressedBlockData[CompressedMaxSize];
+
+ uLongf CompressedSize = compressBound(DataSize);
+
+ // Run-time check that our compile-time guess about CompressedMaxSize was enough:
+ ASSERT(CompressedSize <= CompressedMaxSize);
+
+ compress2((Bytef*)CompressedBlockData, &CompressedSize, (const Bytef*)AllData, sizeof(AllData), Z_DEFAULT_COMPRESSION);
+
+ // Now put all those data into a_Data:
+
+ // "Ground-up continuous", or rather, "biome data present" flag:
+ a_Data.push_back('\x01');
+
+ // 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 BitMap1 = 0xffff;
+ unsigned short BitMap2 = 0;
+ a_Data.append((const char *)&BitMap1, sizeof(short));
+ a_Data.append((const char *)&BitMap2, sizeof(short));
+
+ Int32 CompressedSizeBE = htonl(CompressedSize);
+ a_Data.append((const char *)&CompressedSizeBE, sizeof(CompressedSizeBE));
+
+ // Unlike 29, 39 doesn't have the "unused" int
+
+ a_Data.append(CompressedBlockData, CompressedSize);
+}
+
+
+
+
diff --git a/source/ChunkDataSerializer.h b/source/ChunkDataSerializer.h
index 4c2f4fb4c..513a232b9 100644
--- a/source/ChunkDataSerializer.h
+++ b/source/ChunkDataSerializer.h
@@ -23,11 +23,13 @@ protected:
Serializations m_Serializations;
void Serialize29(AString & a_Data); // Release 1.2.4 and 1.2.5
+ void Serialize39(AString & a_Data); // Release 1.3.1 and 1.3.2
public:
enum
{
RELEASE_1_2_5 = 29,
+ RELEASE_1_3_2 = 39,
} ;
cChunkDataSerializer(
diff --git a/source/Protocol.h b/source/Protocol.h
index 2b6bdd561..f3e688afb 100644
--- a/source/Protocol.h
+++ b/source/Protocol.h
@@ -41,7 +41,7 @@ public:
virtual void DataReceived(const char * a_Data, int a_Size) = 0;
// Sending stuff to clients:
- virtual void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2) = 0;
+ virtual void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) = 0;
virtual void SendBlockChange (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) = 0;
virtual void SendBlockChanges (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) = 0;
virtual void SendChat (const AString & a_Message) = 0;
diff --git a/source/Protocol125.cpp b/source/Protocol125.cpp
index ce86e70c4..2adb68fa0 100644
--- a/source/Protocol125.cpp
+++ b/source/Protocol125.cpp
@@ -112,8 +112,10 @@ cProtocol125::cProtocol125(cClientHandle * a_Client) :
-void cProtocol125::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2)
+void cProtocol125::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType)
{
+ UNUSED(a_BlockType);
+
cCSLock Lock(m_CSPacket);
WriteByte (PACKET_BLOCK_ACTION);
WriteInt (a_BlockX);
@@ -301,6 +303,42 @@ void cProtocol125::SendEntityStatus(const cEntity & a_Entity, char a_Status)
+void cProtocol125::SendEntRelMove(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ)
+{
+ ASSERT(a_Entity.GetUniqueID() != m_Client->GetPlayer()->GetUniqueID()); // Must not send for self
+
+ cCSLock Lock(m_CSPacket);
+ WriteByte(PACKET_ENT_REL_MOVE);
+ WriteInt (a_Entity.GetUniqueID());
+ WriteByte(a_RelX);
+ WriteByte(a_RelY);
+ WriteByte(a_RelZ);
+ Flush();
+}
+
+
+
+
+
+void cProtocol125::SendEntRelMoveLook(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ)
+{
+ ASSERT(a_Entity.GetUniqueID() != m_Client->GetPlayer()->GetUniqueID()); // Must not send for self
+
+ cCSLock Lock(m_CSPacket);
+ WriteByte(PACKET_ENT_REL_MOVE_LOOK);
+ WriteInt (a_Entity.GetUniqueID());
+ WriteByte(a_RelX);
+ WriteByte(a_RelY);
+ WriteByte(a_RelZ);
+ WriteByte((char)((a_Entity.GetRotation() / 360.f) * 256));
+ WriteByte((char)((a_Entity.GetPitch() / 360.f) * 256));
+ Flush();
+}
+
+
+
+
+
void cProtocol125::SendGameMode(eGameMode a_GameMode)
{
cCSLock Lock(m_CSPacket);
@@ -386,7 +424,7 @@ void cProtocol125::SendLogin(const cPlayer & a_Player)
WriteByte (PACKET_LOGIN);
WriteInt (a_Player.GetUniqueID()); // EntityID of the player
WriteString(""); // Username, not used
- WriteString("DEFAULT"); // Level type
+ WriteString("default"); // Level type
WriteInt ((int)a_Player.GetGameMode());
WriteInt (0); // TODO: Dimension (Nether / Overworld / End)
WriteByte (2); // TODO: Difficulty
@@ -416,17 +454,15 @@ void cProtocol125::SendMetadata(const cEntity & a_Entity)
void cProtocol125::SendPickupSpawn(const cPickup & a_Pickup)
{
cCSLock Lock(m_CSPacket);
- WriteByte (PACKET_PICKUP_SPAWN);
- WriteInt (a_Pickup.GetUniqueID());
- WriteShort(a_Pickup.GetItem()->m_ItemType);
- WriteByte (a_Pickup.GetItem()->m_ItemCount);
- WriteShort(a_Pickup.GetItem()->m_ItemDamage);
- WriteInt ((int)(a_Pickup.GetPosX() * 32));
- WriteInt ((int)(a_Pickup.GetPosY() * 32));
- WriteInt ((int)(a_Pickup.GetPosZ() * 32));
- WriteByte ((char)(a_Pickup.GetSpeed().x * 8));
- WriteByte ((char)(a_Pickup.GetSpeed().y * 8));
- WriteByte ((char)(a_Pickup.GetSpeed().z * 8));
+ WriteByte (PACKET_PICKUP_SPAWN);
+ WriteInt (a_Pickup.GetUniqueID());
+ WriteShort (a_Pickup.GetItem()->m_ItemType);
+ WriteByte (a_Pickup.GetItem()->m_ItemCount);
+ WriteShort (a_Pickup.GetItem()->m_ItemDamage);
+ WriteVectorI((Vector3i)(a_Pickup.GetPosition() * 32));
+ WriteByte ((char)(a_Pickup.GetSpeed().x * 8));
+ WriteByte ((char)(a_Pickup.GetSpeed().y * 8));
+ WriteByte ((char)(a_Pickup.GetSpeed().z * 8));
Flush();
}
@@ -509,7 +545,7 @@ void cProtocol125::SendPlayerSpawn(const cPlayer & a_Player)
{
const cItem & HeldItem = a_Player.GetEquippedItem();
cCSLock Lock(m_CSPacket);
- WriteByte (PACKET_PLAYER_SPAWN);
+ WriteByte (PACKET_PLAYER_SPAWN);
WriteInt (a_Player.GetUniqueID());
WriteString(a_Player.GetName());
WriteInt ((int)(a_Player.GetPosX() * 32));
@@ -525,42 +561,6 @@ void cProtocol125::SendPlayerSpawn(const cPlayer & a_Player)
-void cProtocol125::SendEntRelMove(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ)
-{
- ASSERT(a_Entity.GetUniqueID() != m_Client->GetPlayer()->GetUniqueID()); // Must not send for self
-
- cCSLock Lock(m_CSPacket);
- WriteByte(PACKET_ENT_REL_MOVE);
- WriteInt (a_Entity.GetUniqueID());
- WriteByte(a_RelX);
- WriteByte(a_RelY);
- WriteByte(a_RelZ);
- Flush();
-}
-
-
-
-
-
-void cProtocol125::SendEntRelMoveLook(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ)
-{
- ASSERT(a_Entity.GetUniqueID() != m_Client->GetPlayer()->GetUniqueID()); // Must not send for self
-
- cCSLock Lock(m_CSPacket);
- WriteByte(PACKET_ENT_REL_MOVE_LOOK);
- WriteInt (a_Entity.GetUniqueID());
- WriteByte(a_RelX);
- WriteByte(a_RelY);
- WriteByte(a_RelZ);
- WriteByte((char)((a_Entity.GetRotation() / 360.f) * 256));
- WriteByte((char)((a_Entity.GetPitch() / 360.f) * 256));
- Flush();
-}
-
-
-
-
-
void cProtocol125::SendRespawn(void)
{
cCSLock Lock(m_CSPacket);
@@ -569,7 +569,7 @@ void cProtocol125::SendRespawn(void)
WriteByte (2); // TODO: Difficulty; 2 = Normal
WriteByte ((char)m_Client->GetPlayer()->GetGameMode());
WriteShort (256); // Current world height
- WriteString("DEFAULT");
+ WriteString("default");
}
@@ -579,16 +579,13 @@ void cProtocol125::SendRespawn(void)
void cProtocol125::SendSpawnMob(const cMonster & a_Mob)
{
cCSLock Lock(m_CSPacket);
- Vector3i Pos = (Vector3i)(a_Mob.GetPosition() * 32);
- WriteByte(PACKET_SPAWN_MOB);
- WriteInt (a_Mob.GetUniqueID());
- WriteByte(a_Mob.GetMobType());
- WriteInt (Pos.x);
- WriteInt (Pos.y);
- WriteInt (Pos.z);
- WriteByte(0);
- WriteByte(0);
- WriteByte(0);
+ WriteByte (PACKET_SPAWN_MOB);
+ WriteInt (a_Mob.GetUniqueID());
+ WriteByte (a_Mob.GetMobType());
+ WriteVectorI((Vector3i)(a_Mob.GetPosition() * 32));
+ WriteByte (0);
+ WriteByte (0);
+ WriteByte (0);
AString MetaData = GetEntityMetaData(a_Mob);
SendData (MetaData.data(), MetaData.size());
Flush();
@@ -740,6 +737,11 @@ void cProtocol125::SendWindowClose(char a_WindowID)
void cProtocol125::SendWindowOpen(char a_WindowID, char a_WindowType, const AString & a_WindowTitle, char a_NumSlots)
{
+ if (a_WindowType < 0)
+ {
+ // Do not send for inventory windows
+ return;
+ }
cCSLock Lock(m_CSPacket);
WriteByte (PACKET_WINDOW_OPEN);
WriteByte (a_WindowID);
diff --git a/source/Protocol125.h b/source/Protocol125.h
index 3e0535163..2d6696c85 100644
--- a/source/Protocol125.h
+++ b/source/Protocol125.h
@@ -27,7 +27,7 @@ public:
virtual void DataReceived(const char * a_Data, int a_Size) override;
/// Sending stuff to clients:
- virtual void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2) override;
+ virtual void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) override;
virtual void SendBlockChange (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override;
virtual void SendBlockChanges (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) override;
virtual void SendChat (const AString & a_Message) override;
diff --git a/source/Protocol132.cpp b/source/Protocol132.cpp
index 2a4a830c6..5949776d3 100644
--- a/source/Protocol132.cpp
+++ b/source/Protocol132.cpp
@@ -9,6 +9,10 @@
#include "cServer.h"
#include "cClientHandle.h"
#include "CryptoPP/osrng.h"
+#include "cItem.h"
+#include "ChunkDataSerializer.h"
+#include "cPlayer.h"
+#include "cMonster.h"
@@ -44,11 +48,33 @@ const int MAX_ENC_LEN = 512; // Maximum size of the encrypted message; should b
+enum
+{
+ PACKET_KEEP_ALIVE = 0x00,
+ PACKET_LOGIN = 0x01,
+ PACKET_PLAYER_SPAWN = 0x14,
+ PACKET_SPAWN_MOB = 0x18,
+ PACKET_DESTROY_ENTITIES = 0x1d,
+ PACKET_CHUNK_DATA = 0x33,
+ PACKET_BLOCK_CHANGE = 0x34,
+ PACKET_BLOCK_ACTION = 0x36,
+} ;
+
+
+
+
+
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cProtocol132:
cProtocol132::cProtocol132(cClientHandle * a_Client) :
super(a_Client),
+ // DEBUG:
+ m_CurrentIn(0),
+ m_CurrentOut(0),
+ m_EncIn(0),
+ m_EncOut(0),
+
m_IsEncrypted(false)
{
}
@@ -57,10 +83,24 @@ cProtocol132::cProtocol132(cClientHandle * a_Client) :
+cProtocol132::~cProtocol132()
+{
+ if (!m_DataToSend.empty())
+ {
+ LOGD("There are %d unsent bytes while deleting cProtocol132", m_DataToSend.size());
+ }
+}
+
+
+
+
+
void cProtocol132::DataReceived(const char * a_Data, int a_Size)
{
+ m_CurrentIn += a_Size;
if (m_IsEncrypted)
{
+ m_EncIn += a_Size;
byte Decrypted[512];
while (a_Size > 0)
{
@@ -81,11 +121,169 @@ void cProtocol132::DataReceived(const char * a_Data, int a_Size)
+void cProtocol132::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType)
+{
+ cCSLock Lock(m_CSPacket);
+ WriteByte (PACKET_BLOCK_ACTION);
+ WriteInt (a_BlockX);
+ WriteShort((short)a_BlockY);
+ WriteInt (a_BlockZ);
+ WriteByte (a_Byte1);
+ WriteByte (a_Byte2);
+ WriteShort(a_BlockType);
+ Flush();
+}
+
+
+
+
+
+void cProtocol132::SendBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
+{
+ cCSLock Lock(m_CSPacket);
+ WriteByte (PACKET_BLOCK_CHANGE);
+ WriteInt (a_BlockX);
+ WriteByte ((unsigned char)a_BlockY);
+ WriteInt (a_BlockZ);
+ WriteShort(a_BlockType);
+ WriteByte (a_BlockMeta);
+ Flush();
+}
+
+
+
+
+
+void cProtocol132::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer)
+{
+ cCSLock Lock(m_CSPacket);
+
+ // Pre-chunk not used in 1.3.2. Finally.
+
+ //*
+ // Send the chunk data:
+ // Chunk data seems to break the connection for some reason; without it, the connection lives indefinitely
+ AString Serialized = a_Serializer.Serialize(cChunkDataSerializer::RELEASE_1_3_2);
+ WriteByte(PACKET_CHUNK_DATA);
+ WriteInt (a_ChunkX);
+ WriteInt (a_ChunkZ);
+ SendData(Serialized.data(), Serialized.size());
+ Flush();
+ //*/
+}
+
+
+
+
+
+void cProtocol132::SendDestroyEntity(const cEntity & a_Entity)
+{
+ cCSLock Lock(m_CSPacket);
+ WriteByte(PACKET_DESTROY_ENTITIES);
+ WriteByte(1); // entity count
+ WriteInt (a_Entity.GetUniqueID());
+ Flush();
+}
+
+
+
+
+
+void cProtocol132::SendKeepAlive(int a_PingID)
+{
+ cCSLock Lock(m_CSPacket);
+ WriteByte(PACKET_KEEP_ALIVE);
+ WriteInt (a_PingID);
+ Flush();
+}
+
+
+
+
+
+void cProtocol132::SendLogin(const cPlayer & a_Player)
+{
+ cCSLock Lock(m_CSPacket);
+ WriteByte (PACKET_LOGIN);
+ WriteInt (a_Player.GetUniqueID()); // EntityID of the player
+ WriteString("default"); // Level type
+ WriteByte ((int)a_Player.GetGameMode());
+ WriteByte (0); // TODO: Dimension (Nether / Overworld / End)
+ WriteByte (2); // TODO: Difficulty
+ WriteByte (0); // Unused, used to be world height
+ WriteByte (8); // Client list width or something
+ Flush();
+}
+
+
+
+
+
+void cProtocol132::SendPlayerSpawn(const cPlayer & a_Player)
+{
+ const cItem & HeldItem = a_Player.GetEquippedItem();
+ cCSLock Lock(m_CSPacket);
+ WriteByte (PACKET_PLAYER_SPAWN);
+ WriteInt (a_Player.GetUniqueID());
+ WriteString(a_Player.GetName());
+ WriteInt ((int)(a_Player.GetPosX() * 32));
+ WriteInt ((int)(a_Player.GetPosY() * 32));
+ WriteInt ((int)(a_Player.GetPosZ() * 32));
+ WriteByte ((char)((a_Player.GetRot().x / 360.f) * 256));
+ WriteByte ((char)((a_Player.GetRot().y / 360.f) * 256));
+ WriteShort (HeldItem.IsEmpty() ? 0 : HeldItem.m_ItemType);
+ // Player metadata: just use a default metadata value, since the client doesn't like starting without any metadata:
+ WriteByte (0); // Index 0, byte (flags)
+ WriteByte (0); // Flags, empty
+ WriteByte (0x7f); // End of metadata
+ Flush();
+}
+
+
+
+
+
+void cProtocol132::SendSpawnMob(const cMonster & a_Mob)
+{
+ cCSLock Lock(m_CSPacket);
+ WriteByte (PACKET_SPAWN_MOB);
+ WriteInt (a_Mob.GetUniqueID());
+ WriteByte (a_Mob.GetMobType());
+ WriteVectorI((Vector3i)(a_Mob.GetPosition() * 32));
+ WriteByte (0); // yaw
+ WriteByte (0); // pitch
+ WriteByte (0); // head yaw
+ WriteShort (0); // Velocity Z
+ WriteShort (0); // Velocity X
+ WriteShort (0); // Velocity Y
+ AString MetaData = GetEntityMetaData(a_Mob);
+ SendData (MetaData.data(), MetaData.size());
+ Flush();
+}
+
+
+
+
+
+void cProtocol132::SendUnloadChunk(int a_ChunkX, int a_ChunkZ)
+{
+ // Not used in 1.3.2
+ // Does it unload chunks on its own?
+}
+
+
+
+
+
int cProtocol132::ParsePacket(unsigned char a_PacketType)
{
+ // DEBUG:
+ LOGD("Received packet 0x%02x, current bytecount %d, enc %d", a_PacketType, m_CurrentIn, m_EncIn);
+
switch (a_PacketType)
{
default: return super::ParsePacket(a_PacketType); // off-load previously known packets into cProtocol125
+ case 0xcc: return ParseLocaleViewDistance();
case 0xcd: return ParseClientStatuses();
case 0xfc: return ParseEncryptionKeyResponse();
}
@@ -95,6 +293,32 @@ int cProtocol132::ParsePacket(unsigned char a_PacketType)
+int cProtocol132::ParseBlockPlace(void)
+{
+ HANDLE_PACKET_READ(ReadBEInt, int, PosX);
+ HANDLE_PACKET_READ(ReadByte, Byte, PosY);
+ HANDLE_PACKET_READ(ReadBEInt, int, PosZ);
+ HANDLE_PACKET_READ(ReadChar, char, Direction);
+
+ cItem HeldItem;
+ int res = ParseItem(HeldItem);
+ if (res < 0)
+ {
+ return res;
+ }
+
+ HANDLE_PACKET_READ(ReadChar, char, CursorX);
+ HANDLE_PACKET_READ(ReadChar, char, CursorY);
+ HANDLE_PACKET_READ(ReadChar, char, CursorZ);
+
+ m_Client->HandleBlockPlace(PosX, PosY, PosZ, Direction, HeldItem);
+ return PARSE_OK;
+}
+
+
+
+
+
int cProtocol132::ParseHandshake(void)
{
HANDLE_PACKET_READ(ReadByte, Byte, ProtocolVersion);
@@ -107,13 +331,14 @@ int cProtocol132::ParseHandshake(void)
CryptoPP::StringSink sink(key); // GCC won't allow inline instantiation in the following line, damned temporary refs
cRoot::Get()->GetServer()->GetPublicKey().Save(sink);
- // Send a 0xFD Encryption Key Request http://wiki.vg/Protocol#Encryption_Key_Request_.280xFD.29
+ // Send a 0xFD Encryption Key Request http://wiki.vg/Protocol#0xFD
WriteByte((char)0xfd);
WriteString("MCServer");
WriteShort((short)key.size());
SendData(key.data(), key.size());
WriteShort(4);
WriteInt((int)this); // Using 'this' as the cryptographic nonce, so that we don't have to generate one each time :)
+ Flush();
return PARSE_OK;
}
@@ -121,27 +346,10 @@ int cProtocol132::ParseHandshake(void)
-int cProtocol132::ParseLogin(void)
-{
- // Login packet not used in 1.3.2
- return PARSE_ERROR;
-}
-
-
-
-
-
int cProtocol132::ParseClientStatuses(void)
{
HANDLE_PACKET_READ(ReadByte, byte, Status);
-
- // DEBUG:
- // Kick the client, we don't have all the packets yet and sending wrong packets makes the client freeze
- // m_Client->Kick("I don't speak your language (yet)");
-
- // TODO:
- // m_Client->HandleLogin(39, m_Username);
-
+ m_Client->HandleLogin(39, m_Username);
return PARSE_OK;
}
@@ -178,11 +386,72 @@ int cProtocol132::ParseEncryptionKeyResponse(void)
+int cProtocol132::ParseLocaleViewDistance(void)
+{
+ HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Locale);
+ HANDLE_PACKET_READ(ReadChar, char, ViewDistance);
+ HANDLE_PACKET_READ(ReadChar, char, ChatFlags);
+ HANDLE_PACKET_READ(ReadChar, char, ClientDifficulty);
+ // TODO: m_Client->HandleLocale(Locale);
+ // TODO: m_Client->HandleViewDistance(ViewDistance);
+ // TODO: m_Client->HandleChatFlags(ChatFlags);
+ // Ignoring client difficulty
+ return PARSE_OK;
+}
+
+
+
+
+
+int cProtocol132::ParseLogin(void)
+{
+ // Login packet not used in 1.3.2
+ return PARSE_ERROR;
+}
+
+
+
+
+
+int cProtocol132::ParsePlayerAbilities(void)
+{
+ HANDLE_PACKET_READ(ReadBool, bool, Flags);
+ HANDLE_PACKET_READ(ReadChar, char, FlyingSpeed);
+ HANDLE_PACKET_READ(ReadChar, char, WalkingSpeed);
+ // TODO: m_Client->HandlePlayerAbilities(...);
+ return PARSE_OK;
+}
+
+
+
+
+
void cProtocol132::SendData(const char * a_Data, int a_Size)
{
+ // DEBUG:
+ m_DataToSend.append(a_Data, a_Size);
+ m_CurrentOut += a_Size;
+}
+
+
+
+
+
+void cProtocol132::Flush(void)
+{
+ // DEBUG
+ if (m_DataToSend.empty())
+ {
+ LOGD("Flushing empty");
+ return;
+ }
+ LOGD("Flushing packet 0x%02x, %d bytes; %d bytes out, %d enc out", (unsigned char)m_DataToSend[0], m_DataToSend.size(), m_CurrentOut, m_EncOut);
+ const char * a_Data = m_DataToSend.data();
+ int a_Size = m_DataToSend.size();
if (m_IsEncrypted)
{
- byte Encrypted[1024]; // Larger buffer, we may be sending lots of data (chunks)
+ m_EncOut += a_Size;
+ byte Encrypted[4096]; // Larger buffer, we may be sending lots of data (chunks)
while (a_Size > 0)
{
int NumBytes = (a_Size > sizeof(Encrypted)) ? sizeof(Encrypted) : a_Size;
@@ -196,6 +465,35 @@ void cProtocol132::SendData(const char * a_Data, int a_Size)
{
super::SendData(a_Data, a_Size);
}
+ m_DataToSend.clear();
+ // cSleep::MilliSleep(300);
+}
+
+
+
+
+
+void cProtocol132::WriteItem(const cItem & a_Item)
+{
+ short ItemType = a_Item.m_ItemType;
+ ASSERT(ItemType >= -1); // Check validity of packets in debug runtime
+ if (ItemType <= 0)
+ {
+ // Fix, to make sure no invalid values are sent.
+ ItemType = -1;
+ }
+
+ WriteShort(ItemType);
+ if (a_Item.IsEmpty())
+ {
+ return;
+ }
+
+ WriteByte (a_Item.m_ItemCount);
+ WriteShort(a_Item.m_ItemDamage);
+
+ // TODO: Implement enchantments
+ WriteShort(-1);
}
@@ -236,6 +534,7 @@ void cProtocol132::HandleEncryptionKeyResponse(const AString & a_EncKey, const A
WriteByte((char)0xfc);
WriteShort(0);
WriteShort(0);
+ Flush();
StartEncryption(DecryptedKey);
return;
diff --git a/source/Protocol132.h b/source/Protocol132.h
index a0e16b585..2373693b7 100644
--- a/source/Protocol132.h
+++ b/source/Protocol132.h
@@ -24,28 +24,58 @@ class cProtocol132 :
public:
cProtocol132(cClientHandle * a_Client);
+
+ // DEBUG:
+ virtual ~cProtocol132();
/// Called when client sends some data:
virtual void DataReceived(const char * a_Data, int a_Size) override;
+
+ // Sending commands:
+ virtual void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) override;
+ virtual void SendBlockChange (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override;
+ virtual void SendChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) override;
+ virtual void SendDestroyEntity(const cEntity & a_Entity) override;
+ virtual void SendLogin (const cPlayer & a_Player) override;
+ virtual void SendPlayerSpawn (const cPlayer & a_Player) override;
+ virtual void SendSpawnMob (const cMonster & a_Mob) override;
+ virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) override;
+
+ // DEBUG:
+ virtual void SendKeepAlive (int a_PingID) override;
/// Handling of the additional packets:
virtual int ParsePacket(unsigned char a_PacketType) override;
// Modified packets:
- virtual int ParseHandshake(void) override;
- virtual int ParseLogin (void) override;
+ virtual int ParseBlockPlace (void) override;
+ virtual int ParseHandshake (void) override;
+ virtual int ParseLogin (void) override;
+ virtual int ParsePlayerAbilities(void) override;
// New packets:
virtual int ParseClientStatuses (void);
virtual int ParseEncryptionKeyResponse(void);
-
- virtual void SendData(const char * a_Data, int a_Size);
+ virtual int ParseLocaleViewDistance (void);
protected:
bool m_IsEncrypted;
- CryptoPP::CFB_Mode<CryptoPP::AES>::Decryption m_Decryptor; // ((byte*)sDecryptedSharedSecret.c_str(),(unsigned int)16, IV, 1);
+ CryptoPP::CFB_Mode<CryptoPP::AES>::Decryption m_Decryptor;
CryptoPP::CFB_Mode<CryptoPP::AES>::Encryption m_Encryptor;
+ // DEBUG:
+ AString m_DataToSend;
+ int m_CurrentIn, m_CurrentOut;
+ int m_EncIn, m_EncOut;
+
+ virtual void SendData(const char * a_Data, int a_Size) override;
+
+ // DEBUG:
+ virtual void Flush(void) override;
+
+ // Items in slots are sent differently
+ virtual void WriteItem(const cItem & a_Item) override;
+
/// Decrypts the key and nonce, checks nonce, starts the symmetric encryption
void HandleEncryptionKeyResponse(const AString & a_EncKey, const AString & a_EncNonce);
diff --git a/source/ProtocolRecognizer.cpp b/source/ProtocolRecognizer.cpp
index d0a3f4637..6570b29e0 100644
--- a/source/ProtocolRecognizer.cpp
+++ b/source/ProtocolRecognizer.cpp
@@ -60,10 +60,10 @@ void cProtocolRecognizer::DataReceived(const char * a_Data, int a_Size)
-void cProtocolRecognizer::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2)
+void cProtocolRecognizer::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType)
{
ASSERT(m_Protocol != NULL);
- m_Protocol->SendBlockAction(a_BlockX, a_BlockY, a_BlockZ, a_Byte1, a_Byte2);
+ m_Protocol->SendBlockAction(a_BlockX, a_BlockY, a_BlockZ, a_Byte1, a_Byte2, a_BlockType);
}
diff --git a/source/ProtocolRecognizer.h b/source/ProtocolRecognizer.h
index 181c016d9..681c31bb5 100644
--- a/source/ProtocolRecognizer.h
+++ b/source/ProtocolRecognizer.h
@@ -29,7 +29,7 @@ public:
virtual void DataReceived(const char * a_Data, int a_Size) override;
/// Sending stuff to clients:
- virtual void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2) override;
+ virtual void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) override;
virtual void SendBlockChange (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override;
virtual void SendBlockChanges (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) override;
virtual void SendChat (const AString & a_Message) override;
diff --git a/source/cChestEntity.cpp b/source/cChestEntity.cpp
index a798eff47..2a69c7bdb 100644
--- a/source/cChestEntity.cpp
+++ b/source/cChestEntity.cpp
@@ -185,7 +185,7 @@ void cChestEntity::UsedBy(cPlayer * a_Player)
GetWindow()->SendWholeWindow( a_Player->GetClientHandle() );
}
}
- m_World->BroadcastBlockAction(m_PosX, m_PosY, m_PosZ, 1, 1);
+ m_World->BroadcastBlockAction(m_PosX, m_PosY, m_PosZ, 1, 1, E_BLOCK_CHEST);
// This is rather a hack
// Instead of marking the chunk as dirty upon chest contents change, we mark it dirty now
diff --git a/source/cChunk.cpp b/source/cChunk.cpp
index 17b961d3c..4e32b4dad 100644
--- a/source/cChunk.cpp
+++ b/source/cChunk.cpp
@@ -1715,7 +1715,7 @@ void cChunk::BroadcastEntHeadLook(const cEntity & a_Entity, const cClientHandle
-void cChunk::BroadcastBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, const cClientHandle * a_Exclude)
+void cChunk::BroadcastBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType, const cClientHandle * a_Exclude)
{
for (cClientHandleList::const_iterator itr = m_LoadedByClient.begin(); itr != m_LoadedByClient.end(); ++itr )
{
@@ -1723,7 +1723,7 @@ void cChunk::BroadcastBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char
{
continue;
}
- (*itr)->SendBlockAction(a_BlockX, a_BlockY, a_BlockZ, a_Byte1, a_Byte2);
+ (*itr)->SendBlockAction(a_BlockX, a_BlockY, a_BlockZ, a_Byte1, a_Byte2, a_BlockType);
} // for itr - LoadedByClient[]
}
diff --git a/source/cChunk.h b/source/cChunk.h
index c63bd8a92..f7d53ee8c 100644
--- a/source/cChunk.h
+++ b/source/cChunk.h
@@ -179,7 +179,7 @@ public:
void BroadcastEntRelMove (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude = NULL);
void BroadcastEntLook (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
void BroadcastEntHeadLook (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
- void BroadcastBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, const cClientHandle * a_Exclude = NULL);
+ void BroadcastBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType, const cClientHandle * a_Exclude = NULL);
void BroadcastDestroyEntity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
void BroadcastEntityStatus (const cEntity & a_Entity, char a_Status, const cClientHandle * a_Exclude = NULL);
void BroadcastMetadata (const cPawn & a_Pawn, const cClientHandle * a_Exclude = NULL);
diff --git a/source/cChunkMap.cpp b/source/cChunkMap.cpp
index c764a0321..5f9724179 100644
--- a/source/cChunkMap.cpp
+++ b/source/cChunkMap.cpp
@@ -325,7 +325,7 @@ void cChunkMap::BroadcastEntHeadLook(const cEntity & a_Entity, const cClientHand
-void cChunkMap::BroadcastBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, const cClientHandle * a_Exclude)
+void cChunkMap::BroadcastBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType, const cClientHandle * a_Exclude)
{
cCSLock Lock(m_CSLayers);
int x, y, z, ChunkX, ChunkZ;
@@ -339,7 +339,7 @@ void cChunkMap::BroadcastBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, c
return;
}
// It's perfectly legal to broadcast packets even to invalid chunks!
- Chunk->BroadcastBlockAction(a_BlockX, a_BlockY, a_BlockZ, a_Byte1, a_Byte2, a_Exclude);
+ Chunk->BroadcastBlockAction(a_BlockX, a_BlockY, a_BlockZ, a_Byte1, a_Byte2, a_BlockType, a_Exclude);
}
diff --git a/source/cChunkMap.h b/source/cChunkMap.h
index 36cb704a2..4996e1e04 100644
--- a/source/cChunkMap.h
+++ b/source/cChunkMap.h
@@ -61,7 +61,7 @@ public:
void BroadcastEntHeadLook(const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
/// Broadcasts a BlockAction packet to all clients who are in the specified chunk
- void BroadcastBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, const cClientHandle * a_Exclude = NULL);
+ void BroadcastBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType, const cClientHandle * a_Exclude = NULL);
void BroadcastDestroyEntity(const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
diff --git a/source/cClientHandle.cpp b/source/cClientHandle.cpp
index 29446615f..1b0944c4c 100644
--- a/source/cClientHandle.cpp
+++ b/source/cClientHandle.cpp
@@ -1158,9 +1158,9 @@ void cClientHandle::SendEntHeadLook(const cEntity & a_Entity)
-void cClientHandle::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2)
+void cClientHandle::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType)
{
- m_Protocol->SendBlockAction(a_BlockX, a_BlockY, a_BlockZ, a_Byte1, a_Byte2);
+ m_Protocol->SendBlockAction(a_BlockX, a_BlockY, a_BlockZ, a_Byte1, a_Byte2, a_BlockType);
}
diff --git a/source/cClientHandle.h b/source/cClientHandle.h
index e6887d752..ba9cde7f5 100644
--- a/source/cClientHandle.h
+++ b/source/cClientHandle.h
@@ -98,7 +98,7 @@ public:
void SendEntRelMove (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ);
void SendEntLook (const cEntity & a_Entity);
void SendEntHeadLook (const cEntity & a_Entity);
- void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2);
+ void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType);
void SendHealth (void);
void SendRespawn(void);
void SendGameMode(eGameMode a_GameMode);
diff --git a/source/cNoteEntity.cpp b/source/cNoteEntity.cpp
index 4feb9223c..44f911dc4 100644
--- a/source/cNoteEntity.cpp
+++ b/source/cNoteEntity.cpp
@@ -84,7 +84,7 @@ void cNoteEntity::MakeSound( void )
}
}
- m_World->BroadcastBlockAction(m_PosX, m_PosY, m_PosZ, instrument, m_Pitch);
+ m_World->BroadcastBlockAction(m_PosX, m_PosY, m_PosZ, instrument, m_Pitch, E_BLOCK_NOTE_BLOCK);
}
diff --git a/source/cPiston.cpp b/source/cPiston.cpp
index 464db8911..dd8541a10 100644
--- a/source/cPiston.cpp
+++ b/source/cPiston.cpp
@@ -86,7 +86,7 @@ void cPiston::ExtendPiston( int pistx, int pisty, int pistz )
oldy = pisty;
oldz = pistz;
}
- m_World->BroadcastBlockAction(pistx, pisty, pistz, 0, pistonMeta);
+ m_World->BroadcastBlockAction(pistx, pisty, pistz, 0, pistonMeta, E_BLOCK_PISTON);
m_World->FastSetBlock( pistx, pisty, pistz, pistonBlock, pistonMeta | 0x8 );
int extx = pistx;
@@ -118,7 +118,7 @@ void cPiston::RetractPiston( int pistx, int pisty, int pistz )
{
return;
}
- m_World->BroadcastBlockAction(pistx, pisty, pistz, 1, pistonMeta & ~(8));
+ m_World->BroadcastBlockAction(pistx, pisty, pistz, 1, pistonMeta & ~(8), E_BLOCK_PISTON);
m_World->FastSetBlock(pistx, pisty, pistz, pistonBlock, pistonMeta & ~(8));
AddDir(pistx, pisty, pistz, pistonMeta & 7, 1)
diff --git a/source/cPlayer.cpp b/source/cPlayer.cpp
index d3c0107ec..4605049b3 100644
--- a/source/cPlayer.cpp
+++ b/source/cPlayer.cpp
@@ -468,7 +468,7 @@ void cPlayer::CloseWindow(char a_WindowType)
{
int x, y, z;
m_CurrentWindow->GetOwner()->GetBlockPos(x, y, z);
- m_World->BroadcastBlockAction(x, y, z, 1, 0);
+ m_World->BroadcastBlockAction(x, y, z, 1, 0, E_BLOCK_CHEST);
}
m_CurrentWindow->Close( *this );
diff --git a/source/cWorld.cpp b/source/cWorld.cpp
index 9348eda7d..776d25732 100644
--- a/source/cWorld.cpp
+++ b/source/cWorld.cpp
@@ -1304,9 +1304,9 @@ void cWorld::BroadcastEntHeadLook(const cEntity & a_Entity, const cClientHandle
-void cWorld::BroadcastBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, const cClientHandle * a_Exclude)
+void cWorld::BroadcastBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType, const cClientHandle * a_Exclude)
{
- m_ChunkMap->BroadcastBlockAction(a_BlockX, a_BlockY, a_BlockZ, a_Byte1, a_Byte2, a_Exclude);
+ m_ChunkMap->BroadcastBlockAction(a_BlockX, a_BlockY, a_BlockZ, a_Byte1, a_Byte2, a_BlockType, a_Exclude);
}
diff --git a/source/cWorld.h b/source/cWorld.h
index 0751daf5c..df2f3abab 100644
--- a/source/cWorld.h
+++ b/source/cWorld.h
@@ -81,7 +81,7 @@ public:
void BroadcastEntRelMove (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude = NULL);
void BroadcastEntLook (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
void BroadcastEntHeadLook (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
- void BroadcastBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, const cClientHandle * a_Exclude = NULL);
+ void BroadcastBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType, const cClientHandle * a_Exclude = NULL);
void BroadcastDestroyEntity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
void BroadcastEntityStatus (const cEntity & a_Entity, char a_Status, const cClientHandle * a_Exclude = NULL);
void BroadcastMetadata (const cPawn & a_Pawn, const cClientHandle * a_Exclude = NULL);