summaryrefslogblamecommitdiffstats
path: root/src/Protocol/ProtocolRecognizer.cpp
blob: 73f8e0ff1fdd0b58bfa9dd3d11dcf62026e7c12b (plain) (tree)
1
2
3
4
5
6
7
8
9


                         
                                                                                                            




                                                     



                          
                          
                          
                       

                            
                      

                         
                         
                                      





                                                                    
                        

                                                                                                                 






 



                                                                         




                                                           

                                                          
                                                            
                                                          
                                                            
                                                          








                                                                  
                                                                          
 
                                  
         










                                                                        
                                            
         
                                           
                 




                                                                                                                       

                               
                    
                 
                                             
                 
















                                                            
                 


                                             

                 
                                                                              
                 








                                                                                       

                               






         
                                                                                               
 
                                      








                                                                                                                                      
                                      






                                                                                                 
                                                                                                                       
 
                                      
                                                                                          







                                                                                                                                  
                                      








                                                                                                         
                                      





                                                                    
 








                                                                   
 
                                                                               
 
                                      
                                                





 
                                                                                                                    
 
                                      
                                                                         





 









                                                                                     

                                                                                                        
                                      






                                                                    
                                                                                                                       
 
                                      
                                                                         







                                                                     
                                      






                                                









                                                                                                       

                                                                  
                                  




                                                     
                                                                                              
                                                                 
                                         
         




 
 

                                                                                
                                      






                                                               









                                                                                         
                                                                                                                     
 
                                      






                                                                                    

                                                                                                              
                                      








                                                                      
                                      








                                                                  
                                      








                                                                      
                                      






                                                 
                                                                      
 
                                      
                                                 





 
                                                                        
 
                                      
                                                   







                                                                                   
                                      








                                                                      
                                      








                                                                                                                                                                                    
                                      
                                                                                                            







                                                            
                                      








                                             
                                      





                                 









                                                             
 









                                             
                                                                                                       
 
                                      
                                                                      







                                                                                                   
                                      






                                                                     
                                                        
 
                                      






                                            



















                                                                                                      

                                                                                     
                                      






                                                 

                                                
                                      






                                       
                                                                                             
 
                                      
                                                                   





 
                                                                                                                                                                                                                     
 
                                      
                                                                                                                                                  




 










                                                                                                                                                                                      







                                                                         
 

                                                   
                                      






                                          
                                                                           
 
                                      








                                                                              
                                      








                                                                                
                                      








                                                                            
                                      






                                                       
                                                                                                                 
 
                                      
                                                                            







                                                  
                                      








                                                  
                                      








                                                  
                                      








                                                                   
                                      






                                              

                                                                                                 
                                      






                                                            

                                                                                          
                                      






                                                                 









                                              









                                                                             
                                                             
 
                                      
                                             





 
                                              
 
                                      
                                     





 
                                                                     
 
                                      
                                                





 

                                                                                                                     
                                      








                                                                                                                                        
                                      








                                                                                                                
                                      






                                                                 







































                                                                            
                                                                                                                                         
 
                                      
                                                                                   





 
                                                                                                                            
 
                                      






                                                                                        
                                                                   
 
                                      
                                              







                                                              
                                      






                                        

                                                                        
                                      






                                              

                                                                                   
                                      






                                                        

                                                                                   
                                      






                                                                  









                                                                                                   
                                                                                                     
 
                                      
                                                                               







                                                                     
                                      






                                                        
                                                                             
 
                                      
                                                         





 

                                                                                                                                                                                      
                                      






                                                                                                     
                                                                                                        
 
                                      








                                                                       
                                      






                                           

                                                                      
                                      








                                                                   
                                      






                                              
                                                                  
 
                                      
                                             







                                                  
                                      






                                             
                                                                      










                                                          
                                                                                                                                                    
 
                                                                                
                         
                                                                            



                                                                       
         
                                                                      




                                                                

















                                                                 





 


                                                                                      

















                                                                                                   
                                                      















                                                       

                                

                                         
                                              
                                                                                                              



                                         
                                                                                                              



                                         
                                                                                                              



                                         
                                                                                                              



                                         
                                                                                                              

                                    

                                          
                                                                                                               



                                          
                                                                                                               

                                    

                                          
                                                                                                               

                                    

                                        
                                                                                                             

                                    

                                          
                                                                                                               

                                    

                                          
                                                                                                               

                                    

                                        
                                                                                                             

                                    

                        
                                                                                                        


                                                                                                 
                         

                                                                                                                                                                    
                         
                            
                         
                                                                      
                         
                                     
                 
         




 
 

                                                         




















                                                                                 


















                                                                                                     
                                                         


                                                             

                                                                       





                                                                                                                            
                                                          




















                                                                                               
                                                                     
 
                                                  
                                  





 







                                                  
                                                

                                    

