summaryrefslogtreecommitdiffstats
path: root/source/Protocol132.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/Protocol132.cpp')
-rw-r--r--source/Protocol132.cpp339
1 files changed, 319 insertions, 20 deletions
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;