Merge pull request #1466 from mc-server/endofsupport
Removed protocols 1.2 to 1.6
This commit is contained in:
commit
8d55cd409e
@ -1819,8 +1819,7 @@ bool cConnection::HandleServerKick(void)
|
||||
Reason.append(Split[4]);
|
||||
Reason.push_back(0);
|
||||
Reason.append(Split[5]);
|
||||
AString ReasonBE16;
|
||||
UTF8ToRawBEUTF16(Reason.data(), Reason.size(), ReasonBE16);
|
||||
AString ReasonBE16 = UTF8ToRawBEUTF16(Reason.data(), Reason.size());
|
||||
AString PacketStart("\xff");
|
||||
PacketStart.push_back((ReasonBE16.size() / 2) / 256);
|
||||
PacketStart.push_back((ReasonBE16.size() / 2) % 256);
|
||||
|
@ -627,23 +627,6 @@ bool cByteBuffer::WriteBool(bool a_Value)
|
||||
|
||||
|
||||
|
||||
bool cByteBuffer::WriteBEUTF16String16(const AString & a_Value)
|
||||
{
|
||||
CHECK_THREAD;
|
||||
CheckValid();
|
||||
PUTBYTES(2);
|
||||
AString UTF16BE;
|
||||
UTF8ToRawBEUTF16(a_Value.data(), a_Value.size(), UTF16BE);
|
||||
WriteBEShort((short)(UTF16BE.size() / 2));
|
||||
PUTBYTES(UTF16BE.size());
|
||||
WriteBuf(UTF16BE.data(), UTF16BE.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cByteBuffer::WriteVarInt(UInt32 a_Value)
|
||||
{
|
||||
CHECK_THREAD;
|
||||
|
@ -88,7 +88,6 @@ public:
|
||||
bool WriteBEFloat (float a_Value);
|
||||
bool WriteBEDouble (double a_Value);
|
||||
bool WriteBool (bool a_Value);
|
||||
bool WriteBEUTF16String16(const AString & a_Value); // string length as BE short, then string as UTF-16BE
|
||||
bool WriteVarInt (UInt32 a_Value);
|
||||
bool WriteVarUTF8String (const AString & a_Value); // string length as VarInt, then string as UTF-8
|
||||
bool WriteLEInt (int a_Value);
|
||||
|
@ -1749,20 +1749,6 @@ void cClientHandle::HandleRespawn(void)
|
||||
|
||||
|
||||
|
||||
void cClientHandle::HandleDisconnect(const AString & a_Reason)
|
||||
{
|
||||
LOGD("Received d/c packet from %s with reason \"%s\"", m_Username.c_str(), a_Reason.c_str());
|
||||
|
||||
cRoot::Get()->GetPluginManager()->CallHookDisconnect(*this, a_Reason);
|
||||
|
||||
m_HasSentDC = true;
|
||||
Destroy();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cClientHandle::HandleKeepAlive(int a_KeepAliveID)
|
||||
{
|
||||
if (a_KeepAliveID == m_PingID)
|
||||
|
@ -239,7 +239,6 @@ public:
|
||||
void HandleAnimation (char a_Animation);
|
||||
void HandleChat (const AString & a_Message);
|
||||
void HandleCreativeInventory(short a_SlotNum, const cItem & a_HeldItem);
|
||||
void HandleDisconnect (const AString & a_Reason);
|
||||
void HandleEntityCrouch (int a_EntityID, bool a_IsCrouching);
|
||||
void HandleEntityLeaveBed (int a_EntityID);
|
||||
void HandleEntitySprinting (int a_EntityID, bool a_IsSprinting);
|
||||
|
@ -8,11 +8,6 @@ SET (SRCS
|
||||
Authenticator.cpp
|
||||
ChunkDataSerializer.cpp
|
||||
MojangAPI.cpp
|
||||
Protocol125.cpp
|
||||
Protocol132.cpp
|
||||
Protocol14x.cpp
|
||||
Protocol15x.cpp
|
||||
Protocol16x.cpp
|
||||
Protocol17x.cpp
|
||||
Protocol18x.cpp
|
||||
ProtocolRecognizer.cpp)
|
||||
@ -22,11 +17,6 @@ SET (HDRS
|
||||
ChunkDataSerializer.h
|
||||
MojangAPI.h
|
||||
Protocol.h
|
||||
Protocol125.h
|
||||
Protocol132.h
|
||||
Protocol14x.h
|
||||
Protocol15x.h
|
||||
Protocol16x.h
|
||||
Protocol17x.h
|
||||
Protocol18x.h
|
||||
ProtocolRecognizer.h)
|
||||
|
@ -138,108 +138,9 @@ public:
|
||||
protected:
|
||||
cClientHandle * m_Client;
|
||||
cCriticalSection m_CSPacket; // Each SendXYZ() function must acquire this CS in order to send the whole packet at once
|
||||
|
||||
|
||||
/// A generic data-sending routine, all outgoing packet data needs to be routed through this so that descendants may override it
|
||||
virtual void SendData(const char * a_Data, size_t a_Size) = 0;
|
||||
|
||||
/// Called after writing each packet, enables descendants to flush their buffers
|
||||
virtual void Flush(void) {}
|
||||
|
||||
// Helpers for writing partial packet data, write using SendData()
|
||||
void WriteByte(Byte a_Value)
|
||||
{
|
||||
SendData((const char *)&a_Value, 1);
|
||||
}
|
||||
|
||||
void WriteChar(char a_Value)
|
||||
{
|
||||
SendData(&a_Value, 1);
|
||||
}
|
||||
|
||||
void WriteShort(short a_Value)
|
||||
{
|
||||
u_short Value = htons((u_short)a_Value);
|
||||
SendData((const char *)&Value, 2);
|
||||
}
|
||||
|
||||
/*
|
||||
void WriteShort(unsigned short a_Value)
|
||||
{
|
||||
a_Value = htons(a_Value);
|
||||
SendData((const char *)&a_Value, 2);
|
||||
}
|
||||
*/
|
||||
|
||||
void WriteInt(int a_Value)
|
||||
{
|
||||
u_long Value = htonl((u_long)a_Value);
|
||||
SendData((const char *)&Value, 4);
|
||||
}
|
||||
|
||||
void WriteUInt(unsigned int a_Value)
|
||||
{
|
||||
a_Value = htonl(a_Value);
|
||||
SendData((const char *)&a_Value, 4);
|
||||
}
|
||||
|
||||
void WriteInt64 (Int64 a_Value)
|
||||
{
|
||||
UInt64 Value = HostToNetwork8(&a_Value);
|
||||
SendData((const char *)&Value, 8);
|
||||
}
|
||||
|
||||
void WriteFloat (float a_Value)
|
||||
{
|
||||
UInt32 val = HostToNetwork4(&a_Value);
|
||||
SendData((const char *)&val, 4);
|
||||
}
|
||||
|
||||
void WriteDouble(double a_Value)
|
||||
{
|
||||
UInt64 val = HostToNetwork8(&a_Value);
|
||||
SendData((const char *)&val, 8);
|
||||
}
|
||||
|
||||
void WriteString(const AString & a_Value)
|
||||
{
|
||||
AString UTF16;
|
||||
UTF8ToRawBEUTF16(a_Value.c_str(), a_Value.length(), UTF16);
|
||||
WriteShort((short)(UTF16.size() / 2));
|
||||
SendData(UTF16.data(), UTF16.size());
|
||||
}
|
||||
|
||||
void WriteBool(bool a_Value)
|
||||
{
|
||||
WriteByte(a_Value ? 1 : 0);
|
||||
}
|
||||
|
||||
void WriteVectorI(const Vector3i & a_Vector)
|
||||
{
|
||||
WriteInt(a_Vector.x);
|
||||
WriteInt(a_Vector.y);
|
||||
WriteInt(a_Vector.z);
|
||||
}
|
||||
|
||||
void WriteVarInt(UInt32 a_Value)
|
||||
{
|
||||
// A 32-bit integer can be encoded by at most 5 bytes:
|
||||
unsigned char b[5];
|
||||
size_t idx = 0;
|
||||
do
|
||||
{
|
||||
b[idx] = (a_Value & 0x7f) | ((a_Value > 0x7f) ? 0x80 : 0x00);
|
||||
a_Value = a_Value >> 7;
|
||||
idx++;
|
||||
} while (a_Value > 0);
|
||||
|
||||
SendData((const char *)b, idx);
|
||||
}
|
||||
|
||||
void WriteVarUTF8String(const AString & a_String)
|
||||
{
|
||||
WriteVarInt((UInt32)a_String.size());
|
||||
SendData(a_String.data(), a_String.size());
|
||||
}
|
||||
} ;
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,185 +0,0 @@
|
||||
|
||||
// Protocol125.h
|
||||
|
||||
// Interfaces to the cProtocol125 class representing the release 1.2.5 protocol (#29)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Protocol.h"
|
||||
#include "../ByteBuffer.h"
|
||||
#include "../Entities/Painting.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cProtocol125 :
|
||||
public cProtocol
|
||||
{
|
||||
typedef cProtocol super;
|
||||
public:
|
||||
cProtocol125(cClientHandle * a_Client);
|
||||
|
||||
/// Called when client sends some data:
|
||||
virtual void DataReceived(const char * a_Data, size_t a_Size) override;
|
||||
|
||||
/// Sending stuff to clients (alphabetically sorted):
|
||||
virtual void SendAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle) 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 SendBlockBreakAnim (int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage) 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;
|
||||
virtual void SendChat (const cCompositeChat & a_Message) override;
|
||||
virtual void SendChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) override;
|
||||
virtual void SendCollectEntity (const cEntity & a_Entity, const cPlayer & a_Player) override;
|
||||
virtual void SendDestroyEntity (const cEntity & a_Entity) override;
|
||||
virtual void SendDisconnect (const AString & a_Reason) override;
|
||||
virtual void SendEditSign (int a_BlockX, int a_BlockY, int a_BlockZ) override; ///< Request the client to open up the sign editor for the sign (1.6+)
|
||||
virtual void SendEntityEffect (const cEntity & a_Entity, int a_EffectID, int a_Amplifier, short a_Duration) override;
|
||||
virtual void SendEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) override;
|
||||
virtual void SendEntityHeadLook (const cEntity & a_Entity) override;
|
||||
virtual void SendEntityLook (const cEntity & a_Entity) override;
|
||||
virtual void SendEntityMetadata (const cEntity & a_Entity) override;
|
||||
virtual void SendEntityProperties (const cEntity & a_Entity) override;
|
||||
virtual void SendEntityRelMove (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) override;
|
||||
virtual void SendEntityRelMoveLook (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) override;
|
||||
virtual void SendEntityStatus (const cEntity & a_Entity, char a_Status) override;
|
||||
virtual void SendEntityVelocity (const cEntity & a_Entity) override;
|
||||
virtual void SendExplosion (double a_BlockX, double a_BlockY, double a_BlockZ, float a_Radius, const cVector3iArray & a_BlocksAffected, const Vector3d & a_PlayerMotion) override;
|
||||
virtual void SendGameMode (eGameMode a_GameMode) override;
|
||||
virtual void SendHealth (void) override;
|
||||
virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) override;
|
||||
virtual void SendKeepAlive (int a_PingID) override;
|
||||
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override;
|
||||
virtual void SendLoginSuccess (void) override;
|
||||
virtual void SendMapColumn (int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length, unsigned int m_Scale) override;
|
||||
virtual void SendMapDecorators (int a_ID, const cMapDecoratorList & a_Decorators, unsigned int m_Scale) override;
|
||||
virtual void SendMapInfo (int a_ID, unsigned int a_Scale) override;
|
||||
virtual void SendParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmount) override;
|
||||
virtual void SendPaintingSpawn (const cPainting & a_Painting) override;
|
||||
virtual void SendPickupSpawn (const cPickup & a_Pickup) override;
|
||||
virtual void SendPlayerAbilities (void) override {} // This protocol doesn't support such message
|
||||
virtual void SendEntityAnimation (const cEntity & a_Entity, char a_Animation) override;
|
||||
virtual void SendPlayerListAddPlayer (const cPlayer & a_Player) override;
|
||||
virtual void SendPlayerListRemovePlayer (const cPlayer & a_Player) override;
|
||||
virtual void SendPlayerListUpdateGameMode (const cPlayer & a_Player) override;
|
||||
virtual void SendPlayerListUpdatePing (const cPlayer & a_Player) override;
|
||||
virtual void SendPlayerListUpdateDisplayName(const cPlayer & a_Player, const AString & a_CustomName) override;
|
||||
virtual void SendPlayerMaxSpeed (void) override;
|
||||
virtual void SendPlayerMoveLook (void) override;
|
||||
virtual void SendPlayerPosition (void) override;
|
||||
virtual void SendPlayerSpawn (const cPlayer & a_Player) override;
|
||||
virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) override;
|
||||
virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) override;
|
||||
virtual void SendRespawn (eDimension a_Dimension, bool a_ShouldIgnoreDimensionChecks) override;
|
||||
virtual void SendExperience (void) override;
|
||||
virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) override;
|
||||
virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override;
|
||||
virtual void SendScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) override {} // This protocol doesn't support such message
|
||||
virtual void SendDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) override {} // This protocol doesn't support such message
|
||||
virtual void SendSoundEffect (const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch) override;
|
||||
virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override;
|
||||
virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) override;
|
||||
virtual void SendSpawnMob (const cMonster & a_Mob) override;
|
||||
virtual void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch) override;
|
||||
virtual void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType) override;
|
||||
virtual void SendStatistics (const cStatManager & a_Manager) override;
|
||||
virtual void SendTabCompletionResults (const AStringVector & a_Results) override;
|
||||
virtual void SendTeleportEntity (const cEntity & a_Entity) override;
|
||||
virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override;
|
||||
virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle) override;
|
||||
virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) override;
|
||||
virtual void SendUpdateBlockEntity (cBlockEntity & a_BlockEntity) override {}
|
||||
virtual void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) override;
|
||||
virtual void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ) override;
|
||||
virtual void SendWeather (eWeather a_Weather) override;
|
||||
virtual void SendWholeInventory (const cWindow & a_Window) override;
|
||||
virtual void SendWindowClose (const cWindow & a_Window) override;
|
||||
virtual void SendWindowOpen (const cWindow & a_Window) override;
|
||||
virtual void SendWindowProperty (const cWindow & a_Window, int a_Property, int a_Value) override;
|
||||
|
||||
virtual AString GetAuthServerID(void) override;
|
||||
|
||||
protected:
|
||||
/// Results of packet-parsing:
|
||||
enum eParseResult
|
||||
{
|
||||
PARSE_OK = 1,
|
||||
PARSE_ERROR = -1,
|
||||
PARSE_UNKNOWN = -2,
|
||||
PARSE_INCOMPLETE = -3,
|
||||
} ;
|
||||
|
||||
cByteBuffer m_ReceivedData; ///< Buffer for the received data
|
||||
|
||||
AString m_Username; ///< Stored in ParseHandshake(), compared to Login username
|
||||
|
||||
/** The dimension that was last sent to a player in a Respawn or Login packet.
|
||||
Used to avoid Respawning into the same dimension, which confuses the client. */
|
||||
eDimension m_LastSentDimension;
|
||||
|
||||
virtual void SendData(const char * a_Data, size_t a_Size) override;
|
||||
|
||||
/// Sends the Handshake packet
|
||||
void SendHandshake(const AString & a_ConnectionHash);
|
||||
|
||||
/// Parse the packet of the specified type from m_ReceivedData (switch into ParseXYZ())
|
||||
virtual int ParsePacket(unsigned char a_PacketType);
|
||||
|
||||
// Specific packet parsers:
|
||||
virtual int ParseArmAnim (void);
|
||||
virtual int ParseBlockDig (void);
|
||||
virtual int ParseBlockPlace (void);
|
||||
virtual int ParseChat (void);
|
||||
virtual int ParseCreativeInventoryAction(void);
|
||||
virtual int ParseDisconnect (void);
|
||||
virtual int ParseEntityAction (void);
|
||||
virtual int ParseHandshake (void);
|
||||
virtual int ParseKeepAlive (void);
|
||||
virtual int ParseLogin (void);
|
||||
virtual int ParsePing (void);
|
||||
virtual int ParsePlayerAbilities (void);
|
||||
virtual int ParsePlayerLook (void);
|
||||
virtual int ParsePlayerMoveLook (void);
|
||||
virtual int ParsePlayerOnGround (void);
|
||||
virtual int ParsePlayerPosition (void);
|
||||
virtual int ParsePluginMessage (void);
|
||||
virtual int ParseRespawn (void);
|
||||
virtual int ParseSlotSelected (void);
|
||||
virtual int ParseUpdateSign (void);
|
||||
virtual int ParseUseEntity (void);
|
||||
virtual int ParseEnchantItem (void);
|
||||
virtual int ParseWindowClick (void);
|
||||
virtual int ParseWindowClose (void);
|
||||
|
||||
// Utility functions:
|
||||
/// Writes a "pre-chunk" packet
|
||||
void SendPreChunk(int a_ChunkX, int a_ChunkZ, bool a_ShouldLoad);
|
||||
|
||||
/// Writes a "set window items" packet with the specified params
|
||||
void SendWindowSlots(char a_WindowID, int a_NumItems, const cItem * a_Items);
|
||||
|
||||
/// Writes one item, "slot" as the protocol wiki calls it
|
||||
virtual void WriteItem(const cItem & a_Item);
|
||||
|
||||
/// Parses one item, "slot" as the protocol wiki calls it, from m_ReceivedData; returns the usual ParsePacket() codes
|
||||
virtual int ParseItem(cItem & a_Item);
|
||||
|
||||
/// Writes the COMMON entity metadata
|
||||
void WriteCommonMetadata(const cEntity & a_Entity);
|
||||
|
||||
/// Writes normal entity metadata
|
||||
void WriteEntityMetadata(const cEntity & a_Entity);
|
||||
|
||||
/// Writes mobile entity metadata
|
||||
void WriteMobMetadata(const cMonster & a_Mob);
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
@ -1,880 +0,0 @@
|
||||
|
||||
// Protocol132.cpp
|
||||
|
||||
// Implements the cProtocol132 class representing the release 1.3.2 protocol (#39)
|
||||
|
||||
#include "Globals.h"
|
||||
#include "ChunkDataSerializer.h"
|
||||
#include "Protocol132.h"
|
||||
#include "../Root.h"
|
||||
#include "../Server.h"
|
||||
#include "../World.h"
|
||||
#include "../ClientHandle.h"
|
||||
#include "../Item.h"
|
||||
#include "../Entities/Player.h"
|
||||
#include "../Mobs/Monster.h"
|
||||
#include "../UI/Window.h"
|
||||
#include "../Entities/Pickup.h"
|
||||
#include "../WorldStorage/FastNBT.h"
|
||||
#include "../WorldStorage/EnchantmentSerializer.h"
|
||||
#include "../StringCompression.h"
|
||||
#include "PolarSSL++/Sha1Checksum.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define HANDLE_PACKET_READ(Proc, Type, Var) \
|
||||
Type Var; \
|
||||
{ \
|
||||
if (!m_ReceivedData.Proc(Var)) \
|
||||
{ \
|
||||
m_ReceivedData.CheckValid(); \
|
||||
return PARSE_INCOMPLETE; \
|
||||
} \
|
||||
m_ReceivedData.CheckValid(); \
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const int MAX_ENC_LEN = 512; // Maximum size of the encrypted message; should be 128, but who knows...
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PACKET_KEEP_ALIVE = 0x00,
|
||||
PACKET_LOGIN = 0x01,
|
||||
PACKET_ENTITY_EQUIPMENT = 0x05,
|
||||
PACKET_COMPASS = 0x06,
|
||||
PACKET_PLAYER_SPAWN = 0x14,
|
||||
PACKET_COLLECT_PICKUP = 0x16,
|
||||
PACKET_SPAWN_MOB = 0x18,
|
||||
PACKET_DESTROY_ENTITIES = 0x1d,
|
||||
PACKET_CHUNK_DATA = 0x33,
|
||||
PACKET_BLOCK_CHANGE = 0x35,
|
||||
PACKET_BLOCK_ACTION = 0x36,
|
||||
PACKET_BLOCK_BREAK_ANIM = 0x37,
|
||||
PACKET_SOUND_EFFECT = 0x3e,
|
||||
PACKET_SOUND_PARTICLE_EFFECT = 0x3d,
|
||||
PACKET_TAB_COMPLETION = 0xcb,
|
||||
PACKET_LOCALE_VIEW_DISTANCE = 0xcc,
|
||||
PACKET_CLIENT_STATUSES = 0xcd,
|
||||
PACKET_ENCRYPTION_KEY_RESP = 0xfc,
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cProtocol132:
|
||||
|
||||
cProtocol132::cProtocol132(cClientHandle * a_Client) :
|
||||
super(a_Client),
|
||||
m_IsEncrypted(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cProtocol132::~cProtocol132()
|
||||
{
|
||||
if (!m_DataToSend.empty())
|
||||
{
|
||||
LOGD("There are " SIZE_T_FMT " unsent bytes while deleting cProtocol132", m_DataToSend.size());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol132::DataReceived(const char * a_Data, size_t a_Size)
|
||||
{
|
||||
if (m_IsEncrypted)
|
||||
{
|
||||
Byte Decrypted[512];
|
||||
while (a_Size > 0)
|
||||
{
|
||||
size_t NumBytes = (a_Size > sizeof(Decrypted)) ? sizeof(Decrypted) : a_Size;
|
||||
m_Decryptor.ProcessData(Decrypted, (Byte *)a_Data, NumBytes);
|
||||
super::DataReceived((const char *)Decrypted, NumBytes);
|
||||
a_Size -= NumBytes;
|
||||
a_Data += NumBytes;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
super::DataReceived(a_Data, 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);
|
||||
WriteChar (a_Byte1);
|
||||
WriteChar (a_Byte2);
|
||||
WriteShort(a_BlockType);
|
||||
Flush();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol132::SendBlockBreakAnim(int a_entityID, int a_BlockX, int a_BlockY, int a_BlockZ, char stage)
|
||||
{
|
||||
cCSLock Lock(m_CSPacket);
|
||||
WriteByte (PACKET_BLOCK_BREAK_ANIM);
|
||||
WriteInt (a_entityID);
|
||||
WriteInt (a_BlockX);
|
||||
WriteInt (a_BlockY);
|
||||
WriteInt (a_BlockZ);
|
||||
WriteChar (stage);
|
||||
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:
|
||||
AString Serialized = a_Serializer.Serialize(cChunkDataSerializer::RELEASE_1_3_2, a_ChunkX, a_ChunkZ);
|
||||
WriteByte(PACKET_CHUNK_DATA);
|
||||
WriteInt (a_ChunkX);
|
||||
WriteInt (a_ChunkZ);
|
||||
SendData(Serialized.data(), Serialized.size());
|
||||
Flush();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol132::SendCollectEntity(const cEntity & a_Entity, const cPlayer & a_Player)
|
||||
{
|
||||
cCSLock Lock(m_CSPacket);
|
||||
WriteByte(PACKET_COLLECT_PICKUP);
|
||||
WriteInt (a_Entity.GetUniqueID());
|
||||
WriteInt (a_Player.GetUniqueID());
|
||||
Flush();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol132::SendDestroyEntity(const cEntity & a_Entity)
|
||||
{
|
||||
if (a_Entity.GetUniqueID() == m_Client->GetPlayer()->GetUniqueID())
|
||||
{
|
||||
// Do not send "destroy self" to the client, the client would crash (FS #254)
|
||||
return;
|
||||
}
|
||||
|
||||
cCSLock Lock(m_CSPacket);
|
||||
WriteByte(PACKET_DESTROY_ENTITIES);
|
||||
WriteByte(1); // entity count
|
||||
WriteInt (a_Entity.GetUniqueID());
|
||||
Flush();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol132::SendEntityEquipment(const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item)
|
||||
{
|
||||
cCSLock Lock(m_CSPacket);
|
||||
WriteByte (PACKET_ENTITY_EQUIPMENT);
|
||||
WriteInt (a_Entity.GetUniqueID());
|
||||
WriteShort(a_SlotNum);
|
||||
WriteItem (a_Item);
|
||||
Flush();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol132::SendLogin(const cPlayer & a_Player, const cWorld & a_World)
|
||||
{
|
||||
cCSLock Lock(m_CSPacket);
|
||||
WriteByte (PACKET_LOGIN);
|
||||
WriteInt (a_Player.GetUniqueID()); // EntityID of the player
|
||||
WriteString("default"); // Level type
|
||||
WriteByte ((Byte)a_Player.GetGameMode());
|
||||
WriteByte ((Byte)(a_World.GetDimension()));
|
||||
WriteByte (2); // TODO: Difficulty
|
||||
WriteByte (0); // Unused, used to be world height
|
||||
WriteByte (8); // Client list width or something
|
||||
Flush();
|
||||
m_LastSentDimension = a_World.GetDimension();
|
||||
SendCompass(a_World);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
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());
|
||||
if (a_Player.HasCustomName())
|
||||
{
|
||||
WriteString(a_Player.GetCustomName());
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteString(a_Player.GetName());
|
||||
}
|
||||
WriteInt ((int)(a_Player.GetPosX() * 32));
|
||||
WriteInt ((int)(a_Player.GetPosY() * 32));
|
||||
WriteInt ((int)(a_Player.GetPosZ() * 32));
|
||||
WriteChar ((char)((a_Player.GetYaw() / 360.f) * 256));
|
||||
WriteChar ((char)((a_Player.GetPitch() / 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::SendSoundEffect(const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch)
|
||||
{
|
||||
cCSLock Lock(m_CSPacket);
|
||||
WriteByte (PACKET_SOUND_EFFECT);
|
||||
WriteString (a_SoundName);
|
||||
WriteInt ((int)(a_X * 8.0));
|
||||
WriteInt ((int)(a_Y * 8.0));
|
||||
WriteInt ((int)(a_Z * 8.0));
|
||||
WriteFloat (a_Volume);
|
||||
WriteChar ((char)(a_Pitch * 63.0f));
|
||||
Flush();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol132::SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data)
|
||||
{
|
||||
cCSLock Lock(m_CSPacket);
|
||||
WriteByte(PACKET_SOUND_PARTICLE_EFFECT);
|
||||
WriteInt (a_EffectID);
|
||||
WriteInt (a_SrcX);
|
||||
WriteByte((Byte)a_SrcY);
|
||||
WriteInt (a_SrcZ);
|
||||
WriteInt (a_Data);
|
||||
Flush();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol132::SendSpawnMob(const cMonster & a_Mob)
|
||||
{
|
||||
cCSLock Lock(m_CSPacket);
|
||||
WriteByte (PACKET_SPAWN_MOB);
|
||||
WriteInt (a_Mob.GetUniqueID());
|
||||
WriteByte ((Byte)a_Mob.GetMobType());
|
||||
WriteVectorI((Vector3i)(a_Mob.GetPosition() * 32));
|
||||
WriteByte ((Byte)((a_Mob.GetYaw() / 360.f) * 256));
|
||||
WriteByte ((Byte)((a_Mob.GetPitch() / 360.f) * 256));
|
||||
WriteByte ((Byte)((a_Mob.GetHeadYaw() / 360.f) * 256));
|
||||
WriteShort ((short)(a_Mob.GetSpeedX() * 400));
|
||||
WriteShort ((short)(a_Mob.GetSpeedY() * 400));
|
||||
WriteShort ((short)(a_Mob.GetSpeedZ() * 400));
|
||||
|
||||
WriteCommonMetadata(a_Mob);
|
||||
WriteMobMetadata(a_Mob);
|
||||
WriteByte(0x7f);
|
||||
|
||||
Flush();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol132::SendTabCompletionResults(const AStringVector & a_Results)
|
||||
{
|
||||
if (a_Results.empty())
|
||||
{
|
||||
// No results to send
|
||||
return;
|
||||
}
|
||||
|
||||
AString Serialized(a_Results[0]);
|
||||
for (AStringVector::const_iterator itr = a_Results.begin() + 1, end = a_Results.end(); itr != end; ++itr)
|
||||
{
|
||||
Serialized.push_back(0);
|
||||
Serialized.append(*itr);
|
||||
} // for itr - a_Results[]
|
||||
|
||||
cCSLock Lock(m_CSPacket);
|
||||
WriteByte(PACKET_TAB_COMPLETION);
|
||||
WriteString(Serialized);
|
||||
Flush();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol132::SendUnloadChunk(int a_ChunkX, int a_ChunkZ)
|
||||
{
|
||||
// Unloading the chunk is done by sending a "map chunk" packet
|
||||
// with IncludeInitialize set to true and primary bitmap set to 0:
|
||||
cCSLock Lock(m_CSPacket);
|
||||
WriteByte(PACKET_CHUNK_DATA);
|
||||
WriteInt (a_ChunkX);
|
||||
WriteInt (a_ChunkZ);
|
||||
WriteBool(true); // IncludeInitialize
|
||||
WriteShort(0); // Primary bitmap
|
||||
WriteShort(0); // Add bitmap
|
||||
WriteInt(0);
|
||||
Flush();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol132::SendWholeInventory(const cWindow & a_Window)
|
||||
{
|
||||
// 1.3.2 requires player inventory slots to be sent as SetSlot packets,
|
||||
// otherwise it sometimes fails to update the window
|
||||
|
||||
// Send the entire window:
|
||||
super::SendWholeInventory(a_Window);
|
||||
|
||||
// Send the player inventory and hotbar:
|
||||
cPlayer * Player = m_Client->GetPlayer();
|
||||
const cInventory & Inventory = Player->GetInventory();
|
||||
int BaseOffset = a_Window.GetNumSlots() - (cInventory::invNumSlots - cInventory::invInventoryOffset); // Number of non-inventory slots
|
||||
char WindowID = a_Window.GetWindowID();
|
||||
for (short i = 0; i < cInventory::invInventoryCount; i++)
|
||||
{
|
||||
SendInventorySlot(WindowID, BaseOffset + i, Inventory.GetInventorySlot(i));
|
||||
} // for i - Inventory[]
|
||||
BaseOffset += cInventory::invInventoryCount;
|
||||
for (short i = 0; i < cInventory::invHotbarCount; i++)
|
||||
{
|
||||
SendInventorySlot(WindowID, BaseOffset + i, Inventory.GetHotbarSlot(i));
|
||||
} // for i - Hotbar[]
|
||||
|
||||
// Send even the item being dragged:
|
||||
SendInventorySlot(-1, -1, Player->GetDraggingItem());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
AString cProtocol132::GetAuthServerID(void)
|
||||
{
|
||||
// http://wiki.vg/wiki/index.php?title=Session&oldid=2615
|
||||
// Server uses SHA1 to mix ServerID, Client secret and server public key together
|
||||
// The mixing is done in StartEncryption, the result is in m_AuthServerID
|
||||
|
||||
return m_AuthServerID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cProtocol132::ParsePacket(unsigned char a_PacketType)
|
||||
{
|
||||
switch (a_PacketType)
|
||||
{
|
||||
default: return super::ParsePacket(a_PacketType); // off-load previously known packets into cProtocol125
|
||||
case PACKET_CLIENT_STATUSES: return ParseClientStatuses();
|
||||
case PACKET_ENCRYPTION_KEY_RESP: return ParseEncryptionKeyResponse();
|
||||
case PACKET_LOCALE_VIEW_DISTANCE: return ParseLocaleViewDistance();
|
||||
case PACKET_TAB_COMPLETION: return ParseTabCompletion();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
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, BlockFace);
|
||||
|
||||
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->HandleRightClick(PosX, PosY, PosZ, static_cast<eBlockFace>(BlockFace), CursorX, CursorY, CursorZ, HeldItem);
|
||||
return PARSE_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cProtocol132::ParseHandshake(void)
|
||||
{
|
||||
HANDLE_PACKET_READ(ReadByte, Byte, ProtocolVersion);
|
||||
HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Username);
|
||||
HANDLE_PACKET_READ(ReadBEUTF16String16, AString, ServerHost);
|
||||
HANDLE_PACKET_READ(ReadBEInt, int, ServerPort);
|
||||
m_Username = Username;
|
||||
|
||||
if (!m_Client->HandleHandshake( m_Username))
|
||||
{
|
||||
return PARSE_OK; // Player is not allowed into the server
|
||||
}
|
||||
|
||||
// Send a 0xfd Encryption Key Request http://wiki.vg/Protocol#0xFD
|
||||
SendEncryptionKeyRequest();
|
||||
|
||||
return PARSE_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cProtocol132::ParseClientStatuses(void)
|
||||
{
|
||||
HANDLE_PACKET_READ(ReadByte, Byte, Status);
|
||||
if ((Status & 1) == 0)
|
||||
{
|
||||
m_Client->HandleLogin(39, m_Username);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Client->HandleRespawn();
|
||||
}
|
||||
return PARSE_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cProtocol132::ParseEncryptionKeyResponse(void)
|
||||
{
|
||||
// Read the encryption key:
|
||||
HANDLE_PACKET_READ(ReadBEShort, short, EncKeyLength);
|
||||
if (EncKeyLength > MAX_ENC_LEN)
|
||||
{
|
||||
LOGD("Too long encryption key");
|
||||
m_Client->Kick("Hacked client");
|
||||
return PARSE_OK;
|
||||
}
|
||||
AString EncKey;
|
||||
if (!m_ReceivedData.ReadString(EncKey, (size_t)EncKeyLength))
|
||||
{
|
||||
return PARSE_INCOMPLETE;
|
||||
}
|
||||
|
||||
// Read the encryption nonce:
|
||||
HANDLE_PACKET_READ(ReadBEShort, short, EncNonceLength);
|
||||
AString EncNonce;
|
||||
if (!m_ReceivedData.ReadString(EncNonce, (size_t)EncNonceLength))
|
||||
{
|
||||
return PARSE_INCOMPLETE;
|
||||
}
|
||||
if (EncNonceLength > MAX_ENC_LEN)
|
||||
{
|
||||
LOGD("Too long encryption nonce");
|
||||
m_Client->Kick("Hacked client");
|
||||
return PARSE_OK;
|
||||
}
|
||||
|
||||
HandleEncryptionKeyResponse(EncKey, EncNonce);
|
||||
return PARSE_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
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);
|
||||
m_Client->SetLocale(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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cProtocol132::ParseTabCompletion(void)
|
||||
{
|
||||
HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Text);
|
||||
m_Client->HandleTabCompletion(Text);
|
||||
return PARSE_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol132::SendData(const char * a_Data, size_t a_Size)
|
||||
{
|
||||
m_DataToSend.append(a_Data, a_Size);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol132::Flush(void)
|
||||
{
|
||||
ASSERT(m_CSPacket.IsLockedByCurrentThread()); // Did all packets lock the CS properly?
|
||||
|
||||
if (m_DataToSend.empty())
|
||||
{
|
||||
LOGD("Flushing empty");
|
||||
return;
|
||||
}
|
||||
const char * Data = m_DataToSend.data();
|
||||
size_t Size = m_DataToSend.size();
|
||||
if (m_IsEncrypted)
|
||||
{
|
||||
Byte Encrypted[8192]; // Larger buffer, we may be sending lots of data (chunks)
|
||||
while (Size > 0)
|
||||
{
|
||||
size_t NumBytes = (Size > sizeof(Encrypted)) ? sizeof(Encrypted) : Size;
|
||||
m_Encryptor.ProcessData(Encrypted, (Byte *)Data, NumBytes);
|
||||
super::SendData((const char *)Encrypted, NumBytes);
|
||||
Size -= NumBytes;
|
||||
Data += NumBytes;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
super::SendData(Data, Size);
|
||||
}
|
||||
m_DataToSend.clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (a_Item.IsEmpty())
|
||||
{
|
||||
WriteShort(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
WriteShort(ItemType);
|
||||
WriteChar (a_Item.m_ItemCount);
|
||||
WriteShort(a_Item.m_ItemDamage);
|
||||
|
||||
if (a_Item.m_Enchantments.IsEmpty())
|
||||
{
|
||||
WriteShort(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
// Send the enchantments:
|
||||
cFastNBTWriter Writer;
|
||||
const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench";
|
||||
EnchantmentSerializer::WriteToNBTCompound(a_Item.m_Enchantments, Writer, TagName);
|
||||
Writer.Finish();
|
||||
AString Compressed;
|
||||
CompressStringGZIP(Writer.GetResult().data(), Writer.GetResult().size(), Compressed);
|
||||
WriteShort((short)Compressed.size());
|
||||
SendData(Compressed.data(), Compressed.size());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cProtocol132::ParseItem(cItem & a_Item)
|
||||
{
|
||||
HANDLE_PACKET_READ(ReadBEShort, short, ItemType);
|
||||
|
||||
if (ItemType <= -1)
|
||||
{
|
||||
a_Item.Empty();
|
||||
return PARSE_OK;
|
||||
}
|
||||
a_Item.m_ItemType = ItemType;
|
||||
|
||||
HANDLE_PACKET_READ(ReadChar, char, ItemCount);
|
||||
HANDLE_PACKET_READ(ReadBEShort, short, ItemDamage);
|
||||
a_Item.m_ItemCount = ItemCount;
|
||||
a_Item.m_ItemDamage = ItemDamage;
|
||||
if (ItemCount <= 0)
|
||||
{
|
||||
a_Item.Empty();
|
||||
}
|
||||
|
||||
HANDLE_PACKET_READ(ReadBEShort, short, MetadataLength);
|
||||
if (MetadataLength <= 0)
|
||||
{
|
||||
return PARSE_OK;
|
||||
}
|
||||
|
||||
// Read the metadata
|
||||
AString Metadata;
|
||||
Metadata.resize((size_t)MetadataLength);
|
||||
if (!m_ReceivedData.ReadBuf((void *)Metadata.data(), (size_t)MetadataLength))
|
||||
{
|
||||
return PARSE_INCOMPLETE;
|
||||
}
|
||||
|
||||
return ParseItemMetadata(a_Item, Metadata);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cProtocol132::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata)
|
||||
{
|
||||
// Uncompress the GZIPped data:
|
||||
AString Uncompressed;
|
||||
if (UncompressStringGZIP(a_Metadata.data(), a_Metadata.size(), Uncompressed) != Z_OK)
|
||||
{
|
||||
AString HexDump;
|
||||
CreateHexDump(HexDump, a_Metadata.data(), a_Metadata.size(), 16);
|
||||
LOG("Cannot unGZIP item metadata:\n%s", HexDump.c_str());
|
||||
return PARSE_ERROR;
|
||||
}
|
||||
|
||||
// Parse into NBT:
|
||||
cParsedNBT NBT(Uncompressed.data(), Uncompressed.size());
|
||||
if (!NBT.IsValid())
|
||||
{
|
||||
AString HexDump;
|
||||
CreateHexDump(HexDump, Uncompressed.data(), Uncompressed.size(), 16);
|
||||
LOG("Cannot parse NBT item metadata:\n%s", HexDump.c_str());
|
||||
return PARSE_ERROR;
|
||||
}
|
||||
|
||||
// Load enchantments from the NBT:
|
||||
for (int tag = NBT.GetFirstChild(NBT.GetRoot()); tag >= 0; tag = NBT.GetNextSibling(tag))
|
||||
{
|
||||
if (
|
||||
(NBT.GetType(tag) == TAG_List) &&
|
||||
(
|
||||
(NBT.GetName(tag) == "ench") ||
|
||||
(NBT.GetName(tag) == "StoredEnchantments")
|
||||
)
|
||||
)
|
||||
{
|
||||
EnchantmentSerializer::ParseFromNBT(a_Item.m_Enchantments, NBT, tag);
|
||||
}
|
||||
}
|
||||
|
||||
return PARSE_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol132::SendCompass(const cWorld & a_World)
|
||||
{
|
||||
cCSLock Lock(m_CSPacket);
|
||||
WriteByte(PACKET_COMPASS);
|
||||
WriteInt((int)(a_World.GetSpawnX()));
|
||||
WriteInt((int)(a_World.GetSpawnY()));
|
||||
WriteInt((int)(a_World.GetSpawnZ()));
|
||||
Flush();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol132::SendEncryptionKeyRequest(void)
|
||||
{
|
||||
cCSLock Lock(m_CSPacket);
|
||||
cServer * Server = cRoot::Get()->GetServer();
|
||||
WriteByte(0xfd);
|
||||
WriteString(Server->GetServerID());
|
||||
const AString & PublicKeyDER = Server->GetPublicKeyDER();
|
||||
WriteShort((short)(PublicKeyDER.size()));
|
||||
SendData(PublicKeyDER.data(), PublicKeyDER.size());
|
||||
WriteShort(4);
|
||||
WriteInt((int)(intptr_t)this); // Using 'this' as the cryptographic nonce, so that we don't have to generate one each time :)
|
||||
Flush();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol132::HandleEncryptionKeyResponse(const AString & a_EncKey, const AString & a_EncNonce)
|
||||
{
|
||||
// Decrypt EncNonce using privkey
|
||||
cRsaPrivateKey & rsaDecryptor = cRoot::Get()->GetServer()->GetPrivateKey();
|
||||
|
||||
Int32 DecryptedNonce[MAX_ENC_LEN / sizeof(Int32)];
|
||||
int res = rsaDecryptor.Decrypt((const Byte *)a_EncNonce.data(), a_EncNonce.size(), (Byte *)DecryptedNonce, sizeof(DecryptedNonce));
|
||||
if (res != 4)
|
||||
{
|
||||
LOGD("Bad nonce length");
|
||||
m_Client->Kick("Hacked client");
|
||||
return;
|
||||
}
|
||||
if (ntohl(DecryptedNonce[0]) != (unsigned)(uintptr_t)this)
|
||||
{
|
||||
LOGD("Bad nonce value");
|
||||
m_Client->Kick("Hacked client");
|
||||
return;
|
||||
}
|
||||
|
||||
// Decrypt the symmetric encryption key using privkey:
|
||||
Byte DecryptedKey[MAX_ENC_LEN];
|
||||
res = rsaDecryptor.Decrypt((const Byte *)a_EncKey.data(), a_EncKey.size(), DecryptedKey, sizeof(DecryptedKey));
|
||||
if (res != 16)
|
||||
{
|
||||
LOGD("Bad key length");
|
||||
m_Client->Kick("Hacked client");
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
// Send encryption key response:
|
||||
cCSLock Lock(m_CSPacket);
|
||||
WriteByte(0xfc);
|
||||
WriteShort(0);
|
||||
WriteShort(0);
|
||||
Flush();
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
AString DecryptedKeyHex;
|
||||
CreateHexDump(DecryptedKeyHex, DecryptedKey, res, 16);
|
||||
LOGD("Received encryption key, %d bytes:\n%s", res, DecryptedKeyHex.c_str());
|
||||
#endif
|
||||
|
||||
StartEncryption(DecryptedKey);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol132::StartEncryption(const Byte * a_Key)
|
||||
{
|
||||
m_Encryptor.Init(a_Key, a_Key);
|
||||
m_Decryptor.Init(a_Key, a_Key);
|
||||
m_IsEncrypted = true;
|
||||
|
||||
// Prepare the m_AuthServerID:
|
||||
cSha1Checksum Checksum;
|
||||
cServer * Server = cRoot::Get()->GetServer();
|
||||
AString ServerID = Server->GetServerID();
|
||||
Checksum.Update((const Byte *)ServerID.c_str(), ServerID.length());
|
||||
Checksum.Update(a_Key, 16);
|
||||
Checksum.Update((const Byte *)Server->GetPublicKeyDER().data(), Server->GetPublicKeyDER().size());
|
||||
Byte Digest[20];
|
||||
Checksum.Finalize(Digest);
|
||||
cSha1Checksum::DigestToJava(Digest, m_AuthServerID);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -1,115 +0,0 @@
|
||||
|
||||
// Protocol132.h
|
||||
|
||||
// Interfaces to the cProtocol132 class representing the release 1.3.2 protocol (#39)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Protocol125.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127)
|
||||
#pragma warning(disable:4189)
|
||||
#pragma warning(disable:4231)
|
||||
#pragma warning(disable:4244)
|
||||
#pragma warning(disable:4702)
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#include "PolarSSL++/AesCfb128Decryptor.h"
|
||||
#include "PolarSSL++/AesCfb128Encryptor.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cProtocol132 :
|
||||
public cProtocol125
|
||||
{
|
||||
typedef cProtocol125 super;
|
||||
public:
|
||||
|
||||
cProtocol132(cClientHandle * a_Client);
|
||||
virtual ~cProtocol132();
|
||||
|
||||
/// Called when client sends some data:
|
||||
virtual void DataReceived(const char * a_Data, size_t a_Size) override;
|
||||
|
||||
// Sending commands (alphabetically sorted):
|
||||
virtual void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) override;
|
||||
virtual void SendBlockBreakAnim (int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage) 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 SendCollectEntity (const cEntity & a_Entity, const cPlayer & a_Player) override;
|
||||
virtual void SendDestroyEntity (const cEntity & a_Entity) override;
|
||||
virtual void SendEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) override;
|
||||
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override;
|
||||
virtual void SendPlayerSpawn (const cPlayer & a_Player) override;
|
||||
virtual void SendSoundEffect (const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch) override;
|
||||
virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override;
|
||||
virtual void SendSpawnMob (const cMonster & a_Mob) override;
|
||||
virtual void SendTabCompletionResults(const AStringVector & a_Results) override;
|
||||
virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) override;
|
||||
virtual void SendWholeInventory (const cWindow & a_Window) override;
|
||||
|
||||
virtual AString GetAuthServerID(void) override;
|
||||
|
||||
/// Handling of the additional packets:
|
||||
virtual int ParsePacket(unsigned char a_PacketType) override;
|
||||
|
||||
// Modified packets:
|
||||
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 int ParseLocaleViewDistance (void);
|
||||
virtual int ParseTabCompletion (void);
|
||||
|
||||
protected:
|
||||
bool m_IsEncrypted;
|
||||
|
||||
cAesCfb128Decryptor m_Decryptor;
|
||||
cAesCfb128Encryptor m_Encryptor;
|
||||
|
||||
AString m_DataToSend;
|
||||
|
||||
/// The ServerID used for session authentication; set in StartEncryption(), used in GetAuthServerID()
|
||||
AString m_AuthServerID;
|
||||
|
||||
virtual void SendData(const char * a_Data, size_t a_Size) override;
|
||||
|
||||
// DEBUG:
|
||||
virtual void Flush(void) override;
|
||||
|
||||
// Items in slots are sent differently
|
||||
virtual void WriteItem(const cItem & a_Item) override;
|
||||
virtual int ParseItem(cItem & a_Item) override;
|
||||
|
||||
/// Parses the metadata that may come with the item.
|
||||
int ParseItemMetadata(cItem & a_Item, const AString & a_Metadata);
|
||||
|
||||
virtual void SendCompass(const cWorld & a_World);
|
||||
virtual void SendEncryptionKeyRequest(void);
|
||||
|
||||
/// Decrypts the key and nonce, checks nonce, starts the symmetric encryption
|
||||
void HandleEncryptionKeyResponse(const AString & a_EncKey, const AString & a_EncNonce);
|
||||
|
||||
/// Starts the symmetric encryption with the specified key; also sets m_AuthServerID
|
||||
void StartEncryption(const Byte * a_Key);
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
@ -1,265 +0,0 @@
|
||||
|
||||
// Protocol14x.cpp
|
||||
|
||||
/*
|
||||
Implements the 1.4.x protocol classes representing these protocols:
|
||||
- cProtocol142:
|
||||
- release 1.4.2 protocol (#47)
|
||||
- release 1.4.4 protocol (#49) - the same protocol class is used, because the only difference is in a packet that MCServer doesn't implement yet (ITEM_DATA)
|
||||
- release 1.4.5 protocol (same as 1.4.4)
|
||||
- cProtocol146:
|
||||
- release 1.4.6 protocol (#51)
|
||||
*/
|
||||
|
||||
#include "Globals.h"
|
||||
#include "Protocol14x.h"
|
||||
#include "../Root.h"
|
||||
#include "../Server.h"
|
||||
#include "../ClientHandle.h"
|
||||
#include "../Item.h"
|
||||
#include "ChunkDataSerializer.h"
|
||||
#include "../Entities/Player.h"
|
||||
#include "../Mobs/Monster.h"
|
||||
#include "../UI/Window.h"
|
||||
#include "../Entities/Pickup.h"
|
||||
#include "../Entities/FallingBlock.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127)
|
||||
#pragma warning(disable:4244)
|
||||
#pragma warning(disable:4231)
|
||||
#pragma warning(disable:4189)
|
||||
#pragma warning(disable:4702)
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
|
||||
#define HANDLE_PACKET_READ(Proc, Type, Var) \
|
||||
Type Var; \
|
||||
{ \
|
||||
if (!m_ReceivedData.Proc(Var)) \
|
||||
{ \
|
||||
m_ReceivedData.CheckValid(); \
|
||||
return PARSE_INCOMPLETE; \
|
||||
} \
|
||||
m_ReceivedData.CheckValid(); \
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PACKET_UPDATE_TIME = 0x04,
|
||||
PACKET_PICKUP_SPAWN = 0x15,
|
||||
PACKET_SPAWN_OBJECT = 0x17,
|
||||
PACKET_ENTITY_METADATA = 0x28,
|
||||
PACKET_SOUND_PARTICLE_EFFECT = 0x3d
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cProtocol142:
|
||||
|
||||
cProtocol142::cProtocol142(cClientHandle * a_Client) :
|
||||
super(a_Client)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cProtocol142::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);
|
||||
HANDLE_PACKET_READ(ReadChar, char, ShouldShowCape); // <-- new in 1.4.2
|
||||
m_Client->SetLocale(Locale);
|
||||
// TODO: m_Client->HandleViewDistance(ViewDistance);
|
||||
// TODO: m_Client->HandleChatFlags(ChatFlags);
|
||||
// Ignoring client difficulty
|
||||
return PARSE_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol142::SendPickupSpawn(const cPickup & a_Pickup)
|
||||
{
|
||||
cCSLock Lock(m_CSPacket);
|
||||
WriteByte (PACKET_PICKUP_SPAWN);
|
||||
WriteInt (a_Pickup.GetUniqueID());
|
||||
WriteItem (a_Pickup.GetItem());
|
||||
WriteVectorI((Vector3i)(a_Pickup.GetPosition() * 32));
|
||||
WriteChar((char)(a_Pickup.GetSpeedX() * 8));
|
||||
WriteChar((char)(a_Pickup.GetSpeedY() * 8));
|
||||
WriteChar((char)(a_Pickup.GetSpeedZ() * 8));
|
||||
Flush();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol142::SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data)
|
||||
{
|
||||
cCSLock Lock(m_CSPacket);
|
||||
WriteByte(PACKET_SOUND_PARTICLE_EFFECT);
|
||||
WriteInt (a_EffectID);
|
||||
WriteInt (a_SrcX);
|
||||
WriteByte((Byte)a_SrcY);
|
||||
WriteInt (a_SrcZ);
|
||||
WriteInt (a_Data);
|
||||
WriteBool(0);
|
||||
Flush();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol142::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle)
|
||||
{
|
||||
cCSLock Lock(m_CSPacket);
|
||||
WriteByte (PACKET_UPDATE_TIME);
|
||||
WriteInt64(a_WorldAge);
|
||||
WriteInt64(a_TimeOfDay);
|
||||
Flush();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cProtocol146:
|
||||
|
||||
cProtocol146::cProtocol146(cClientHandle * a_Client) :
|
||||
super(a_Client)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol146::SendPickupSpawn(const cPickup & a_Pickup)
|
||||
{
|
||||
ASSERT(!a_Pickup.GetItem().IsEmpty());
|
||||
|
||||
cCSLock Lock(m_CSPacket);
|
||||
|
||||
// Send a SPAWN_OBJECT packet for the base entity:
|
||||
WriteByte(PACKET_SPAWN_OBJECT);
|
||||
WriteInt (a_Pickup.GetUniqueID());
|
||||
WriteByte(0x02);
|
||||
WriteInt ((int)(a_Pickup.GetPosX() * 32));
|
||||
WriteInt ((int)(a_Pickup.GetPosY() * 32));
|
||||
WriteInt ((int)(a_Pickup.GetPosZ() * 32));
|
||||
WriteInt (1);
|
||||
WriteShort((short)(a_Pickup.GetSpeedX() * 32));
|
||||
WriteShort((short)(a_Pickup.GetSpeedY() * 32));
|
||||
WriteShort((short)(a_Pickup.GetSpeedZ() * 32));
|
||||
WriteByte(0);
|
||||
WriteByte(0);
|
||||
|
||||
// Send a ENTITY_METADATA packet with the slot info:
|
||||
WriteByte(PACKET_ENTITY_METADATA);
|
||||
WriteInt(a_Pickup.GetUniqueID());
|
||||
WriteByte(0xaa); // a slot value at index 10
|
||||
WriteItem(a_Pickup.GetItem());
|
||||
WriteByte(0x7f); // End of metadata
|
||||
Flush();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol146::SendSpawnFallingBlock(const cFallingBlock & a_FallingBlock)
|
||||
{
|
||||
// Send a spawn object / vehicle packet
|
||||
cCSLock Lock(m_CSPacket);
|
||||
|
||||
WriteByte(PACKET_SPAWN_OBJECT);
|
||||
WriteInt (a_FallingBlock.GetUniqueID());
|
||||
WriteByte(70);
|
||||
WriteInt ((int)(a_FallingBlock.GetPosX() * 32));
|
||||
WriteInt ((int)(a_FallingBlock.GetPosY() * 32));
|
||||
WriteInt ((int)(a_FallingBlock.GetPosZ() * 32));
|
||||
WriteByte (0); // Pitch
|
||||
WriteByte (0); // Yaw
|
||||
WriteInt (a_FallingBlock.GetBlockType()); // data indicator = blocktype
|
||||
WriteShort((short)(a_FallingBlock.GetSpeedX() * 400));
|
||||
WriteShort((short)(a_FallingBlock.GetSpeedY() * 400));
|
||||
WriteShort((short)(a_FallingBlock.GetSpeedZ() * 400));
|
||||
Flush();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol146::SendSpawnObject(const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch)
|
||||
{
|
||||
cCSLock Lock(m_CSPacket);
|
||||
WriteByte(PACKET_SPAWN_OBJECT);
|
||||
WriteInt (a_Entity.GetUniqueID());
|
||||
WriteChar(a_ObjectType);
|
||||
WriteInt ((int)(a_Entity.GetPosX() * 32));
|
||||
WriteInt ((int)(a_Entity.GetPosY() * 32));
|
||||
WriteInt ((int)(a_Entity.GetPosZ() * 32));
|
||||
WriteByte(a_Pitch);
|
||||
WriteByte(a_Yaw);
|
||||
WriteInt (a_ObjectData);
|
||||
if (a_ObjectData != 0)
|
||||
{
|
||||
WriteShort((short)(a_Entity.GetSpeedX() * 400));
|
||||
WriteShort((short)(a_Entity.GetSpeedY() * 400));
|
||||
WriteShort((short)(a_Entity.GetSpeedZ() * 400));
|
||||
}
|
||||
Flush();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol146::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType)
|
||||
{
|
||||
cCSLock Lock(m_CSPacket);
|
||||
WriteByte (PACKET_SPAWN_OBJECT);
|
||||
WriteInt (a_Vehicle.GetUniqueID());
|
||||
WriteChar (a_VehicleType);
|
||||
WriteInt ((int)(a_Vehicle.GetPosX() * 32));
|
||||
WriteInt ((int)(a_Vehicle.GetPosY() * 32));
|
||||
WriteInt ((int)(a_Vehicle.GetPosZ() * 32));
|
||||
WriteByte ((Byte)((a_Vehicle.GetPitch() / 360.f) * 256));
|
||||
WriteByte ((Byte)((a_Vehicle.GetYaw() / 360.f) * 256));
|
||||
WriteInt (a_VehicleSubType);
|
||||
if (a_VehicleSubType != 0)
|
||||
{
|
||||
WriteShort((short)(a_Vehicle.GetSpeedX() * 400));
|
||||
WriteShort((short)(a_Vehicle.GetSpeedY() * 400));
|
||||
WriteShort((short)(a_Vehicle.GetSpeedZ() * 400));
|
||||
}
|
||||
Flush();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,63 +0,0 @@
|
||||
|
||||
// Protocol14x.h
|
||||
|
||||
/*
|
||||
Interfaces to the 1.4.x protocol classes representing these protocols:
|
||||
- cProtocol142:
|
||||
- release 1.4.2 protocol (#47)
|
||||
- release 1.4.4 protocol (#49) - the same protocol class is used, because the only difference is in a packet that MCServer doesn't implement yet (ITEM_DATA)
|
||||
- release 1.4.5 protocol (same as 1.4.4)
|
||||
- cProtocol146:
|
||||
- release 1.4.6 protocol (#51)
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Protocol132.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cProtocol142 :
|
||||
public cProtocol132
|
||||
{
|
||||
typedef cProtocol132 super;
|
||||
|
||||
public:
|
||||
cProtocol142(cClientHandle * a_Client);
|
||||
|
||||
// Sending commands (alphabetically sorted):
|
||||
virtual void SendPickupSpawn (const cPickup & a_Pickup) override;
|
||||
virtual void SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override;
|
||||
virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle) override;
|
||||
|
||||
// Specific packet parsers:
|
||||
virtual int ParseLocaleViewDistance(void) override;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cProtocol146 :
|
||||
public cProtocol142
|
||||
{
|
||||
typedef cProtocol142 super;
|
||||
|
||||
public:
|
||||
cProtocol146(cClientHandle * a_Client);
|
||||
|
||||
virtual void SendPickupSpawn (const cPickup & a_Pickup) override;
|
||||
virtual void SendSpawnFallingBlock(const cFallingBlock & a_FallingBlock) override;
|
||||
virtual void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch) override;
|
||||
virtual void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType) override;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
@ -1,209 +0,0 @@
|
||||
|
||||
// Protocol15x.cpp
|
||||
|
||||
/*
|
||||
Implements the 1.5.x protocol classes:
|
||||
- cProtocol150
|
||||
- release 1.5 protocol (#60)
|
||||
- release 1.5.2 protocol (#61, no relevant changes found)
|
||||
*/
|
||||
|
||||
#include "Globals.h"
|
||||
#include "Protocol15x.h"
|
||||
#include "../ClientHandle.h"
|
||||
#include "../Item.h"
|
||||
#include "../UI/Window.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define HANDLE_PACKET_READ(Proc, Type, Var) \
|
||||
Type Var; \
|
||||
{ \
|
||||
if (!m_ReceivedData.Proc(Var)) \
|
||||
{ \
|
||||
m_ReceivedData.CheckValid(); \
|
||||
return PARSE_INCOMPLETE; \
|
||||
} \
|
||||
m_ReceivedData.CheckValid(); \
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PACKET_WINDOW_OPEN = 0x64,
|
||||
PACKET_PARTICLE_EFFECT = 0x3F,
|
||||
PACKET_SCOREBOARD_OBJECTIVE = 0xCE,
|
||||
PACKET_SCORE_UPDATE = 0xCF,
|
||||
PACKET_DISPLAY_OBJECTIVE = 0xD0
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cProtocol150:
|
||||
|
||||
cProtocol150::cProtocol150(cClientHandle * a_Client) :
|
||||
super(a_Client)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol150::SendWindowOpen(const cWindow & a_Window)
|
||||
{
|
||||
if (a_Window.GetWindowType() < 0)
|
||||
{
|
||||
// Do not send for inventory windows
|
||||
return;
|
||||
}
|
||||
cCSLock Lock(m_CSPacket);
|
||||
WriteByte (PACKET_WINDOW_OPEN);
|
||||
WriteByte (a_Window.GetWindowID());
|
||||
WriteByte (a_Window.GetWindowType());
|
||||
WriteString(a_Window.GetWindowTitle());
|
||||
WriteByte (a_Window.GetNumNonInventorySlots());
|
||||
WriteByte (1); // Use title
|
||||
Flush();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol150::SendParticleEffect(const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmount)
|
||||
{
|
||||
cCSLock Lock(m_CSPacket);
|
||||
WriteByte(PACKET_PARTICLE_EFFECT);
|
||||
WriteString(a_ParticleName);
|
||||
WriteFloat(a_SrcX);
|
||||
WriteFloat(a_SrcY);
|
||||
WriteFloat(a_SrcZ);
|
||||
WriteFloat(a_OffsetX);
|
||||
WriteFloat(a_OffsetY);
|
||||
WriteFloat(a_OffsetZ);
|
||||
WriteFloat(a_ParticleData);
|
||||
WriteInt(a_ParticleAmount);
|
||||
Flush();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol150::SendScoreboardObjective(const AString & a_Name, const AString & a_DisplayName, Byte a_Mode)
|
||||
{
|
||||
cCSLock Lock(m_CSPacket);
|
||||
WriteByte(PACKET_SCOREBOARD_OBJECTIVE);
|
||||
WriteString(a_Name);
|
||||
WriteString(a_DisplayName);
|
||||
WriteByte(a_Mode);
|
||||
Flush();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol150::SendScoreUpdate(const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode)
|
||||
{
|
||||
cCSLock Lock(m_CSPacket);
|
||||
WriteByte(PACKET_SCORE_UPDATE);
|
||||
WriteString(a_Player);
|
||||
WriteByte(a_Mode);
|
||||
|
||||
if (a_Mode != 1)
|
||||
{
|
||||
WriteString(a_Objective);
|
||||
WriteInt((int) a_Score);
|
||||
}
|
||||
|
||||
Flush();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol150::SendDisplayObjective(const AString & a_Objective, cScoreboard::eDisplaySlot a_Display)
|
||||
{
|
||||
cCSLock Lock(m_CSPacket);
|
||||
WriteByte(PACKET_DISPLAY_OBJECTIVE);
|
||||
WriteByte((int) a_Display);
|
||||
WriteString(a_Objective);
|
||||
Flush();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cProtocol150::ParseWindowClick(void)
|
||||
{
|
||||
HANDLE_PACKET_READ(ReadChar, char, WindowID);
|
||||
HANDLE_PACKET_READ(ReadBEShort, short, SlotNum);
|
||||
HANDLE_PACKET_READ(ReadByte, Byte, Button);
|
||||
HANDLE_PACKET_READ(ReadBEShort, short, TransactionID);
|
||||
HANDLE_PACKET_READ(ReadByte, Byte, Mode);
|
||||
cItem HeldItem;
|
||||
int res = ParseItem(HeldItem);
|
||||
if (res < 0)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
// Convert Button, Mode, SlotNum and HeldItem into eClickAction:
|
||||
eClickAction Action = caUnknown;
|
||||
switch ((Mode << 8) | Button)
|
||||
{
|
||||
case 0x0000: Action = (SlotNum != -999) ? caLeftClick : caLeftClickOutside; break;
|
||||
case 0x0001: Action = (SlotNum != -999) ? caRightClick : caRightClickOutside; break;
|
||||
case 0x0100: Action = caShiftLeftClick; break;
|
||||
case 0x0101: Action = caShiftRightClick; break;
|
||||
case 0x0200: Action = caNumber1; break;
|
||||
case 0x0201: Action = caNumber2; break;
|
||||
case 0x0202: Action = caNumber3; break;
|
||||
case 0x0203: Action = caNumber4; break;
|
||||
case 0x0204: Action = caNumber5; break;
|
||||
case 0x0205: Action = caNumber6; break;
|
||||
case 0x0206: Action = caNumber7; break;
|
||||
case 0x0207: Action = caNumber8; break;
|
||||
case 0x0208: Action = caNumber9; break;
|
||||
case 0x0300: Action = caMiddleClick; break;
|
||||
case 0x0400: Action = (SlotNum == -999) ? caLeftClickOutsideHoldNothing : caDropKey; break;
|
||||
case 0x0401: Action = (SlotNum == -999) ? caRightClickOutsideHoldNothing : caCtrlDropKey; break;
|
||||
case 0x0500: Action = (SlotNum == -999) ? caLeftPaintBegin : caUnknown; break;
|
||||
case 0x0501: Action = (SlotNum != -999) ? caLeftPaintProgress : caUnknown; break;
|
||||
case 0x0502: Action = (SlotNum == -999) ? caLeftPaintEnd : caUnknown; break;
|
||||
case 0x0504: Action = (SlotNum == -999) ? caRightPaintBegin : caUnknown; break;
|
||||
case 0x0505: Action = (SlotNum != -999) ? caRightPaintProgress : caUnknown; break;
|
||||
case 0x0506: Action = (SlotNum == -999) ? caRightPaintEnd : caUnknown; break;
|
||||
case 0x0600: Action = caDblClick; break;
|
||||
}
|
||||
|
||||
if (Action == caUnknown)
|
||||
{
|
||||
LOGWARNING("Received an unknown click action combination: Mode = %d, Button = %d, Slot = %d, HeldItem = %s. Ignoring packet.",
|
||||
Mode, Button, SlotNum, ItemToFullString(HeldItem).c_str()
|
||||
);
|
||||
ASSERT(!"Unknown click action");
|
||||
return PARSE_OK;
|
||||
}
|
||||
|
||||
m_Client->HandleWindowClick(WindowID, SlotNum, Action, HeldItem);
|
||||
return PARSE_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,42 +0,0 @@
|
||||
|
||||
// Protocol15x.h
|
||||
|
||||
/*
|
||||
Declares the 1.5.x protocol classes:
|
||||
- cProtocol150
|
||||
- release 1.5 and 1.5.1 protocol (#60)
|
||||
- release 1.5.2 protocol (#61; no relevant changes found)
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Protocol14x.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cProtocol150 :
|
||||
public cProtocol146
|
||||
{
|
||||
typedef cProtocol146 super;
|
||||
|
||||
public:
|
||||
cProtocol150(cClientHandle * a_Client);
|
||||
|
||||
virtual void SendWindowOpen (const cWindow & a_Window) override;
|
||||
virtual void SendParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmount) override;
|
||||
virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override;
|
||||
virtual void SendScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) override;
|
||||
virtual void SendDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) override;
|
||||
|
||||
virtual int ParseWindowClick(void);
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
@ -1,312 +0,0 @@
|
||||
|
||||
// Protocol16x.cpp
|
||||
|
||||
/*
|
||||
Implements the 1.6.x protocol classes:
|
||||
- cProtocol161
|
||||
- release 1.6.1 protocol (#73)
|
||||
- cProtocol162
|
||||
- release 1.6.2 protocol (#74)
|
||||
- release 1.6.3 protocol (#77) - no relevant changes
|
||||
- release 1.6.4 protocol (#78) - no relevant changes
|
||||
(others may be added later in the future for the 1.6 release series)
|
||||
*/
|
||||
|
||||
#include "Globals.h"
|
||||
#include "Protocol16x.h"
|
||||
#include "../ClientHandle.h"
|
||||
#include "../Entities/Entity.h"
|
||||
#include "../Entities/Player.h"
|
||||
#include "../UI/Window.h"
|
||||
#include "../CompositeChat.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define HANDLE_PACKET_READ(Proc, Type, Var) \
|
||||
Type Var; \
|
||||
{ \
|
||||
if (!m_ReceivedData.Proc(Var)) \
|
||||
{ \
|
||||
m_ReceivedData.CheckValid(); \
|
||||
return PARSE_INCOMPLETE; \
|
||||
} \
|
||||
m_ReceivedData.CheckValid(); \
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PACKET_CHAT = 0x03,
|
||||
PACKET_UPDATE_HEALTH = 0x08,
|
||||
PACKET_STEER_VEHICLE = 0x1b,
|
||||
PACKET_ATTACH_ENTITY = 0x27,
|
||||
PACKET_ENTITY_PROPERTIES = 0x2c,
|
||||
PACKET_WINDOW_OPEN = 0x64,
|
||||
PACKET_TILE_EDITOR_OPEN = 0x85,
|
||||
PACKET_PLAYER_ABILITIES = 0xca,
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cProtocol161:
|
||||
|
||||
cProtocol161::cProtocol161(cClientHandle * a_Client) :
|
||||
super(a_Client)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol161::SendAttachEntity(const cEntity & a_Entity, const cEntity * a_Vehicle)
|
||||
{
|
||||
cCSLock Lock(m_CSPacket);
|
||||
WriteByte(PACKET_ATTACH_ENTITY);
|
||||
WriteInt(a_Entity.GetUniqueID());
|
||||
WriteInt((a_Vehicle == NULL) ? -1 : a_Vehicle->GetUniqueID());
|
||||
WriteBool(false); // TODO: "Should use leash?" -> no
|
||||
Flush();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol161::SendChat(const AString & a_Message)
|
||||
{
|
||||
super::SendChat(Printf("{\"text\":\"%s\"}", EscapeString(a_Message).c_str()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol161::SendChat(const cCompositeChat & a_Message)
|
||||
{
|
||||
// This protocol version doesn't support composite messages to the full
|
||||
// Just extract each part's text and use it:
|
||||
|
||||
super::SendChat(Printf("{\"text\":\"%s\"}", EscapeString(a_Message.ExtractText()).c_str()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol161::SendEditSign(int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||
{
|
||||
cCSLock Lock(m_CSPacket);
|
||||
WriteByte(PACKET_TILE_EDITOR_OPEN);
|
||||
WriteByte(0);
|
||||
WriteInt(a_BlockX);
|
||||
WriteInt(a_BlockY);
|
||||
WriteInt(a_BlockZ);
|
||||
Flush();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol161::SendGameMode(eGameMode a_GameMode)
|
||||
{
|
||||
super::SendGameMode(a_GameMode);
|
||||
SendPlayerMaxSpeed();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol161::SendHealth(void)
|
||||
{
|
||||
cCSLock Lock(m_CSPacket);
|
||||
WriteByte (PACKET_UPDATE_HEALTH);
|
||||
cPlayer * Player = m_Client->GetPlayer();
|
||||
WriteFloat((float)Player->GetHealth());
|
||||
WriteShort((short)Player->GetFoodLevel());
|
||||
WriteFloat((float)Player->GetFoodSaturationLevel());
|
||||
Flush();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol161::SendPlayerMaxSpeed(void)
|
||||
{
|
||||
cCSLock Lock(m_CSPacket);
|
||||
cPlayer * Player = m_Client->GetPlayer();
|
||||
WriteByte(PACKET_ENTITY_PROPERTIES);
|
||||
WriteInt(Player->GetUniqueID());
|
||||
WriteInt(1);
|
||||
WriteString("generic.movementSpeed");
|
||||
WriteDouble(0.1 * Player->GetMaxSpeed());
|
||||
Flush();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol161::SendRespawn(eDimension a_Dimension, bool a_ShouldIgnoreDimensionChecks)
|
||||
{
|
||||
// Besides sending the respawn, we need to also send the player max speed, otherwise the client reverts to super-fast
|
||||
super::SendRespawn(a_Dimension, a_ShouldIgnoreDimensionChecks);
|
||||
SendPlayerMaxSpeed();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol161::SendWindowOpen(const cWindow & a_Window)
|
||||
{
|
||||
if (a_Window.GetWindowType() < 0)
|
||||
{
|
||||
// Do not send for inventory windows
|
||||
return;
|
||||
}
|
||||
cCSLock Lock(m_CSPacket);
|
||||
WriteByte (PACKET_WINDOW_OPEN);
|
||||
WriteChar (a_Window.GetWindowID());
|
||||
WriteByte ((Byte)a_Window.GetWindowType());
|
||||
WriteString(a_Window.GetWindowTitle());
|
||||
WriteByte ((Byte)a_Window.GetNumNonInventorySlots());
|
||||
WriteByte (1); // Use title
|
||||
if (a_Window.GetWindowType() == cWindow::wtAnimalChest)
|
||||
{
|
||||
WriteInt(0); // TODO: The animal's EntityID
|
||||
}
|
||||
Flush();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cProtocol161::ParseEntityAction(void)
|
||||
{
|
||||
HANDLE_PACKET_READ(ReadBEInt, int, EntityID);
|
||||
HANDLE_PACKET_READ(ReadChar, char, ActionID);
|
||||
HANDLE_PACKET_READ(ReadBEInt, int, UnknownHorseVal);
|
||||
|
||||
switch (ActionID)
|
||||
{
|
||||
case 1: m_Client->HandleEntityCrouch(EntityID, true); break; // Crouch
|
||||
case 2: m_Client->HandleEntityCrouch(EntityID, false); break; // Uncrouch
|
||||
case 3: m_Client->HandleEntityLeaveBed(EntityID); break; // Leave Bed
|
||||
case 4: m_Client->HandleEntitySprinting(EntityID, true); break; // Start sprinting
|
||||
case 5: m_Client->HandleEntitySprinting(EntityID, false); break; // Stop sprinting
|
||||
}
|
||||
|
||||
return PARSE_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cProtocol161::ParseLogin(void)
|
||||
{
|
||||
// The login packet is sent by Forge clients only
|
||||
// Only parse the packet, do no extra processing
|
||||
// Note that the types and the names have been only guessed and are not verified at all!
|
||||
HANDLE_PACKET_READ(ReadBEInt, int, Int1);
|
||||
HANDLE_PACKET_READ(ReadBEUTF16String16, AString, String1);
|
||||
HANDLE_PACKET_READ(ReadChar, char, Char1);
|
||||
HANDLE_PACKET_READ(ReadChar, char, Char2);
|
||||
HANDLE_PACKET_READ(ReadChar, char, Char3);
|
||||
HANDLE_PACKET_READ(ReadByte, Byte, Byte1);
|
||||
HANDLE_PACKET_READ(ReadByte, Byte, Byte2);
|
||||
return PARSE_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cProtocol161::ParsePlayerAbilities(void)
|
||||
{
|
||||
HANDLE_PACKET_READ(ReadByte, Byte, Flags);
|
||||
HANDLE_PACKET_READ(ReadBEFloat, float, FlyingSpeed);
|
||||
HANDLE_PACKET_READ(ReadBEFloat, float, WalkingSpeed);
|
||||
// TODO: m_Client->HandlePlayerAbilities(...);
|
||||
return PARSE_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cProtocol161::ParseSteerVehicle(void)
|
||||
{
|
||||
HANDLE_PACKET_READ(ReadBEFloat, float, Sideways);
|
||||
HANDLE_PACKET_READ(ReadBEFloat, float, Forward);
|
||||
HANDLE_PACKET_READ(ReadBool, bool, Jump);
|
||||
HANDLE_PACKET_READ(ReadBool, bool, Unmount);
|
||||
if (Unmount)
|
||||
{
|
||||
m_Client->HandleUnmount();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Client->HandleSteerVehicle(Forward, Sideways);
|
||||
}
|
||||
return PARSE_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cProtocol161::ParsePacket(unsigned char a_PacketType)
|
||||
{
|
||||
switch (a_PacketType)
|
||||
{
|
||||
case PACKET_STEER_VEHICLE: return ParseSteerVehicle();
|
||||
default: return super::ParsePacket(a_PacketType);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cProtocol162:
|
||||
|
||||
cProtocol162::cProtocol162(cClientHandle * a_Client) :
|
||||
super(a_Client)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol162::SendPlayerMaxSpeed(void)
|
||||
{
|
||||
cCSLock Lock(m_CSPacket);
|
||||
cPlayer * Player = m_Client->GetPlayer();
|
||||
WriteByte(PACKET_ENTITY_PROPERTIES);
|
||||
WriteInt(Player->GetUniqueID());
|
||||
WriteInt(1);
|
||||
WriteString("generic.movementSpeed");
|
||||
WriteDouble(0.1 * Player->GetMaxSpeed());
|
||||
WriteShort(0);
|
||||
Flush();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -1,78 +0,0 @@
|
||||
|
||||
// Protocol16x.h
|
||||
|
||||
/*
|
||||
Declares the 1.6.x protocol classes:
|
||||
- cProtocol161
|
||||
- release 1.6.1 protocol (#73)
|
||||
- cProtocol162
|
||||
- release 1.6.2 protocol (#74)
|
||||
- release 1.6.3 protocol (#77) - no relevant changes
|
||||
- release 1.6.4 protocol (#78) - no relevant changes
|
||||
(others may be added later in the future for the 1.6 release series)
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Protocol15x.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cProtocol161 :
|
||||
public cProtocol150
|
||||
{
|
||||
typedef cProtocol150 super;
|
||||
|
||||
public:
|
||||
cProtocol161(cClientHandle * a_Client);
|
||||
|
||||
protected:
|
||||
|
||||
// cProtocol150 overrides:
|
||||
virtual void SendAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle) override;
|
||||
virtual void SendChat (const AString & a_Message) override;
|
||||
virtual void SendChat (const cCompositeChat & a_Message) override;
|
||||
virtual void SendEditSign (int a_BlockX, int a_BlockY, int a_BlockZ) override; ///< Request the client to open up the sign editor for the sign (1.6+)
|
||||
virtual void SendGameMode (eGameMode a_GameMode) override;
|
||||
virtual void SendHealth (void) override;
|
||||
virtual void SendPlayerMaxSpeed(void) override;
|
||||
virtual void SendRespawn (eDimension a_Dimension, bool a_ShouldIgnoreDimensionChecks) override;
|
||||
virtual void SendWindowOpen (const cWindow & a_Window) override;
|
||||
|
||||
virtual int ParseEntityAction (void) override;
|
||||
virtual int ParseLogin (void) override;
|
||||
virtual int ParsePlayerAbilities(void) override;
|
||||
|
||||
// New packets:
|
||||
virtual int ParseSteerVehicle(void);
|
||||
|
||||
// Enable new packets' handling
|
||||
virtual int ParsePacket(unsigned char a_PacketType) override;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cProtocol162 :
|
||||
public cProtocol161
|
||||
{
|
||||
typedef cProtocol161 super;
|
||||
|
||||
public:
|
||||
cProtocol162(cClientHandle * a_Client);
|
||||
|
||||
protected:
|
||||
// cProtocol161 overrides:
|
||||
virtual void SendPlayerMaxSpeed(void) override;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
@ -2217,20 +2217,6 @@ void cProtocol172::HandlePacketWindowClose(cByteBuffer & a_ByteBuffer)
|
||||
|
||||
|
||||
|
||||
void cProtocol172::WritePacket(cByteBuffer & a_Packet)
|
||||
{
|
||||
cCSLock Lock(m_CSPacket);
|
||||
AString Pkt;
|
||||
a_Packet.ReadAll(Pkt);
|
||||
WriteVarInt((UInt32)Pkt.size());
|
||||
SendData(Pkt.data(), Pkt.size());
|
||||
Flush();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol172::SendData(const char * a_Data, size_t a_Size)
|
||||
{
|
||||
if (m_IsEncrypted)
|
||||
|
@ -296,9 +296,6 @@ protected:
|
||||
void HandlePacketWindowClose (cByteBuffer & a_ByteBuffer);
|
||||
|
||||
|
||||
/** Writes an entire packet into the output stream. a_Packet is expected to start with the packet type; data length is prepended here. */
|
||||
void WritePacket(cByteBuffer & a_Packet);
|
||||
|
||||
/** Sends the data to the client, encrypting them if needed. */
|
||||
virtual void SendData(const char * a_Data, size_t a_Size) override;
|
||||
|
||||
|
@ -2508,20 +2508,6 @@ void cProtocol180::HandlePacketWindowClose(cByteBuffer & a_ByteBuffer)
|
||||
|
||||
|
||||
|
||||
void cProtocol180::WritePacket(cByteBuffer & a_Packet)
|
||||
{
|
||||
cCSLock Lock(m_CSPacket);
|
||||
AString Pkt;
|
||||
a_Packet.ReadAll(Pkt);
|
||||
WriteVarInt((UInt32)Pkt.size());
|
||||
SendData(Pkt.data(), Pkt.size());
|
||||
Flush();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol180::SendData(const char * a_Data, size_t a_Size)
|
||||
{
|
||||
if (m_IsEncrypted)
|
||||
|
@ -313,9 +313,6 @@ protected:
|
||||
void HandlePacketWindowClose (cByteBuffer & a_ByteBuffer);
|
||||
|
||||
|
||||
/** Writes an entire packet into the output stream. a_Packet is expected to start with the packet type; data length is prepended here. */
|
||||
void WritePacket(cByteBuffer & a_Packet);
|
||||
|
||||
/** Sends the data to the client, encrypting them if needed. */
|
||||
virtual void SendData(const char * a_Data, size_t a_Size) override;
|
||||
|
||||
|
@ -7,11 +7,6 @@
|
||||
#include "Globals.h"
|
||||
|
||||
#include "ProtocolRecognizer.h"
|
||||
#include "Protocol125.h"
|
||||
#include "Protocol132.h"
|
||||
#include "Protocol14x.h"
|
||||
#include "Protocol15x.h"
|
||||
#include "Protocol16x.h"
|
||||
#include "Protocol17x.h"
|
||||
#include "Protocol18x.h"
|
||||
#include "../ClientHandle.h"
|
||||
@ -50,17 +45,6 @@ AString cProtocolRecognizer::GetVersionTextFromInt(int a_ProtocolVersion)
|
||||
{
|
||||
switch (a_ProtocolVersion)
|
||||
{
|
||||
case PROTO_VERSION_1_2_5: return "1.2.5";
|
||||
case PROTO_VERSION_1_3_2: return "1.3.2";
|
||||
// case PROTO_VERSION_1_4_2: return "1.4.2";
|
||||
case PROTO_VERSION_1_4_4: return "1.4.4";
|
||||
case PROTO_VERSION_1_4_6: return "1.4.6";
|
||||
case PROTO_VERSION_1_5_0: return "1.5";
|
||||
case PROTO_VERSION_1_5_2: return "1.5.2";
|
||||
case PROTO_VERSION_1_6_1: return "1.6.1";
|
||||
case PROTO_VERSION_1_6_2: return "1.6.2";
|
||||
case PROTO_VERSION_1_6_3: return "1.6.3";
|
||||
case PROTO_VERSION_1_6_4: return "1.6.4";
|
||||
case PROTO_VERSION_1_7_2: return "1.7.2";
|
||||
case PROTO_VERSION_1_7_6: return "1.7.6";
|
||||
case PROTO_VERSION_1_8_0: return "1.8";
|
||||
@ -213,8 +197,13 @@ void cProtocolRecognizer::SendDisconnect(const AString & a_Reason)
|
||||
else
|
||||
{
|
||||
// This is used when the client sends a server-ping, respond with the default packet:
|
||||
WriteByte (0xff); // PACKET_DISCONNECT
|
||||
WriteString(a_Reason);
|
||||
static const int Packet = 0xff; // PACKET_DISCONNECT
|
||||
SendData((const char *)&Packet, 1); // WriteByte()
|
||||
|
||||
AString UTF16 = UTF8ToRawBEUTF16(a_Reason.c_str(), a_Reason.length());
|
||||
static const short Size = htons((short)(UTF16.size() / 2));
|
||||
SendData((const char *)&Size, 2); // WriteShort()
|
||||
SendData(UTF16.data(), UTF16.size()); // WriteString()
|
||||
}
|
||||
}
|
||||
|
||||
@ -873,51 +862,8 @@ bool cProtocolRecognizer::TryRecognizeProtocol(void)
|
||||
{
|
||||
// NOTE: If a new protocol is added or an old one is removed, adjust MCS_CLIENT_VERSIONS and
|
||||
// MCS_PROTOCOL_VERSIONS macros in the header file, as well as PROTO_VERSION_LATEST macro
|
||||
|
||||
// The first packet should be a Handshake, 0x02:
|
||||
unsigned char PacketType;
|
||||
if (!m_Buffer.ReadByte(PacketType))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
switch (PacketType)
|
||||
{
|
||||
case 0x02: return TryRecognizeLengthlessProtocol(); // Handshake, continue recognizing
|
||||
case 0xfe:
|
||||
{
|
||||
// This may be either a packet length or the length-less Ping packet
|
||||
Byte NextByte;
|
||||
if (!m_Buffer.ReadByte(NextByte))
|
||||
{
|
||||
// Not enough data for either protocol
|
||||
// This could actually happen with the 1.2 / 1.3 client, but their support is fading out anyway
|
||||
return false;
|
||||
}
|
||||
if (NextByte != 0x01)
|
||||
{
|
||||
// This is definitely NOT a length-less Ping packet, handle as lengthed protocol:
|
||||
break;
|
||||
}
|
||||
if (!m_Buffer.ReadByte(NextByte))
|
||||
{
|
||||
// There is no more data. Although this *could* mean TCP fragmentation, it is highly unlikely
|
||||
// and rather this is a 1.4 client sending a regular Ping packet (without the following Plugin message)
|
||||
SendLengthlessServerPing();
|
||||
return false;
|
||||
}
|
||||
if (NextByte == 0xfa)
|
||||
{
|
||||
// Definitely a length-less Ping followed by a Plugin message
|
||||
SendLengthlessServerPing();
|
||||
return false;
|
||||
}
|
||||
// Definitely a lengthed Initial handshake, handle below:
|
||||
break;
|
||||
}
|
||||
} // switch (PacketType)
|
||||
|
||||
// This must be a lengthed protocol, try if it has the entire initial handshake packet:
|
||||
m_Buffer.ResetRead();
|
||||
// Lengthed protocol, try if it has the entire initial handshake packet:
|
||||
UInt32 PacketLen;
|
||||
UInt32 ReadSoFar = (UInt32)m_Buffer.GetReadableSpace();
|
||||
if (!m_Buffer.ReadVarInt(PacketLen))
|
||||
@ -938,61 +884,6 @@ bool cProtocolRecognizer::TryRecognizeProtocol(void)
|
||||
|
||||
|
||||
|
||||
bool cProtocolRecognizer::TryRecognizeLengthlessProtocol(void)
|
||||
{
|
||||
// The comm started with 0x02, which is a Handshake packet in the length-less protocol family
|
||||
// 1.3.2 starts with 0x02 0x39 <name-length-short>
|
||||
// 1.2.5 starts with 0x02 <name-length-short> and name is expected to less than 0x3900 long :)
|
||||
char ch;
|
||||
if (!m_Buffer.ReadChar(ch))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
switch (ch)
|
||||
{
|
||||
case PROTO_VERSION_1_3_2:
|
||||
{
|
||||
m_Protocol = new cProtocol132(m_Client);
|
||||
return true;
|
||||
}
|
||||
case PROTO_VERSION_1_4_2:
|
||||
case PROTO_VERSION_1_4_4:
|
||||
{
|
||||
m_Protocol = new cProtocol142(m_Client);
|
||||
return true;
|
||||
}
|
||||
case PROTO_VERSION_1_4_6:
|
||||
{
|
||||
m_Protocol = new cProtocol146(m_Client);
|
||||
return true;
|
||||
}
|
||||
case PROTO_VERSION_1_5_0:
|
||||
case PROTO_VERSION_1_5_2:
|
||||
{
|
||||
m_Protocol = new cProtocol150(m_Client);
|
||||
return true;
|
||||
}
|
||||
case PROTO_VERSION_1_6_1:
|
||||
{
|
||||
m_Protocol = new cProtocol161(m_Client);
|
||||
return true;
|
||||
}
|
||||
case PROTO_VERSION_1_6_2:
|
||||
case PROTO_VERSION_1_6_3:
|
||||
case PROTO_VERSION_1_6_4:
|
||||
{
|
||||
m_Protocol = new cProtocol162(m_Client);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
m_Protocol = new cProtocol125(m_Client);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cProtocolRecognizer::TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRemaining)
|
||||
{
|
||||
UInt32 PacketType;
|
||||
@ -1090,80 +981,3 @@ bool cProtocolRecognizer::TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRema
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocolRecognizer::SendLengthlessServerPing(void)
|
||||
{
|
||||
AString Reply;
|
||||
cServer * Server = cRoot::Get()->GetServer();
|
||||
|
||||
AString ServerDescription = Server->GetDescription();
|
||||
int NumPlayers = Server->GetNumPlayers();
|
||||
int MaxPlayers = Server->GetMaxPlayers();
|
||||
AString Favicon = Server->GetFaviconData();
|
||||
cRoot::Get()->GetPluginManager()->CallHookServerPing(*m_Client, ServerDescription, NumPlayers, MaxPlayers, Favicon);
|
||||
|
||||
switch (cRoot::Get()->GetPrimaryServerVersion())
|
||||
{
|
||||
case PROTO_VERSION_1_2_5:
|
||||
case PROTO_VERSION_1_3_2:
|
||||
{
|
||||
// http://wiki.vg/wiki/index.php?title=Protocol&oldid=3099#Server_List_Ping_.280xFE.29
|
||||
Printf(Reply, "%s%s%i%s%i",
|
||||
ServerDescription.c_str(),
|
||||
cChatColor::Delimiter,
|
||||
NumPlayers,
|
||||
cChatColor::Delimiter,
|
||||
MaxPlayers
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
case PROTO_VERSION_1_4_2:
|
||||
case PROTO_VERSION_1_4_4:
|
||||
case PROTO_VERSION_1_4_6:
|
||||
case PROTO_VERSION_1_5_0:
|
||||
case PROTO_VERSION_1_5_2:
|
||||
case PROTO_VERSION_1_6_1:
|
||||
case PROTO_VERSION_1_6_2:
|
||||
case PROTO_VERSION_1_6_3:
|
||||
case PROTO_VERSION_1_6_4:
|
||||
{
|
||||
// The server list ping now has 1 more byte of "magic". Mojang just loves to complicate stuff.
|
||||
// http://wiki.vg/wiki/index.php?title=Protocol&oldid=3101#Server_List_Ping_.280xFE.29
|
||||
// _X 2012_10_31: I know that this needn't eat the byte, since it still may be in transit.
|
||||
// Who cares? We're disconnecting anyway.
|
||||
m_Buffer.ResetRead();
|
||||
if (m_Buffer.CanReadBytes(2))
|
||||
{
|
||||
Byte val;
|
||||
m_Buffer.ReadByte(val); // Packet type - Serverlist ping
|
||||
m_Buffer.ReadByte(val); // 0x01 magic value
|
||||
ASSERT(val == 0x01);
|
||||
}
|
||||
|
||||
AString ProtocolVersionNum;
|
||||
Printf(ProtocolVersionNum, "%d", cRoot::Get()->GetPrimaryServerVersion());
|
||||
AString ProtocolVersionTxt(GetVersionTextFromInt(cRoot::Get()->GetPrimaryServerVersion()));
|
||||
|
||||
// Cannot use Printf() because of in-string NUL bytes.
|
||||
Reply = cChatColor::Delimiter;
|
||||
Reply.append("1");
|
||||
Reply.push_back(0);
|
||||
Reply.append(ProtocolVersionNum);
|
||||
Reply.push_back(0);
|
||||
Reply.append(ProtocolVersionTxt);
|
||||
Reply.push_back(0);
|
||||
Reply.append(ServerDescription);
|
||||
Reply.push_back(0);
|
||||
Reply.append(Printf("%d", NumPlayers));
|
||||
Reply.push_back(0);
|
||||
Reply.append(Printf("%d", MaxPlayers));
|
||||
break;
|
||||
}
|
||||
} // switch (m_PrimaryServerVersion)
|
||||
m_Client->Kick(Reply);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -18,8 +18,8 @@
|
||||
|
||||
|
||||
// Adjust these if a new protocol is added or an old one is removed:
|
||||
#define MCS_CLIENT_VERSIONS "1.2.4, 1.2.5, 1.3.1, 1.3.2, 1.4.2, 1.4.4, 1.4.5, 1.4.6, 1.4.7, 1.5, 1.5.1, 1.5.2, 1.6.1, 1.6.2, 1.6.3, 1.6.4, 1.7.2, 1.7.4, 1.7.5, 1.7.6, 1.7.7, 1.7.8, 1.7.9, 1.7.10, 1.8"
|
||||
#define MCS_PROTOCOL_VERSIONS "29, 39, 47, 49, 51, 60, 61, 73, 74, 77, 78, 4, 5"
|
||||
#define MCS_CLIENT_VERSIONS "1.7.x, 1.8"
|
||||
#define MCS_PROTOCOL_VERSIONS "4, 5, 47"
|
||||
|
||||
|
||||
|
||||
@ -33,22 +33,6 @@ class cProtocolRecognizer :
|
||||
public:
|
||||
enum
|
||||
{
|
||||
PROTO_VERSION_1_2_5 = 29,
|
||||
PROTO_VERSION_1_3_2 = 39,
|
||||
PROTO_VERSION_1_4_2 = 47,
|
||||
PROTO_VERSION_1_4_4 = 49,
|
||||
PROTO_VERSION_1_4_6 = 51,
|
||||
PROTO_VERSION_1_5_0 = 60,
|
||||
PROTO_VERSION_1_5_2 = 61,
|
||||
PROTO_VERSION_1_6_1 = 73,
|
||||
PROTO_VERSION_1_6_2 = 74,
|
||||
PROTO_VERSION_1_6_3 = 77,
|
||||
PROTO_VERSION_1_6_4 = 78,
|
||||
|
||||
PROTO_VERSION_NEXT,
|
||||
PROTO_VERSION_LATEST = PROTO_VERSION_NEXT - 1, ///< Automatically assigned to the last protocol version, this serves as the default for PrimaryServerVersion
|
||||
|
||||
// These will be kept "under" the next / latest, because the next and latest are only needed for previous protocols
|
||||
PROTO_VERSION_1_7_2 = 4,
|
||||
PROTO_VERSION_1_7_6 = 5,
|
||||
PROTO_VERSION_1_8_0 = 47,
|
||||
@ -150,23 +134,11 @@ protected:
|
||||
/// Tries to recognize protocol based on m_Buffer contents; returns true if recognized
|
||||
bool TryRecognizeProtocol(void);
|
||||
|
||||
/** Tries to recognize a protocol in the length-less family, based on m_Buffer; returns true if recognized.
|
||||
Handles protocols before release 1.7, that didn't include packet lengths, and started with a 0x02 handshake packet
|
||||
Note that length-less server ping is handled directly in TryRecognizeProtocol(), this function is called only
|
||||
when the 0x02 Handshake packet has been received
|
||||
*/
|
||||
bool TryRecognizeLengthlessProtocol(void);
|
||||
|
||||
/** Tries to recognize a protocol in the leghted family (1.7+), based on m_Buffer; returns true if recognized.
|
||||
The packet length and type have already been read, type is 0
|
||||
The number of bytes remaining in the packet is passed as a_PacketLengthRemaining
|
||||
**/
|
||||
bool TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRemaining);
|
||||
|
||||
/** Called when the recognizer gets a length-less protocol's server ping packet
|
||||
Responds with server stats and destroys the client.
|
||||
*/
|
||||
void SendLengthlessServerPing(void);
|
||||
} ;
|
||||
|
||||
|
||||
|
12
src/Root.cpp
12
src/Root.cpp
@ -42,7 +42,6 @@ cRoot* cRoot::s_Root = NULL;
|
||||
|
||||
|
||||
cRoot::cRoot(void) :
|
||||
m_PrimaryServerVersion(cProtocolRecognizer::PROTO_VERSION_LATEST),
|
||||
m_pDefaultWorld(NULL),
|
||||
m_InputThread(NULL),
|
||||
m_Server(NULL),
|
||||
@ -142,17 +141,6 @@ void cRoot::Start(void)
|
||||
IniFile.AddHeaderComment(" See: http://wiki.mc-server.org/doku.php?id=configure:settings.ini for further configuration help");
|
||||
}
|
||||
|
||||
m_PrimaryServerVersion = IniFile.GetValueI("Server", "PrimaryServerVersion", 0);
|
||||
if (m_PrimaryServerVersion == 0)
|
||||
{
|
||||
m_PrimaryServerVersion = cProtocolRecognizer::PROTO_VERSION_LATEST;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make a note in the log that the primary server version is explicitly set in the ini file
|
||||
LOGINFO("Primary server version set explicitly to %d.", m_PrimaryServerVersion);
|
||||
}
|
||||
|
||||
LOG("Starting server...");
|
||||
m_MojangAPI.Start(IniFile); // Mojang API needs to be started before plugins, so that plugins may use it for DB upgrades on server init
|
||||
if (!m_Server->InitServer(IniFile))
|
||||
|
@ -73,9 +73,6 @@ public:
|
||||
/// Writes chunkstats, for each world and totals, to the output callback
|
||||
void LogChunkStats(cCommandOutputCallback & a_Output);
|
||||
|
||||
int GetPrimaryServerVersion(void) const { return m_PrimaryServerVersion; } // tolua_export
|
||||
void SetPrimaryServerVersion(int a_Version) { m_PrimaryServerVersion = a_Version; } // tolua_export
|
||||
|
||||
cMonsterConfig * GetMonsterConfig(void) { return m_MonsterConfig; }
|
||||
|
||||
cCraftingRecipes * GetCraftingRecipes(void) { return m_CraftingRecipes; } // tolua_export
|
||||
@ -169,9 +166,6 @@ private:
|
||||
|
||||
typedef std::map<AString, cWorld *> WorldMap;
|
||||
typedef std::vector<cCommand> cCommandQueue;
|
||||
|
||||
/// The version of the protocol that is primary for the server (reported in the server list). All versions are still supported.
|
||||
int m_PrimaryServerVersion;
|
||||
|
||||
cWorld * m_pDefaultWorld;
|
||||
WorldMap m_WorldsByName;
|
||||
|
@ -441,10 +441,10 @@ static bool isLegalUTF8(const unsigned char * source, int length)
|
||||
|
||||
|
||||
|
||||
AString & UTF8ToRawBEUTF16(const char * a_UTF8, size_t a_UTF8Length, AString & a_UTF16)
|
||||
AString UTF8ToRawBEUTF16(const char * a_UTF8, size_t a_UTF8Length)
|
||||
{
|
||||
a_UTF16.clear();
|
||||
a_UTF16.reserve(a_UTF8Length * 3);
|
||||
AString UTF16;
|
||||
UTF16.reserve(a_UTF8Length * 3);
|
||||
|
||||
const unsigned char * source = (const unsigned char*)a_UTF8;
|
||||
const unsigned char * sourceEnd = source + a_UTF8Length;
|
||||
@ -458,12 +458,12 @@ AString & UTF8ToRawBEUTF16(const char * a_UTF8, size_t a_UTF8Length, AString & a
|
||||
unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
|
||||
if (source + extraBytesToRead >= sourceEnd)
|
||||
{
|
||||
return a_UTF16;
|
||||
return UTF16;
|
||||
}
|
||||
// Do this check whether lenient or strict
|
||||
if (!isLegalUTF8(source, extraBytesToRead + 1))
|
||||
{
|
||||
return a_UTF16;
|
||||
return UTF16;
|
||||
}
|
||||
|
||||
// The cases all fall through. See "Note A" below.
|
||||
@ -487,13 +487,13 @@ AString & UTF8ToRawBEUTF16(const char * a_UTF8, size_t a_UTF8Length, AString & a
|
||||
ch = ' ';
|
||||
}
|
||||
unsigned short v = htons((unsigned short)ch);
|
||||
a_UTF16.append((const char *)&v, 2);
|
||||
UTF16.append((const char *)&v, 2);
|
||||
}
|
||||
else if (ch > UNI_MAX_UTF16)
|
||||
{
|
||||
// Invalid value, replace with a space
|
||||
unsigned short v = htons(' ');
|
||||
a_UTF16.append((const char *)&v, 2);
|
||||
UTF16.append((const char *)&v, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -501,11 +501,11 @@ AString & UTF8ToRawBEUTF16(const char * a_UTF8, size_t a_UTF8Length, AString & a
|
||||
ch -= halfBase;
|
||||
unsigned short v1 = htons((ch >> halfShift) + UNI_SUR_HIGH_START);
|
||||
unsigned short v2 = htons((ch & halfMask) + UNI_SUR_LOW_START);
|
||||
a_UTF16.append((const char *)&v1, 2);
|
||||
a_UTF16.append((const char *)&v2, 2);
|
||||
UTF16.append((const char *)&v1, 2);
|
||||
UTF16.append((const char *)&v2, 2);
|
||||
}
|
||||
}
|
||||
return a_UTF16;
|
||||
return UTF16;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -66,8 +66,8 @@ extern void ReplaceString(AString & iHayStack, const AString & iNeedle, const AS
|
||||
/// Converts a stream of BE shorts into UTF-8 string; returns a ref to a_UTF8
|
||||
extern AString & RawBEToUTF8(const char * a_RawData, size_t a_NumShorts, AString & a_UTF8);
|
||||
|
||||
/// Converts a UTF-8 string into a UTF-16 BE string, packing that back into AString; return a ref to a_UTF16
|
||||
extern AString & UTF8ToRawBEUTF16(const char * a_UTF8, size_t a_UTF8Length, AString & a_UTF16);
|
||||
/// Converts a UTF-8 string into a UTF-16 BE string; returns a ref to a_UTF16
|
||||
extern AString UTF8ToRawBEUTF16(const char * a_UTF8, size_t a_UTF8Length);
|
||||
|
||||
/// Creates a nicely formatted HEX dump of the given memory block. Max a_BytesPerLine is 120
|
||||
extern AString & CreateHexDump(AString & a_Out, const void * a_Data, size_t a_Size, size_t a_BytesPerLine);
|
||||
|
Loading…
Reference in New Issue
Block a user