// ProtocolRecognizer.cpp

// Implements the cProtocolRecognizer class representing the meta-protocol that recognizes possibly multiple
// protocol versions and redirects everything to them

#include "Globals.h"

#include "ProtocolRecognizer.h"
#include "Protocol_1_8.h"
#include "Protocol_1_9.h"
#include "Protocol_1_10.h"
#include "Protocol_1_11.h"
#include "Protocol_1_12.h"
#include "Protocol_1_13.h"
#include "Packetizer.h"
#include "../ClientHandle.h"
#include "../Root.h"
#include "../Server.h"
#include "../World.h"
#include "../ChatColor.h"
#include "../JsonUtils.h"
#include "../Bindings/PluginManager.h"





cProtocolRecognizer::cProtocolRecognizer(cClientHandle * a_Client) :
	Super(a_Client),
	m_Buffer(8192),  // We need a larger buffer to support BungeeCord - it sends one huge packet at the start
	m_InPingForUnrecognizedVersion(false)
{
}





AString cProtocolRecognizer::GetVersionTextFromInt(int a_ProtocolVersion)
{
	switch (a_ProtocolVersion)
	{
		case PROTO_VERSION_1_8_0:   return "1.8";
		case PROTO_VERSION_1_9_0:   return "1.9";
		case PROTO_VERSION_1_9_1:   return "1.9.1";
		case PROTO_VERSION_1_9_2:   return "1.9.2";
		case PROTO_VERSION_1_9_4:   return "1.9.4";
		case PROTO_VERSION_1_10_0:  return "1.10";
		case PROTO_VERSION_1_11_0:  return "1.11";
		case PROTO_VERSION_1_11_1:  return "1.11.1";
		case PROTO_VERSION_1_12:    return "1.12";
		case PROTO_VERSION_1_12_1:  return "1.12.1";
		case PROTO_VERSION_1_13:    return "1.13";
	}
	ASSERT(!"Unknown protocol version");
	return Printf("Unknown protocol (%d)", a_ProtocolVersion);
}





void cProtocolRecognizer::DataReceived(const char * a_Data, size_t a_Size)
{
	if (m_Protocol != nullptr)
	{
		// Protocol was already recognized, send to the handler:
		m_Protocol->DataReceived(a_Data, a_Size);
		return;
	}

	if (!m_Buffer.Write(a_Data, a_Size))
	{
		m_Client->Kick("Unsupported protocol version");
		return;
	}

	if (!m_InPingForUnrecognizedVersion)
	{
		if (TryRecognizeProtocol())
		{
			// The protocol has just been recognized, dump the whole m_Buffer contents into it for parsing:
			AString Dump;
			m_Buffer.ResetRead();
			m_Buffer.ReadAll(Dump);
			m_Protocol->DataReceived(Dump.data(), Dump.size());
			return;
		}
		else
		{
			m_Buffer.ResetRead();
		}
	}

	if (!m_InPingForUnrecognizedVersion)
	{
		return;
	}

	// Handle server list ping packets
	for (;;)
	{
		UInt32 PacketLen;
		UInt32 PacketID;
		if (
			!m_Buffer.ReadVarInt32(PacketLen) ||
			!m_Buffer.CanReadBytes(PacketLen) ||
			!m_Buffer.ReadVarInt32(PacketID)
		)
		{
			// Not enough data
			m_Buffer.ResetRead();
			break;
		}

		if ((PacketID == 0x00) && (PacketLen == 1))  // Request packet
		{
			HandlePacketStatusRequest();
		}
		else if ((PacketID == 0x01) && (PacketLen == 9))  // Ping packet
		{
			HandlePacketStatusPing();
		}
		else
		{
			m_Client->Kick("Server list ping failed, unrecognized packet");
			return;
		}
	}
}





