Cuberite
A lightweight, fast and extensible game server for Minecraft
Protocol_1_8.cpp
Go to the documentation of this file.
1 
2 // Protocol_1_8.cpp
3 
4 /*
5 Implements the 1.8 protocol classes:
6  - cProtocol_1_8_0
7  - release 1.8 protocol (#47)
8 */
9 
10 #include "Globals.h"
11 #include "Protocol_1_8.h"
12 #include "main.h"
13 #include "../mbedTLS++/Sha1Checksum.h"
14 #include "Packetizer.h"
15 
16 #include "../ClientHandle.h"
17 #include "../Root.h"
18 #include "../Server.h"
19 #include "../World.h"
20 #include "../EffectID.h"
21 #include "../StringCompression.h"
22 #include "../CompositeChat.h"
23 #include "../UUID.h"
24 #include "../World.h"
25 #include "../JsonUtils.h"
26 
27 #include "../WorldStorage/FastNBT.h"
28 #include "../WorldStorage/EnchantmentSerializer.h"
29 
30 #include "../Entities/ExpOrb.h"
31 #include "../Entities/Minecart.h"
32 #include "../Entities/FallingBlock.h"
33 #include "../Entities/Floater.h"
34 #include "../Entities/Painting.h"
35 #include "../Entities/Pickup.h"
36 #include "../Entities/Player.h"
37 #include "../Entities/ItemFrame.h"
38 #include "../Entities/ArrowEntity.h"
39 #include "../Entities/FireworkEntity.h"
40 
41 #include "../Mobs/IncludeAllMonsters.h"
42 #include "../UI/Window.h"
43 #include "../UI/HorseWindow.h"
44 
45 #include "../BlockEntities/BannerEntity.h"
46 #include "../BlockEntities/BeaconEntity.h"
47 #include "../BlockEntities/CommandBlockEntity.h"
48 #include "../BlockEntities/EnchantingTableEntity.h"
49 #include "../BlockEntities/MobHeadEntity.h"
50 #include "../BlockEntities/MobSpawnerEntity.h"
51 #include "../BlockEntities/FlowerPotEntity.h"
52 #include "../Bindings/PluginManager.h"
53 
54 
55 
56 
57 
58 const int MAX_ENC_LEN = 512; // Maximum size of the encrypted message; should be 128, but who knows...
59 static const UInt32 CompressionThreshold = 256; // After how large a packet should we compress it.
60 
61 
62 
63 
64 
66 // cProtocol_1_8_0:
67 
68 cProtocol_1_8_0::cProtocol_1_8_0(cClientHandle * a_Client, const AString & a_ServerAddress, State a_State) :
69  Super(a_Client),
70  m_State(a_State),
71  m_ServerAddress(a_ServerAddress),
72  m_IsEncrypted(false)
73 {
74  AStringVector Params;
75  SplitZeroTerminatedStrings(a_ServerAddress, Params);
76 
77  if (Params.size() >= 2)
78  {
79  m_ServerAddress = Params[0];
80 
81  if (Params[1] == "FML")
82  {
83  LOGD("Forge client connected!");
85  }
86  else if (Params.size() == 4)
87  {
88  if (cRoot::Get()->GetServer()->ShouldAllowBungeeCord())
89  {
90  // BungeeCord handling:
91  // If BC is setup with ip_forward == true, it sends additional data in the login packet's ServerAddress field:
92  // hostname\00ip-address\00uuid\00profile-properties-as-json
93 
94  LOGD("Player at %s connected via BungeeCord", Params[1].c_str());
95 
96  cUUID UUID;
97  UUID.FromString(Params[2]);
98 
99  Json::Value root;
100  if (!JsonUtils::ParseString(Params[3], root))
101  {
102  LOGERROR("Unable to parse player properties: '%s'", Params[3]);
103  m_Client->ProxyInit(Params[1], UUID);
104  }
105  else
106  {
107  m_Client->ProxyInit(Params[1], UUID, root);
108  }
109  }
110  else
111  {
112  LOG("BungeeCord is disabled, but client sent additional data, set AllowBungeeCord=1 if you want to allow it");
113  }
114  }
115  else
116  {
117  LOG("Unknown additional data sent in server address (BungeeCord/FML?): %zu parameters", Params.size());
118  // TODO: support FML + BungeeCord? (what parameters does it send in that case?) https://github.com/SpigotMC/BungeeCord/issues/899
119  }
120  }
121 
122  // Create the comm log file, if so requested:
124  {
125  static int sCounter = 0;
126  cFile::CreateFolder("CommLogs");
127  AString IP(a_Client->GetIPString());
128  ReplaceString(IP, ":", "_");
129  auto FileName = fmt::format(FMT_STRING("CommLogs/{:x}_{}__{}.log"),
130  static_cast<unsigned>(time(nullptr)),
131  sCounter++,
132  IP.c_str()
133  );
134  if (!m_CommLogFile.Open(FileName, cFile::fmWrite))
135  {
136  LOG("Cannot log communication to file, the log file \"%s\" cannot be opened for writing.", FileName.c_str());
137  }
138  }
139 }
140 
141 
142 
143 
144 
146 {
147  if (m_IsEncrypted)
148  {
149  m_Decryptor.ProcessData(a_Data.data(), a_Data.size());
150  }
151 
152  AddReceivedData(a_Buffer, a_Data);
153 }
154 
155 
156 
157 
158 
160 {
161  if (m_IsEncrypted)
162  {
163  m_Encryptor.ProcessData(a_Data.data(), a_Data.size());
164  }
165 }
166 
167 
168 
169 
170 
171 void cProtocol_1_8_0::SendAttachEntity(const cEntity & a_Entity, const cEntity & a_Vehicle)
172 {
173  ASSERT(m_State == 3); // In game mode?
174 
175  cPacketizer Pkt(*this, pktAttachEntity);
176  Pkt.WriteBEUInt32(a_Entity.GetUniqueID());
177  Pkt.WriteBEUInt32(a_Vehicle.GetUniqueID());
178  Pkt.WriteBool(false);
179 }
180 
181 
182 
183 
184 
185 void cProtocol_1_8_0::SendBlockAction(Vector3i a_BlockPos, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType)
186 {
187  ASSERT(m_State == 3); // In game mode?
188 
189  cPacketizer Pkt(*this, pktBlockAction);
190  Pkt.WriteXYZPosition64(a_BlockPos);
191  Pkt.WriteBEInt8(a_Byte1);
192  Pkt.WriteBEInt8(a_Byte2);
193  Pkt.WriteVarInt32(a_BlockType);
194 }
195 
196 
197 
198 
199 
200 void cProtocol_1_8_0::SendBlockBreakAnim(UInt32 a_EntityID, Vector3i a_BlockPos, char a_Stage)
201 {
202  ASSERT(m_State == 3); // In game mode?
203 
204  cPacketizer Pkt(*this, pktBlockBreakAnim);
205  Pkt.WriteVarInt32(a_EntityID);
206  Pkt.WriteXYZPosition64(a_BlockPos);
207  Pkt.WriteBEInt8(a_Stage);
208 }
209 
210 
211 
212 
213 
214 void cProtocol_1_8_0::SendBlockChange(Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
215 {
216  ASSERT(m_State == 3); // In game mode?
217 
218  cPacketizer Pkt(*this, pktBlockChange);
219  Pkt.WriteXYZPosition64(a_BlockPos);
220  Pkt.WriteVarInt32((static_cast<UInt32>(a_BlockType) << 4) | (static_cast<UInt32>(a_BlockMeta) & 15));
221 }
222 
223 
224 
225 
226 
227 void cProtocol_1_8_0::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes)
228 {
229  ASSERT(m_State == 3); // In game mode?
230 
231  cPacketizer Pkt(*this, pktBlockChanges);
232  Pkt.WriteBEInt32(a_ChunkX);
233  Pkt.WriteBEInt32(a_ChunkZ);
234  Pkt.WriteVarInt32(static_cast<UInt32>(a_Changes.size()));
235 
236  for (const auto & Change : a_Changes)
237  {
238  Int16 Coords = static_cast<Int16>(Change.m_RelY | (Change.m_RelZ << 8) | (Change.m_RelX << 12));
239  Pkt.WriteBEInt16(Coords);
240  Pkt.WriteVarInt32(static_cast<UInt32>(Change.m_BlockType & 0xFFF) << 4 | (Change.m_BlockMeta & 0xF));
241  }
242 }
243 
244 
245 
246 
247 
248 void cProtocol_1_8_0::SendBossBarAdd(UInt32 a_UniqueID, const cCompositeChat & a_Title, float a_FractionFilled, BossBarColor a_Color, BossBarDivisionType a_DivisionType, bool a_DarkenSky, bool a_PlayEndMusic, bool a_CreateFog)
249 {
250  // No such packet here
251 }
252 
253 
254 
255 
256 
258 {
259  // No such packet here
260 }
261 
262 
263 
264 
265 
266 void cProtocol_1_8_0::SendBossBarUpdateFlags(UInt32 a_UniqueID, bool a_DarkenSky, bool a_PlayEndMusic, bool a_CreateFog)
267 {
268  // No such packet here
269 }
270 
271 
272 
273 
274 
275 void cProtocol_1_8_0::SendBossBarUpdateHealth(UInt32 a_UniqueID, float a_FractionFilled)
276 {
277  // No such packet here
278 }
279 
280 
281 
282 
283 
285 {
286  // No such packet here
287 }
288 
289 
290 
291 
292 
294 {
295  // No such packet here
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_8_0::SendChat(const AString & a_Message, eChatType a_Type)
313 {
314  ASSERT(m_State == 3); // In game mode?
315 
316  SendChatRaw(JsonUtils::SerializeSingleValueJsonObject("text", a_Message), a_Type);
317 }
318 
319 
320 
321 
322 
323 void cProtocol_1_8_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_8_0::SendChatRaw(const AString & a_MessageRaw, eChatType a_Type)
335 {
336  ASSERT(m_State == 3); // In game mode?
337 
338  // Prevent chat messages that might trigger CVE-2021-44228
339  if (a_MessageRaw.find("${") != std::string::npos)
340  {
341  return;
342  }
343 
344  // Send the json string to the client:
345  cPacketizer Pkt(*this, pktChatRaw);
346  Pkt.WriteString(a_MessageRaw);
347  Pkt.WriteBEInt8([a_Type]() -> signed char
348  {
349  switch (a_Type)
350  {
351  case eChatType::ctChatBox: return 0;
352  case eChatType::ctSystem: return 1;
353  case eChatType::ctAboveActionBar: return 2;
354  }
355  UNREACHABLE("Unsupported chat type");
356  }());
357 }
358 
359 
360 
361 
362 
364 {
365  ASSERT(m_State == 3); // In game mode?
366 
367  cCSLock Lock(m_CSPacket);
368  m_Client->SendData(a_ChunkData);
369 }
370 
371 
372 
373 
374 
375 void cProtocol_1_8_0::SendCollectEntity(const cEntity & a_Collected, const cEntity & a_Collector, unsigned a_Count)
376 {
377  UNUSED(a_Count);
378  ASSERT(m_State == 3); // In game mode?
379 
380  cPacketizer Pkt(*this, pktCollectEntity);
381  Pkt.WriteVarInt32(a_Collected.GetUniqueID());
382  Pkt.WriteVarInt32(a_Collector.GetUniqueID());
383 }
384 
385 
386 
387 
388 
390 {
391  ASSERT(m_State == 3); // In game mode?
392 
393  {
394  cPacketizer Pkt(*this, pktDestroyEntity);
395  Pkt.WriteVarInt32(1);
396  Pkt.WriteVarInt32(a_Entity.GetUniqueID());
397  }
398 
399  if (!a_Entity.IsMob())
400  {
401  return;
402  }
403 
404  const auto & Mob = static_cast<const cMonster &>(a_Entity);
405  if ((Mob.GetMobType() == mtEnderDragon) || (Mob.GetMobType() == mtWither))
406  {
407  SendBossBarRemove(Mob.GetUniqueID());
408  }
409 }
410 
411 
412 
413 
414 
415 void cProtocol_1_8_0::SendDetachEntity(const cEntity & a_Entity, const cEntity & a_PreviousVehicle)
416 {
417  ASSERT(m_State == 3); // In game mode?
418 
419  cPacketizer Pkt(*this, pktAttachEntity);
420  Pkt.WriteBEUInt32(a_Entity.GetUniqueID());
421  Pkt.WriteBEUInt32(0);
422  Pkt.WriteBool(false);
423 }
424 
425 
426 
427 
428 
430 {
431  switch (m_State)
432  {
433  case State::Login:
434  {
437  break;
438  }
439  case State::Game:
440  {
443  break;
444  }
445  default:
446  {
447  FLOGERROR(
448  "Tried to send disconnect in invalid game state {0}",
449  static_cast<int>(m_State)
450  );
451  }
452  }
453 }
454 
455 
456 
457 
458 
460 {
461  ASSERT(m_State == 3); // In game mode?
462 
463  cPacketizer Pkt(*this, pktEditSign);
464  Pkt.WriteXYZPosition64(a_BlockPos);
465 }
466 
467 
468 
469 
470 
471 void cProtocol_1_8_0::SendEntityAnimation(const cEntity & a_Entity, const EntityAnimation a_Animation)
472 {
473  ASSERT(m_State == 3); // In game mode?
474 
475  if (a_Animation == EntityAnimation::PlayerEntersBed)
476  {
477  ASSERT(a_Entity.IsPlayer());
478  const auto BedPosition = static_cast<const cPlayer &>(a_Entity).GetLastBedPos();
479 
480  cPacketizer Pkt(*this, pktUseBed);
481  Pkt.WriteVarInt32(a_Entity.GetUniqueID());
482  Pkt.WriteXYZPosition64(BedPosition.x, BedPosition.y, BedPosition.z);
483  return;
484  }
485 
486  if (const auto AnimationID = GetProtocolEntityAnimation(a_Animation); AnimationID != static_cast<unsigned char>(-1))
487  {
488  cPacketizer Pkt(*this, pktEntityAnimation);
489  Pkt.WriteVarInt32(a_Entity.GetUniqueID());
490  Pkt.WriteBEUInt8(AnimationID);
491  return;
492  }
493 
494  if (const auto StatusID = GetProtocolEntityStatus(a_Animation); StatusID != -1)
495  {
496  cPacketizer Pkt(*this, pktEntityStatus);
497  Pkt.WriteBEUInt32(a_Entity.GetUniqueID());
498  Pkt.WriteBEInt8(StatusID);
499  }
500 }
501 
502 
503 
504 
505 
506 void cProtocol_1_8_0::SendEntityEffect(const cEntity & a_Entity, int a_EffectID, int a_Amplifier, int a_Duration)
507 {
508  ASSERT(m_State == 3); // In game mode?
509 
510  cPacketizer Pkt(*this, pktEntityEffect);
511  Pkt.WriteVarInt32(a_Entity.GetUniqueID());
512  Pkt.WriteBEUInt8(static_cast<UInt8>(a_EffectID));
513  Pkt.WriteBEUInt8(static_cast<UInt8>(a_Amplifier));
514  Pkt.WriteVarInt32(static_cast<UInt32>(a_Duration));
515  Pkt.WriteBool(false); // Hide particles
516 }
517 
518 
519 
520 
521 
522 void cProtocol_1_8_0::SendEntityEquipment(const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item)
523 {
524  ASSERT(m_State == 3); // In game mode?
525 
526  cPacketizer Pkt(*this, pktEntityEquipment);
527  Pkt.WriteVarInt32(a_Entity.GetUniqueID());
528  Pkt.WriteBEInt16(a_SlotNum);
529  WriteItem(Pkt, a_Item);
530 }
531 
532 
533 
534 
535 
537 {
538  ASSERT(m_State == 3); // In game mode?
539 
540  cPacketizer Pkt(*this, pktEntityHeadLook);
541  Pkt.WriteVarInt32(a_Entity.GetUniqueID());
542  Pkt.WriteByteAngle(a_Entity.GetHeadYaw());
543 }
544 
545 
546 
547 
548 
550 {
551  ASSERT(m_State == 3); // In game mode?
552 
553  cPacketizer Pkt(*this, pktEntityLook);
554  Pkt.WriteVarInt32(a_Entity.GetUniqueID());
555  Pkt.WriteByteAngle(a_Entity.GetYaw());
556  Pkt.WriteByteAngle(a_Entity.GetPitch());
557  Pkt.WriteBool(a_Entity.IsOnGround());
558 }
559 
560 
561 
562 
563 
565 {
566  ASSERT(m_State == 3); // In game mode?
567 
568  cPacketizer Pkt(*this, pktEntityMeta);
569  Pkt.WriteVarInt32(a_Entity.GetUniqueID());
570  WriteEntityMetadata(Pkt, a_Entity);
571  Pkt.WriteBEUInt8(0x7f); // The termination byte
572 }
573 
574 
575 
576 
577 
579 {
580  ASSERT(m_State == 3); // In game mode?
581 
582  const auto Delta = (a_Entity.GetPosition() * 32).Floor() - (a_Entity.GetLastSentPosition() * 32).Floor();
583 
584  // Ensure that the delta has enough precision and is within range of a BEInt8:
585  if (
586  Delta.HasNonZeroLength() &&
590  )
591  {
592  const auto Move = static_cast<Vector3<Int8>>(Delta);
593 
594  // Difference within limitations, use a relative move packet
595  if (a_Entity.IsOrientationDirty())
596  {
597  cPacketizer Pkt(*this, pktEntityRelMoveLook);
598  Pkt.WriteVarInt32(a_Entity.GetUniqueID());
599  Pkt.WriteBEInt8(Move.x);
600  Pkt.WriteBEInt8(Move.y);
601  Pkt.WriteBEInt8(Move.z);
602  Pkt.WriteByteAngle(a_Entity.GetYaw());
603  Pkt.WriteByteAngle(a_Entity.GetPitch());
604  Pkt.WriteBool(a_Entity.IsOnGround());
605  }
606  else
607  {
608  cPacketizer Pkt(*this, pktEntityRelMove);
609  Pkt.WriteVarInt32(a_Entity.GetUniqueID());
610  Pkt.WriteBEInt8(Move.x);
611  Pkt.WriteBEInt8(Move.y);
612  Pkt.WriteBEInt8(Move.z);
613  Pkt.WriteBool(a_Entity.IsOnGround());
614  }
615 
616  return;
617  }
618 
619  // Too big or small a movement, do a teleport.
620 
621  cPacketizer Pkt(*this, pktTeleportEntity);
622  Pkt.WriteVarInt32(a_Entity.GetUniqueID());
623  Pkt.WriteFPInt(a_Entity.GetPosX());
624  Pkt.WriteFPInt(a_Entity.GetPosY());
625  Pkt.WriteFPInt(a_Entity.GetPosZ());
626  Pkt.WriteByteAngle(a_Entity.GetYaw());
627  Pkt.WriteByteAngle(a_Entity.GetPitch());
628  Pkt.WriteBool(a_Entity.IsOnGround());
629 }
630 
631 
632 
633 
634 
636 {
637  ASSERT(m_State == 3); // In game mode?
638 
639  cPacketizer Pkt(*this, pktEntityProperties);
640  Pkt.WriteVarInt32(a_Entity.GetUniqueID());
641  WriteEntityProperties(Pkt, a_Entity);
642 }
643 
644 
645 
646 
647 
649 {
650  ASSERT(m_State == 3); // In game mode?
651 
652  cPacketizer Pkt(*this, pktEntityVelocity);
653  Pkt.WriteVarInt32(a_Entity.GetUniqueID());
654  // 400 = 8000 / 20 ... Conversion from our speed in m / s to 8000 m / tick
655  Pkt.WriteBEInt16(static_cast<Int16>(a_Entity.GetSpeedX() * 400));
656  Pkt.WriteBEInt16(static_cast<Int16>(a_Entity.GetSpeedY() * 400));
657  Pkt.WriteBEInt16(static_cast<Int16>(a_Entity.GetSpeedZ() * 400));
658 }
659 
660 
661 
662 
663 
665 {
666  ASSERT(m_State == 3); // In game mode?
667 
668  cPacketizer Pkt(*this, pktExperience);
669  cPlayer * Player = m_Client->GetPlayer();
670  Pkt.WriteBEFloat(Player->GetXpPercentage());
671  Pkt.WriteVarInt32(static_cast<UInt32>(Player->GetXpLevel()));
672  Pkt.WriteVarInt32(static_cast<UInt32>(Player->GetCurrentXp()));
673 }
674 
675 
676 
677 
678 
680 {
681  ASSERT(m_State == 3); // In game mode?
682 
684  Pkt.WriteVarInt32(a_ExpOrb.GetUniqueID());
685  Pkt.WriteFPInt(a_ExpOrb.GetPosX());
686  Pkt.WriteFPInt(a_ExpOrb.GetPosY());
687  Pkt.WriteFPInt(a_ExpOrb.GetPosZ());
688  Pkt.WriteBEInt16(static_cast<Int16>(a_ExpOrb.GetReward()));
689 }
690 
691 
692 
693 
694 
695 void cProtocol_1_8_0::SendExplosion(const Vector3f a_Position, const float a_Power)
696 {
697  ASSERT(m_State == 3); // In game mode?
698 
699  cPacketizer Pkt(*this, pktExplosion);
700  Pkt.WriteBEFloat(a_Position.x);
701  Pkt.WriteBEFloat(a_Position.y);
702  Pkt.WriteBEFloat(a_Position.z);
703  Pkt.WriteBEFloat(a_Power);
704  Pkt.WriteBEUInt32(0);
705  Pkt.WriteBEFloat(0);
706  Pkt.WriteBEFloat(0);
707  Pkt.WriteBEFloat(0);
708 }
709 
710 
711 
712 
713 
715 {
716  ASSERT(m_State == 3); // In game mode?
717 
718  cPacketizer Pkt(*this, pktGameMode);
719  Pkt.WriteBEUInt8(3); // Reason: Change game mode
720  Pkt.WriteBEFloat(static_cast<float>(a_GameMode)); // The protocol really represents the value with a float!
721 }
722 
723 
724 
725 
726 
728 {
729  ASSERT(m_State == 3); // In game mode?
730 
731  cPacketizer Pkt(*this, pktUpdateHealth);
732  cPlayer * Player = m_Client->GetPlayer();
733  Pkt.WriteBEFloat(static_cast<float>(Player->GetHealth()));
734  Pkt.WriteVarInt32(static_cast<UInt32>(Player->GetFoodLevel()));
735  Pkt.WriteBEFloat(static_cast<float>(Player->GetFoodSaturationLevel()));
736 }
737 
738 
739 
740 
741 
743 {
744  ASSERT((a_ItemIndex >= 0) && (a_ItemIndex <= 8)); // Valid check
745 
746  cPacketizer Pkt(*this, pktHeldItemChange);
747  Pkt.WriteBEInt8(static_cast<Int8>(a_ItemIndex));
748 }
749 
750 
751 
752 
753 
755 {
756  ASSERT(m_State == 3); // In game mode?
757 
758  cPacketizer Pkt(*this, pktTitle);
759  Pkt.WriteVarInt32(3); // Hide title
760 }
761 
762 
763 
764 
765 
766 void cProtocol_1_8_0::SendInventorySlot(char a_WindowID, short a_SlotNum, const cItem & a_Item)
767 {
768  ASSERT(m_State == 3); // In game mode?
769 
770  cPacketizer Pkt(*this, pktInventorySlot);
771  Pkt.WriteBEInt8(a_WindowID);
772  Pkt.WriteBEInt16(a_SlotNum);
773  WriteItem(Pkt, a_Item);
774 }
775 
776 
777 
778 
779 
781 {
782  // Drop the packet if the protocol is not in the Game state yet (caused a client crash):
783  if (m_State != 3)
784  {
785  LOGWARNING("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);
786  return;
787  }
788 
789  cPacketizer Pkt(*this, pktKeepAlive);
790  Pkt.WriteVarInt32(a_PingID);
791 }
792 
793 
794 
795 
796 
797 void cProtocol_1_8_0::SendLeashEntity(const cEntity & a_Entity, const cEntity & a_EntityLeashedTo)
798 {
799  ASSERT(m_State == 3); // In game mode?
800 
801  cPacketizer Pkt(*this, pktLeashEntity);
802  Pkt.WriteBEUInt32(a_Entity.GetUniqueID());
803  Pkt.WriteBEUInt32(a_EntityLeashedTo.GetUniqueID());
804  Pkt.WriteBool(true);
805 }
806 
807 
808 
809 
810 
812 {
813  ASSERT(m_State == 3); // In game mode?
814 
815  cPacketizer Pkt(*this, pktLeashEntity);
816  Pkt.WriteBEUInt32(a_Entity.GetUniqueID());
817  Pkt.WriteBEInt32(-1);
818  Pkt.WriteBool(true);
819 }
820 
821 
822 
823 
824 
825 void cProtocol_1_8_0::SendLogin(const cPlayer & a_Player, const cWorld & a_World)
826 {
827  // Send the Join Game packet:
828  {
829  cServer * Server = cRoot::Get()->GetServer();
830  cPacketizer Pkt(*this, pktJoinGame);
831  Pkt.WriteBEUInt32(a_Player.GetUniqueID());
832  Pkt.WriteBEUInt8(static_cast<UInt8>(a_Player.GetEffectiveGameMode()) | (Server->IsHardcore() ? 0x08 : 0)); // Hardcore flag bit 4
833  Pkt.WriteBEInt8(static_cast<Int8>(a_World.GetDimension()));
834  Pkt.WriteBEUInt8(2); // TODO: Difficulty (set to Normal)
835  Pkt.WriteBEUInt8(static_cast<UInt8>(Clamp<size_t>(Server->GetMaxPlayers(), 0, 255)));
836  Pkt.WriteString("default"); // Level type - wtf?
837  Pkt.WriteBool(false); // Reduced Debug Info - wtf?
838  }
839 
840  // Send the spawn position:
841  {
842  cPacketizer Pkt(*this, pktSpawnPosition);
843  Pkt.WriteXYZPosition64(a_World.GetSpawnX(), a_World.GetSpawnY(), a_World.GetSpawnZ());
844  }
845 
846  // Send the server difficulty:
847  {
848  cPacketizer Pkt(*this, pktDifficulty);
849  Pkt.WriteBEInt8(1);
850  }
851 }
852 
853 
854 
855 
856 
858 {
859  ASSERT(m_State == 2); // State: login?
860 
861  // Enable compression:
862  {
863  cPacketizer Pkt(*this, pktStartCompression);
865  }
866 
867  m_State = State::Game;
868 
869  {
870  cPacketizer Pkt(*this, pktLoginSuccess);
873  }
874 }
875 
876 
877 
878 
879 
881 {
882  ASSERT(m_State == 3); // In game mode?
883  double PosX = a_Painting.GetPosX();
884  double PosY = a_Painting.GetPosY();
885  double PosZ = a_Painting.GetPosZ();
886 
887  cPacketizer Pkt(*this, pktSpawnPainting);
888  Pkt.WriteVarInt32(a_Painting.GetUniqueID());
889  Pkt.WriteString(a_Painting.GetName());
890  Pkt.WriteXYZPosition64(static_cast<Int32>(PosX), static_cast<Int32>(PosY), static_cast<Int32>(PosZ));
891  Pkt.WriteBEInt8(static_cast<Int8>(a_Painting.GetProtocolFacing()));
892 }
893 
894 
895 
896 
897 
898 void cProtocol_1_8_0::SendMapData(const cMap & a_Map, int a_DataStartX, int a_DataStartY)
899 {
900  ASSERT(m_State == 3); // In game mode?
901 
902  cPacketizer Pkt(*this, pktMapData);
903  Pkt.WriteVarInt32(a_Map.GetID());
904  Pkt.WriteBEUInt8(static_cast<UInt8>(a_Map.GetScale()));
905 
906  Pkt.WriteVarInt32(static_cast<UInt32>(a_Map.GetDecorators().size()));
907  for (const auto & Decorator : a_Map.GetDecorators())
908  {
909  Pkt.WriteBEUInt8(static_cast<Byte>((static_cast<Int32>(Decorator.GetType()) << 4) | (Decorator.GetRot() & 0xF)));
910  Pkt.WriteBEUInt8(static_cast<UInt8>(Decorator.GetPixelX()));
911  Pkt.WriteBEUInt8(static_cast<UInt8>(Decorator.GetPixelZ()));
912  }
913 
914  Pkt.WriteBEUInt8(128);
915  Pkt.WriteBEUInt8(128);
916  Pkt.WriteBEUInt8(static_cast<UInt8>(a_DataStartX));
917  Pkt.WriteBEUInt8(static_cast<UInt8>(a_DataStartY));
918  Pkt.WriteVarInt32(static_cast<UInt32>(a_Map.GetData().size()));
919  for (auto itr = a_Map.GetData().cbegin(); itr != a_Map.GetData().cend(); ++itr)
920  {
921  Pkt.WriteBEUInt8(*itr);
922  }
923 }
924 
925 
926 
927 
928 
930 {
931  ASSERT(m_State == 3); // In game mode?
932 
933  Byte Flags = 0;
934  const cPlayer * Player = m_Client->GetPlayer();
935 
936  if (Player->IsGameModeCreative() || Player->IsGameModeSpectator())
937  {
938  Flags |= 0x01; // Invulnerability.
939  }
940  if (Player->IsFlying())
941  {
942  Flags |= 0x02;
943  }
944  if (Player->CanFly())
945  {
946  Flags |= 0x04;
947  }
948  if (Player->IsGameModeCreative())
949  {
950  Flags |= 0x08; // Godmode: creative instant break.
951  }
952 
953  cPacketizer Pkt(*this, pktPlayerAbilities);
954  Pkt.WriteBEUInt8(Flags);
955  Pkt.WriteBEFloat(static_cast<float>(0.05 * Player->GetFlyingMaxSpeed()));
956  Pkt.WriteBEFloat(static_cast<float>(0.1 * Player->GetNormalMaxSpeed()));
957 }
958 
959 
960 
961 
962 
963 void cProtocol_1_8_0::SendParticleEffect(const AString & a_ParticleName, Vector3f a_Src, Vector3f a_Offset, float a_ParticleData, int a_ParticleAmount)
964 {
965  ASSERT(m_State == 3); // In game mode?
966 
967  cPacketizer Pkt(*this, pktParticleEffect);
968  Pkt.WriteBEInt32(GetProtocolParticleID(a_ParticleName));
969  Pkt.WriteBool(false);
970  Pkt.WriteBEFloat(a_Src.x);
971  Pkt.WriteBEFloat(a_Src.y);
972  Pkt.WriteBEFloat(a_Src.z);
973  Pkt.WriteBEFloat(a_Offset.x);
974  Pkt.WriteBEFloat(a_Offset.y);
975  Pkt.WriteBEFloat(a_Offset.z);
976  Pkt.WriteBEFloat(a_ParticleData);
977  Pkt.WriteBEInt32(a_ParticleAmount);
978 }
979 
980 
981 
982 
983 
984 void cProtocol_1_8_0::SendParticleEffect(const AString & a_ParticleName, Vector3f a_Src, Vector3f a_Offset, float a_ParticleData, int a_ParticleAmount, std::array<int, 2> a_Data)
985 {
986  ASSERT(m_State == 3); // In game mode?
987 
988  const auto ParticleID = GetProtocolParticleID(a_ParticleName);
989 
990  cPacketizer Pkt(*this, pktParticleEffect);
991  Pkt.WriteBEInt32(ParticleID);
992  Pkt.WriteBool(false);
993  Pkt.WriteBEFloat(a_Src.x);
994  Pkt.WriteBEFloat(a_Src.y);
995  Pkt.WriteBEFloat(a_Src.z);
996  Pkt.WriteBEFloat(a_Offset.x);
997  Pkt.WriteBEFloat(a_Offset.y);
998  Pkt.WriteBEFloat(a_Offset.z);
999  Pkt.WriteBEFloat(a_ParticleData);
1000  Pkt.WriteBEInt32(a_ParticleAmount);
1001 
1002  switch (ParticleID)
1003  {
1004  // iconcrack
1005  case 36:
1006  {
1007  Pkt.WriteVarInt32(static_cast<UInt32>(a_Data[0]));
1008  Pkt.WriteVarInt32(static_cast<UInt32>(a_Data[1]));
1009  break;
1010  }
1011  // blockcrack
1012  // blockdust
1013  case 37:
1014  case 38:
1015  {
1016  Pkt.WriteVarInt32(static_cast<UInt32>(a_Data[0]));
1017  break;
1018  }
1019  }
1020 }
1021 
1022 
1023 
1024 
1025 
1027 {
1028  ASSERT(m_State == 3); // In game mode?
1029 
1030  cPacketizer Pkt(*this, pktPlayerList);
1031  Pkt.WriteVarInt32(0);
1032  Pkt.WriteVarInt32(1);
1033  Pkt.WriteUUID(a_Player.GetUUID());
1034  Pkt.WriteString(a_Player.GetPlayerListName());
1035 
1036  const Json::Value & Properties = a_Player.GetClientHandle()->GetProperties();
1037  Pkt.WriteVarInt32(Properties.size());
1038  for (auto & Node : Properties)
1039  {
1040  Pkt.WriteString(Node.get("name", "").asString());
1041  Pkt.WriteString(Node.get("value", "").asString());
1042  AString Signature = Node.get("signature", "").asString();
1043  if (Signature.empty())
1044  {
1045  Pkt.WriteBool(false);
1046  }
1047  else
1048  {
1049  Pkt.WriteBool(true);
1050  Pkt.WriteString(Signature);
1051  }
1052  }
1053 
1054  Pkt.WriteVarInt32(static_cast<UInt32>(a_Player.GetEffectiveGameMode()));
1055  Pkt.WriteVarInt32(static_cast<UInt32>(a_Player.GetClientHandle()->GetPing()));
1056  Pkt.WriteBool(false);
1057 }
1058 
1059 
1060 
1061 
1062 
1064 {
1065  ASSERT(m_State == 3); // In game mode?
1066 
1068  Pkt.WriteString(a_Header.CreateJsonString(false));
1069  Pkt.WriteString(a_Footer.CreateJsonString(false));
1070 }
1071 
1072 
1073 
1074 
1075 
1077 {
1078  ASSERT(m_State == 3); // In game mode?
1079 
1080  cPacketizer Pkt(*this, pktPlayerList);
1081  Pkt.WriteVarInt32(4);
1082  Pkt.WriteVarInt32(1);
1083  Pkt.WriteUUID(a_Player.GetUUID());
1084 }
1085 
1086 
1087 
1088 
1089 
1090 void cProtocol_1_8_0::SendPlayerListUpdateDisplayName(const cPlayer & a_Player, const AString & a_CustomName)
1091 {
1092  ASSERT(m_State == 3); // In game mode?
1093 
1094  cPacketizer Pkt(*this, pktPlayerList);
1095  Pkt.WriteVarInt32(3);
1096  Pkt.WriteVarInt32(1);
1097  Pkt.WriteUUID(a_Player.GetUUID());
1098 
1099  if (a_CustomName.empty())
1100  {
1101  Pkt.WriteBool(false);
1102  }
1103  else
1104  {
1105  Pkt.WriteBool(true);
1106  Pkt.WriteString(JsonUtils::SerializeSingleValueJsonObject("text", a_CustomName));
1107  }
1108 }
1109 
1110 
1111 
1112 
1113 
1115 {
1116  ASSERT(m_State == 3); // In game mode?
1117 
1118  cPacketizer Pkt(*this, pktPlayerList);
1119  Pkt.WriteVarInt32(1);
1120  Pkt.WriteVarInt32(1);
1121  Pkt.WriteUUID(a_Player.GetUUID());
1122  Pkt.WriteVarInt32(static_cast<UInt32>(a_Player.GetEffectiveGameMode()));
1123 }
1124 
1125 
1126 
1127 
1128 
1130 {
1131  ASSERT(m_State == 3); // In game mode?
1132 
1133  cPacketizer Pkt(*this, pktPlayerList);
1134  Pkt.WriteVarInt32(2);
1135 
1136  const auto World = m_Client->GetPlayer()->GetWorld();
1137  Pkt.WriteVarInt32(static_cast<UInt32>(World->GetPlayerCount()));
1138  World->ForEachPlayer([&Pkt](cPlayer & a_Player)
1139  {
1140  Pkt.WriteUUID(a_Player.GetUUID());
1141  Pkt.WriteVarInt32(static_cast<UInt32>(a_Player.GetClientHandle()->GetPing()));
1142  return false;
1143  });
1144 }
1145 
1146 
1147 
1148 
1149 
1150 void cProtocol_1_8_0::SendPlayerMoveLook (const Vector3d a_Pos, const float a_Yaw, const float a_Pitch, const bool a_IsRelative)
1151 {
1152  ASSERT(m_State == 3); // In game mode?
1153 
1154  cPacketizer Pkt(*this, pktPlayerMoveLook);
1155  Pkt.WriteBEDouble(a_Pos.x);
1156  Pkt.WriteBEDouble(a_Pos.y);
1157  Pkt.WriteBEDouble(a_Pos.z);
1158  Pkt.WriteBEFloat(a_Yaw);
1159  Pkt.WriteBEFloat(a_Pitch);
1160 
1161  if (a_IsRelative)
1162  {
1163  // Set all bits to 1 - makes everything relative
1164  Pkt.WriteBEUInt8(static_cast<UInt8>(-1));
1165  }
1166  else
1167  {
1168  // Set all bits to 0 - make everything absolute
1169  Pkt.WriteBEUInt8(0);
1170  }
1171 }
1172 
1173 
1174 
1175 
1176 
1178 {
1179  cPlayer * Player = m_Client->GetPlayer();
1180  SendPlayerMoveLook(Player->GetPosition(), static_cast<float>(Player->GetYaw()), static_cast<float>(Player->GetPitch()), false);
1181 }
1182 
1183 
1184 
1185 
1186 
1188 {
1189  // 1.8 has no concept of a permission level.
1190 }
1191 
1192 
1193 
1194 
1195 
1197 {
1198  // There is no dedicated packet for this, send the whole thing:
1200 }
1201 
1202 
1203 
1204 
1205 
1207 {
1208  // Called to spawn another player for the client
1209  cPacketizer Pkt(*this, pktSpawnOtherPlayer);
1210  Pkt.WriteVarInt32(a_Player.GetUniqueID());
1211  Pkt.WriteUUID(a_Player.GetUUID());
1212  Vector3d LastSentPos = a_Player.GetLastSentPosition();
1213  Pkt.WriteFPInt(LastSentPos.x);
1214  Pkt.WriteFPInt(LastSentPos.y + 0.001); // The "+ 0.001" is there because otherwise the player falls through the block they were standing on.
1215  Pkt.WriteFPInt(LastSentPos.z);
1216  Pkt.WriteByteAngle(a_Player.GetYaw());
1217  Pkt.WriteByteAngle(a_Player.GetPitch());
1218  Pkt.WriteBEInt16(a_Player.GetEquippedItem().IsEmpty() ? 0 : a_Player.GetEquippedItem().m_ItemType);
1219  WriteEntityMetadata(Pkt, a_Player);
1220  Pkt.WriteBEUInt8(0x7f); // Metadata: end
1221 }
1222 
1223 
1224 
1225 
1226 
1228 {
1229  ASSERT(m_State == 3); // In game mode?
1230 
1231  cPacketizer Pkt(*this, pktPluginMessage);
1232  Pkt.WriteString(a_Channel);
1233  Pkt.WriteBuf(a_Message);
1234 }
1235 
1236 
1237 
1238 
1239 
1240 void cProtocol_1_8_0::SendRemoveEntityEffect(const cEntity & a_Entity, int a_EffectID)
1241 {
1242  ASSERT(m_State == 3); // In game mode?
1243 
1244  cPacketizer Pkt(*this, pktRemoveEntityEffect);
1245  Pkt.WriteVarInt32(a_Entity.GetUniqueID());
1246  Pkt.WriteBEUInt8(static_cast<UInt8>(a_EffectID));
1247 }
1248 
1249 
1250 
1251 
1252 
1254 {
1255  ASSERT(m_State == 3); // In game mode?
1256 
1257  cPacketizer Pkt(*this, pktTitle);
1258  Pkt.WriteVarInt32(4); // Reset title
1259 }
1260 
1261 
1262 
1263 
1264 
1265 void cProtocol_1_8_0::SendResourcePack(const AString & a_ResourcePackUrl)
1266 {
1267  cPacketizer Pkt(*this, pktResourcePack);
1268 
1269  cSha1Checksum Checksum;
1270  Checksum.Update(reinterpret_cast<const Byte *>(a_ResourcePackUrl.c_str()), a_ResourcePackUrl.size());
1271  Byte Digest[20];
1272  Checksum.Finalize(Digest);
1273  AString Sha1Output;
1274  cSha1Checksum::DigestToHex(Digest, Sha1Output);
1275 
1276  Pkt.WriteString(a_ResourcePackUrl);
1277  Pkt.WriteString(Sha1Output);
1278 }
1279 
1280 
1281 
1282 
1283 
1285 {
1286  cPacketizer Pkt(*this, pktRespawn);
1287  cPlayer * Player = m_Client->GetPlayer();
1288  Pkt.WriteBEInt32(static_cast<Int32>(a_Dimension));
1289  Pkt.WriteBEUInt8(2); // TODO: Difficulty (set to Normal)
1290  Pkt.WriteBEUInt8(static_cast<Byte>(Player->GetEffectiveGameMode()));
1291  Pkt.WriteString("default");
1292 }
1293 
1294 
1295 
1296 
1297 
1298 void cProtocol_1_8_0::SendScoreboardObjective(const AString & a_Name, const AString & a_DisplayName, Byte a_Mode)
1299 {
1300  ASSERT(m_State == 3); // In game mode?
1301 
1302  cPacketizer Pkt(*this, pktScoreboardObjective);
1303  Pkt.WriteString(a_Name);
1304  Pkt.WriteBEUInt8(a_Mode);
1305  if ((a_Mode == 0) || (a_Mode == 2))
1306  {
1307  Pkt.WriteString(a_DisplayName);
1308  Pkt.WriteString("integer");
1309  }
1310 }
1311 
1312 
1313 
1314 
1315 
1316 void cProtocol_1_8_0::SendScoreUpdate(const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode)
1317 {
1318  ASSERT(m_State == 3); // In game mode?
1319 
1320  cPacketizer Pkt(*this, pktUpdateScore);
1321  Pkt.WriteString(a_Player);
1322  Pkt.WriteBEUInt8(a_Mode);
1323  Pkt.WriteString(a_Objective);
1324 
1325  if (a_Mode != 1)
1326  {
1327  Pkt.WriteVarInt32(static_cast<UInt32>(a_Score));
1328  }
1329 }
1330 
1331 
1332 
1333 
1334 
1336 {
1337  ASSERT(m_State == 3); // In game mode?
1338 
1339  cPacketizer Pkt(*this, pktDisplayObjective);
1340  Pkt.WriteBEUInt8(static_cast<UInt8>(a_Display));
1341  Pkt.WriteString(a_Objective);
1342 }
1343 
1344 
1345 
1346 
1347 
1349 {
1350  SendSetRawSubTitle(a_SubTitle.CreateJsonString(false));
1351 }
1352 
1353 
1354 
1355 
1356 
1358 {
1359  ASSERT(m_State == 3); // In game mode?
1360 
1361  cPacketizer Pkt(*this, pktTitle);
1362  Pkt.WriteVarInt32(1); // Set subtitle
1363  Pkt.WriteString(a_SubTitle);
1364 }
1365 
1366 
1367 
1368 
1369 
1371 {
1372  SendSetRawTitle(a_Title.CreateJsonString(false));
1373 }
1374 
1375 
1376 
1377 
1378 
1380 {
1381  ASSERT(m_State == 3); // In game mode?
1382 
1383  cPacketizer Pkt(*this, pktTitle);
1384  Pkt.WriteVarInt32(0); // Set title
1385  Pkt.WriteString(a_Title);
1386 }
1387 
1388 
1389 
1390 
1391 
1392 void cProtocol_1_8_0::SendSoundEffect(const AString & a_SoundName, Vector3d a_Origin, float a_Volume, float a_Pitch)
1393 {
1394  ASSERT(m_State == 3); // In game mode?
1395 
1396  cPacketizer Pkt(*this, pktSoundEffect);
1397  Pkt.WriteString(a_SoundName);
1398  Pkt.WriteBEInt32(static_cast<Int32>(a_Origin.x * 8.0));
1399  Pkt.WriteBEInt32(static_cast<Int32>(a_Origin.y * 8.0));
1400  Pkt.WriteBEInt32(static_cast<Int32>(a_Origin.z * 8.0));
1401  Pkt.WriteBEFloat(a_Volume);
1402  Pkt.WriteBEUInt8(static_cast<Byte>(a_Pitch * 63));
1403 }
1404 
1405 
1406 
1407 
1408 
1409 void cProtocol_1_8_0::SendSoundParticleEffect(const EffectID a_EffectID, Vector3i a_Origin, int a_Data)
1410 {
1411  ASSERT(m_State == 3); // In game mode?
1412 
1413  cPacketizer Pkt(*this, pktSoundParticleEffect);
1414  Pkt.WriteBEInt32(static_cast<int>(a_EffectID));
1415  Pkt.WriteXYZPosition64(a_Origin);
1416  Pkt.WriteBEInt32(a_Data);
1417  Pkt.WriteBool(false);
1418 }
1419 
1420 
1421 
1422 
1423 
1425 {
1426  Int32 EntityData = /* Default: velocity present flag */ 1;
1427  const auto EntityType = GetProtocolEntityType(a_Entity);
1428 
1429  if (a_Entity.IsMinecart())
1430  {
1431  const auto & Cart = static_cast<const cMinecart &>(a_Entity);
1432  EntityData = static_cast<Int32>(Cart.GetPayload());
1433  }
1434  else if (a_Entity.IsItemFrame())
1435  {
1436  const auto & Frame = static_cast<const cItemFrame &>(a_Entity);
1437  EntityData = static_cast<Int32>(Frame.GetProtocolFacing());
1438  }
1439  else if (a_Entity.IsFallingBlock())
1440  {
1441  const auto & Block = static_cast<const cFallingBlock &>(a_Entity);
1442  EntityData = Block.GetBlockType() | (static_cast<Int32>(Block.GetBlockMeta()) << 12);
1443  }
1444  else if (a_Entity.IsFloater())
1445  {
1446  const auto & Floater = static_cast<const cFloater &>(a_Entity);
1447  EntityData = static_cast<Int32>(Floater.GetOwnerID());
1448  }
1449  else if (a_Entity.IsProjectile())
1450  {
1451  using PType = cProjectileEntity::eKind;
1452  const auto & Projectile = static_cast<const cProjectileEntity &>(a_Entity);
1453 
1454  if (Projectile.GetProjectileKind() == PType::pkArrow)
1455  {
1456  const auto & Arrow = static_cast<const cArrowEntity &>(Projectile);
1457  EntityData = static_cast<Int32>(Arrow.GetCreatorUniqueID() + 1);
1458  }
1459  }
1460 
1461  SendEntitySpawn(a_Entity, EntityType, EntityData);
1462 }
1463 
1464 
1465 
1466 
1467 
1469 {
1470  ASSERT(m_State == 3); // In game mode?
1471 
1472  const auto MobType = GetProtocolMobType(a_Mob.GetMobType());
1473 
1474  // If the type is not valid in this protocol bail out:
1475  if (MobType == 0)
1476  {
1477  return;
1478  }
1479 
1480  cPacketizer Pkt(*this, pktSpawnMob);
1481  Pkt.WriteVarInt32(a_Mob.GetUniqueID());
1482  Pkt.WriteBEUInt8(static_cast<Byte>(MobType));
1483  Vector3d LastSentPos = a_Mob.GetLastSentPosition();
1484  Pkt.WriteFPInt(LastSentPos.x);
1485  Pkt.WriteFPInt(LastSentPos.y);
1486  Pkt.WriteFPInt(LastSentPos.z);
1487  Pkt.WriteByteAngle(a_Mob.GetHeadYaw()); // Doesn't seem to be used
1488  Pkt.WriteByteAngle(a_Mob.GetPitch());
1489  Pkt.WriteByteAngle(a_Mob.GetYaw());
1490  Pkt.WriteBEInt16(static_cast<Int16>(a_Mob.GetSpeedX() * 400));
1491  Pkt.WriteBEInt16(static_cast<Int16>(a_Mob.GetSpeedY() * 400));
1492  Pkt.WriteBEInt16(static_cast<Int16>(a_Mob.GetSpeedZ() * 400));
1493  WriteEntityMetadata(Pkt, a_Mob);
1494  Pkt.WriteBEUInt8(0x7f); // Metadata terminator
1495 }
1496 
1497 
1498 
1499 
1500 
1502 {
1503  ASSERT(m_State == 3); // In game mode?
1504 
1505  cPacketizer Pkt(*this, pktStatistics);
1506 
1507  // No need to check Size != 0.
1508  // Assume that the vast majority of the time there's at least one statistic to send:
1509  Pkt.WriteVarInt32(static_cast<UInt32>(a_Manager.Custom.size()));
1510 
1511  for (const auto & [Statistic, Value] : a_Manager.Custom)
1512  {
1513  Pkt.WriteString(GetProtocolStatisticName(Statistic));
1514  Pkt.WriteVarInt32(static_cast<UInt32>(Value));
1515  }
1516 }
1517 
1518 
1519 
1520 
1521 
1523 {
1524  ASSERT(m_State == 3); // In game mode?
1525 
1527  Pkt.WriteVarInt32(static_cast<UInt32>(a_Results.size()));
1528 
1529  for (AStringVector::const_iterator itr = a_Results.begin(), end = a_Results.end(); itr != end; ++itr)
1530  {
1531  Pkt.WriteString(*itr);
1532  }
1533 }
1534 
1535 
1536 
1537 
1538 
1540 {
1541  ASSERT(m_State == 3); // In game mode?
1542 
1543  cPacketizer Pkt(*this, pktSpawnGlobalEntity);
1544  Pkt.WriteVarInt32(0); // EntityID = 0, always
1545  Pkt.WriteBEUInt8(1); // Type = Thunderbolt
1546  Pkt.WriteFPInt(a_Origin.x);
1547  Pkt.WriteFPInt(a_Origin.y);
1548  Pkt.WriteFPInt(a_Origin.z);
1549 }
1550 
1551 
1552 
1553 
1554 
1555 void cProtocol_1_8_0::SendTitleTimes(int a_FadeInTicks, int a_DisplayTicks, int a_FadeOutTicks)
1556 {
1557  ASSERT(m_State == 3); // In game mode?
1558 
1559  cPacketizer Pkt(*this, pktTitle);
1560  Pkt.WriteVarInt32(2); // Set title display times
1561  Pkt.WriteBEInt32(a_FadeInTicks);
1562  Pkt.WriteBEInt32(a_DisplayTicks);
1563  Pkt.WriteBEInt32(a_FadeOutTicks);
1564 }
1565 
1566 
1567 
1568 
1569 
1570 void cProtocol_1_8_0::SendTimeUpdate(const cTickTimeLong a_WorldAge, const cTickTimeLong a_WorldDate, const bool a_DoDaylightCycle)
1571 {
1572  ASSERT(m_State == 3); // In game mode?
1573 
1574  cPacketizer Pkt(*this, pktTimeUpdate);
1575  Pkt.WriteBEInt64(a_WorldAge.count());
1576 
1577  if (a_DoDaylightCycle)
1578  {
1579  Pkt.WriteBEInt64(a_WorldDate.count());
1580  }
1581  else
1582  {
1583  // Negating the date stops time from advancing on the client
1584  // (the std::min construction is to handle the case where the date is exactly zero):
1585  Pkt.WriteBEInt64(std::min(-a_WorldDate.count(), -1LL));
1586  }
1587 }
1588 
1589 
1590 
1591 
1592 
1593 void cProtocol_1_8_0::SendUnloadChunk(int a_ChunkX, int a_ChunkZ)
1594 {
1595  ASSERT(m_State == 3); // In game mode?
1596 
1597  cPacketizer Pkt(*this, pktUnloadChunk);
1598  Pkt.WriteBEInt32(a_ChunkX);
1599  Pkt.WriteBEInt32(a_ChunkZ);
1600  Pkt.WriteBool(true);
1601  Pkt.WriteBEInt16(0); // Primary bitmap
1602  Pkt.WriteVarInt32(0); // Data size
1603 }
1604 
1605 
1606 
1607 
1608 
1610 {
1611  ASSERT(m_State == 3); // In game mode?
1612 
1613  Byte Action;
1614  switch (a_BlockEntity.GetBlockType())
1615  {
1616  case E_BLOCK_CHEST:
1618  case E_BLOCK_END_PORTAL:
1619  case E_BLOCK_TRAPPED_CHEST:
1620  {
1621  // The ones with a action of 0 is just a workaround to send the block entities to a client.
1622  // Todo: 18.09.2020 - remove this when block entities are transmitted in the ChunkData packet - 12xx12
1623  Action = 0;
1624  break;
1625  }
1626 
1627  case E_BLOCK_MOB_SPAWNER: Action = 1; break; // Update mob spawner spinny mob thing
1628  case E_BLOCK_COMMAND_BLOCK: Action = 2; break; // Update command block text
1629  case E_BLOCK_BEACON: Action = 3; break; // Update beacon entity
1630  case E_BLOCK_HEAD: Action = 4; break; // Update mobhead entity
1631  case E_BLOCK_FLOWER_POT: Action = 5; break; // Update flower pot
1632  case E_BLOCK_WALL_BANNER:
1633  case E_BLOCK_STANDING_BANNER: Action = 6; break; // Update banner
1634 
1635  default: return; // Block entities change between versions
1636  }
1637 
1638  cPacketizer Pkt(*this, pktUpdateBlockEntity);
1639  Pkt.WriteXYZPosition64(a_BlockEntity.GetPosX(), a_BlockEntity.GetPosY(), a_BlockEntity.GetPosZ());
1640  Pkt.WriteBEUInt8(Action);
1641 
1642  cFastNBTWriter Writer;
1643  WriteBlockEntity(Writer, a_BlockEntity);
1644  Writer.Finish();
1645  Pkt.WriteBuf(Writer.GetResult());
1646 }
1647 
1648 
1649 
1650 
1651 
1652 void cProtocol_1_8_0::SendUpdateSign(Vector3i a_BlockPos, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4)
1653 {
1654  ASSERT(m_State == 3); // In game mode?
1655 
1656  cPacketizer Pkt(*this, pktUpdateSign);
1657  Pkt.WriteXYZPosition64(a_BlockPos);
1658 
1659  AString Lines[] = { a_Line1, a_Line2, a_Line3, a_Line4 };
1660  for (size_t i = 0; i < ARRAYCOUNT(Lines); i++)
1661  {
1663  }
1664 }
1665 
1666 
1667 
1668 
1669 
1671 {
1672  // Client doesn't support this feature
1673  return;
1674 }
1675 
1676 
1677 
1678 
1679 
1681 {
1682  // Client doesn't support this feature
1683  return;
1684 }
1685 
1686 
1687 
1688 
1689 
1691 {
1692  ASSERT(m_State == 3); // In game mode?
1693 
1694  {
1695  cPacketizer Pkt(*this, pktWeather);
1696  Pkt.WriteBEUInt8((a_Weather == wSunny) ? 1 : 2); // End rain / begin rain
1697  Pkt.WriteBEFloat(0); // Unused for weather
1698  }
1699 
1700  // TODO: Fade effect, somehow
1701 }
1702 
1703 
1704 
1705 
1706 
1708 {
1709  ASSERT(m_State == 3); // In game mode?
1710 
1711  cPacketizer Pkt(*this, pktWindowItems);
1712  Pkt.WriteBEUInt8(static_cast<UInt8>(a_Window.GetWindowID()));
1713  Pkt.WriteBEInt16(static_cast<Int16>(a_Window.GetNumSlots()));
1714  cItems Slots;
1715  a_Window.GetSlots(*(m_Client->GetPlayer()), Slots);
1716  for (cItems::const_iterator itr = Slots.begin(), end = Slots.end(); itr != end; ++itr)
1717  {
1718  WriteItem(Pkt, *itr);
1719  } // for itr - Slots[]
1720 }
1721 
1722 
1723 
1724 
1725 
1727 {
1728  ASSERT(m_State == 3); // In game mode?
1729 
1730  cPacketizer Pkt(*this, pktWindowClose);
1731  Pkt.WriteBEUInt8(static_cast<UInt8>(a_Window.GetWindowID()));
1732 }
1733 
1734 
1735 
1736 
1737 
1739 {
1740  ASSERT(m_State == 3); // In game mode?
1741 
1742  if (a_Window.GetWindowType() < 0)
1743  {
1744  // Do not send this packet for player inventory windows
1745  return;
1746  }
1747 
1748  cPacketizer Pkt(*this, pktWindowOpen);
1749  Pkt.WriteBEUInt8(static_cast<UInt8>(a_Window.GetWindowID()));
1750  Pkt.WriteString(a_Window.GetWindowTypeName());
1752 
1753  switch (a_Window.GetWindowType())
1754  {
1755  case cWindow::wtWorkbench:
1757  case cWindow::wtAnvil:
1758  {
1759  Pkt.WriteBEUInt8(0);
1760  break;
1761  }
1762  default:
1763  {
1764  Pkt.WriteBEUInt8(static_cast<UInt8>(a_Window.GetNumNonInventorySlots()));
1765  break;
1766  }
1767  }
1768 
1769  if (a_Window.GetWindowType() == cWindow::wtAnimalChest)
1770  {
1771  UInt32 HorseID = static_cast<const cHorseWindow &>(a_Window).GetHorseID();
1772  Pkt.WriteBEInt32(static_cast<Int32>(HorseID));
1773  }
1774 }
1775 
1776 
1777 
1778 
1779 
1780 void cProtocol_1_8_0::SendWindowProperty(const cWindow & a_Window, size_t a_Property, short a_Value)
1781 {
1782  ASSERT(m_State == 3); // In game mode?
1783 
1784  cPacketizer Pkt(*this, pktWindowProperty);
1785  Pkt.WriteBEUInt8(static_cast<UInt8>(a_Window.GetWindowID()));
1786  Pkt.WriteBEInt16(static_cast<Int16>(a_Property));
1787  Pkt.WriteBEInt16(a_Value);
1788 }
1789 
1790 
1791 
1792 
1793 
1795 {
1796  const auto Uncompressed = a_Packet.GetView();
1797 
1798  if (Uncompressed.size() < CompressionThreshold)
1799  {
1800  /* Size doesn't reach threshold, not worth compressing.
1801 
1802  --------------- Packet format ----------------
1803  |--- Header ---------------------------------|
1804  | PacketSize: Size of all fields below |
1805  | DataSize: Zero, means below not compressed |
1806  |--- Body -----------------------------------|
1807  | a_Packet: copy of uncompressed data |
1808  ----------------------------------------------
1809  */
1810  const UInt32 DataSize = 0;
1811  const auto PacketSize = static_cast<UInt32>(cByteBuffer::GetVarIntSize(DataSize) + Uncompressed.size());
1812 
1813  cByteBuffer LengthHeaderBuffer(
1814  cByteBuffer::GetVarIntSize(PacketSize) +
1815  cByteBuffer::GetVarIntSize(DataSize)
1816  );
1817 
1818  LengthHeaderBuffer.WriteVarInt32(PacketSize);
1819  LengthHeaderBuffer.WriteVarInt32(DataSize);
1820 
1821  ContiguousByteBuffer LengthData;
1822  LengthHeaderBuffer.ReadAll(LengthData);
1823 
1824  a_CompressedData.reserve(LengthData.size() + Uncompressed.size());
1825  a_CompressedData = LengthData;
1826  a_CompressedData += Uncompressed;
1827 
1828  return;
1829  }
1830 
1831  /* Definitely worth compressing.
1832 
1833  --------------- Packet format ----------------
1834  |--- Header ---------------------------------|
1835  | PacketSize: Size of all fields below |
1836  | DataSize: Size of uncompressed a_Packet |
1837  |--- Body -----------------------------------|
1838  | CompressedData: compressed a_Packet |
1839  ----------------------------------------------
1840  */
1841 
1842  const auto CompressedData = a_Packet.Compress();
1843  const auto Compressed = CompressedData.GetView();
1844 
1845  const UInt32 DataSize = static_cast<UInt32>(Uncompressed.size());
1846  const auto PacketSize = static_cast<UInt32>(cByteBuffer::GetVarIntSize(DataSize) + Compressed.size());
1847 
1848  cByteBuffer LengthHeaderBuffer(
1849  cByteBuffer::GetVarIntSize(PacketSize) +
1850  cByteBuffer::GetVarIntSize(DataSize)
1851  );
1852 
1853  LengthHeaderBuffer.WriteVarInt32(PacketSize);
1854  LengthHeaderBuffer.WriteVarInt32(DataSize);
1855 
1856  ContiguousByteBuffer LengthData;
1857  LengthHeaderBuffer.ReadAll(LengthData);
1858 
1859  a_CompressedData.reserve(LengthData.size() + Compressed.size());
1860  a_CompressedData = LengthData;
1861  a_CompressedData += Compressed;
1862 }
1863 
1864 
1865 
1866 
1867 
1869 {
1870  // Normalize the blockface values returned from the protocol
1871  // Anything known gets mapped 1:1, everything else returns BLOCK_FACE_NONE
1872  switch (a_BlockFace)
1873  {
1874  case BLOCK_FACE_XM: return BLOCK_FACE_XM;
1875  case BLOCK_FACE_XP: return BLOCK_FACE_XP;
1876  case BLOCK_FACE_YM: return BLOCK_FACE_YM;
1877  case BLOCK_FACE_YP: return BLOCK_FACE_YP;
1878  case BLOCK_FACE_ZM: return BLOCK_FACE_ZM;
1879  case BLOCK_FACE_ZP: return BLOCK_FACE_ZP;
1880  default: return BLOCK_FACE_NONE;
1881  }
1882 }
1883 
1884 
1885 
1886 
1887 
1889 {
1890  switch (a_PacketType)
1891  {
1892  case pktAttachEntity: return 0x1b;
1893  case pktBlockAction: return 0x24;
1894  case pktBlockBreakAnim: return 0x25;
1895  case pktBlockChange: return 0x23;
1896  case pktBlockChanges: return 0x22;
1897  case pktCameraSetTo: return 0x43;
1898  case pktChatRaw: return 0x02;
1899  case pktCollectEntity: return 0x0d;
1900  case pktDestroyEntity: return 0x13;
1901  case pktDifficulty: return 0x41;
1902  case pktDisconnectDuringGame: return 0x40;
1903  case pktDisconnectDuringLogin: return 0x00;
1904  case pktDisplayObjective: return 0x3d;
1905  case pktEditSign: return 0x36;
1906  case pktEncryptionRequest: return 0x01;
1907  case pktEntityAnimation: return 0x0b;
1908  case pktEntityEffect: return 0x1d;
1909  case pktEntityEquipment: return 0x04;
1910  case pktEntityHeadLook: return 0x19;
1911  case pktEntityLook: return 0x16;
1912  case pktEntityMeta: return 0x1c;
1913  case pktEntityProperties: return 0x20;
1914  case pktEntityRelMove: return 0x15;
1915  case pktEntityRelMoveLook: return 0x17;
1916  case pktEntityStatus: return 0x1a;
1917  case pktEntityVelocity: return 0x12;
1918  case pktExperience: return 0x1f;
1919  case pktExplosion: return 0x27;
1920  case pktGameMode: return 0x2b;
1921  case pktHeldItemChange: return 0x09;
1922  case pktInventorySlot: return 0x2f;
1923  case pktJoinGame: return 0x01;
1924  case pktKeepAlive: return 0x00;
1925  case pktLeashEntity: return 0x1b;
1926  case pktLoginSuccess: return 0x02;
1927  case pktMapData: return 0x34;
1928  case pktParticleEffect: return 0x2a;
1929  case pktPingResponse: return 0x01;
1930  case pktPlayerAbilities: return 0x39;
1931  case pktPlayerList: return 0x38;
1932  case pktPlayerListHeaderFooter: return 0x47;
1933  case pktPlayerMoveLook: return 0x08;
1934  case pktPluginMessage: return 0x3f;
1935  case pktRemoveEntityEffect: return 0x1e;
1936  case pktResourcePack: return 0x48;
1937  case pktRespawn: return 0x07;
1938  case pktScoreboardObjective: return 0x3b;
1939  case pktSoundEffect: return 0x29;
1940  case pktSoundParticleEffect: return 0x28;
1941  case pktSpawnExperienceOrb: return 0x11;
1942  case pktSpawnGlobalEntity: return 0x2c;
1943  case pktSpawnMob: return 0x0f;
1944  case pktSpawnObject: return 0x0e;
1945  case pktSpawnOtherPlayer: return 0x0c;
1946  case pktSpawnPainting: return 0x10;
1947  case pktSpawnPosition: return 0x05;
1948  case pktStartCompression: return 0x03;
1949  case pktStatistics: return 0x37;
1950  case pktStatusResponse: return 0x00;
1951  case pktTabCompletionResults: return 0x3a;
1952  case pktTeleportEntity: return 0x18;
1953  case pktTimeUpdate: return 0x03;
1954  case pktTitle: return 0x45;
1955  case pktUnloadChunk: return 0x21;
1956  case pktUpdateBlockEntity: return 0x35;
1957  case pktUpdateHealth: return 0x06;
1958  case pktUpdateScore: return 0x3c;
1959  case pktUpdateSign: return 0x33;
1960  case pktUseBed: return 0x0a;
1961  case pktWeather: return 0x2b;
1962  case pktWindowClose: return 0x2e;
1963  case pktWindowItems: return 0x30;
1964  case pktWindowOpen: return 0x2d;
1965  case pktWindowProperty: return 0x31;
1966  default:
1967  {
1968  LOG("Unhandled outgoing packet type: %s (0x%02x)", cPacketizer::PacketTypeToStr(a_PacketType), a_PacketType);
1969  ASSERT(!"Unhandled outgoing packet type");
1970  return 0;
1971  }
1972  }
1973 }
1974 
1975 
1976 
1977 
1978 
1979 unsigned char cProtocol_1_8_0::GetProtocolEntityAnimation(const EntityAnimation a_Animation) const
1980 {
1981  switch (a_Animation)
1982  {
1985  case EntityAnimation::PlayerLeavesBed: return 2;
1987  case EntityAnimation::PlayerOffHandSwings: return 0;
1988  default: return static_cast<unsigned char>(-1);
1989  }
1990 }
1991 
1992 
1993 
1994 
1995 
1996 signed char cProtocol_1_8_0::GetProtocolEntityStatus(const EntityAnimation a_Animation) const
1997 {
1998  switch (a_Animation)
1999  {
2000  case EntityAnimation::AnimalFallsInLove: return 18;
2002  case EntityAnimation::GuardianAttacks: return 21;
2003  case EntityAnimation::HorseTamingFails: return 6;
2004  case EntityAnimation::HorseTamingSucceeds: return 7;
2005  case EntityAnimation::IronGolemAttacks: return 4;
2006  case EntityAnimation::IronGolemOffersGift: return 11;
2008  case EntityAnimation::MinecartTNTIgnites: return 10;
2009  case EntityAnimation::MobSpawns: return 20;
2010  case EntityAnimation::OcelotTrusts: return 6;
2011  case EntityAnimation::OcelotDistrusts: return 7;
2012  case EntityAnimation::PawnBerryBushPricks: return 2;
2013  case EntityAnimation::PawnBurns: return 2;
2014  case EntityAnimation::PawnDies: return 3;
2015  case EntityAnimation::PawnDrowns: return 2;
2016  case EntityAnimation::PawnHurts: return 2;
2017  case EntityAnimation::PawnThornsPricks: return 2;
2019  case EntityAnimation::RabbitJumps: return 1;
2020  case EntityAnimation::SheepEatsGrass: return 10;
2021  case EntityAnimation::VillagerKisses: return 12;
2022  case EntityAnimation::VillagerShowsAnger: return 13;
2024  case EntityAnimation::WitchMagicks: return 15;
2025  case EntityAnimation::WolfShakesWater: return 8;
2026  case EntityAnimation::WolfTamingFails: return 6;
2027  case EntityAnimation::WolfTamingSucceeds: return 7;
2029  default: return -1;
2030  }
2031 }
2032 
2033 
2034 
2035 
2036 
2038 {
2039  switch (a_MobType)
2040  {
2041  // Map invalid type to Giant for easy debugging (if this ever spawns, something has gone very wrong)
2042  case mtInvalidType: return 53;
2043  case mtBat: return 65;
2044  case mtBlaze: return 61;
2045  case mtCaveSpider: return 59;
2046  case mtChicken: return 93;
2047  case mtCow: return 92;
2048  case mtCreeper: return 50;
2049  case mtEnderDragon: return 63;
2050  case mtEnderman: return 58;
2051  case mtEndermite: return 67;
2052  case mtGhast: return 56;
2053  case mtGiant: return 53;
2054  case mtGuardian: return 68;
2055  case mtHorse: return 100;
2056  case mtIronGolem: return 99;
2057  case mtMagmaCube: return 62;
2058  case mtMooshroom: return 96;
2059  case mtOcelot: return 98;
2060  case mtPig: return 90;
2061  case mtRabbit: return 101;
2062  case mtSheep: return 91;
2063  case mtSilverfish: return 60;
2064  case mtSkeleton: return 51;
2065  case mtSlime: return 55;
2066  case mtSnowGolem: return 97;
2067  case mtSpider: return 52;
2068  case mtSquid: return 94;
2069  case mtVillager: return 120;
2070  case mtWitch: return 66;
2071  case mtWither: return 64;
2072  case mtWitherSkeleton: return 51;
2073  case mtWolf: return 95;
2074  case mtZombie: return 54;
2075  case mtZombiePigman: return 57;
2076  case mtZombieVillager: return 27;
2077 
2078  // Mobs that get replaced with another because they were added later
2079  case mtCat: return GetProtocolMobType(mtOcelot);
2080  case mtDonkey: return GetProtocolMobType(mtHorse);
2081  case mtMule: return GetProtocolMobType(mtHorse);
2084  case mtStray: return GetProtocolMobType(mtSkeleton);
2085  case mtHusk: return GetProtocolMobType(mtZombie);
2086 
2087  default: return 0;
2088  }
2089 }
2090 
2091 
2092 
2093 
2094 
2096 {
2097  return Version::v1_8_0;
2098 }
2099 
2100 
2101 
2102 
2103 
2104 bool cProtocol_1_8_0::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType)
2105 {
2106  switch (m_State)
2107  {
2108  case State::Status:
2109  {
2110  switch (a_PacketType)
2111  {
2112  case 0x00: HandlePacketStatusRequest(a_ByteBuffer); return true;
2113  case 0x01: HandlePacketStatusPing (a_ByteBuffer); return true;
2114  }
2115  break;
2116  }
2117 
2118  case State::Login:
2119  {
2120  switch (a_PacketType)
2121  {
2122  case 0x00: HandlePacketLoginStart (a_ByteBuffer); return true;
2123  case 0x01: HandlePacketLoginEncryptionResponse(a_ByteBuffer); return true;
2124  }
2125  break;
2126  }
2127 
2128  case State::Game:
2129  {
2130  switch (a_PacketType)
2131  {
2132  case 0x00: HandlePacketKeepAlive (a_ByteBuffer); return true;
2133  case 0x01: HandlePacketChatMessage (a_ByteBuffer); return true;
2134  case 0x02: HandlePacketUseEntity (a_ByteBuffer); return true;
2135  case 0x03: HandlePacketPlayer (a_ByteBuffer); return true;
2136  case 0x04: HandlePacketPlayerPos (a_ByteBuffer); return true;
2137  case 0x05: HandlePacketPlayerLook (a_ByteBuffer); return true;
2138  case 0x06: HandlePacketPlayerPosLook (a_ByteBuffer); return true;
2139  case 0x07: HandlePacketBlockDig (a_ByteBuffer); return true;
2140  case 0x08: HandlePacketBlockPlace (a_ByteBuffer); return true;
2141  case 0x09: HandlePacketSlotSelect (a_ByteBuffer); return true;
2142  case 0x0a: HandlePacketAnimation (a_ByteBuffer); return true;
2143  case 0x0b: HandlePacketEntityAction (a_ByteBuffer); return true;
2144  case 0x0c: HandlePacketSteerVehicle (a_ByteBuffer); return true;
2145  case 0x0d: HandlePacketWindowClose (a_ByteBuffer); return true;
2146  case 0x0e: HandlePacketWindowClick (a_ByteBuffer); return true;
2147  case 0x0f: // Confirm transaction - not used in MCS
2148  case 0x10: HandlePacketCreativeInventoryAction(a_ByteBuffer); return true;
2149  case 0x11: HandlePacketEnchantItem (a_ByteBuffer); return true;
2150  case 0x12: HandlePacketUpdateSign (a_ByteBuffer); return true;
2151  case 0x13: HandlePacketPlayerAbilities (a_ByteBuffer); return true;
2152  case 0x14: HandlePacketTabComplete (a_ByteBuffer); return true;
2153  case 0x15: HandlePacketClientSettings (a_ByteBuffer); return true;
2154  case 0x16: HandlePacketClientStatus (a_ByteBuffer); return true;
2155  case 0x17: HandlePacketPluginMessage (a_ByteBuffer); return true;
2156  case 0x18: HandlePacketSpectate (a_ByteBuffer); return true;
2157  case 0x19: HandlePacketResourcePackStatus (a_ByteBuffer); return true;
2158  }
2159  break;
2160  }
2161  } // switch (m_State)
2162 
2163  // Unknown packet type, report to the ClientHandle:
2164  m_Client->PacketUnknown(a_PacketType);
2165  return false;
2166 }
2167 
2168 
2169 
2170 
2171 
2173 {
2174  HANDLE_READ(a_ByteBuffer, ReadBEInt64, Int64, Timestamp);
2175 
2176  cPacketizer Pkt(*this, pktPingResponse);
2177  Pkt.WriteBEInt64(Timestamp);
2178 }
2179 
2180 
2181 
2182 
2183 
2185 {
2186  cServer * Server = cRoot::Get()->GetServer();
2187  AString ServerDescription = Server->GetDescription();
2188  auto NumPlayers = static_cast<signed>(Server->GetNumPlayers());
2189  auto MaxPlayers = static_cast<signed>(Server->GetMaxPlayers());
2190  AString Favicon = Server->GetFaviconData();
2191 
2192  cRoot::Get()->GetPluginManager()->CallHookServerPing(*m_Client, ServerDescription, NumPlayers, MaxPlayers, Favicon);
2193 
2194  // Version:
2195  Json::Value Version;
2196  const auto ProtocolVersion = GetProtocolVersion();
2197  Version["name"] = "Cuberite " + cMultiVersionProtocol::GetVersionTextFromInt(ProtocolVersion);
2198  Version["protocol"] = static_cast<std::underlying_type_t<cProtocol::Version>>(ProtocolVersion);
2199 
2200  // Players:
2201  Json::Value Players;
2202  Players["online"] = NumPlayers;
2203  Players["max"] = MaxPlayers;
2204  // TODO: Add "sample"
2205 
2206  // Description:
2207  Json::Value Description;
2208  Description["text"] = std::move(ServerDescription);
2209 
2210  // Create the response:
2211  Json::Value ResponseValue;
2212  ResponseValue["version"] = Version;
2213  ResponseValue["players"] = Players;
2214  ResponseValue["description"] = Description;
2215  m_Client->ForgeAugmentServerListPing(ResponseValue);
2216  if (!Favicon.empty())
2217  {
2218  ResponseValue["favicon"] = "data:image/png;base64," + Favicon;
2219  }
2220 
2221  // Serialize the response into a packet:
2222  cPacketizer Pkt(*this, pktStatusResponse);
2223  Pkt.WriteString(JsonUtils::WriteFastString(ResponseValue));
2224 }
2225 
2226 
2227 
2228 
2229 
2231 {
2232  UInt32 EncKeyLength, EncNonceLength;
2233  if (!a_ByteBuffer.ReadVarInt(EncKeyLength))
2234  {
2235  return;
2236  }
2237  ContiguousByteBuffer EncKey;
2238  if (!a_ByteBuffer.ReadSome(EncKey, EncKeyLength))
2239  {
2240  return;
2241  }
2242  if (!a_ByteBuffer.ReadVarInt(EncNonceLength))
2243  {
2244  return;
2245  }
2246  ContiguousByteBuffer EncNonce;
2247  if (!a_ByteBuffer.ReadSome(EncNonce, EncNonceLength))
2248  {
2249  return;
2250  }
2251  if ((EncKeyLength > MAX_ENC_LEN) || (EncNonceLength > MAX_ENC_LEN))
2252  {
2253  LOGD("Too long encryption");
2254  m_Client->Kick("Hacked client");
2255  return;
2256  }
2257 
2258  // Decrypt EncNonce using privkey
2259  cRsaPrivateKey & rsaDecryptor = cRoot::Get()->GetServer()->GetPrivateKey();
2260  UInt32 DecryptedNonce[MAX_ENC_LEN / sizeof(Int32)];
2261  int res = rsaDecryptor.Decrypt(EncNonce, reinterpret_cast<Byte *>(DecryptedNonce), sizeof(DecryptedNonce));
2262  if (res != 4)
2263  {
2264  LOGD("Bad nonce length: got %d, exp %d", res, 4);
2265  m_Client->Kick("Hacked client");
2266  return;
2267  }
2268  if (ntohl(DecryptedNonce[0]) != static_cast<unsigned>(reinterpret_cast<uintptr_t>(this)))
2269  {
2270  LOGD("Bad nonce value");
2271  m_Client->Kick("Hacked client");
2272  return;
2273  }
2274 
2275  // Decrypt the symmetric encryption key using privkey:
2276  Byte DecryptedKey[MAX_ENC_LEN];
2277  res = rsaDecryptor.Decrypt(EncKey, DecryptedKey, sizeof(DecryptedKey));
2278  if (res != 16)
2279  {
2280  LOGD("Bad key length");
2281  m_Client->Kick("Hacked client");
2282  return;
2283  }
2284 
2285  StartEncryption(DecryptedKey);
2286  m_Client->HandleLogin();
2287 }
2288 
2289 
2290 
2291 
2292 
2294 {
2295  AString Username;
2296  if (!a_ByteBuffer.ReadVarUTF8String(Username))
2297  {
2298  m_Client->Kick("Bad username");
2299  return;
2300  }
2301 
2302  if (!m_Client->HandleHandshake(Username))
2303  {
2304  // The client is not welcome here, they have been sent a Kick packet already
2305  return;
2306  }
2307 
2308  m_Client->SetUsername(std::move(Username));
2309 
2310  // If auth is required, then send the encryption request:
2311  if (const auto Server = cRoot::Get()->GetServer(); Server->ShouldAuthenticate())
2312  {
2313  cPacketizer Pkt(*this, pktEncryptionRequest);
2314  Pkt.WriteString(Server->GetServerID());
2315  const auto PubKeyDer = Server->GetPublicKeyDER();
2316  Pkt.WriteVarInt32(static_cast<UInt32>(PubKeyDer.size()));
2317  Pkt.WriteBuf(PubKeyDer);
2318  Pkt.WriteVarInt32(4);
2319  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 :)
2320  return;
2321  }
2322 
2323  m_Client->HandleLogin();
2324 }
2325 
2326 
2327 
2328 
2329 
2331 {
2332  m_Client->HandleAnimation(true); // Packet exists solely for arm-swing notification (main hand).
2333 }
2334 
2335 
2336 
2337 
2338 
2340 {
2341  HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Status);
2342 
2343  Vector3i Position;
2344  if (!a_ByteBuffer.ReadXYZPosition64(Position))
2345  {
2346  return;
2347  }
2348 
2349  HANDLE_READ(a_ByteBuffer, ReadBEInt8, Int8, Face);
2350 
2352 }
2353 
2354 
2355 
2356 
2357 
2359 {
2360  Vector3i BlockPos;
2361  if (!a_ByteBuffer.ReadXYZPosition64(BlockPos))
2362  {
2363  return;
2364  }
2365 
2366  HANDLE_READ(a_ByteBuffer, ReadBEInt8, Int8, Face);
2367 
2368  cItem Item; // Ignored
2369  ReadItem(a_ByteBuffer, Item, 3);
2370 
2371  HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, CursorX);
2372  HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, CursorY);
2373  HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, CursorZ);
2374 
2375  eBlockFace blockFace = FaceIntToBlockFace(Face);
2376  if (blockFace == eBlockFace::BLOCK_FACE_NONE)
2377  {
2378  m_Client->HandleUseItem(true);
2379  }
2380  else
2381  {
2382  m_Client->HandleRightClick(BlockPos, blockFace, {CursorX, CursorY, CursorZ}, true);
2383  }
2384 }
2385 
2386 
2387 
2388 
2389 
2391 {
2392  HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Message);
2393 
2394  m_Client->HandleChat(Message);
2395 }
2396 
2397 
2398 
2399 
2400 
2402 {
2403  HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Locale);
2404  HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, ViewDistance);
2405  HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, ChatFlags);
2406  HANDLE_READ(a_ByteBuffer, ReadBool, bool, ChatColors);
2407  HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, SkinParts);
2408 
2409  m_Client->SetLocale(Locale);
2410  m_Client->SetViewDistance(ViewDistance);
2411  m_Client->GetPlayer()->SetSkinParts(SkinParts);
2412  // TODO: Handle chat flags and chat colors
2413 }
2414 
2415 
2416 
2417 
2418 
2420 {
2421  HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, ActionID);
2422 
2423  switch (ActionID)
2424  {
2425  case 0:
2426  {
2427  // Respawn
2429  break;
2430  }
2431  case 1:
2432  {
2433  // Request stats
2435  break;
2436  }
2437  case 2:
2438  {
2439  // Open Inventory achievement
2441  break;
2442  }
2443  }
2444 }
2445 
2446 
2447 
2448 
2449 
2451 {
2452  HANDLE_READ(a_ByteBuffer, ReadBEInt16, Int16, SlotNum);
2453 
2454  cItem Item;
2455  if (!ReadItem(a_ByteBuffer, Item))
2456  {
2457  return;
2458  }
2459  m_Client->HandleCreativeInventory(SlotNum, Item, (SlotNum == -1) ? caLeftClickOutside : caLeftClick);
2460 }
2461 
2462 
2463 
2464 
2465 
2467 {
2468  HANDLE_READ(a_ByteBuffer, ReadVarInt, UInt32, PlayerID);
2469  HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Action);
2470  HANDLE_READ(a_ByteBuffer, ReadVarInt, UInt32, JumpBoost);
2471 
2472  if (PlayerID != m_Client->GetPlayer()->GetUniqueID())
2473  {
2474  LOGD("Player \"%s\" attempted to action another entity - hacked client?", m_Client->GetUsername().c_str());
2475  return;
2476  }
2477 
2478  switch (Action)
2479  {
2480  case 0: return m_Client->HandleCrouch(true);
2481  case 1: return m_Client->HandleCrouch(false);
2482  case 2: return m_Client->HandleLeaveBed();
2483  case 3: return m_Client->HandleSprint(true);
2484  case 4: return m_Client->HandleSprint(false);
2485  case 6: return m_Client->HandleOpenHorseInventory();
2486  }
2487 }
2488 
2489 
2490 
2491 
2492 
2494 {
2495  HANDLE_READ(a_ByteBuffer, ReadVarInt, UInt32, KeepAliveID);
2496 
2497  m_Client->HandleKeepAlive(KeepAliveID);
2498 }
2499 
2500 
2501 
2502 
2503 
2505 {
2506  HANDLE_READ(a_ByteBuffer, ReadBool, bool, IsOnGround);
2507  // TODO: m_Client->HandlePlayerOnGround(IsOnGround);
2508 }
2509 
2510 
2511 
2512 
2513 
2515 {
2516  HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Flags);
2517  HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, FlyingSpeed);
2518  HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, WalkingSpeed);
2519 
2520  // COnvert the bitfield into individual boolean flags:
2521  bool IsFlying = false;
2522  if ((Flags & 2) != 0)
2523  {
2524  IsFlying = true;
2525  }
2526 
2527  m_Client->HandlePlayerAbilities(IsFlying, FlyingSpeed, WalkingSpeed);
2528 }
2529 
2530 
2531 
2532 
2533 
2535 {
2536  HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, Yaw);
2537  HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, Pitch);
2538  HANDLE_READ(a_ByteBuffer, ReadBool, bool, IsOnGround);
2539 
2540  m_Client->HandlePlayerLook(Yaw, Pitch, IsOnGround);
2541 }
2542 
2543 
2544 
2545 
2546 
2548 {
2549  HANDLE_READ(a_ByteBuffer, ReadBEDouble, double, PosX);
2550  HANDLE_READ(a_ByteBuffer, ReadBEDouble, double, PosY);
2551  HANDLE_READ(a_ByteBuffer, ReadBEDouble, double, PosZ);
2552  HANDLE_READ(a_ByteBuffer, ReadBool, bool, IsOnGround);
2553 
2554  m_Client->HandlePlayerMove({PosX, PosY, PosZ}, IsOnGround);
2555 }
2556 
2557 
2558 
2559 
2560 
2562 {
2563  HANDLE_READ(a_ByteBuffer, ReadBEDouble, double, PosX);
2564  HANDLE_READ(a_ByteBuffer, ReadBEDouble, double, PosY);
2565  HANDLE_READ(a_ByteBuffer, ReadBEDouble, double, PosZ);
2566  HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, Yaw);
2567  HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, Pitch);
2568  HANDLE_READ(a_ByteBuffer, ReadBool, bool, IsOnGround);
2569 
2570  m_Client->HandlePlayerMoveLook({PosX, PosY, PosZ}, Yaw, Pitch, IsOnGround);
2571 }
2572 
2573 
2574 
2575 
2576 
2578 {
2579  // https://wiki.vg/index.php?title=Plugin_channels&oldid=14089#MC.7CAdvCmd
2580 
2581  HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Channel);
2582 
2583  const std::string_view ChannelView = Channel;
2584 
2585  // If the plugin channel is recognized vanilla, handle it directly:
2586  if (ChannelView.substr(0, 3) == "MC|")
2587  {
2588  HandleVanillaPluginMessage(a_ByteBuffer, ChannelView.substr(3));
2589  return;
2590  }
2591 
2592  ContiguousByteBuffer Data;
2593 
2594  // Read the plugin message and relay to clienthandle:
2595  a_ByteBuffer.ReadSome(Data, a_ByteBuffer.GetReadableSpace());
2596  m_Client->HandlePluginMessage(Channel, Data);
2597 }
2598 
2599 
2600 
2601 
2602 
2604 {
2605  HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Hash);
2606  HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Status);
2607 
2609 }
2610 
2611 
2612 
2613 
2614 
2616 {
2617  HANDLE_READ(a_ByteBuffer, ReadBEInt16, Int16, SlotNum);
2618 
2619  m_Client->HandleSlotSelected(SlotNum);
2620 }
2621 
2622 
2623 
2624 
2625 
2627 {
2628  cUUID playerUUID;
2629  if (!a_ByteBuffer.ReadUUID(playerUUID))
2630  {
2631  return;
2632  }
2633 
2634  m_Client->HandleSpectate(playerUUID);
2635 }
2636 
2637 
2638 
2639 
2640 
2642 {
2643  HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, Sideways);
2644  HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, Forward);
2645  HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Flags);
2646 
2647  if ((Flags & 0x2) != 0)
2648  {
2650  }
2651  else if ((Flags & 0x1) != 0)
2652  {
2653  // jump
2654  }
2655  else
2656  {
2657  m_Client->HandleSteerVehicle(Forward, Sideways);
2658  }
2659 }
2660 
2661 
2662 
2663 
2664 
2666 {
2667  HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Text);
2668  HANDLE_READ(a_ByteBuffer, ReadBool, bool, HasPosition);
2669 
2670  if (HasPosition)
2671  {
2672  HANDLE_READ(a_ByteBuffer, ReadBEInt64, Int64, Position);
2673  }
2674 
2676 }
2677 
2678 
2679 
2680 
2681 
2683 {
2684  Vector3i Position;
2685  if (!a_ByteBuffer.ReadXYZPosition64(Position))
2686  {
2687  return;
2688  }
2689 
2690  AString Lines[4];
2691  Json::Value root;
2692  for (int i = 0; i < 4; i++)
2693  {
2694  HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Line);
2695 
2696  if (JsonUtils::ParseString(Line, root) && root.isString())
2697  {
2698  Lines[i] = root.asString();
2699  }
2700  }
2701 
2702  m_Client->HandleUpdateSign(Position, Lines[0], Lines[1], Lines[2], Lines[3]);
2703 }
2704 
2705 
2706 
2707 
2708 
2710 {
2711  HANDLE_READ(a_ByteBuffer, ReadVarInt, UInt32, EntityID);
2712  HANDLE_READ(a_ByteBuffer, ReadVarInt, UInt32, Type);
2713 
2714  switch (Type)
2715  {
2716  case 0:
2717  {
2718  m_Client->HandleUseEntity(EntityID, false);
2719  break;
2720  }
2721  case 1:
2722  {
2723  m_Client->HandleUseEntity(EntityID, true);
2724  break;
2725  }
2726  case 2:
2727  {
2728  HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, TargetX);
2729  HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, TargetY);
2730  HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, TargetZ);
2731 
2732  // TODO: Do anything
2733  break;
2734  }
2735  default:
2736  {
2737  ASSERT(!"Unhandled use entity type!");
2738  return;
2739  }
2740  }
2741 }
2742 
2743 
2744 
2745 
2746 
2748 {
2749  HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, WindowID);
2750  HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Enchantment);
2751 
2752  m_Client->HandleEnchantItem(WindowID, Enchantment);
2753 }
2754 
2755 
2756 
2757 
2758 
2760 {
2761  HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, WindowID);
2762  HANDLE_READ(a_ByteBuffer, ReadBEInt16, Int16, SlotNum);
2763  HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Button);
2764  HANDLE_READ(a_ByteBuffer, ReadBEUInt16, UInt16, TransactionID);
2765  HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Mode);
2766 
2767  cItem Item;
2768  ReadItem(a_ByteBuffer, Item);
2769 
2771  static const Int16 SLOT_NUM_OUTSIDE = -999;
2772 
2773  // Convert Button, Mode, SlotNum and HeldItem into eClickAction:
2774  eClickAction Action;
2775  switch ((Mode << 8) | Button)
2776  {
2777  case 0x0000: Action = (SlotNum != SLOT_NUM_OUTSIDE) ? caLeftClick : caLeftClickOutside; break;
2778  case 0x0001: Action = (SlotNum != SLOT_NUM_OUTSIDE) ? caRightClick : caRightClickOutside; break;
2779  case 0x0100: Action = caShiftLeftClick; break;
2780  case 0x0101: Action = caShiftRightClick; break;
2781  case 0x0200: Action = caNumber1; break;
2782  case 0x0201: Action = caNumber2; break;
2783  case 0x0202: Action = caNumber3; break;
2784  case 0x0203: Action = caNumber4; break;
2785  case 0x0204: Action = caNumber5; break;
2786  case 0x0205: Action = caNumber6; break;
2787  case 0x0206: Action = caNumber7; break;
2788  case 0x0207: Action = caNumber8; break;
2789  case 0x0208: Action = caNumber9; break;
2790  case 0x0302: Action = caMiddleClick; break;
2791  case 0x0400: Action = (SlotNum == SLOT_NUM_OUTSIDE) ? caLeftClickOutsideHoldNothing : caDropKey; break;
2792  case 0x0401: Action = (SlotNum == SLOT_NUM_OUTSIDE) ? caRightClickOutsideHoldNothing : caCtrlDropKey; break;
2793  case 0x0500: Action = (SlotNum == SLOT_NUM_OUTSIDE) ? caLeftPaintBegin : caUnknown; break;
2794  case 0x0501: Action = (SlotNum != SLOT_NUM_OUTSIDE) ? caLeftPaintProgress : caUnknown; break;
2795  case 0x0502: Action = (SlotNum == SLOT_NUM_OUTSIDE) ? caLeftPaintEnd : caUnknown; break;
2796  case 0x0504: Action = (SlotNum == SLOT_NUM_OUTSIDE) ? caRightPaintBegin : caUnknown; break;
2797  case 0x0505: Action = (SlotNum != SLOT_NUM_OUTSIDE) ? caRightPaintProgress : caUnknown; break;
2798  case 0x0506: Action = (SlotNum == SLOT_NUM_OUTSIDE) ? caRightPaintEnd : caUnknown; break;
2799  case 0x0508: Action = (SlotNum == SLOT_NUM_OUTSIDE) ? caMiddlePaintBegin : caUnknown; break;
2800  case 0x0509: Action = (SlotNum != SLOT_NUM_OUTSIDE) ? caMiddlePaintProgress : caUnknown; break;
2801  case 0x050a: Action = (SlotNum == SLOT_NUM_OUTSIDE) ? caMiddlePaintEnd : caUnknown; break;
2802  case 0x0600: Action = caDblClick; break;
2803  default:
2804  {
2805  LOGWARNING("Unhandled window click mode / button combination: %d (0x%x)", (Mode << 8) | Button, (Mode << 8) | Button);
2806  Action = caUnknown;
2807  break;
2808  }
2809  }
2810 
2811  m_Client->HandleWindowClick(WindowID, SlotNum, Action, Item);
2812 }
2813 
2814 
2815 
2816 
2817 
2819 {
2820  HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, WindowID);
2821 
2822  m_Client->HandleWindowClose(WindowID);
2823 }
2824 
2825 
2826 
2827 
2828 
2829 void cProtocol_1_8_0::HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const std::string_view a_Channel)
2830 {
2831  if ((a_Channel == "AdvCdm") || (a_Channel == "AdvCmd")) // Spelling was fixed in 15w34.
2832  {
2833  HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Type);
2834 
2835  switch (Type)
2836  {
2837  case 0x00:
2838  {
2839  HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, BlockX);
2840  HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, BlockY);
2841  HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, BlockZ);
2842  HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Command);
2843  HANDLE_READ(a_ByteBuffer, ReadBool, bool, TrackOutput);
2844 
2845  // Editing a command-block:
2846  m_Client->HandleCommandBlockBlockChange({BlockX, BlockY, BlockZ}, Command);
2847  return;
2848  }
2849  case 0x01:
2850  {
2851  HANDLE_READ(a_ByteBuffer, ReadBEUInt32, UInt32, EntityID);
2852  HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Command);
2853  HANDLE_READ(a_ByteBuffer, ReadBool, bool, TrackOutput);
2854 
2855  // Editing a command-block-minecart:
2856  m_Client->HandleCommandBlockEntityChange(EntityID, Command);
2857  return;
2858  }
2859  default:
2860  {
2861  LOGD("Player \"%s\" sent an invalid command block edit type - hacked client?", m_Client->GetUsername().c_str());
2862  return;
2863  }
2864  }
2865  }
2866  else if (a_Channel == "Beacon")
2867  {
2868  HANDLE_READ(a_ByteBuffer, ReadBEUInt32, UInt32, Effect1);
2869  HANDLE_READ(a_ByteBuffer, ReadBEUInt32, UInt32, Effect2);
2870 
2871  m_Client->HandleBeaconSelection(Effect1, Effect2);
2872  }
2873  else if (a_Channel == "BEdit")
2874  {
2875  if (cItem UnsignedBook; ReadItem(a_ByteBuffer, UnsignedBook))
2876  {
2877  // TODO: m_Client->HandleBookEdit
2878  }
2879  }
2880  else if (a_Channel == "BSign")
2881  {
2882  if (cItem WrittenBook; ReadItem(a_ByteBuffer, WrittenBook))
2883  {
2884  // TODO: m_Client->HandleBookSign
2885  }
2886  }
2887  else if (a_Channel == "Brand")
2888  {
2889  HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Brand);
2890 
2891  m_Client->SetClientBrand(Brand);
2892  m_Client->SendPluginMessage("MC|Brand", "\x08""Cuberite"); // Send back our brand, including the length.
2893  }
2894  else if (a_Channel == "ItemName")
2895  {
2896  HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, ItemName);
2897 
2898  m_Client->HandleAnvilItemName(ItemName);
2899  }
2900  else if (a_Channel == "TrSel")
2901  {
2902  HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, SlotNum);
2903 
2904  m_Client->HandleNPCTrade(SlotNum);
2905  }
2906 }
2907 
2908 
2909 
2910 
2911 
2913 {
2914  // Parse into NBT:
2915  cParsedNBT NBT(a_Metadata);
2916  if (!NBT.IsValid())
2917  {
2918  AString HexDump;
2919  CreateHexDump(HexDump, a_Metadata.data(), std::max<size_t>(a_Metadata.size(), 1024), 16);
2920  LOGWARNING("Cannot parse NBT item metadata: %s at (%zu / %zu bytes)\n%s",
2921  NBT.GetErrorCode().message().c_str(), NBT.GetErrorPos(), a_Metadata.size(), HexDump.c_str()
2922  );
2923  return;
2924  }
2925 
2926  // Load enchantments and custom display names from the NBT data:
2927  for (int tag = NBT.GetFirstChild(NBT.GetRoot()); tag >= 0; tag = NBT.GetNextSibling(tag))
2928  {
2929  AString TagName = NBT.GetName(tag);
2930  switch (NBT.GetType(tag))
2931  {
2932  case TAG_List:
2933  {
2934  if ((TagName == "ench") || (TagName == "StoredEnchantments")) // Enchantments tags
2935  {
2937  }
2938  break;
2939  }
2940  case TAG_Compound:
2941  {
2942  if (TagName == "display") // Custom name and lore tag
2943  {
2944  for (int displaytag = NBT.GetFirstChild(tag); displaytag >= 0; displaytag = NBT.GetNextSibling(displaytag))
2945  {
2946  if ((NBT.GetType(displaytag) == TAG_String) && (NBT.GetName(displaytag) == "Name")) // Custon name tag
2947  {
2948  a_Item.m_CustomName = NBT.GetString(displaytag);
2949  }
2950  else if ((NBT.GetType(displaytag) == TAG_List) && (NBT.GetName(displaytag) == "Lore")) // Lore tag
2951  {
2952  for (int loretag = NBT.GetFirstChild(displaytag); loretag >= 0; loretag = NBT.GetNextSibling(loretag)) // Loop through array of strings
2953  {
2954  a_Item.m_LoreTable.push_back(NBT.GetString(loretag));
2955  }
2956  }
2957  else if ((NBT.GetType(displaytag) == TAG_Int) && (NBT.GetName(displaytag) == "color"))
2958  {
2959  a_Item.m_ItemColor.m_Color = static_cast<unsigned int>(NBT.GetInt(displaytag));
2960  }
2961  }
2962  }
2963  else if ((TagName == "Fireworks") || (TagName == "Explosion"))
2964  {
2965  cFireworkItem::ParseFromNBT(a_Item.m_FireworkItem, NBT, tag, static_cast<ENUM_ITEM_TYPE>(a_Item.m_ItemType));
2966  }
2967  break;
2968  }
2969  case TAG_Int:
2970  {
2971  if (TagName == "RepairCost")
2972  {
2973  a_Item.m_RepairCost = NBT.GetInt(tag);
2974  }
2975  break;
2976  }
2977  default: LOGD("Unimplemented NBT data when parsing!"); break;
2978  }
2979  }
2980 }
2981 
2982 
2983 
2984 
2985 
2986 bool cProtocol_1_8_0::ReadItem(cByteBuffer & a_ByteBuffer, cItem & a_Item, size_t a_KeepRemainingBytes) const
2987 {
2988  HANDLE_PACKET_READ(a_ByteBuffer, ReadBEInt16, Int16, ItemType);
2989 
2990  if (ItemType == -1)
2991  {
2992  // The item is empty, no more data follows
2993  a_Item.Empty();
2994  return true;
2995  }
2996  a_Item.m_ItemType = ItemType;
2997 
2998  HANDLE_PACKET_READ(a_ByteBuffer, ReadBEInt8, Int8, ItemCount);
2999  HANDLE_PACKET_READ(a_ByteBuffer, ReadBEInt16, Int16, ItemDamage);
3000 
3001  a_Item.m_ItemCount = ItemCount;
3002  a_Item.m_ItemDamage = ItemDamage;
3003  if (ItemCount <= 0)
3004  {
3005  a_Item.Empty();
3006  }
3007 
3009  if (!a_ByteBuffer.ReadSome(Metadata, a_ByteBuffer.GetReadableSpace() - a_KeepRemainingBytes) || Metadata.empty() || (Metadata[0] == std::byte(0)))
3010  {
3011  // No metadata
3012  return true;
3013  }
3014 
3015  ParseItemMetadata(a_Item, Metadata);
3016  return true;
3017 }
3018 
3019 
3020 
3021 
3022 
3023 void cProtocol_1_8_0::SendEntitySpawn(const cEntity & a_Entity, const UInt8 a_ObjectType, const Int32 a_ObjectData)
3024 {
3025  ASSERT(m_State == 3); // In game mode?
3026 
3027  cPacketizer Pkt(*this, pktSpawnObject);
3028  Pkt.WriteVarInt32(a_Entity.GetUniqueID());
3029  Pkt.WriteBEUInt8(a_ObjectType);
3030  Pkt.WriteFPInt(a_Entity.GetPosX());
3031  Pkt.WriteFPInt(a_Entity.GetPosY());
3032  Pkt.WriteFPInt(a_Entity.GetPosZ());
3033  Pkt.WriteByteAngle(a_Entity.GetPitch());
3034  Pkt.WriteByteAngle(a_Entity.GetYaw());
3035  Pkt.WriteBEInt32(a_ObjectData);
3036 
3037  if (a_ObjectData != 0)
3038  {
3039  Pkt.WriteBEInt16(static_cast<Int16>(a_Entity.GetSpeedX() * 400));
3040  Pkt.WriteBEInt16(static_cast<Int16>(a_Entity.GetSpeedY() * 400));
3041  Pkt.WriteBEInt16(static_cast<Int16>(a_Entity.GetSpeedZ() * 400));
3042  }
3043 }
3044 
3045 
3046 
3047 
3048 
3050 {
3052 
3055 
3056  const auto PacketData = m_Compressor.GetView();
3057 
3058  if (m_State == 3)
3059  {
3060  ContiguousByteBuffer CompressedPacket;
3061 
3062  // Compress the packet payload:
3063  cProtocol_1_8_0::CompressPacket(m_Compressor, CompressedPacket);
3064 
3065  // Send the packet's payload compressed:
3066  m_Client->SendData(CompressedPacket);
3067  }
3068  else
3069  {
3070  // Compression doesn't apply to this state, send raw data:
3071  m_OutPacketLenBuffer.WriteVarInt32(static_cast<UInt32>(PacketData.size()));
3072  ContiguousByteBuffer LengthData;
3073  m_OutPacketLenBuffer.ReadAll(LengthData);
3075  m_Client->SendData(LengthData);
3076 
3077  // Send the packet's payload directly:
3078  m_Client->SendData(PacketData);
3079  }
3080 
3081  // Log the comm into logfile:
3083  {
3084  AString Hex;
3085  ASSERT(PacketData.size() > 0);
3086  CreateHexDump(Hex, PacketData.data(), PacketData.size(), 16);
3087  m_CommLogFile.Write(fmt::format(
3088  FMT_STRING("Outgoing packet: type {} (translated to 0x{:02x}), length {} (0x{:04x}), state {}. Payload (incl. type):\n{}\n"),
3090  PacketData.size(), PacketData.size(), m_State, Hex
3091  ));
3092  /*
3093  // Useful for debugging a new protocol:
3094  LOGD("Outgoing packet: type %s (translated to 0x%02x), length %u (0x%04x), state %d. Payload (incl. type):\n%s\n",
3095  cPacketizer::PacketTypeToStr(a_Pkt.GetPacketType()), GetPacketID(a_Pkt.GetPacketType()),
3096  PacketLen, PacketLen, m_State, Hex
3097  );
3098  //*/
3099  }
3100  /*
3101  // Useful for debugging a new protocol:
3102  std::this_thread::sleep_for(std::chrono::milliseconds(100));
3103  */
3104 }
3105 
3106 
3107 
3108 
3109 
3110 void cProtocol_1_8_0::WriteBlockEntity(cFastNBTWriter & a_Writer, const cBlockEntity & a_BlockEntity) const
3111 {
3112  switch (a_BlockEntity.GetBlockType())
3113  {
3114  case E_BLOCK_WALL_BANNER:
3116  {
3117  auto & BannerEntity = static_cast<const cBannerEntity &>(a_BlockEntity);
3118  a_Writer.AddInt("Base", static_cast<Int32>(BannerEntity.GetBaseColor()));
3119  break;
3120  }
3121  case E_BLOCK_BEACON:
3122  case E_BLOCK_CHEST:
3123  {
3124  // Nothing!
3125  break;
3126  }
3127  case E_BLOCK_COMMAND_BLOCK:
3128  {
3129  auto & CommandBlockEntity = static_cast<const cCommandBlockEntity &>(a_BlockEntity);
3130  a_Writer.AddByte("TrackOutput", 1); // Neither I nor the MC wiki has any idea about this
3131  a_Writer.AddInt("SuccessCount", CommandBlockEntity.GetResult());
3132  a_Writer.AddString("Command", CommandBlockEntity.GetCommand());
3133  // You can set custom names for windows in Vanilla
3134  // For a command block, this would be the 'name' prepended to anything it outputs into global chat
3135  // MCS doesn't have this, so just leave it @ '@'. (geddit?)
3136  a_Writer.AddString("CustomName", "@");
3137  if (!CommandBlockEntity.GetLastOutput().empty())
3138  {
3139  a_Writer.AddString("LastOutput", JsonUtils::SerializeSingleValueJsonObject("text", CommandBlockEntity.GetLastOutput()));
3140  }
3141  break;
3142  }
3144  case E_BLOCK_END_PORTAL:
3145  {
3146  // Nothing!
3147  break;
3148  }
3149  case E_BLOCK_HEAD:
3150  {
3151  auto & MobHeadEntity = static_cast<const cMobHeadEntity &>(a_BlockEntity);
3152  a_Writer.AddByte("SkullType", MobHeadEntity.GetType() & 0xFF);
3153  a_Writer.AddByte("Rot", MobHeadEntity.GetRotation() & 0xFF);
3154 
3155  // The new Block Entity format for a Mob Head. See: https://minecraft.wiki/w/Head#Block_entity
3156  a_Writer.BeginCompound("Owner");
3157  a_Writer.AddString("Id", MobHeadEntity.GetOwnerUUID().ToShortString());
3158  a_Writer.AddString("Name", MobHeadEntity.GetOwnerName());
3159  a_Writer.BeginCompound("Properties");
3160  a_Writer.BeginList("textures", TAG_Compound);
3161  a_Writer.BeginCompound("");
3162  a_Writer.AddString("Signature", MobHeadEntity.GetOwnerTextureSignature());
3163  a_Writer.AddString("Value", MobHeadEntity.GetOwnerTexture());
3164  a_Writer.EndCompound();
3165  a_Writer.EndList();
3166  a_Writer.EndCompound();
3167  a_Writer.EndCompound();
3168  break;
3169  }
3170  case E_BLOCK_FLOWER_POT:
3171  {
3172  auto & FlowerPotEntity = static_cast<const cFlowerPotEntity &>(a_BlockEntity);
3173  a_Writer.AddInt("Item", static_cast<Int32>(FlowerPotEntity.GetItem().m_ItemType));
3174  a_Writer.AddInt("Data", static_cast<Int32>(FlowerPotEntity.GetItem().m_ItemDamage));
3175  break;
3176  }
3177  case E_BLOCK_MOB_SPAWNER:
3178  {
3179  auto & MobSpawnerEntity = static_cast<const cMobSpawnerEntity &>(a_BlockEntity);
3180  a_Writer.AddString("EntityId", cMonster::MobTypeToVanillaName(MobSpawnerEntity.GetEntity()));
3181  a_Writer.AddShort("Delay", MobSpawnerEntity.GetSpawnDelay());
3182  break;
3183  }
3184  default:
3185  {
3186  return;
3187  }
3188  }
3189 
3190  a_Writer.AddInt("x", a_BlockEntity.GetPosX());
3191  a_Writer.AddInt("y", a_BlockEntity.GetPosY());
3192  a_Writer.AddInt("z", a_BlockEntity.GetPosZ());
3193 }
3194 
3195 
3196 
3197 
3198 
3199 void cProtocol_1_8_0::WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a_Entity) const
3200 {
3201  // Common metadata:
3202  Byte Flags = 0;
3203  if (a_Entity.IsOnFire())
3204  {
3205  Flags |= 0x01;
3206  }
3207  if (a_Entity.IsCrouched())
3208  {
3209  Flags |= 0x02;
3210  }
3211  if (a_Entity.IsSprinting())
3212  {
3213  Flags |= 0x08;
3214  }
3215  if (a_Entity.IsRclking())
3216  {
3217  Flags |= 0x10;
3218  }
3219  if (a_Entity.IsInvisible())
3220  {
3221  Flags |= 0x20;
3222  }
3223  if (a_Entity.IsElytraFlying())
3224  {
3225  Flags |= 0x80;
3226  }
3227  a_Pkt.WriteBEUInt8(0); // Byte(0) + index 0
3228  a_Pkt.WriteBEUInt8(Flags);
3229 
3230  switch (a_Entity.GetEntityType())
3231  {
3232  case cEntity::etPlayer:
3233  {
3234  auto & Player = static_cast<const cPlayer &>(a_Entity);
3235 
3236  // Player name:
3237  a_Pkt.WriteBEUInt8(0x82);
3238  a_Pkt.WriteString(Player.GetName());
3239 
3240  // Player health:
3241  a_Pkt.WriteBEUInt8(0x66);
3242  a_Pkt.WriteBEFloat(static_cast<float>(Player.GetHealth()));
3243 
3244  // Skin flags:
3245  a_Pkt.WriteBEUInt8(0x0A);
3246  a_Pkt.WriteBEUInt8(static_cast<UInt8>(Player.GetSkinParts()));
3247 
3248  break;
3249  }
3250  case cEntity::etPickup:
3251  {
3252  a_Pkt.WriteBEUInt8((5 << 5) | 10); // Slot(5) + index 10
3253  WriteItem(a_Pkt, static_cast<const cPickup &>(a_Entity).GetItem());
3254  break;
3255  }
3256  case cEntity::etMinecart:
3257  {
3258  a_Pkt.WriteBEUInt8(0x51);
3259 
3260  // The following expression makes Minecarts shake more with less health or higher damage taken
3261  // It gets half the maximum health, and takes it away from the current health minus the half health:
3262  /*
3263  Health: 5 | 3 - (5 - 3) = 1 (shake power)
3264  Health: 3 | 3 - (3 - 3) = 3
3265  Health: 1 | 3 - (1 - 3) = 5
3266  */
3267  auto & Minecart = static_cast<const cMinecart &>(a_Entity);
3268  a_Pkt.WriteBEInt32(static_cast<Int32>((((a_Entity.GetMaxHealth() / 2) - (a_Entity.GetHealth() - (a_Entity.GetMaxHealth() / 2))) * Minecart.LastDamage()) * 4));
3269  a_Pkt.WriteBEUInt8(0x52);
3270  a_Pkt.WriteBEInt32(1); // Shaking direction, doesn't seem to affect anything
3271  a_Pkt.WriteBEUInt8(0x73);
3272  a_Pkt.WriteBEFloat(static_cast<float>(Minecart.LastDamage() + 10)); // Damage taken / shake effect multiplyer
3273 
3274  if (Minecart.GetPayload() == cMinecart::mpNone)
3275  {
3276  auto & RideableMinecart = static_cast<const cRideableMinecart &>(Minecart);
3277  const cItem & MinecartContent = RideableMinecart.GetContent();
3278  if (!MinecartContent.IsEmpty())
3279  {
3280  a_Pkt.WriteBEUInt8(0x54);
3281  int Content = MinecartContent.m_ItemType;
3282  Content |= MinecartContent.m_ItemDamage << 8;
3283  a_Pkt.WriteBEInt32(Content);
3284  a_Pkt.WriteBEUInt8(0x55);
3285  a_Pkt.WriteBEInt32(RideableMinecart.GetBlockHeight());
3286  a_Pkt.WriteBEUInt8(0x56);
3287  a_Pkt.WriteBEUInt8(1);
3288  }
3289  }
3290  else if (Minecart.GetPayload() == cMinecart::mpFurnace)
3291  {
3292  a_Pkt.WriteBEUInt8(0x10);
3293  a_Pkt.WriteBEUInt8(static_cast<const cMinecartWithFurnace &>(Minecart).IsFueled() ? 1 : 0);
3294  }
3295  break;
3296  } // case etMinecart
3297 
3298  case cEntity::etProjectile:
3299  {
3300  auto & Projectile = static_cast<const cProjectileEntity &>(a_Entity);
3301  switch (Projectile.GetProjectileKind())
3302  {
3304  {
3305  a_Pkt.WriteBEUInt8(0x10);
3306  a_Pkt.WriteBEUInt8(static_cast<const cArrowEntity &>(Projectile).IsCritical() ? 1 : 0);
3307  break;
3308  }
3310  {
3311  a_Pkt.WriteBEUInt8(0xa8);
3312  WriteItem(a_Pkt, static_cast<const cFireworkEntity &>(Projectile).GetItem());
3313  break;
3314  }
3315  default:
3316  {
3317  break;
3318  }
3319  }
3320  break;
3321  } // case etProjectile
3322 
3323  case cEntity::etMonster:
3324  {
3325  WriteMobMetadata(a_Pkt, static_cast<const cMonster &>(a_Entity));
3326  break;
3327  }
3328 
3329  case cEntity::etItemFrame:
3330  {
3331  auto & Frame = static_cast<const cItemFrame &>(a_Entity);
3332  a_Pkt.WriteBEUInt8(0xa8);
3333  WriteItem(a_Pkt, Frame.GetItem());
3334  a_Pkt.WriteBEUInt8(0x09);
3335  a_Pkt.WriteBEUInt8(Frame.GetItemRotation());
3336  break;
3337  } // case etItemFrame
3338 
3339  default:
3340  {
3341  break;
3342  }
3343  }
3344 }
3345 
3346 
3347 
3348 
3349 
3350 void cProtocol_1_8_0::WriteEntityProperties(cPacketizer & a_Pkt, const cEntity & a_Entity) const
3351 {
3352  if (a_Entity.IsPlayer())
3353  {
3354  const auto & Player = static_cast<const cPlayer &>(a_Entity);
3355 
3356  a_Pkt.WriteBEInt32(1); // Count.
3357  a_Pkt.WriteString("generic.movementSpeed");
3358  a_Pkt.WriteBEDouble(0.1 * Player.GetNormalMaxSpeed()); // The default game speed is 0.1, multiply that value by the relative speed.
3359 
3360  // It seems the modifiers aren't conditionally activated; their effects are applied immediately!
3361  // We have to keep on re-sending this packet when the client notifies us of sprint start and end, and so on. Strange.
3362 
3363  if (Player.IsSprinting())
3364  {
3365  a_Pkt.WriteVarInt32(1); // Modifier count.
3366  a_Pkt.WriteBEUInt64(0x662a6b8dda3e4c1c);
3367  a_Pkt.WriteBEUInt64(0x881396ea6097278d); // UUID of the modifier (sprinting speed boost).
3368  a_Pkt.WriteBEDouble(Player.GetSprintingMaxSpeed() - Player.GetNormalMaxSpeed());
3369  a_Pkt.WriteBEUInt8(2);
3370  }
3371  else
3372  {
3373  a_Pkt.WriteVarInt32(0);
3374  }
3375  }
3376  else
3377  {
3378  // const cMonster & Mob = (const cMonster &)a_Entity;
3379 
3380  // TODO: Send properties and modifiers based on the mob type
3381 
3382  a_Pkt.WriteBEInt32(0);
3383  }
3384 }
3385 
3386 
3387 
3388 
3389 
3390 void cProtocol_1_8_0::WriteItem(cPacketizer & a_Pkt, const cItem & a_Item) const
3391 {
3392  short ItemType = a_Item.m_ItemType;
3393  ASSERT(ItemType >= -1); // Check validity of packets in debug runtime
3394  if (ItemType <= 0)
3395  {
3396  // Fix, to make sure no invalid values are sent.
3397  ItemType = -1;
3398  }
3399 
3400  if (a_Item.IsEmpty())
3401  {
3402  a_Pkt.WriteBEInt16(-1);
3403  return;
3404  }
3405 
3406  a_Pkt.WriteBEInt16(ItemType);
3407  a_Pkt.WriteBEInt8(a_Item.m_ItemCount);
3408  a_Pkt.WriteBEInt16(a_Item.m_ItemDamage);
3409 
3410  if (a_Item.m_Enchantments.IsEmpty() && a_Item.IsBothNameAndLoreEmpty() && (a_Item.m_ItemType != E_ITEM_FIREWORK_ROCKET) && (a_Item.m_ItemType != E_ITEM_FIREWORK_STAR) && !a_Item.m_ItemColor.IsValid())
3411  {
3412  a_Pkt.WriteBEInt8(0);
3413  return;
3414  }
3415 
3416 
3417  // Send the enchantments and custom names:
3418  cFastNBTWriter Writer;
3419  if (a_Item.m_RepairCost != 0)
3420  {
3421  Writer.AddInt("RepairCost", a_Item.m_RepairCost);
3422  }
3423  if (!a_Item.m_Enchantments.IsEmpty())
3424  {
3425  const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench";
3427  }
3428  if (!a_Item.IsBothNameAndLoreEmpty() || a_Item.m_ItemColor.IsValid())
3429  {
3430  Writer.BeginCompound("display");
3431  if (a_Item.m_ItemColor.IsValid())
3432  {
3433  Writer.AddInt("color", static_cast<Int32>(a_Item.m_ItemColor.m_Color));
3434  }
3435 
3436  if (!a_Item.IsCustomNameEmpty())
3437  {
3438  Writer.AddString("Name", a_Item.m_CustomName);
3439  }
3440  if (!a_Item.IsLoreEmpty())
3441  {
3442  Writer.BeginList("Lore", TAG_String);
3443 
3444  for (const auto & Line : a_Item.m_LoreTable)
3445  {
3446  Writer.AddString("", Line);
3447  }
3448 
3449  Writer.EndList();
3450  }
3451  Writer.EndCompound();
3452  }
3453  if ((a_Item.m_ItemType == E_ITEM_FIREWORK_ROCKET) || (a_Item.m_ItemType == E_ITEM_FIREWORK_STAR))
3454  {
3455  cFireworkItem::WriteToNBTCompound(a_Item.m_FireworkItem, Writer, static_cast<ENUM_ITEM_TYPE>(a_Item.m_ItemType));
3456  }
3457  Writer.Finish();
3458 
3459  const auto Result = Writer.GetResult();
3460  if (Result.empty())
3461  {
3462  a_Pkt.WriteBEInt8(0);
3463  return;
3464  }
3465  a_Pkt.WriteBuf(Result);
3466 }
3467 
3468 
3469 
3470 
3471 
3472 void cProtocol_1_8_0::WriteMobMetadata(cPacketizer & a_Pkt, const cMonster & a_Mob) const
3473 {
3474  // Living Enitiy Metadata
3475  if (a_Mob.HasCustomName())
3476  {
3477  a_Pkt.WriteBEUInt8(0x82);
3478  a_Pkt.WriteString(a_Mob.GetCustomName());
3479 
3480  a_Pkt.WriteBEUInt8(0x03);
3481  a_Pkt.WriteBool(a_Mob.IsCustomNameAlwaysVisible());
3482  }
3483 
3484  a_Pkt.WriteBEUInt8(0x66);
3485  a_Pkt.WriteBEFloat(static_cast<float>(a_Mob.GetHealth()));
3486 
3487  switch (a_Mob.GetMobType())
3488  {
3489  case mtBat:
3490  {
3491  auto & Bat = static_cast<const cBat &>(a_Mob);
3492  a_Pkt.WriteBEUInt8(0x10);
3493  a_Pkt.WriteBEUInt8(Bat.IsHanging() ? 1 : 0);
3494  break;
3495  } // case mtBat
3496 
3497  case mtChicken:
3498  {
3499  auto & Chicken = static_cast<const cChicken &>(a_Mob);
3500  a_Pkt.WriteBEUInt8(0x0c);
3501  a_Pkt.WriteBEInt8(Chicken.IsBaby() ? -1 : (Chicken.IsInLoveCooldown() ? 1 : 0));
3502  break;
3503  } // case mtChicken
3504 
3505  case mtCow:
3506  {
3507  auto & Cow = static_cast<const cCow &>(a_Mob);
3508  a_Pkt.WriteBEUInt8(0x0c);
3509  a_Pkt.WriteBEInt8(Cow.IsBaby() ? -1 : (Cow.IsInLoveCooldown() ? 1 : 0));
3510  break;
3511  } // case mtCow
3512 
3513  case mtCreeper:
3514  {
3515  auto & Creeper = static_cast<const cCreeper &>(a_Mob);
3516  a_Pkt.WriteBEUInt8(0x10);
3517  a_Pkt.WriteBEUInt8(Creeper.IsBlowing() ? 1 : 255);
3518  a_Pkt.WriteBEUInt8(0x11);
3519  a_Pkt.WriteBEUInt8(Creeper.IsCharged() ? 1 : 0);
3520  break;
3521  } // case mtCreeper
3522 
3523  case mtEnderman:
3524  {
3525  auto & Enderman = static_cast<const cEnderman &>(a_Mob);
3526  a_Pkt.WriteBEUInt8(0x30);
3527  a_Pkt.WriteBEInt16(static_cast<Byte>(Enderman.GetCarriedBlock()));
3528  a_Pkt.WriteBEUInt8(0x11);
3529  a_Pkt.WriteBEUInt8(static_cast<Byte>(Enderman.GetCarriedMeta()));
3530  a_Pkt.WriteBEUInt8(0x12);
3531  a_Pkt.WriteBEUInt8(Enderman.IsScreaming() ? 1 : 0);
3532  break;
3533  } // case mtEnderman
3534 
3535  case mtGhast:
3536  {
3537  auto & Ghast = static_cast<const cGhast &>(a_Mob);
3538  a_Pkt.WriteBEUInt8(0x10);
3539  a_Pkt.WriteBEUInt8(Ghast.IsCharging());
3540  break;
3541  } // case mtGhast
3542 
3543  case mtHorse:
3544  {
3545  auto & Horse = static_cast<const cHorse &>(a_Mob);
3546  int Flags = 0;
3547  if (Horse.IsTame())
3548  {
3549  Flags |= 0x02;
3550  }
3551  if (Horse.IsSaddled())
3552  {
3553  Flags |= 0x04;
3554  }
3555  if (Horse.IsChested())
3556  {
3557  Flags |= 0x08;
3558  }
3559  if (Horse.IsEating())
3560  {
3561  Flags |= 0x20;
3562  }
3563  if (Horse.IsRearing())
3564  {
3565  Flags |= 0x40;
3566  }
3567  if (Horse.IsMthOpen())
3568  {
3569  Flags |= 0x80;
3570  }
3571  a_Pkt.WriteBEUInt8(0x50); // Int at index 16
3572  a_Pkt.WriteBEInt32(Flags);
3573  a_Pkt.WriteBEUInt8(0x13); // Byte at index 19
3574  a_Pkt.WriteBEUInt8(static_cast<UInt8>(Horse.GetHorseType()));
3575  a_Pkt.WriteBEUInt8(0x54); // Int at index 20
3576  int Appearance = 0;
3577  Appearance = Horse.GetHorseColor();
3578  Appearance |= Horse.GetHorseStyle() << 8;
3579  a_Pkt.WriteBEInt32(Appearance);
3580  a_Pkt.WriteBEUInt8(0x56); // Int at index 22
3581  a_Pkt.WriteBEInt32(Horse.GetHorseArmour());
3582  a_Pkt.WriteBEUInt8(0x0c);
3583  a_Pkt.WriteBEInt8(Horse.IsBaby() ? -1 : (Horse.IsInLoveCooldown() ? 1 : 0));
3584  break;
3585  } // case mtHorse
3586 
3587  case mtMagmaCube:
3588  {
3589  auto & MagmaCube = static_cast<const cMagmaCube &>(a_Mob);
3590  a_Pkt.WriteBEUInt8(0x10);
3591  a_Pkt.WriteBEUInt8(static_cast<UInt8>(MagmaCube.GetSize()));
3592  break;
3593  } // case mtMagmaCube
3594 
3595  case mtOcelot:
3596  {
3597  auto & Ocelot = static_cast<const cOcelot &>(a_Mob);
3598  a_Pkt.WriteBEUInt8(0x0c);
3599  a_Pkt.WriteBEInt8(Ocelot.IsBaby() ? -1 : (Ocelot.IsInLoveCooldown() ? 1 : 0));
3600  break;
3601  } // case mtOcelot
3602 
3603  case mtPig:
3604  {
3605  auto & Pig = static_cast<const cPig &>(a_Mob);
3606  a_Pkt.WriteBEUInt8(0x0c);
3607  a_Pkt.WriteBEInt8(Pig.IsBaby() ? -1 : (Pig.IsInLoveCooldown() ? 1 : 0));
3608  a_Pkt.WriteBEUInt8(0x10);
3609  a_Pkt.WriteBEUInt8(Pig.IsSaddled() ? 1 : 0);
3610  break;
3611  } // case mtPig
3612 
3613  case mtSheep:
3614  {
3615  auto & Sheep = static_cast<const cSheep &>(a_Mob);
3616  a_Pkt.WriteBEUInt8(0x0c);
3617  a_Pkt.WriteBEInt8(Sheep.IsBaby() ? -1 : (Sheep.IsInLoveCooldown() ? 1 : 0));
3618 
3619  a_Pkt.WriteBEUInt8(0x10);
3620  Byte SheepMetadata = 0;
3621  SheepMetadata = static_cast<Byte>(Sheep.GetFurColor());
3622  if (Sheep.IsSheared())
3623  {
3624  SheepMetadata |= 0x10;
3625  }
3626  a_Pkt.WriteBEUInt8(SheepMetadata);
3627  break;
3628  } // case mtSheep
3629 
3630  case mtRabbit:
3631  {
3632  auto & Rabbit = static_cast<const cRabbit &>(a_Mob);
3633  a_Pkt.WriteBEUInt8(0x12);
3634  a_Pkt.WriteBEUInt8(static_cast<UInt8>(Rabbit.GetRabbitType()));
3635  a_Pkt.WriteBEUInt8(0x0c);
3636  a_Pkt.WriteBEInt8(Rabbit.IsBaby() ? -1 : (Rabbit.IsInLoveCooldown() ? 1 : 0));
3637  break;
3638  } // case mtRabbit
3639 
3640  case mtSlime:
3641  {
3642  auto & Slime = static_cast<const cSlime &>(a_Mob);
3643  a_Pkt.WriteBEUInt8(0x10);
3644  a_Pkt.WriteBEUInt8(static_cast<UInt8>(Slime.GetSize()));
3645  break;
3646  } // case mtSlime
3647 
3648  case mtSkeleton:
3649  case mtStray:
3650  {
3651  a_Pkt.WriteBEUInt8(0x0d);
3652  a_Pkt.WriteBEUInt8(0); // Is normal skeleton
3653  break;
3654  }
3655 
3656  case mtVillager:
3657  {
3658  auto & Villager = static_cast<const cVillager &>(a_Mob);
3659  a_Pkt.WriteBEUInt8(0x50);
3660  a_Pkt.WriteBEInt32(Villager.GetVilType());
3661  a_Pkt.WriteBEUInt8(0x0c);
3662  a_Pkt.WriteBEInt8(Villager.IsBaby() ? -1 : 0);
3663  break;
3664  } // case mtVillager
3665 
3666  case mtWitch:
3667  {
3668  auto & Witch = static_cast<const cWitch &>(a_Mob);
3669  a_Pkt.WriteBEUInt8(0x15);
3670  a_Pkt.WriteBEUInt8(Witch.IsAngry() ? 1 : 0);
3671  break;
3672  } // case mtWitch
3673 
3674  case mtWither:
3675  {
3676  auto & Wither = static_cast<const cWither &>(a_Mob);
3677  a_Pkt.WriteBEUInt8(0x54); // Int at index 20
3678  a_Pkt.WriteBEInt32(static_cast<Int32>(Wither.GetWitherInvulnerableTicks()));
3679  a_Pkt.WriteBEUInt8(0x66); // Float at index 6
3680  a_Pkt.WriteBEFloat(static_cast<float>(a_Mob.GetHealth()));
3681  break;
3682  } // case mtWither
3683 
3684  case mtWitherSkeleton:
3685  {
3686  a_Pkt.WriteBEUInt8(0x0d);
3687  a_Pkt.WriteBEUInt8(1); // Is wither skeleton
3688  break;
3689  } // case mtWitherSkeleton
3690 
3691  case mtWolf:
3692  {
3693  auto & Wolf = static_cast<const cWolf &>(a_Mob);
3694  Byte WolfStatus = 0;
3695  if (Wolf.IsSitting())
3696  {
3697  WolfStatus |= 0x1;
3698  }
3699  if (Wolf.IsAngry())
3700  {
3701  WolfStatus |= 0x2;
3702  }
3703  if (Wolf.IsTame())
3704  {
3705  WolfStatus |= 0x4;
3706  }
3707  a_Pkt.WriteBEUInt8(0x10);
3708  a_Pkt.WriteBEUInt8(WolfStatus);
3709 
3710  a_Pkt.WriteBEUInt8(0x72);
3711  a_Pkt.WriteBEFloat(static_cast<float>(a_Mob.GetHealth()));
3712  a_Pkt.WriteBEUInt8(0x13);
3713  a_Pkt.WriteBEUInt8(Wolf.IsBegging() ? 1 : 0);
3714  a_Pkt.WriteBEUInt8(0x14);
3715  a_Pkt.WriteBEUInt8(static_cast<UInt8>(Wolf.GetCollarColor()));
3716  a_Pkt.WriteBEUInt8(0x0c);
3717  a_Pkt.WriteBEInt8(Wolf.IsBaby() ? -1 : 0);
3718  break;
3719  } // case mtWolf
3720 
3721  case mtHusk:
3722  case mtZombie:
3723  {
3724  auto & Zombie = static_cast<const cZombie &>(a_Mob);
3725  a_Pkt.WriteBEUInt8(0x0c);
3726  a_Pkt.WriteBEInt8(Zombie.IsBaby() ? 1 : -1);
3727  a_Pkt.WriteBEUInt8(0x0d);
3728  a_Pkt.WriteBEUInt8(0);
3729  a_Pkt.WriteBEUInt8(0x0e);
3730  a_Pkt.WriteBEUInt8(0);
3731  break;
3732  } // case mtZombie
3733 
3734  case mtZombiePigman:
3735  {
3736  auto & ZombiePigman = static_cast<const cZombiePigman &>(a_Mob);
3737  a_Pkt.WriteBEUInt8(0x0c);
3738  a_Pkt.WriteBEInt8(ZombiePigman.IsBaby() ? 1 : -1);
3739  break;
3740  } // case mtZombiePigman
3741 
3742  case mtZombieVillager:
3743  {
3744  auto & ZombieVillager = reinterpret_cast<const cZombieVillager &>(a_Mob);
3745  a_Pkt.WriteBEUInt8(0x0c);
3746  a_Pkt.WriteBEInt8(ZombieVillager.IsBaby() ? 1 : -1);
3747  a_Pkt.WriteBEUInt8(0x0d);
3748  a_Pkt.WriteBEUInt8(1);
3749  a_Pkt.WriteBEUInt8(0x0e);
3750  a_Pkt.WriteBEUInt8((ZombieVillager.ConversionTime() == -1) ? 0 : 1);
3751  break;
3752  } // case mtZombieVillager
3753 
3754  case mtBlaze:
3755  case mtElderGuardian:
3756  case mtGuardian:
3757  {
3758  // TODO: Mobs with extra fields that aren't implemented
3759  break;
3760  }
3761 
3762  case mtCat:
3763 
3764 
3765  case mtDonkey:
3766  case mtMule:
3767  case mtSkeletonHorse:
3768  case mtZombieHorse:
3769  {
3770  // Todo: Mobs not added yet. Grouped ones have the same metadata
3771  ASSERT(!"cProtocol_1_8::WriteMobMetadata: received unimplemented type");
3772  break;
3773  }
3774 
3775  case mtCaveSpider:
3776  case mtEnderDragon:
3777  case mtGiant:
3778  case mtIronGolem:
3779  case mtMooshroom:
3780  case mtSilverfish:
3781  case mtEndermite:
3782  case mtSnowGolem:
3783  case mtSpider:
3784  case mtSquid:
3785  {
3786  // Allowed mobs without additional metadata
3787  break;
3788  }
3789 
3790  default: UNREACHABLE("cProtocol_1_8::WriteMobMetadata: received mob of invalid type");
3791  } // switch (a_Mob.GetType())
3792 }
3793 
3794 
3795 
3796 
3797 
3799 {
3800  // Write the incoming data into the comm log file:
3802  {
3803  if (a_Buffer.GetReadableSpace() > 0)
3804  {
3805  ContiguousByteBuffer AllData;
3806  size_t OldReadableSpace = a_Buffer.GetReadableSpace();
3807  a_Buffer.ReadAll(AllData);
3808  a_Buffer.ResetRead();
3809  a_Buffer.SkipRead(a_Buffer.GetReadableSpace() - OldReadableSpace);
3810  ASSERT(a_Buffer.GetReadableSpace() == OldReadableSpace);
3811  AString Hex;
3812  CreateHexDump(Hex, AllData.data(), AllData.size(), 16);
3813  m_CommLogFile.Write(fmt::format(
3814  FMT_STRING("Incoming data, {0} (0x{0:x}) unparsed bytes already present in buffer:\n{1}\n"),
3815  AllData.size(), Hex
3816  ));
3817  }
3818  AString Hex;
3819  CreateHexDump(Hex, a_Data.data(), a_Data.size(), 16);
3820  m_CommLogFile.Write(fmt::format(
3821  FMT_STRING("Incoming data: {0} (0x{0:x}) bytes: \n{1}\n"),
3822  a_Data.size(), Hex
3823  ));
3824  m_CommLogFile.Flush();
3825  }
3826 
3827  if (!a_Buffer.Write(a_Data.data(), a_Data.size()))
3828  {
3829  // Too much data in the incoming queue, report to caller:
3831  return;
3832  }
3833 
3834  // Handle all complete packets:
3835  for (;;)
3836  {
3837  UInt32 PacketLen;
3838  if (!a_Buffer.ReadVarInt(PacketLen))
3839  {
3840  // Not enough data
3841  a_Buffer.ResetRead();
3842  break;
3843  }
3844  if (!a_Buffer.CanReadBytes(PacketLen))
3845  {
3846  // The full packet hasn't been received yet
3847  a_Buffer.ResetRead();
3848  break;
3849  }
3850 
3851  // Check packet for compression:
3852  if (m_State == 3)
3853  {
3854  UInt32 NumBytesRead = static_cast<UInt32>(a_Buffer.GetReadableSpace());
3855 
3856  UInt32 UncompressedSize;
3857  if (!a_Buffer.ReadVarInt(UncompressedSize))
3858  {
3859  m_Client->Kick("Compression packet incomplete");
3860  return;
3861  }
3862 
3863  NumBytesRead -= static_cast<UInt32>(a_Buffer.GetReadableSpace()); // How many bytes has the UncompressedSize taken up?
3864  ASSERT(PacketLen > NumBytesRead);
3865  PacketLen -= NumBytesRead;
3866 
3867  if (UncompressedSize > 0)
3868  {
3869  // Decompress the data:
3870  m_Extractor.ReadFrom(a_Buffer, PacketLen);
3871  a_Buffer.CommitRead();
3872 
3873  const auto UncompressedData = m_Extractor.Extract(UncompressedSize);
3874  const auto Uncompressed = UncompressedData.GetView();
3875  cByteBuffer bb(Uncompressed.size());
3876 
3877  // Compression was used, move the uncompressed data:
3878  VERIFY(bb.Write(Uncompressed.data(), Uncompressed.size()));
3879 
3880  HandlePacket(bb);
3881  continue;
3882  }
3883  }
3884 
3885  // Move the packet payload to a separate cByteBuffer, bb:
3886  cByteBuffer bb(PacketLen);
3887 
3888  // No compression was used, move directly:
3889  VERIFY(a_Buffer.ReadToByteBuffer(bb, static_cast<size_t>(PacketLen)));
3890  a_Buffer.CommitRead();
3891 
3892  HandlePacket(bb);
3893  } // for (ever)
3894 
3895  // Log any leftover bytes into the logfile:
3896  if (g_ShouldLogCommIn && (a_Buffer.GetReadableSpace() > 0) && m_CommLogFile.IsOpen())
3897  {
3898  ContiguousByteBuffer AllData;
3899  size_t OldReadableSpace = a_Buffer.GetReadableSpace();
3900  a_Buffer.ReadAll(AllData);
3901  a_Buffer.ResetRead();
3902  a_Buffer.SkipRead(a_Buffer.GetReadableSpace() - OldReadableSpace);
3903  ASSERT(a_Buffer.GetReadableSpace() == OldReadableSpace);
3904  AString Hex;
3905  CreateHexDump(Hex, AllData.data(), AllData.size(), 16);
3906  m_CommLogFile.Write(fmt::format(
3907  FMT_STRING("There are {0} (0x{0:x}) bytes of non-parse-able data left in the buffer:\n{1}"),
3908  a_Buffer.GetReadableSpace(), Hex
3909  ));
3910  m_CommLogFile.Flush();
3911  }
3912 }
3913 
3914 
3915 
3916 
3917 
3919 {
3920  using Type = cEntity::eEntityType;
3921 
3922  switch (a_Entity.GetEntityType())
3923  {
3924  case Type::etEnderCrystal: return 51;
3925  case Type::etPickup: return 2;
3926  case Type::etFallingBlock: return 70;
3927  case Type::etMinecart: return 10;
3928  case Type::etBoat: return 1;
3929  case Type::etTNT: return 50;
3930  case Type::etProjectile:
3931  {
3932  using PType = cProjectileEntity::eKind;
3933  const auto & Projectile = static_cast<const cProjectileEntity &>(a_Entity);
3934 
3935  switch (Projectile.GetProjectileKind())
3936  {
3937  case PType::pkArrow: return 60;
3938  case PType::pkSnowball: return 61;
3939  case PType::pkEgg: return 62;
3940  case PType::pkGhastFireball: return 63;
3941  case PType::pkFireCharge: return 64;
3942  case PType::pkEnderPearl: return 65;
3943  case PType::pkExpBottle: return 75;
3944  case PType::pkSplashPotion: return 73;
3945  case PType::pkFirework: return 76;
3946  case PType::pkWitherSkull: return 66;
3947  }
3948 
3949  break;
3950  }
3951  case Type::etFloater: return 90;
3952  case Type::etItemFrame: return 71;
3953  case Type::etLeashKnot: return 77;
3954 
3955  // Non-objects must not be sent
3956  case Type::etEntity:
3957  case Type::etPlayer:
3958  case Type::etMonster:
3959  case Type::etExpOrb:
3960  case Type::etPainting: break;
3961  }
3962  UNREACHABLE("Unhandled entity kind");
3963 }
3964 
3965 
3966 
3967 
3968 
3969 int cProtocol_1_8_0::GetProtocolParticleID(const AString & a_ParticleName) const
3970 {
3971  static const std::unordered_map<AString, int> ParticleMap
3972  {
3973  // Initialize the ParticleMap:
3974  { "explode", 0 },
3975  { "largeexplode", 1 },
3976  { "hugeexplosion", 2 },
3977  { "fireworksspark", 3 },
3978  { "bubble", 4 },
3979  { "splash", 5 },
3980  { "wake", 6 },
3981  { "suspended", 7 },
3982  { "depthsuspend", 8 },
3983  { "crit", 9 },
3984  { "magiccrit", 10 },
3985  { "smoke", 11 },
3986  { "largesmoke", 12 },
3987  { "spell", 13 },
3988  { "instantspell", 14 },
3989  { "mobspell", 15 },
3990  { "mobspellambient", 16 },
3991  { "witchmagic", 17 },
3992  { "dripwater", 18 },
3993  { "driplava", 19 },
3994  { "angryvillager", 20 },
3995  { "happyvillager", 21 },
3996  { "townaura", 22 },
3997  { "note", 23 },
3998  { "portal", 24 },
3999  { "enchantmenttable", 25 },
4000  { "flame", 26 },
4001  { "lava", 27 },
4002  { "footstep", 28 },
4003  { "cloud", 29 },
4004  { "reddust", 30 },
4005  { "snowballpoof", 31 },
4006  { "snowshovel", 32 },
4007  { "slime", 33 },
4008  { "heart", 34 },
4009  { "barrier", 35 },
4010  { "iconcrack", 36 },
4011  { "blockcrack", 37 },
4012  { "blockdust", 38 },
4013  { "droplet", 39 },
4014  { "take", 40 },
4015  { "mobappearance", 41 },
4016  { "dragonbreath", 42 },
4017  { "endrod", 43 },
4018  { "damageindicator", 44 },
4019  { "sweepattack", 45 },
4020  { "fallingdust", 46 },
4021  { "totem", 47 },
4022  { "spit", 48 }
4023  };
4024 
4025  const auto ParticleName = StrToLower(a_ParticleName);
4026  const auto FindResult = ParticleMap.find(ParticleName);
4027  if (FindResult == ParticleMap.end())
4028  {
4029  LOGWARNING("Unknown particle: %s", a_ParticleName.c_str());
4030  ASSERT(!"Unknown particle");
4031  return 0;
4032  }
4033 
4034  return FindResult->second;
4035 }
4036 
4037 
4038 
4039 
4040 
4042 {
4043  switch (a_Statistic)
4044  {
4045  // V1.8 Achievements
4046  case CustomStatistic::AchOpenInventory: return "achievement.openInventory";
4047  case CustomStatistic::AchMineWood: return "achievement.mineWood";
4048  case CustomStatistic::AchBuildWorkBench: return "achievement.buildWorkBench";
4049  case CustomStatistic::AchBuildPickaxe: return "achievement.buildPickaxe";
4050  case CustomStatistic::AchBuildFurnace: return "achievement.buildFurnace";
4051  case CustomStatistic::AchAcquireIron: return "achievement.acquireIron";
4052  case CustomStatistic::AchBuildHoe: return "achievement.buildHoe";
4053  case CustomStatistic::AchMakeBread: return "achievement.makeBread";
4054  case CustomStatistic::AchBakeCake: return "achievement.bakeCake";
4055  case CustomStatistic::AchBuildBetterPickaxe: return "achievement.buildBetterPickaxe";
4056  case CustomStatistic::AchCookFish: return "achievement.cookFish";
4057  case CustomStatistic::AchOnARail: return "achievement.onARail";
4058  case CustomStatistic::AchBuildSword: return "achievement.buildSword";
4059  case CustomStatistic::AchKillEnemy: return "achievement.killEnemy";
4060  case CustomStatistic::AchKillCow: return "achievement.killCow";
4061  case CustomStatistic::AchFlyPig: return "achievement.flyPig";
4062  case CustomStatistic::AchSnipeSkeleton: return "achievement.snipeSkeleton";
4063  case CustomStatistic::AchDiamonds: return "achievement.diamonds";
4064  case CustomStatistic::AchPortal: return "achievement.portal";
4065  case CustomStatistic::AchGhast: return "achievement.ghast";
4066  case CustomStatistic::AchBlazeRod: return "achievement.blazeRod";
4067  case CustomStatistic::AchPotion: return "achievement.potion";
4068  case CustomStatistic::AchTheEnd: return "achievement.theEnd";
4069  case CustomStatistic::AchTheEnd2: return "achievement.theEnd2";
4070  case CustomStatistic::AchEnchantments: return "achievement.enchantments";
4071  case CustomStatistic::AchOverkill: return "achievement.overkill";
4072  case CustomStatistic::AchBookcase: return "achievement.bookcase";
4073  case CustomStatistic::AchExploreAllBiomes: return "achievement.exploreAllBiomes";
4074  case CustomStatistic::AchSpawnWither: return "achievement.spawnWither";
4075  case CustomStatistic::AchKillWither: return "achievement.killWither";
4076  case CustomStatistic::AchFullBeacon: return "achievement.fullBeacon";
4077  case CustomStatistic::AchBreedCow: return "achievement.breedCow";
4078  case CustomStatistic::AchDiamondsToYou: return "achievement.diamondsToYou";
4079 
4080  // V1.8 stats
4081  case CustomStatistic::AnimalsBred: return "stat.animalsBred";
4082  case CustomStatistic::BoatOneCm: return "stat.boatOneCm";
4083  case CustomStatistic::ClimbOneCm: return "stat.climbOneCm";
4084  case CustomStatistic::CrouchOneCm: return "stat.crouchOneCm";
4085  case CustomStatistic::DamageDealt: return "stat.damageDealt";
4086  case CustomStatistic::DamageTaken: return "stat.damageTaken";
4087  case CustomStatistic::Deaths: return "stat.deaths";
4088  case CustomStatistic::Drop: return "stat.drop";
4089  case CustomStatistic::FallOneCm: return "stat.fallOneCm";
4090  case CustomStatistic::FishCaught: return "stat.fishCaught";
4091  case CustomStatistic::FlyOneCm: return "stat.flyOneCm";
4092  case CustomStatistic::HorseOneCm: return "stat.horseOneCm";
4093  case CustomStatistic::Jump: return "stat.jump";
4094  case CustomStatistic::LeaveGame: return "stat.leaveGame";
4095  case CustomStatistic::MinecartOneCm: return "stat.minecartOneCm";
4096  case CustomStatistic::MobKills: return "stat.mobKills";
4097  case CustomStatistic::PigOneCm: return "stat.pigOneCm";
4098  case CustomStatistic::PlayerKills: return "stat.playerKills";
4099  case CustomStatistic::PlayOneMinute: return "stat.playOneMinute";
4100  case CustomStatistic::SprintOneCm: return "stat.sprintOneCm";
4101  case CustomStatistic::SwimOneCm: return "stat.swimOneCm";
4102  case CustomStatistic::TalkedToVillager: return "stat.talkedToVillager";
4103  case CustomStatistic::TimeSinceDeath: return "stat.timeSinceDeath";
4104  case CustomStatistic::TradedWithVillager: return "stat.tradedWithVillager";
4105  case CustomStatistic::WalkOneCm: return "stat.walkOneCm";
4106  case CustomStatistic::WalkUnderWaterOneCm: return "stat.diveOneCm";
4107 
4108  // V1.8.2 stats
4109  case CustomStatistic::CleanArmor: return "stat.armorCleaned";
4110  case CustomStatistic::CleanBanner: return "stat.bannerCleaned";
4111  case CustomStatistic::EatCakeSlice: return "stat.cakeSlicesEaten";
4112  case CustomStatistic::EnchantItem: return "stat.itemEnchanted";
4113  case CustomStatistic::FillCauldron: return "stat.cauldronFilled";
4114  case CustomStatistic::InspectDispenser: return "stat.dispenserInspected";
4115  case CustomStatistic::InspectDropper: return "stat.dropperInspected";
4116  case CustomStatistic::InspectHopper: return "stat.hopperInspected";
4117  case CustomStatistic::InteractWithBeacon: return "stat.beaconInteraction";
4118  case CustomStatistic::InteractWithBrewingstand: return "stat.brewingstandInteraction";
4119  case CustomStatistic::InteractWithCraftingTable: return "stat.craftingTableInteraction";
4120  case CustomStatistic::InteractWithFurnace: return "stat.furnaceInteraction";
4121  case CustomStatistic::OpenChest: return "stat.chestOpened";
4122  case CustomStatistic::OpenEnderchest: return "stat.enderchestOpened";
4123  case CustomStatistic::PlayNoteblock: return "stat.noteblockPlayed";
4124  case CustomStatistic::PlayRecord: return "stat.recordPlayed";
4125  case CustomStatistic::PotFlower: return "stat.flowerPotted";
4126  case CustomStatistic::TriggerTrappedChest: return "stat.trappedChestTriggered";
4127  case CustomStatistic::TuneNoteblock: return "stat.noteblockTuned";
4128  case CustomStatistic::UseCauldron: return "stat.cauldronUsed";
4129 
4130  // V1.9 stats
4131  case CustomStatistic::AviateOneCm: return "stat.aviateOneCm";
4132  case CustomStatistic::SleepInBed: return "stat.sleepInBed";
4133  case CustomStatistic::SneakTime: return "stat.sneakTime";
4134  default: return "";
4135  }
4136 }
4137 
4138 
4139 
4140 
4141 
4143 {
4144  UInt32 PacketType;
4145  if (!a_Buffer.ReadVarInt(PacketType))
4146  {
4147  // Not enough data
4148  return;
4149  }
4150 
4151  // Log the packet info into the comm log file:
4153  {
4154  ContiguousByteBuffer PacketData;
4155  a_Buffer.ReadAll(PacketData);
4156  a_Buffer.ResetRead();
4157  a_Buffer.ReadVarInt(PacketType); // We have already read the packet type once, it will be there again
4158  ASSERT(PacketData.size() > 0); // We have written an extra NUL, so there had to be at least one byte read
4159  PacketData.resize(PacketData.size() - 1);
4160  AString PacketDataHex;
4161  CreateHexDump(PacketDataHex, PacketData.data(), PacketData.size(), 16);
4162  m_CommLogFile.Write(fmt::format(
4163  FMT_STRING("Next incoming packet is type {0} (0x{0:x}), length {1} (0x{1:x}) at state {2}. Payload:\n{3}\n"),
4164  PacketType, a_Buffer.GetUsedSpace(), m_State, PacketDataHex
4165  ));
4166  }
4167 
4168  if (!HandlePacket(a_Buffer, PacketType))
4169  {
4170  // Unknown packet, already been reported, but without the length. Log the length here:
4171  LOGWARNING("Unhandled packet: type 0x%x, state %d, length %u", PacketType, m_State, a_Buffer.GetUsedSpace());
4172 
4173 #ifndef NDEBUG
4174  // Dump the packet contents into the log:
4175  a_Buffer.ResetRead();
4176  ContiguousByteBuffer Packet;
4177  a_Buffer.ReadAll(Packet);
4178  Packet.resize(Packet.size() - 1); // Drop the final NUL pushed there for over-read detection
4179  AString Out;
4180  CreateHexDump(Out, Packet.data(), Packet.size(), 24);
4181  LOGD("Packet contents:\n%s", Out.c_str());
4182 #endif // !NDEBUG
4183 
4184  // Put a message in the comm log:
4186  {
4187  m_CommLogFile.Write("^^^^^^ Unhandled packet ^^^^^^\n\n\n");
4188  }
4189 
4190  return;
4191  }
4192 
4193  // The packet should have nothing left in the buffer:
4194  if (a_Buffer.GetReadableSpace() != 0)
4195  {
4196  // Read more or less than packet length, report as error
4197  LOGWARNING("Protocol 1.8: Wrong number of bytes read for packet 0x%x, state %d. Read %zu bytes, packet contained %u bytes",
4198  PacketType, m_State, a_Buffer.GetUsedSpace() - a_Buffer.GetReadableSpace(), a_Buffer.GetUsedSpace()
4199  );
4200 
4201  // Put a message in the comm log:
4203  {
4204  m_CommLogFile.Write(fmt::format(
4205  FMT_STRING("^^^^^^ Wrong number of bytes read for this packet (exp 1 left, got {} left) ^^^^^^\n\n\n"),
4206  a_Buffer.GetReadableSpace()
4207  ));
4208  m_CommLogFile.Flush();
4209  }
4210 
4211  ASSERT(!"Read wrong number of bytes!");
4212  m_Client->PacketError(PacketType);
4213  }
4214 }
4215 
4216 
4217 
4218 
4219 
4221 {
4222  m_Encryptor.Init(a_Key, a_Key);
4223  m_Decryptor.Init(a_Key, a_Key);
4224  m_IsEncrypted = true;
4225 
4226  // Prepare the m_AuthServerID:
4227  cSha1Checksum Checksum;
4228  cServer * Server = cRoot::Get()->GetServer();
4229  const AString & ServerID = Server->GetServerID();
4230  Checksum.Update(reinterpret_cast<const Byte *>(ServerID.c_str()), ServerID.length());
4231  Checksum.Update(a_Key, 16);
4232  Checksum.Update(reinterpret_cast<const Byte *>(Server->GetPublicKeyDER().data()), Server->GetPublicKeyDER().size());
4233  Byte Digest[20];
4234  Checksum.Finalize(Digest);
4236 }
@ E_BLOCK_HEAD
Definition: BlockType.h:159
@ E_BLOCK_STANDING_BANNER
Definition: BlockType.h:195
@ E_BLOCK_ENCHANTMENT_TABLE
Definition: BlockType.h:131
@ E_BLOCK_BEACON
Definition: BlockType.h:153
@ E_BLOCK_CHEST
Definition: BlockType.h:64
@ E_BLOCK_TRAPPED_CHEST
Definition: BlockType.h:161
@ E_BLOCK_COMMAND_BLOCK
Definition: BlockType.h:152
@ E_BLOCK_END_PORTAL
Definition: BlockType.h:134
@ E_BLOCK_FLOWER_POT
Definition: BlockType.h:155
@ E_BLOCK_MOB_SPAWNER
Definition: BlockType.h:62
@ E_BLOCK_WALL_BANNER
Definition: BlockType.h:196
ENUM_ITEM_TYPE
Definition: BlockType.h:295
@ E_ITEM_FIREWORK_STAR
Definition: BlockType.h:448
@ E_ITEM_FIREWORK_ROCKET
Definition: BlockType.h:447
@ E_ITEM_BOOK
Definition: BlockType.h:385
std::vector< sSetBlock > sSetBlockVector
Definition: ChunkDef.h:441
unsigned char NIBBLETYPE
The datatype used by nibbledata (meta, light, skylight)
Definition: ChunkDef.h:44
unsigned char BLOCKTYPE
The datatype used by blockdata.
Definition: ChunkDef.h:41
eWeather
Definition: Defines.h:160
@ wSunny
Definition: Defines.h:166
BossBarDivisionType
Definition: Defines.h:443
EntityAnimation
Definition: Defines.h:458
@ EntityGetsMagicalCriticalHit
eChatType
Definition: Defines.h:149
@ ctAboveActionBar
Definition: Defines.h:152
@ ctChatBox
Definition: Defines.h:150
@ ctSystem
Definition: Defines.h:151
eDimension
Dimension of a world.
Definition: Defines.h:231
eGameMode
Definition: Defines.h:125
eClickAction
Individual actions sent in the WindowClick packet.
Definition: Defines.h:82
@ caRightPaintProgress
Definition: Defines.h:108
@ caDblClick
Definition: Defines.h:113
@ caLeftPaintProgress
Definition: Defines.h:107
@ caNumber6
Definition: Defines.h:93
@ caNumber8
Definition: Defines.h:95
@ caMiddleClick
Definition: Defines.h:97
@ caCtrlDropKey
Definition: Defines.h:99
@ caLeftPaintEnd
Definition: Defines.h:110
@ caLeftClickOutside
Definition: Defines.h:100
@ caMiddlePaintEnd
Definition: Defines.h:112
@ caLeftClickOutsideHoldNothing
Definition: Defines.h:102
@ caDropKey
Definition: Defines.h:98
@ caShiftRightClick
Definition: Defines.h:87
@ caNumber7
Definition: Defines.h:94
@ caRightClick
Definition: Defines.h:85
@ caNumber4
Definition: Defines.h:91
@ caNumber1
Definition: Defines.h:88
@ caMiddlePaintBegin
Definition: Defines.h:106
@ caMiddlePaintProgress
Definition: Defines.h:109
@ caNumber3
Definition: Defines.h:90
@ caLeftPaintBegin
Definition: Defines.h:104
@ caRightClickOutsideHoldNothing
Definition: Defines.h:103
@ caNumber9
Definition: Defines.h:96
@ caNumber2
Definition: Defines.h:89
@ caRightPaintEnd
Definition: Defines.h:111
@ caRightClickOutside
Definition: Defines.h:101
@ caUnknown
Definition: Defines.h:115
@ caShiftLeftClick
Definition: Defines.h:86
@ caNumber5
Definition: Defines.h:92
@ caRightPaintBegin
Definition: Defines.h:105
@ caLeftClick
Definition: Defines.h:84
eBlockFace
Block face constants, used in PlayerDigging and PlayerBlockPlacement packets and bbox collision calc.
Definition: Defines.h:38
@ BLOCK_FACE_XP
Definition: Defines.h:41
@ BLOCK_FACE_YP
Definition: Defines.h:43
@ BLOCK_FACE_YM
Definition: Defines.h:42
@ BLOCK_FACE_ZM
Definition: Defines.h:44
@ BLOCK_FACE_ZP
Definition: Defines.h:45
@ BLOCK_FACE_XM
Definition: Defines.h:40
@ BLOCK_FACE_NONE
Definition: Defines.h:39
BossBarColor
Definition: Defines.h:428
EffectID
Definition: EffectID.h:6
#define UNREACHABLE(x)
Definition: Globals.h:288
std::chrono::duration< signed long long int, cTickTime::period > cTickTimeLong
Definition: Globals.h:367
#define ARRAYCOUNT(X)
Evaluates to the number of elements in an array (compile-time!)
Definition: Globals.h:231
#define VERIFY(x)
Definition: Globals.h:280
unsigned int UInt32
Definition: Globals.h:157
signed long long Int64
Definition: Globals.h:151
signed short Int16
Definition: Globals.h:153
std::basic_string_view< std::byte > ContiguousByteBufferView
Definition: Globals.h:376
signed char Int8
Definition: Globals.h:154
signed int Int32
Definition: Globals.h:152
unsigned char UInt8
Definition: Globals.h:159
#define ASSERT(x)
Definition: Globals.h:276
unsigned short UInt16
Definition: Globals.h:158
std::basic_string< std::byte > ContiguousByteBuffer
Definition: Globals.h:375
#define UNUSED
Definition: Globals.h:72
unsigned char Byte
Definition: Globals.h:161
void LOGERROR(std::string_view a_Format, const Args &... args)
Definition: LoggerSimple.h:73
void LOGWARNING(std::string_view a_Format, const Args &... args)
Definition: LoggerSimple.h:67
void LOG(std::string_view a_Format, const Args &... args)
Definition: LoggerSimple.h:55
#define LOGD
Definition: LoggerSimple.h:83
void FLOGERROR(std::string_view a_Format, const Args &... args)
Definition: LoggerSimple.h:47
bool g_ShouldLogCommOut
If set to true, the protocols will log each player's outgoing (S->C) communication to a per-connectio...
Definition: main.cpp:22
bool g_ShouldLogCommIn
If set to true, the protocols will log each player's incoming (C->S) communication to a per-connectio...
Definition: main.cpp:21
eMonsterType
Identifies individual monster type.
Definition: MonsterTypes.h:11
@ mtZombieVillager
Definition: MonsterTypes.h:82
@ mtElderGuardian
Definition: MonsterTypes.h:25
@ mtSkeleton
Definition: MonsterTypes.h:59
@ mtSheep
Definition: MonsterTypes.h:56
@ mtEndermite
Definition: MonsterTypes.h:28
@ mtMagmaCube
Definition: MonsterTypes.h:40
@ mtWolf
Definition: MonsterTypes.h:77
@ mtStray
Definition: MonsterTypes.h:65
@ mtRabbit
Definition: MonsterTypes.h:53
@ mtCat
Definition: MonsterTypes.h:16
@ mtZombie
Definition: MonsterTypes.h:79
@ mtOcelot
Definition: MonsterTypes.h:43
@ mtDonkey
Definition: MonsterTypes.h:23
@ mtEnderman
Definition: MonsterTypes.h:27
@ mtHusk
Definition: MonsterTypes.h:36
@ mtCaveSpider
Definition: MonsterTypes.h:17
@ mtWither
Definition: MonsterTypes.h:75
@ mtSkeletonHorse
Definition: MonsterTypes.h:60
@ mtPig
Definition: MonsterTypes.h:47
@ mtVillager
Definition: MonsterTypes.h:71
@ mtHorse
Definition: MonsterTypes.h:34
@ mtZombieHorse
Definition: MonsterTypes.h:80
@ mtWitch
Definition: MonsterTypes.h:74
@ mtCow
Definition: MonsterTypes.h:20
@ mtEnderDragon
Definition: MonsterTypes.h:26
@ mtMooshroom
Definition: MonsterTypes.h:41
@ mtSquid
Definition: MonsterTypes.h:64
@ mtInvalidType
Definition: MonsterTypes.h:12
@ mtBat
Definition: MonsterTypes.h:14
@ mtChicken
Definition: MonsterTypes.h:18
@ mtGiant
Definition: MonsterTypes.h:32
@ mtSnowGolem
Definition: MonsterTypes.h:62
@ mtBlaze
Definition: MonsterTypes.h:15
@ mtIronGolem
Definition: MonsterTypes.h:38
@ mtCreeper
Definition: MonsterTypes.h:21
@ mtSpider
Definition: MonsterTypes.h:63
@ mtMule
Definition: MonsterTypes.h:42
@ mtGhast
Definition: MonsterTypes.h:31
@ mtSilverfish
Definition: MonsterTypes.h:58
@ mtZombiePigman
Definition: MonsterTypes.h:85
@ mtSlime
Definition: MonsterTypes.h:61
@ mtWitherSkeleton
Definition: MonsterTypes.h:76
@ mtGuardian
Definition: MonsterTypes.h:33
#define HANDLE_PACKET_READ(ByteBuf, Proc, Type, Var)
Definition: Packetizer.h:41
#define HANDLE_READ(ByteBuf, Proc, Type, Var)
Macros used to read packets more easily.
Definition: Packetizer.h:28
static const UInt32 CompressionThreshold
const int MAX_ENC_LEN
CustomStatistic
Item
Definition: Items.h:4
@ WrittenBook
@ Rabbit
@ Chicken
@ Minecart
AString StrToLower(const AString &s)
Returns a lower-cased copy of the string.
bool SplitZeroTerminatedStrings(const AString &a_Strings, AStringVector &a_Output)
Splits a string that has embedded \0 characters, on those characters.
void ReplaceString(AString &iHayStack, const AString &iNeedle, const AString &iReplaceWith)
Replaces each occurence of iNeedle in iHayStack with iReplaceWith.
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...
std::vector< AString > AStringVector
Definition: StringUtils.h:12
std::string AString
Definition: StringUtils.h:11
@ TAG_List
Definition: FastNBT.h:41
@ TAG_String
Definition: FastNBT.h:40
@ TAG_Compound
Definition: FastNBT.h:42
@ TAG_Int
Definition: FastNBT.h:35
AString SerializeSingleValueJsonObject(const AString &a_Key, const AString &a_Value)
Creates a Json string representing an object with the specified single value.
Definition: JsonUtils.cpp:47
AString WriteFastString(const Json::Value &a_Root)
Definition: JsonUtils.cpp:12
bool ParseString(const AString &a_JsonStr, Json::Value &a_Root, AString *a_ErrorMsg)
Definition: JsonUtils.cpp:34
Utilities to allow casting a cWorld to one of its interfaces without including World....
Definition: OpaqueWorld.h:13
void ParseFromNBT(cEnchantments &a_Enchantments, const cParsedNBT &a_NBT, int a_EnchListTagIdx)
Reads the enchantments from the specified NBT list tag (ench or StoredEnchantments)
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...
bool CallHookServerPing(cClientHandle &a_ClientHandle, AString &a_ServerDescription, int &a_OnlinePlayersCount, int &a_MaxPlayersCount, AString &a_Favicon)
int GetPosZ() const
Definition: BlockEntity.h:93
int GetPosY() const
Definition: BlockEntity.h:92
int GetPosX() const
Definition: BlockEntity.h:91
BLOCKTYPE GetBlockType() const
Definition: BlockEntity.h:97
An object that can store incoming bytes and lets its clients read the bytes sequentially The bytes ar...
Definition: ByteBuffer.h:32
size_t GetUsedSpace(void) const
Returns the number of bytes that are currently in the ringbuffer.
Definition: ByteBuffer.cpp:185
bool SkipRead(size_t a_Count)
Skips reading by a_Count bytes; returns false if not enough bytes in the ringbuffer.
Definition: ByteBuffer.cpp:961
bool CanReadBytes(size_t a_Count) const
Returns true if the specified amount of bytes are available for reading.
Definition: ByteBuffer.cpp:235
void CommitRead(void)
Removes the bytes that have been read from the ringbuffer.
void ReadAll(ContiguousByteBuffer &a_Data)
Reads all available data into a_Data.
Definition: ByteBuffer.cpp:977
bool ReadUUID(cUUID &a_Value)
Definition: ByteBuffer.cpp:573
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:988
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:198
bool ReadVarInt(T &a_Value)
Reads VarInt, assigns it to anything that can be assigned from an UInt64 (unsigned short,...
Definition: ByteBuffer.h:88
bool ReadXYZPosition64(int &a_BlockX, int &a_BlockY, int &a_BlockZ)
Definition: ByteBuffer.cpp:505
bool WriteVarInt32(UInt32 a_Value)
Definition: ByteBuffer.cpp:745
static size_t GetVarIntSize(UInt32 a_Value)
Gets the number of bytes that are needed to represent the given VarInt.
bool ReadVarUTF8String(AString &a_Value)
Definition: ByteBuffer.cpp:458
bool ReadSome(ContiguousByteBuffer &a_String, size_t a_Count)
Reads a_Count bytes into a_String; returns true if successful.
Definition: ByteBuffer.cpp:927
void ResetRead(void)
Restarts next reading operation at the start of the ringbuffer.
bool Write(const void *a_Bytes, size_t a_Count)
Writes the bytes specified to the ringbuffer.
Definition: ByteBuffer.cpp:111
static bool CanBEInt8Represent(int a_Value)
Returns if the given value can fit in a protocol big-endian 8 bit integer.
Definition: ByteBuffer.cpp:217
ContiguousByteBufferView GetView() const
void ReadFrom(cByteBuffer &Buffer)
void ReadFrom(cByteBuffer &Buffer, size_t Size)
Compression::Result Extract(size_t UncompressedSize)
void HandleUnmount(void)
void HandleCommandBlockBlockChange(Vector3i a_BlockPos, const AString &a_NewCommand)
Called when the protocol receives a message, indicating that the player set a new command in the comm...
void SetLocale(const AString &a_Locale)
Definition: ClientHandle.h:267
void HandleLeftClick(Vector3i a_BlockPos, eBlockFace a_BlockFace, UInt8 a_Status)
void HandleCommandBlockEntityChange(UInt32 a_EntityID, const AString &a_NewCommand)
Called when the protocol receives a message, indicating that the player set a new command in the comm...
void HandleRespawn(void)
void SetViewDistance(int a_ViewDistance)
Sets the maximal view distance.
void SetUsername(AString &&a_Username)
void HandleEnchantItem(UInt8 a_WindowID, UInt8 a_Enchantment)
Called when the player enchants an Item in the Enchanting table UI.
void Kick(const AString &a_Reason)
void HandleChat(const AString &a_Message)
Called when the protocol detects a chat packet.
void ForgeAugmentServerListPing(Json::Value &a_Response)
Add the Forge mod list to the server ping response.
Definition: ClientHandle.h:290
void SetClientBrand(const AString &a_ClientBrand)
Called by the protocol when it receives the MC|Brand plugin message.
Definition: ClientHandle.h:276
void HandleResourcePack(UInt8 a_Status)
void HandleAnvilItemName(const AString &a_ItemName)
Called when the protocol receives a MC|ItemName plugin message, indicating that the player named an i...
void PacketUnknown(UInt32 a_PacketType)
void HandleWindowClick(UInt8 a_WindowID, Int16 a_SlotNum, eClickAction a_ClickAction, const cItem &a_HeldItem)
short GetPing(void) const
Definition: ClientHandle.h:256
void HandleLeaveBed()
Handles a player exiting his bed.
void HandleKeepAlive(UInt32 a_KeepAliveID)
void PacketError(UInt32 a_PacketType)
void SendPluginMessage(const AString &a_Channel, std::string_view a_Message)
void HandlePlayerLook(float a_Rotation, float a_Pitch, bool a_IsOnGround)
void HandleRightClick(Vector3i a_BlockPos, eBlockFace a_BlockFace, Vector3i a_Cursor, bool a_UsedMainHand)
void HandlePluginMessage(const AString &a_Channel, ContiguousByteBufferView a_Message)
bool HandleHandshake(const AString &a_Username)
Called when the protocol handshake has been received (for protocol versions that support it; otherwis...
const cUUID & GetUUID(void) const
Returns the player's UUID, as used by the protocol.
Definition: ClientHandle.h:81
void ProxyInit(const AString &a_IPString, const cUUID &a_UUID)
Function to mark bungee / proxy connection on this client, and to add proxy-related data.
void HandleUseEntity(UInt32 a_TargetEntityID, bool a_IsLeftClick)
void HandleUpdateSign(Vector3i a_BlockPos, const AString &a_Line1, const AString &a_Line2, const AString &a_Line3, const AString &a_Line4)
void SetIsForgeClient()
Mark a client connection as using Forge.
Definition: ClientHandle.h:296
void HandleSteerVehicle(float Forward, float Sideways)
void HandleUseItem(bool a_UsedMainHand)
void HandleSprint(bool a_IsSprinting)
Handles a player sprinting or slowing back down.
const AString & GetUsername(void) const
void HandlePlayerMove(Vector3d a_Pos, bool a_IsOnGround)
Verifies and sets player position, performing relevant checks.
const AString & GetIPString(void) const
Definition: ClientHandle.h:72
void HandleTabCompletion(const AString &a_Text)
void HandlePlayerAbilities(bool a_IsFlying, float FlyingSpeed, float WalkingSpeed)
void HandleNPCTrade(int a_SlotNum)
Called when the protocol receives a MC|TrSel packet, indicating that the player used a trade in the N...
void HandleSpectate(const cUUID &a_PlayerUUID)
void HandleBeaconSelection(unsigned a_PrimaryEffect, unsigned a_SecondaryEffect)
Called when the protocol receives a MC|Beacon plugin message, indicating that the player set an effec...
void HandleWindowClose(UInt8 a_WindowID)
void HandleCrouch(bool a_IsCrouching)
Handles a player sneaking or unsneaking.
cPlayer * GetPlayer(void)
Definition: ClientHandle.h:78
void PacketBufferFull(void)
void HandleSlotSelected(Int16 a_SlotNum)
void HandlePlayerMoveLook(Vector3d a_Pos, float a_Rotation, float a_Pitch, bool a_IsOnGround)
bool HandleLogin()
Called when the protocol has finished logging the user in.
void HandleOpenHorseInventory()
Handles a player opening his inventory while riding a horse.
void SendData(ContiguousByteBufferView a_Data)
void HandleAnimation(bool a_SwingMainHand)
Called when the protocol receives a (hand swing) animation packet.
const Json::Value & GetProperties(void) const
Definition: ClientHandle.h:88
void HandleCreativeInventory(Int16 a_SlotNum, const cItem &a_HeldItem, eClickAction a_ClickAction)
Called when the client clicks the creative inventory window.
unsigned int m_Color
Definition: Color.h:56
bool IsValid() const
Returns whether the color is a valid color.
Definition: Color.h:28
Container for a single chat message composed of multiple functional parts.
Definition: CompositeChat.h:34
AString CreateJsonString(bool a_ShouldUseChatPrefixes=true) const
bool IsEmpty(void) const
Returns true if there are no enchantments.
bool IsCritical(void) const
Returns true if the arrow is set as critical.
Definition: ArrowEntity.h:70
Definition: Entity.h:76
bool IsProjectile(void) const
Definition: Entity.h:168
virtual bool IsElytraFlying(void) const
Definition: Entity.h:487
virtual bool IsRclking(void) const
Definition: Entity.h:490
bool IsPlayer(void) const
Definition: Entity.h:160
double GetSpeedZ(void) const
Definition: Entity.h:204
virtual bool IsCrouched(void) const
Definition: Entity.h:486
float GetMaxHealth(void) const
Definition: Entity.h:407
double GetSpeedY(void) const
Definition: Entity.h:203
bool IsItemFrame(void) const
Definition: Entity.h:171
Vector3d GetLastSentPosition(void) const
Returns the last position we sent to all the clients.
Definition: Entity.h:304
double GetPosX(void) const
Definition: Entity.h:195
double GetPosZ(void) const
Definition: Entity.h:197
bool IsMinecart(void) const
Definition: Entity.h:165
UInt32 GetUniqueID(void) const
Definition: Entity.h:253
eEntityType GetEntityType(void) const
Definition: Entity.h:156
double GetPitch(void) const
Definition: Entity.h:199
virtual bool IsOnFire(void) const
Definition: Entity.h:489
bool IsOrientationDirty() const
Returns whether the entity's orientation has been set manually.
Definition: Entity.cpp:2093
double GetPosY(void) const
Definition: Entity.h:196
double GetHeadYaw(void) const
Definition: Entity.h:192
virtual bool IsOnGround(void) const
Returns whether the entity is on ground or not.
Definition: Entity.h:519
bool IsFallingBlock(void) const
Definition: Entity.h:164
bool IsFloater(void) const
Definition: Entity.h:170
virtual bool IsInvisible(void) const
Definition: Entity.h:488
double GetYaw(void) const
Definition: Entity.h:198
float GetHealth(void) const
Returns the health of this entity.
Definition: Entity.h:367
const Vector3d & GetPosition(void) const
Exported in ManualBindings.
Definition: Entity.h:297
eEntityType
Definition: Entity.h:89
@ etPickup
Definition: Entity.h:93
@ etProjectile
Definition: Entity.h:99
@ etItemFrame
Definition: Entity.h:102
@ etMinecart
Definition: Entity.h:96
@ etMonster
Definition: Entity.h:94
@ etPlayer
Definition: Entity.h:92
virtual bool IsSprinting(void) const
Definition: Entity.h:492
double GetSpeedX(void) const
Definition: Entity.h:202
cWorld * GetWorld(void) const
Definition: Entity.h:190
bool IsMob(void) const
Definition: Entity.h:162
Definition: ExpOrb.h:13
int GetReward(void) const
Get the exp amount.
Definition: ExpOrb.h:40
Byte GetProtocolFacing() const
Returns the direction in which the entity is facing.
Definition: HangingEntity.h:28
@ mpNone
Definition: Minecart.h:31
@ mpFurnace
Definition: Minecart.h:33
bool IsFueled(void) const
Definition: Minecart.h:201
const AString & GetName(void) const
Returns the protocol name of the painting.
Definition: Painting.h:25
Definition: Pickup.h:20
Definition: Player.h:29
cClientHandle * GetClientHandle(void) const
Definition: Player.h:276
void AwardAchievement(CustomStatistic a_Ach)
Awards the player an achievement.
Definition: Player.cpp:1372
StatisticsManager & GetStatistics()
Return the associated statistic and achievement manager.
Definition: Player.h:237
int GetCurrentXp(void)
Gets the current experience.
Definition: Player.h:117
const cUUID & GetUUID(void) const
Returns the UUID that has been read from the client, or nil if not available.
Definition: Player.cpp:2431
const cItem & GetEquippedItem(void) const
Definition: Player.h:162
float GetXpPercentage(void) const
Gets the experience bar percentage - XpP.
Definition: Player.cpp:246
virtual bool CanFly(void) const
Returns wheter the player can fly or not.
Definition: Player.h:549
double GetFlyingMaxSpeed(void) const
Gets the flying relative maximum speed.
Definition: Player.h:475
int GetXpLevel(void) const
Gets the current level - XpLevel.
Definition: Player.cpp:237
bool IsGameModeCreative(void) const
Returns true if the player is in Creative mode, either explicitly, or by inheriting from current worl...
Definition: Player.cpp:1025
void SetSkinParts(int a_Parts)
Definition: Player.cpp:2504
double GetNormalMaxSpeed(void) const
Gets the normal relative maximum speed.
Definition: Player.h:469
bool IsGameModeSpectator(void) const
Returns true if the player is in Spectator mode, either explicitly, or by inheriting from current wor...
Definition: Player.cpp:1052
bool IsFlying(void) const
Returns true if the player is currently flying.
Definition: Player.h:377
int GetFoodLevel(void) const
Definition: Player.h:354
AString GetPlayerListName(void) const
Returns the name that is used in the playerlist.
Definition: Player.cpp:1685
eGameMode GetEffectiveGameMode(void) const
Returns the current effective gamemode (inherited gamemode is resolved before returning)
Definition: Player.cpp:1531
double GetFoodSaturationLevel(void) const
Definition: Player.h:355
eKind
The kind of the projectile.
Definition: Item.h:37
bool IsBothNameAndLoreEmpty(void) const
Definition: Item.h:95
cEnchantments m_Enchantments
Definition: Item.h:166
bool IsCustomNameEmpty(void) const
Definition: Item.h:101
char m_ItemCount
Definition: Item.h:164
AString m_CustomName
Definition: Item.h:167
bool IsEmpty(void) const
Returns true if the item represents an empty stack - either the type is invalid, or count is zero.
Definition: Item.h:69
cColor m_ItemColor
Definition: Item.h:202
bool IsLoreEmpty(void) const
Definition: Item.h:102
AStringVector m_LoreTable
Definition: Item.h:171
short m_ItemType
Definition: Item.h:163
int m_RepairCost
Definition: Item.h:200
void Empty(void)
Empties the item and frees up any dynamic storage used by the internals.
Definition: Item.cpp:63
cFireworkItem m_FireworkItem
Definition: Item.h:201
short m_ItemDamage
Definition: Item.h:165
This class bridges a vector of cItem for safe access via Lua.
Definition: Item.h:215
Encapsulates an in-game world map.
Definition: Map.h:83
const cMapDecoratorList GetDecorators(void) const
Definition: Map.h:168
const cColorList & GetData(void) const
Definition: Map.h:170
unsigned int GetScale(void) const
Definition: Map.h:147
unsigned int GetID(void) const
Definition: Map.h:152
void Init(const Byte a_Key[16], const Byte a_IV[16])
Initializes the decryptor with the specified Key / IV.
void ProcessData(std::byte *a_EncryptedIn, size_t a_Length)
Decrypts a_Length bytes of the encrypted data in-place; produces a_Length output bytes.
void ProcessData(std::byte *a_PlainIn, size_t a_Length)
Encrypts a_Length bytes of the plain data in-place; produces a_Length output bytes.
void Init(const Byte a_Key[16], const Byte a_IV[16])
Initializes the decryptor with the specified Key / IV.
Encapsulates an RSA private key used in PKI cryptography.
Definition: RsaPrivateKey.h:21
int Decrypt(ContiguousByteBufferView a_EncryptedData, Byte *a_DecryptedData, size_t a_DecryptedMaxLength)
Decrypts the data using RSAES-PKCS#1 algorithm.
Calculates a SHA1 checksum for data stream.
Definition: Sha1Checksum.h:20
void Update(const Byte *a_Data, size_t a_Length)
Adds the specified data to the checksum.
void Finalize(Checksum &a_Output)
Calculates and returns the final checksum.
static void DigestToHex(const Checksum &a_Digest, AString &a_Out)
Converts a SHA1 digest into hex.
static void DigestToJava(const Checksum &a_Digest, AString &a_Out)
Converts a raw 160-bit SHA1 digest into a Java Hex representation According to http://wiki....
Definition: Bat.h:12
Definition: Cow.h:12
Definition: Ghast.h:12
Definition: Horse.h:14
static AString MobTypeToVanillaName(eMonsterType a_MobType)
Translates MobType enum to the vanilla name of the mob, empty string if unknown.
Definition: Monster.cpp:1025
bool HasCustomName(void) const
Returns true if the monster has a custom name.
Definition: Monster.h:165
const AString & GetCustomName(void) const
Gets the custom name of the monster.
Definition: Monster.h:168
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:175
eMonsterType GetMobType(void) const
Definition: Monster.h:70
Definition: Ocelot.h:13
Definition: Pig.h:12
Definition: Rabbit.h:27
Definition: Sheep.h:12
Definition: Slime.h:12
Definition: Witch.h:12
Definition: Wither.h:12
Definition: Wolf.h:14
Definition: Zombie.h:11
RAII for cCriticalSection - locks the CS on creation, unlocks on destruction.
void Flush()
Flushes all the bufferef output into the file (only when writing)
Definition: File.cpp:695
static bool CreateFolder(const AString &a_FolderPath)
Creates a new folder with the specified name.
Definition: File.cpp:454
@ fmWrite
Definition: File.h:55
bool Open(const AString &iFileName, eMode iMode)
Definition: File.cpp:52
bool IsOpen(void) const
Definition: File.cpp:118
int Write(const void *a_Buffer, size_t a_NumBytes)
Writes up to a_NumBytes bytes from a_Buffer, returns the number of bytes actually written,...
Definition: File.cpp:180
Composes an individual packet in the protocol's m_OutPacketBuffer; sends it just before being destruc...
Definition: Packetizer.h:60
cProtocol::ePacketType GetPacketType() const
Definition: Packetizer.h:196
void WriteVarInt32(UInt32 a_Value)
Definition: Packetizer.h:141
void WriteUUID(const cUUID &a_UUID)
Writes the specified UUID as a 128-bit BigEndian integer.
Definition: Packetizer.cpp:44
void WriteBEUInt32(UInt32 a_Value)
Definition: Packetizer.h:111
void WriteBEInt32(Int32 a_Value)
Definition: Packetizer.h:105
void WriteBool(bool a_Value)
Definition: Packetizer.h:76
static AString PacketTypeToStr(cProtocol::ePacketType a_PacketType)
Returns the human-readable representation of the packet type.
Definition: Packetizer.cpp:56
void WriteXYZPosition64(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:161
void WriteBEUInt64(UInt64 a_Value)
Definition: Packetizer.h:123
void WriteBEFloat(float a_Value)
Definition: Packetizer.h:129
void WriteFPInt(double a_Value)
Writes the double value as a 27:5 fixed-point integer.
Definition: Packetizer.cpp:35
void WriteBEInt16(Int16 a_Value)
Definition: Packetizer.h:93
void WriteString(const AString &a_Value)
Definition: Packetizer.h:147
void WriteBEUInt8(UInt8 a_Value)
Definition: Packetizer.h:81
void WriteBEDouble(double a_Value)
Definition: Packetizer.h:135
void WriteBuf(const ContiguousByteBufferView a_Data)
Definition: Packetizer.h:153
void WriteBEInt64(Int64 a_Value)
Definition: Packetizer.h:117
void WriteByteAngle(double a_Angle)
Writes the specified angle using a single byte.
Definition: Packetizer.cpp:26
void WriteBEInt8(Int8 a_Value)
Definition: Packetizer.h:87
cCriticalSection m_CSPacket
Provides synchronization for sending the entire packet at once.
Definition: Protocol.h:477
cByteBuffer m_OutPacketLenBuffer
Buffer for composing packet length (so that each cPacketizer instance doesn't allocate a new cPacketB...
Definition: Protocol.h:483
ePacketType
Logical types of outgoing packets.
Definition: Protocol.h:57
@ pktUnloadChunk
Definition: Protocol.h:123
@ pktEntityHeadLook
Definition: Protocol.h:77
@ pktSoundEffect
Definition: Protocol.h:108
@ pktEntityRelMove
Definition: Protocol.h:81
@ pktSoundParticleEffect
Definition: Protocol.h:109
@ pktEntityVelocity
Definition: Protocol.h:84
@ pktEntityMeta
Definition: Protocol.h:79
@ pktAttachEntity
Definition: Protocol.h:58
@ pktBlockChanges
Definition: Protocol.h:62
@ pktDisplayObjective
Definition: Protocol.h:71
@ pktChatRaw
Definition: Protocol.h:65
@ pktUseBed
Definition: Protocol.h:129
@ pktMapData
Definition: Protocol.h:95
@ pktResourcePack
Definition: Protocol.h:104
@ pktSpawnGlobalEntity
Definition: Protocol.h:111
@ pktKeepAlive
Definition: Protocol.h:92
@ pktInventorySlot
Definition: Protocol.h:90
@ pktSpawnPainting
Definition: Protocol.h:114
@ pktParticleEffect
Definition: Protocol.h:96
@ pktSpawnOtherPlayer
Definition: Protocol.h:113
@ pktCameraSetTo
Definition: Protocol.h:64
@ pktEntityEffect
Definition: Protocol.h:75
@ pktTeleportEntity
Definition: Protocol.h:120
@ pktUpdateBlockEntity
Definition: Protocol.h:125
@ pktPluginMessage
Definition: Protocol.h:102
@ pktSpawnExperienceOrb
Definition: Protocol.h:110
@ pktSpawnObject
Definition: Protocol.h:107
@ pktPlayerMoveLook
Definition: Protocol.h:101
@ pktEditSign
Definition: Protocol.h:72
@ pktStatistics
Definition: Protocol.h:117
@ pktSpawnPosition
Definition: Protocol.h:115
@ pktTimeUpdate
Definition: Protocol.h:121
@ pktStatusResponse
Definition: Protocol.h:118
@ pktPlayerList
Definition: Protocol.h:99
@ pktEntityRelMoveLook
Definition: Protocol.h:82
@ pktJoinGame
Definition: Protocol.h:91
@ pktExplosion
Definition: Protocol.h:86
@ pktDifficulty
Definition: Protocol.h:68
@ pktDestroyEntity
Definition: Protocol.h:67
@ pktUpdateHealth
Definition: Protocol.h:126
@ pktUpdateScore
Definition: Protocol.h:127
@ pktPingResponse
Definition: Protocol.h:97
@ pktEntityEquipment
Definition: Protocol.h:76
@ pktWindowOpen
Definition: Protocol.h:133
@ pktUpdateSign
Definition: Protocol.h:128
@ pktRespawn
Definition: Protocol.h:105
@ pktWindowProperty
Definition: Protocol.h:134
@ pktEntityProperties
Definition: Protocol.h:80
@ pktEntityStatus
Definition: Protocol.h:83
@ pktEncryptionRequest
Definition: Protocol.h:73
@ pktScoreboardObjective
Definition: Protocol.h:106
@ pktCollectEntity
Definition: Protocol.h:66
@ pktBlockChange
Definition: Protocol.h:61
@ pktRemoveEntityEffect
Definition: Protocol.h:103
@ pktBlockBreakAnim
Definition: Protocol.h:60
@ pktTabCompletionResults
Definition: Protocol.h:119
@ pktHeldItemChange
Definition: Protocol.h:88
@ pktEntityAnimation
Definition: Protocol.h:74
@ pktWindowClose
Definition: Protocol.h:132
@ pktSpawnMob
Definition: Protocol.h:112
@ pktStartCompression
Definition: Protocol.h:116
@ pktLoginSuccess
Definition: Protocol.h:94
@ pktPlayerListHeaderFooter
Definition: Protocol.h:100
@ pktEntityLook
Definition: Protocol.h:78
@ pktDisconnectDuringGame
Definition: Protocol.h:70
@ pktTitle
Definition: Protocol.h:122
@ pktPlayerAbilities
Definition: Protocol.h:98
@ pktWeather
Definition: Protocol.h:130
@ pktExperience
Definition: Protocol.h:85
@ pktGameMode
Definition: Protocol.h:87
@ pktLeashEntity
Definition: Protocol.h:93
@ pktDisconnectDuringLogin
Definition: Protocol.h:69
@ pktBlockAction
Definition: Protocol.h:59
@ pktWindowItems
Definition: Protocol.h:131
Version
The protocol version number, received from the client in the Handshake packet.
Definition: Protocol.h:335
cByteBuffer m_OutPacketBuffer
Buffer for composing the outgoing packets, through cPacketizer.
Definition: Protocol.h:480
cClientHandle * m_Client
Definition: Protocol.h:472
virtual void SendBossBarUpdateStyle(UInt32 a_UniqueID, BossBarColor a_Color, BossBarDivisionType a_DivisionType) override
virtual void SendSoundEffect(const AString &a_SoundName, Vector3d a_Origin, float a_Volume, float a_Pitch) override
virtual void WriteEntityProperties(cPacketizer &a_Pkt, const cEntity &a_Entity) const
Writes the entity properties for the specified entity, including the Count field.
virtual void SendPlayerListRemovePlayer(const cPlayer &a_Player) override
void AddReceivedData(cByteBuffer &a_Buffer, ContiguousByteBufferView a_Data)
Adds the received (unencrypted) data to m_ReceivedData, parses complete packets.
virtual void ParseItemMetadata(cItem &a_Item, ContiguousByteBufferView a_Metadata) const
Parses item metadata as read by ReadItem(), into the item enchantments.
virtual void HandlePacketEntityAction(cByteBuffer &a_ByteBuffer)
virtual void HandlePacketPlayer(cByteBuffer &a_ByteBuffer)
virtual void SendEntityVelocity(const cEntity &a_Entity) override
virtual void SendPlayerListHeaderFooter(const cCompositeChat &a_Header, const cCompositeChat &a_Footer) override
virtual void SendUpdateBlockEntity(cBlockEntity &a_BlockEntity) override
virtual void HandlePacketUpdateSign(cByteBuffer &a_ByteBuffer)
virtual void HandlePacketStatusPing(cByteBuffer &a_ByteBuffer)
virtual void SendEntitySpawn(const cEntity &a_Entity, const UInt8 a_ObjectType, const Int32 a_ObjectData)
Sends the entity type and entity-dependent data required for the entity to initially spawn.
virtual void HandlePacketLoginEncryptionResponse(cByteBuffer &a_ByteBuffer)
virtual void DataPrepared(ContiguousByteBuffer &a_Data) override
Called by cClientHandle to finalise a buffer of prepared data before they are sent to the client.
virtual void SendGameMode(eGameMode a_GameMode) override
virtual void HandlePacketEnchantItem(cByteBuffer &a_ByteBuffer)
virtual void SendTabCompletionResults(const AStringVector &a_Results) override
virtual UInt32 GetProtocolMobType(eMonsterType a_MobType) const
Converts eMonsterType to protocol-specific mob types.
virtual void SendTimeUpdate(cTickTimeLong a_WorldAge, cTickTimeLong a_WorldDate, bool a_DoDaylightCycle) override
virtual void SendPlayerListUpdateGameMode(const cPlayer &a_Player) override
virtual void SendPlayerListAddPlayer(const cPlayer &a_Player) override
virtual void WriteEntityMetadata(cPacketizer &a_Pkt, const cEntity &a_Entity) const
Writes the metadata for the specified entity, not including the terminating 0x7f.
void StartEncryption(const Byte *a_Key)
virtual void SendRemoveEntityEffect(const cEntity &a_Entity, int a_EffectID) override
virtual void HandlePacketUseEntity(cByteBuffer &a_ByteBuffer)
virtual void SendParticleEffect(const AString &a_ParticleName, Vector3f a_Src, Vector3f a_Offset, float a_ParticleData, int a_ParticleAmount) override
virtual void SendScoreUpdate(const AString &a_Objective, const AString &a_Player, cObjective::Score a_Score, Byte a_Mode) override
virtual void SendExperienceOrb(const cExpOrb &a_ExpOrb) override
virtual unsigned char GetProtocolEntityAnimation(EntityAnimation a_Animation) const
Converts an animation into an ID suitable for use with the Entity Animation packet.
virtual void SendResourcePack(const AString &a_ResourcePackUrl) override
virtual void WriteBlockEntity(cFastNBTWriter &a_Writer, const cBlockEntity &a_BlockEntity) const
Writes the block entity data for the specified block entity into the packet.
virtual void HandlePacketClientSettings(cByteBuffer &a_ByteBuffer)
virtual void SendWholeInventory(const cWindow &a_Window) override
virtual void SendPlayerPosition(void) override
virtual void SendBlockAction(Vector3i a_BlockPos, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) override
virtual void SendSetRawSubTitle(const AString &a_SubTitle) override
virtual void HandlePacketLoginStart(cByteBuffer &a_ByteBuffer)
virtual void HandlePacketPlayerPos(cByteBuffer &a_ByteBuffer)
virtual void SendExperience(void) override
virtual void SendEntityPosition(const cEntity &a_Entity) override
virtual void SendExplosion(Vector3f a_Position, float a_Power) override
virtual void SendBossBarAdd(UInt32 a_UniqueID, const cCompositeChat &a_Title, float a_FractionFilled, BossBarColor a_Color, BossBarDivisionType a_DivisionType, bool a_DarkenSky, bool a_PlayEndMusic, bool a_CreateFog) override
virtual void SendRespawn(eDimension a_Dimension) override
virtual void SendUnlockRecipe(UInt32 a_RecipeID) override
virtual void SendScoreboardObjective(const AString &a_Name, const AString &a_DisplayName, Byte a_Mode) override
virtual void SendEntityProperties(const cEntity &a_Entity) override
virtual void HandlePacketCreativeInventoryAction(cByteBuffer &a_ByteBuffer)
virtual UInt32 GetPacketID(ePacketType a_Packet) const override
Get the packet ID for a given packet.
virtual void SendPluginMessage(const AString &a_Channel, ContiguousByteBufferView a_Message) override
virtual void SendInventorySlot(char a_WindowID, short a_SlotNum, const cItem &a_Item) override
virtual void SendSetRawTitle(const AString &a_Title) override
virtual void SendUnleashEntity(const cEntity &a_Entity) override
virtual void SendSoundParticleEffect(const EffectID a_EffectID, Vector3i a_Origin, int a_Data) override
virtual void SendInitRecipes(UInt32 a_RecipeID) override
virtual void HandlePacketWindowClose(cByteBuffer &a_ByteBuffer)
virtual void SendSetTitle(const cCompositeChat &a_Title) override
virtual void SendBlockBreakAnim(UInt32 a_EntityID, Vector3i a_BlockPos, char a_Stage) override
virtual void HandleVanillaPluginMessage(cByteBuffer &a_ByteBuffer, std::string_view a_Channel)
Parses Vanilla plugin messages into specific ClientHandle calls.
virtual void SendChat(const AString &a_Message, eChatType a_Type) override
virtual void SendBossBarUpdateHealth(UInt32 a_UniqueID, float a_FractionFilled) override
virtual void HandlePacketStatusRequest(cByteBuffer &a_ByteBuffer)
virtual void SendEntityMetadata(const cEntity &a_Entity) override
virtual void SendEntityEffect(const cEntity &a_Entity, int a_EffectID, int a_Amplifier, int a_Duration) override
virtual void HandlePacketPluginMessage(cByteBuffer &a_ByteBuffer)
cAesCfb128Decryptor m_Decryptor
Definition: Protocol_1_8.h:253
cFile m_CommLogFile
The logfile where the comm is logged, when g_ShouldLogComm is true.
Definition: Protocol_1_8.h:260
virtual void SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlockVector &a_Changes) override
virtual void HandlePacketPlayerAbilities(cByteBuffer &a_ByteBuffer)
virtual void SendUnloadChunk(int a_ChunkX, int a_ChunkZ) override
virtual void WriteMobMetadata(cPacketizer &a_Pkt, const cMonster &a_Mob) const
Writes the mob-specific metadata for the specified mob.
virtual void SendDisconnect(const AString &a_Reason) override
virtual void SendWindowClose(const cWindow &a_Window) override
virtual void SendDisplayObjective(const AString &a_Objective, cScoreboard::eDisplaySlot a_Display) override
virtual void SendDestroyEntity(const cEntity &a_Entity) override
virtual void SendPlayerPermissionLevel(void) override
virtual void SendHealth(void) override
virtual void WriteItem(cPacketizer &a_Pkt, const cItem &a_Item) const
Writes the item data into a packet.
virtual void SendSetSubTitle(const cCompositeChat &a_SubTitle) override
virtual void SendWindowProperty(const cWindow &a_Window, size_t a_Property, short a_Value) override
virtual void SendHeldItemChange(int a_ItemIndex) override
virtual void SendEntityHeadLook(const cEntity &a_Entity) override
virtual void SendPlayerListUpdatePing() override
virtual void SendLogin(const cPlayer &a_Player, const cWorld &a_World) override
virtual void SendPlayerMoveLook(void) override
cProtocol_1_8_0(cClientHandle *a_Client, const AString &a_ServerAddress, State a_State)
virtual void SendBossBarRemove(UInt32 a_UniqueID) override
virtual void SendCollectEntity(const cEntity &a_Collected, const cEntity &a_Collector, unsigned a_Count) override
virtual void SendBlockChange(Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override
virtual void SendPlayerAbilities(void) override
virtual void SendResetTitle(void) override
virtual void HandlePacketChatMessage(cByteBuffer &a_ByteBuffer)
State m_State
State of the protocol.
Definition: Protocol_1_8.h:143
virtual UInt8 GetProtocolEntityType(const cEntity &a_Entity) const
Converts an entity to a protocol-specific entity type.
virtual void HandlePacketKeepAlive(cByteBuffer &a_ByteBuffer)
virtual void SendLoginSuccess(void) override
virtual void SendBossBarUpdateTitle(UInt32 a_UniqueID, const cCompositeChat &a_Title) override
virtual void HandlePacketResourcePackStatus(cByteBuffer &a_ByteBuffer)
virtual void SendDetachEntity(const cEntity &a_Entity, const cEntity &a_PreviousVehicle) override
virtual void HandlePacketBlockPlace(cByteBuffer &a_ByteBuffer)
static const char * GetProtocolStatisticName(CustomStatistic a_Statistic)
Converts a statistic to a protocol-specific string.
virtual void SendMapData(const cMap &a_Map, int a_DataStartX, int a_DataStartY) override
virtual void SendTitleTimes(int a_FadeInTicks, int a_DisplayTicks, int a_FadeOutTicks) override
virtual int GetProtocolParticleID(const AString &a_ParticleName) const
The 1.8 protocol use a particle id instead of a string.
virtual bool ReadItem(cByteBuffer &a_ByteBuffer, cItem &a_Item, size_t a_KeepRemainingBytes=0) const
Reads an item out of the received data, sets a_Item to the values read.
virtual void HandlePacketPlayerPosLook(cByteBuffer &a_ByteBuffer)
static eBlockFace FaceIntToBlockFace(Int32 a_FaceInt)
Converts the BlockFace received by the protocol into eBlockFace constants.
virtual void HandlePacketBlockDig(cByteBuffer &a_ByteBuffer)
virtual void HandlePacketPlayerLook(cByteBuffer &a_ByteBuffer)
CircularBufferCompressor m_Compressor
Definition: Protocol_1_8.h:256
virtual void SendEntityAnimation(const cEntity &a_Entity, EntityAnimation a_Animation) override
virtual void SendKeepAlive(UInt32 a_PingID) override
virtual Version GetProtocolVersion() const override
Returns the protocol version.
virtual void SendCameraSetTo(const cEntity &a_Entity) override
virtual signed char GetProtocolEntityStatus(EntityAnimation a_Animation) const
Converts an animation into an ID suitable for use with the Entity Status packet.
virtual void HandlePacketWindowClick(cByteBuffer &a_ByteBuffer)
virtual void SendWindowOpen(const cWindow &a_Window) override
virtual void SendHideTitle(void) override
static void CompressPacket(CircularBufferCompressor &a_Packet, ContiguousByteBuffer &a_Compressed)
Compress the packet.
virtual void SendPlayerSpawn(const cPlayer &a_Player) override
cAesCfb128Encryptor m_Encryptor
Definition: Protocol_1_8.h:254
virtual void SendPlayerListUpdateDisplayName(const cPlayer &a_Player, const AString &a_CustomName) override
virtual void SendBossBarUpdateFlags(UInt32 a_UniqueID, bool a_DarkenSky, bool a_PlayEndMusic, bool a_CreateFog) override
virtual void DataReceived(cByteBuffer &a_Buffer, ContiguousByteBuffer &a_Data) override
Called by cClientHandle to process data, when the client sends some.
virtual void SendAttachEntity(const cEntity &a_Entity, const cEntity &a_Vehicle) override
virtual void SendSpawnEntity(const cEntity &a_Entity) override
virtual void HandlePacketSteerVehicle(cByteBuffer &a_ByteBuffer)
virtual void SendEntityLook(const cEntity &a_Entity) override
virtual void SendPacket(cPacketizer &a_Packet) override
Sends the packet to the client.
CircularBufferExtractor m_Extractor
Definition: Protocol_1_8.h:257
virtual void SendSpawnMob(const cMonster &a_Mob) override
virtual void SendThunderbolt(Vector3i a_BlockPos) override
virtual void HandlePacketClientStatus(cByteBuffer &a_ByteBuffer)
virtual void SendStatistics(const StatisticsManager &a_Manager) override
virtual void HandlePacketSlotSelect(cByteBuffer &a_ByteBuffer)
virtual void SendChatRaw(const AString &a_MessageRaw, eChatType a_Type) override
virtual void SendEditSign(Vector3i a_BlockPos) override
Request the client to open up the sign editor for the sign (1.6+)
virtual void HandlePacketAnimation(cByteBuffer &a_ByteBuffer)
virtual bool HandlePacket(cByteBuffer &a_ByteBuffer, UInt32 a_PacketType)
Reads and handles the packet.
virtual void SendWeather(eWeather a_Weather) override
AString m_ServerAddress
Definition: Protocol_1_8.h:247
virtual void SendLeashEntity(const cEntity &a_Entity, const cEntity &a_EntityLeashedTo) override
virtual void SendPaintingSpawn(const cPainting &a_Painting) override
virtual void SendUpdateSign(Vector3i a_BlockPos, const AString &a_Line1, const AString &a_Line2, const AString &a_Line3, const AString &a_Line4) override
AString m_AuthServerID
Definition: Protocol_1_8.h:249
virtual void HandlePacketTabComplete(cByteBuffer &a_ByteBuffer)
virtual void SendEntityEquipment(const cEntity &a_Entity, short a_SlotNum, const cItem &a_Item) override
virtual void HandlePacketSpectate(cByteBuffer &a_ByteBuffer)
virtual void SendChunkData(ContiguousByteBufferView a_ChunkData) override
static AString GetVersionTextFromInt(cProtocol::Version a_ProtocolVersion)
Translates protocol version number into protocol version text: 49 -> "1.4.4".
cServer * GetServer(void)
Definition: Root.h:71
static cRoot * Get()
Definition: Root.h:52
cPluginManager * GetPluginManager(void)
Definition: Root.h:111
Definition: Server.h:56
ContiguousByteBufferView GetPublicKeyDER(void) const
Definition: Server.h:144
size_t GetMaxPlayers(void) const
Definition: Server.h:70
const AString & GetDescription(void) const
Definition: Server.h:65
const AString & GetServerID(void) const
Definition: Server.h:129
size_t GetNumPlayers(void) const
Definition: Server.h:71
cRsaPrivateKey & GetPrivateKey(void)
Definition: Server.h:143
bool IsHardcore(void) const
Definition: Server.h:93
const AString & GetFaviconData(void) const
Returns base64 encoded favicon data (obtained from favicon.png)
Definition: Server.h:141
Class that manages the statistics and achievements of a single player.
std::unordered_map< CustomStatistic, StatValue > Custom
ContiguousByteBufferView GetView() const
Returns a view (of type std::byte) of the internal store.
Represents a UI window.
Definition: Window.h:54
@ wtWorkbench
Definition: Window.h:60
@ wtAnvil
Definition: Window.h:67
@ wtAnimalChest
Definition: Window.h:70
@ wtEnchantment
Definition: Window.h:63
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:171
int GetNumNonInventorySlots(void) const
Returns the number of slots, excluding the player's inventory (used for network protocols)
Definition: Window.h:93
int GetNumSlots(void) const
Returns the total number of slots.
Definition: Window.cpp:90
char GetWindowID(void) const
Definition: Window.h:80
const AString & GetWindowTitle() const
Definition: Window.h:140
int GetWindowType(void) const
Definition: Window.h:81
const AString GetWindowTypeName(void) const
Returns the textual representation of the window's type, such as "minecraft:chest".
Definition: Window.cpp:62
Definition: UUID.h:11
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
AString ToLongString() const
Converts the UUID to a long form string (i.e.
Definition: UUID.cpp:151
T x
Definition: Vector3.h:17
T y
Definition: Vector3.h:17
T z
Definition: Vector3.h:17
Definition: World.h:53
int GetSpawnX(void) const
Definition: World.h:585
int GetSpawnZ(void) const
Definition: World.h:587
virtual eDimension GetDimension(void) const override
Definition: World.h:133
int GetSpawnY(void) const
Definition: World.h:586
Parses and contains the parsed data Also implements data accessor functions for tree traversal and va...
Definition: FastNBT.h:153
int GetNextSibling(int a_Tag) const
Returns the next sibling of the specified tag, or -1 if none.
Definition: FastNBT.h:175
size_t GetErrorPos() const
Returns the position where an error occurred while parsing.
Definition: FastNBT.h:163
std::error_code GetErrorCode() const
Returns the error code for the parsing of the NBT data.
Definition: FastNBT.h:160
int GetFirstChild(int a_Tag) const
Returns the first child of the specified tag, or -1 if none / not applicable.
Definition: FastNBT.h:169
bool IsValid(void) const
Definition: FastNBT.h:157
AString GetName(int a_Tag) const
Returns the tag's name.
Definition: FastNBT.h:293
eTagType GetType(int a_Tag) const
Definition: FastNBT.h:210
int GetRoot(void) const
Returns the root tag of the hierarchy.
Definition: FastNBT.h:166
Int32 GetInt(int a_Tag) const
Returns the value stored in an Int tag.
Definition: FastNBT.h:234
AString GetString(int a_Tag) const
Returns the value stored in a String tag.
Definition: FastNBT.h:280
void AddByte(const AString &a_Name, unsigned char a_Value)
Definition: FastNBT.cpp:551
void AddShort(const AString &a_Name, Int16 a_Value)
Definition: FastNBT.cpp:561
void AddInt(const AString &a_Name, Int32 a_Value)
Definition: FastNBT.cpp:572
void Finish(void)
Definition: FastNBT.cpp:674
void AddString(const AString &a_Name, std::string_view a_Value)
Definition: FastNBT.cpp:616
void EndList(void)
Definition: FastNBT.cpp:536
void BeginList(const AString &a_Name, eTagType a_ChildrenType)
Definition: FastNBT.cpp:512
void EndCompound(void)
Definition: FastNBT.cpp:499
void BeginCompound(const AString &a_Name)
Definition: FastNBT.cpp:481
ContiguousByteBufferView GetResult(void) const
Definition: FastNBT.h:351
static void WriteToNBTCompound(const cFireworkItem &a_FireworkItem, cFastNBTWriter &a_Writer, const ENUM_ITEM_TYPE a_Type)
Writes firework NBT data to a Writer object.
static void ParseFromNBT(cFireworkItem &a_FireworkItem, const cParsedNBT &a_NBT, int a_TagIdx, const ENUM_ITEM_TYPE a_Type)
Reads NBT data from a NBT object and populates a FireworkItem with it.