Cuberite
A lightweight, fast and extensible game server for Minecraft
Protocol_1_12.cpp
Go to the documentation of this file.
1 
2 // Protocol_1_12.cpp
3 
4 /*
5 Implements the 1.12 protocol classes:
6 - release 1.12 protocol (#335)
7 */
8 
9 #include "Globals.h"
10 #include "Protocol_1_12.h"
11 #include "ProtocolRecognizer.h"
12 #include "Packetizer.h"
13 
14 #include "../Entities/Boat.h"
15 #include "../Entities/Minecart.h"
16 #include "../Entities/Pickup.h"
17 #include "../Entities/Player.h"
18 #include "../Entities/ItemFrame.h"
19 #include "../Entities/ArrowEntity.h"
20 #include "../Entities/FireworkEntity.h"
21 #include "../Entities/SplashPotionEntity.h"
22 
23 #include "../Mobs/IncludeAllMonsters.h"
24 
25 #include "../Root.h"
26 #include "../Server.h"
27 #include "../ClientHandle.h"
28 #include "../Bindings/PluginManager.h"
29 
30 
31 
32 
33 
34 // The disabled error is intended, since the Metadata have overlapping indexes
35 // based on the type of the Entity.
36 //
37 // IMPORTANT: The enum is used to automate the sequential counting of the
38 // Metadata indexes. Adding a new enum value causes the following values to
39 // increase their index. Therefore the ordering of the enum values is VERY important!
40 #ifdef __clang__
41 #pragma clang diagnostic push
42 #pragma clang diagnostic ignored "-Wduplicate-enum"
43 #endif
44 
45 namespace Metadata
46 {
48  {
49  // Entity
51  ENTITY_AIR,
56  _ENTITY_NEXT, // Used by descendants
57 
58  // Potion
59  POTION_THROWN = _ENTITY_NEXT,
60 
61  // FallingBlock
62  FALLING_BLOCK_POSITION = _ENTITY_NEXT,
63 
64  // AreaEffectCloud
65  AREA_EFFECT_CLOUD_RADIUS = _ENTITY_NEXT,
71 
72  // Arrow
73  ARROW_CRITICAL = _ENTITY_NEXT,
74  _ARROW_NEXT,
75 
76  // TippedArrow
77  TIPPED_ARROW_COLOR = _ARROW_NEXT,
78 
79  // Boat
80  BOAT_LAST_HIT_TIME = _ENTITY_NEXT,
83  BOAT_TYPE,
86 
87  // EnderCrystal
88  ENDER_CRYSTAL_BEAM_TARGET = _ENTITY_NEXT,
90 
91  // Fireball
92  _FIREBALL_NEXT = _ENTITY_NEXT,
93 
94  // WitherSkull
95  WITHER_SKULL_INVULNERABLE = _FIREBALL_NEXT,
96 
97  // Fireworks
98  FIREWORK_INFO = _ENTITY_NEXT,
99  FIREWORK_BOOSTED_ENTITY_ID, // 1.11.1 only
100 
101  // Hanging
102  _HANGING_NEXT = _ENTITY_NEXT,
103 
104  // ItemFrame
105  ITEM_FRAME_ITEM = _HANGING_NEXT,
107 
108  // Item
109  ITEM_ITEM = _ENTITY_NEXT,
110 
111  // Living
112  LIVING_ACTIVE_HAND = _ENTITY_NEXT,
117  _LIVING_NEXT,
118 
119  // Player
120  PLAYER_ADDITIONAL_HEARTHS = _LIVING_NEXT,
121  PLAYER_SCORE,
124 
125  // ArmorStand
126  ARMOR_STAND_STATUS = _LIVING_NEXT,
133 
134  // Insentient
135  INSENTIENT_STATUS = _LIVING_NEXT,
136  _INSENTIENT_NEXT,
137 
138  // Ambient
139  _AMBIENT_NEXT = _INSENTIENT_NEXT,
140 
141  // Bat
142  BAT_HANGING = _AMBIENT_NEXT,
143 
144  // Creature
145  _CREATURE_NEXT = _INSENTIENT_NEXT,
146 
147  // Ageable
148  AGEABLE_BABY = _CREATURE_NEXT,
149  _AGEABLE_NEXT,
150 
151  // PolarBear
152  POLAR_BEAR_STANDING = _AGEABLE_NEXT,
153 
154  // Animal
155  _ANIMAL_NEXT = _AGEABLE_NEXT,
156 
157  // Abstract horse
158  ABSTRACT_HORSE_STATUS = _ANIMAL_NEXT,
160  _ABSTRACT_HORSE_NEXT,
161 
162  // Horse
163  HORSE_VARIANT = _ABSTRACT_HORSE_NEXT,
164  HORSE_ARMOR,
165 
166  // Chested horse
167  CHESTED_HORSE_CHESTED = _ABSTRACT_HORSE_NEXT,
168  _CHESTED_HORSE_NEXT,
169 
170  // Llama
171  LLAMA_STRENGTH = _CHESTED_HORSE_NEXT,
174 
175  // Pig
176  PIG_HAS_SADDLE = _ANIMAL_NEXT,
177  PIG_TOTAL_CARROT_ON_A_STICK_BOOST, // 1.11.1 only
178 
179  // Rabbit
180  RABBIT_TYPE = _ANIMAL_NEXT,
181 
182  // Sheep
183  SHEEP_STATUS = _ANIMAL_NEXT,
184 
185  // TameableAnimal
186  TAMEABLE_ANIMAL_STATUS = _ANIMAL_NEXT,
188  _TAMEABLE_NEXT,
189 
190  // Ocelot
191  OCELOT_TYPE = _TAMEABLE_NEXT,
192 
193  // Wolf
194  WOLF_DAMAGE_TAKEN = _TAMEABLE_NEXT,
195  WOLF_BEGGING,
197 
198  // Villager
199  VILLAGER_PROFESSION = _AGEABLE_NEXT,
200 
201  // Golem
202  _GOLEM_NEXT = _CREATURE_NEXT,
203 
204  // IronGolem
205  IRON_GOLEM_PLAYER_CREATED = _GOLEM_NEXT,
206 
207  // Shulker
208  SHULKER_FACING_DIRECTION = _GOLEM_NEXT,
211 
212  // Monster
213  _MONSTER_NEXT = _CREATURE_NEXT,
214 
215  // Blaze
216  BLAZE_ON_FIRE = _MONSTER_NEXT,
217 
218  // Creeper
219  CREEPER_STATE = _MONSTER_NEXT,
222 
223  // Guardian
224  GUARDIAN_STATUS = _MONSTER_NEXT,
226 
227  // Abstract Skeleton
228  ABSTRACT_SKELETON_ARMS_SWINGING = _MONSTER_NEXT,
229 
230  // Spider
231  SPIDER_CLIMBING = _MONSTER_NEXT,
232 
233  // Witch
234  WITCH_AGGRESIVE = _MONSTER_NEXT,
235 
236  // Wither
237  WITHER_FIRST_HEAD_TARGET = _MONSTER_NEXT,
241 
242  // Zombie
243  ZOMBIE_IS_BABY = _MONSTER_NEXT,
244  ZOMBIE_UNUSED, // Was type
246  _ZOMBIE_NEXT,
247 
248  // Zombie villager
249  ZOMBIE_VILLAGER_CONVERTING = _ZOMBIE_NEXT,
251 
252  // Enderman
253  ENDERMAN_CARRIED_BLOCK = _MONSTER_NEXT,
255 
256  // Evocation illager
257  EVOKER_SPELL = _MONSTER_NEXT,
258 
259  // Vex
260  VEX_FLAGS = _MONSTER_NEXT,
261 
262  // Vindication illager
263  VINDICATOR_FLAGS = _MONSTER_NEXT,
264 
265  // EnderDragon
266  ENDER_DRAGON_DRAGON_PHASE = _INSENTIENT_NEXT,
267 
268  // Flying
269  _FLYING_NEXT = _INSENTIENT_NEXT,
270 
271  // Ghast
272  GHAST_ATTACKING = _FLYING_NEXT,
273 
274  // Slime
275  SLIME_SIZE = _INSENTIENT_NEXT,
276 
277  // Minecart
278  MINECART_SHAKING_POWER = _ENTITY_NEXT,
284  _MINECART_NEXT,
285 
286  // MinecartCommandBlock
287  MINECART_COMMAND_BLOCK_COMMAND = _MINECART_NEXT,
289 
290  // MinecartFurnace
291  MINECART_FURNACE_POWERED = _MINECART_NEXT,
292 
293  // TNTPrimed
294  TNT_PRIMED_FUSE_TIME = _ENTITY_NEXT,
295  };
296 }
297 
298 #ifdef __clang__
299 #pragma clang diagnostic pop // Restore ignored clang errors
300 #endif
301 
302 
303 
304 
305 
306 #define HANDLE_READ(ByteBuf, Proc, Type, Var) \
307  Type Var; \
308  do { \
309  if (!ByteBuf.Proc(Var))\
310  {\
311  return;\
312  } \
313  } while (false)
314 
315 
316 
317 
318 
319 cProtocol_1_12::cProtocol_1_12(cClientHandle * a_Client, const AString & a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State) :
320  Super(a_Client, a_ServerAddress, a_ServerPort, a_State)
321 {
322 }
323 
324 
325 
326 
327 
329 {
330  ASSERT(m_State == 3); // In game mode?
331 
332  cPacketizer Pkt(*this, pktSpawnMob);
333  Pkt.WriteVarInt32(a_Mob.GetUniqueID());
334  // TODO: Bad way to write a UUID, and it's not a true UUID, but this is functional for now.
335  Pkt.WriteBEUInt64(0);
336  Pkt.WriteBEUInt64(a_Mob.GetUniqueID());
337  Pkt.WriteVarInt32(static_cast<UInt32>(a_Mob.GetMobType()));
338  Pkt.WriteBEDouble(a_Mob.GetPosX());
339  Pkt.WriteBEDouble(a_Mob.GetPosY());
340  Pkt.WriteBEDouble(a_Mob.GetPosZ());
341  Pkt.WriteByteAngle(a_Mob.GetPitch());
342  Pkt.WriteByteAngle(a_Mob.GetHeadYaw());
343  Pkt.WriteByteAngle(a_Mob.GetYaw());
344  Pkt.WriteBEInt16(static_cast<Int16>(a_Mob.GetSpeedX() * 400));
345  Pkt.WriteBEInt16(static_cast<Int16>(a_Mob.GetSpeedY() * 400));
346  Pkt.WriteBEInt16(static_cast<Int16>(a_Mob.GetSpeedZ() * 400));
347  WriteEntityMetadata(Pkt, a_Mob);
348  Pkt.WriteBEUInt8(0xff); // Metadata terminator
349 }
350 
351 
352 
353 
354 
356 {
357  int BlockX, BlockY, BlockZ;
358  if (!a_ByteBuffer.ReadPosition64(BlockX, BlockY, BlockZ))
359  {
360  return;
361  }
362 
363  HANDLE_READ(a_ByteBuffer, ReadVarInt, Int32, Face);
364  HANDLE_READ(a_ByteBuffer, ReadVarInt, Int32, Hand);
365  HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, CursorX);
366  HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, CursorY);
367  HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, CursorZ);
368  m_Client->HandleRightClick(BlockX, BlockY, BlockZ, FaceIntToBlockFace(Face), FloorC(CursorX * 16), FloorC(CursorY * 16), FloorC(CursorZ * 16), HandIntToEnum(Hand));
369 }
370 
371 
372 
373 
374 
376 {
377  cServer * Server = cRoot::Get()->GetServer();
378  AString ServerDescription = Server->GetDescription();
379  auto NumPlayers = static_cast<signed>(Server->GetNumPlayers());
380  auto MaxPlayers = static_cast<signed>(Server->GetMaxPlayers());
381  AString Favicon = Server->GetFaviconData();
382  cRoot::Get()->GetPluginManager()->CallHookServerPing(*m_Client, ServerDescription, NumPlayers, MaxPlayers, Favicon);
383 
384  // Version:
385  Json::Value Version;
386  Version["name"] = "Cuberite 1.12";
387  Version["protocol"] = cProtocolRecognizer::PROTO_VERSION_1_12;
388 
389  // Players:
390  Json::Value Players;
391  Players["online"] = NumPlayers;
392  Players["max"] = MaxPlayers;
393  // TODO: Add "sample"
394 
395  // Description:
396  Json::Value Description;
397  Description["text"] = ServerDescription.c_str();
398 
399  // Create the response:
400  Json::Value ResponseValue;
401  ResponseValue["version"] = Version;
402  ResponseValue["players"] = Players;
403  ResponseValue["description"] = Description;
404  m_Client->ForgeAugmentServerListPing(ResponseValue);
405  if (!Favicon.empty())
406  {
407  ResponseValue["favicon"] = Printf("data:image/png;base64,%s", Favicon.c_str());
408  }
409 
410  // Serialize the response into a packet:
411  Json::FastWriter Writer;
412  cPacketizer Pkt(*this, pktStatusResponse);
413  Pkt.WriteString(Writer.write(ResponseValue));
414 }
415 
416 
417 
418 
419 
421 {
422  using namespace Metadata;
423 
424  // Common metadata:
425  Int8 Flags = 0;
426  if (a_Entity.IsOnFire())
427  {
428  Flags |= 0x01;
429  }
430  if (a_Entity.IsCrouched())
431  {
432  Flags |= 0x02;
433  }
434  if (a_Entity.IsSprinting())
435  {
436  Flags |= 0x08;
437  }
438  if (a_Entity.IsRclking())
439  {
440  Flags |= 0x10;
441  }
442  if (a_Entity.IsInvisible())
443  {
444  Flags |= 0x20;
445  }
446  a_Pkt.WriteBEUInt8(ENTITY_FLAGS); // Index
447  a_Pkt.WriteBEUInt8(METADATA_TYPE_BYTE); // Type
448  a_Pkt.WriteBEInt8(Flags);
449 
450  switch (a_Entity.GetEntityType())
451  {
452  case cEntity::etPlayer:
453  {
454  auto & Player = static_cast<const cPlayer &>(a_Entity);
455 
456  // TODO Set player custom name to their name.
457  // Then it's possible to move the custom name of mobs to the entities
458  // and to remove the "special" player custom name.
461  a_Pkt.WriteString(Player.GetName());
462 
465  a_Pkt.WriteBEFloat(static_cast<float>(Player.GetHealth()));
466 
469  a_Pkt.WriteBEUInt8(static_cast<UInt8>(Player.GetSkinParts()));
470 
473  a_Pkt.WriteBEUInt8(static_cast<UInt8>(Player.GetMainHand()));
474  break;
475  }
476  case cEntity::etPickup:
477  {
478  a_Pkt.WriteBEUInt8(ITEM_ITEM);
480  WriteItem(a_Pkt, static_cast<const cPickup &>(a_Entity).GetItem());
481  break;
482  }
483  case cEntity::etMinecart:
484  {
487 
488  // The following expression makes Minecarts shake more with less health or higher damage taken
489  auto & Minecart = static_cast<const cMinecart &>(a_Entity);
490  auto maxHealth = a_Entity.GetMaxHealth();
491  auto curHealth = a_Entity.GetHealth();
492  a_Pkt.WriteVarInt32(static_cast<UInt32>((maxHealth - curHealth) * Minecart.LastDamage() * 4));
493 
494  a_Pkt.WriteBEUInt8(MINECART_SHAKING_DIRECTION); // (doesn't seem to effect anything)
496  a_Pkt.WriteVarInt32(1);
497 
498  a_Pkt.WriteBEUInt8(MINECART_SHAKING_MULTIPLIER); // or damage taken
500  a_Pkt.WriteBEFloat(static_cast<float>(Minecart.LastDamage() + 10));
501 
502  if (Minecart.GetPayload() == cMinecart::mpNone)
503  {
504  auto & RideableMinecart = static_cast<const cRideableMinecart &>(Minecart);
505  const cItem & MinecartContent = RideableMinecart.GetContent();
506  if (!MinecartContent.IsEmpty())
507  {
510  int Content = MinecartContent.m_ItemType;
511  Content |= MinecartContent.m_ItemDamage << 8;
512  a_Pkt.WriteVarInt32(static_cast<UInt32>(Content));
513 
516  a_Pkt.WriteVarInt32(static_cast<UInt32>(RideableMinecart.GetBlockHeight()));
517 
520  a_Pkt.WriteBool(true);
521  }
522  }
523  else if (Minecart.GetPayload() == cMinecart::mpFurnace)
524  {
527  a_Pkt.WriteBool(static_cast<const cMinecartWithFurnace &>(Minecart).IsFueled());
528  }
529  break;
530  } // case etMinecart
531 
533  {
534  auto & Projectile = static_cast<const cProjectileEntity &>(a_Entity);
535  switch (Projectile.GetProjectileKind())
536  {
538  {
541  a_Pkt.WriteBEInt8(static_cast<const cArrowEntity &>(Projectile).IsCritical() ? 1 : 0);
542  break;
543  }
545  {
546  a_Pkt.WriteBEUInt8(FIREWORK_INFO); // Firework item used for this firework
548  WriteItem(a_Pkt, static_cast<const cFireworkEntity &>(Projectile).GetItem());
549 
550  // FIREWORK_BOOSTED_ENTITY_ID, in 1.11.1 only
551  break;
552  }
554  {
555  a_Pkt.WriteBEUInt8(POTION_THROWN); // Potion item which was thrown
557  WriteItem(a_Pkt, static_cast<const cSplashPotionEntity &>(Projectile).GetItem());
558  }
559  default:
560  {
561  break;
562  }
563  }
564  break;
565  } // case etProjectile
566 
567  case cEntity::etMonster:
568  {
569  WriteMobMetadata(a_Pkt, static_cast<const cMonster &>(a_Entity));
570  break;
571  }
572 
573  case cEntity::etBoat:
574  {
575  auto & Boat = static_cast<const cBoat &>(a_Entity);
576 
579  a_Pkt.WriteVarInt32(static_cast<UInt32>(Boat.GetLastDamage()));
580 
583  a_Pkt.WriteVarInt32(static_cast<UInt32>(Boat.GetForwardDirection()));
584 
587  a_Pkt.WriteBEFloat(Boat.GetDamageTaken());
588 
589  a_Pkt.WriteBEInt8(BOAT_TYPE);
591  a_Pkt.WriteVarInt32(static_cast<UInt32>(Boat.GetMaterial()));
592 
595  a_Pkt.WriteBool(Boat.IsRightPaddleUsed());
596 
599  a_Pkt.WriteBool(Boat.IsLeftPaddleUsed());
600 
601  break;
602  } // case etBoat
603 
605  {
606  auto & Frame = static_cast<const cItemFrame &>(a_Entity);
609  WriteItem(a_Pkt, Frame.GetItem());
612  a_Pkt.WriteVarInt32(Frame.GetItemRotation());
613  break;
614  } // case etItemFrame
615 
616  default:
617  {
618  break;
619  }
620  }
621 }
622 
623 
624 
625 
626 
628 {
629  using namespace Metadata;
630 
631  // Living Enitiy Metadata
632  if (a_Mob.HasCustomName())
633  {
634  // TODO: As of 1.9 _all_ entities can have custom names; should this be moved up?
637  a_Pkt.WriteString(a_Mob.GetCustomName());
638 
639  a_Pkt.WriteBEUInt8(ENTITY_CUSTOM_NAME_VISIBLE); // Custom name always visible
641  a_Pkt.WriteBool(a_Mob.IsCustomNameAlwaysVisible());
642  }
643 
646  a_Pkt.WriteBEFloat(static_cast<float>(a_Mob.GetHealth()));
647 
648  switch (a_Mob.GetMobType())
649  {
650  case mtBat:
651  {
652  auto & Bat = static_cast<const cBat &>(a_Mob);
653  a_Pkt.WriteBEUInt8(BAT_HANGING);
655  a_Pkt.WriteBEInt8(Bat.IsHanging() ? 1 : 0);
656  break;
657  } // case mtBat
658 
659  case mtChicken:
660  {
661  auto & Chicken = static_cast<const cChicken &>(a_Mob);
662 
663  a_Pkt.WriteBEUInt8(AGEABLE_BABY);
665  a_Pkt.WriteBool(Chicken.IsBaby());
666  break;
667  } // case mtChicken
668 
669  case mtCow:
670  {
671  auto & Cow = static_cast<const cCow &>(a_Mob);
672 
673  a_Pkt.WriteBEUInt8(AGEABLE_BABY);
675  a_Pkt.WriteBool(Cow.IsBaby());
676  break;
677  } // case mtCow
678 
679  case mtCreeper:
680  {
681  auto & Creeper = static_cast<const cCreeper &>(a_Mob);
682  a_Pkt.WriteBEUInt8(CREEPER_STATE); // (idle or "blowing")
684  a_Pkt.WriteVarInt32(Creeper.IsBlowing() ? 1 : static_cast<UInt32>(-1));
685 
688  a_Pkt.WriteBool(Creeper.IsCharged());
689 
692  a_Pkt.WriteBool(Creeper.IsBurnedWithFlintAndSteel());
693  break;
694  } // case mtCreeper
695 
696  case mtEnderman:
697  {
698  auto & Enderman = static_cast<const cEnderman &>(a_Mob);
701  UInt32 Carried = 0;
702  Carried |= static_cast<UInt32>(Enderman.GetCarriedBlock() << 4);
703  Carried |= Enderman.GetCarriedMeta();
704  a_Pkt.WriteVarInt32(Carried);
705 
708  a_Pkt.WriteBool(Enderman.IsScreaming());
709  break;
710  } // case mtEnderman
711 
712  case mtGhast:
713  {
714  auto & Ghast = static_cast<const cGhast &>(a_Mob);
717  a_Pkt.WriteBool(Ghast.IsCharging());
718  break;
719  } // case mtGhast
720 
721  case mtHorse:
722  {
723  // XXX This behaves incorrectly with different varients; horses have different entity IDs now
724 
725  // Abstract horse
726  auto & Horse = static_cast<const cHorse &>(a_Mob);
727  Int8 Flags = 0;
728  if (Horse.IsTame())
729  {
730  Flags |= 0x02;
731  }
732  if (Horse.IsSaddled())
733  {
734  Flags |= 0x04;
735  }
736  if (Horse.IsChested())
737  {
738  Flags |= 0x08;
739  }
740  if (Horse.IsEating())
741  {
742  Flags |= 0x20;
743  }
744  if (Horse.IsRearing())
745  {
746  Flags |= 0x40;
747  }
748  if (Horse.IsMthOpen())
749  {
750  Flags |= 0x80;
751  }
754  a_Pkt.WriteBEInt8(Flags);
755 
756  // This doesn't exist any more; it'll cause horses to all be the normal type
757  // a_Pkt.WriteBEUInt8(HORSE_TYPE);
758  // a_Pkt.WriteBEUInt8(METADATA_TYPE_VARINT);
759  // a_Pkt.WriteVarInt32(static_cast<UInt32>(Horse.GetHorseType()));
760 
761  // Regular horses
762  a_Pkt.WriteBEUInt8(HORSE_VARIANT); // Color / style
764  int Appearance = 0;
765  Appearance = Horse.GetHorseColor();
766  Appearance |= Horse.GetHorseStyle() << 8;
767  a_Pkt.WriteVarInt32(static_cast<UInt32>(Appearance));
768 
769  a_Pkt.WriteBEUInt8(HORSE_ARMOR);
771  a_Pkt.WriteVarInt32(static_cast<UInt32>(Horse.GetHorseArmour()));
772 
773  a_Pkt.WriteBEUInt8(AGEABLE_BABY);
775  a_Pkt.WriteBool(Horse.IsBaby());
776  break;
777  } // case mtHorse
778 
779  case mtMagmaCube:
780  {
781  auto & MagmaCube = static_cast<const cMagmaCube &>(a_Mob);
782  a_Pkt.WriteBEUInt8(SLIME_SIZE);
784  a_Pkt.WriteVarInt32(static_cast<UInt32>(MagmaCube.GetSize()));
785  break;
786  } // case mtMagmaCube
787 
788  case mtOcelot:
789  {
790  auto & Ocelot = static_cast<const cOcelot &>(a_Mob);
791 
792  a_Pkt.WriteBEUInt8(AGEABLE_BABY);
794  a_Pkt.WriteBool(Ocelot.IsBaby());
795 
796  Int8 OcelotStatus = 0;
797  if (Ocelot.IsSitting())
798  {
799  OcelotStatus |= 0x1;
800  }
801  if (Ocelot.IsTame())
802  {
803  OcelotStatus |= 0x4;
804  }
807  a_Pkt.WriteBEInt8(OcelotStatus);
808 
809  a_Pkt.WriteBEUInt8(OCELOT_TYPE);
811  a_Pkt.WriteVarInt32(static_cast<UInt32>(Ocelot.GetOcelotType()));
812 
813  break;
814  } // case mtOcelot
815 
816  case mtPig:
817  {
818  auto & Pig = static_cast<const cPig &>(a_Mob);
819 
820  a_Pkt.WriteBEUInt8(AGEABLE_BABY);
822  a_Pkt.WriteBool(Pig.IsBaby());
823 
826  a_Pkt.WriteBool(Pig.IsSaddled());
827 
828  // PIG_TOTAL_CARROT_ON_A_STICK_BOOST in 1.11.1 only
829  break;
830  } // case mtPig
831 
832  case mtRabbit:
833  {
834  auto & Rabbit = static_cast<const cRabbit &>(a_Mob);
835  a_Pkt.WriteBEUInt8(AGEABLE_BABY);
837  a_Pkt.WriteBool(Rabbit.IsBaby());
838 
839  a_Pkt.WriteBEUInt8(RABBIT_TYPE);
841  a_Pkt.WriteVarInt32(static_cast<UInt32>(Rabbit.GetRabbitType()));
842  break;
843  } // case mtRabbit
844 
845  case mtSheep:
846  {
847  auto & Sheep = static_cast<const cSheep &>(a_Mob);
848 
849  a_Pkt.WriteBEUInt8(AGEABLE_BABY);
851  a_Pkt.WriteBool(Sheep.IsBaby());
852 
853  a_Pkt.WriteBEUInt8(SHEEP_STATUS);
855  Int8 SheepMetadata = 0;
856  SheepMetadata = static_cast<Int8>(Sheep.GetFurColor());
857  if (Sheep.IsSheared())
858  {
859  SheepMetadata |= 0x10;
860  }
861  a_Pkt.WriteBEInt8(SheepMetadata);
862  break;
863  } // case mtSheep
864 
865  case mtSkeleton:
866  {
867  // XXX Skeletons are separate entities; all skeletons are currently treated as regular ones
868 
869  // auto & Skeleton = static_cast<const cSkeleton &>(a_Mob);
870  // a_Pkt.WriteBEUInt8(SKELETON_TYPE);
871  // a_Pkt.WriteBEUInt8(METADATA_TYPE_VARINT);
872  // a_Pkt.WriteVarInt32(Skeleton.IsWither() ? 1 : 0);
873  break;
874  } // case mtSkeleton
875 
876  case mtSlime:
877  {
878  auto & Slime = static_cast<const cSlime &>(a_Mob);
879  a_Pkt.WriteBEUInt8(SLIME_SIZE);
881  a_Pkt.WriteVarInt32(static_cast<UInt32>(Slime.GetSize()));
882  break;
883  } // case mtSlime
884 
885  case mtVillager:
886  {
887  auto & Villager = static_cast<const cVillager &>(a_Mob);
888  a_Pkt.WriteBEUInt8(AGEABLE_BABY);
890  a_Pkt.WriteBool(Villager.IsBaby());
891 
894  a_Pkt.WriteVarInt32(static_cast<UInt32>(Villager.GetVilType()));
895  break;
896  } // case mtVillager
897 
898  case mtWitch:
899  {
900  auto & Witch = static_cast<const cWitch &>(a_Mob);
903  a_Pkt.WriteBool(Witch.IsAngry());
904  break;
905  } // case mtWitch
906 
907  case mtWither:
908  {
909  auto & Wither = static_cast<const cWither &>(a_Mob);
912  a_Pkt.WriteVarInt32(Wither.GetWitherInvulnerableTicks());
913 
914  // TODO: Use boss bar packet for health
915  break;
916  } // case mtWither
917 
918  case mtWolf:
919  {
920  auto & Wolf = static_cast<const cWolf &>(a_Mob);
921  a_Pkt.WriteBEUInt8(AGEABLE_BABY);
923  a_Pkt.WriteBool(Wolf.IsBaby());
924 
925  Int8 WolfStatus = 0;
926  if (Wolf.IsSitting())
927  {
928  WolfStatus |= 0x1;
929  }
930  if (Wolf.IsAngry())
931  {
932  WolfStatus |= 0x2;
933  }
934  if (Wolf.IsTame())
935  {
936  WolfStatus |= 0x4;
937  }
940  a_Pkt.WriteBEInt8(WolfStatus);
941 
944  a_Pkt.WriteBEFloat(static_cast<float>(a_Mob.GetHealth())); // TODO Not use the current health
945 
946  a_Pkt.WriteBEUInt8(WOLF_BEGGING);
948  a_Pkt.WriteBool(Wolf.IsBegging());
949 
952  a_Pkt.WriteVarInt32(static_cast<UInt32>(Wolf.GetCollarColor()));
953  break;
954  } // case mtWolf
955 
956  case mtZombie:
957  {
958  // XXX Zombies were also split into new sublcasses; this doesn't handle that.
959  auto & Zombie = static_cast<const cZombie &>(a_Mob);
962  a_Pkt.WriteBool(Zombie.IsBaby());
963 
964  // These don't exist
965  // a_Pkt.WriteBEUInt8(ZOMBIE_TYPE);
966  // a_Pkt.WriteBEUInt8(METADATA_TYPE_VARINT);
967  // a_Pkt.WriteVarInt32(Zombie.IsVillagerZombie() ? 1 : 0);
968 
969  // a_Pkt.WriteBEUInt8(ZOMBIE_CONVERTING);
970  // a_Pkt.WriteBEUInt8(METADATA_TYPE_BOOL);
971  // a_Pkt.WriteBool(Zombie.IsConverting());
972  break;
973  } // case mtZombie
974 
975  case mtZombiePigman:
976  {
977  auto & ZombiePigman = static_cast<const cZombiePigman &>(a_Mob);
978  a_Pkt.WriteBEUInt8(AGEABLE_BABY);
980  a_Pkt.WriteBool(ZombiePigman.IsBaby());
981  break;
982  } // case mtZombiePigman
983 
984  case mtBlaze:
985  case mtEnderDragon:
986  case mtGuardian:
987  case mtIronGolem:
988  case mtSnowGolem:
989  case mtSpider:
990  {
991  // TODO: Mobs with extra fields that aren't implemented
992  break;
993  }
994 
995  case mtMooshroom:
996  case mtCaveSpider:
997  {
998  // Not mentioned on http://wiki.vg/Entities
999  break;
1000  }
1001 
1002  case mtGiant:
1003  case mtSilverfish:
1004  case mtSquid:
1005  {
1006  // Mobs with no extra fields
1007  break;
1008  }
1009 
1010  case mtInvalidType:
1011  {
1012  ASSERT(!"cProtocol_1_12::WriteMobMetadata: Recieved mob of invalid type");
1013  break;
1014  }
1015  } // switch (a_Mob.GetType())
1016 }
1017 
1018 
1019 
1020 
1021 
1023 {
1024  switch (a_Packet)
1025  {
1026  case pktAttachEntity: return 0x42;
1027  case pktCameraSetTo: return 0x38;
1028  case pktCollectEntity: return 0x4a;
1029  case pktDestroyEntity: return 0x31;
1030  case pktDisplayObjective: return 0x3a;
1031  case pktEntityEffect: return 0x4e;
1032  case pktEntityEquipment: return 0x3e;
1033  case pktEntityHeadLook: return 0x35;
1034  case pktEntityLook: return 0x28;
1035  case pktEntityMeta: return 0x3b;
1036  case pktEntityProperties: return 0x4d;
1037  case pktEntityRelMove: return 0x26;
1038  case pktEntityRelMoveLook: return 0x27;
1039  case pktEntityVelocity: return 0x3d;
1040  case pktExperience: return 0x3f;
1041  case pktHeldItemChange: return 0x39;
1042  case pktLeashEntity: return 0x3c;
1043  case pktPlayerMaxSpeed: return 0x4d;
1044  case pktRemoveEntityEffect: return 0x32;
1045  case pktRespawn: return 0x34;
1046  case pktScoreboardObjective: return 0x41;
1047  case pktSpawnPosition: return 0x45;
1048  case pktTeleportEntity: return 0x4b;
1049  case pktTimeUpdate: return 0x46;
1050  case pktTitle: return 0x47;
1051  case pktUpdateBlockEntity: return 0x09;
1052  case pktUpdateHealth: return 0x40;
1053  case pktUpdateScore: return 0x44;
1054 
1055  default: return Super::GetPacketID(a_Packet);
1056  }
1057 }
1058 
1059 
1060 
1061 
1062 
1064 {
1065  a_ByteBuffer.SkipRead(a_ByteBuffer.GetReadableSpace() - 1);
1066  m_Client->GetPlayer()->SendMessageInfo("The green crafting book feature is not implemented yet.");
1067 }
1068 
1069 
1070 
1071 
1072 
1074 {
1075  a_ByteBuffer.SkipRead(a_ByteBuffer.GetReadableSpace() - 1);
1076  m_Client->GetPlayer()->SendMessageInfo("The new advancements are not implemented.");
1077 }
1078 
1079 
1080 
1081 
1082 
1083 void cProtocol_1_12::SendTitleTimes(int a_FadeInTicks, int a_DisplayTicks, int a_FadeOutTicks)
1084 {
1085  ASSERT(m_State == 3); // In game mode?
1086 
1087  cPacketizer Pkt(*this, pktTitle);
1088  Pkt.WriteVarInt32(3); // Set title display times
1089  Pkt.WriteBEInt32(a_FadeInTicks);
1090  Pkt.WriteBEInt32(a_DisplayTicks);
1091  Pkt.WriteBEInt32(a_FadeOutTicks);
1092 }
1093 
1094 
1095 
1096 
1097 
1099 {
1100  ASSERT(m_State == 3); // In game mode?
1101 
1102  cPacketizer Pkt(*this, pktTitle);
1103  Pkt.WriteVarInt32(4); // Hide title
1104 }
1105 
1106 
1107 
1108 
1109 
1111 {
1112  ASSERT(m_State == 3); // In game mode?
1113 
1114  cPacketizer Pkt(*this, pktTitle);
1115  Pkt.WriteVarInt32(5); // Reset title
1116 }
1117 
1118 
1119 
1120 
1121 
1122 void cProtocol_1_12::SendCollectEntity(const cEntity & a_Entity, const cPlayer & a_Player, int a_Count)
1123 {
1124  ASSERT(m_State == 3); // In game mode?
1125 
1126  cPacketizer Pkt(*this, pktCollectEntity);
1127  Pkt.WriteVarInt32(a_Entity.GetUniqueID());
1128  Pkt.WriteVarInt32(a_Player.GetUniqueID());
1129  Pkt.WriteVarInt32(static_cast<UInt32>(a_Count));
1130 }
1131 
1132 
1133 
1134 
1135 
1136 bool cProtocol_1_12::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType)
1137 {
1138  switch (m_State)
1139  {
1140  case 1:
1141  {
1142  // Status
1143  switch (a_PacketType)
1144  {
1145  case 0x00: HandlePacketStatusRequest(a_ByteBuffer); return true;
1146  case 0x01: HandlePacketStatusPing(a_ByteBuffer); return true;
1147  }
1148  break;
1149  }
1150 
1151  case 2:
1152  {
1153  // Login
1154  switch (a_PacketType)
1155  {
1156  case 0x00: HandlePacketLoginStart(a_ByteBuffer); return true;
1157  case 0x01: HandlePacketLoginEncryptionResponse(a_ByteBuffer); return true;
1158  }
1159  break;
1160  }
1161 
1162  case 3:
1163  {
1164  // Game
1165  switch (a_PacketType)
1166  {
1167  case 0x00: HandleConfirmTeleport(a_ByteBuffer); return true;
1168  case 0x01: break; // Prepare Crafting Grid, not yet implemented
1169  case 0x02: HandlePacketTabComplete(a_ByteBuffer); return true;
1170  case 0x03: HandlePacketChatMessage(a_ByteBuffer); return true;
1171  case 0x04: HandlePacketClientStatus(a_ByteBuffer); return true;
1172  case 0x05: HandlePacketClientSettings(a_ByteBuffer); return true;
1173  case 0x06: break; // Confirm transaction - not used in Cuberite
1174  case 0x07: HandlePacketEnchantItem(a_ByteBuffer); return true;
1175  case 0x08: HandlePacketWindowClick(a_ByteBuffer); return true;
1176  case 0x09: HandlePacketWindowClose(a_ByteBuffer); return true;
1177  case 0x0a: HandlePacketPluginMessage(a_ByteBuffer); return true;
1178  case 0x0b: HandlePacketUseEntity(a_ByteBuffer); return true;
1179  case 0x0c: HandlePacketKeepAlive(a_ByteBuffer); return true;
1180  case 0x0d: HandlePacketPlayer(a_ByteBuffer); return true;
1181  case 0x0e: HandlePacketPlayerPos(a_ByteBuffer); return true;
1182  case 0x0f: HandlePacketPlayerPosLook(a_ByteBuffer); return true;
1183  case 0x10: HandlePacketPlayerLook(a_ByteBuffer); return true;
1184  case 0x11: HandlePacketVehicleMove(a_ByteBuffer); return true;
1185  case 0x12: HandlePacketBoatSteer(a_ByteBuffer); return true;
1186  case 0x13: HandlePacketPlayerAbilities(a_ByteBuffer); return true;
1187  case 0x14: HandlePacketBlockDig(a_ByteBuffer); return true;
1188  case 0x15: HandlePacketEntityAction(a_ByteBuffer); return true;
1189  case 0x16: HandlePacketSteerVehicle(a_ByteBuffer); return true;
1190  case 0x17: HandlePacketCraftingBookData(a_ByteBuffer); return true;
1191  case 0x18: break; // Resource pack status - not yet implemented
1192  case 0x19: HandlePacketAdvancementTab(a_ByteBuffer); return true;
1193  case 0x1a: HandlePacketSlotSelect(a_ByteBuffer); return true;
1194  case 0x1b: HandlePacketCreativeInventoryAction(a_ByteBuffer); return true;
1195  case 0x1c: HandlePacketUpdateSign(a_ByteBuffer); return true;
1196  case 0x1d: HandlePacketAnimation(a_ByteBuffer); return true;
1197  case 0x1e: HandlePacketSpectate(a_ByteBuffer); return true;
1198  case 0x1f: HandlePacketBlockPlace(a_ByteBuffer); return true;
1199  case 0x20: HandlePacketUseItem(a_ByteBuffer); return true;
1200  }
1201  break;
1202  }
1203  default:
1204  {
1205  // Received a packet in an unknown state, report:
1206  LOGWARNING("Received a packet in an unknown protocol state %d. Ignoring further packets.", m_State);
1207 
1208  // Cannot kick the client - we don't know this state and thus the packet number for the kick packet
1209 
1210  // Switch to a state when all further packets are silently ignored:
1211  m_State = 255;
1212  return false;
1213  }
1214  case 255:
1215  {
1216  // This is the state used for "not processing packets anymore" when we receive a bad packet from a client.
1217  // Do not output anything (the caller will do that for us), just return failure
1218  return false;
1219  }
1220  } // switch (m_State)
1221 
1222  // Unknown packet type, report to the ClientHandle:
1223  m_Client->PacketUnknown(a_PacketType);
1224  return false;
1225 }
1226 
1227 
1228 
1229 
1230 
1231 cProtocol_1_12_1::cProtocol_1_12_1(cClientHandle * a_Client, const AString & a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State) :
1232  Super(a_Client, a_ServerAddress, a_ServerPort, a_State)
1233 {
1234 }
1235 
1236 
1237 
1238 
1239 
1241 {
1242  switch (a_Packet)
1243  {
1244  case pktAttachEntity: return 0x43;
1245  case pktCameraSetTo: return 0x39;
1246  case pktCollectEntity: return 0x4b;
1247  case pktDestroyEntity: return 0x32;
1248  case pktDisplayObjective: return 0x3b;
1249  case pktEntityEffect: return 0x4f;
1250  case pktEntityEquipment: return 0x3f;
1251  case pktEntityHeadLook: return 0x36;
1252  case pktEntityMeta: return 0x3c;
1253  case pktEntityProperties: return 0x4e;
1254  case pktEntityVelocity: return 0x3e;
1255  case pktExperience: return 0x40;
1256  case pktHeldItemChange: return 0x3a;
1257  case pktLeashEntity: return 0x3d;
1258  case pktPlayerList: return 0x2e;
1259  case pktPlayerAbilities: return 0x2c;
1260  case pktPlayerMaxSpeed: return 0x4e;
1261  case pktPlayerMoveLook: return 0x2f;
1262  case pktRemoveEntityEffect: return 0x33;
1263  case pktRespawn: return 0x35;
1264  case pktScoreboardObjective: return 0x42;
1265  case pktSpawnPosition: return 0x46;
1266  case pktUpdateHealth: return 0x41;
1267  case pktUpdateScore: return 0x45;
1268  case pktUseBed: return 0x30;
1269  case pktTeleportEntity: return 0x4c;
1270  case pktTimeUpdate: return 0x47;
1271  case pktTitle: return 0x48;
1272 
1273  default: return Super::GetPacketID(a_Packet);
1274  }
1275 }
1276 
1277 
1278 
1279 
1280 
1282 {
1283  cServer * Server = cRoot::Get()->GetServer();
1284  AString ServerDescription = Server->GetDescription();
1285  auto NumPlayers = static_cast<signed>(Server->GetNumPlayers());
1286  auto MaxPlayers = static_cast<signed>(Server->GetMaxPlayers());
1287  AString Favicon = Server->GetFaviconData();
1288  cRoot::Get()->GetPluginManager()->CallHookServerPing(*m_Client, ServerDescription, NumPlayers, MaxPlayers, Favicon);
1289 
1290  // Version:
1291  Json::Value Version;
1292  Version["name"] = "Cuberite 1.12.1";
1293  Version["protocol"] = cProtocolRecognizer::PROTO_VERSION_1_12_1;
1294 
1295  // Players:
1296  Json::Value Players;
1297  Players["online"] = NumPlayers;
1298  Players["max"] = MaxPlayers;
1299  // TODO: Add "sample"
1300 
1301  // Description:
1302  Json::Value Description;
1303  Description["text"] = ServerDescription.c_str();
1304 
1305  // Create the response:
1306  Json::Value ResponseValue;
1307  ResponseValue["version"] = Version;
1308  ResponseValue["players"] = Players;
1309  ResponseValue["description"] = Description;
1310  if (!Favicon.empty())
1311  {
1312  ResponseValue["favicon"] = Printf("data:image/png;base64,%s", Favicon.c_str());
1313  }
1314 
1315  // Serialize the response into a packet:
1316  Json::FastWriter Writer;
1317  cPacketizer Pkt(*this, pktStatusResponse);
1318  Pkt.WriteString(Writer.write(ResponseValue));
1319 }
1320 
1321 
1322 
1323 
1324 
1325 bool cProtocol_1_12_1::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType)
1326 {
1327  switch (m_State)
1328  {
1329  case 1:
1330  {
1331  // Status
1332  switch (a_PacketType)
1333  {
1334  case 0x00: HandlePacketStatusRequest(a_ByteBuffer); return true;
1335  case 0x01: HandlePacketStatusPing(a_ByteBuffer); return true;
1336  }
1337  break;
1338  }
1339 
1340  case 2:
1341  {
1342  // Login
1343  switch (a_PacketType)
1344  {
1345  case 0x00: HandlePacketLoginStart(a_ByteBuffer); return true;
1346  case 0x01: HandlePacketLoginEncryptionResponse(a_ByteBuffer); return true;
1347  }
1348  break;
1349  }
1350 
1351  case 3:
1352  {
1353  // Game
1354  switch (a_PacketType)
1355  {
1356  case 0x00: HandleConfirmTeleport(a_ByteBuffer); return true;
1357  case 0x01: HandlePacketTabComplete(a_ByteBuffer); return true;
1358  case 0x02: HandlePacketChatMessage(a_ByteBuffer); return true;
1359  case 0x03: HandlePacketClientStatus(a_ByteBuffer); return true;
1360  case 0x04: HandlePacketClientSettings(a_ByteBuffer); return true;
1361  case 0x05: break; // Confirm transaction - not used in Cuberite
1362  case 0x06: HandlePacketEnchantItem(a_ByteBuffer); return true;
1363  case 0x07: HandlePacketWindowClick(a_ByteBuffer); return true;
1364  case 0x08: HandlePacketWindowClose(a_ByteBuffer); return true;
1365  case 0x09: HandlePacketPluginMessage(a_ByteBuffer); return true;
1366  case 0x0a: HandlePacketUseEntity(a_ByteBuffer); return true;
1367  case 0x0b: HandlePacketKeepAlive(a_ByteBuffer); return true;
1368  case 0x0c: HandlePacketPlayer(a_ByteBuffer); return true;
1369  case 0x0d: HandlePacketPlayerPos(a_ByteBuffer); return true;
1370  case 0x0e: HandlePacketPlayerPosLook(a_ByteBuffer); return true;
1371  case 0x0f: HandlePacketPlayerLook(a_ByteBuffer); return true;
1372  case 0x10: HandlePacketVehicleMove(a_ByteBuffer); return true;
1373  case 0x11: HandlePacketBoatSteer(a_ByteBuffer); return true;
1374  case 0x12: break; // Craft Recipe Request - not yet implemented
1375  case 0x13: HandlePacketPlayerAbilities(a_ByteBuffer); return true;
1376  case 0x14: HandlePacketBlockDig(a_ByteBuffer); return true;
1377  case 0x15: HandlePacketEntityAction(a_ByteBuffer); return true;
1378  case 0x16: HandlePacketSteerVehicle(a_ByteBuffer); return true;
1379  case 0x17: HandlePacketCraftingBookData(a_ByteBuffer); return true;
1380  case 0x18: break; // Resource pack status - not yet implemented
1381  case 0x19: HandlePacketAdvancementTab(a_ByteBuffer); return true;
1382  case 0x1a: HandlePacketSlotSelect(a_ByteBuffer); return true;
1383  case 0x1b: HandlePacketCreativeInventoryAction(a_ByteBuffer); return true;
1384  case 0x1c: HandlePacketUpdateSign(a_ByteBuffer); return true;
1385  case 0x1d: HandlePacketAnimation(a_ByteBuffer); return true;
1386  case 0x1e: HandlePacketSpectate(a_ByteBuffer); return true;
1387  case 0x1f: HandlePacketBlockPlace(a_ByteBuffer); return true;
1388  case 0x20: HandlePacketUseItem(a_ByteBuffer); return true;
1389  }
1390  break;
1391  }
1392  default:
1393  {
1394  // Received a packet in an unknown state, report:
1395  LOGWARNING("Received a packet in an unknown protocol state %d. Ignoring further packets.", m_State);
1396 
1397  // Cannot kick the client - we don't know this state and thus the packet number for the kick packet
1398 
1399  // Switch to a state when all further packets are silently ignored:
1400  m_State = 255;
1401  return false;
1402  }
1403  case 255:
1404  {
1405  // This is the state used for "not processing packets anymore" when we receive a bad packet from a client.
1406  // Do not output anything (the caller will do that for us), just return failure
1407  return false;
1408  }
1409  } // switch (m_State)
1410 
1411  // Unknown packet type, report to the ClientHandle:
1412  m_Client->PacketUnknown(a_PacketType);
1413  return false;
1414 }
1415 
1416 
1417 
1418 
1420 // cProtocol_1_12_2:
1421 
1423 {
1424  HANDLE_READ(a_ByteBuffer, ReadBEInt64, Int64, KeepAliveID);
1425  if (
1426  (KeepAliveID <= std::numeric_limits<UInt32>::max()) &&
1427  (KeepAliveID >= 0)
1428  )
1429  {
1430  // The server will only send a UInt32 so any value out of that range shouldn't keep the client alive.
1431  m_Client->HandleKeepAlive(static_cast<UInt32>(KeepAliveID));
1432  }
1433 }
1434 
1435 
1436 
1437 
1438 
1440 {
1441  cServer * Server = cRoot::Get()->GetServer();
1442  AString ServerDescription = Server->GetDescription();
1443  auto NumPlayers = static_cast<signed>(Server->GetNumPlayers());
1444  auto MaxPlayers = static_cast<signed>(Server->GetMaxPlayers());
1445  AString Favicon = Server->GetFaviconData();
1446  cRoot::Get()->GetPluginManager()->CallHookServerPing(*m_Client, ServerDescription, NumPlayers, MaxPlayers, Favicon);
1447 
1448  // Version:
1449  Json::Value Version;
1450  Version["name"] = "Cuberite 1.12.2";
1451  Version["protocol"] = cProtocolRecognizer::PROTO_VERSION_1_12_2;
1452 
1453  // Players:
1454  Json::Value Players;
1455  Players["online"] = NumPlayers;
1456  Players["max"] = MaxPlayers;
1457  // TODO: Add "sample"
1458 
1459  // Description:
1460  Json::Value Description;
1461  Description["text"] = ServerDescription.c_str();
1462 
1463  // Create the response:
1464  Json::Value ResponseValue;
1465  ResponseValue["version"] = Version;
1466  ResponseValue["players"] = Players;
1467  ResponseValue["description"] = Description;
1468  if (!Favicon.empty())
1469  {
1470  ResponseValue["favicon"] = Printf("data:image/png;base64,%s", Favicon.c_str());
1471  }
1472 
1473  // Serialize the response into a packet:
1474  Json::FastWriter Writer;
1475  cPacketizer Pkt(*this, pktStatusResponse);
1476  Pkt.WriteString(Writer.write(ResponseValue));
1477 }
1478 
1479 
1480 
1481 
1482 
1484 {
1485  // Drop the packet if the protocol is not in the Game state yet (caused a client crash):
1486  if (m_State != 3)
1487  {
1488  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);
1489  return;
1490  }
1491 
1492  cPacketizer Pkt(*this, pktKeepAlive);
1493  Pkt.WriteBEInt64(a_PingID);
1494 }
virtual bool HandlePacket(cByteBuffer &a_ByteBuffer, UInt32 a_PacketType) override
Reads and handles the packet.
virtual void WriteMobMetadata(cPacketizer &a_Pkt, const cMonster &a_Mob) override
Writes the mob-specific metadata for the specified mob.
double GetPosY(void) const
Definition: Entity.h:207
virtual void HandlePacketEnchantItem(cByteBuffer &a_ByteBuffer)
virtual void HandlePacketPlayerLook(cByteBuffer &a_ByteBuffer)
#define HANDLE_READ(ByteBuf, Proc, Type, Var)
virtual void HandlePacketPlayer(cByteBuffer &a_ByteBuffer)
virtual void HandlePacketKeepAlive(cByteBuffer &a_ByteBuffer)
UInt32 m_State
State of the protocol.
Definition: Protocol_1_9.h:154
double GetPitch(void) const
Definition: Entity.h:210
Definition: Rabbit.h:25
virtual void HandlePacketUpdateSign(cByteBuffer &a_ByteBuffer)
void WriteBEInt8(Int8 a_Value)
Definition: Packetizer.h:56
double GetPosX(void) const
Definition: Entity.h:206
eEntityType GetEntityType(void) const
Definition: Entity.h:168
eMonsterType GetMobType(void) const
Definition: Monster.h:68
void HandleKeepAlive(UInt32 a_KeepAliveID)
virtual void SendSpawnMob(const cMonster &a_Mob) override
Definition: Witch.h:10
size_t GetReadableSpace(void) const
Returns the number of bytes that are currently available for reading (may be less than UsedSpace due ...
Definition: ByteBuffer.cpp:194
void SendMessageInfo(const AString &a_Message)
Definition: Player.cpp:1417
short m_ItemDamage
Definition: Item.h:211
signed char Int8
Definition: Globals.h:110
double GetHeadYaw(void) const
Definition: Entity.h:203
const AString & GetCustomName(void) const
Gets the custom name of the monster.
Definition: Monster.h:162
eHand HandIntToEnum(Int32 a_Hand)
Converts the hand parameter received by the protocol into eHand constants.
Definition: Boat.h:18
double GetSpeedX(void) const
Definition: Entity.h:213
virtual UInt32 GetPacketID(ePacketType a_Packet) override
Get the packet ID for a given packet.
eBlockFace FaceIntToBlockFace(Int32 a_FaceInt)
Converts the BlockFace received by the protocol into eBlockFace constants.
virtual void HandlePacketBlockDig(cByteBuffer &a_ByteBuffer)
virtual void WriteEntityMetadata(cPacketizer &a_Pkt, const cEntity &a_Entity) override
Writes the metadata for the specified entity, not including the terminating 0xff. ...
virtual void HandlePacketPlayerPosLook(cByteBuffer &a_ByteBuffer)
virtual void HandlePacketStatusPing(cByteBuffer &a_ByteBuffer)
virtual void WriteItem(cPacketizer &a_Pkt, const cItem &a_Item)
Writes the item data into a packet.
virtual void HandlePacketBoatSteer(cByteBuffer &a_ByteBuffer)
void HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, eHand a_Hand)
Definition: Player.h:27
virtual void HandlePacketClientStatus(cByteBuffer &a_ByteBuffer)
Definition: Ocelot.h:11
bool IsEmpty(void) const
Definition: Item.h:116
virtual void HandlePacketWindowClick(cByteBuffer &a_ByteBuffer)
Definition: Cow.h:10
void WriteBEInt16(Int16 a_Value)
Definition: Packetizer.h:62
virtual void HandlePacketPlayerAbilities(cByteBuffer &a_ByteBuffer)
Definition: Bat.h:10
virtual bool IsOnFire(void) const
Definition: Entity.h:486
virtual void HandlePacketClientSettings(cByteBuffer &a_ByteBuffer)
void PacketUnknown(UInt32 a_PacketType)
bool CallHookServerPing(cClientHandle &a_ClientHandle, AString &a_ServerDescription, int &a_OnlinePlayersCount, int &a_MaxPlayersCount, AString &a_Favicon)
bool HasCustomName(void) const
Returns true if the monster has a custom name.
Definition: Monster.h:159
virtual void SendResetTitle(void) override
virtual void HandlePacketUseItem(cByteBuffer &a_ByteBuffer)
void WriteBEUInt8(UInt8 a_Value)
Definition: Packetizer.h:50
virtual bool IsCrouched(void) const
Definition: Entity.h:487
const AString & GetDescription(void) const
Definition: Server.h:65
Definition: Horse.h:11
void WriteString(const AString &a_Value)
Definition: Packetizer.h:116
double GetSpeedZ(void) const
Definition: Entity.h:215
The version 110 protocol, used by 1.9.3 and 1.9.4.
Definition: Protocol_1_9.h:326
const AString & GetFaviconData(void) const
Returns base64 encoded favicon data (obtained from favicon.png)
Definition: Server.h:129
void WriteBEInt32(Int32 a_Value)
Definition: Packetizer.h:74
cClientHandle * m_Client
Definition: Protocol.h:244
Definition: Sheep.h:10
virtual void HandlePacketVehicleMove(cByteBuffer &a_ByteBuffer)
virtual bool IsInvisible(void) const
Definition: Entity.h:491
virtual void HandlePacketSteerVehicle(cByteBuffer &a_ByteBuffer)
virtual void HandlePacketTabComplete(cByteBuffer &a_ByteBuffer)
virtual void SendCollectEntity(const cEntity &a_Entity, const cPlayer &a_Player, int a_Count) override
virtual void HandlePacketPluginMessage(cByteBuffer &a_ByteBuffer)
bool IsCustomNameAlwaysVisible(void) const
Is the custom name of this monster always visible? If not, you only see the name when you sight the m...
Definition: Monster.h:169
Definition: Ghast.h:10
Definition: Server.h:55
virtual void HandlePacketChatMessage(cByteBuffer &a_ByteBuffer)
virtual void HandlePacketBlockPlace(cByteBuffer &a_ByteBuffer) override
Definition: Pig.h:10
size_t GetMaxPlayers(void) const
Definition: Server.h:70
virtual void HandlePacketStatusRequest(cByteBuffer &a_ByteBuffer) override
virtual void HandleConfirmTeleport(cByteBuffer &a_ByteBuffer)
void WriteByteAngle(double a_Angle)
Writes the specified angle using a single byte.
Definition: Packetizer.cpp:26
virtual void HandlePacketSpectate(cByteBuffer &a_ByteBuffer)
cPlayer * GetPlayer(void)
Definition: ClientHandle.h:75
virtual void SendTitleTimes(int a_FadeInTicks, int a_DisplayTicks, int a_FadeOutTicks) override
virtual void HandlePacketAnimation(cByteBuffer &a_ByteBuffer)
AString & Printf(AString &str, const char *format, fmt::ArgList args)
Output the formatted text into the string.
Definition: StringUtils.cpp:55
virtual void SendHideTitle(void) override
float GetHealth(void) const
Returns the health of this entity.
Definition: Entity.h:380
virtual void HandlePacketLoginEncryptionResponse(cByteBuffer &a_ByteBuffer)
#define ASSERT(x)
Definition: Globals.h:335
void LOGWARNING(const char *a_Format, fmt::ArgList a_ArgList)
Definition: Logger.cpp:174
size_t GetNumPlayers(void) const
Definition: Server.h:71
An object that can store incoming bytes and lets its clients read the bytes sequentially The bytes ar...
Definition: ByteBuffer.h:29
Definition: Slime.h:10
void WriteBEDouble(double a_Value)
Definition: Packetizer.h:104
float GetMaxHealth(void) const
Definition: Entity.h:417
bool SkipRead(size_t a_Count)
Skips reading by a_Count bytes; returns false if not enough bytes in the ringbuffer.
Definition: ByteBuffer.cpp:833
virtual UInt32 GetPacketID(ePacketType a_Packet) override
Get the packet ID for a given packet.
unsigned short UInt16
Definition: Globals.h:114
double GetYaw(void) const
Definition: Entity.h:209
virtual bool IsSprinting(void) const
Definition: Entity.h:489
virtual void HandlePacketStatusRequest(cByteBuffer &a_ByteBuffer) override
virtual void HandlePacketCraftingBookData(cByteBuffer &a_ByteBuffer)
std::string AString
Definition: StringUtils.h:13
cServer * GetServer(void)
Definition: Root.h:69
double GetSpeedY(void) const
Definition: Entity.h:214
virtual void SendKeepAlive(UInt32 a_PingID) override
virtual bool HandlePacket(cByteBuffer &a_ByteBuffer, UInt32 a_PacketType) override
Reads and handles the packet.
virtual void HandlePacketUseEntity(cByteBuffer &a_ByteBuffer)
Composes an individual packet in the protocol&#39;s m_OutPacketBuffer; sends it just before being destruc...
Definition: Packetizer.h:28
void ForgeAugmentServerListPing(Json::Value &a_Response)
Add the Forge mod list to the server ping response.
Definition: ClientHandle.h:270
static cRoot * Get()
Definition: Root.h:51
cProtocol_1_12(cClientHandle *a_Client, const AString &a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State)
void WriteVarInt32(UInt32 a_Value)
Definition: Packetizer.h:110
signed int Int32
Definition: Globals.h:108
Definition: Entity.h:73
void WriteBEFloat(float a_Value)
Definition: Packetizer.h:98
unsigned int UInt32
Definition: Globals.h:113
virtual bool IsRclking(void) const
Definition: Entity.h:490
virtual void HandlePacketPlayerPos(cByteBuffer &a_ByteBuffer)
Definition: Wolf.h:12
cProtocol_1_12_1(cClientHandle *a_Client, const AString &a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State)
double GetPosZ(void) const
Definition: Entity.h:208
short m_ItemType
Definition: Item.h:209
Definition: Wither.h:10
void WriteBool(bool a_Value)
Definition: Packetizer.h:45
virtual UInt32 GetPacketID(ePacketType a_Packet) override
Get the packet ID for a given packet.
virtual void HandlePacketWindowClose(cByteBuffer &a_ByteBuffer)
void WriteBEUInt64(UInt64 a_Value)
Definition: Packetizer.h:92
std::enable_if< std::is_arithmetic< T >::value, C >::type FloorC(T a_Value)
Floors a value, then casts it to C (an int by default)
Definition: Globals.h:362
virtual void HandlePacketStatusRequest(cByteBuffer &a_ByteBuffer) override
bool ReadPosition64(int &a_BlockX, int &a_BlockY, int &a_BlockZ)
Definition: ByteBuffer.cpp:475
ePacketType
Logical types of outgoing packets.
Definition: Protocol.h:68
Definition: Item.h:36
virtual void HandlePacketKeepAlive(cByteBuffer &a_ByteBuffer) override
Definition: Zombie.h:9
virtual void HandlePacketLoginStart(cByteBuffer &a_ByteBuffer)
signed long long Int64
Definition: Globals.h:107
void WriteBEInt64(Int64 a_Value)
Definition: Packetizer.h:86
UInt32 GetUniqueID(void) const
Definition: Entity.h:261
virtual void HandlePacketSlotSelect(cByteBuffer &a_ByteBuffer)
cPluginManager * GetPluginManager(void)
Definition: Root.h:114
virtual void HandlePacketAdvancementTab(cByteBuffer &a_ByteBuffer)
virtual void HandlePacketCreativeInventoryAction(cByteBuffer &a_ByteBuffer)
virtual void HandlePacketEntityAction(cByteBuffer &a_ByteBuffer)