void cProtocolRecognizer::SendAttachEntity(const cEntity & a_Entity, const cEntity & a_Vehicle)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendAttachEntity(a_Entity, a_Vehicle);
}





void cProtocolRecognizer::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendBlockAction(a_BlockX, a_BlockY, a_BlockZ, a_Byte1, a_Byte2, a_BlockType);
}





void cProtocolRecognizer::SendBlockBreakAnim(UInt32 a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendBlockBreakAnim(a_EntityID, a_BlockX, a_BlockY, a_BlockZ, a_Stage);
}





void cProtocolRecognizer::SendBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendBlockChange(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta);
}





void cProtocolRecognizer::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendBlockChanges(a_ChunkX, a_ChunkZ, a_Changes);
}





void cProtocolRecognizer::SendCameraSetTo(const cEntity & a_Entity)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendCameraSetTo(a_Entity);
}





void cProtocolRecognizer::SendChat(const AString & a_Message, eChatType a_Type)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendChat(a_Message, a_Type);
}





void cProtocolRecognizer::SendChat(const cCompositeChat & a_Message, eChatType a_Type, bool a_ShouldUseChatPrefixes)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendChat(a_Message, a_Type, a_ShouldUseChatPrefixes);
}





void cProtocolRecognizer::SendChatRaw(const AString & a_MessageRaw, eChatType a_Type)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendChatRaw(a_MessageRaw, a_Type);
}





void cProtocolRecognizer::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendChunkData(a_ChunkX, a_ChunkZ, a_Serializer);
}





void cProtocolRecognizer::SendCollectEntity(const cEntity & a_Collected, const cEntity & a_Collector, unsigned a_Count)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendCollectEntity(a_Collected, a_Collector, a_Count);
}





void cProtocolRecognizer::SendDestroyEntity(const cEntity & a_Entity)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendDestroyEntity(a_Entity);
}





void cProtocolRecognizer::SendDetachEntity(const cEntity & a_Entity, const cEntity & a_PreviousVehicle)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendDetachEntity(a_Entity, a_PreviousVehicle);
}





void cProtocolRecognizer::SendDisconnect(const AString & a_Reason)
{
	if (m_Protocol != nullptr)
	{
		m_Protocol->SendDisconnect(a_Reason);
	}
	else
	{
		AString Message = Printf("{\"text\":\"%s\"}", EscapeString(a_Reason).c_str());
		cPacketizer Pkt(*this, pktDisconnectDuringLogin);
		Pkt.WriteString(Message);
	}
}





void cProtocolRecognizer::SendEditSign(int a_BlockX, int a_BlockY, int a_BlockZ)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendEditSign(a_BlockX, a_BlockY, a_BlockZ);
}





void cProtocolRecognizer::SendEntityAnimation(const cEntity & a_Entity, char a_Animation)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendEntityAnimation(a_Entity, a_Animation);
}





void cProtocolRecognizer::SendEntityEffect(const cEntity & a_Entity, int a_EffectID, int a_Amplifier, int a_Duration)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendEntityEffect(a_Entity, a_EffectID, a_Amplifier, a_Duration);
}





void cProtocolRecognizer::SendEntityEquipment(const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendEntityEquipment(a_Entity, a_SlotNum, a_Item);
}





void cProtocolRecognizer::SendEntityHeadLook(const cEntity & a_Entity)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendEntityHeadLook(a_Entity);
}





void cProtocolRecognizer::SendEntityLook(const cEntity & a_Entity)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendEntityLook(a_Entity);
}





void cProtocolRecognizer::SendEntityMetadata(const cEntity & a_Entity)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendEntityMetadata(a_Entity);
}





void cProtocolRecognizer::SendEntityPosition(const cEntity & a_Entity)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendEntityPosition(a_Entity);
}





void cProtocolRecognizer::SendEntityProperties(const cEntity & a_Entity)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendEntityProperties(a_Entity);
}





void cProtocolRecognizer::SendEntityStatus(const cEntity & a_Entity, char a_Status)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendEntityStatus(a_Entity, a_Status);
}





void cProtocolRecognizer::SendEntityVelocity(const cEntity & a_Entity)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendEntityVelocity(a_Entity);
}





