1
0

ProtoProxy: The login part of the protocol is implemented.

This commit is contained in:
madmaxoft 2013-10-29 15:47:22 +01:00
parent fe82ada084
commit 21192e5ead
2 changed files with 229 additions and 220 deletions

View File

@ -52,7 +52,7 @@
#define CLIENTSEND(...) SendData(m_ClientSocket, __VA_ARGS__, "Client")
#define SERVERSEND(...) SendData(m_ServerSocket, __VA_ARGS__, "Server")
#define CLIENTENCRYPTSEND(...) SendEncryptedData(m_ClientSocket, m_ClientEncryptor, __VA_ARGS__, "Client")
#define CLIENTENCRYPTSEND(...) SendData(m_ClientSocket, __VA_ARGS__, "Client") // The client conn is always unencrypted
#define SERVERENCRYPTSEND(...) SendEncryptedData(m_ServerSocket, m_ServerEncryptor, __VA_ARGS__, "Server")
#define COPY_TO_SERVER() \
@ -99,12 +99,13 @@
CLIENTENCRYPTSEND(ToClient.data(), ToClient.size()); \
break; \
} \
case csWaitingForEncryption: \
/* case csWaitingForEncryption: \
{ \
Log("Waiting for client encryption, queued %u bytes", ToClient.size()); \
m_ClientEncryptionBuffer.append(ToClient.data(), ToClient.size()); \
break; \
} \
*/ \
} \
DebugSleep(50); \
}
@ -276,7 +277,9 @@ cConnection::cConnection(SOCKET a_ClientSocket, cServer & a_Server) :
m_ClientBuffer(1024 KiB),
m_ServerBuffer(1024 KiB),
m_HasClientPinged(false),
m_ProtocolState(-1)
m_ServerProtocolState(-1),
m_ClientProtocolState(-1),
m_IsServerEncrypted(false)
{
// Create the Logs subfolder, if not already created:
#if defined(_WIN32)
@ -459,7 +462,6 @@ bool cConnection::RelayFromServer(void)
{
m_ServerDecryptor.ProcessData((byte *)Buffer, (byte *)Buffer, res);
DataLog(Buffer, res, "Decrypted %d bytes from the SERVER", res);
m_ClientEncryptor.ProcessData((byte *)Buffer, (byte *)Buffer, res);
return CLIENTSEND(Buffer, res);
}
}
@ -492,13 +494,10 @@ bool cConnection::RelayFromClient(void)
}
case csEncryptedUnderstood:
{
m_ClientDecryptor.ProcessData((byte *)Buffer, (byte *)Buffer, res);
DataLog(Buffer, res, "Decrypted %d bytes from the CLIENT", res);
return DecodeClientsPackets(Buffer, res);
}
case csEncryptedUnknown:
{
m_ClientDecryptor.ProcessData((byte *)Buffer, (byte *)Buffer, res);
DataLog(Buffer, res, "Decrypted %d bytes from the CLIENT", res);
m_ServerEncryptor.ProcessData((byte *)Buffer, (byte *)Buffer, res);
return SERVERSEND(Buffer, res);
@ -608,7 +607,7 @@ bool cConnection::DecodeClientsPackets(const char * a_Data, int a_Size)
UInt32 PacketType;
VERIFY(m_ClientBuffer.ReadVarInt(PacketType));
Log("Decoding client's packets, there are now %d bytes in the queue; next packet is 0x%0x, %u bytes long", m_ClientBuffer.GetReadableSpace(), PacketType, PacketLen);
switch (m_ProtocolState)
switch (m_ClientProtocolState)
{
case -1:
{
@ -625,15 +624,26 @@ bool cConnection::DecodeClientsPackets(const char * a_Data, int a_Size)
// Status query
switch (PacketType)
{
case 0: HANDLE_CLIENT_READ(HandleClientStatusRequest); break;
case 1: HANDLE_CLIENT_READ(HandleClientStatusPing); break;
case 0x00: HANDLE_CLIENT_READ(HandleClientStatusRequest); break;
case 0x01: HANDLE_CLIENT_READ(HandleClientStatusPing); break;
}
break;
}
case 2:
{
// Login / game
// Login
switch (PacketType)
{
case 0x00: HANDLE_CLIENT_READ(HandleClientLoginStart); break;
case 0x01: HANDLE_CLIENT_READ(HandleClientLoginEncryptionKeyResponse); break;
}
break;
}
case 3:
{
// Game:
switch (PacketType)
{
case PACKET_BLOCK_DIG: HANDLE_CLIENT_READ(HandleClientBlockDig); break;
@ -642,7 +652,6 @@ bool cConnection::DecodeClientsPackets(const char * a_Data, int a_Size)
case PACKET_CLIENT_STATUSES: HANDLE_CLIENT_READ(HandleClientClientStatuses); break;
case PACKET_CREATIVE_INVENTORY_ACTION: HANDLE_CLIENT_READ(HandleClientCreativeInventoryAction); break;
case PACKET_DISCONNECT: HANDLE_CLIENT_READ(HandleClientDisconnect); break;
case PACKET_ENCRYPTION_KEY_RESPONSE: HANDLE_CLIENT_READ(HandleClientEncryptionKeyResponse); break;
case PACKET_ENTITY_ACTION: HANDLE_CLIENT_READ(HandleClientEntityAction); break;
case PACKET_S_KEEPALIVE: HANDLE_CLIENT_READ(HandleClientKeepAlive); break;
case PACKET_LOCALE_AND_VIEW: HANDLE_CLIENT_READ(HandleClientLocaleAndView); break;
@ -733,7 +742,7 @@ bool cConnection::DecodeServersPackets(const char * a_Data, int a_Size)
VERIFY(m_ServerBuffer.ReadVarInt(PacketType));
Log("Decoding server's packets, there are now %d bytes in the queue; next packet is 0x%0x, %u bytes long", m_ServerBuffer.GetReadableSpace(), PacketType, PacketLen);
LogFlush();
switch (m_ProtocolState)
switch (m_ServerProtocolState)
{
case -1:
{
@ -754,18 +763,30 @@ bool cConnection::DecodeServersPackets(const char * a_Data, int a_Size)
case 2:
{
// Login / game:
// Login:
switch (PacketType)
{
case PACKET_ATTACH_ENTITY: HANDLE_SERVER_READ(HandleServerAttachEntity); break;
case PACKET_BLOCK_ACTION: HANDLE_SERVER_READ(HandleServerBlockAction); break;
case PACKET_BLOCK_CHANGE: HANDLE_SERVER_READ(HandleServerBlockChange); break;
case PACKET_CHANGE_GAME_STATE: HANDLE_SERVER_READ(HandleServerChangeGameState); break;
case PACKET_C_CHAT_MESSAGE: HANDLE_SERVER_READ(HandleServerChatMessage); break;
case PACKET_COLLECT_PICKUP: HANDLE_SERVER_READ(HandleServerCollectPickup); break;
case PACKET_DESTROY_ENTITIES: HANDLE_SERVER_READ(HandleServerDestroyEntities); break;
case PACKET_ENCRYPTION_KEY_REQUEST: HANDLE_SERVER_READ(HandleServerEncryptionKeyRequest); break;
case PACKET_ENCRYPTION_KEY_RESPONSE: HANDLE_SERVER_READ(HandleServerEncryptionKeyResponse); break;
case 0x00: HANDLE_SERVER_READ(HandleServerLoginDisconnect); break;
case 0x01: HANDLE_SERVER_READ(HandleServerLoginEncryptionKeyRequest); break;
case 0x02: HANDLE_SERVER_READ(HandleServerLoginSuccess); break;
}
break;
}
case 3:
{
// Game:
switch (PacketType)
{
/*
case 0x1b: HANDLE_SERVER_READ(HandleServerAttachEntity); break;
case 0x24: HANDLE_SERVER_READ(HandleServerBlockAction); break;
case 0x23: HANDLE_SERVER_READ(HandleServerBlockChange); break;
case 0x2b: HANDLE_SERVER_READ(HandleServerChangeGameState); break;
case 0x02: HANDLE_SERVER_READ(HandleServerChatMessage); break;
case 0x0d: HANDLE_SERVER_READ(HandleServerCollectPickup); break;
case 0x13: HANDLE_SERVER_READ(HandleServerDestroyEntities); break;
*/
case PACKET_ENTITY: HANDLE_SERVER_READ(HandleServerEntity); break;
case PACKET_ENTITY_EQUIPMENT: HANDLE_SERVER_READ(HandleServerEntityEquipment); break;
case PACKET_ENTITY_HEAD_LOOK: HANDLE_SERVER_READ(HandleServerEntityHeadLook); break;
@ -852,6 +873,76 @@ bool cConnection::DecodeServersPackets(const char * a_Data, int a_Size)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// packet handling, client-side, initial handshake:
bool cConnection::HandleClientHandshake(void)
{
// Read the packet from the client:
HANDLE_CLIENT_PACKET_READ(ReadVarInt, UInt32, ProtocolVersion);
HANDLE_CLIENT_PACKET_READ(ReadVarUTF8String, AString, ServerHost);
HANDLE_CLIENT_PACKET_READ(ReadBEShort, short, ServerPort);
HANDLE_CLIENT_PACKET_READ(ReadVarInt, UInt32, NextState);
m_ClientBuffer.CommitRead();
Log("Received an initial handshake packet from the client:");
Log(" ProtocolVersion = %u", ProtocolVersion);
Log(" ServerHost = \"%s\"", ServerHost.c_str());
Log(" ServerPort = %d", ServerPort);
Log(" NextState = %u", NextState);
// Send the same packet to the server, but with our port:
cByteBuffer Packet(512);
Packet.WriteVarInt(0); // Packet type - initial handshake
Packet.WriteVarInt(ProtocolVersion);
Packet.WriteVarUTF8String(ServerHost);
Packet.WriteBEShort(m_Server.GetConnectPort());
Packet.WriteVarInt(NextState);
AString Pkt;
Packet.ReadAll(Pkt);
cByteBuffer ToServer(512);
ToServer.WriteVarUTF8String(Pkt);
SERVERSEND(ToServer);
m_ClientProtocolState = (int)NextState;
m_ServerProtocolState = (int)NextState;
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// packet handling, client-side, login:
bool cConnection::HandleClientLoginEncryptionKeyResponse(void)
{
Log("Client: Unexpected packet: encryption key response");
return true;
}
bool cConnection::HandleClientLoginStart(void)
{
HANDLE_CLIENT_PACKET_READ(ReadVarUTF8String, AString, UserName);
Log("Received a login start packet from the client:");
Log(" Username = \"%s\"", UserName.c_str());
COPY_TO_SERVER();
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// packet handling, client-side, game:
bool cConnection::HandleClientAnimation(void)
{
HANDLE_CLIENT_PACKET_READ(ReadBEInt, int, EntityID);
@ -972,33 +1063,6 @@ bool cConnection::HandleClientDisconnect(void)
bool cConnection::HandleClientEncryptionKeyResponse(void)
{
HANDLE_CLIENT_PACKET_READ(ReadBEShort, short, EncKeyLength);
AString EncKey;
if (!m_ClientBuffer.ReadString(EncKey, EncKeyLength))
{
return true;
}
HANDLE_CLIENT_PACKET_READ(ReadBEShort, short, EncNonceLength);
AString EncNonce;
if (!m_ClientBuffer.ReadString(EncNonce, EncNonceLength))
{
return true;
}
if ((EncKeyLength > MAX_ENC_LEN) || (EncNonceLength > MAX_ENC_LEN))
{
Log("Client: Too long encryption params");
return true;
}
StartClientEncryption(EncKey, EncNonce);
return true;
}
bool cConnection::HandleClientEntityAction(void)
{
HANDLE_CLIENT_PACKET_READ(ReadBEInt, int, PlayerID);
@ -1016,43 +1080,6 @@ bool cConnection::HandleClientEntityAction(void)
bool cConnection::HandleClientHandshake(void)
{
// Read the packet from the client:
HANDLE_CLIENT_PACKET_READ(ReadVarInt, UInt32, ProtocolVersion);
HANDLE_CLIENT_PACKET_READ(ReadVarUTF8String, AString, ServerHost);
HANDLE_CLIENT_PACKET_READ(ReadBEShort, short, ServerPort);
HANDLE_CLIENT_PACKET_READ(ReadVarInt, UInt32, NextState);
m_ClientBuffer.CommitRead();
Log("Received an initial handshake packet from the client:");
Log(" ProtocolVersion = %u", ProtocolVersion);
Log(" ServerHost = \"%s\"", ServerHost.c_str());
Log(" ServerPort = %d", ServerPort);
Log(" NextState = %u", NextState);
// Send the same packet to the server, but with our port:
cByteBuffer Packet(512);
Packet.WriteVarInt(0); // Packet type - initial handshake
Packet.WriteVarInt(ProtocolVersion);
Packet.WriteVarUTF8String(ServerHost);
Packet.WriteBEShort(m_Server.GetConnectPort());
Packet.WriteVarInt(NextState);
AString Pkt;
Packet.ReadAll(Pkt);
cByteBuffer ToServer(512);
ToServer.WriteVarUTF8String(Pkt);
SERVERSEND(ToServer);
m_ProtocolState = (int)NextState;
return true;
}
bool cConnection::HandleClientKeepAlive(void)
{
HANDLE_CLIENT_PACKET_READ(ReadBEInt, int, ID);
@ -1325,6 +1352,84 @@ bool cConnection::HandleClientWindowClose(void)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// packet handling, server-side, login:
bool cConnection::HandleServerLoginDisconnect(void)
{
HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Reason);
Log("Received a login-disconnect packet from the server:");
Log(" Reason = \"%s\"", Reason.c_str());
COPY_TO_SERVER();
return true;
}
bool cConnection::HandleServerLoginEncryptionKeyRequest(void)
{
// Read the packet from the server:
HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, ServerID);
HANDLE_SERVER_PACKET_READ(ReadBEShort, short, PublicKeyLength);
AString PublicKey;
if (!m_ServerBuffer.ReadString(PublicKey, PublicKeyLength))
{
return false;
}
HANDLE_SERVER_PACKET_READ(ReadBEShort, short, NonceLength);
AString Nonce;
if (!m_ServerBuffer.ReadString(Nonce, NonceLength))
{
return false;
}
Log("Got PACKET_ENCRYPTION_KEY_REQUEST from the SERVER:");
Log(" ServerID = %s", ServerID.c_str());
// Reply to the server:
SendEncryptionKeyResponse(PublicKey, Nonce);
// Do not send to client - we want the client connection open
return true;
}
bool cConnection::HandleServerLoginSuccess(void)
{
HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, UUID);
HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Username);
Log("Received a login success packet from the server:");
Log(" UUID = \"%s\"", UUID.c_str());
Log(" Username = \"%s\"", Username.c_str());
Log("Server is now in protocol state Game.");
m_ServerProtocolState = 3;
if (m_IsServerEncrypted)
{
Log("Server communication is now encrypted");
m_ServerState = csEncryptedUnderstood;
DataLog(m_ServerEncryptionBuffer.data(), m_ServerEncryptionBuffer.size(), "Sending the queued data to server (%u bytes):", m_ServerEncryptionBuffer.size());
SERVERENCRYPTSEND(m_ServerEncryptionBuffer.data(), m_ServerEncryptionBuffer.size());
m_ServerEncryptionBuffer.clear();
}
COPY_TO_CLIENT();
Log("Client is now in protocol state Game.");
m_ClientProtocolState = 3;
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// packet handling, server-side, game:
bool cConnection::HandleServerAttachEntity(void)
{
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, EntityID);
@ -1453,48 +1558,6 @@ bool cConnection::HandleServerDestroyEntities(void)
bool cConnection::HandleServerEncryptionKeyRequest(void)
{
// Read the packet from the server:
HANDLE_SERVER_PACKET_READ(ReadBEUTF16String16, AString, ServerID);
HANDLE_SERVER_PACKET_READ(ReadBEShort, short, PublicKeyLength);
AString PublicKey;
if (!m_ServerBuffer.ReadString(PublicKey, PublicKeyLength))
{
return false;
}
HANDLE_SERVER_PACKET_READ(ReadBEShort, short, NonceLength);
AString Nonce;
if (!m_ServerBuffer.ReadString(Nonce, NonceLength))
{
return false;
}
Log("Got PACKET_ENCRYPTION_KEY_REQUEST from the SERVER:");
Log(" ServerID = %s", ServerID.c_str());
// Reply to the server:
SendEncryptionKeyResponse(PublicKey, Nonce);
// Send a 0xFD Encryption Key Request http://wiki.vg/Protocol#0xFD to the client, using our own key:
Log("Sending PACKET_ENCRYPTION_KEY_REQUEST to the CLIENT");
AString key;
StringSink sink(key); // GCC won't allow inline instantiation in the following line, damned temporary refs
m_Server.GetPublicKey().Save(sink);
cByteBuffer ToClient(512);
ToClient.WriteByte (PACKET_ENCRYPTION_KEY_REQUEST);
ToClient.WriteBEUTF16String16(ServerID);
ToClient.WriteBEShort ((short)key.size());
ToClient.WriteBuf (key.data(), key.size());
ToClient.WriteBEShort (4);
ToClient.WriteBEInt (m_Nonce); // Using 'this' as the cryptographic nonce, so that we don't have to generate one each time :)
CLIENTSEND(ToClient);
return true;
}
bool cConnection::HandleServerEntity(void)
{
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, EntityID);
@ -1779,26 +1842,6 @@ bool cConnection::HandleServerKeepAlive(void)
bool cConnection::HandleServerEncryptionKeyResponse(void)
{
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, Lengths);
if (Lengths != 0)
{
Log("Lengths are not zero!");
return true;
}
Log("Server communication is now encrypted");
m_ServerState = csEncryptedUnderstood;
DataLog(m_ServerEncryptionBuffer.data(), m_ServerEncryptionBuffer.size(), "Sending the queued data to server (%u bytes):", m_ServerEncryptionBuffer.size());
SERVERENCRYPTSEND(m_ServerEncryptionBuffer.data(), m_ServerEncryptionBuffer.size());
m_ServerEncryptionBuffer.clear();
return true;
}
bool cConnection::HandleServerKick(void)
{
HANDLE_SERVER_PACKET_READ(ReadBEUTF16String16, AString, Reason);
@ -2826,68 +2869,14 @@ void cConnection::SendEncryptionKeyResponse(const AString & a_ServerPublicKey, c
// Send the packet to the server:
Log("Sending PACKET_ENCRYPTION_KEY_RESPONSE to the SERVER");
cByteBuffer ToServer(1024);
ToServer.WriteByte(PACKET_ENCRYPTION_KEY_RESPONSE);
ToServer.WriteByte(0x01); // To server: Encryption key response
ToServer.WriteBEShort(EncryptedLength);
ToServer.WriteBuf(EncryptedSecret, EncryptedLength);
ToServer.WriteBEShort(EncryptedLength);
ToServer.WriteBuf(EncryptedNonce, EncryptedLength);
SERVERSEND(ToServer);
m_ServerState = csWaitingForEncryption;
}
void cConnection::StartClientEncryption(const AString & a_EncKey, const AString & a_EncNonce)
{
// Decrypt EncNonce using privkey
RSAES<PKCS1v15>::Decryptor rsaDecryptor(m_Server.GetPrivateKey());
time_t CurTime = time(NULL);
RandomPool rng;
rng.Put((const byte *)&CurTime, sizeof(CurTime));
byte DecryptedNonce[MAX_ENC_LEN];
DecodingResult res = rsaDecryptor.Decrypt(rng, (const byte *)a_EncNonce.data(), a_EncNonce.size(), DecryptedNonce);
if (!res.isValidCoding || (res.messageLength != 4))
{
Log("Client: Bad nonce length");
return;
}
if (ntohl(*((int *)DecryptedNonce)) != m_Nonce)
{
Log("Bad nonce value");
return;
}
// Decrypt the symmetric encryption key using privkey:
byte SharedSecret[MAX_ENC_LEN];
res = rsaDecryptor.Decrypt(rng, (const byte *)a_EncKey.data(), a_EncKey.size(), SharedSecret);
if (!res.isValidCoding || (res.messageLength != 16))
{
Log("Bad key length");
return;
}
// Send encryption key response:
cByteBuffer ToClient(6);
ToClient.WriteByte((char)0xfc);
ToClient.WriteBEShort(0);
ToClient.WriteBEShort(0);
CLIENTSEND(ToClient);
// Start the encryption:
m_ClientEncryptor.SetKey(SharedSecret, 16, MakeParameters(Name::IV(), ConstByteArrayParameter(SharedSecret, 16))(Name::FeedbackSize(), 1));
m_ClientDecryptor.SetKey(SharedSecret, 16, MakeParameters(Name::IV(), ConstByteArrayParameter(SharedSecret, 16))(Name::FeedbackSize(), 1));
Log("Client connection is now encrypted");
m_ClientState = csEncryptedUnderstood;
// Send the queued data:
DataLog(m_ClientEncryptionBuffer.data(), m_ClientEncryptionBuffer.size(), "Sending the queued data to client (%u bytes):", m_ClientEncryptionBuffer.size());
CLIENTENCRYPTSEND(m_ClientEncryptionBuffer.data(), m_ClientEncryptionBuffer.size());
m_ClientEncryptionBuffer.clear();
// Handle all postponed server data
DecodeServersPackets(NULL, 0);
m_ServerState = csEncryptedUnderstood;
m_IsServerEncrypted = true;
}

View File

@ -71,17 +71,27 @@ protected:
Decryptor m_ServerDecryptor;
Encryptor m_ServerEncryptor;
Decryptor m_ClientDecryptor;
Encryptor m_ClientEncryptor;
AString m_ClientEncryptionBuffer; // Buffer for the data to be sent to the client once encryption is established
AString m_ServerEncryptionBuffer; // Buffer for the data to be sent to the server once encryption is established
/// Set to true when PACKET_PING is received from the client; will cause special parsing for server kick
bool m_HasClientPinged;
/// State the protocol is in (as defined by the initial handshake), -1 if no initial handshake received yet
int m_ProtocolState;
/*
The protocol states can be one of:
-1: no initial handshake received yet
1: status
2: login
3: game
*/
/// State the to-server protocol is in (as defined by the initial handshake / login), -1 if no initial handshake received yet
int m_ServerProtocolState;
/// State the to-client protocol is in (as defined by the initial handshake / login), -1 if no initial handshake received yet
int m_ClientProtocolState;
/// True if the server connection has provided encryption keys
bool m_IsServerEncrypted;
bool ConnectToServer(void);
@ -112,7 +122,18 @@ protected:
/// Decodes packets coming from the server, sends appropriate counterparts to the client; returns false if the connection is to be dropped
bool DecodeServersPackets(const char * a_Data, int a_Size);
// Packet handling, client-side:
// Packet handling, client-side, initial:
bool HandleClientHandshake(void);
// Packet handling, client-side, status:
bool HandleClientStatusPing(void);
bool HandleClientStatusRequest(void);
// Packet handling, client-side, login:
bool HandleClientLoginEncryptionKeyResponse(void);
bool HandleClientLoginStart(void);
// Packet handling, client-side, game:
bool HandleClientAnimation(void);
bool HandleClientBlockDig(void);
bool HandleClientBlockPlace(void);
@ -120,9 +141,7 @@ protected:
bool HandleClientClientStatuses(void);
bool HandleClientCreativeInventoryAction(void);
bool HandleClientDisconnect(void);
bool HandleClientEncryptionKeyResponse(void);
bool HandleClientEntityAction(void);
bool HandleClientHandshake(void);
bool HandleClientKeepAlive(void);
bool HandleClientLocaleAndView(void);
bool HandleClientPing(void);
@ -133,15 +152,18 @@ protected:
bool HandleClientPlayerPositionLook(void);
bool HandleClientPluginMessage(void);
bool HandleClientSlotSelect(void);
bool HandleClientStatusPing(void);
bool HandleClientStatusRequest(void);
bool HandleClientTabCompletion(void);
bool HandleClientUpdateSign(void);
bool HandleClientUseEntity(void);
bool HandleClientWindowClick(void);
bool HandleClientWindowClose(void);
// Packet handling, server-side:
// Packet handling, server-side, login:
bool HandleServerLoginDisconnect(void);
bool HandleServerLoginEncryptionKeyRequest(void);
bool HandleServerLoginSuccess(void);
// Packet handling, server-side, game:
bool HandleServerAttachEntity(void);
bool HandleServerBlockAction(void);
bool HandleServerBlockChange(void);
@ -150,8 +172,6 @@ protected:
bool HandleServerCollectPickup(void);
bool HandleServerCompass(void);
bool HandleServerDestroyEntities(void);
bool HandleServerEncryptionKeyRequest(void);
bool HandleServerEncryptionKeyResponse(void);
bool HandleServerEntity(void);
bool HandleServerEntityEquipment(void);
bool HandleServerEntityHeadLook(void);