Cuberite
A lightweight, fast and extensible game server for Minecraft
Protocol_1_9.cpp
Go to the documentation of this file.
1 
2 // Protocol_1_9.cpp
3 
4 /*
5 Implements the 1.9 protocol classes:
6  - cProtocol_1_9_0
7  - release 1.9 protocol (#107)
8  - cProtocol_1_9_1
9  - release 1.9.1 protocol (#108)
10  - cProtocol_1_9_2
11  - release 1.9.2 protocol (#109)
12  - cProtocol_1_9_4
13  - release 1.9.4 protocol (#110)
14 */
15 
16 #include "Globals.h"
17 #include "json/json.h"
18 #include "Protocol_1_9.h"
19 #include "ChunkDataSerializer.h"
20 #include "../mbedTLS++/Sha1Checksum.h"
21 #include "Packetizer.h"
22 
23 #include "../ClientHandle.h"
24 #include "../Root.h"
25 #include "../Server.h"
26 #include "../World.h"
27 #include "../StringCompression.h"
28 #include "../CompositeChat.h"
29 #include "../Statistics.h"
30 
31 #include "../WorldStorage/FastNBT.h"
32 
33 #include "../Entities/ExpOrb.h"
34 #include "../Entities/Minecart.h"
35 #include "../Entities/FallingBlock.h"
36 #include "../Entities/Painting.h"
37 #include "../Entities/Pickup.h"
38 #include "../Entities/Player.h"
39 #include "../Entities/ItemFrame.h"
40 #include "../Entities/ArrowEntity.h"
41 #include "../Entities/FireworkEntity.h"
42 #include "../Entities/SplashPotionEntity.h"
43 
44 #include "../Items/ItemSpawnEgg.h"
45 
46 #include "../Mobs/IncludeAllMonsters.h"
47 #include "../UI/HorseWindow.h"
48 
49 #include "../BlockEntities/BeaconEntity.h"
50 #include "../BlockEntities/CommandBlockEntity.h"
51 #include "../BlockEntities/MobHeadEntity.h"
52 #include "../BlockEntities/MobSpawnerEntity.h"
53 #include "../BlockEntities/FlowerPotEntity.h"
54 #include "../Bindings/PluginManager.h"
55 
56 
57 
58 
59 
61 static const Int16 SLOT_NUM_OUTSIDE = -999;
62 
64 static const UInt32 MAIN_HAND = 0;
65 static const UInt32 OFF_HAND = 1;
66 
67 
68 
69 
70 
71 #define HANDLE_READ(ByteBuf, Proc, Type, Var) \
72  Type Var; \
73  do { \
74  if (!ByteBuf.Proc(Var))\
75  {\
76  return;\
77  } \
78  } while (false)
79 
80 
81 
82 
83 
84 #define HANDLE_PACKET_READ(ByteBuf, Proc, Type, Var) \
85  Type Var; \
86  do { \
87  { \
88  if (!ByteBuf.Proc(Var)) \
89  { \
90  ByteBuf.CheckValid(); \
91  return false; \
92  } \
93  ByteBuf.CheckValid(); \
94  } \
95  } while (false)
96 
97 
98 
99 
100 
101 const int MAX_ENC_LEN = 512; // Maximum size of the encrypted message; should be 128, but who knows...
102 const uLongf MAX_COMPRESSED_PACKET_LEN = 200 KiB; // Maximum size of compressed packets.
103 
104 
105 
106 
107 
108 // fwd: main.cpp:
110 
111 
112 
113 
114 
116 // cProtocol_1_9_0:
117 
118 cProtocol_1_9_0::cProtocol_1_9_0(cClientHandle * a_Client, const AString & a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State) :
119  Super(a_Client),
120  m_ServerAddress(a_ServerAddress),
121  m_ServerPort(a_ServerPort),
122  m_State(a_State),
123  m_IsTeleportIdConfirmed(true),
124  m_OutstandingTeleportId(0),
125  m_ReceivedData(32 KiB),
126  m_IsEncrypted(false)
127 {
128 
129  AStringVector Params;
130  SplitZeroTerminatedStrings(a_ServerAddress, Params);
131 
132  if (Params.size() >= 2)
133  {
134  m_ServerAddress = Params[0];
135 
136  if (Params[1] == "FML")
137  {
138  LOGD("Forge client connected!");
140  }
141  else if (Params.size() == 4)
142  {
144  {
145  // BungeeCord handling:
146  // If BC is setup with ip_forward == true, it sends additional data in the login packet's ServerAddress field:
147  // hostname\00ip-address\00uuid\00profile-properties-as-json
148 
149  LOGD("Player at %s connected via BungeeCord", Params[1].c_str());
150 
151  m_Client->SetIPString(Params[1]);
152 
153  cUUID UUID;
154  UUID.FromString(Params[2]);
155  m_Client->SetUUID(UUID);
156 
157  Json::Value root;
158  Json::Reader reader;
159  if (!reader.parse(Params[3], root))
160  {
161  LOGERROR("Unable to parse player properties: '%s'", Params[3]);
162  }
163  else
164  {
165  m_Client->SetProperties(root);
166  }
167  }
168  else
169  {
170  LOG("BungeeCord is disabled, but client sent additional data, set AllowBungeeCord=1 if you want to allow it");
171  }
172  }
173  else
174  {
175  LOG("Unknown additional data sent in server address (BungeeCord/FML?): %zu parameters", Params.size());
176  // TODO: support FML + BungeeCord? (what parameters does it send in that case?) https://github.com/SpigotMC/BungeeCord/issues/899
177  }
178  }
179 
180  // Create the comm log file, if so requested:
182  {
183  static int sCounter = 0;
184  cFile::CreateFolder("CommLogs");
185  AString IP(a_Client->GetIPString());
186  ReplaceString(IP, ":", "_");
187  AString FileName = Printf("CommLogs/%x_%d__%s.log",
188  static_cast<unsigned>(time(nullptr)),
189  sCounter++,
190  IP.c_str()
191  );
192  if (!m_CommLogFile.Open(FileName, cFile::fmWrite))
193  {
194  LOG("Cannot log communication to file, the log file \"%s\" cannot be opened for writing.", FileName.c_str());
195  }
196  }
197 }
198 
199 
200 
201 
202 
203 void cProtocol_1_9_0::DataReceived(const char * a_Data, size_t a_Size)
204 {
205  if (m_IsEncrypted)
206  {
207  Byte Decrypted[512];
208  while (a_Size > 0)
209  {
210  size_t NumBytes = (a_Size > sizeof(Decrypted)) ? sizeof(Decrypted) : a_Size;
211  m_Decryptor.ProcessData(Decrypted, reinterpret_cast<const Byte *>(a_Data), NumBytes);
212  AddReceivedData(reinterpret_cast<const char *>(Decrypted), NumBytes);
213  a_Size -= NumBytes;
214  a_Data += NumBytes;
215  }
216  }
217  else
218  {
219  AddReceivedData(a_Data, a_Size);
220  }
221 }
222 
223 
224 
225 
226 
227 void cProtocol_1_9_0::SendAttachEntity(const cEntity & a_Entity, const cEntity & a_Vehicle)
228 {
229  ASSERT(m_State == 3); // In game mode?
230  cPacketizer Pkt(*this, pktAttachEntity);
231  Pkt.WriteVarInt32(a_Vehicle.GetUniqueID());
232  Pkt.WriteVarInt32(1); // 1 passenger
233  Pkt.WriteVarInt32(a_Entity.GetUniqueID());
234 }
235 
236 
237 
238 
239 
240 void cProtocol_1_9_0::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType)
241 {
242  ASSERT(m_State == 3); // In game mode?
243 
244  cPacketizer Pkt(*this, pktBlockAction);
245  Pkt.WritePosition64(a_BlockX, a_BlockY, a_BlockZ);
246  Pkt.WriteBEInt8(a_Byte1);
247  Pkt.WriteBEInt8(a_Byte2);
248  Pkt.WriteVarInt32(a_BlockType);
249 }
250 
251 
252 
253 
254 
255 void cProtocol_1_9_0::SendBlockBreakAnim(UInt32 a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage)
256 {
257  ASSERT(m_State == 3); // In game mode?
258 
259  cPacketizer Pkt(*this, pktBlockBreakAnim);
260  Pkt.WriteVarInt32(a_EntityID);
261  Pkt.WritePosition64(a_BlockX, a_BlockY, a_BlockZ);
262  Pkt.WriteBEInt8(a_Stage);
263 }
264 
265 
266 
267 
268 
269 void cProtocol_1_9_0::SendBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
270 {
271  ASSERT(m_State == 3); // In game mode?
272 
273  cPacketizer Pkt(*this, pktBlockChange);
274  Pkt.WritePosition64(a_BlockX, a_BlockY, a_BlockZ);
275  Pkt.WriteVarInt32((static_cast<UInt32>(a_BlockType) << 4) | (static_cast<UInt32>(a_BlockMeta) & 15));
276 }
277 
278 
279 
280 
281 
282 void cProtocol_1_9_0::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes)
283 {
284  ASSERT(m_State == 3); // In game mode?
285 
286  cPacketizer Pkt(*this, pktBlockChanges);
287  Pkt.WriteBEInt32(a_ChunkX);
288  Pkt.WriteBEInt32(a_ChunkZ);
289  Pkt.WriteVarInt32(static_cast<UInt32>(a_Changes.size()));
290  for (sSetBlockVector::const_iterator itr = a_Changes.begin(), end = a_Changes.end(); itr != end; ++itr)
291  {
292  Int16 Coords = static_cast<Int16>(itr->m_RelY | (itr->m_RelZ << 8) | (itr->m_RelX << 12));
293  Pkt.WriteBEInt16(Coords);
294  Pkt.WriteVarInt32(static_cast<UInt32>(itr->m_BlockType & 0xFFF) << 4 | (itr->m_BlockMeta & 0xF));
295  } // for itr - a_Changes[]
296 }
297 
298 
299 
300 
301 
303 {
304  cPacketizer Pkt(*this, pktCameraSetTo);
305  Pkt.WriteVarInt32(a_Entity.GetUniqueID());
306 }
307 
308 
309 
310 
311 
312 void cProtocol_1_9_0::SendChat(const AString & a_Message, eChatType a_Type)
313 {
314  ASSERT(m_State == 3); // In game mode?
315 
316  SendChatRaw(Printf("{\"text\":\"%s\"}", EscapeString(a_Message).c_str()), a_Type);
317 }
318 
319 
320 
321 
322 
323 void cProtocol_1_9_0::SendChat(const cCompositeChat & a_Message, eChatType a_Type, bool a_ShouldUseChatPrefixes)
324 {
325  ASSERT(m_State == 3); // In game mode?
326 
327  SendChatRaw(a_Message.CreateJsonString(a_ShouldUseChatPrefixes), a_Type);
328 }
329 
330 
331 
332 
333 
334 void cProtocol_1_9_0::SendChatRaw(const AString & a_MessageRaw, eChatType a_Type)
335 {
336  ASSERT(m_State == 3); // In game mode?
337 
338  // Send the json string to the client:
339  cPacketizer Pkt(*this, pktChatRaw);
340  Pkt.WriteString(a_MessageRaw);
341  Pkt.WriteBEInt8(a_Type);
342 }
343 
344 
345 
346 
347 
348 void cProtocol_1_9_0::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer)
349 {
350  ASSERT(m_State == 3); // In game mode?
351 
352  // Serialize first, before creating the Packetizer (the packetizer locks a CS)
353  // This contains the flags and bitmasks, too
354  const AString & ChunkData = a_Serializer.Serialize(cChunkDataSerializer::RELEASE_1_9_0, a_ChunkX, a_ChunkZ, {});
355 
356  cCSLock Lock(m_CSPacket);
357  SendData(ChunkData.data(), ChunkData.size());
358 }
359 
360 
361 
362 
363 
364 void cProtocol_1_9_0::SendCollectEntity(const cEntity & a_Entity, const cPlayer & a_Player, int a_Count)
365 {
366  UNUSED(a_Count);
367  ASSERT(m_State == 3); // In game mode?
368 
369  cPacketizer Pkt(*this, pktCollectEntity);
370  Pkt.WriteVarInt32(a_Entity.GetUniqueID());
371  Pkt.WriteVarInt32(a_Player.GetUniqueID());
372 }
373 
374 
375 
376 
377 
379 {
380  ASSERT(m_State == 3); // In game mode?
381 
382  cPacketizer Pkt(*this, pktDestroyEntity);
383  Pkt.WriteVarInt32(1);
384  Pkt.WriteVarInt32(a_Entity.GetUniqueID());
385 }
386 
387 
388 
389 
390 
391 void cProtocol_1_9_0::SendDetachEntity(const cEntity & a_Entity, const cEntity & a_PreviousVehicle)
392 {
393  ASSERT(m_State == 3); // In game mode?
394  cPacketizer Pkt(*this, pktAttachEntity);
395  Pkt.WriteVarInt32(a_PreviousVehicle.GetUniqueID());
396  Pkt.WriteVarInt32(0); // No passangers
397 }
398 
399 
400 
401 
402 
404 {
405  switch (m_State)
406  {
407  case 2:
408  {
409  // During login:
411  Pkt.WriteString(Printf("{\"text\":\"%s\"}", EscapeString(a_Reason).c_str()));
412  break;
413  }
414  case 3:
415  {
416  // In-game:
418  Pkt.WriteString(Printf("{\"text\":\"%s\"}", EscapeString(a_Reason).c_str()));
419  break;
420  }
421  }
422 }
423 
424 
425 
426 
427 
428 void cProtocol_1_9_0::SendEditSign(int a_BlockX, int a_BlockY, int a_BlockZ)
429 {
430  ASSERT(m_State == 3); // In game mode?
431 
432  cPacketizer Pkt(*this, pktEditSign);
433  Pkt.WritePosition64(a_BlockX, a_BlockY, a_BlockZ);
434 }
435 
436 
437 
438 
439 
440 void cProtocol_1_9_0::SendEntityEffect(const cEntity & a_Entity, int a_EffectID, int a_Amplifier, int a_Duration)
441 {
442  ASSERT(m_State == 3); // In game mode?
443 
444  cPacketizer Pkt(*this, pktEntityEffect);
445  Pkt.WriteVarInt32(a_Entity.GetUniqueID());
446  Pkt.WriteBEUInt8(static_cast<UInt8>(a_EffectID));
447  Pkt.WriteBEUInt8(static_cast<UInt8>(a_Amplifier));
448  Pkt.WriteVarInt32(static_cast<UInt32>(a_Duration));
449  Pkt.WriteBool(false); // Hide particles
450 }
451 
452 
453 
454 
455 
456 void cProtocol_1_9_0::SendEntityEquipment(const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item)
457 {
458  ASSERT(m_State == 3); // In game mode?
459 
460  cPacketizer Pkt(*this, pktEntityEquipment);
461  Pkt.WriteVarInt32(a_Entity.GetUniqueID());
462  // Needs to be adjusted due to the insertion of offhand at slot 1
463  if (a_SlotNum > 0)
464  {
465  a_SlotNum++;
466  }
467  Pkt.WriteVarInt32(static_cast<UInt32>(a_SlotNum));
468  WriteItem(Pkt, a_Item);
469 }
470 
471 
472 
473 
474 
476 {
477  ASSERT(m_State == 3); // In game mode?
478 
479  cPacketizer Pkt(*this, pktEntityHeadLook);
480  Pkt.WriteVarInt32(a_Entity.GetUniqueID());
481  Pkt.WriteByteAngle(a_Entity.GetHeadYaw());
482 }
483 
484 
485 
486 
487 
489 {
490  ASSERT(m_State == 3); // In game mode?
491 
492  cPacketizer Pkt(*this, pktEntityLook);
493  Pkt.WriteVarInt32(a_Entity.GetUniqueID());
494  Pkt.WriteByteAngle(a_Entity.GetYaw());
495  Pkt.WriteByteAngle(a_Entity.GetPitch());
496  Pkt.WriteBool(a_Entity.IsOnGround());
497 }
498 
499 
500 
501 
502 
504 {
505  ASSERT(m_State == 3); // In game mode?
506 
507  cPacketizer Pkt(*this, pktEntityMeta);
508  Pkt.WriteVarInt32(a_Entity.GetUniqueID());
509  WriteEntityMetadata(Pkt, a_Entity);
510  Pkt.WriteBEUInt8(0xff); // The termination byte
511 }
512 
513 
514 
515 
516 
518 {
519  ASSERT(m_State == 3); // In game mode?
520 
521  cPacketizer Pkt(*this, pktEntityProperties);
522  Pkt.WriteVarInt32(a_Entity.GetUniqueID());
523  WriteEntityProperties(Pkt, a_Entity);
524 }
525 
526 
527 
528 
529 
530 void cProtocol_1_9_0::SendEntityRelMove(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ)
531 {
532  ASSERT(m_State == 3); // In game mode?
533 
534  cPacketizer Pkt(*this, pktEntityRelMove);
535  Pkt.WriteVarInt32(a_Entity.GetUniqueID());
536  // TODO: 1.9 changed these from chars to shorts, meaning that there can be more percision and data. Other code needs to be updated for that.
537  Pkt.WriteBEInt16(a_RelX * 128);
538  Pkt.WriteBEInt16(a_RelY * 128);
539  Pkt.WriteBEInt16(a_RelZ * 128);
540  Pkt.WriteBool(a_Entity.IsOnGround());
541 }
542 
543 
544 
545 
546 
547 void cProtocol_1_9_0::SendEntityRelMoveLook(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ)
548 {
549  ASSERT(m_State == 3); // In game mode?
550 
551  cPacketizer Pkt(*this, pktEntityRelMoveLook);
552  Pkt.WriteVarInt32(a_Entity.GetUniqueID());
553  // TODO: 1.9 changed these from chars to shorts, meaning that there can be more percision and data. Other code needs to be updated for that.
554  Pkt.WriteBEInt16(a_RelX * 128);
555  Pkt.WriteBEInt16(a_RelY * 128);
556  Pkt.WriteBEInt16(a_RelZ * 128);
557  Pkt.WriteByteAngle(a_Entity.GetYaw());
558  Pkt.WriteByteAngle(a_Entity.GetPitch());
559  Pkt.WriteBool(a_Entity.IsOnGround());
560 }
561 
562 
563 
564 
565 
566 void cProtocol_1_9_0::SendEntityStatus(const cEntity & a_Entity, char a_Status)
567 {
568  ASSERT(m_State == 3); // In game mode?
569 
570  cPacketizer Pkt(*this, pktEntityStatus);
571  Pkt.WriteBEUInt32(a_Entity.GetUniqueID());
572  Pkt.WriteBEInt8(a_Status);
573 }
574 
575 
576 
577 
578 
580 {
581  ASSERT(m_State == 3); // In game mode?
582 
583  cPacketizer Pkt(*this, pktEntityVelocity);
584  Pkt.WriteVarInt32(a_Entity.GetUniqueID());
585  // 400 = 8000 / 20 ... Conversion from our speed in m / s to 8000 m / tick
586  Pkt.WriteBEInt16(static_cast<Int16>(a_Entity.GetSpeedX() * 400));
587  Pkt.WriteBEInt16(static_cast<Int16>(a_Entity.GetSpeedY() * 400));
588  Pkt.WriteBEInt16(static_cast<Int16>(a_Entity.GetSpeedZ() * 400));
589 }
590 
591 
592 
593 
594 
596 {
597  ASSERT(m_State == 3); // In game mode?
598 
599  cPacketizer Pkt(*this, pktExperience);
600  cPlayer * Player = m_Client->GetPlayer();
601  Pkt.WriteBEFloat(Player->GetXpPercentage());
602  Pkt.WriteVarInt32(static_cast<UInt32>(Player->GetXpLevel()));
603  Pkt.WriteVarInt32(static_cast<UInt32>(Player->GetCurrentXp()));
604 }
605 
606 
607 
608 
609 
611 {
612  ASSERT(m_State == 3); // In game mode?
613 
615  Pkt.WriteVarInt32(a_ExpOrb.GetUniqueID());
616  Pkt.WriteBEDouble(a_ExpOrb.GetPosX());
617  Pkt.WriteBEDouble(a_ExpOrb.GetPosY());
618  Pkt.WriteBEDouble(a_ExpOrb.GetPosZ());
619  Pkt.WriteBEInt16(static_cast<Int16>(a_ExpOrb.GetReward()));
620 }
621 
622 
623 
624 
625 
626 void cProtocol_1_9_0::SendExplosion(double a_BlockX, double a_BlockY, double a_BlockZ, float a_Radius, const cVector3iArray & a_BlocksAffected, const Vector3d & a_PlayerMotion)
627 {
628  ASSERT(m_State == 3); // In game mode?
629 
630  cPacketizer Pkt(*this, pktExplosion);
631  Pkt.WriteBEFloat(static_cast<float>(a_BlockX));
632  Pkt.WriteBEFloat(static_cast<float>(a_BlockY));
633  Pkt.WriteBEFloat(static_cast<float>(a_BlockZ));
634  Pkt.WriteBEFloat(static_cast<float>(a_Radius));
635  Pkt.WriteBEUInt32(static_cast<UInt32>(a_BlocksAffected.size()));
636  for (cVector3iArray::const_iterator itr = a_BlocksAffected.begin(), end = a_BlocksAffected.end(); itr != end; ++itr)
637  {
638  Pkt.WriteBEInt8(static_cast<Int8>(itr->x));
639  Pkt.WriteBEInt8(static_cast<Int8>(itr->y));
640  Pkt.WriteBEInt8(static_cast<Int8>(itr->z));
641  } // for itr - a_BlockAffected[]
642  Pkt.WriteBEFloat(static_cast<float>(a_PlayerMotion.x));
643  Pkt.WriteBEFloat(static_cast<float>(a_PlayerMotion.y));
644  Pkt.WriteBEFloat(static_cast<float>(a_PlayerMotion.z));
645 }
646 
647 
648 
649 
650 
652 {
653  ASSERT(m_State == 3); // In game mode?
654 
655  cPacketizer Pkt(*this, pktGameMode);
656  Pkt.WriteBEUInt8(3); // Reason: Change game mode
657  Pkt.WriteBEFloat(static_cast<float>(a_GameMode)); // The protocol really represents the value with a float!
658 }
659 
660 
661 
662 
663 
665 {
666  ASSERT(m_State == 3); // In game mode?
667 
668  cPacketizer Pkt(*this, pktUpdateHealth);
669  cPlayer * Player = m_Client->GetPlayer();
670  Pkt.WriteBEFloat(static_cast<float>(Player->GetHealth()));
671  Pkt.WriteVarInt32(static_cast<UInt32>(Player->GetFoodLevel()));
672  Pkt.WriteBEFloat(static_cast<float>(Player->GetFoodSaturationLevel()));
673 }
674 
675 
676 
677 
678 
680 {
681  ASSERT((a_ItemIndex >= 0) && (a_ItemIndex <= 8)); // Valid check
682 
683  cPacketizer Pkt(*this, pktHeldItemChange);
684  cPlayer * Player = m_Client->GetPlayer();
685  Pkt.WriteBEInt8(static_cast<Int8>(Player->GetInventory().GetEquippedSlotNum()));
686 }
687 
688 
689 
690 
691 
693 {
694  ASSERT(m_State == 3); // In game mode?
695 
696  cPacketizer Pkt(*this, pktTitle);
697  Pkt.WriteVarInt32(3); // Hide title
698 }
699 
700 
701 
702 
703 
704 void cProtocol_1_9_0::SendInventorySlot(char a_WindowID, short a_SlotNum, const cItem & a_Item)
705 {
706  ASSERT(m_State == 3); // In game mode?
707 
708  cPacketizer Pkt(*this, pktInventorySlot);
709  Pkt.WriteBEInt8(a_WindowID);
710  Pkt.WriteBEInt16(a_SlotNum);
711  WriteItem(Pkt, a_Item);
712 }
713 
714 
715 
716 
717 
719 {
720  // Drop the packet if the protocol is not in the Game state yet (caused a client crash):
721  if (m_State != 3)
722  {
723  LOG("Trying to send a KeepAlive packet to a player who's not yet fully logged in (%d). The protocol class prevented the packet.", m_State);
724  return;
725  }
726 
727  cPacketizer Pkt(*this, pktKeepAlive);
728  Pkt.WriteVarInt32(a_PingID);
729 }
730 
731 
732 
733 
734 
735 void cProtocol_1_9_0::SendLeashEntity(const cEntity & a_Entity, const cEntity & a_EntityLeashedTo)
736 {
737  ASSERT(m_State == 3); // In game mode?
738  cPacketizer Pkt(*this, pktLeashEntity);
739  Pkt.WriteBEUInt32(a_Entity.GetUniqueID());
740  Pkt.WriteBEUInt32(a_EntityLeashedTo.GetUniqueID());
741 }
742 
743 
744 
745 
746 
748 {
749  ASSERT(m_State == 3); // In game mode?
750  cPacketizer Pkt(*this, pktLeashEntity);
751  Pkt.WriteBEUInt32(a_Entity.GetUniqueID());
752  Pkt.WriteBEInt32(-1); // Unleash a_Entity
753 }
754 
755 
756 
757 
758 
759 void cProtocol_1_9_0::SendLogin(const cPlayer & a_Player, const cWorld & a_World)
760 {
761  // Send the Join Game packet:
762  {
763  cServer * Server = cRoot::Get()->GetServer();
764  cPacketizer Pkt(*this, pktJoinGame);
765  Pkt.WriteBEUInt32(a_Player.GetUniqueID());
766  Pkt.WriteBEUInt8(static_cast<UInt8>(a_Player.GetEffectiveGameMode()) | (Server->IsHardcore() ? 0x08 : 0)); // Hardcore flag bit 4
767  Pkt.WriteBEInt8(static_cast<Int8>(a_World.GetDimension()));
768  Pkt.WriteBEUInt8(2); // TODO: Difficulty (set to Normal)
769  Pkt.WriteBEUInt8(static_cast<UInt8>(Clamp<size_t>(Server->GetMaxPlayers(), 0, 255)));
770  Pkt.WriteString("default"); // Level type - wtf?
771  Pkt.WriteBool(false); // Reduced Debug Info - wtf?
772  }
773 
774  // Send the spawn position:
775  {
776  cPacketizer Pkt(*this, pktSpawnPosition);
777  Pkt.WritePosition64(FloorC(a_World.GetSpawnX()), FloorC(a_World.GetSpawnY()), FloorC(a_World.GetSpawnZ()));
778  }
779 
780  // Send the server difficulty:
781  {
782  cPacketizer Pkt(*this, pktDifficulty);
783  Pkt.WriteBEInt8(1);
784  }
785 
786  // Send player abilities:
788 }
789 
790 
791 
792 
793 
795 {
796  ASSERT(m_State == 2); // State: login?
797 
798  // Enable compression:
799  {
800  cPacketizer Pkt(*this, pktStartCompression);
801  Pkt.WriteVarInt32(256);
802  }
803 
804  m_State = 3; // State = Game
805 
806  {
807  cPacketizer Pkt(*this, pktLoginSuccess);
810  }
811 }
812 
813 
814 
815 
816 
818 {
819  ASSERT(m_State == 3); // In game mode?
820  double PosX = a_Painting.GetPosX();
821  double PosY = a_Painting.GetPosY();
822  double PosZ = a_Painting.GetPosZ();
823 
824  cPacketizer Pkt(*this, pktSpawnPainting);
825  Pkt.WriteVarInt32(a_Painting.GetUniqueID());
826  // TODO: Bad way to write a UUID, and it's not a true UUID, but this is functional for now.
827  Pkt.WriteBEUInt64(0);
828  Pkt.WriteBEUInt64(a_Painting.GetUniqueID());
829  Pkt.WriteString(a_Painting.GetName().c_str());
830  Pkt.WritePosition64(static_cast<Int32>(PosX), static_cast<Int32>(PosY), static_cast<Int32>(PosZ));
831  Pkt.WriteBEInt8(static_cast<Int8>(a_Painting.GetProtocolFacing()));
832 }
833 
834 
835 
836 
837 
838 void cProtocol_1_9_0::SendMapData(const cMap & a_Map, int a_DataStartX, int a_DataStartY)
839 {
840  ASSERT(m_State == 3); // In game mode?
841 
842  cPacketizer Pkt(*this, pktMapData);
843  Pkt.WriteVarInt32(a_Map.GetID());
844  Pkt.WriteBEUInt8(static_cast<UInt8>(a_Map.GetScale()));
845 
846  Pkt.WriteBool(true);
847  Pkt.WriteVarInt32(static_cast<UInt32>(a_Map.GetDecorators().size()));
848  for (const auto & Decorator : a_Map.GetDecorators())
849  {
850  Pkt.WriteBEUInt8(static_cast<Byte>((static_cast<Int32>(Decorator.GetType()) << 4) | (Decorator.GetRot() & 0xF)));
851  Pkt.WriteBEUInt8(static_cast<UInt8>(Decorator.GetPixelX()));
852  Pkt.WriteBEUInt8(static_cast<UInt8>(Decorator.GetPixelZ()));
853  }
854 
855  Pkt.WriteBEUInt8(128);
856  Pkt.WriteBEUInt8(128);
857  Pkt.WriteBEUInt8(static_cast<UInt8>(a_DataStartX));
858  Pkt.WriteBEUInt8(static_cast<UInt8>(a_DataStartY));
859  Pkt.WriteVarInt32(static_cast<UInt32>(a_Map.GetData().size()));
860  for (auto itr = a_Map.GetData().cbegin(); itr != a_Map.GetData().cend(); ++itr)
861  {
862  Pkt.WriteBEUInt8(*itr);
863  }
864 }
865 
866 
867 
868 
869 
871 {
872  ASSERT(m_State == 3); // In game mode?
873 
874  { // TODO Use SendSpawnObject
875  cPacketizer Pkt(*this, pktSpawnObject);
876  Pkt.WriteVarInt32(a_Pickup.GetUniqueID());
877  // TODO: Bad way to write a UUID, and it's not a true UUID, but this is functional for now.
878  Pkt.WriteBEUInt64(0);
879  Pkt.WriteBEUInt64(a_Pickup.GetUniqueID());
880  Pkt.WriteBEUInt8(2); // Type = Pickup
881  Pkt.WriteBEDouble(a_Pickup.GetPosX());
882  Pkt.WriteBEDouble(a_Pickup.GetPosY());
883  Pkt.WriteBEDouble(a_Pickup.GetPosZ());
884  Pkt.WriteByteAngle(a_Pickup.GetYaw());
885  Pkt.WriteByteAngle(a_Pickup.GetPitch());
886  Pkt.WriteBEInt32(0); // No object data
887  Pkt.WriteBEInt16(0); // No velocity
888  Pkt.WriteBEInt16(0);
889  Pkt.WriteBEInt16(0);
890  }
891 
892  SendEntityMetadata(a_Pickup);
893 }
894 
895 
896 
897 
898 
900 {
901  ASSERT(m_State == 3); // In game mode?
902 
903  cPacketizer Pkt(*this, pktPlayerAbilities);
904  Byte Flags = 0;
905  cPlayer * Player = m_Client->GetPlayer();
906  if (Player->IsGameModeCreative())
907  {
908  Flags |= 0x01;
909  Flags |= 0x08; // Godmode, used for creative
910  }
911  if (Player->IsFlying())
912  {
913  Flags |= 0x02;
914  }
915  if (Player->CanFly())
916  {
917  Flags |= 0x04;
918  }
919  Pkt.WriteBEUInt8(Flags);
920  Pkt.WriteBEFloat(static_cast<float>(0.05 * Player->GetFlyingMaxSpeed()));
921  Pkt.WriteBEFloat(static_cast<float>(0.1 * Player->GetNormalMaxSpeed()));
922 }
923 
924 
925 
926 
927 
928 void cProtocol_1_9_0::SendEntityAnimation(const cEntity & a_Entity, char a_Animation)
929 {
930  ASSERT(m_State == 3); // In game mode?
931 
932  cPacketizer Pkt(*this, pktEntityAnimation);
933  Pkt.WriteVarInt32(a_Entity.GetUniqueID());
934  Pkt.WriteBEInt8(a_Animation);
935 }
936 
937 
938 
939 
940 
941 void cProtocol_1_9_0::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)
942 {
943  ASSERT(m_State == 3); // In game mode?
944  int ParticleID = GetParticleID(a_ParticleName);
945 
946  cPacketizer Pkt(*this, pktParticleEffect);
947  Pkt.WriteBEInt32(ParticleID);
948  Pkt.WriteBool(false);
949  Pkt.WriteBEFloat(a_SrcX);
950  Pkt.WriteBEFloat(a_SrcY);
951  Pkt.WriteBEFloat(a_SrcZ);
952  Pkt.WriteBEFloat(a_OffsetX);
953  Pkt.WriteBEFloat(a_OffsetY);
954  Pkt.WriteBEFloat(a_OffsetZ);
955  Pkt.WriteBEFloat(a_ParticleData);
956  Pkt.WriteBEInt32(a_ParticleAmount);
957 }
958 
959 
960 
961 
962 
963 void cProtocol_1_9_0::SendParticleEffect(const AString & a_ParticleName, Vector3f a_Src, Vector3f a_Offset, float a_ParticleData, int a_ParticleAmount, std::array<int, 2> a_Data)
964 {
965  ASSERT(m_State == 3); // In game mode?
966  int ParticleID = GetParticleID(a_ParticleName);
967 
968  cPacketizer Pkt(*this, pktParticleEffect);
969  Pkt.WriteBEInt32(ParticleID);
970  Pkt.WriteBool(false);
971  Pkt.WriteBEFloat(a_Src.x);
972  Pkt.WriteBEFloat(a_Src.y);
973  Pkt.WriteBEFloat(a_Src.z);
974  Pkt.WriteBEFloat(a_Offset.x);
975  Pkt.WriteBEFloat(a_Offset.y);
976  Pkt.WriteBEFloat(a_Offset.z);
977  Pkt.WriteBEFloat(a_ParticleData);
978  Pkt.WriteBEInt32(a_ParticleAmount);
979  switch (ParticleID)
980  {
981  // iconcrack
982  case 36:
983  {
984  Pkt.WriteVarInt32(static_cast<UInt32>(a_Data[0]));
985  Pkt.WriteVarInt32(static_cast<UInt32>(a_Data[1]));
986  break;
987  }
988  // blockcrack
989  // blockdust
990  case 37:
991  case 38:
992  {
993  Pkt.WriteVarInt32(static_cast<UInt32>(a_Data[0]));
994  break;
995  }
996  default:
997  {
998  break;
999  }
1000  }
1001 }
1002 
1003 
1004 
1005 
1006 
1008 {
1009  ASSERT(m_State == 3); // In game mode?
1010 
1011  cPacketizer Pkt(*this, pktPlayerList);
1012  Pkt.WriteVarInt32(0);
1013  Pkt.WriteVarInt32(1);
1014  Pkt.WriteUUID(a_Player.GetUUID());
1015  Pkt.WriteString(a_Player.GetPlayerListName());
1016 
1017  const Json::Value & Properties = a_Player.GetClientHandle()->GetProperties();
1018  Pkt.WriteVarInt32(Properties.size());
1019  for (auto & Node : Properties)
1020  {
1021  Pkt.WriteString(Node.get("name", "").asString());
1022  Pkt.WriteString(Node.get("value", "").asString());
1023  AString Signature = Node.get("signature", "").asString();
1024  if (Signature.empty())
1025  {
1026  Pkt.WriteBool(false);
1027  }
1028  else
1029  {
1030  Pkt.WriteBool(true);
1031  Pkt.WriteString(Signature);
1032  }
1033  }
1034 
1035  Pkt.WriteVarInt32(static_cast<UInt32>(a_Player.GetEffectiveGameMode()));
1036  Pkt.WriteVarInt32(static_cast<UInt32>(a_Player.GetClientHandle()->GetPing()));
1037  Pkt.WriteBool(false);
1038 }
1039 
1040 
1041 
1042 
1043 
1045 {
1046  ASSERT(m_State == 3); // In game mode?
1047 
1048  cPacketizer Pkt(*this, pktPlayerList);
1049  Pkt.WriteVarInt32(4);
1050  Pkt.WriteVarInt32(1);
1051  Pkt.WriteUUID(a_Player.GetUUID());
1052 }
1053 
1054 
1055 
1056 
1057 
1059 {
1060  ASSERT(m_State == 3); // In game mode?
1061 
1062  cPacketizer Pkt(*this, pktPlayerList);
1063  Pkt.WriteVarInt32(1);
1064  Pkt.WriteVarInt32(1);
1065  Pkt.WriteUUID(a_Player.GetUUID());
1066  Pkt.WriteVarInt32(static_cast<UInt32>(a_Player.GetEffectiveGameMode()));
1067 }
1068 
1069 
1070 
1071 
1072 
1074 {
1075  ASSERT(m_State == 3); // In game mode?
1076 
1077  auto ClientHandle = a_Player.GetClientHandlePtr();
1078  if (ClientHandle != nullptr)
1079  {
1080  cPacketizer Pkt(*this, pktPlayerList);
1081  Pkt.WriteVarInt32(2);
1082  Pkt.WriteVarInt32(1);
1083  Pkt.WriteUUID(a_Player.GetUUID());
1084  Pkt.WriteVarInt32(static_cast<UInt32>(ClientHandle->GetPing()));
1085  }
1086 }
1087 
1088 
1089 
1090 
1091 
1092 void cProtocol_1_9_0::SendPlayerListUpdateDisplayName(const cPlayer & a_Player, const AString & a_CustomName)
1093 {
1094  ASSERT(m_State == 3); // In game mode?
1095 
1096  cPacketizer Pkt(*this, pktPlayerList);
1097  Pkt.WriteVarInt32(3);
1098  Pkt.WriteVarInt32(1);
1099  Pkt.WriteUUID(a_Player.GetUUID());
1100 
1101  if (a_CustomName.empty())
1102  {
1103  Pkt.WriteBool(false);
1104  }
1105  else
1106  {
1107  Pkt.WriteBool(true);
1108  Pkt.WriteString(Printf("{\"text\":\"%s\"}", a_CustomName.c_str()));
1109  }
1110 }
1111 
1112 
1113 
1114 
1115 
1117 {
1118  ASSERT(m_State == 3); // In game mode?
1119 
1120  cPacketizer Pkt(*this, pktPlayerMaxSpeed);
1121  cPlayer * Player = m_Client->GetPlayer();
1122  Pkt.WriteVarInt32(Player->GetUniqueID());
1123  Pkt.WriteBEInt32(1); // Count
1124  Pkt.WriteString("generic.movementSpeed");
1125  // The default game speed is 0.1, multiply that value by the relative speed:
1126  Pkt.WriteBEDouble(0.1 * Player->GetNormalMaxSpeed());
1127  if (Player->IsSprinting())
1128  {
1129  Pkt.WriteVarInt32(1); // Modifier count
1130  Pkt.WriteBEUInt64(0x662a6b8dda3e4c1c);
1131  Pkt.WriteBEUInt64(0x881396ea6097278d); // UUID of the modifier
1132  Pkt.WriteBEDouble(Player->GetSprintingMaxSpeed() - Player->GetNormalMaxSpeed());
1133  Pkt.WriteBEUInt8(2);
1134  }
1135  else
1136  {
1137  Pkt.WriteVarInt32(0); // Modifier count
1138  }
1139 }
1140 
1141 
1142 
1143 
1144 
1146 {
1147  ASSERT(m_State == 3); // In game mode?
1148 
1149  cPacketizer Pkt(*this, pktPlayerMoveLook);
1150  cPlayer * Player = m_Client->GetPlayer();
1151  Pkt.WriteBEDouble(Player->GetPosX());
1152  Pkt.WriteBEDouble(Player->GetPosY());
1153  Pkt.WriteBEDouble(Player->GetPosZ());
1154  Pkt.WriteBEFloat(static_cast<float>(Player->GetYaw()));
1155  Pkt.WriteBEFloat(static_cast<float>(Player->GetPitch()));
1156  Pkt.WriteBEUInt8(0);
1158 
1159  // This teleport ID hasn't been confirmed yet
1160  m_IsTeleportIdConfirmed = false;
1161 }
1162 
1163 
1164 
1165 
1166 
1168 {
1169  // There is no dedicated packet for this, send the whole thing:
1171 }
1172 
1173 
1174 
1175 
1176 
1178 {
1179  // Called to spawn another player for the client
1180  cPacketizer Pkt(*this, pktSpawnOtherPlayer);
1181  Pkt.WriteVarInt32(a_Player.GetUniqueID());
1182  Pkt.WriteUUID(a_Player.GetUUID());
1183  Vector3d LastSentPos = a_Player.GetLastSentPos();
1184  Pkt.WriteBEDouble(LastSentPos.x);
1185  Pkt.WriteBEDouble(LastSentPos.y + 0.001); // The "+ 0.001" is there because otherwise the player falls through the block they were standing on.
1186  Pkt.WriteBEDouble(LastSentPos.z);
1187  Pkt.WriteByteAngle(a_Player.GetYaw());
1188  Pkt.WriteByteAngle(a_Player.GetPitch());
1189  WriteEntityMetadata(Pkt, a_Player);
1190  Pkt.WriteBEUInt8(0xff); // Metadata: end
1191 }
1192 
1193 
1194 
1195 
1196 
1197 void cProtocol_1_9_0::SendPluginMessage(const AString & a_Channel, const AString & a_Message)
1198 {
1199  ASSERT(m_State == 3); // In game mode?
1200 
1201  cPacketizer Pkt(*this, pktPluginMessage);
1202  Pkt.WriteString(a_Channel);
1203  Pkt.WriteBuf(a_Message.data(), a_Message.size());
1204 }
1205 
1206 
1207 
1208 
1209 
1210 void cProtocol_1_9_0::SendRemoveEntityEffect(const cEntity & a_Entity, int a_EffectID)
1211 {
1212  ASSERT(m_State == 3); // In game mode?
1213 
1214  cPacketizer Pkt(*this, pktRemoveEntityEffect);
1215  Pkt.WriteVarInt32(a_Entity.GetUniqueID());
1216  Pkt.WriteBEUInt8(static_cast<UInt8>(a_EffectID));
1217 }
1218 
1219 
1220 
1221 
1222 
1224 {
1225  ASSERT(m_State == 3); // In game mode?
1226 
1227  cPacketizer Pkt(*this, pktTitle);
1228  Pkt.WriteVarInt32(4); // Reset title
1229 }
1230 
1231 
1232 
1233 
1234 
1236 {
1237  cPacketizer Pkt(*this, pktRespawn);
1238  cPlayer * Player = m_Client->GetPlayer();
1239  Pkt.WriteBEInt32(static_cast<Int32>(a_Dimension));
1240  Pkt.WriteBEUInt8(2); // TODO: Difficulty (set to Normal)
1241  Pkt.WriteBEUInt8(static_cast<Byte>(Player->GetEffectiveGameMode()));
1242  Pkt.WriteString("default");
1243 }
1244 
1245 
1246 
1247 
1248 
1249 void cProtocol_1_9_0::SendScoreboardObjective(const AString & a_Name, const AString & a_DisplayName, Byte a_Mode)
1250 {
1251  ASSERT(m_State == 3); // In game mode?
1252 
1253  cPacketizer Pkt(*this, pktScoreboardObjective);
1254  Pkt.WriteString(a_Name);
1255  Pkt.WriteBEUInt8(a_Mode);
1256  if ((a_Mode == 0) || (a_Mode == 2))
1257  {
1258  Pkt.WriteString(a_DisplayName);
1259  Pkt.WriteString("integer");
1260  }
1261 }
1262 
1263 
1264 
1265 
1266 
1267 void cProtocol_1_9_0::SendScoreUpdate(const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode)
1268 {
1269  ASSERT(m_State == 3); // In game mode?
1270 
1271  cPacketizer Pkt(*this, pktUpdateScore);
1272  Pkt.WriteString(a_Player);
1273  Pkt.WriteBEUInt8(a_Mode);
1274  Pkt.WriteString(a_Objective);
1275 
1276  if (a_Mode != 1)
1277  {
1278  Pkt.WriteVarInt32(static_cast<UInt32>(a_Score));
1279  }
1280 }
1281 
1282 
1283 
1284 
1285 
1287 {
1288  ASSERT(m_State == 3); // In game mode?
1289 
1290  cPacketizer Pkt(*this, pktDisplayObjective);
1291  Pkt.WriteBEUInt8(static_cast<UInt8>(a_Display));
1292  Pkt.WriteString(a_Objective);
1293 }
1294 
1295 
1296 
1297 
1298 
1300 {
1301  SendSetRawSubTitle(a_SubTitle.CreateJsonString(false));
1302 }
1303 
1304 
1305 
1306 
1307 
1309 {
1310  ASSERT(m_State == 3); // In game mode?
1311 
1312  cPacketizer Pkt(*this, pktTitle);
1313  Pkt.WriteVarInt32(1); // Set subtitle
1314  Pkt.WriteString(a_SubTitle);
1315 }
1316 
1317 
1318 
1319 
1320 
1322 {
1323  SendSetRawTitle(a_Title.CreateJsonString(false));
1324 }
1325 
1326 
1327 
1328 
1329 
1331 {
1332  ASSERT(m_State == 3); // In game mode?
1333 
1334  cPacketizer Pkt(*this, pktTitle);
1335  Pkt.WriteVarInt32(0); // Set title
1336  Pkt.WriteString(a_Title);
1337 }
1338 
1339 
1340 
1341 
1342 
1343 void cProtocol_1_9_0::SendSoundEffect(const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch)
1344 {
1345  ASSERT(m_State == 3); // In game mode?
1346 
1347  cPacketizer Pkt(*this, pktSoundEffect);
1348  Pkt.WriteString(a_SoundName);
1349  Pkt.WriteVarInt32(0); // Master sound category (may want to be changed to a parameter later)
1350  Pkt.WriteBEInt32(static_cast<Int32>(a_X * 8.0));
1351  Pkt.WriteBEInt32(static_cast<Int32>(a_Y * 8.0));
1352  Pkt.WriteBEInt32(static_cast<Int32>(a_Z * 8.0));
1353  Pkt.WriteBEFloat(a_Volume);
1354  Pkt.WriteBEUInt8(static_cast<Byte>(a_Pitch * 63));
1355 }
1356 
1357 
1358 
1359 
1360 
1361 void cProtocol_1_9_0::SendSoundParticleEffect(const EffectID a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data)
1362 {
1363  ASSERT(m_State == 3); // In game mode?
1364 
1365  cPacketizer Pkt(*this, pktSoundParticleEffect);
1366  Pkt.WriteBEInt32(static_cast<int>(a_EffectID));
1367  Pkt.WritePosition64(a_SrcX, a_SrcY, a_SrcZ);
1368  Pkt.WriteBEInt32(a_Data);
1369  Pkt.WriteBool(false);
1370 }
1371 
1372 
1373 
1374 
1375 
1377 {
1378  ASSERT(m_State == 3); // In game mode?
1379 
1380  cPacketizer Pkt(*this, pktSpawnObject);
1381  Pkt.WriteVarInt32(a_FallingBlock.GetUniqueID());
1382  // TODO: Bad way to write a UUID, and it's not a true UUID, but this is functional for now.
1383  Pkt.WriteBEUInt64(0);
1384  Pkt.WriteBEUInt64(a_FallingBlock.GetUniqueID());
1385  Pkt.WriteBEUInt8(70); // Falling block
1386  Vector3d LastSentPos = a_FallingBlock.GetLastSentPos();
1387  Pkt.WriteBEDouble(LastSentPos.x);
1388  Pkt.WriteBEDouble(LastSentPos.y);
1389  Pkt.WriteBEDouble(LastSentPos.z);
1390  Pkt.WriteByteAngle(a_FallingBlock.GetYaw());
1391  Pkt.WriteByteAngle(a_FallingBlock.GetPitch());
1392  Pkt.WriteBEInt32(static_cast<Int32>(a_FallingBlock.GetBlockType()) | (static_cast<Int32>(a_FallingBlock.GetBlockMeta()) << 12));
1393  Pkt.WriteBEInt16(static_cast<Int16>(a_FallingBlock.GetSpeedX() * 400));
1394  Pkt.WriteBEInt16(static_cast<Int16>(a_FallingBlock.GetSpeedY() * 400));
1395  Pkt.WriteBEInt16(static_cast<Int16>(a_FallingBlock.GetSpeedZ() * 400));
1396 }
1397 
1398 
1399 
1400 
1401 
1403 {
1404  ASSERT(m_State == 3); // In game mode?
1405 
1406  cPacketizer Pkt(*this, pktSpawnMob);
1407  Pkt.WriteVarInt32(a_Mob.GetUniqueID());
1408  // TODO: Bad way to write a UUID, and it's not a true UUID, but this is functional for now.
1409  Pkt.WriteBEUInt64(0);
1410  Pkt.WriteBEUInt64(a_Mob.GetUniqueID());
1411  Pkt.WriteBEUInt8(static_cast<Byte>(a_Mob.GetMobType()));
1412  Vector3d LastSentPos = a_Mob.GetLastSentPos();
1413  Pkt.WriteBEDouble(LastSentPos.x);
1414  Pkt.WriteBEDouble(LastSentPos.y);
1415  Pkt.WriteBEDouble(LastSentPos.z);
1416  Pkt.WriteByteAngle(a_Mob.GetPitch());
1417  Pkt.WriteByteAngle(a_Mob.GetHeadYaw());
1418  Pkt.WriteByteAngle(a_Mob.GetYaw());
1419  Pkt.WriteBEInt16(static_cast<Int16>(a_Mob.GetSpeedX() * 400));
1420  Pkt.WriteBEInt16(static_cast<Int16>(a_Mob.GetSpeedY() * 400));
1421  Pkt.WriteBEInt16(static_cast<Int16>(a_Mob.GetSpeedZ() * 400));
1422  WriteEntityMetadata(Pkt, a_Mob);
1423  Pkt.WriteBEUInt8(0xff); // Metadata terminator
1424 }
1425 
1426 
1427 
1428 
1429 
1430 void cProtocol_1_9_0::SendSpawnObject(const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch)
1431 {
1432  ASSERT(m_State == 3); // In game mode?
1433  double PosX = a_Entity.GetPosX();
1434  double PosZ = a_Entity.GetPosZ();
1435  double Yaw = a_Entity.GetYaw();
1436  if (a_ObjectType == 71)
1437  {
1438  FixItemFramePositions(a_ObjectData, PosX, PosZ, Yaw);
1439  }
1440 
1441  cPacketizer Pkt(*this, pktSpawnObject);
1442  Pkt.WriteVarInt32(a_Entity.GetUniqueID());
1443  // TODO: Bad way to write a UUID, and it's not a true UUID, but this is functional for now.
1444  Pkt.WriteBEUInt64(0);
1445  Pkt.WriteBEUInt64(a_Entity.GetUniqueID());
1446  Pkt.WriteBEUInt8(static_cast<UInt8>(a_ObjectType));
1447  Pkt.WriteBEDouble(PosX);
1448  Pkt.WriteBEDouble(a_Entity.GetPosY());
1449  Pkt.WriteBEDouble(PosZ);
1450  Pkt.WriteByteAngle(a_Entity.GetPitch());
1451  Pkt.WriteByteAngle(Yaw);
1452  Pkt.WriteBEInt32(a_ObjectData);
1453  Pkt.WriteBEInt16(static_cast<Int16>(a_Entity.GetSpeedX() * 400));
1454  Pkt.WriteBEInt16(static_cast<Int16>(a_Entity.GetSpeedY() * 400));
1455  Pkt.WriteBEInt16(static_cast<Int16>(a_Entity.GetSpeedZ() * 400));
1456 }
1457 
1458 
1459 
1460 
1461 
1462 void cProtocol_1_9_0::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType)
1463 {
1464  ASSERT(m_State == 3); // In game mode?
1465 
1466  cPacketizer Pkt(*this, pktSpawnObject);
1467  Pkt.WriteVarInt32(a_Vehicle.GetUniqueID());
1468  // TODO: Bad way to write a UUID, and it's not a true UUID, but this is functional for now.
1469  Pkt.WriteBEUInt64(0);
1470  Pkt.WriteBEUInt64(a_Vehicle.GetUniqueID());
1471  Pkt.WriteBEUInt8(static_cast<UInt8>(a_VehicleType));
1472  Vector3d LastSentPos = a_Vehicle.GetLastSentPos();
1473  Pkt.WriteBEDouble(LastSentPos.x);
1474  Pkt.WriteBEDouble(LastSentPos.y);
1475  Pkt.WriteBEDouble(LastSentPos.z);
1476  Pkt.WriteByteAngle(a_Vehicle.GetPitch());
1477  Pkt.WriteByteAngle(a_Vehicle.GetYaw());
1478  Pkt.WriteBEInt32(a_VehicleSubType);
1479  Pkt.WriteBEInt16(static_cast<Int16>(a_Vehicle.GetSpeedX() * 400));
1480  Pkt.WriteBEInt16(static_cast<Int16>(a_Vehicle.GetSpeedY() * 400));
1481  Pkt.WriteBEInt16(static_cast<Int16>(a_Vehicle.GetSpeedZ() * 400));
1482 }
1483 
1484 
1485 
1486 
1487 
1489 {
1490  ASSERT(m_State == 3); // In game mode?
1491 
1492  cPacketizer Pkt(*this, pktStatistics);
1493  Pkt.WriteVarInt32(statCount); // TODO 2014-05-11 xdot: Optimization: Send "dirty" statistics only
1494 
1495  size_t Count = static_cast<size_t>(statCount);
1496  for (size_t i = 0; i < Count; ++i)
1497  {
1498  StatValue Value = a_Manager.GetValue(static_cast<eStatistic>(i));
1499  const AString & StatName = cStatInfo::GetName(static_cast<eStatistic>(i));
1500 
1501  Pkt.WriteString(StatName);
1502  Pkt.WriteVarInt32(static_cast<UInt32>(Value));
1503  }
1504 }
1505 
1506 
1507 
1508 
1509 
1511 {
1512  ASSERT(m_State == 3); // In game mode?
1513 
1515  Pkt.WriteVarInt32(static_cast<UInt32>(a_Results.size()));
1516 
1517  for (AStringVector::const_iterator itr = a_Results.begin(), end = a_Results.end(); itr != end; ++itr)
1518  {
1519  Pkt.WriteString(*itr);
1520  }
1521 }
1522 
1523 
1524 
1525 
1526 
1528 {
1529  ASSERT(m_State == 3); // In game mode?
1530 
1531  cPacketizer Pkt(*this, pktTeleportEntity);
1532  Pkt.WriteVarInt32(a_Entity.GetUniqueID());
1533  Pkt.WriteBEDouble(a_Entity.GetPosX());
1534  Pkt.WriteBEDouble(a_Entity.GetPosY());
1535  Pkt.WriteBEDouble(a_Entity.GetPosZ());
1536  Pkt.WriteByteAngle(a_Entity.GetYaw());
1537  Pkt.WriteByteAngle(a_Entity.GetPitch());
1538  Pkt.WriteBool(a_Entity.IsOnGround());
1539 }
1540 
1541 
1542 
1543 
1544 
1545 void cProtocol_1_9_0::SendThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ)
1546 {
1547  ASSERT(m_State == 3); // In game mode?
1548 
1549  cPacketizer Pkt(*this, pktSpawnGlobalEntity);
1550  Pkt.WriteVarInt32(0); // EntityID = 0, always
1551  Pkt.WriteBEUInt8(1); // Type = Thunderbolt
1552  Pkt.WriteBEDouble(a_BlockX);
1553  Pkt.WriteBEDouble(a_BlockY);
1554  Pkt.WriteBEDouble(a_BlockZ);
1555 }
1556 
1557 
1558 
1559 
1560 
1561 void cProtocol_1_9_0::SendTitleTimes(int a_FadeInTicks, int a_DisplayTicks, int a_FadeOutTicks)
1562 {
1563  ASSERT(m_State == 3); // In game mode?
1564 
1565  cPacketizer Pkt(*this, pktTitle);
1566  Pkt.WriteVarInt32(2); // Set title display times
1567  Pkt.WriteBEInt32(a_FadeInTicks);
1568  Pkt.WriteBEInt32(a_DisplayTicks);
1569  Pkt.WriteBEInt32(a_FadeOutTicks);
1570 }
1571 
1572 
1573 
1574 
1575 
1576 void cProtocol_1_9_0::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle)
1577 {
1578  ASSERT(m_State == 3); // In game mode?
1579  if (!a_DoDaylightCycle)
1580  {
1581  // When writing a "-" before the number the client ignores it but it will stop the client-side time expiration.
1582  a_TimeOfDay = std::min(-a_TimeOfDay, -1LL);
1583  }
1584 
1585  cPacketizer Pkt(*this, pktTimeUpdate);
1586  Pkt.WriteBEInt64(a_WorldAge);
1587  Pkt.WriteBEInt64(a_TimeOfDay);
1588 }
1589 
1590 
1591 
1592 
1593 
1594 void cProtocol_1_9_0::SendUnloadChunk(int a_ChunkX, int a_ChunkZ)
1595 {
1596  ASSERT(m_State == 3); // In game mode?
1597 
1598  cPacketizer Pkt(*this, pktUnloadChunk);
1599  Pkt.WriteBEInt32(a_ChunkX);
1600  Pkt.WriteBEInt32(a_ChunkZ);
1601 }
1602 
1603 
1604 
1605 
1606 
1608 {
1609  ASSERT(m_State == 3); // In game mode?
1610 
1611  cPacketizer Pkt(*this, pktUpdateBlockEntity);
1612  Pkt.WritePosition64(a_BlockEntity.GetPosX(), a_BlockEntity.GetPosY(), a_BlockEntity.GetPosZ());
1613  Byte Action = 0;
1614  switch (a_BlockEntity.GetBlockType())
1615  {
1616  case E_BLOCK_MOB_SPAWNER: Action = 1; break; // Update mob spawner spinny mob thing
1617  case E_BLOCK_COMMAND_BLOCK: Action = 2; break; // Update command block text
1618  case E_BLOCK_BEACON: Action = 3; break; // Update beacon entity
1619  case E_BLOCK_HEAD: Action = 4; break; // Update Mobhead entity
1620  case E_BLOCK_FLOWER_POT: Action = 5; break; // Update flower pot
1621  case E_BLOCK_BED: Action = 11; break; // Update bed color
1622  default: ASSERT(!"Unhandled or unimplemented BlockEntity update request!"); break;
1623  }
1624  Pkt.WriteBEUInt8(Action);
1625 
1626  WriteBlockEntity(Pkt, a_BlockEntity);
1627 }
1628 
1629 
1630 
1631 
1632 
1633 void cProtocol_1_9_0::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)
1634 {
1635  ASSERT(m_State == 3); // In game mode?
1636 
1637  cPacketizer Pkt(*this, pktUpdateSign);
1638  Pkt.WritePosition64(a_BlockX, a_BlockY, a_BlockZ);
1639 
1640  Json::StyledWriter JsonWriter;
1641  AString Lines[] = { a_Line1, a_Line2, a_Line3, a_Line4 };
1642  for (size_t i = 0; i < ARRAYCOUNT(Lines); i++)
1643  {
1644  Json::Value RootValue;
1645  RootValue["text"] = Lines[i];
1646  Pkt.WriteString(JsonWriter.write(RootValue).c_str());
1647  }
1648 }
1649 
1650 
1651 
1652 
1653 
1654 void cProtocol_1_9_0::SendUseBed(const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ)
1655 {
1656  ASSERT(m_State == 3); // In game mode?
1657 
1658  cPacketizer Pkt(*this, pktUseBed);
1659  Pkt.WriteVarInt32(a_Entity.GetUniqueID());
1660  Pkt.WritePosition64(a_BlockX, a_BlockY, a_BlockZ);
1661 }
1662 
1663 
1664 
1665 
1666 
1668 {
1669  ASSERT(m_State == 3); // In game mode?
1670 
1671  {
1672  cPacketizer Pkt(*this, pktWeather);
1673  Pkt.WriteBEUInt8((a_Weather == wSunny) ? 1 : 2); // End rain / begin rain
1674  Pkt.WriteBEFloat(0); // Unused for weather
1675  }
1676 
1677  // TODO: Fade effect, somehow
1678 }
1679 
1680 
1681 
1682 
1683 
1685 {
1686  ASSERT(m_State == 3); // In game mode?
1687 
1688  cPacketizer Pkt(*this, pktWindowItems);
1689  Pkt.WriteBEInt8(a_Window.GetWindowID());
1690  Pkt.WriteBEInt16(static_cast<Int16>(a_Window.GetNumSlots()));
1691  cItems Slots;
1692  a_Window.GetSlots(*(m_Client->GetPlayer()), Slots);
1693  for (cItems::const_iterator itr = Slots.begin(), end = Slots.end(); itr != end; ++itr)
1694  {
1695  WriteItem(Pkt, *itr);
1696  } // for itr - Slots[]
1697 }
1698 
1699 
1700 
1701 
1702 
1704 {
1705  ASSERT(m_State == 3); // In game mode?
1706 
1707  cPacketizer Pkt(*this, pktWindowClose);
1708  Pkt.WriteBEInt8(a_Window.GetWindowID());
1709 }
1710 
1711 
1712 
1713 
1714 
1716 {
1717  ASSERT(m_State == 3); // In game mode?
1718 
1719  if (a_Window.GetWindowType() < 0)
1720  {
1721  // Do not send this packet for player inventory windows
1722  return;
1723  }
1724 
1725  cPacketizer Pkt(*this, pktWindowOpen);
1726  Pkt.WriteBEInt8(a_Window.GetWindowID());
1727  Pkt.WriteString(a_Window.GetWindowTypeName());
1728  Pkt.WriteString(Printf("{\"text\":\"%s\"}", a_Window.GetWindowTitle().c_str()));
1729 
1730  switch (a_Window.GetWindowType())
1731  {
1732  case cWindow::wtWorkbench:
1734  case cWindow::wtAnvil:
1735  {
1736  Pkt.WriteBEInt8(0);
1737  break;
1738  }
1739  default:
1740  {
1741  Pkt.WriteBEInt8(static_cast<Int8>(a_Window.GetNumNonInventorySlots()));
1742  break;
1743  }
1744  }
1745 
1746  if (a_Window.GetWindowType() == cWindow::wtAnimalChest)
1747  {
1748  UInt32 HorseID = static_cast<const cHorseWindow &>(a_Window).GetHorseID();
1749  Pkt.WriteBEInt32(static_cast<Int32>(HorseID));
1750  }
1751 }
1752 
1753 
1754 
1755 
1756 
1757 void cProtocol_1_9_0::SendWindowProperty(const cWindow & a_Window, short a_Property, short a_Value)
1758 {
1759  ASSERT(m_State == 3); // In game mode?
1760 
1761  cPacketizer Pkt(*this, pktWindowProperty);
1762  Pkt.WriteBEInt8(a_Window.GetWindowID());
1763  Pkt.WriteBEInt16(a_Property);
1764  Pkt.WriteBEInt16(a_Value);
1765 }
1766 
1767 
1768 
1769 
1770 
1771 bool cProtocol_1_9_0::CompressPacket(const AString & a_Packet, AString & a_CompressedData)
1772 {
1773  // Compress the data:
1774  char CompressedData[MAX_COMPRESSED_PACKET_LEN];
1775 
1776  uLongf CompressedSize = compressBound(static_cast<uLongf>(a_Packet.size()));
1777  if (CompressedSize >= MAX_COMPRESSED_PACKET_LEN)
1778  {
1779  ASSERT(!"Too high packet size.");
1780  return false;
1781  }
1782 
1783  int Status = compress2(
1784  reinterpret_cast<Bytef *>(CompressedData), &CompressedSize,
1785  reinterpret_cast<const Bytef *>(a_Packet.data()), static_cast<uLongf>(a_Packet.size()), Z_DEFAULT_COMPRESSION
1786  );
1787  if (Status != Z_OK)
1788  {
1789  return false;
1790  }
1791 
1792  AString LengthData;
1793  cByteBuffer Buffer(20);
1794  Buffer.WriteVarInt32(static_cast<UInt32>(a_Packet.size()));
1795  Buffer.ReadAll(LengthData);
1796  Buffer.CommitRead();
1797 
1798  Buffer.WriteVarInt32(static_cast<UInt32>(CompressedSize + LengthData.size()));
1799  Buffer.WriteVarInt32(static_cast<UInt32>(a_Packet.size()));
1800  Buffer.ReadAll(LengthData);
1801  Buffer.CommitRead();
1802 
1803  a_CompressedData.clear();
1804  a_CompressedData.reserve(LengthData.size() + CompressedSize);
1805  a_CompressedData.append(LengthData.data(), LengthData.size());
1806  a_CompressedData.append(CompressedData, CompressedSize);
1807  return true;
1808 }
1809 
1810 
1811 
1812 
1813 
1814 int cProtocol_1_9_0::GetParticleID(const AString & a_ParticleName)
1815 {
1816  static std::map<AString, int> ParticleMap;
1817  if (ParticleMap.empty())
1818  {
1819  // Initialize the ParticleMap:
1820  ParticleMap["explode"] = 0;
1821  ParticleMap["largeexplode"] = 1;
1822  ParticleMap["hugeexplosion"] = 2;
1823  ParticleMap["fireworksspark"] = 3;
1824  ParticleMap["bubble"] = 4;
1825  ParticleMap["splash"] = 5;
1826  ParticleMap["wake"] = 6;
1827  ParticleMap["suspended"] = 7;
1828  ParticleMap["depthsuspend"] = 8;
1829  ParticleMap["crit"] = 9;
1830  ParticleMap["magiccrit"] = 10;
1831  ParticleMap["smoke"] = 11;
1832  ParticleMap["largesmoke"] = 12;
1833  ParticleMap["spell"] = 13;
1834  ParticleMap["instantspell"] = 14;
1835  ParticleMap["mobspell"] = 15;
1836  ParticleMap["mobspellambient"] = 16;
1837  ParticleMap["witchmagic"] = 17;
1838  ParticleMap["dripwater"] = 18;
1839  ParticleMap["driplava"] = 19;
1840  ParticleMap["angryvillager"] = 20;
1841  ParticleMap["happyvillager"] = 21;
1842  ParticleMap["townaura"] = 22;
1843  ParticleMap["note"] = 23;
1844  ParticleMap["portal"] = 24;
1845  ParticleMap["enchantmenttable"] = 25;
1846  ParticleMap["flame"] = 26;
1847  ParticleMap["lava"] = 27;
1848  ParticleMap["footstep"] = 28;
1849  ParticleMap["cloud"] = 29;
1850  ParticleMap["reddust"] = 30;
1851  ParticleMap["snowballpoof"] = 31;
1852  ParticleMap["snowshovel"] = 32;
1853  ParticleMap["slime"] = 33;
1854  ParticleMap["heart"] = 34;
1855  ParticleMap["barrier"] = 35;
1856  ParticleMap["iconcrack"] = 36;
1857  ParticleMap["blockcrack"] = 37;
1858  ParticleMap["blockdust"] = 38;
1859  ParticleMap["droplet"] = 39;
1860  ParticleMap["take"] = 40;
1861  ParticleMap["mobappearance"] = 41;
1862  ParticleMap["dragonbreath"] = 42;
1863  ParticleMap["endrod"] = 43;
1864  ParticleMap["damageindicator"] = 44;
1865  ParticleMap["sweepattack"] = 45;
1866  ParticleMap["fallingdust"] = 46;
1867  ParticleMap["totem"] = 47;
1868  ParticleMap["spit"] = 48;
1869  }
1870 
1871  AString ParticleName = StrToLower(a_ParticleName);
1872  if (ParticleMap.find(ParticleName) == ParticleMap.end())
1873  {
1874  LOGWARNING("Unknown particle: %s", a_ParticleName.c_str());
1875  ASSERT(!"Unknown particle");
1876  return 0;
1877  }
1878 
1879  return ParticleMap[ParticleName];
1880 }
1881 
1882 
1883 
1884 
1885 
1886 void cProtocol_1_9_0::FixItemFramePositions(int a_ObjectData, double & a_PosX, double & a_PosZ, double & a_Yaw)
1887 {
1888  switch (a_ObjectData)
1889  {
1890  case 0:
1891  {
1892  a_PosZ += 1;
1893  a_Yaw = 0;
1894  break;
1895  }
1896  case 1:
1897  {
1898  a_PosX -= 1;
1899  a_Yaw = 90;
1900  break;
1901  }
1902  case 2:
1903  {
1904  a_PosZ -= 1;
1905  a_Yaw = 180;
1906  break;
1907  }
1908  case 3:
1909  {
1910  a_PosX += 1;
1911  a_Yaw = 270;
1912  break;
1913  }
1914  }
1915 }
1916 
1917 
1918 
1919 
1920 
1921 void cProtocol_1_9_0::AddReceivedData(const char * a_Data, size_t a_Size)
1922 {
1923  // Write the incoming data into the comm log file:
1925  {
1926  if (m_ReceivedData.GetReadableSpace() > 0)
1927  {
1928  AString AllData;
1929  size_t OldReadableSpace = m_ReceivedData.GetReadableSpace();
1930  m_ReceivedData.ReadAll(AllData);
1933  ASSERT(m_ReceivedData.GetReadableSpace() == OldReadableSpace);
1934  AString Hex;
1935  CreateHexDump(Hex, AllData.data(), AllData.size(), 16);
1936  m_CommLogFile.Printf("Incoming data, %zu (0x%zx) unparsed bytes already present in buffer:\n%s\n",
1937  AllData.size(), AllData.size(), Hex.c_str()
1938  );
1939  }
1940  AString Hex;
1941  CreateHexDump(Hex, a_Data, a_Size, 16);
1942  m_CommLogFile.Printf("Incoming data: %u (0x%x) bytes: \n%s\n",
1943  static_cast<unsigned>(a_Size), static_cast<unsigned>(a_Size), Hex.c_str()
1944  );
1945  m_CommLogFile.Flush();
1946  }
1947 
1948  if (!m_ReceivedData.Write(a_Data, a_Size))
1949  {
1950  // Too much data in the incoming queue, report to caller:
1952  return;
1953  }
1954 
1955  // Handle all complete packets:
1956  for (;;)
1957  {
1958  UInt32 PacketLen;
1959  if (!m_ReceivedData.ReadVarInt(PacketLen))
1960  {
1961  // Not enough data
1963  break;
1964  }
1965  if (!m_ReceivedData.CanReadBytes(PacketLen))
1966  {
1967  // The full packet hasn't been received yet
1969  break;
1970  }
1971 
1972  // Check packet for compression:
1973  UInt32 UncompressedSize = 0;
1974  AString UncompressedData;
1975  if (m_State == 3)
1976  {
1977  UInt32 NumBytesRead = static_cast<UInt32>(m_ReceivedData.GetReadableSpace());
1978 
1979  if (!m_ReceivedData.ReadVarInt(UncompressedSize))
1980  {
1981  m_Client->Kick("Compression packet incomplete");
1982  return;
1983  }
1984 
1985  NumBytesRead -= static_cast<UInt32>(m_ReceivedData.GetReadableSpace()); // How many bytes has the UncompressedSize taken up?
1986  ASSERT(PacketLen > NumBytesRead);
1987  PacketLen -= NumBytesRead;
1988 
1989  if (UncompressedSize > 0)
1990  {
1991  // Decompress the data:
1992  AString CompressedData;
1993  VERIFY(m_ReceivedData.ReadString(CompressedData, PacketLen));
1994  if (InflateString(CompressedData.data(), PacketLen, UncompressedData) != Z_OK)
1995  {
1996  m_Client->Kick("Compression failure");
1997  return;
1998  }
1999  PacketLen = static_cast<UInt32>(UncompressedData.size());
2000  if (PacketLen != UncompressedSize)
2001  {
2002  m_Client->Kick("Wrong uncompressed packet size given");
2003  return;
2004  }
2005  }
2006  }
2007 
2008  // Move the packet payload to a separate cByteBuffer, bb:
2009  cByteBuffer bb(PacketLen + 1);
2010  if (UncompressedSize == 0)
2011  {
2012  // No compression was used, move directly
2013  VERIFY(m_ReceivedData.ReadToByteBuffer(bb, static_cast<size_t>(PacketLen)));
2014  }
2015  else
2016  {
2017  // Compression was used, move the uncompressed data:
2018  VERIFY(bb.Write(UncompressedData.data(), UncompressedData.size()));
2019  }
2021 
2022  UInt32 PacketType;
2023  if (!bb.ReadVarInt(PacketType))
2024  {
2025  // Not enough data
2026  break;
2027  }
2028 
2029  // Write one NUL extra, so that we can detect over-reads
2030  bb.Write("\0", 1);
2031 
2032  // Log the packet info into the comm log file:
2034  {
2035  AString PacketData;
2036  bb.ReadAll(PacketData);
2037  bb.ResetRead();
2038  bb.ReadVarInt(PacketType); // We have already read the packet type once, it will be there again
2039  ASSERT(PacketData.size() > 0); // We have written an extra NUL, so there had to be at least one byte read
2040  PacketData.resize(PacketData.size() - 1);
2041  AString PacketDataHex;
2042  CreateHexDump(PacketDataHex, PacketData.data(), PacketData.size(), 16);
2043  m_CommLogFile.Printf("Next incoming packet is type %u (0x%x), length %u (0x%x) at state %d. Payload:\n%s\n",
2044  PacketType, PacketType, PacketLen, PacketLen, m_State, PacketDataHex.c_str()
2045  );
2046  }
2047 
2048  if (!HandlePacket(bb, PacketType))
2049  {
2050  // Unknown packet, already been reported, but without the length. Log the length here:
2051  LOGWARNING("Protocol 1.9: Unhandled packet: type 0x%x, state %d, length %u", PacketType, m_State, PacketLen);
2052 
2053  #ifdef _DEBUG
2054  // Dump the packet contents into the log:
2055  bb.ResetRead();
2056  AString Packet;
2057  bb.ReadAll(Packet);
2058  Packet.resize(Packet.size() - 1); // Drop the final NUL pushed there for over-read detection
2059  AString Out;
2060  CreateHexDump(Out, Packet.data(), Packet.size(), 24);
2061  LOGD("Packet contents:\n%s", Out.c_str());
2062  #endif // _DEBUG
2063 
2064  // Put a message in the comm log:
2066  {
2067  m_CommLogFile.Printf("^^^^^^ Unhandled packet ^^^^^^\n\n\n");
2068  }
2069 
2070  return;
2071  }
2072 
2073  // The packet should have 1 byte left in the buffer - the NUL we had added
2074  if (bb.GetReadableSpace() != 1)
2075  {
2076  // Read more or less than packet length, report as error
2077  LOGWARNING("Protocol 1.9: Wrong number of bytes read for packet 0x%x, state %d. Read %zu bytes, packet contained %u bytes",
2078  PacketType, m_State, bb.GetUsedSpace() - bb.GetReadableSpace(), PacketLen
2079  );
2080 
2081  // Put a message in the comm log:
2083  {
2084  m_CommLogFile.Printf("^^^^^^ Wrong number of bytes read for this packet (exp %d left, got %zu left) ^^^^^^\n\n\n",
2085  1, bb.GetReadableSpace()
2086  );
2087  m_CommLogFile.Flush();
2088  }
2089 
2090  ASSERT(!"Read wrong number of bytes!");
2091  m_Client->PacketError(PacketType);
2092  }
2093  } // for (ever)
2094 
2095  // Log any leftover bytes into the logfile:
2097  {
2098  AString AllData;
2099  size_t OldReadableSpace = m_ReceivedData.GetReadableSpace();
2100  m_ReceivedData.ReadAll(AllData);
2103  ASSERT(m_ReceivedData.GetReadableSpace() == OldReadableSpace);
2104  AString Hex;
2105  CreateHexDump(Hex, AllData.data(), AllData.size(), 16);
2106  m_CommLogFile.Printf("Protocol 1.9: There are %zu (0x%zx) bytes of non-parse-able data left in the buffer:\n%s",
2108  );
2109  m_CommLogFile.Flush();
2110  }
2111 }
2112 
2113 
2114 
2115 
2116 
2118 {
2119  switch (a_Packet)
2120  {
2121  case pktAttachEntity: return 0x40;
2122  case pktBlockAction: return 0x0a;
2123  case pktBlockBreakAnim: return 0x08;
2124  case pktBlockChange: return 0x0b;
2125  case pktBlockChanges: return 0x10;
2126  case pktCameraSetTo: return 0x36;
2127  case pktChatRaw: return 0x0f;
2128  case pktCollectEntity: return 0x49;
2129  case pktDestroyEntity: return 0x30;
2130  case pktDifficulty: return 0x0d;
2131  case pktDisconnectDuringGame: return 0x1a;
2132  case pktDisconnectDuringLogin: return 0x0;
2133  case pktDisplayObjective: return 0x38;
2134  case pktEditSign: return 0x2a;
2135  case pktEncryptionRequest: return 0x01;
2136  case pktEntityAnimation: return 0x06;
2137  case pktEntityEffect: return 0x4c;
2138  case pktEntityEquipment: return 0x3c;
2139  case pktEntityHeadLook: return 0x34;
2140  case pktEntityLook: return 0x27;
2141  case pktEntityMeta: return 0x39;
2142  case pktEntityProperties: return 0x4b;
2143  case pktEntityRelMove: return 0x25;
2144  case pktEntityRelMoveLook: return 0x26;
2145  case pktEntityStatus: return 0x1b;
2146  case pktEntityVelocity: return 0x3b;
2147  case pktExperience: return 0x3d;
2148  case pktExplosion: return 0x1c;
2149  case pktGameMode: return 0x1e;
2150  case pktHeldItemChange: return 0x37;
2151  case pktInventorySlot: return 0x16;
2152  case pktJoinGame: return 0x23;
2153  case pktKeepAlive: return 0x1f;
2154  case pktLeashEntity: return 0x3a;
2155  case pktLoginSuccess: return 0x02;
2156  case pktMapData: return 0x24;
2157  case pktParticleEffect: return 0x22;
2158  case pktPingResponse: return 0x01;
2159  case pktPlayerAbilities: return 0x2b;
2160  case pktPlayerList: return 0x2d;
2161  case pktPlayerMaxSpeed: return 0x4b;
2162  case pktPlayerMoveLook: return 0x2e;
2163  case pktPluginMessage: return 0x18;
2164  case pktRemoveEntityEffect: return 0x31;
2165  case pktRespawn: return 0x33;
2166  case pktScoreboardObjective: return 0x3f;
2167  case pktSpawnExperienceOrb: return 0x01;
2168  case pktSpawnGlobalEntity: return 0x02;
2169  case pktSpawnObject: return 0x00;
2170  case pktSpawnOtherPlayer: return 0x05;
2171  case pktSpawnPainting: return 0x04;
2172  case pktSpawnPosition: return 0x43;
2173  case pktSoundEffect: return 0x19;
2174  case pktSoundParticleEffect: return 0x21;
2175  case pktSpawnMob: return 0x03;
2176  case pktStartCompression: return 0x03;
2177  case pktStatistics: return 0x07;
2178  case pktStatusResponse: return 0x00;
2179  case pktTabCompletionResults: return 0x0e;
2180  case pktTeleportEntity: return 0x4a;
2181  case pktTimeUpdate: return 0x44;
2182  case pktTitle: return 0x45;
2183  case pktUnloadChunk: return 0x1d;
2184  case pktUpdateBlockEntity: return 0x09;
2185  case pktUpdateHealth: return 0x3e;
2186  case pktUpdateScore: return 0x42;
2187  case pktUpdateSign: return 0x46;
2188  case pktUseBed: return 0x2f;
2189  case pktWeather: return 0x1e;
2190  case pktWindowClose: return 0x12;
2191  case pktWindowItems: return 0x14;
2192  case pktWindowOpen: return 0x13;
2193  case pktWindowProperty: return 0x15;
2194  }
2195  UNREACHABLE("Unsupported outgoing packet type");
2196 }
2197 
2198 
2199 
2200 
2201 
2202 bool cProtocol_1_9_0::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType)
2203 {
2204  switch (m_State)
2205  {
2206  case 1:
2207  {
2208  // Status
2209  switch (a_PacketType)
2210  {
2211  case 0x00: HandlePacketStatusRequest(a_ByteBuffer); return true;
2212  case 0x01: HandlePacketStatusPing (a_ByteBuffer); return true;
2213  }
2214  break;
2215  }
2216 
2217  case 2:
2218  {
2219  // Login
2220  switch (a_PacketType)
2221  {
2222  case 0x00: HandlePacketLoginStart (a_ByteBuffer); return true;
2223  case 0x01: HandlePacketLoginEncryptionResponse(a_ByteBuffer); return true;
2224  }
2225  break;
2226  }
2227 
2228  case 3:
2229  {
2230  // Game
2231  switch (a_PacketType)
2232  {
2233  case 0x00: HandleConfirmTeleport (a_ByteBuffer); return true;
2234  case 0x01: HandlePacketTabComplete (a_ByteBuffer); return true;
2235  case 0x02: HandlePacketChatMessage (a_ByteBuffer); return true;
2236  case 0x03: HandlePacketClientStatus (a_ByteBuffer); return true;
2237  case 0x04: HandlePacketClientSettings (a_ByteBuffer); return true;
2238  case 0x05: break; // Confirm transaction - not used in MCS
2239  case 0x06: HandlePacketEnchantItem (a_ByteBuffer); return true;
2240  case 0x07: HandlePacketWindowClick (a_ByteBuffer); return true;
2241  case 0x08: HandlePacketWindowClose (a_ByteBuffer); return true;
2242  case 0x09: HandlePacketPluginMessage (a_ByteBuffer); return true;
2243  case 0x0a: HandlePacketUseEntity (a_ByteBuffer); return true;
2244  case 0x0b: HandlePacketKeepAlive (a_ByteBuffer); return true;
2245  case 0x0c: HandlePacketPlayerPos (a_ByteBuffer); return true;
2246  case 0x0d: HandlePacketPlayerPosLook (a_ByteBuffer); return true;
2247  case 0x0e: HandlePacketPlayerLook (a_ByteBuffer); return true;
2248  case 0x0f: HandlePacketPlayer (a_ByteBuffer); return true;
2249  case 0x10: HandlePacketVehicleMove (a_ByteBuffer); return true;
2250  case 0x11: HandlePacketBoatSteer (a_ByteBuffer); return true;
2251  case 0x12: HandlePacketPlayerAbilities (a_ByteBuffer); return true;
2252  case 0x13: HandlePacketBlockDig (a_ByteBuffer); return true;
2253  case 0x14: HandlePacketEntityAction (a_ByteBuffer); return true;
2254  case 0x15: HandlePacketSteerVehicle (a_ByteBuffer); return true;
2255  case 0x16: break; // Resource pack status - not yet implemented
2256  case 0x17: HandlePacketSlotSelect (a_ByteBuffer); return true;
2257  case 0x18: HandlePacketCreativeInventoryAction(a_ByteBuffer); return true;
2258  case 0x19: HandlePacketUpdateSign (a_ByteBuffer); return true;
2259  case 0x1a: HandlePacketAnimation (a_ByteBuffer); return true;
2260  case 0x1b: HandlePacketSpectate (a_ByteBuffer); return true;
2261  case 0x1c: HandlePacketBlockPlace (a_ByteBuffer); return true;
2262  case 0x1d: HandlePacketUseItem (a_ByteBuffer); return true;
2263  }
2264  break;
2265  }
2266  default:
2267  {
2268  // Received a packet in an unknown state, report:
2269  LOGWARNING("Received a packet in an unknown protocol state %d. Ignoring further packets.", m_State);
2270 
2271  // Cannot kick the client - we don't know this state and thus the packet number for the kick packet
2272 
2273  // Switch to a state when all further packets are silently ignored:
2274  m_State = 255;
2275  return false;
2276  }
2277  case 255:
2278  {
2279  // This is the state used for "not processing packets anymore" when we receive a bad packet from a client.
2280  // Do not output anything (the caller will do that for us), just return failure
2281  return false;
2282  }
2283  } // switch (m_State)
2284 
2285  // Unknown packet type, report to the ClientHandle:
2286  m_Client->PacketUnknown(a_PacketType);
2287  return false;
2288 }
2289 
2290 
2291 
2292 
2293 
2295 {
2296  HANDLE_READ(a_ByteBuffer, ReadBEInt64, Int64, Timestamp);
2297 
2298  cPacketizer Pkt(*this, pktPingResponse);
2299  Pkt.WriteBEInt64(Timestamp);
2300 }
2301 
2302 
2303 
2304 
2305 
2307 {
2308  cServer * Server = cRoot::Get()->GetServer();
2309  AString ServerDescription = Server->GetDescription();
2310  auto NumPlayers = static_cast<signed>(Server->GetNumPlayers());
2311  auto MaxPlayers = static_cast<signed>(Server->GetMaxPlayers());
2312  AString Favicon = Server->GetFaviconData();
2313  cRoot::Get()->GetPluginManager()->CallHookServerPing(*m_Client, ServerDescription, NumPlayers, MaxPlayers, Favicon);
2314 
2315  // Version:
2316  Json::Value Version;
2317  Version["name"] = "Cuberite 1.9";
2318  Version["protocol"] = 107;
2319 
2320  // Players:
2321  Json::Value Players;
2322  Players["online"] = NumPlayers;
2323  Players["max"] = MaxPlayers;
2324  // TODO: Add "sample"
2325 
2326  // Description:
2327  Json::Value Description;
2328  Description["text"] = ServerDescription.c_str();
2329 
2330  // Create the response:
2331  Json::Value ResponseValue;
2332  ResponseValue["version"] = Version;
2333  ResponseValue["players"] = Players;
2334  ResponseValue["description"] = Description;
2335  m_Client->ForgeAugmentServerListPing(ResponseValue);
2336  if (!Favicon.empty())
2337  {
2338  ResponseValue["favicon"] = Printf("data:image/png;base64,%s", Favicon.c_str());
2339  }
2340 
2341  Json::FastWriter Writer;
2342  AString Response = Writer.write(ResponseValue);
2343 
2344  cPacketizer Pkt(*this, pktStatusResponse);
2345  Pkt.WriteString(Response);
2346 }
2347 
2348 
2349 
2350 
2351 
2353 {
2354  UInt32 EncKeyLength, EncNonceLength;
2355  if (!a_ByteBuffer.ReadVarInt(EncKeyLength))
2356  {
2357  return;
2358  }
2359  AString EncKey;
2360  if (!a_ByteBuffer.ReadString(EncKey, EncKeyLength))
2361  {
2362  return;
2363  }
2364  if (!a_ByteBuffer.ReadVarInt(EncNonceLength))
2365  {
2366  return;
2367  }
2368  AString EncNonce;
2369  if (!a_ByteBuffer.ReadString(EncNonce, EncNonceLength))
2370  {
2371  return;
2372  }
2373  if ((EncKeyLength > MAX_ENC_LEN) || (EncNonceLength > MAX_ENC_LEN))
2374  {
2375  LOGD("Too long encryption");
2376  m_Client->Kick("Hacked client");
2377  return;
2378  }
2379 
2380  // Decrypt EncNonce using privkey
2381  cRsaPrivateKey & rsaDecryptor = cRoot::Get()->GetServer()->GetPrivateKey();
2382  UInt32 DecryptedNonce[MAX_ENC_LEN / sizeof(Int32)];
2383  int res = rsaDecryptor.Decrypt(reinterpret_cast<const Byte *>(EncNonce.data()), EncNonce.size(), reinterpret_cast<Byte *>(DecryptedNonce), sizeof(DecryptedNonce));
2384  if (res != 4)
2385  {
2386  LOGD("Bad nonce length: got %d, exp %d", res, 4);
2387  m_Client->Kick("Hacked client");
2388  return;
2389  }
2390  if (ntohl(DecryptedNonce[0]) != static_cast<unsigned>(reinterpret_cast<uintptr_t>(this)))
2391  {
2392  LOGD("Bad nonce value");
2393  m_Client->Kick("Hacked client");
2394  return;
2395  }
2396 
2397  // Decrypt the symmetric encryption key using privkey:
2398  Byte DecryptedKey[MAX_ENC_LEN];
2399  res = rsaDecryptor.Decrypt(reinterpret_cast<const Byte *>(EncKey.data()), EncKey.size(), DecryptedKey, sizeof(DecryptedKey));
2400  if (res != 16)
2401  {
2402  LOGD("Bad key length");
2403  m_Client->Kick("Hacked client");
2404  return;
2405  }
2406 
2407  StartEncryption(DecryptedKey);
2409 }
2410 
2411 
2412 
2413 
2414 
2416 {
2417  AString Username;
2418  if (!a_ByteBuffer.ReadVarUTF8String(Username))
2419  {
2420  m_Client->Kick("Bad username");
2421  return;
2422  }
2423 
2424  if (!m_Client->HandleHandshake(Username))
2425  {
2426  // The client is not welcome here, they have been sent a Kick packet already
2427  return;
2428  }
2429 
2430  cServer * Server = cRoot::Get()->GetServer();
2431  // If auth is required, then send the encryption request:
2432  if (Server->ShouldAuthenticate())
2433  {
2434  cPacketizer Pkt(*this, pktEncryptionRequest);
2435  Pkt.WriteString(Server->GetServerID());
2436  const AString & PubKeyDer = Server->GetPublicKeyDER();
2437  Pkt.WriteVarInt32(static_cast<UInt32>(PubKeyDer.size()));
2438  Pkt.WriteBuf(PubKeyDer.data(), PubKeyDer.size());
2439  Pkt.WriteVarInt32(4);
2440  Pkt.WriteBEInt32(static_cast<int>(reinterpret_cast<intptr_t>(this))); // Using 'this' as the cryptographic nonce, so that we don't have to generate one each time :)
2441  m_Client->SetUsername(Username);
2442  return;
2443  }
2444 
2445  m_Client->HandleLogin(Username);
2446 }
2447 
2448 
2449 
2450 
2451 
2453 {
2454  HANDLE_READ(a_ByteBuffer, ReadVarInt, Int32, Hand);
2455 
2456  m_Client->HandleAnimation(0); // Packet exists solely for arm-swing notification
2457 }
2458 
2459 
2460 
2461 
2462 
2464 {
2465  HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Status);
2466 
2467  int BlockX, BlockY, BlockZ;
2468  if (!a_ByteBuffer.ReadPosition64(BlockX, BlockY, BlockZ))
2469  {
2470  return;
2471  }
2472 
2473  HANDLE_READ(a_ByteBuffer, ReadVarInt, Int32, Face);
2474  m_Client->HandleLeftClick(BlockX, BlockY, BlockZ, FaceIntToBlockFace(Face), Status);
2475 }
2476 
2477 
2478 
2479 
2480 
2482 {
2483  int BlockX, BlockY, BlockZ;
2484  if (!a_ByteBuffer.ReadPosition64(BlockX, BlockY, BlockZ))
2485  {
2486  return;
2487  }
2488 
2489  HANDLE_READ(a_ByteBuffer, ReadVarInt, Int32, Face);
2490  HANDLE_READ(a_ByteBuffer, ReadVarInt, Int32, Hand);
2491  HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, CursorX);
2492  HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, CursorY);
2493  HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, CursorZ);
2494  m_Client->HandleRightClick(BlockX, BlockY, BlockZ, FaceIntToBlockFace(Face), CursorX, CursorY, CursorZ, HandIntToEnum(Hand));
2495 }
2496 
2497 
2498 
2499 
2500 
2502 {
2503  HANDLE_READ(a_ByteBuffer, ReadBool, bool, RightPaddle);
2504  HANDLE_READ(a_ByteBuffer, ReadBool, bool, LeftPaddle);
2505 
2506  // Get the players vehicle
2507  cPlayer * Player = m_Client->GetPlayer();
2508  cEntity * Vehicle = Player->GetAttached();
2509 
2510  if (Vehicle)
2511  {
2512  if (Vehicle->GetEntityType() == cEntity::etBoat)
2513  {
2514  auto * Boat = static_cast<cBoat *>(Vehicle);
2515  Boat->UpdatePaddles(RightPaddle, LeftPaddle);
2516  }
2517  }
2518 }
2519 
2520 
2521 
2522 
2523 
2525 {
2526  HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Message);
2527  m_Client->HandleChat(Message);
2528 }
2529 
2530 
2531 
2532 
2533 
2535 {
2536  HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Locale);
2537  HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, ViewDistance);
2538  HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, ChatFlags);
2539  HANDLE_READ(a_ByteBuffer, ReadBool, bool, ChatColors);
2540  HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, SkinParts);
2541  HANDLE_READ(a_ByteBuffer, ReadVarInt, UInt32, MainHand);
2542 
2543  m_Client->SetLocale(Locale);
2544  m_Client->SetViewDistance(ViewDistance);
2545  m_Client->GetPlayer()->SetSkinParts(SkinParts);
2546  m_Client->GetPlayer()->SetMainHand(static_cast<eMainHand>(MainHand));
2547  // TODO: Handle chat flags and chat colors
2548 }
2549 
2550 
2551 
2552 
2553 
2555 {
2556  HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, ActionID);
2557  switch (ActionID)
2558  {
2559  case 0:
2560  {
2561  // Respawn
2563  break;
2564  }
2565  case 1:
2566  {
2567  // Request stats
2568  const cStatManager & Manager = m_Client->GetPlayer()->GetStatManager();
2569  SendStatistics(Manager);
2570 
2571  break;
2572  }
2573  case 2:
2574  {
2575  // Open Inventory achievement
2577  break;
2578  }
2579  }
2580 }
2581 
2582 
2583 
2584 
2585 
2587 {
2588  HANDLE_READ(a_ByteBuffer, ReadVarInt32, UInt32, TeleportID);
2589 
2590  // Can we stop throwing away incoming player position packets?
2591  if (TeleportID == m_OutstandingTeleportId)
2592  {
2593  m_IsTeleportIdConfirmed = true;
2594  }
2595 }
2596 
2597 
2598 
2599 
2600 
2602 {
2603  HANDLE_READ(a_ByteBuffer, ReadBEInt16, Int16, SlotNum);
2604  cItem Item;
2605  if (!ReadItem(a_ByteBuffer, Item))
2606  {
2607  return;
2608  }
2609  m_Client->HandleCreativeInventory(SlotNum, Item, (SlotNum == -1) ? caLeftClickOutside : caLeftClick);
2610 }
2611 
2612 
2613 
2614 
2615 
2617 {
2618  HANDLE_READ(a_ByteBuffer, ReadVarInt, UInt32, PlayerID);
2619  HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Action);
2620  HANDLE_READ(a_ByteBuffer, ReadVarInt, UInt32, JumpBoost);
2621 
2622  switch (Action)
2623  {
2624  case 0: m_Client->HandleEntityCrouch(PlayerID, true); break; // Crouch
2625  case 1: m_Client->HandleEntityCrouch(PlayerID, false); break; // Uncrouch
2626  case 2: m_Client->HandleEntityLeaveBed(PlayerID); break; // Leave Bed
2627  case 3: m_Client->HandleEntitySprinting(PlayerID, true); break; // Start sprinting
2628  case 4: m_Client->HandleEntitySprinting(PlayerID, false); break; // Stop sprinting
2629  case 7: m_Client->HandleOpenHorseInventory(PlayerID); break; // Open horse inventory
2630  }
2631 }
2632 
2633 
2634 
2635 
2636 
2638 {
2639  HANDLE_READ(a_ByteBuffer, ReadVarInt, UInt32, KeepAliveID);
2640  m_Client->HandleKeepAlive(KeepAliveID);
2641 }
2642 
2643 
2644 
2645 
2646 
2648 {
2649  HANDLE_READ(a_ByteBuffer, ReadBool, bool, IsOnGround);
2650  // TODO: m_Client->HandlePlayerOnGround(IsOnGround);
2651 }
2652 
2653 
2654 
2655 
2656 
2658 {
2659  HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Flags);
2660  HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, FlyingSpeed);
2661  HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, WalkingSpeed);
2662 
2663  // COnvert the bitfield into individual boolean flags:
2664  bool IsFlying = false, CanFly = false;
2665  if ((Flags & 2) != 0)
2666  {
2667  IsFlying = true;
2668  }
2669  if ((Flags & 4) != 0)
2670  {
2671  CanFly = true;
2672  }
2673 
2674  m_Client->HandlePlayerAbilities(CanFly, IsFlying, FlyingSpeed, WalkingSpeed);
2675 }
2676 
2677 
2678 
2679 
2680 
2682 {
2683  HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, Yaw);
2684  HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, Pitch);
2685  HANDLE_READ(a_ByteBuffer, ReadBool, bool, IsOnGround);
2686  m_Client->HandlePlayerLook(Yaw, Pitch, IsOnGround);
2687 }
2688 
2689 
2690 
2691 
2692 
2694 {
2695  HANDLE_READ(a_ByteBuffer, ReadBEDouble, double, PosX);
2696  HANDLE_READ(a_ByteBuffer, ReadBEDouble, double, PosY);
2697  HANDLE_READ(a_ByteBuffer, ReadBEDouble, double, PosZ);
2698  HANDLE_READ(a_ByteBuffer, ReadBool, bool, IsOnGround);
2699 
2701  {
2702  m_Client->HandlePlayerPos(PosX, PosY, PosZ, PosY + (m_Client->GetPlayer()->IsCrouched() ? 1.54 : 1.62), IsOnGround);
2703  }
2704 }
2705 
2706 
2707 
2708 
2709 
2711 {
2712  HANDLE_READ(a_ByteBuffer, ReadBEDouble, double, PosX);
2713  HANDLE_READ(a_ByteBuffer, ReadBEDouble, double, PosY);
2714  HANDLE_READ(a_ByteBuffer, ReadBEDouble, double, PosZ);
2715  HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, Yaw);
2716  HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, Pitch);
2717  HANDLE_READ(a_ByteBuffer, ReadBool, bool, IsOnGround);
2718 
2720  {
2721  m_Client->HandlePlayerMoveLook(PosX, PosY, PosZ, PosY + 1.62, Yaw, Pitch, IsOnGround);
2722  }
2723 }
2724 
2725 
2726 
2727 
2728 
2730 {
2731  HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Channel);
2732 
2733  // If the plugin channel is recognized vanilla, handle it directly:
2734  if (Channel.substr(0, 3) == "MC|")
2735  {
2736  HandleVanillaPluginMessage(a_ByteBuffer, Channel);
2737 
2738  // Skip any unread data (vanilla sometimes sends garbage at the end of a packet; #1692):
2739  if (a_ByteBuffer.GetReadableSpace() > 1)
2740  {
2741  LOGD("Protocol 1.8: Skipping garbage data at the end of a vanilla PluginMessage packet, %u bytes",
2742  static_cast<unsigned>(a_ByteBuffer.GetReadableSpace() - 1)
2743  );
2744  a_ByteBuffer.SkipRead(a_ByteBuffer.GetReadableSpace() - 1);
2745  }
2746 
2747  return;
2748  }
2749 
2750  // Read the plugin message and relay to clienthandle:
2751  AString Data;
2752  VERIFY(a_ByteBuffer.ReadString(Data, a_ByteBuffer.GetReadableSpace() - 1)); // Always succeeds
2753  m_Client->HandlePluginMessage(Channel, Data);
2754 }
2755 
2756 
2757 
2758 
2759 
2761 {
2762  HANDLE_READ(a_ByteBuffer, ReadBEInt16, Int16, SlotNum);
2763  m_Client->HandleSlotSelected(SlotNum);
2764 }
2765 
2766 
2767 
2768 
2769 
2771 {
2772  cUUID playerUUID;
2773  if (!a_ByteBuffer.ReadUUID(playerUUID))
2774  {
2775  return;
2776  }
2777 
2778  m_Client->HandleSpectate(playerUUID);
2779 }
2780 
2781 
2782 
2783 
2784 
2786 {
2787  HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, Sideways);
2788  HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, Forward);
2789  HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Flags);
2790 
2791  if ((Flags & 0x2) != 0)
2792  {
2794  }
2795  else if ((Flags & 0x1) != 0)
2796  {
2797  // TODO: Handle vehicle jump (for animals)
2798  }
2799  else
2800  {
2801  m_Client->HandleSteerVehicle(Forward, Sideways);
2802  }
2803 }
2804 
2805 
2806 
2807 
2808 
2810 {
2811  HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Text);
2812  HANDLE_READ(a_ByteBuffer, ReadBool, bool, AssumeCommand);
2813  HANDLE_READ(a_ByteBuffer, ReadBool, bool, HasPosition);
2814 
2815  if (HasPosition)
2816  {
2817  HANDLE_READ(a_ByteBuffer, ReadBEInt64, Int64, Position);
2818  }
2819 
2821 }
2822 
2823 
2824 
2825 
2826 
2828 {
2829  int BlockX, BlockY, BlockZ;
2830  if (!a_ByteBuffer.ReadPosition64(BlockX, BlockY, BlockZ))
2831  {
2832  return;
2833  }
2834 
2835  AString Lines[4];
2836  for (int i = 0; i < 4; i++)
2837  {
2838  HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Line);
2839  Lines[i] = Line;
2840  }
2841 
2842  m_Client->HandleUpdateSign(BlockX, BlockY, BlockZ, Lines[0], Lines[1], Lines[2], Lines[3]);
2843 }
2844 
2845 
2846 
2847 
2848 
2850 {
2851  HANDLE_READ(a_ByteBuffer, ReadVarInt, UInt32, EntityID);
2852  HANDLE_READ(a_ByteBuffer, ReadVarInt, UInt32, Type);
2853 
2854  switch (Type)
2855  {
2856  case 0:
2857  {
2858  HANDLE_READ(a_ByteBuffer, ReadVarInt, UInt32, Hand);
2859  if (Hand == MAIN_HAND) // TODO: implement handling of off-hand actions; ignore them for now to avoid processing actions twice
2860  {
2861  m_Client->HandleUseEntity(EntityID, false);
2862  }
2863  break;
2864  }
2865  case 1:
2866  {
2867  m_Client->HandleUseEntity(EntityID, true);
2868  break;
2869  }
2870  case 2:
2871  {
2872  HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, TargetX);
2873  HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, TargetY);
2874  HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, TargetZ);
2875  HANDLE_READ(a_ByteBuffer, ReadVarInt, UInt32, Hand);
2876 
2877  // TODO: Do anything
2878  break;
2879  }
2880  default:
2881  {
2882  ASSERT(!"Unhandled use entity type!");
2883  return;
2884  }
2885  }
2886 }
2887 
2888 
2889 
2890 
2891 
2893 {
2894  HANDLE_READ(a_ByteBuffer, ReadVarInt, Int32, Hand);
2895 
2897 }
2898 
2899 
2900 
2901 
2902 
2904 {
2905  HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, WindowID);
2906  HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Enchantment);
2907 
2908  m_Client->HandleEnchantItem(WindowID, Enchantment);
2909 }
2910 
2911 
2912 
2913 
2914 
2916 {
2917  // This handles updating the vehicles location server side
2918  HANDLE_READ(a_ByteBuffer, ReadBEDouble, double, xPos);
2919  HANDLE_READ(a_ByteBuffer, ReadBEDouble, double, yPos);
2920  HANDLE_READ(a_ByteBuffer, ReadBEDouble, double, zPos);
2921  HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, yaw);
2922  HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, pitch);
2923 
2924  // Get the players vehicle
2925  cEntity * Vehicle = m_Client->GetPlayer()->GetAttached();
2926 
2927  if (Vehicle)
2928  {
2929  Vehicle->SetPosX(xPos);
2930  Vehicle->SetPosY(yPos);
2931  Vehicle->SetPosZ(zPos);
2932  Vehicle->SetYaw(yaw);
2933  Vehicle->SetPitch(pitch);
2934  }
2935 }
2936 
2937 
2938 
2939 
2940 
2942 {
2943  HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, WindowID);
2944  HANDLE_READ(a_ByteBuffer, ReadBEInt16, Int16, SlotNum);
2945  HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Button);
2946  HANDLE_READ(a_ByteBuffer, ReadBEUInt16, UInt16, TransactionID);
2947  HANDLE_READ(a_ByteBuffer, ReadVarInt32, UInt32, Mode);
2948  cItem Item;
2949  ReadItem(a_ByteBuffer, Item);
2950 
2951  // Convert Button, Mode, SlotNum and HeldItem into eClickAction:
2952  eClickAction Action;
2953  switch ((Mode << 8) | Button)
2954  {
2955  case 0x0000: Action = (SlotNum != SLOT_NUM_OUTSIDE) ? caLeftClick : caLeftClickOutside; break;
2956  case 0x0001: Action = (SlotNum != SLOT_NUM_OUTSIDE) ? caRightClick : caRightClickOutside; break;
2957  case 0x0100: Action = caShiftLeftClick; break;
2958  case 0x0101: Action = caShiftRightClick; break;
2959  case 0x0200: Action = caNumber1; break;
2960  case 0x0201: Action = caNumber2; break;
2961  case 0x0202: Action = caNumber3; break;
2962  case 0x0203: Action = caNumber4; break;
2963  case 0x0204: Action = caNumber5; break;
2964  case 0x0205: Action = caNumber6; break;
2965  case 0x0206: Action = caNumber7; break;
2966  case 0x0207: Action = caNumber8; break;
2967  case 0x0208: Action = caNumber9; break;
2968  case 0x0302: Action = caMiddleClick; break;
2969  case 0x0400: Action = (SlotNum == SLOT_NUM_OUTSIDE) ? caLeftClickOutsideHoldNothing : caDropKey; break;
2970  case 0x0401: Action = (SlotNum == SLOT_NUM_OUTSIDE) ? caRightClickOutsideHoldNothing : caCtrlDropKey; break;
2971  case 0x0500: Action = (SlotNum == SLOT_NUM_OUTSIDE) ? caLeftPaintBegin : caUnknown; break;
2972  case 0x0501: Action = (SlotNum != SLOT_NUM_OUTSIDE) ? caLeftPaintProgress : caUnknown; break;
2973  case 0x0502: Action = (SlotNum == SLOT_NUM_OUTSIDE) ? caLeftPaintEnd : caUnknown; break;
2974  case 0x0504: Action = (SlotNum == SLOT_NUM_OUTSIDE) ? caRightPaintBegin : caUnknown; break;
2975  case 0x0505: Action = (SlotNum != SLOT_NUM_OUTSIDE) ? caRightPaintProgress : caUnknown; break;
2976  case 0x0506: Action = (SlotNum == SLOT_NUM_OUTSIDE) ? caRightPaintEnd : caUnknown; break;
2977  case 0x0508: Action = (SlotNum == SLOT_NUM_OUTSIDE) ? caMiddlePaintBegin : caUnknown; break;
2978  case 0x0509: Action = (SlotNum != SLOT_NUM_OUTSIDE) ? caMiddlePaintProgress : caUnknown; break;
2979  case 0x050a: Action = (SlotNum == SLOT_NUM_OUTSIDE) ? caMiddlePaintEnd : caUnknown; break;
2980  case 0x0600: Action = caDblClick; break;
2981  default:
2982  {
2983  LOGWARNING("Unhandled window click mode / button combination: %d (0x%x)", (Mode << 8) | Button, (Mode << 8) | Button);
2984  Action = caUnknown;
2985  break;
2986  }
2987  }
2988 
2989  m_Client->HandleWindowClick(WindowID, SlotNum, Action, Item);
2990 }
2991 
2992 
2993 
2994 
2995 
2997 {
2998  HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, WindowID);
2999  m_Client->HandleWindowClose(WindowID);
3000 }
3001 
3002 
3003 
3004 
3005 
3006 void cProtocol_1_9_0::HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const AString & a_Channel)
3007 {
3008  if (a_Channel == "MC|AdvCdm")
3009  {
3010  HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Mode);
3011  switch (Mode)
3012  {
3013  case 0x00:
3014  {
3015  HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, BlockX);
3016  HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, BlockY);
3017  HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, BlockZ);
3018  HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Command);
3019  m_Client->HandleCommandBlockBlockChange(BlockX, BlockY, BlockZ, Command);
3020  break;
3021  }
3022 
3023  default:
3024  {
3025  m_Client->SendChat(Printf("Failure setting command block command; unhandled mode %u (0x%02x)", Mode, Mode), mtFailure);
3026  LOG("Unhandled MC|AdvCdm packet mode.");
3027  return;
3028  }
3029  } // switch (Mode)
3030  return;
3031  }
3032  else if (a_Channel == "MC|Brand")
3033  {
3034  HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Brand);
3035  m_Client->SetClientBrand(Brand);
3036  // Send back our brand, including the length:
3037  SendPluginMessage("MC|Brand", "\x08""Cuberite");
3038  return;
3039  }
3040  else if (a_Channel == "MC|Beacon")
3041  {
3042  HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, Effect1);
3043  HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, Effect2);
3044  m_Client->HandleBeaconSelection(Effect1, Effect2);
3045  return;
3046  }
3047  else if (a_Channel == "MC|ItemName")
3048  {
3049  HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, ItemName);
3050  m_Client->HandleAnvilItemName(ItemName);
3051  return;
3052  }
3053  else if (a_Channel == "MC|TrSel")
3054  {
3055  HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, SlotNum);
3056  m_Client->HandleNPCTrade(SlotNum);
3057  return;
3058  }
3059  LOG("Unhandled vanilla plugin channel: \"%s\".", a_Channel.c_str());
3060 
3061  // Read the payload and send it through to the clienthandle:
3062  AString Message;
3063  VERIFY(a_ByteBuffer.ReadString(Message, a_ByteBuffer.GetReadableSpace() - 1));
3064  m_Client->HandlePluginMessage(a_Channel, Message);
3065 }
3066 
3067 
3068 
3069 
3070 
3071 void cProtocol_1_9_0::SendData(const char * a_Data, size_t a_Size)
3072 {
3073  if (m_IsEncrypted)
3074  {
3075  Byte Encrypted[8192]; // Larger buffer, we may be sending lots of data (chunks)
3076  while (a_Size > 0)
3077  {
3078  size_t NumBytes = (a_Size > sizeof(Encrypted)) ? sizeof(Encrypted) : a_Size;
3079  m_Encryptor.ProcessData(Encrypted, reinterpret_cast<const Byte *>(a_Data), NumBytes);
3080  m_Client->SendData(reinterpret_cast<const char *>(Encrypted), NumBytes);
3081  a_Size -= NumBytes;
3082  a_Data += NumBytes;
3083  }
3084  }
3085  else
3086  {
3087  m_Client->SendData(a_Data, a_Size);
3088  }
3089 }
3090 
3091 
3092 
3093 
3094 
3095 bool cProtocol_1_9_0::ReadItem(cByteBuffer & a_ByteBuffer, cItem & a_Item, size_t a_KeepRemainingBytes)
3096 {
3097  HANDLE_PACKET_READ(a_ByteBuffer, ReadBEInt16, Int16, ItemType);
3098  if (ItemType == -1)
3099  {
3100  // The item is empty, no more data follows
3101  a_Item.Empty();
3102  return true;
3103  }
3104  a_Item.m_ItemType = ItemType;
3105 
3106  HANDLE_PACKET_READ(a_ByteBuffer, ReadBEInt8, Int8, ItemCount);
3107  HANDLE_PACKET_READ(a_ByteBuffer, ReadBEInt16, Int16, ItemDamage);
3108  a_Item.m_ItemCount = ItemCount;
3109  a_Item.m_ItemDamage = ItemDamage;
3110  if (ItemCount <= 0)
3111  {
3112  a_Item.Empty();
3113  }
3114 
3115  AString Metadata;
3116  if (!a_ByteBuffer.ReadString(Metadata, a_ByteBuffer.GetReadableSpace() - a_KeepRemainingBytes - 1) || (Metadata.size() == 0) || (Metadata[0] == 0))
3117  {
3118  // No metadata
3119  return true;
3120  }
3121 
3122  ParseItemMetadata(a_Item, Metadata);
3123  return true;
3124 }
3125 
3126 
3127 
3128 
3129 
3130 void cProtocol_1_9_0::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata)
3131 {
3132  // Parse into NBT:
3133  cParsedNBT NBT(a_Metadata.data(), a_Metadata.size());
3134  if (!NBT.IsValid())
3135  {
3136  AString HexDump;
3137  CreateHexDump(HexDump, a_Metadata.data(), std::max<size_t>(a_Metadata.size(), 1024), 16);
3138  LOGWARNING("Cannot parse NBT item metadata: %s at (%zu / %zu bytes)\n%s",
3139  NBT.GetErrorCode().message().c_str(), NBT.GetErrorPos(), a_Metadata.size(), HexDump.c_str()
3140  );
3141  return;
3142  }
3143 
3144  // Load enchantments and custom display names from the NBT data:
3145  for (int tag = NBT.GetFirstChild(NBT.GetRoot()); tag >= 0; tag = NBT.GetNextSibling(tag))
3146  {
3147  AString TagName = NBT.GetName(tag);
3148  switch (NBT.GetType(tag))
3149  {
3150  case TAG_List:
3151  {
3152  if ((TagName == "ench") || (TagName == "StoredEnchantments")) // Enchantments tags
3153  {
3155  }
3156  break;
3157  }
3158  case TAG_Compound:
3159  {
3160  if (TagName == "display") // Custom name and lore tag
3161  {
3162  for (int displaytag = NBT.GetFirstChild(tag); displaytag >= 0; displaytag = NBT.GetNextSibling(displaytag))
3163  {
3164  if ((NBT.GetType(displaytag) == TAG_String) && (NBT.GetName(displaytag) == "Name")) // Custon name tag
3165  {
3166  a_Item.m_CustomName = NBT.GetString(displaytag);
3167  }
3168  else if ((NBT.GetType(displaytag) == TAG_List) && (NBT.GetName(displaytag) == "Lore")) // Lore tag
3169  {
3170  a_Item.m_LoreTable.clear();
3171  for (int loretag = NBT.GetFirstChild(displaytag); loretag >= 0; loretag = NBT.GetNextSibling(loretag)) // Loop through array of strings
3172  {
3173  a_Item.m_LoreTable.push_back(NBT.GetString(loretag));
3174  }
3175  }
3176  else if ((NBT.GetType(displaytag) == TAG_Int) && (NBT.GetName(displaytag) == "color"))
3177  {
3178  a_Item.m_ItemColor.m_Color = static_cast<unsigned int>(NBT.GetInt(displaytag));
3179  }
3180  }
3181  }
3182  else if ((TagName == "Fireworks") || (TagName == "Explosion"))
3183  {
3184  cFireworkItem::ParseFromNBT(a_Item.m_FireworkItem, NBT, tag, static_cast<ENUM_ITEM_ID>(a_Item.m_ItemType));
3185  }
3186  else if (TagName == "EntityTag")
3187  {
3188  for (int entitytag = NBT.GetFirstChild(tag); entitytag >= 0; entitytag = NBT.GetNextSibling(entitytag))
3189  {
3190  if ((NBT.GetType(entitytag) == TAG_String) && (NBT.GetName(entitytag) == "id"))
3191  {
3192  AString NBTName = NBT.GetString(entitytag);
3193  ReplaceString(NBTName, "minecraft:", "");
3194  eMonsterType MonsterType = cMonster::StringToMobType(NBTName);
3195  a_Item.m_ItemDamage = static_cast<short>(MonsterType);
3196 
3197  }
3198  }
3199  }
3200  break;
3201  }
3202  case TAG_Int:
3203  {
3204  if (TagName == "RepairCost")
3205  {
3206  a_Item.m_RepairCost = NBT.GetInt(tag);
3207  }
3208  break;
3209  }
3210  case TAG_String:
3211  {
3212  if (TagName == "Potion")
3213  {
3214  AString PotionEffect = NBT.GetString(tag);
3215  if (PotionEffect.find("minecraft:") == AString::npos)
3216  {
3217  LOGD("Unknown or missing domain on potion effect name %s!", PotionEffect.c_str());
3218  continue;
3219  }
3220 
3221  if (PotionEffect.find("water") != AString::npos)
3222  {
3223  a_Item.m_ItemDamage = 0;
3224  // Water bottles shouldn't have other bits set on them; exit early.
3225  continue;
3226  }
3227  if (PotionEffect.find("empty") != AString::npos)
3228  {
3229  a_Item.m_ItemDamage = 0;
3230  }
3231  else if (PotionEffect.find("mundane") != AString::npos)
3232  {
3233  a_Item.m_ItemDamage = 0;
3234  }
3235  else if (PotionEffect.find("thick") != AString::npos)
3236  {
3237  a_Item.m_ItemDamage = 32;
3238  }
3239  else if (PotionEffect.find("awkward") != AString::npos)
3240  {
3241  a_Item.m_ItemDamage = 16;
3242  }
3243  else if (PotionEffect.find("regeneration") != AString::npos)
3244  {
3245  a_Item.m_ItemDamage = 1;
3246  }
3247  else if (PotionEffect.find("swiftness") != AString::npos)
3248  {
3249  a_Item.m_ItemDamage = 2;
3250  }
3251  else if (PotionEffect.find("fire_resistance") != AString::npos)
3252  {
3253  a_Item.m_ItemDamage = 3;
3254  }
3255  else if (PotionEffect.find("poison") != AString::npos)
3256  {
3257  a_Item.m_ItemDamage = 4;
3258  }
3259  else if (PotionEffect.find("healing") != AString::npos)
3260  {
3261  a_Item.m_ItemDamage = 5;
3262  }
3263  else if (PotionEffect.find("night_vision") != AString::npos)
3264  {
3265  a_Item.m_ItemDamage = 6;
3266  }
3267  else if (PotionEffect.find("weakness") != AString::npos)
3268  {
3269  a_Item.m_ItemDamage = 8;
3270  }
3271  else if (PotionEffect.find("strength") != AString::npos)
3272  {
3273  a_Item.m_ItemDamage = 9;
3274  }
3275  else if (PotionEffect.find("slowness") != AString::npos)
3276  {
3277  a_Item.m_ItemDamage = 10;
3278  }
3279  else if (PotionEffect.find("leaping") != AString::npos)
3280  {
3281  a_Item.m_ItemDamage = 11;
3282  }
3283  else if (PotionEffect.find("harming") != AString::npos)
3284  {
3285  a_Item.m_ItemDamage = 12;
3286  }
3287  else if (PotionEffect.find("water_breathing") != AString::npos)
3288  {
3289  a_Item.m_ItemDamage = 13;
3290  }
3291  else if (PotionEffect.find("invisibility") != AString::npos)
3292  {
3293  a_Item.m_ItemDamage = 14;
3294  }
3295  else
3296  {
3297  // Note: luck potions are not handled and will reach this location
3298  LOGD("Unknown potion type for effect name %s!", PotionEffect.c_str());
3299  continue;
3300  }
3301 
3302  if (PotionEffect.find("strong") != AString::npos)
3303  {
3304  a_Item.m_ItemDamage |= 0x20;
3305  }
3306  if (PotionEffect.find("long") != AString::npos)
3307  {
3308  a_Item.m_ItemDamage |= 0x40;
3309  }
3310 
3311  // Ugly special case with the changed splash potion ID in 1.9
3312  if ((a_Item.m_ItemType == 438) || (a_Item.m_ItemType == 441))
3313  {
3314  // Splash or lingering potions - change the ID to the normal one and mark as splash potions
3315  a_Item.m_ItemType = E_ITEM_POTION;
3316  a_Item.m_ItemDamage |= 0x4000; // Is splash potion
3317  }
3318  else
3319  {
3320  a_Item.m_ItemDamage |= 0x2000; // Is drinkable
3321  }
3322  }
3323  break;
3324  }
3325  default: LOGD("Unimplemented NBT data when parsing!"); break;
3326  }
3327  }
3328 }
3329 
3330 
3331 
3332 
3333 
3335 {
3336  m_Encryptor.Init(a_Key, a_Key);
3337  m_Decryptor.Init(a_Key, a_Key);
3338  m_IsEncrypted = true;
3339 
3340  // Prepare the m_AuthServerID:
3341  cSha1Checksum Checksum;
3342  cServer * Server = cRoot::Get()->GetServer();
3343  const AString & ServerID = Server->GetServerID();
3344  Checksum.Update(reinterpret_cast<const Byte *>(ServerID.c_str()), ServerID.length());
3345  Checksum.Update(a_Key, 16);
3346  Checksum.Update(reinterpret_cast<const Byte *>(Server->GetPublicKeyDER().data()), Server->GetPublicKeyDER().size());
3347  Byte Digest[20];
3348  Checksum.Finalize(Digest);
3350 }
3351 
3352 
3353 
3354 
3355 
3357 {
3358  // Normalize the blockface values returned from the protocol
3359  // Anything known gets mapped 1:1, everything else returns BLOCK_FACE_NONE
3360  switch (a_BlockFace)
3361  {
3362  case BLOCK_FACE_XM: return BLOCK_FACE_XM;
3363  case BLOCK_FACE_XP: return BLOCK_FACE_XP;
3364  case BLOCK_FACE_YM: return BLOCK_FACE_YM;
3365  case BLOCK_FACE_YP: return BLOCK_FACE_YP;
3366  case BLOCK_FACE_ZM: return BLOCK_FACE_ZM;
3367  case BLOCK_FACE_ZP: return BLOCK_FACE_ZP;
3368  default: return BLOCK_FACE_NONE;
3369  }
3370 }
3371 
3372 
3373 
3374 
3375 
3377 {
3378  // Convert hand parameter into eHand enum
3379  switch (a_Hand)
3380  {
3381  case MAIN_HAND: return eHand::hMain;
3382  case OFF_HAND: return eHand::hOff;
3383  default:
3384  {
3385  ASSERT(!"Unknown hand value");
3386  return eHand::hMain;
3387  }
3388  }
3389 }
3390 
3391 
3392 
3393 
3394 
3396 {
3397  UInt32 PacketLen = static_cast<UInt32>(m_OutPacketBuffer.GetUsedSpace());
3398  AString PacketData, CompressedPacket;
3399  m_OutPacketBuffer.ReadAll(PacketData);
3401 
3402  if ((m_State == 3) && (PacketLen >= 256))
3403  {
3404  // Compress the packet payload:
3405  if (!cProtocol_1_9_0::CompressPacket(PacketData, CompressedPacket))
3406  {
3407  return;
3408  }
3409  }
3410  else if (m_State == 3)
3411  {
3412  // The packet is not compressed, indicate this in the packet header:
3413  m_OutPacketLenBuffer.WriteVarInt32(PacketLen + 1);
3415  AString LengthData;
3416  m_OutPacketLenBuffer.ReadAll(LengthData);
3417  SendData(LengthData.data(), LengthData.size());
3418  }
3419  else
3420  {
3421  // Compression doesn't apply to this state, send raw data:
3423  AString LengthData;
3424  m_OutPacketLenBuffer.ReadAll(LengthData);
3425  SendData(LengthData.data(), LengthData.size());
3426  }
3427 
3428  // Send the packet's payload, either direct or compressed:
3429  if (CompressedPacket.empty())
3430  {
3432  SendData(PacketData.data(), PacketData.size());
3433  }
3434  else
3435  {
3436  SendData(CompressedPacket.data(), CompressedPacket.size());
3437  }
3438 
3439  // Log the comm into logfile:
3441  {
3442  AString Hex;
3443  ASSERT(PacketData.size() > 0);
3444  CreateHexDump(Hex, PacketData.data(), PacketData.size(), 16);
3445  m_CommLogFile.Printf("Outgoing packet: type %s (translated to 0x%02x), length %u (0x%04x), state %d. Payload (incl. type):\n%s\n",
3447  PacketLen, PacketLen, m_State, Hex
3448  );
3449  /*
3450  // Useful for debugging a new protocol:
3451  LOGD("Outgoing packet: type %s (translated to 0x%02x), length %u (0x%04x), state %d. Payload (incl. type):\n%s\n",
3452  cPacketizer::PacketTypeToStr(a_Pkt.GetPacketType()), GetPacketID(a_Pkt.GetPacketType()),
3453  PacketLen, PacketLen, m_State, Hex
3454  );
3455  //*/
3456  }
3457  /*
3458  // Useful for debugging a new protocol:
3459  std::this_thread::sleep_for(std::chrono::milliseconds(100));
3460  */
3461 }
3462 
3463 
3464 
3465 
3466 
3467 void cProtocol_1_9_0::WriteItem(cPacketizer & a_Pkt, const cItem & a_Item)
3468 {
3469  short ItemType = a_Item.m_ItemType;
3470  ASSERT(ItemType >= -1); // Check validity of packets in debug runtime
3471  if (ItemType <= 0)
3472  {
3473  // Fix, to make sure no invalid values are sent.
3474  ItemType = -1;
3475  }
3476 
3477  if (a_Item.IsEmpty())
3478  {
3479  a_Pkt.WriteBEInt16(-1);
3480  return;
3481  }
3482 
3483  if ((ItemType == E_ITEM_POTION) && ((a_Item.m_ItemDamage & 0x4000) != 0))
3484  {
3485  // Ugly special case for splash potion ids which changed in 1.9; this can be removed when the new 1.9 ids are implemented
3486  a_Pkt.WriteBEInt16(438); // minecraft:splash_potion
3487  }
3488  else
3489  {
3490  // Normal item
3491  a_Pkt.WriteBEInt16(ItemType);
3492  }
3493  a_Pkt.WriteBEInt8(a_Item.m_ItemCount);
3494  if ((ItemType == E_ITEM_POTION) || (ItemType == E_ITEM_SPAWN_EGG))
3495  {
3496  // These items lost their metadata; if it is sent they don't render correctly.
3497  a_Pkt.WriteBEInt16(0);
3498  }
3499  else
3500  {
3501  a_Pkt.WriteBEInt16(a_Item.m_ItemDamage);
3502  }
3503 
3504  if (a_Item.m_Enchantments.IsEmpty() && a_Item.IsBothNameAndLoreEmpty() && (ItemType != E_ITEM_FIREWORK_ROCKET) && (ItemType != E_ITEM_FIREWORK_STAR) && !a_Item.m_ItemColor.IsValid() && (ItemType != E_ITEM_POTION) && (ItemType != E_ITEM_SPAWN_EGG))
3505  {
3506  a_Pkt.WriteBEInt8(0);
3507  return;
3508  }
3509 
3510 
3511  // Send the enchantments and custom names:
3512  cFastNBTWriter Writer;
3513  if (a_Item.m_RepairCost != 0)
3514  {
3515  Writer.AddInt("RepairCost", a_Item.m_RepairCost);
3516  }
3517  if (!a_Item.m_Enchantments.IsEmpty())
3518  {
3519  const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench";
3521  }
3522  if (!a_Item.IsBothNameAndLoreEmpty() || a_Item.m_ItemColor.IsValid())
3523  {
3524  Writer.BeginCompound("display");
3525  if (a_Item.m_ItemColor.IsValid())
3526  {
3527  Writer.AddInt("color", static_cast<Int32>(a_Item.m_ItemColor.m_Color));
3528  }
3529 
3530  if (!a_Item.IsCustomNameEmpty())
3531  {
3532  Writer.AddString("Name", a_Item.m_CustomName.c_str());
3533  }
3534  if (!a_Item.IsLoreEmpty())
3535  {
3536  Writer.BeginList("Lore", TAG_String);
3537 
3538  for (const auto & Line : a_Item.m_LoreTable)
3539  {
3540  Writer.AddString("", Line);
3541  }
3542 
3543  Writer.EndList();
3544  }
3545  Writer.EndCompound();
3546  }
3547  if ((a_Item.m_ItemType == E_ITEM_FIREWORK_ROCKET) || (a_Item.m_ItemType == E_ITEM_FIREWORK_STAR))
3548  {
3549  cFireworkItem::WriteToNBTCompound(a_Item.m_FireworkItem, Writer, static_cast<ENUM_ITEM_ID>(a_Item.m_ItemType));
3550  }
3551  if (a_Item.m_ItemType == E_ITEM_POTION)
3552  {
3553  // 1.9 potions use a different format. In the future (when only 1.9+ is supported) this should be its own class
3554  AString PotionID = "empty"; // Fallback of "Uncraftable potion" for unhandled cases
3555 
3557  if (Type != cEntityEffect::effNoEffect)
3558  {
3559  switch (Type)
3560  {
3561  case cEntityEffect::effRegeneration: PotionID = "regeneration"; break;
3562  case cEntityEffect::effSpeed: PotionID = "swiftness"; break;
3563  case cEntityEffect::effFireResistance: PotionID = "fire_resistance"; break;
3564  case cEntityEffect::effPoison: PotionID = "poison"; break;
3565  case cEntityEffect::effInstantHealth: PotionID = "healing"; break;
3566  case cEntityEffect::effNightVision: PotionID = "night_vision"; break;
3567  case cEntityEffect::effWeakness: PotionID = "weakness"; break;
3568  case cEntityEffect::effStrength: PotionID = "strength"; break;
3569  case cEntityEffect::effSlowness: PotionID = "slowness"; break;
3570  case cEntityEffect::effJumpBoost: PotionID = "leaping"; break;
3571  case cEntityEffect::effInstantDamage: PotionID = "harming"; break;
3572  case cEntityEffect::effWaterBreathing: PotionID = "water_breathing"; break;
3573  case cEntityEffect::effInvisibility: PotionID = "invisibility"; break;
3574  default: ASSERT(!"Unknown potion effect"); break;
3575  }
3577  {
3578  PotionID = "strong_" + PotionID;
3579  }
3580  else if (a_Item.m_ItemDamage & 0x40)
3581  {
3582  // Extended potion bit
3583  PotionID = "long_" + PotionID;
3584  }
3585  }
3586  else
3587  {
3588  // Empty potions: Water bottles and other base ones
3589  if (a_Item.m_ItemDamage == 0)
3590  {
3591  // No other bits set; thus it's a water bottle
3592  PotionID = "water";
3593  }
3594  else
3595  {
3596  switch (a_Item.m_ItemDamage & 0x3f)
3597  {
3598  case 0x00: PotionID = "mundane"; break;
3599  case 0x10: PotionID = "awkward"; break;
3600  case 0x20: PotionID = "thick"; break;
3601  }
3602  // Default cases will use "empty" from before.
3603  }
3604  }
3605 
3606  PotionID = "minecraft:" + PotionID;
3607 
3608  Writer.AddString("Potion", PotionID.c_str());
3609  }
3610  if (a_Item.m_ItemType == E_ITEM_SPAWN_EGG)
3611  {
3612  // Convert entity ID to the name.
3614  if (MonsterType != eMonsterType::mtInvalidType)
3615  {
3616  Writer.BeginCompound("EntityTag");
3617  Writer.AddString("id", "minecraft:" + cMonster::MobTypeToVanillaNBT(MonsterType));
3618  Writer.EndCompound();
3619  }
3620  }
3621 
3622  Writer.Finish();
3623 
3624  AString Result = Writer.GetResult();
3625  if (Result.size() == 0)
3626  {
3627  a_Pkt.WriteBEInt8(0);
3628  return;
3629  }
3630  a_Pkt.WriteBuf(Result.data(), Result.size());
3631 }
3632 
3633 
3634 
3635 
3636 
3637 void cProtocol_1_9_0::WriteBlockEntity(cPacketizer & a_Pkt, const cBlockEntity & a_BlockEntity)
3638 {
3639  cFastNBTWriter Writer;
3640 
3641  switch (a_BlockEntity.GetBlockType())
3642  {
3643  case E_BLOCK_BEACON:
3644  {
3645  auto & BeaconEntity = static_cast<const cBeaconEntity &>(a_BlockEntity);
3646  Writer.AddInt("x", BeaconEntity.GetPosX());
3647  Writer.AddInt("y", BeaconEntity.GetPosY());
3648  Writer.AddInt("z", BeaconEntity.GetPosZ());
3649  Writer.AddInt("Primary", BeaconEntity.GetPrimaryEffect());
3650  Writer.AddInt("Secondary", BeaconEntity.GetSecondaryEffect());
3651  Writer.AddInt("Levels", BeaconEntity.GetBeaconLevel());
3652  Writer.AddString("id", "Beacon"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though
3653  break;
3654  }
3655 
3656  case E_BLOCK_COMMAND_BLOCK:
3657  {
3658  auto & CommandBlockEntity = static_cast<const cCommandBlockEntity &>(a_BlockEntity);
3659  Writer.AddByte("TrackOutput", 1); // Neither I nor the MC wiki has any idea about this
3660  Writer.AddInt("SuccessCount", CommandBlockEntity.GetResult());
3661  Writer.AddInt("x", CommandBlockEntity.GetPosX());
3662  Writer.AddInt("y", CommandBlockEntity.GetPosY());
3663  Writer.AddInt("z", CommandBlockEntity.GetPosZ());
3664  Writer.AddString("Command", CommandBlockEntity.GetCommand().c_str());
3665  // You can set custom names for windows in Vanilla
3666  // For a command block, this would be the 'name' prepended to anything it outputs into global chat
3667  // MCS doesn't have this, so just leave it @ '@'. (geddit?)
3668  Writer.AddString("CustomName", "@");
3669  Writer.AddString("id", "Control"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though
3670  if (!CommandBlockEntity.GetLastOutput().empty())
3671  {
3672  Writer.AddString("LastOutput", Printf("{\"text\":\"%s\"}", CommandBlockEntity.GetLastOutput().c_str()));
3673  }
3674  break;
3675  }
3676 
3677  case E_BLOCK_HEAD:
3678  {
3679  auto & MobHeadEntity = static_cast<const cMobHeadEntity &>(a_BlockEntity);
3680  Writer.AddInt("x", MobHeadEntity.GetPosX());
3681  Writer.AddInt("y", MobHeadEntity.GetPosY());
3682  Writer.AddInt("z", MobHeadEntity.GetPosZ());
3683  Writer.AddByte("SkullType", MobHeadEntity.GetType() & 0xFF);
3684  Writer.AddByte("Rot", MobHeadEntity.GetRotation() & 0xFF);
3685  Writer.AddString("id", "Skull"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though
3686 
3687  // The new Block Entity format for a Mob Head. See: https://minecraft.gamepedia.com/Head#Block_entity
3688  Writer.BeginCompound("Owner");
3689  Writer.AddString("Id", MobHeadEntity.GetOwnerUUID().ToShortString());
3690  Writer.AddString("Name", MobHeadEntity.GetOwnerName());
3691  Writer.BeginCompound("Properties");
3692  Writer.BeginList("textures", TAG_Compound);
3693  Writer.BeginCompound("");
3694  Writer.AddString("Signature", MobHeadEntity.GetOwnerTextureSignature());
3695  Writer.AddString("Value", MobHeadEntity.GetOwnerTexture());
3696  Writer.EndCompound();
3697  Writer.EndList();
3698  Writer.EndCompound();
3699  Writer.EndCompound();
3700  break;
3701  }
3702 
3703  case E_BLOCK_FLOWER_POT:
3704  {
3705  auto & FlowerPotEntity = static_cast<const cFlowerPotEntity &>(a_BlockEntity);
3706  Writer.AddInt("x", FlowerPotEntity.GetPosX());
3707  Writer.AddInt("y", FlowerPotEntity.GetPosY());
3708  Writer.AddInt("z", FlowerPotEntity.GetPosZ());
3709  Writer.AddInt("Item", static_cast<Int32>(FlowerPotEntity.GetItem().m_ItemType));
3710  Writer.AddInt("Data", static_cast<Int32>(FlowerPotEntity.GetItem().m_ItemDamage));
3711  Writer.AddString("id", "FlowerPot"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though
3712  break;
3713  }
3714 
3715  case E_BLOCK_MOB_SPAWNER:
3716  {
3717  auto & MobSpawnerEntity = static_cast<const cMobSpawnerEntity &>(a_BlockEntity);
3718  Writer.AddInt("x", MobSpawnerEntity.GetPosX());
3719  Writer.AddInt("y", MobSpawnerEntity.GetPosY());
3720  Writer.AddInt("z", MobSpawnerEntity.GetPosZ());
3721  Writer.BeginCompound("SpawnData");
3722  Writer.AddString("id", cMonster::MobTypeToVanillaName(MobSpawnerEntity.GetEntity()));
3723  Writer.EndCompound();
3724  Writer.AddShort("Delay", MobSpawnerEntity.GetSpawnDelay());
3725  Writer.AddString("id", "MobSpawner");
3726  break;
3727  }
3728 
3729  default:
3730  {
3731  break;
3732  }
3733  }
3734 
3735  Writer.Finish();
3736  a_Pkt.WriteBuf(Writer.GetResult().data(), Writer.GetResult().size());
3737 }
3738 
3739 
3740 
3741 
3742 
3744 {
3745  // Common metadata:
3746  Int8 Flags = 0;
3747  if (a_Entity.IsOnFire())
3748  {
3749  Flags |= 0x01;
3750  }
3751  if (a_Entity.IsCrouched())
3752  {
3753  Flags |= 0x02;
3754  }
3755  if (a_Entity.IsSprinting())
3756  {
3757  Flags |= 0x08;
3758  }
3759  if (a_Entity.IsRclking())
3760  {
3761  Flags |= 0x10;
3762  }
3763  if (a_Entity.IsInvisible())
3764  {
3765  Flags |= 0x20;
3766  }
3767  a_Pkt.WriteBEUInt8(0); // Index 0
3768  a_Pkt.WriteBEUInt8(METADATA_TYPE_BYTE); // Type
3769  a_Pkt.WriteBEInt8(Flags);
3770 
3771  switch (a_Entity.GetEntityType())
3772  {
3773  case cEntity::etPlayer:
3774  {
3775  auto & Player = static_cast<const cPlayer &>(a_Entity);
3776 
3777  // TODO Set player custom name to their name.
3778  // Then it's possible to move the custom name of mobs to the entities
3779  // and to remove the "special" player custom name.
3780  a_Pkt.WriteBEUInt8(2); // Index 2: Custom name
3782  a_Pkt.WriteString(Player.GetName());
3783 
3784  a_Pkt.WriteBEUInt8(6); // Index 6: Health
3786  a_Pkt.WriteBEFloat(static_cast<float>(Player.GetHealth()));
3787 
3788  a_Pkt.WriteBEUInt8(12);
3790  a_Pkt.WriteBEUInt8(static_cast<UInt8>(Player.GetSkinParts()));
3791 
3792  a_Pkt.WriteBEUInt8(13);
3794  a_Pkt.WriteBEUInt8(static_cast<UInt8>(Player.GetMainHand()));
3795  break;
3796  }
3797  case cEntity::etPickup:
3798  {
3799  a_Pkt.WriteBEUInt8(5); // Index 5: Item
3801  WriteItem(a_Pkt, static_cast<const cPickup &>(a_Entity).GetItem());
3802  break;
3803  }
3804  case cEntity::etMinecart:
3805  {
3806  a_Pkt.WriteBEUInt8(5); // Index 5: Shaking power
3808 
3809  // The following expression makes Minecarts shake more with less health or higher damage taken
3810  auto & Minecart = static_cast<const cMinecart &>(a_Entity);
3811  auto maxHealth = a_Entity.GetMaxHealth();
3812  auto curHealth = a_Entity.GetHealth();
3813  a_Pkt.WriteVarInt32(static_cast<UInt32>((maxHealth - curHealth) * Minecart.LastDamage() * 4));
3814 
3815  a_Pkt.WriteBEUInt8(6); // Index 6: Shaking direction (doesn't seem to effect anything)
3817  a_Pkt.WriteVarInt32(1);
3818 
3819  a_Pkt.WriteBEUInt8(7); // Index 7: Shake multiplier / damage taken
3821  a_Pkt.WriteBEFloat(static_cast<float>(Minecart.LastDamage() + 10));
3822 
3823  if (Minecart.GetPayload() == cMinecart::mpNone)
3824  {
3825  auto & RideableMinecart = static_cast<const cRideableMinecart &>(Minecart);
3826  const cItem & MinecartContent = RideableMinecart.GetContent();
3827  if (!MinecartContent.IsEmpty())
3828  {
3829  a_Pkt.WriteBEUInt8(8); // Index 8: Block ID and damage
3831  int Content = MinecartContent.m_ItemType;
3832  Content |= MinecartContent.m_ItemDamage << 8;
3833  a_Pkt.WriteVarInt32(static_cast<UInt32>(Content));
3834 
3835  a_Pkt.WriteBEUInt8(9); // Index 9: Block ID and damage
3837  a_Pkt.WriteVarInt32(static_cast<UInt32>(RideableMinecart.GetBlockHeight()));
3838 
3839  a_Pkt.WriteBEUInt8(10); // Index 10: Show block
3841  a_Pkt.WriteBool(true);
3842  }
3843  }
3844  else if (Minecart.GetPayload() == cMinecart::mpFurnace)
3845  {
3846  a_Pkt.WriteBEUInt8(11); // Index 11: Is powered
3848  a_Pkt.WriteBool(static_cast<const cMinecartWithFurnace &>(Minecart).IsFueled());
3849  }
3850  break;
3851  } // case etMinecart
3852 
3853  case cEntity::etProjectile:
3854  {
3855  auto & Projectile = static_cast<const cProjectileEntity &>(a_Entity);
3856  switch (Projectile.GetProjectileKind())
3857  {
3859  {
3860  a_Pkt.WriteBEUInt8(5); // Index 5: Is critical
3862  a_Pkt.WriteBEInt8(static_cast<const cArrowEntity &>(Projectile).IsCritical() ? 1 : 0);
3863  break;
3864  }
3866  {
3867  a_Pkt.WriteBEUInt8(5); // Index 5: Firework item used for this firework
3869  WriteItem(a_Pkt, static_cast<const cFireworkEntity &>(Projectile).GetItem());
3870  break;
3871  }
3873  {
3874  a_Pkt.WriteBEUInt8(5); // Index 5: Potion item which was thrown
3876  WriteItem(a_Pkt, static_cast<const cSplashPotionEntity &>(Projectile).GetItem());
3877  }
3878  default:
3879  {
3880  break;
3881  }
3882  }
3883  break;
3884  } // case etProjectile
3885 
3886  case cEntity::etMonster:
3887  {
3888  WriteMobMetadata(a_Pkt, static_cast<const cMonster &>(a_Entity));
3889  break;
3890  }
3891 
3892  case cEntity::etBoat:
3893  {
3894  auto & Boat = static_cast<const cBoat &>(a_Entity);
3895 
3896  a_Pkt.WriteBEInt8(5); // Index 6: Time since last hit
3898  a_Pkt.WriteVarInt32(static_cast<UInt32>(Boat.GetLastDamage()));
3899 
3900  a_Pkt.WriteBEInt8(6); // Index 7: Forward direction
3902  a_Pkt.WriteVarInt32(static_cast<UInt32>(Boat.GetForwardDirection()));
3903 
3904  a_Pkt.WriteBEInt8(7); // Index 8: Damage taken
3906  a_Pkt.WriteBEFloat(Boat.GetDamageTaken());
3907 
3908  a_Pkt.WriteBEInt8(8); // Index 9: Type
3910  a_Pkt.WriteVarInt32(static_cast<UInt32>(Boat.GetMaterial()));
3911 
3912  a_Pkt.WriteBEInt8(9); // Index 10: Right paddle turning
3914  a_Pkt.WriteBool(Boat.IsRightPaddleUsed());
3915 
3916  a_Pkt.WriteBEInt8(10); // Index 11: Left paddle turning
3918  a_Pkt.WriteBool(Boat.IsLeftPaddleUsed());
3919 
3920  break;
3921  } // case etBoat
3922 
3923  case cEntity::etItemFrame:
3924  {
3925  auto & Frame = static_cast<const cItemFrame &>(a_Entity);
3926  a_Pkt.WriteBEUInt8(5); // Index 5: Item
3928  WriteItem(a_Pkt, Frame.GetItem());
3929  a_Pkt.WriteBEUInt8(6); // Index 6: Rotation
3931  a_Pkt.WriteVarInt32(Frame.GetItemRotation());
3932  break;
3933  } // case etItemFrame
3934 
3935  default:
3936  {
3937  break;
3938  }
3939  }
3940 }
3941 
3942 
3943 
3944 
3945 
3947 {
3948  // Living Enitiy Metadata
3949  if (a_Mob.HasCustomName())
3950  {
3951  // TODO: As of 1.9 _all_ entities can have custom names; should this be moved up?
3952  a_Pkt.WriteBEUInt8(2); // Index 2: Custom name
3954  a_Pkt.WriteString(a_Mob.GetCustomName());
3955 
3956  a_Pkt.WriteBEUInt8(3); // Index 3: Custom name always visible
3958  a_Pkt.WriteBool(a_Mob.IsCustomNameAlwaysVisible());
3959  }
3960 
3961  a_Pkt.WriteBEUInt8(6); // Index 6: Health
3963  a_Pkt.WriteBEFloat(static_cast<float>(a_Mob.GetHealth()));
3964 
3965  switch (a_Mob.GetMobType())
3966  {
3967  case mtBat:
3968  {
3969  auto & Bat = static_cast<const cBat &>(a_Mob);
3970  a_Pkt.WriteBEUInt8(11); // Index 11: Bat flags - currently only hanging
3972  a_Pkt.WriteBEInt8(Bat.IsHanging() ? 1 : 0);
3973  break;
3974  } // case mtBat
3975 
3976  case mtChicken:
3977  {
3978  auto & Chicken = static_cast<const cChicken &>(a_Mob);
3979 
3980  a_Pkt.WriteBEUInt8(11); // Index 11: Is baby
3982  a_Pkt.WriteBool(Chicken.IsBaby());
3983  break;
3984  } // case mtChicken
3985 
3986  case mtCow:
3987  {
3988  auto & Cow = static_cast<const cCow &>(a_Mob);
3989 
3990  a_Pkt.WriteBEUInt8(11); // Index 11: Is baby
3992  a_Pkt.WriteBool(Cow.IsBaby());
3993  break;
3994  } // case mtCow
3995 
3996  case mtCreeper:
3997  {
3998  auto & Creeper = static_cast<const cCreeper &>(a_Mob);
3999  a_Pkt.WriteBEUInt8(11); // Index 11: State (idle or "blowing")
4001  a_Pkt.WriteVarInt32(Creeper.IsBlowing() ? 1 : 0xffffffff);
4002 
4003  a_Pkt.WriteBEUInt8(12); // Index 12: Is charged
4005  a_Pkt.WriteBool(Creeper.IsCharged());
4006 
4007  a_Pkt.WriteBEUInt8(13); // Index 13: Is ignited
4009  a_Pkt.WriteBool(Creeper.IsBurnedWithFlintAndSteel());
4010  break;
4011  } // case mtCreeper
4012 
4013  case mtEnderman:
4014  {
4015  auto & Enderman = static_cast<const cEnderman &>(a_Mob);
4016  a_Pkt.WriteBEUInt8(11); // Index 11: Carried block
4018  UInt32 Carried = 0;
4019  Carried |= static_cast<UInt32>(Enderman.GetCarriedBlock() << 4);
4020  Carried |= Enderman.GetCarriedMeta();
4021  a_Pkt.WriteVarInt32(Carried);
4022 
4023  a_Pkt.WriteBEUInt8(12); // Index 12: Is screaming
4025  a_Pkt.WriteBool(Enderman.IsScreaming());
4026  break;
4027  } // case mtEnderman
4028 
4029  case mtGhast:
4030  {
4031  auto & Ghast = static_cast<const cGhast &>(a_Mob);
4032  a_Pkt.WriteBEUInt8(11); // Is attacking
4034  a_Pkt.WriteBool(Ghast.IsCharging());
4035  break;
4036  } // case mtGhast
4037 
4038  case mtHorse:
4039  {
4040  auto & Horse = static_cast<const cHorse &>(a_Mob);
4041  Int8 Flags = 0;
4042  if (Horse.IsTame())
4043  {
4044  Flags |= 0x02;
4045  }
4046  if (Horse.IsSaddled())
4047  {
4048  Flags |= 0x04;
4049  }
4050  if (Horse.IsChested())
4051  {
4052  Flags |= 0x08;
4053  }
4054  if (Horse.IsEating())
4055  {
4056  Flags |= 0x20;
4057  }
4058  if (Horse.IsRearing())
4059  {
4060  Flags |= 0x40;
4061  }
4062  if (Horse.IsMthOpen())
4063  {
4064  Flags |= 0x80;
4065  }
4066  a_Pkt.WriteBEUInt8(12); // Index 12: flags
4068  a_Pkt.WriteBEInt8(Flags);
4069 
4070  a_Pkt.WriteBEUInt8(13); // Index 13: Variant / type
4072  a_Pkt.WriteVarInt32(static_cast<UInt32>(Horse.GetHorseType()));
4073 
4074  a_Pkt.WriteBEUInt8(14); // Index 14: Color / style
4076  int Appearance = 0;
4077  Appearance = Horse.GetHorseColor();
4078  Appearance |= Horse.GetHorseStyle() << 8;
4079  a_Pkt.WriteVarInt32(static_cast<UInt32>(Appearance));
4080 
4081  a_Pkt.WriteBEUInt8(16); // Index 16: Armor
4083  a_Pkt.WriteVarInt32(static_cast<UInt32>(Horse.GetHorseArmour()));
4084 
4085  a_Pkt.WriteBEUInt8(11); // Index 11: Is baby
4087  a_Pkt.WriteBool(Horse.IsBaby());
4088  break;
4089  } // case mtHorse
4090 
4091  case mtMagmaCube:
4092  {
4093  auto & MagmaCube = static_cast<const cMagmaCube &>(a_Mob);
4094  a_Pkt.WriteBEUInt8(11); // Index 11: Size
4096  a_Pkt.WriteVarInt32(static_cast<UInt32>(MagmaCube.GetSize()));
4097  break;
4098  } // case mtMagmaCube
4099 
4100  case mtOcelot:
4101  {
4102  auto & Ocelot = static_cast<const cOcelot &>(a_Mob);
4103 
4104  a_Pkt.WriteBEUInt8(11); // Index 11: Is baby
4106  a_Pkt.WriteBool(Ocelot.IsBaby());
4107  break;
4108  } // case mtOcelot
4109 
4110  case mtPig:
4111  {
4112  auto & Pig = static_cast<const cPig &>(a_Mob);
4113 
4114  a_Pkt.WriteBEUInt8(11); // Index 11: Is baby
4116  a_Pkt.WriteBool(Pig.IsBaby());
4117 
4118  a_Pkt.WriteBEUInt8(12); // Index 12: Is saddled
4120  a_Pkt.WriteBool(Pig.IsSaddled());
4121 
4122  break;
4123  } // case mtPig
4124 
4125  case mtRabbit:
4126  {
4127  auto & Rabbit = static_cast<const cRabbit &>(a_Mob);
4128  a_Pkt.WriteBEUInt8(11); // Index 11: Is baby
4130  a_Pkt.WriteBool(Rabbit.IsBaby());
4131 
4132  a_Pkt.WriteBEUInt8(12); // Index 12: Type
4134  a_Pkt.WriteVarInt32(static_cast<UInt32>(Rabbit.GetRabbitType()));
4135  break;
4136  } // case mtRabbit
4137 
4138  case mtSheep:
4139  {
4140  auto & Sheep = static_cast<const cSheep &>(a_Mob);
4141 
4142  a_Pkt.WriteBEUInt8(11); // Index 11: Is baby
4144  a_Pkt.WriteBool(Sheep.IsBaby());
4145 
4146  a_Pkt.WriteBEUInt8(12); // Index 12: sheared, color
4148  Int8 SheepMetadata = 0;
4149  SheepMetadata = static_cast<Int8>(Sheep.GetFurColor());
4150  if (Sheep.IsSheared())
4151  {
4152  SheepMetadata |= 0x10;
4153  }
4154  a_Pkt.WriteBEInt8(SheepMetadata);
4155  break;
4156  } // case mtSheep
4157 
4158  case mtSkeleton:
4159  {
4160  auto & Skeleton = static_cast<const cSkeleton &>(a_Mob);
4161  a_Pkt.WriteBEUInt8(11); // Index 11: Type
4163  a_Pkt.WriteVarInt32(Skeleton.IsWither() ? 1 : 0);
4164  break;
4165  } // case mtSkeleton
4166 
4167  case mtSlime:
4168  {
4169  auto & Slime = static_cast<const cSlime &>(a_Mob);
4170  a_Pkt.WriteBEUInt8(11); // Index 11: Size
4172  a_Pkt.WriteVarInt32(static_cast<UInt32>(Slime.GetSize()));
4173  break;
4174  } // case mtSlime
4175 
4176  case mtVillager:
4177  {
4178  auto & Villager = static_cast<const cVillager &>(a_Mob);
4179  a_Pkt.WriteBEUInt8(11); // Index 11: Is baby
4181  a_Pkt.WriteBool(Villager.IsBaby());
4182 
4183  a_Pkt.WriteBEUInt8(12); // Index 12: Type
4185  a_Pkt.WriteVarInt32(static_cast<UInt32>(Villager.GetVilType()));
4186  break;
4187  } // case mtVillager
4188 
4189  case mtWitch:
4190  {
4191  auto & Witch = static_cast<const cWitch &>(a_Mob);
4192  a_Pkt.WriteBEUInt8(11); // Index 11: Is angry
4194  a_Pkt.WriteBool(Witch.IsAngry());
4195  break;
4196  } // case mtWitch
4197 
4198  case mtWither:
4199  {
4200  auto & Wither = static_cast<const cWither &>(a_Mob);
4201  a_Pkt.WriteBEUInt8(14); // Index 14: Invulnerable ticks
4203  a_Pkt.WriteVarInt32(Wither.GetWitherInvulnerableTicks());
4204 
4205  // TODO: Use boss bar packet for health
4206  break;
4207  } // case mtWither
4208 
4209  case mtWolf:
4210  {
4211  auto & Wolf = static_cast<const cWolf &>(a_Mob);
4212  a_Pkt.WriteBEUInt8(11); // Index 11: Is baby
4214  a_Pkt.WriteBool(Wolf.IsBaby());
4215 
4216  Int8 WolfStatus = 0;
4217  if (Wolf.IsSitting())
4218  {
4219  WolfStatus |= 0x1;
4220  }
4221  if (Wolf.IsAngry())
4222  {
4223  WolfStatus |= 0x2;
4224  }
4225  if (Wolf.IsTame())
4226  {
4227  WolfStatus |= 0x4;
4228  }
4229  a_Pkt.WriteBEUInt8(12); // Index 12: status
4231  a_Pkt.WriteBEInt8(WolfStatus);
4232 
4233  a_Pkt.WriteBEUInt8(14); // Index 14: Health
4235  a_Pkt.WriteBEFloat(static_cast<float>(a_Mob.GetHealth()));
4236 
4237  a_Pkt.WriteBEUInt8(15); // Index 15: Is begging
4239  a_Pkt.WriteBool(Wolf.IsBegging());
4240 
4241  a_Pkt.WriteBEUInt8(16); // Index 16: Collar color
4243  a_Pkt.WriteVarInt32(static_cast<UInt32>(Wolf.GetCollarColor()));
4244  break;
4245  } // case mtWolf
4246 
4247  case mtZombie:
4248  {
4249  auto & Zombie = static_cast<const cZombie &>(a_Mob);
4250  a_Pkt.WriteBEUInt8(11); // Index 11: Is baby
4252  a_Pkt.WriteBool(Zombie.IsBaby());
4253 
4254  a_Pkt.WriteBEUInt8(12); // Index 12: Is a villager
4256  a_Pkt.WriteVarInt32(Zombie.IsVillagerZombie() ? 1 : 0); // TODO: This actually encodes the zombie villager profession, but that isn't implemented yet.
4257 
4258  a_Pkt.WriteBEUInt8(13); // Index 13: Is converting
4260  a_Pkt.WriteBool(Zombie.IsConverting());
4261  break;
4262  } // case mtZombie
4263 
4264  case mtZombiePigman:
4265  {
4266  auto & ZombiePigman = static_cast<const cZombiePigman &>(a_Mob);
4267  a_Pkt.WriteBEUInt8(11); // Index 11: Is baby
4269  a_Pkt.WriteBool(ZombiePigman.IsBaby());
4270  break;
4271  } // case mtZombiePigman
4272 
4273  default: break;
4274  } // switch (a_Mob.GetType())
4275 }
4276 
4277 
4278 
4279 
4280 
4282 {
4283  if (!a_Entity.IsMob())
4284  {
4285  // No properties for anything else than mobs
4286  a_Pkt.WriteBEInt32(0);
4287  return;
4288  }
4289 
4290  // const cMonster & Mob = (const cMonster &)a_Entity;
4291 
4292  // TODO: Send properties and modifiers based on the mob type
4293 
4294  a_Pkt.WriteBEInt32(0); // NumProperties
4295 }
4296 
4297 
4298 
4299 
4300 
4302 // cProtocol_1_9_1:
4303 
4304 cProtocol_1_9_1::cProtocol_1_9_1(cClientHandle * a_Client, const AString & a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State) :
4305  Super(a_Client, a_ServerAddress, a_ServerPort, a_State)
4306 {
4307 }
4308 
4309 
4310 
4311 
4312 
4313 void cProtocol_1_9_1::SendLogin(const cPlayer & a_Player, const cWorld & a_World)
4314 {
4315  // Send the Join Game packet:
4316  {
4317  cServer * Server = cRoot::Get()->GetServer();
4318  cPacketizer Pkt(*this, pktJoinGame);
4319  Pkt.WriteBEUInt32(a_Player.GetUniqueID());
4320  Pkt.WriteBEUInt8(static_cast<UInt8>(a_Player.GetEffectiveGameMode()) | (Server->IsHardcore() ? 0x08 : 0)); // Hardcore flag bit 4
4321  Pkt.WriteBEInt32(static_cast<Int32>(a_World.GetDimension())); // This is the change from 1.9.0 (Int8 to Int32)
4322  Pkt.WriteBEUInt8(2); // TODO: Difficulty (set to Normal)
4323  Pkt.WriteBEUInt8(static_cast<UInt8>(Clamp<size_t>(Server->GetMaxPlayers(), 0, 255)));
4324  Pkt.WriteString("default"); // Level type - wtf?
4325  Pkt.WriteBool(false); // Reduced Debug Info - wtf?
4326  }
4327 
4328  // Send the spawn position:
4329  {
4330  cPacketizer Pkt(*this, pktSpawnPosition);
4331  Pkt.WritePosition64(FloorC(a_World.GetSpawnX()), FloorC(a_World.GetSpawnY()), FloorC(a_World.GetSpawnZ()));
4332  }
4333 
4334  // Send the server difficulty:
4335  {
4336  cPacketizer Pkt(*this, pktDifficulty);
4337  Pkt.WriteBEInt8(1);
4338  }
4339 
4340  // Send player abilities:
4342 }
4343 
4344 
4345 
4346 
4347 
4349 {
4350  cServer * Server = cRoot::Get()->GetServer();
4351  AString ServerDescription = Server->GetDescription();
4352  auto NumPlayers = static_cast<signed>(Server->GetNumPlayers());
4353  auto MaxPlayers = static_cast<signed>(Server->GetMaxPlayers());
4354  AString Favicon = Server->GetFaviconData();
4355  cRoot::Get()->GetPluginManager()->CallHookServerPing(*m_Client, ServerDescription, NumPlayers, MaxPlayers, Favicon);
4356 
4357  // Version:
4358  Json::Value Version;
4359  Version["name"] = "Cuberite 1.9.1";
4360  Version["protocol"] = 108;
4361 
4362  // Players:
4363  Json::Value Players;
4364  Players["online"] = NumPlayers;
4365  Players["max"] = MaxPlayers;
4366  // TODO: Add "sample"
4367 
4368  // Description:
4369  Json::Value Description;
4370  Description["text"] = ServerDescription.c_str();
4371 
4372  // Create the response:
4373  Json::Value ResponseValue;
4374  ResponseValue["version"] = Version;
4375  ResponseValue["players"] = Players;
4376  ResponseValue["description"] = Description;
4377  m_Client->ForgeAugmentServerListPing(ResponseValue);
4378  if (!Favicon.empty())
4379  {
4380  ResponseValue["favicon"] = Printf("data:image/png;base64,%s", Favicon.c_str());
4381  }
4382 
4383  Json::FastWriter Writer;
4384  AString Response = Writer.write(ResponseValue);
4385 
4386  cPacketizer Pkt(*this, pktStatusResponse);
4387  Pkt.WriteString(Response);
4388 }
4389 
4390 
4391 
4392 
4393 
4395 // cProtocol_1_9_2:
4396 
4397 cProtocol_1_9_2::cProtocol_1_9_2(cClientHandle * a_Client, const AString & a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State) :
4398  Super(a_Client, a_ServerAddress, a_ServerPort, a_State)
4399 {
4400 }
4401 
4402 
4403 
4404 
4405 
4407 {
4408  cServer * Server = cRoot::Get()->GetServer();
4409  AString ServerDescription = Server->GetDescription();
4410  auto NumPlayers = static_cast<signed>(Server->GetNumPlayers());
4411  auto MaxPlayers = static_cast<signed>(Server->GetMaxPlayers());
4412  AString Favicon = Server->GetFaviconData();
4413  cRoot::Get()->GetPluginManager()->CallHookServerPing(*m_Client, ServerDescription, NumPlayers, MaxPlayers, Favicon);
4414 
4415  // Version:
4416  Json::Value Version;
4417  Version["name"] = "Cuberite 1.9.2";
4418  Version["protocol"] = 109;
4419 
4420  // Players:
4421  Json::Value Players;
4422  Players["online"] = NumPlayers;
4423  Players["max"] = MaxPlayers;
4424  // TODO: Add "sample"
4425 
4426  // Description:
4427  Json::Value Description;
4428  Description["text"] = ServerDescription.c_str();
4429 
4430  // Create the response:
4431  Json::Value ResponseValue;
4432  ResponseValue["version"] = Version;
4433  ResponseValue["players"] = Players;
4434  ResponseValue["description"] = Description;
4435  m_Client->ForgeAugmentServerListPing(ResponseValue);
4436  if (!Favicon.empty())
4437  {
4438  ResponseValue["favicon"] = Printf("data:image/png;base64,%s", Favicon.c_str());
4439  }
4440 
4441  Json::FastWriter Writer;
4442  AString Response = Writer.write(ResponseValue);
4443 
4444  cPacketizer Pkt(*this, pktStatusResponse);
4445  Pkt.WriteString(Response);
4446 }
4447 
4448 
4449 
4450 
4451 
4453 // cProtocol_1_9_4:
4454 
4455 cProtocol_1_9_4::cProtocol_1_9_4(cClientHandle * a_Client, const AString & a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State) :
4456  Super(a_Client, a_ServerAddress, a_ServerPort, a_State)
4457 {
4458 }
4459 
4460 
4461 
4462 
4463 
4465 {
4466  cServer * Server = cRoot::Get()->GetServer();
4467  AString ServerDescription = Server->GetDescription();
4468  auto NumPlayers = static_cast<signed>(Server->GetNumPlayers());
4469  auto MaxPlayers = static_cast<signed>(Server->GetMaxPlayers());
4470  AString Favicon = Server->GetFaviconData();
4471  cRoot::Get()->GetPluginManager()->CallHookServerPing(*m_Client, ServerDescription, NumPlayers, MaxPlayers, Favicon);
4472 
4473  // Version:
4474  Json::Value Version;
4475  Version["name"] = "Cuberite 1.9.4";
4476  Version["protocol"] = 110;
4477 
4478  // Players:
4479  Json::Value Players;
4480  Players["online"] = NumPlayers;
4481  Players["max"] = MaxPlayers;
4482  // TODO: Add "sample"
4483 
4484  // Description:
4485  Json::Value Description;
4486  Description["text"] = ServerDescription.c_str();
4487 
4488  // Create the response:
4489  Json::Value ResponseValue;
4490  ResponseValue["version"] = Version;
4491  ResponseValue["players"] = Players;
4492  ResponseValue["description"] = Description;
4493  m_Client->ForgeAugmentServerListPing(ResponseValue);
4494  if (!Favicon.empty())
4495  {
4496  ResponseValue["favicon"] = Printf("data:image/png;base64,%s", Favicon.c_str());
4497  }
4498 
4499  Json::FastWriter Writer;
4500  AString Response = Writer.write(ResponseValue);
4501 
4502  cPacketizer Pkt(*this, pktStatusResponse);
4503  Pkt.WriteString(Response);
4504 }
4505 
4506 
4507 
4508 
4509 
4510 void cProtocol_1_9_4::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer)
4511 {
4512  ASSERT(m_State == 3); // In game mode?
4513 
4514  // Serialize first, before creating the Packetizer (the packetizer locks a CS)
4515  // This contains the flags and bitmasks, too
4516  const AString & ChunkData = a_Serializer.Serialize(cChunkDataSerializer::RELEASE_1_9_4, a_ChunkX, a_ChunkZ, {});
4517 
4518  cCSLock Lock(m_CSPacket);
4519  SendData(ChunkData.data(), ChunkData.size());
4520 }
4521 
4522 
4523 
4524 
4525 
4526 void cProtocol_1_9_4::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)
4527 {
4528  ASSERT(m_State == 3); // In game mode?
4529 
4530  // 1.9.4 removed the update sign packet and now uses Update Block Entity
4531  cPacketizer Pkt(*this, pktUpdateBlockEntity);
4532  Pkt.WritePosition64(a_BlockX, a_BlockY, a_BlockZ);
4533  Pkt.WriteBEUInt8(9); // Action 9 - update sign
4534 
4535  cFastNBTWriter Writer;
4536  Writer.AddInt("x", a_BlockX);
4537  Writer.AddInt("y", a_BlockY);
4538  Writer.AddInt("z", a_BlockZ);
4539  Writer.AddString("id", "Sign");
4540 
4541  Json::StyledWriter JsonWriter;
4542  Json::Value Line1;
4543  Line1["text"] = a_Line1;
4544  Writer.AddString("Text1", JsonWriter.write(Line1));
4545  Json::Value Line2;
4546  Line2["text"] = a_Line2;
4547  Writer.AddString("Text2", JsonWriter.write(Line2));
4548  Json::Value Line3;
4549  Line3["text"] = a_Line3;
4550  Writer.AddString("Text3", JsonWriter.write(Line3));
4551  Json::Value Line4;
4552  Line4["text"] = a_Line4;
4553  Writer.AddString("Text4", JsonWriter.write(Line4));
4554 
4555  Writer.Finish();
4556  Pkt.WriteBuf(Writer.GetResult().data(), Writer.GetResult().size());
4557 }
4558 
4559 
4560 
4561 
4562 
4564 {
4565  switch (a_Packet)
4566  {
4567  case pktCollectEntity: return 0x48;
4568  case pktEntityEffect: return 0x4b;
4569  case pktEntityProperties: return 0x4a;
4570  case pktPlayerMaxSpeed: return 0x4a;
4571  case pktTeleportEntity: return 0x49;
4572 
4573  default: return Super::GetPacketID(a_Packet);
4574  }
4575 }
eType
All types of entity effects (numbers correspond to protocol / storage types)
Definition: EntityEffect.h:11
cProtocol::ePacketType GetPacketType() const
Definition: Packetizer.h:143
static int GetParticleID(const AString &a_ParticleName)
The 1.8 protocol use a particle id instead of a string.
AString ToLongString() const
Converts the UUID to a long form string (i.e.
Definition: UUID.cpp:151
double GetPosY(void) const
Definition: Entity.h:207
virtual void HandlePacketEnchantItem(cByteBuffer &a_ByteBuffer)
virtual void SendScoreUpdate(const AString &a_Objective, const AString &a_Player, cObjective::Score a_Score, Byte a_Mode) override
virtual void SendSpawnVehicle(const cEntity &a_Vehicle, char a_VehicleType, char a_VehicleSubType) override
virtual void HandlePacketPlayerLook(cByteBuffer &a_ByteBuffer)
void Finalize(Checksum &a_Output)
Calculates and returns the final checksum.
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+)
bool WriteVarInt32(UInt32 a_Value)
Definition: ByteBuffer.cpp:660
void HandleCreativeInventory(Int16 a_SlotNum, const cItem &a_HeldItem, eClickAction a_ClickAction)
Called when the client clicks the creative inventory window.
void HandleWindowClick(UInt8 a_WindowID, Int16 a_SlotNum, eClickAction a_ClickAction, const cItem &a_HeldItem)
virtual void HandlePacketPlayer(cByteBuffer &a_ByteBuffer)
#define HANDLE_PACKET_READ(ByteBuf, Proc, Type, Var)
void ReadAll(AString &a_Data)
Reads all available data into a_Data.
Definition: ByteBuffer.cpp:849
void WriteToNBTCompound(const cEnchantments &a_Enchantments, cFastNBTWriter &a_Writer, const AString &a_ListTagName)
Writes the enchantments into the specified NBT writer; begins with the LIST tag of the specified name...
virtual void HandlePacketKeepAlive(cByteBuffer &a_ByteBuffer)
bool m_IsTeleportIdConfirmed
The current teleport ID, and whether it has been confirmed by the client.
Definition: Protocol_1_9.h:157
UInt32 m_State
State of the protocol.
Definition: Protocol_1_9.h:154
double GetPitch(void) const
Definition: Entity.h:210
Byte GetProtocolFacing() const
Returns the direction in which the entity is facing.
Definition: HangingEntity.h:38
Definition: Rabbit.h:25
virtual void SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) override
virtual void HandlePacketUpdateSign(cByteBuffer &a_ByteBuffer)
virtual void WriteEntityMetadata(cPacketizer &a_Pkt, const cEntity &a_Entity)
Writes the metadata for the specified entity, not including the terminating 0xff. ...
void WriteBEInt8(Int8 a_Value)
Definition: Packetizer.h:56
eGameMode
Definition: Defines.h:116
double GetPosX(void) const
Definition: Entity.h:206
eDimension
Dimension of a world.
Definition: BlockID.h:1127
void EndList(void)
Definition: FastNBT.cpp:519
StatValue GetValue(const eStatistic a_Stat) const
Return the value of the specified stat.
Definition: Statistics.cpp:150
void Init(const Byte a_Key[16], const Byte a_IV[16])
Initializes the decryptor with the specified Key / IV.
T x
Definition: Vector3.h:17
void HandleRespawn(void)
eEntityType GetEntityType(void) const
Definition: Entity.h:168
void HandleEnchantItem(UInt8 a_WindowID, UInt8 a_Enchantment)
Called when the player enchants an Item in the Enchanting table UI.
eMonsterType GetMobType(void) const
Definition: Monster.h:68
void HandleKeepAlive(UInt32 a_KeepAliveID)
eWeather
Definition: Defines.h:151
int GetXpLevel(void)
Gets the current level - XpLevel.
Definition: Player.cpp:469
bool IsBothNameAndLoreEmpty(void) const
Definition: Item.h:142
static cEntityEffect::eType GetPotionEffectType(short a_ItemDamage)
Translates the potion&#39;s damage value into the entity effect that the potion gives.
virtual bool IsCrouched(void) const override
Definition: Player.h:568
virtual void HandlePacketStatusRequest(cByteBuffer &a_ByteBuffer)
void ParseItemMetadata(cItem &a_Item, const AString &a_Metadata)
Parses item metadata as read by ReadItem(), into the item enchantments.
Definition: ExpOrb.h:11
Definition: Witch.h:10
void HandleAnimation(int a_Animation)
size_t GetReadableSpace(void) const
Returns the number of bytes that are currently available for reading (may be less than UsedSpace due ...
Definition: ByteBuffer.cpp:194
const Json::Value & GetProperties(void) const
Definition: ClientHandle.h:85
virtual void SendPluginMessage(const AString &a_Channel, const AString &a_Message) override
virtual void SendData(const char *a_Data, size_t a_Size) override
Sends the data to the client, encrypting them if needed.
virtual void SendEntityEffect(const cEntity &a_Entity, int a_EffectID, int a_Amplifier, int a_Duration) override
virtual bool CanFly(void) const
Returns wheter the player can fly or not.
Definition: Player.h:526
Definition: Defines.h:209
void HandlePlayerAbilities(bool a_CanFly, bool a_IsFlying, float FlyingSpeed, float WalkingSpeed)
BLOCKTYPE GetBlockType() const
Definition: BlockEntity.h:111
Class that manages the statistics and achievements of a single player.
Definition: Statistics.h:127
#define VERIFY(x)
Definition: Globals.h:339
short m_ItemDamage
Definition: Item.h:211
void HandleUnmount(void)
signed char Int8
Definition: Globals.h:110
const AString & GetWindowTitle() const
Definition: Window.h:140
double GetHeadYaw(void) const
Definition: Entity.h:203
const AString & GetCustomName(void) const
Gets the custom name of the monster.
Definition: Monster.h:162
eHand HandIntToEnum(Int32 a_Hand)
Converts the hand parameter received by the protocol into eHand constants.
Definition: Boat.h:18
double GetSpeedX(void) const
Definition: Entity.h:213
cProtocol_1_9_2(cClientHandle *a_Client, const AString &a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State)
int GetEquippedSlotNum(void)
Returns slot number of equiped item.
Definition: Inventory.h:149
virtual void SendEntityVelocity(const cEntity &a_Entity) override
void WriteUUID(const cUUID &a_UUID)
Writes the specified UUID as a 128-bit BigEndian integer.
Definition: Packetizer.cpp:44
int GetPosY() const
Definition: BlockEntity.h:106
const AString GetWindowTypeName(void) const
Returns the textual representation of the window&#39;s type, such as "minecraft:chest".
Definition: Window.cpp:64
void HandleOpenHorseInventory(UInt32 a_EntityID)
Handles a player opening their inventory while riding a horse.
AString m_ServerAddress
Definition: Protocol_1_9.h:147
cClientHandlePtr GetClientHandlePtr(void) const
Returns the SharedPtr to client handle associated with the player.
Definition: Player.h:259
unsigned int AwardAchievement(const eStatistic a_Ach)
Awards the player an achievement.
Definition: Player.cpp:1605
int m_RepairCost
Definition: Item.h:221
signed short Int16
Definition: Globals.h:109
eBlockFace FaceIntToBlockFace(Int32 a_FaceInt)
Converts the BlockFace received by the protocol into eBlockFace constants.
virtual void HandlePacketBlockDig(cByteBuffer &a_ByteBuffer)
bool ReadVarUTF8String(AString &a_Value)
Definition: ByteBuffer.cpp:436
virtual void SendSoundParticleEffect(const EffectID a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override
int GetWindowType(void) const
Definition: Window.h:81
unsigned char BLOCKTYPE
The datatype used by blockdata.
Definition: ChunkDef.h:42
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 SendSetRawTitle(const AString &a_Title) override
void Init(const Byte a_Key[16], const Byte a_IV[16])
Initializes the decryptor with the specified Key / IV.
cAesCfb128Encryptor m_Encryptor
Definition: Protocol_1_9.h:166
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 HandlePacketPlayerPosLook(cByteBuffer &a_ByteBuffer)
Encapsulates an in-game world map.
Definition: Map.h:80
void UpdatePaddles(bool rightPaddleUsed, bool leftPaddleUsed)
Definition: Boat.cpp:167
virtual void SendPlayerListUpdateDisplayName(const cPlayer &a_Player, const AString &a_CustomName) override
bool FromString(const AString &a_StringUUID)
Tries to interpret the string as a short or long form UUID and assign from it.
Definition: UUID.cpp:102
virtual void HandlePacketStatusPing(cByteBuffer &a_ByteBuffer)
void WriteBuf(const char *a_Data, size_t a_Size)
Definition: Packetizer.h:122
virtual void SendUpdateBlockEntity(cBlockEntity &a_BlockEntity) override
static void WriteToNBTCompound(const cFireworkItem &a_FireworkItem, cFastNBTWriter &a_Writer, const ENUM_ITEM_ID a_Type)
Writes firework NBT data to a Writer object.
virtual void SendDestroyEntity(const cEntity &a_Entity) override
eChatType
Definition: Defines.h:140
void ProcessData(Byte *a_EncryptedOut, const Byte *a_PlainIn, size_t a_Length)
Encrypts a_Length bytes of the plain data; produces a_Length output bytes.
static AString PacketTypeToStr(cProtocol::ePacketType a_PacketType)
Returns the human-readable representation of the packet type.
Definition: Packetizer.cpp:56
cProtocol_1_9_0(cClientHandle *a_Client, const AString &a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State)
virtual void SendHealth(void) override
static bool CreateFolder(const AString &a_FolderPath)
Creates a new folder with the specified name.
Definition: File.cpp:454
virtual void WriteItem(cPacketizer &a_Pkt, const cItem &a_Item)
Writes the item data into a packet.
virtual void SendHeldItemChange(int a_ItemIndex) override
cColor m_ItemColor
Definition: Item.h:223
Parses and contains the parsed data Also implements data accessor functions for tree traversal and va...
Definition: FastNBT.h:152
void AddShort(const AString &a_Name, Int16 a_Value)
Definition: FastNBT.cpp:544
virtual void HandlePacketBoatSteer(cByteBuffer &a_ByteBuffer)
void HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, eHand a_Hand)
AString GetPlayerListName(void) const
Returns the name that is used in the playerlist.
Definition: Player.cpp:1888
void GetSlots(cPlayer &a_Player, cItems &a_Slots) const
Fills a_Slots with the slots read from m_SlotAreas[], for the specified player.
Definition: Window.cpp:173
virtual void SendPlayerListRemovePlayer(const cPlayer &a_Player) override
Definition: Player.h:27
virtual UInt32 GetPacketID(ePacketType a_Packet) override
Get the packet ID for a given packet.
cCriticalSection m_CSPacket
Provides synchronization for sending the entire packet at once.
Definition: Protocol.h:249
static const Int16 SLOT_NUM_OUTSIDE
The slot number that the client uses to indicate "outside the window".
virtual void HandlePacketClientStatus(cByteBuffer &a_ByteBuffer)
Definition: Ocelot.h:11
bool ReadString(AString &a_String, size_t a_Count)
Reads a_Count bytes into a_String; returns true if successful.
Definition: ByteBuffer.cpp:799
void SetSkinParts(int a_Parts)
Definition: Player.cpp:2838
virtual void SendTitleTimes(int a_FadeInTicks, int a_DisplayTicks, int a_FadeOutTicks) override
virtual void SendChatRaw(const AString &a_MessageRaw, eChatType a_Type) override
const AString & GetPublicKeyDER(void) const
Definition: Server.h:132
Definition: Defines.h:208
cFireworkItem m_FireworkItem
Definition: Item.h:222
bool ReadUUID(cUUID &a_Value)
Definition: ByteBuffer.cpp:500
virtual void SendStatistics(const cStatManager &a_Manager) override
bool IsEmpty(void) const
Definition: Item.h:116
virtual void HandlePacketWindowClick(cByteBuffer &a_ByteBuffer)
Definition: Cow.h:10
int Printf(const char *a_Fmt, fmt::ArgList)
Definition: File.cpp:695
virtual void SendSetTitle(const cCompositeChat &a_Title) override
void WriteBEInt16(Int16 a_Value)
Definition: Packetizer.h:62
virtual void HandlePacketPlayerAbilities(cByteBuffer &a_ByteBuffer)
Definition: Bat.h:10
int GetFoodLevel(void) const
Definition: Player.h:322
virtual bool IsOnFire(void) const
Definition: Entity.h:486
virtual void HandlePacketClientSettings(cByteBuffer &a_ByteBuffer)
void PacketUnknown(UInt32 a_PacketType)
void HandleSteerVehicle(float Forward, float Sideways)
bool CallHookServerPing(cClientHandle &a_ClientHandle, AString &a_ServerDescription, int &a_OnlinePlayersCount, int &a_MaxPlayersCount, AString &a_Favicon)
bool HasCustomName(void) const
Returns true if the monster has a custom name.
Definition: Monster.h:159
int GetPosX() const
Definition: BlockEntity.h:105
bool IsValid() const
Returns whether the color is a valid color.
Definition: Color.h:28
bool IsMob(void) const
Definition: Entity.h:173
#define HANDLE_READ(ByteBuf, Proc, Type, Var)
void AddByte(const AString &a_Name, unsigned char a_Value)
Definition: FastNBT.cpp:534
virtual void SendWholeInventory(const cWindow &a_Window) override
virtual bool HandlePacket(cByteBuffer &a_ByteBuffer, UInt32 a_PacketType)
Reads and handles the packet.
bool ShouldAuthenticate(void) const
Returns true if authentication has been turned on in server settings.
Definition: Server.h:135
void HandleWindowClose(UInt8 a_WindowID)
int GetPosZ() const
Definition: BlockEntity.h:107
virtual void HandlePacketUseItem(cByteBuffer &a_ByteBuffer)
int Decrypt(const Byte *a_EncryptedData, size_t a_EncryptedLength, Byte *a_DecryptedData, size_t a_DecryptedMaxLength)
Decrypts the data using RSAES-PKCS#1 algorithm.
virtual void SendPlayerPosition(void) override
void WriteBEUInt8(UInt8 a_Value)
Definition: Packetizer.h:50
BLOCKTYPE GetBlockType(void) const
Definition: FallingBlock.h:28
virtual bool IsCrouched(void) const
Definition: Entity.h:487
void SetPitch(double a_Pitch)
Definition: Entity.cpp:2070
const AString & GetDescription(void) const
Definition: Server.h:65
Definition: Horse.h:11
virtual void SendRespawn(eDimension a_Dimension) override
unsigned char NIBBLETYPE
The datatype used by nibbledata (meta, light, skylight)
Definition: ChunkDef.h:45
void WriteString(const AString &a_Value)
Definition: Packetizer.h:116
int GetNumNonInventorySlots(void) const
Returns the number of slots, excluding the player&#39;s inventory (used for network protocols) ...
Definition: Window.h:93
virtual void SendDisconnect(const AString &a_Reason) override
Definition: Pickup.h:18
virtual void SendPaintingSpawn(const cPainting &a_Painting) override
std::vector< Vector3i > cVector3iArray
Definition: Vector3.h:454
void HandleNPCTrade(int a_SlotNum)
Called when the protocol receives a MC|TrSel packet, indicating that the player used a trade in the N...
double GetSpeedZ(void) const
Definition: Entity.h:215
void ReplaceString(AString &iHayStack, const AString &iNeedle, const AString &iReplaceWith)
Replaces each occurence of iNeedle in iHayStack with iReplaceWith.
virtual void HandlePacketStatusRequest(cByteBuffer &a_ByteBuffer) override
bool HandleHandshake(const AString &a_Username)
Called when the protocol handshake has been received (for protocol versions that support it; otherwis...
const int MAX_ENC_LEN
virtual void SendTabCompletionResults(const AStringVector &a_Results) override
void HandleCommandBlockBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, const AString &a_NewCommand)
Called when the protocol receives a MC|AdvCdm plugin message, indicating that the player set a new co...
void AddReceivedData(const char *a_Data, size_t a_Size)
Adds the received (unencrypted) data to m_ReceivedData, parses complete packets.
void HandleTabCompletion(const AString &a_Text)
const AString & GetFaviconData(void) const
Returns base64 encoded favicon data (obtained from favicon.png)
Definition: Server.h:129
void WriteBEInt32(Int32 a_Value)
Definition: Packetizer.h:74
void HandlePlayerPos(double a_PosX, double a_PosY, double a_PosZ, double a_Stance, bool a_IsOnGround)
Verifies and sets player position, performing relevant checks Calls relevant methods to process movem...
cClientHandle * m_Client
Definition: Protocol.h:244
virtual void SendMapData(const cMap &a_Map, int a_DataStartX, int a_DataStartY) override
virtual void SendExperience(void) override
virtual void SendAttachEntity(const cEntity &a_Entity, const cEntity &a_Vehicle) override
Sending stuff to clients (alphabetically sorted):
Definition: Sheep.h:10
cByteBuffer m_ReceivedData
Buffer for the received data.
Definition: Protocol_1_9.h:161
virtual void HandlePacketVehicleMove(cByteBuffer &a_ByteBuffer)
void LOGERROR(const char *a_Format, fmt::ArgList a_ArgList)
Definition: Logger.cpp:183
void PacketError(UInt32 a_PacketType)
virtual void WriteMobMetadata(cPacketizer &a_Pkt, const cMonster &a_Mob)
Writes the mob-specific metadata for the specified mob.
virtual bool IsInvisible(void) const
Definition: Entity.h:491
T y
Definition: Vector3.h:17
virtual void HandlePacketBlockPlace(cByteBuffer &a_ByteBuffer)
virtual void HandlePacketSteerVehicle(cByteBuffer &a_ByteBuffer)
virtual void WriteBlockEntity(cPacketizer &a_Pkt, const cBlockEntity &a_BlockEntity)
Writes the block entity data for the specified block entity into the packet.
void HandlePlayerMoveLook(double a_PosX, double a_PosY, double a_PosZ, double a_Stance, float a_Rotation, float a_Pitch, bool a_IsOnGround)
void SetPosY(double a_PosY)
Definition: Entity.h:224
void HandlePlayerLook(float a_Rotation, float a_Pitch, bool a_IsOnGround)
void SendData(const char *a_Data, size_t a_Size)
AString EscapeString(const AString &a_Message)
Returns a copy of a_Message with all quotes and backslashes escaped by a backslash.
virtual void SendSetSubTitle(const cCompositeChat &a_SubTitle) override
eMonsterType
Identifies individual monster type, as well as their network type-ID.
Definition: MonsterTypes.h:10
virtual void SendEntityAnimation(const cEntity &a_Entity, char a_Animation) override
virtual void SendScoreboardObjective(const AString &a_Name, const AString &a_DisplayName, Byte a_Mode) override
bool IsOpen(void) const
Definition: File.cpp:116
static eMonsterType ItemDamageToMonsterType(short a_ItemDamage)
Converts the Spawn egg item damage to the monster type to spawn.
Definition: ItemSpawnEgg.h:59
T z
Definition: Vector3.h:17
bool Write(const void *a_Bytes, size_t a_Count)
Writes the bytes specified to the ringbuffer.
Definition: ByteBuffer.cpp:111
virtual void SendEntityHeadLook(const cEntity &a_Entity) override
bool g_ShouldLogCommIn
virtual void HandlePacketTabComplete(cByteBuffer &a_ByteBuffer)
virtual void SendThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ) override
virtual void SendChat(const AString &a_Message, eChatType a_Type) override
unsigned int GetScale(void) const
Definition: Map.h:145
bool g_ShouldLogCommOut
static void ParseFromNBT(cFireworkItem &a_FireworkItem, const cParsedNBT &a_NBT, int a_TagIdx, const ENUM_ITEM_ID a_Type)
Reads NBT data from a NBT object and populates a FireworkItem with it.
virtual void HandlePacketPluginMessage(cByteBuffer &a_ByteBuffer)
virtual void SendGameMode(eGameMode a_GameMode) override
void SetMainHand(eMainHand a_Hand)
Definition: Player.cpp:2848
unsigned int GetID(void) const
Definition: Map.h:150
bool IsCustomNameAlwaysVisible(void) const
Is the custom name of this monster always visible? If not, you only see the name when you sight the m...
Definition: Monster.h:169
Definition: Ghast.h:10
Definition: UUID.h:10
Definition: Server.h:55
virtual void SendDisplayObjective(const AString &a_Objective, cScoreboard::eDisplaySlot a_Display) override
eClickAction
Individual actions sent in the WindowClick packet.
Definition: Defines.h:73
unsigned int m_Color
Definition: Color.h:56
void Kick(const AString &a_Reason)
std::vector< AString > AStringVector
Definition: StringUtils.h:14
virtual void HandlePacketChatMessage(cByteBuffer &a_ByteBuffer)
cStatManager & GetStatManager()
Return the associated statistic and achievement manager.
Definition: Player.h:225
cProtocol_1_9_1(cClientHandle *a_Client, const AString &a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State)
cEnchantments m_Enchantments
Definition: Item.h:212
void CommitRead(void)
Removes the bytes that have been read from the ringbuffer.
Definition: ByteBuffer.cpp:885
Definition: Pig.h:10
const cColorList & GetData(void) const
Definition: Map.h:168
const AString & GetServerID(void) const
Definition: Server.h:117
size_t GetMaxPlayers(void) const
Definition: Server.h:70
virtual void SendEntityRelMove(const cEntity &a_Entity, char a_RelX, char a_RelY, char a_RelZ) override
cProtocol_1_9_4(cClientHandle *a_Client, const AString &a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State)
void WriteEntityProperties(cPacketizer &a_Pkt, const cEntity &a_Entity)
Writes the entity properties for the specified entity, including the Count field. ...
Container for a single chat message composed of multiple functional parts.
Definition: CompositeChat.h:31
virtual void HandleConfirmTeleport(cByteBuffer &a_ByteBuffer)
virtual void SendResetTitle(void) override
void WriteBEUInt32(UInt32 a_Value)
Definition: Packetizer.h:80
virtual void SendUnloadChunk(int a_ChunkX, int a_ChunkZ) override
void Update(const Byte *a_Data, size_t a_Length)
Adds the specified data to the checksum.
void EndCompound(void)
Definition: FastNBT.cpp:482
cAesCfb128Decryptor m_Decryptor
Definition: Protocol_1_9.h:165
static short GetPotionEffectIntensity(short a_ItemDamage)
Retrieves the intensity level from the potion&#39;s damage value.
void WriteByteAngle(double a_Angle)
Writes the specified angle using a single byte.
Definition: Packetizer.cpp:26
void SetProperties(const Json::Value &a_Properties)
Sets the player&#39;s properties, such as skin image and signature.
Definition: ClientHandle.h:90
virtual bool IsOnGround(void) const
Returns whether the entity is on ground or not.
Definition: Entity.h:518
virtual void SendCollectEntity(const cEntity &a_Entity, const cPlayer &a_Player, int a_Count) override
virtual void HandlePacketSpectate(cByteBuffer &a_ByteBuffer)
int InflateString(const char *a_Data, size_t a_Length, AString &a_Uncompressed)
Uncompresses a_Data into a_Uncompressed using Inflate; returns Z_OK for success or Z_XXX error consta...
double GetSpawnY(void) const
Definition: World.h:692
virtual void SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle) override
void SetUUID(const cUUID &a_UUID)
Sets the player&#39;s UUID, as used by the protocol.
Definition: ClientHandle.h:83
virtual void SendPlayerAbilities(void) override
Definition: World.h:65
AString m_CustomName
Definition: Item.h:213
bool IsLoreEmpty(void) const
Definition: Item.h:149
virtual void SendBlockBreakAnim(UInt32 a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage) override
virtual void SendInventorySlot(char a_WindowID, short a_SlotNum, const cItem &a_Item) override
cPlayer * GetPlayer(void)
Definition: ClientHandle.h:75
bool IsFlying(void) const
Returns true if the player is currently flying.
Definition: Player.h:345
short GetPing(void) const
Definition: ClientHandle.h:236
bool ReadToByteBuffer(cByteBuffer &a_Dst, size_t a_NumBytes)
Reads the specified number of bytes and writes it into the destinatio bytebuffer. ...
Definition: ByteBuffer.cpp:860
virtual void SendPickupSpawn(const cPickup &a_Pickup) override
cFile m_CommLogFile
The logfile where the comm is logged, when g_ShouldLogComm is true.
Definition: Protocol_1_9.h:169
virtual void SendLeashEntity(const cEntity &a_Entity, const cEntity &a_EntityLeashedTo) override
bool Open(const AString &iFileName, eMode iMode)
Definition: File.cpp:50
double GetNormalMaxSpeed(void) const
Gets the normal relative maximum speed.
Definition: Player.h:458
const cUUID & GetUUID(void) const
Returns the player&#39;s UUID, as used by the protocol.
Definition: ClientHandle.h:78
virtual void SendPlayerMaxSpeed(void) override
Informs the client of the maximum player speed (1.6.1+)
void HandleUseItem(eHand a_Hand)
Serializes one chunk&#39;s data to (possibly multiple) protocol versions.
char m_ItemCount
Definition: Item.h:210
bool ShouldAllowBungeeCord(void) const
Returns true if BungeeCord logins (that specify the player&#39;s UUID) are allowed.
Definition: Server.h:152
float GetXpPercentage(void)
Gets the experience bar percentage - XpP.
Definition: Player.cpp:478
virtual void HandlePacketAnimation(cByteBuffer &a_ByteBuffer)
AString m_AuthServerID
Definition: Protocol_1_9.h:151
virtual void SendUseBed(const cEntity &a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ) override
bool CanReadBytes(size_t a_Count) const
Returns true if the specified amount of bytes are available for reading.
Definition: ByteBuffer.cpp:213
virtual void SendKeepAlive(UInt32 a_PingID) override
AString & Printf(AString &str, const char *format, fmt::ArgList args)
Output the formatted text into the string.
Definition: StringUtils.cpp:55
void SetClientBrand(const AString &a_ClientBrand)
Called by the protocol when it receives the MC|Brand plugin message.
Definition: ClientHandle.h:256
virtual void SendDetachEntity(const cEntity &a_Entity, const cEntity &a_PreviousVehicle) override
void SetViewDistance(int a_ViewDistance)
Sets the maximal view distance.
float GetHealth(void) const
Returns the health of this entity.
Definition: Entity.h:380
void HandleEntitySprinting(UInt32 a_EntityID, bool a_IsSprinting)
virtual void HandlePacketLoginEncryptionResponse(cByteBuffer &a_ByteBuffer)
#define ASSERT(x)
Definition: Globals.h:335
cRsaPrivateKey & GetPrivateKey(void)
Definition: Server.h:131
void LOGWARNING(const char *a_Format, fmt::ArgList a_ArgList)
Definition: Logger.cpp:174
void HandleChat(const AString &a_Message)
Called when the protocol detects a chat packet.
static AString MobTypeToVanillaNBT(eMonsterType a_MobType)
Translates the MobType enum to the vanilla nbt name.
Definition: Monster.cpp:951
UInt32 m_OutstandingTeleportId
Definition: Protocol_1_9.h:158
cByteBuffer m_OutPacketBuffer
Buffer for composing the outgoing packets, through cPacketizer.
Definition: Protocol.h:252
#define LOGD(...)
Definition: LoggerSimple.h:40
virtual void SendWeather(eWeather a_Weather) override
Vector3d GetLastSentPos(void) const
Returns the last position we sent to all the clients.
Definition: Entity.h:314
virtual eDimension GetDimension(void) const override
Definition: World.h:151
void ResetRead(void)
Restarts next reading operation at the start of the ringbuffer.
Definition: ByteBuffer.cpp:896
size_t GetNumPlayers(void) const
Definition: Server.h:71
An object that can store incoming bytes and lets its clients read the bytes sequentially The bytes ar...
Definition: ByteBuffer.h:29
Definition: Slime.h:10
void HandleEntityLeaveBed(UInt32 a_EntityID)
void Empty(void)
Definition: Item.h:92
void HandlePluginMessage(const AString &a_Channel, const AString &a_Message)
int GetCurrentXp(void)
Gets the current experience.
Definition: Player.h:97
virtual void SendEntityMetadata(const cEntity &a_Entity) override
void WriteBEDouble(double a_Value)
Definition: Packetizer.h:104
virtual void SendExperienceOrb(const cExpOrb &a_ExpOrb) override
virtual void HandlePacketStatusRequest(cByteBuffer &a_ByteBuffer) override
#define KiB
Allows arithmetic expressions like "32 KiB" (but consider using parenthesis around it...
Definition: Globals.h:293
void HandleSpectate(const cUUID &a_PlayerUUID)
float GetMaxHealth(void) const
Definition: Entity.h:417
const uLongf MAX_COMPRESSED_PACKET_LEN
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
eHand
Definition: Defines.h:206
void SendChat(const AString &a_Message, eMessageType a_ChatPrefix, const AString &a_AdditionalData="")
int GetNumSlots(void) const
Returns the total number of slots.
Definition: Window.cpp:92
double GetSpawnZ(void) const
Definition: World.h:693
bool SkipRead(size_t a_Count)
Skips reading by a_Count bytes; returns false if not enough bytes in the ringbuffer.
Definition: ByteBuffer.cpp:833
#define UNUSED
Definition: Globals.h:152
virtual void SendLoginSuccess(void) override
virtual void SendPlayerMoveLook(void) override
bool ReadVarInt(T &a_Value)
Reads VarInt, assigns it to anything that can be assigned from an UInt64 (unsigned short...
Definition: ByteBuffer.h:76
virtual void SendBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override
double GetFoodSaturationLevel(void) const
Definition: Player.h:323
const AString & Serialize(int a_Version, int a_ChunkX, int a_ChunkZ, const std::map< UInt32, UInt32 > &a_BlockTypeMap)
Serializes the contained chunk data into the specified protocol version.
virtual void SendEntityProperties(const cEntity &a_Entity) override
void StartEncryption(const Byte *a_Key)
virtual void SendHideTitle(void) override
unsigned short UInt16
Definition: Globals.h:114
unsigned char UInt8
Definition: Globals.h:115
double GetYaw(void) const
Definition: Entity.h:209
virtual void HandlePacketStatusRequest(cByteBuffer &a_ByteBuffer) override
const AString & GetResult(void) const
Definition: FastNBT.h:342
virtual bool IsSprinting(void) const
Definition: Entity.h:489
void HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, UInt8 a_Status)
NIBBLETYPE GetBlockMeta(void) const
Definition: FallingBlock.h:29
virtual void SendWindowOpen(const cWindow &a_Window) override
std::string AString
Definition: StringUtils.h:13
eBlockFace
Block face constants, used in PlayerDigging and PlayerBlockPlacement packets and bbox collision calc...
Definition: Defines.h:29
void SetIsForgeClient()
Mark a client connection as using Forge.
Definition: ClientHandle.h:276
Calculates a SHA1 checksum for data stream.
Definition: Sha1Checksum.h:19
static eMonsterType StringToMobType(const AString &a_MobTypeName)
Translates MobType string to the enum, mtInvalidType if not recognized.
Definition: Monster.cpp:970
cEntity * GetAttached()
Gets entity (vehicle) attached to this entity.
Definition: Entity.cpp:1953
size_t GetUsedSpace(void) const
Returns the number of bytes that are currently in the ringbuffer.
Definition: ByteBuffer.cpp:181
virtual void SendEntityRelMoveLook(const cEntity &a_Entity, char a_RelX, char a_RelY, char a_RelZ) override
cServer * GetServer(void)
Definition: Root.h:69
static const UInt32 OFF_HAND
double GetSpeedY(void) const
Definition: Entity.h:214
double GetSprintingMaxSpeed(void) const
Gets the sprinting relative maximum speed.
Definition: Player.h:461
Encapsulates an RSA private key used in PKI cryptography.
Definition: RsaPrivateKey.h:20
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 HandlePacketUseEntity(cByteBuffer &a_ByteBuffer)
virtual void SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer &a_Serializer) override
static void FixItemFramePositions(int a_ObjectData, double &a_PosX, double &a_PosZ, double &a_Yaw)
Minecraft 1.8 use other locations to spawn the item frame.
void ProcessData(Byte *a_DecryptedOut, const Byte *a_EncryptedIn, size_t a_Length)
Decrypts a_Length bytes of the encrypted data; produces a_Length output bytes.
virtual void SendPlayerListUpdatePing(const cPlayer &a_Player) override
cByteBuffer m_OutPacketLenBuffer
Buffer for composing packet length (so that each cPacketizer instance doesn&#39;t allocate a new cPacketB...
Definition: Protocol.h:255
Composes an individual packet in the protocol&#39;s m_OutPacketBuffer; sends it just before being destruc...
Definition: Packetizer.h:28
void ForgeAugmentServerListPing(Json::Value &a_Response)
Add the Forge mod list to the server ping response.
Definition: ClientHandle.h:270
static cRoot * Get()
Definition: Root.h:51
void AddString(const AString &a_Name, const AString &a_Value)
Definition: FastNBT.cpp:599
void LOG(const char *a_Format, fmt::ArgList a_ArgList)
Definition: Logger.cpp:156
const AString & GetUsername(void) const
AString & CreateHexDump(AString &a_Out, const void *a_Data, size_t a_Size, size_t a_BytesPerLine)
format binary data this way: 00001234: 31 32 33 34 35 36 37 38 39 30 61 62 63 64 65 66 1234567890abcd...
void WritePosition64(int a_BlockX, int a_BlockY, int a_BlockZ)
Writes the specified block position as a single encoded 64-bit BigEndian integer. ...
Definition: Packetizer.h:129
double GetFlyingMaxSpeed(void) const
Gets the flying relative maximum speed.
Definition: Player.h:464
void WriteVarInt32(UInt32 a_Value)
Definition: Packetizer.h:110
virtual void SendPacket(cPacketizer &a_Packet) override
Sends the packet to the client.
bool HandleLogin(const AString &a_Username)
Called when the protocol has finished logging the user in.
virtual void SendPlayerListAddPlayer(const cPlayer &a_Player) override
signed int Int32
Definition: Globals.h:108
virtual bool IsSprinting(void) const override
Definition: Player.h:569
Definition: Entity.h:73
virtual void SendLogin(const cPlayer &a_Player, const cWorld &a_World) override
RAII for cCriticalSection - locks the CS on creation, unlocks on destruction.
void WriteBEFloat(float a_Value)
Definition: Packetizer.h:98
AString CreateJsonString(bool a_ShouldUseChatPrefixes=true) const
void PacketBufferFull(void)
virtual void SendRemoveEntityEffect(const cEntity &a_Entity, int a_EffectID) override
virtual void DataReceived(const char *a_Data, size_t a_Size) override
Called when client sends some data:
virtual void SendWindowProperty(const cWindow &a_Window, short a_Property, short a_Value) override
unsigned int UInt32
Definition: Globals.h:113
void Flush(void)
Flushes all the bufferef output into the file (only when writing)
Definition: File.cpp:705
virtual void SendUnleashEntity(const cEntity &a_Entity) override
Represents a UI window.
Definition: Window.h:53
static bool CompressPacket(const AString &a_Packet, AString &a_Compressed)
Compress the packet.
virtual void SendEntityLook(const cEntity &a_Entity) override
bool IsHardcore(void) const
Definition: Server.h:93
virtual bool IsRclking(void) const
Definition: Entity.h:490
void AddInt(const AString &a_Name, Int32 a_Value)
Definition: FastNBT.cpp:555
virtual void HandlePacketPlayerPos(cByteBuffer &a_ByteBuffer)
virtual void SendCameraSetTo(const cEntity &a_Entity) override
virtual void SendPlayerListUpdateGameMode(const cPlayer &a_Player) override
void HandleBeaconSelection(int a_PrimaryEffect, int a_SecondaryEffect)
Called when the protocol receives a MC|Beacon plugin message, indicating that the player set an effec...
Definition: Wolf.h:12
virtual void HandleVanillaPluginMessage(cByteBuffer &a_ByteBuffer, const AString &a_Channel)
Parses Vanilla plugin messages into specific ClientHandle calls.
double GetPosZ(void) const
Definition: Entity.h:208
unsigned char Byte
Definition: Globals.h:117
AStringVector m_LoreTable
Definition: Item.h:217
bool IsGameModeCreative(void) const
Returns true if the player is in Creative mode, either explicitly, or by inheriting from current worl...
Definition: Player.cpp:1260
void HandleEntityCrouch(UInt32 a_EntityID, bool a_IsCrouching)
char GetWindowID(void) const
Definition: Window.h:80
virtual void SendEntityStatus(const cEntity &a_Entity, char a_Status) override
short m_ItemType
Definition: Item.h:209
Definition: Wither.h:10
virtual void SendExplosion(double a_BlockX, double a_BlockY, double a_BlockZ, float a_Radius, const cVector3iArray &a_BlocksAffected, const Vector3d &a_PlayerMotion) override
void Finish(void)
Definition: FastNBT.cpp:645
virtual void SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlockVector &a_Changes) override
virtual void SendPlayerSpawn(const cPlayer &a_Player) override
const cMapDecoratorList GetDecorators(void) const
Definition: Map.h:166
void WriteBool(bool a_Value)
Definition: Packetizer.h:45
virtual UInt32 GetPacketID(ePacketType a_Packet) override
Get the packet ID for a given packet.
const cUUID & GetUUID(void) const
Returns the UUID that has been read from the client, or nil if not available.
Definition: Player.h:521
void SetYaw(double a_Yaw)
Definition: Entity.cpp:2059
int StatValue
Definition: Statistics.h:120
void HandleUseEntity(UInt32 a_TargetEntityID, bool a_IsLeftClick)
virtual void SendSpawnMob(const cMonster &a_Mob) override
void HandleSlotSelected(Int16 a_SlotNum)
void SetPosX(double a_PosX)
Definition: Entity.h:223
virtual void HandlePacketWindowClose(cByteBuffer &a_ByteBuffer)
eGameMode GetEffectiveGameMode(void) const
Returns the current effective gamemode (inherited gamemode is resolved before returning) ...
Definition: Player.h:179
virtual void SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer &a_Serializer) override
void WriteBEUInt64(UInt64 a_Value)
Definition: Packetizer.h:92
virtual bool ReadItem(cByteBuffer &a_ByteBuffer, cItem &a_Item, size_t a_KeepRemainingBytes=0)
Reads an item out of the received data, sets a_Item to the values read.
AString StrToLower(const AString &s)
Returns a lower-cased copy of the string.
std::enable_if< std::is_arithmetic< T >::value, C >::type FloorC(T a_Value)
Floors a value, then casts it to C (an int by default)
Definition: Globals.h:362
cInventory & GetInventory(void)
Definition: Player.h:136
bool ReadPosition64(int &a_BlockX, int &a_BlockY, int &a_BlockZ)
Definition: ByteBuffer.cpp:475
virtual void SendWindowClose(const cWindow &a_Window) override
virtual void SendSetRawSubTitle(const AString &a_SubTitle) override
void BeginList(const AString &a_Name, eTagType a_ChildrenType)
Definition: FastNBT.cpp:495
static AString MobTypeToVanillaName(eMonsterType a_MobType)
Translates MobType enum to the vanilla name of the mob, empty string if unknown.
Definition: Monster.cpp:932
#define ARRAYCOUNT(X)
Evaluates to the number of elements in an array (compile-time!)
Definition: Globals.h:290
void SetPosZ(double a_PosZ)
Definition: Entity.h:225
ePacketType
Logical types of outgoing packets.
Definition: Protocol.h:68
Definition: Item.h:36
void HandleAnvilItemName(const AString &a_ItemName)
Called when the protocol receives a MC|ItemName plugin message, indicating that the player named an i...
EffectID
Definition: EffectID.h:5
const AString & GetName(void) const
Returns the protocol name of the painting.
Definition: Painting.h:25
void BeginCompound(const AString &a_Name)
Definition: FastNBT.cpp:464
void SetUsername(const AString &a_Username)
Definition: Zombie.h:9
static void DigestToJava(const Checksum &a_Digest, AString &a_JavaOut)
Converts a raw 160-bit SHA1 digest into a Java Hex representation According to http://wiki.vg/Protocol_Encryption.
#define UNREACHABLE(x)
Use to mark code that should be impossible to reach.
Definition: Globals.h:344
virtual void HandlePacketLoginStart(cByteBuffer &a_ByteBuffer)
signed long long Int64
Definition: Globals.h:107
void SetIPString(const AString &a_IPString)
Sets the IP string that the client is using.
Definition: ClientHandle.h:73
virtual void SendTeleportEntity(const cEntity &a_Entity) override
bool IsCustomNameEmpty(void) const
Definition: Item.h:148
bool IsEmpty(void) const
Returns true if there are no enchantments.
std::vector< sSetBlock > sSetBlockVector
Definition: ChunkDef.h:564
virtual void SendEntityEquipment(const cEntity &a_Entity, short a_SlotNum, const cItem &a_Item) override
int GetReward(void) const
Get the exp amount.
Definition: ExpOrb.h:39
void WriteBEInt64(Int64 a_Value)
Definition: Packetizer.h:86
UInt32 GetUniqueID(void) const
Definition: Entity.h:261
void ParseFromNBT(cEnchantments &a_Enchantments, const cParsedNBT &a_NBT, int a_EnchListTagIdx)
Reads the enchantments from the specified NBT list tag (ench or StoredEnchantments) ...
This class bridges a vector of cItem for safe access via Lua.
Definition: Item.h:234
cClientHandle * GetClientHandle(void) const
Returns the raw client handle associated with the player.
Definition: Player.h:254
static const UInt32 MAIN_HAND
Value for main hand in Hand parameter for Protocol 1.9.
virtual void HandlePacketSlotSelect(cByteBuffer &a_ByteBuffer)
cPluginManager * GetPluginManager(void)
Definition: Root.h:114
const AString & GetIPString(void) const
Definition: ClientHandle.h:69
virtual void SendLogin(const cPlayer &a_Player, const cWorld &a_World) override
virtual void HandlePacketCreativeInventoryAction(cByteBuffer &a_ByteBuffer)
virtual void SendSpawnFallingBlock(const cFallingBlock &a_FallingBlock) override
double GetSpawnX(void) const
Definition: World.h:691
static const AString & GetName(const eStatistic a_Type)
Type -> Name.
Definition: Statistics.cpp:102
void HandleUpdateSign(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)
virtual void SendSpawnObject(const cEntity &a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch) override
virtual void HandlePacketEntityAction(cByteBuffer &a_ByteBuffer)
void SetLocale(const AString &a_Locale)
Definition: ClientHandle.h:247
bool SplitZeroTerminatedStrings(const AString &a_Strings, AStringVector &a_Output)
Splits a string that has embedded \0 characters, on those characters.