void cProtocolRecognizer::SendExplosion(double a_BlockX, double a_BlockY, double a_BlockZ, float a_Radius, const cVector3iArray & a_BlocksAffected, const Vector3d & a_PlayerMotion)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendExplosion(a_BlockX, a_BlockY, a_BlockZ, a_Radius, a_BlocksAffected, a_PlayerMotion);
}





void cProtocolRecognizer::SendGameMode(eGameMode a_GameMode)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendGameMode(a_GameMode);
}





void cProtocolRecognizer::SendHealth(void)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendHealth();
}





void cProtocolRecognizer::SendHeldItemChange(int a_ItemIndex)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendHeldItemChange(a_ItemIndex);
}





void cProtocolRecognizer::SendHideTitle(void)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendHideTitle();
}





void cProtocolRecognizer::SendWindowProperty(const cWindow & a_Window, short a_Property, short a_Value)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendWindowProperty(a_Window, a_Property, a_Value);
}





void cProtocolRecognizer::SendInventorySlot(char a_WindowID, short a_SlotNum, const cItem & a_Item)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendInventorySlot(a_WindowID, a_SlotNum, a_Item);
}





void cProtocolRecognizer::SendKeepAlive(UInt32 a_PingID)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendKeepAlive(a_PingID);
}





void cProtocolRecognizer::SendLeashEntity(const cEntity & a_Entity, const cEntity & a_EntityLeashedTo)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendLeashEntity(a_Entity, a_EntityLeashedTo);
}





void cProtocolRecognizer::SendUnleashEntity(const cEntity & a_Entity)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendUnleashEntity(a_Entity);
}





void cProtocolRecognizer::SendLogin(const cPlayer & a_Player, const cWorld & a_World)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendLogin(a_Player, a_World);
}





void cProtocolRecognizer::SendLoginSuccess(void)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendLoginSuccess();
}





void cProtocolRecognizer::SendMapData(const cMap & a_Map, int a_DataStartX, int a_DataStartY)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendMapData(a_Map, a_DataStartX, a_DataStartY);
}





void cProtocolRecognizer::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)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendParticleEffect(a_ParticleName, a_SrcX, a_SrcY, a_SrcZ, a_OffsetX, a_OffsetY, a_OffsetZ, a_ParticleData, a_ParticleAmount);
}





void cProtocolRecognizer::SendParticleEffect(const AString & a_ParticleName, Vector3f a_Src, Vector3f a_Offset, float a_ParticleData, int a_ParticleAmount, std::array<int, 2> a_Data)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendParticleEffect(a_ParticleName, a_Src, a_Offset, a_ParticleData, a_ParticleAmount, a_Data);
}





void cProtocolRecognizer::SendPaintingSpawn(const cPainting & a_Painting)
{
	m_Protocol->SendPaintingSpawn(a_Painting);
}





void cProtocolRecognizer::SendPlayerAbilities(void)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendPlayerAbilities();
}





void cProtocolRecognizer::SendPlayerListAddPlayer(const cPlayer & a_Player)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendPlayerListAddPlayer(a_Player);
}





void cProtocolRecognizer::SendPlayerListRemovePlayer(const cPlayer & a_Player)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendPlayerListRemovePlayer(a_Player);
}





void cProtocolRecognizer::SendPlayerListUpdateGameMode(const cPlayer & a_Player)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendPlayerListUpdateGameMode(a_Player);
}





void cProtocolRecognizer::SendPlayerListUpdatePing(const cPlayer & a_Player)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendPlayerListUpdatePing(a_Player);
}





void cProtocolRecognizer::SendPlayerListUpdateDisplayName(const cPlayer & a_Player, const AString & a_CustomName)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendPlayerListUpdateDisplayName(a_Player, a_CustomName);
}





void cProtocolRecognizer::SendPlayerMaxSpeed(void)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendPlayerMaxSpeed();
}





void cProtocolRecognizer::SendPlayerMoveLook(void)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendPlayerMoveLook();
}





void cProtocolRecognizer::SendPlayerPosition(void)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendPlayerPosition();
}





void cProtocolRecognizer::SendPlayerSpawn(const cPlayer & a_Player)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendPlayerSpawn(a_Player);
}





void cProtocolRecognizer::SendPluginMessage(const AString & a_Channel, const AString & a_Message)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendPluginMessage(a_Channel, a_Message);
}





void cProtocolRecognizer::SendRemoveEntityEffect(const cEntity & a_Entity, int a_EffectID)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendRemoveEntityEffect(a_Entity, a_EffectID);
}





void cProtocolRecognizer::SendResetTitle(void)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendResetTitle();
}





void cProtocolRecognizer::SendResourcePack(const AString & a_ResourcePackUrl)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendResourcePack(a_ResourcePackUrl);
}





void cProtocolRecognizer::SendRespawn(eDimension a_Dimension)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendRespawn(a_Dimension);
}





void cProtocolRecognizer::SendExperience(void)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendExperience();
}





void cProtocolRecognizer::SendExperienceOrb(const cExpOrb & a_ExpOrb)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendExperienceOrb(a_ExpOrb);
}





void cProtocolRecognizer::SendScoreboardObjective(const AString & a_Name, const AString & a_DisplayName, Byte a_Mode)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendScoreboardObjective(a_Name, a_DisplayName, a_Mode);
}





void cProtocolRecognizer::SendScoreUpdate(const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendScoreUpdate(a_Objective, a_Player, a_Score, a_Mode);
}





void cProtocolRecognizer::SendDisplayObjective(const AString & a_Objective, cScoreboard::eDisplaySlot a_Display)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendDisplayObjective(a_Objective, a_Display);
}





void cProtocolRecognizer::SendSetSubTitle(const cCompositeChat & a_SubTitle)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendSetSubTitle(a_SubTitle);
}





void cProtocolRecognizer::SendSetRawSubTitle(const AString & a_SubTitle)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendSetRawSubTitle(a_SubTitle);
}





void cProtocolRecognizer::SendSetTitle(const cCompositeChat & a_Title)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendSetTitle(a_Title);
}





void cProtocolRecognizer::SendSetRawTitle(const AString & a_Title)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendSetRawTitle(a_Title);
}





void cProtocolRecognizer::SendSoundEffect(const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendSoundEffect(a_SoundName, a_X, a_Y, a_Z, a_Volume, a_Pitch);
}





void cProtocolRecognizer::SendSoundParticleEffect(const EffectID a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendSoundParticleEffect(a_EffectID, a_SrcX, a_SrcY, a_SrcZ, a_Data);
}





void cProtocolRecognizer::SendSpawnEntity(const cEntity & a_Entity)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendSpawnEntity(a_Entity);
}





void cProtocolRecognizer::SendSpawnMob(const cMonster & a_Mob)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendSpawnMob(a_Mob);
}





void cProtocolRecognizer::SendStatistics(const cStatManager & a_Manager)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendStatistics(a_Manager);
}





void cProtocolRecognizer::SendTabCompletionResults(const AStringVector & a_Results)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendTabCompletionResults(a_Results);
}





void cProtocolRecognizer::SendThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendThunderbolt(a_BlockX, a_BlockY, a_BlockZ);
}





void cProtocolRecognizer::SendTitleTimes(int a_FadeInTicks, int a_DisplayTicks, int a_FadeOutTicks)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendTitleTimes(a_FadeInTicks, a_DisplayTicks, a_FadeOutTicks);
}





void cProtocolRecognizer::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendTimeUpdate(a_WorldAge, a_TimeOfDay, a_DoDaylightCycle);
}





void cProtocolRecognizer::SendUnloadChunk(int a_ChunkX, int a_ChunkZ)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendUnloadChunk(a_ChunkX, a_ChunkZ);
}





void cProtocolRecognizer::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendUpdateBlockEntity(a_BlockEntity);
}





void cProtocolRecognizer::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)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendUpdateSign(a_BlockX, a_BlockY, a_BlockZ, a_Line1, a_Line2, a_Line3, a_Line4);
}





void cProtocolRecognizer::SendUseBed(const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendUseBed(a_Entity, a_BlockX, a_BlockY, a_BlockZ);
}





void cProtocolRecognizer::SendWeather(eWeather a_Weather)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendWeather(a_Weather);
}





void cProtocolRecognizer::SendWholeInventory(const cWindow & a_Window)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendWholeInventory(a_Window);
}





void cProtocolRecognizer::SendWindowClose(const cWindow & a_Window)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendWindowClose(a_Window);
}





void cProtocolRecognizer::SendWindowOpen(const cWindow & a_Window)
{
	ASSERT(m_Protocol != nullptr);
	m_Protocol->SendWindowOpen(a_Window);
}





AString cProtocolRecognizer::GetAuthServerID(void)
{
	ASSERT(m_Protocol != nullptr);
	return m_Protocol->GetAuthServerID();
}





void cProtocolRecognizer::SendData(const char * a_Data, size_t a_Size)
{
	// This is used only when handling the server ping
	m_Client->SendData(a_Data, a_Size);
}





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

	// Lengthed protocol, try if it has the entire initial handshake packet:
	UInt32 PacketLen;
	UInt32 ReadSoFar = static_cast<UInt32>(m_Buffer.GetReadableSpace());
	if (!m_Buffer.ReadVarInt(PacketLen))
	{
		// Not enough bytes for the packet length, keep waiting
		return false;
	}
	ReadSoFar -= static_cast<UInt32>(m_Buffer.GetReadableSpace());
	if (!m_Buffer.CanReadBytes(PacketLen))
	{
		// Not enough bytes for the packet, keep waiting
		return false;
	}
	if (!TryRecognizeLengthedProtocol(PacketLen - ReadSoFar))
	{
		return false;
	}

	// The protocol has been recognized, initialize it:
	ASSERT(m_Protocol != nullptr);
	try
	{
		m_Protocol->Initialize(*m_Client);
	}
	catch (const std::exception & exc)
	{
		m_Client->Kick(exc.what());
		m_Protocol.reset();
		return false;
	}
	return true;
}





bool cProtocolRecognizer::TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRemaining)
{
	UInt32 PacketType;
	if (!m_Buffer.ReadVarInt(PacketType))
	{
		return false;
	}
	if (PacketType != 0x00)
	{
		// Not an initial handshake packet, we don't know how to talk to them
		LOGINFO("Client \"%s\" uses an unsupported protocol (lengthed, initial packet %u)",
			m_Client->GetIPString().c_str(), PacketType
		);
		m_Client->Kick("Unsupported protocol version");
		return false;
	}
	UInt32 ProtocolVersion;
	if (!m_Buffer.ReadVarInt(ProtocolVersion))
	{
		return false;
	}
	m_Client->SetProtocolVersion(ProtocolVersion);
	AString ServerAddress;
	UInt16 ServerPort;
	UInt32 NextState;
	if (!m_Buffer.ReadVarUTF8String(ServerAddress))
	{
		return false;
	}
	if (!m_Buffer.ReadBEUInt16(ServerPort))
	{
		return false;
	}
	if (!m_Buffer.ReadVarInt(NextState))
	{
		return false;
	}
	m_Buffer.CommitRead();
	switch (ProtocolVersion)
	{
		case PROTO_VERSION_1_8_0:
		{
			m_Buffer.CommitRead();
			m_Protocol.reset(new cProtocol_1_8_0(m_Client, ServerAddress, ServerPort, NextState));
			return true;
		}
		case PROTO_VERSION_1_9_0:
		{
			m_Protocol.reset(new cProtocol_1_9_0(m_Client, ServerAddress, ServerPort, NextState));
			return true;
		}
		case PROTO_VERSION_1_9_1:
		{
			m_Protocol.reset(new cProtocol_1_9_1(m_Client, ServerAddress, ServerPort, NextState));
			return true;
		}
		case PROTO_VERSION_1_9_2:
		{
			m_Protocol.reset(new cProtocol_1_9_2(m_Client, ServerAddress, ServerPort, NextState));
			return true;
		}
		case PROTO_VERSION_1_9_4:
		{
			m_Protocol.reset(new cProtocol_1_9_4(m_Client, ServerAddress, ServerPort, NextState));
			return true;
		}
		case PROTO_VERSION_1_10_0:
		{
			m_Protocol.reset(new cProtocol_1_10_0(m_Client, ServerAddress, ServerPort, NextState));
			return true;
		}
		case PROTO_VERSION_1_11_0:
		{
			m_Protocol.reset(new cProtocol_1_11_0(m_Client, ServerAddress, ServerPort, NextState));
			return true;
		}
		case PROTO_VERSION_1_11_1:
		{
			m_Protocol.reset(new cProtocol_1_11_1(m_Client, ServerAddress, ServerPort, NextState));
			return true;
		}
		case PROTO_VERSION_1_12:
		{
			m_Protocol.reset(new cProtocol_1_12(m_Client, ServerAddress, ServerPort, NextState));
			return true;
		}
		case PROTO_VERSION_1_12_1:
		{
			m_Protocol.reset(new cProtocol_1_12_1(m_Client, ServerAddress, ServerPort, NextState));
			return true;
		}
		case PROTO_VERSION_1_12_2:
		{
			m_Protocol.reset(new cProtocol_1_12_2(m_Client, ServerAddress, ServerPort, NextState));
			return true;
		}
		case PROTO_VERSION_1_13:
		{
			m_Protocol.reset(new cProtocol_1_13(m_Client, ServerAddress, ServerPort, NextState));
			return true;
		}
		default:
		{
			LOGD("Client \"%s\" uses an unsupported protocol (lengthed, version %u (0x%x))",
				m_Client->GetIPString().c_str(), ProtocolVersion, ProtocolVersion
			);
			if (NextState != 1)
			{
				m_Client->Kick(Printf("Unsupported protocol version %u, please use one of these versions:\n" MCS_CLIENT_VERSIONS, ProtocolVersion));
				return false;
			}
			else
			{
				m_InPingForUnrecognizedVersion = true;
			}
			return false;
		}
	}
}





void cProtocolRecognizer::SendPacket(cPacketizer & a_Pkt)
{
	// Writes out the packet normally.
	UInt32 PacketLen = static_cast<UInt32>(m_OutPacketBuffer.GetUsedSpace());
	AString PacketData, CompressedPacket;
	m_OutPacketBuffer.ReadAll(PacketData);
	m_OutPacketBuffer.CommitRead();

	// Compression doesn't apply to this state, send raw data:
	m_OutPacketLenBuffer.WriteVarInt32(PacketLen);
	AString LengthData;
	m_OutPacketLenBuffer.ReadAll(LengthData);
	SendData(LengthData.data(), LengthData.size());

	// Send the packet's payload
	m_OutPacketLenBuffer.CommitRead();
	SendData(PacketData.data(), PacketData.size());
}





UInt32 cProtocolRecognizer::GetPacketID(ePacketType a_PacketType)
{
	switch (a_PacketType)
	{
		case pktDisconnectDuringLogin: return 0x00;
		case pktStatusResponse:        return 0x00;
		case pktPingResponse:          return 0x01;
		default:
		{
			ASSERT(!"cProtocolRecognizer::GetPacketID() called for an unhandled packet");
			return 0;
		}
	}
}





void cProtocolRecognizer::HandlePacketStatusRequest(void)
{
	cServer * Server = cRoot::Get()->GetServer();
	AString ServerDescription = Server->GetDescription();
	auto NumPlayers = static_cast<signed>(Server->GetNumPlayers());
	auto MaxPlayers = static_cast<signed>(Server->GetMaxPlayers());
	AString Favicon = Server->GetFaviconData();
	cRoot::Get()->GetPluginManager()->CallHookServerPing(*m_Client, ServerDescription, NumPlayers, MaxPlayers, Favicon);

	// Version:
	Json::Value Version;
	Version["name"] = "Cuberite " MCS_CLIENT_VERSIONS;
	Version["protocol"] = MCS_LATEST_PROTOCOL_VERSION;

	// Players:
	Json::Value Players;
	Players["online"] = NumPlayers;
	Players["max"] = MaxPlayers;
	// TODO: Add "sample"

	// Description:
	Json::Value Description;
	Description["text"] = ServerDescription.c_str();

	// Create the response:
	Json::Value ResponseValue;
	ResponseValue["version"] = Version;
	ResponseValue["players"] = Players;
	ResponseValue["description"] = Description;
	if (!Favicon.empty())
	{
		ResponseValue["favicon"] = Printf("data:image/png;base64,%s", Favicon.c_str());
	}

	AString Response = JsonUtils::WriteFastString(ResponseValue);

	cPacketizer Pkt(*this, pktStatusResponse);
	Pkt.WriteString(Response);
}





void cProtocolRecognizer::HandlePacketStatusPing()
{
	Int64 Timestamp;
	if (!m_Buffer.ReadBEInt64(Timestamp))
	{
		return;
	}

	cPacketizer Pkt(*this, pktPingResponse);
	Pkt.WriteBEInt64(Timestamp);
}