Cuberite
A lightweight, fast and extensible game server for Minecraft
Protocol_1_10.cpp
Go to the documentation of this file.
1 
2 // Protocol_1_10.cpp
3 
4 /*
5 Implements the 1.10 protocol classes:
6  - cProtocol_1_10_0
7  - release 1.10 protocol (#210), also used by 1.10.1 and 1.10.2
8 */
9 
10 #include "Globals.h"
11 #include "Protocol_1_10.h"
12 #include "Packetizer.h"
13 
14 #include "json/json.h"
15 
16 #include "../Root.h"
17 #include "../Server.h"
18 #include "../ClientHandle.h"
19 
20 #include "../WorldStorage/FastNBT.h"
21 
22 #include "../Entities/Boat.h"
23 #include "../Entities/ExpOrb.h"
24 #include "../Entities/Minecart.h"
25 #include "../Entities/FallingBlock.h"
26 #include "../Entities/Painting.h"
27 #include "../Entities/Pickup.h"
28 #include "../Entities/Player.h"
29 #include "../Entities/ItemFrame.h"
30 #include "../Entities/ArrowEntity.h"
31 #include "../Entities/FireworkEntity.h"
32 #include "../Entities/SplashPotionEntity.h"
33 
34 #include "../Mobs/IncludeAllMonsters.h"
35 
36 #include "../BlockEntities/BeaconEntity.h"
37 #include "../BlockEntities/CommandBlockEntity.h"
38 #include "../BlockEntities/MobHeadEntity.h"
39 #include "../BlockEntities/MobSpawnerEntity.h"
40 #include "../BlockEntities/FlowerPotEntity.h"
41 
42 #include "../Bindings/PluginManager.h"
43 
44 
45 
46 
47 
48 // The disabled error is intended, since the Metadata have overlapping indexes
49 // based on the type of the Entity.
50 //
51 // IMPORTANT: The enum is used to automate the sequential counting of the
52 // Metadata indexes. Adding a new enum value causes the following values to
53 // increase their index. Therefore the ordering of the enum values is VERY important!
54 #ifdef __clang__
55  #pragma clang diagnostic push
56  #pragma clang diagnostic ignored "-Wduplicate-enum"
57 #endif
58 
59 namespace Metadata
60 {
62  {
63  // Entity
70  _ENTITY_NEXT, // Used by descendants
71 
72  // Potion
73  POTION_THROWN = _ENTITY_NEXT,
74 
75  // FallingBlock
76  FALLING_BLOCK_POSITION = _ENTITY_NEXT,
77 
78  // AreaEffectCloud
79  AREA_EFFECT_CLOUD_RADIUS = _ENTITY_NEXT,
85 
86  // Arrow
87  ARROW_CRITICAL = _ENTITY_NEXT,
88  _ARROW_NEXT,
89 
90  // TippedArrow
91  TIPPED_ARROW_COLOR = _ARROW_NEXT,
92 
93  // Boat
94  BOAT_LAST_HIT_TIME = _ENTITY_NEXT,
100 
101  // EnderCrystal
104 
105  // Fireball
106  _FIREBALL_NEXT = _ENTITY_NEXT,
107 
108  // WitherSkull
109  WITHER_SKULL_INVULNERABLE = _FIREBALL_NEXT,
110 
111  // Fireworks
112  FIREWORK_INFO = _ENTITY_NEXT,
113 
114  // Hanging
115  _HANGING_NEXT = _ENTITY_NEXT,
116 
117  // ItemFrame
118  ITEM_FRAME_ITEM = _HANGING_NEXT,
120 
121  // Item
122  ITEM_ITEM = _ENTITY_NEXT,
123 
124  // Living
125  LIVING_ACTIVE_HAND = _ENTITY_NEXT,
130  _LIVING_NEXT,
131 
132  // Player
137 
138  // ArmorStand
139  ARMOR_STAND_STATUS = _LIVING_NEXT,
146 
147  // Insentient
148  INSENTIENT_STATUS = _LIVING_NEXT,
149  _INSENTIENT_NEXT,
150 
151  // Ambient
152  _AMBIENT_NEXT = _INSENTIENT_NEXT,
153 
154  // Bat
155  BAT_HANGING = _AMBIENT_NEXT,
156 
157  // Creature
158  _CREATURE_NEXT = _INSENTIENT_NEXT,
159 
160  // Ageable
161  AGEABLE_BABY = _CREATURE_NEXT,
162  _AGEABLE_NEXT,
163 
164  // PolarBear
165  POLAR_BEAR_STANDING = _AGEABLE_NEXT,
166 
167  // Animal
168  _ANIMAL_NEXT = _AGEABLE_NEXT,
169 
170  // Horse
171  HORSE_STATUS = _ANIMAL_NEXT,
176 
177  // Pig
178  PIG_HAS_SADDLE = _ANIMAL_NEXT,
179 
180  // Rabbit
181  RABBIT_TYPE = _ANIMAL_NEXT,
182 
183  // Sheep
184  SHEEP_STATUS = _ANIMAL_NEXT,
185 
186  // TameableAnimal
187  TAMEABLE_ANIMAL_STATUS = _ANIMAL_NEXT,
189  _TAMEABLE_NEXT,
190 
191  // Ocelot
192  OCELOT_TYPE = _TAMEABLE_NEXT,
193 
194  // Wolf
195  WOLF_DAMAGE_TAKEN = _TAMEABLE_NEXT,
198 
199  // Villager
200  VILLAGER_PROFESSION = _AGEABLE_NEXT,
201 
202  // Golem
203  _GOLEM_NEXT = _CREATURE_NEXT,
204 
205  // IronGolem
207 
208  // Shulker
212 
213  // Monster
214  _MONSTER_NEXT = _CREATURE_NEXT,
215 
216  // Blaze
217  BLAZE_ON_FIRE = _MONSTER_NEXT,
218 
219  // Creeper
220  CREEPER_STATE = _MONSTER_NEXT,
223 
224  // Guardian
225  GUARDIAN_STATUS = _MONSTER_NEXT,
227 
228  // Skeleton
229  SKELETON_TYPE = _MONSTER_NEXT,
231 
232  // Spider
233  SPIDER_CLIMBING = _MONSTER_NEXT,
234 
235  // Witch
236  WITCH_AGGRESIVE = _MONSTER_NEXT,
237 
238  // Wither
239  WITHER_FIRST_HEAD_TARGET = _MONSTER_NEXT,
243 
244  // Zombie
245  ZOMBIE_IS_BABY = _MONSTER_NEXT,
249 
250  // Enderman
251  ENDERMAN_CARRIED_BLOCK = _MONSTER_NEXT,
253 
254  // EnderDragon
255  ENDER_DRAGON_DRAGON_PHASE = _INSENTIENT_NEXT,
256 
257  // Flying
258  _FLYING_NEXT = _INSENTIENT_NEXT,
259 
260  // Ghast
261  GHAST_ATTACKING = _FLYING_NEXT,
262 
263  // Slime
264  SLIME_SIZE = _INSENTIENT_NEXT,
265 
266  // Minecart
267  MINECART_SHAKING_POWER = _ENTITY_NEXT,
273  _MINECART_NEXT,
274 
275  // MinecartCommandBlock
278 
279  // MinecartFurnace
280  MINECART_FURNACE_POWERED = _MINECART_NEXT,
281 
282  // TNTPrimed
283  TNT_PRIMED_FUSE_TIME = _ENTITY_NEXT,
284  };
285 }
286 
287 #ifdef __clang__
288  #pragma clang diagnostic pop // Restore ignored clang errors
289 #endif
290 
291 
292 
293 
294 cProtocol_1_10_0::cProtocol_1_10_0(cClientHandle * a_Client, const AString & a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State) :
295  Super(a_Client, a_ServerAddress, a_ServerPort, a_State)
296 {
297 }
298 
299 
300 
301 
302 
303 void cProtocol_1_10_0::SendSoundEffect(const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch)
304 {
305  ASSERT(m_State == 3); // In game mode?
306 
307  cPacketizer Pkt(*this, pktSoundEffect);
308  Pkt.WriteString(a_SoundName);
309  Pkt.WriteVarInt32(0); // Master sound category (may want to be changed to a parameter later)
310  Pkt.WriteBEInt32(FloorC(a_X * 8.0));
311  Pkt.WriteBEInt32(FloorC(a_Y * 8.0));
312  Pkt.WriteBEInt32(FloorC(a_Z * 8.0));
313  Pkt.WriteBEFloat(a_Volume);
314  Pkt.WriteBEFloat(a_Pitch);
315 }
316 
317 
318 
319 
320 
322 {
323  cServer * Server = cRoot::Get()->GetServer();
324  AString ServerDescription = Server->GetDescription();
325  auto NumPlayers = static_cast<signed>(Server->GetNumPlayers());
326  auto MaxPlayers = static_cast<signed>(Server->GetMaxPlayers());
327  AString Favicon = Server->GetFaviconData();
328  cRoot::Get()->GetPluginManager()->CallHookServerPing(*m_Client, ServerDescription, NumPlayers, MaxPlayers, Favicon);
329 
330  // Version:
331  Json::Value Version;
332  Version["name"] = "Cuberite 1.10";
333  Version["protocol"] = 210;
334 
335  // Players:
336  Json::Value Players;
337  Players["online"] = NumPlayers;
338  Players["max"] = MaxPlayers;
339  // TODO: Add "sample"
340 
341  // Description:
342  Json::Value Description;
343  Description["text"] = ServerDescription.c_str();
344 
345  // Create the response:
346  Json::Value ResponseValue;
347  ResponseValue["version"] = Version;
348  ResponseValue["players"] = Players;
349  ResponseValue["description"] = Description;
350  m_Client->ForgeAugmentServerListPing(ResponseValue);
351  if (!Favicon.empty())
352  {
353  ResponseValue["favicon"] = Printf("data:image/png;base64,%s", Favicon.c_str());
354  }
355 
356  Json::FastWriter Writer;
357  AString Response = Writer.write(ResponseValue);
358 
359  cPacketizer Pkt(*this, pktStatusResponse);
360  Pkt.WriteString(Response);
361 }
362 
363 
364 
365 
366 
368 {
369  using namespace Metadata;
370 
371  // Common metadata:
372  Int8 Flags = 0;
373  if (a_Entity.IsOnFire())
374  {
375  Flags |= 0x01;
376  }
377  if (a_Entity.IsCrouched())
378  {
379  Flags |= 0x02;
380  }
381  if (a_Entity.IsSprinting())
382  {
383  Flags |= 0x08;
384  }
385  if (a_Entity.IsRclking())
386  {
387  Flags |= 0x10;
388  }
389  if (a_Entity.IsInvisible())
390  {
391  Flags |= 0x20;
392  }
393  a_Pkt.WriteBEUInt8(ENTITY_FLAGS); // Index
394  a_Pkt.WriteBEUInt8(METADATA_TYPE_BYTE); // Type
395  a_Pkt.WriteBEInt8(Flags);
396 
397  switch (a_Entity.GetEntityType())
398  {
399  case cEntity::etPlayer:
400  {
401  auto & Player = static_cast<const cPlayer &>(a_Entity);
402 
403  // TODO Set player custom name to their name.
404  // Then it's possible to move the custom name of mobs to the entities
405  // and to remove the "special" player custom name.
408  a_Pkt.WriteString(Player.GetName());
409 
412  a_Pkt.WriteBEFloat(static_cast<float>(Player.GetHealth()));
413 
416  a_Pkt.WriteBEUInt8(static_cast<UInt8>(Player.GetSkinParts()));
417 
420  a_Pkt.WriteBEUInt8(static_cast<UInt8>(Player.GetMainHand()));
421  break;
422  }
423  case cEntity::etPickup:
424  {
425  a_Pkt.WriteBEUInt8(ITEM_ITEM);
427  WriteItem(a_Pkt, static_cast<const cPickup &>(a_Entity).GetItem());
428  break;
429  }
430  case cEntity::etMinecart:
431  {
434 
435  // The following expression makes Minecarts shake more with less health or higher damage taken
436  auto & Minecart = static_cast<const cMinecart &>(a_Entity);
437  auto maxHealth = a_Entity.GetMaxHealth();
438  auto curHealth = a_Entity.GetHealth();
439  a_Pkt.WriteVarInt32(static_cast<UInt32>((maxHealth - curHealth) * Minecart.LastDamage() * 4));
440 
441  a_Pkt.WriteBEUInt8(MINECART_SHAKING_DIRECTION); // (doesn't seem to effect anything)
443  a_Pkt.WriteVarInt32(1);
444 
445  a_Pkt.WriteBEUInt8(MINECART_SHAKING_MULTIPLIER); // or damage taken
447  a_Pkt.WriteBEFloat(static_cast<float>(Minecart.LastDamage() + 10));
448 
449  if (Minecart.GetPayload() == cMinecart::mpNone)
450  {
451  auto & RideableMinecart = static_cast<const cRideableMinecart &>(Minecart);
452  const cItem & MinecartContent = RideableMinecart.GetContent();
453  if (!MinecartContent.IsEmpty())
454  {
457  int Content = MinecartContent.m_ItemType;
458  Content |= MinecartContent.m_ItemDamage << 8;
459  a_Pkt.WriteVarInt32(static_cast<UInt32>(Content));
460 
463  a_Pkt.WriteVarInt32(static_cast<UInt32>(RideableMinecart.GetBlockHeight()));
464 
467  a_Pkt.WriteBool(true);
468  }
469  }
470  else if (Minecart.GetPayload() == cMinecart::mpFurnace)
471  {
474  a_Pkt.WriteBool(static_cast<const cMinecartWithFurnace &>(Minecart).IsFueled());
475  }
476  break;
477  } // case etMinecart
478 
480  {
481  auto & Projectile = static_cast<const cProjectileEntity &>(a_Entity);
482  switch (Projectile.GetProjectileKind())
483  {
485  {
488  a_Pkt.WriteBEInt8(static_cast<const cArrowEntity &>(Projectile).IsCritical() ? 1 : 0);
489  break;
490  }
492  {
493  a_Pkt.WriteBEUInt8(FIREWORK_INFO); // Firework item used for this firework
495  WriteItem(a_Pkt, static_cast<const cFireworkEntity &>(Projectile).GetItem());
496  break;
497  }
499  {
500  a_Pkt.WriteBEUInt8(POTION_THROWN); // Potion item which was thrown
502  WriteItem(a_Pkt, static_cast<const cSplashPotionEntity &>(Projectile).GetItem());
503  }
504  default:
505  {
506  break;
507  }
508  }
509  break;
510  } // case etProjectile
511 
512  case cEntity::etMonster:
513  {
514  WriteMobMetadata(a_Pkt, static_cast<const cMonster &>(a_Entity));
515  break;
516  }
517 
518  case cEntity::etBoat:
519  {
520  auto & Boat = static_cast<const cBoat &>(a_Entity);
521 
524  a_Pkt.WriteVarInt32(static_cast<UInt32>(Boat.GetLastDamage()));
525 
528  a_Pkt.WriteVarInt32(static_cast<UInt32>(Boat.GetForwardDirection()));
529 
532  a_Pkt.WriteBEFloat(Boat.GetDamageTaken());
533 
534  a_Pkt.WriteBEInt8(BOAT_TYPE);
536  a_Pkt.WriteVarInt32(static_cast<UInt32>(Boat.GetMaterial()));
537 
540  a_Pkt.WriteBool(Boat.IsRightPaddleUsed());
541 
544  a_Pkt.WriteBool(Boat.IsLeftPaddleUsed());
545 
546  break;
547  } // case etBoat
548 
550  {
551  auto & Frame = static_cast<const cItemFrame &>(a_Entity);
554  WriteItem(a_Pkt, Frame.GetItem());
557  a_Pkt.WriteVarInt32(Frame.GetItemRotation());
558  break;
559  } // case etItemFrame
560 
561  default:
562  {
563  break;
564  }
565  }
566 }
567 
568 
569 
570 
571 
572 void cProtocol_1_10_0::WriteBlockEntity(cPacketizer & a_Pkt, const cBlockEntity & a_BlockEntity)
573 {
574  cFastNBTWriter Writer;
575 
576  switch (a_BlockEntity.GetBlockType())
577  {
578  case E_BLOCK_BEACON:
579  {
580  auto & BeaconEntity = static_cast<const cBeaconEntity &>(a_BlockEntity);
581  Writer.AddInt("x", BeaconEntity.GetPosX());
582  Writer.AddInt("y", BeaconEntity.GetPosY());
583  Writer.AddInt("z", BeaconEntity.GetPosZ());
584  Writer.AddInt("Primary", BeaconEntity.GetPrimaryEffect());
585  Writer.AddInt("Secondary", BeaconEntity.GetSecondaryEffect());
586  Writer.AddInt("Levels", BeaconEntity.GetBeaconLevel());
587  Writer.AddString("id", "Beacon"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though
588  break;
589  }
590 
592  {
593  auto & CommandBlockEntity = static_cast<const cCommandBlockEntity &>(a_BlockEntity);
594  Writer.AddByte("TrackOutput", 1); // Neither I nor the MC wiki has any idea about this
595  Writer.AddInt("SuccessCount", CommandBlockEntity.GetResult());
596  Writer.AddInt("x", CommandBlockEntity.GetPosX());
597  Writer.AddInt("y", CommandBlockEntity.GetPosY());
598  Writer.AddInt("z", CommandBlockEntity.GetPosZ());
599  Writer.AddString("Command", CommandBlockEntity.GetCommand().c_str());
600  // You can set custom names for windows in Vanilla
601  // For a command block, this would be the 'name' prepended to anything it outputs into global chat
602  // MCS doesn't have this, so just leave it @ '@'. (geddit?)
603  Writer.AddString("CustomName", "@");
604  Writer.AddString("id", "Control"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though
605  if (!CommandBlockEntity.GetLastOutput().empty())
606  {
607  Writer.AddString("LastOutput", Printf("{\"text\":\"%s\"}", CommandBlockEntity.GetLastOutput().c_str()));
608  }
609  break;
610  }
611 
612  case E_BLOCK_HEAD:
613  {
614  auto & MobHeadEntity = static_cast<const cMobHeadEntity &>(a_BlockEntity);
615  Writer.AddInt("x", MobHeadEntity.GetPosX());
616  Writer.AddInt("y", MobHeadEntity.GetPosY());
617  Writer.AddInt("z", MobHeadEntity.GetPosZ());
618  Writer.AddByte("SkullType", MobHeadEntity.GetType() & 0xFF);
619  Writer.AddByte("Rot", MobHeadEntity.GetRotation() & 0xFF);
620  Writer.AddString("id", "Skull"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though
621 
622  // The new Block Entity format for a Mob Head. See: https://minecraft.gamepedia.com/Head#Block_entity
623  Writer.BeginCompound("Owner");
624  Writer.AddString("Id", MobHeadEntity.GetOwnerUUID().ToShortString());
625  Writer.AddString("Name", MobHeadEntity.GetOwnerName());
626  Writer.BeginCompound("Properties");
627  Writer.BeginList("textures", TAG_Compound);
628  Writer.BeginCompound("");
629  Writer.AddString("Signature", MobHeadEntity.GetOwnerTextureSignature());
630  Writer.AddString("Value", MobHeadEntity.GetOwnerTexture());
631  Writer.EndCompound();
632  Writer.EndList();
633  Writer.EndCompound();
634  Writer.EndCompound();
635  break;
636  }
637 
638  case E_BLOCK_FLOWER_POT:
639  {
640  auto & FlowerPotEntity = static_cast<const cFlowerPotEntity &>(a_BlockEntity);
641  Writer.AddInt("x", FlowerPotEntity.GetPosX());
642  Writer.AddInt("y", FlowerPotEntity.GetPosY());
643  Writer.AddInt("z", FlowerPotEntity.GetPosZ());
644  Writer.AddInt("Item", static_cast<Int32>(FlowerPotEntity.GetItem().m_ItemType));
645  Writer.AddInt("Data", static_cast<Int32>(FlowerPotEntity.GetItem().m_ItemDamage));
646  Writer.AddString("id", "FlowerPot"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though
647  break;
648  }
649 
650  case E_BLOCK_MOB_SPAWNER:
651  {
652  auto & MobSpawnerEntity = static_cast<const cMobSpawnerEntity &>(a_BlockEntity);
653  Writer.AddInt("x", MobSpawnerEntity.GetPosX());
654  Writer.AddInt("y", MobSpawnerEntity.GetPosY());
655  Writer.AddInt("z", MobSpawnerEntity.GetPosZ());
656  Writer.BeginCompound("SpawnData");
657  Writer.AddString("id", cMonster::MobTypeToVanillaName(MobSpawnerEntity.GetEntity()));
658  Writer.EndCompound();
659  Writer.AddShort("Delay", MobSpawnerEntity.GetSpawnDelay());
660  Writer.AddString("id", "MobSpawner");
661  break;
662  }
663 
664  default:
665  {
666  break;
667  }
668  }
669 
670  Writer.Finish();
671  a_Pkt.WriteBuf(Writer.GetResult().data(), Writer.GetResult().size());
672 }
673 
674 
675 
676 
677 
679 {
680  using namespace Metadata;
681 
682  // Living Enitiy Metadata
683  if (a_Mob.HasCustomName())
684  {
685  // TODO: As of 1.9 _all_ entities can have custom names; should this be moved up?
688  a_Pkt.WriteString(a_Mob.GetCustomName());
689 
690  a_Pkt.WriteBEUInt8(ENTITY_CUSTOM_NAME_VISIBLE); // Custom name always visible
692  a_Pkt.WriteBool(a_Mob.IsCustomNameAlwaysVisible());
693  }
694 
697  a_Pkt.WriteBEFloat(static_cast<float>(a_Mob.GetHealth()));
698 
699  switch (a_Mob.GetMobType())
700  {
701  case mtBat:
702  {
703  auto & Bat = static_cast<const cBat &>(a_Mob);
704  a_Pkt.WriteBEUInt8(BAT_HANGING);
706  a_Pkt.WriteBEInt8(Bat.IsHanging() ? 1 : 0);
707  break;
708  } // case mtBat
709 
710  case mtChicken:
711  {
712  auto & Chicken = static_cast<const cChicken &>(a_Mob);
713 
714  a_Pkt.WriteBEUInt8(AGEABLE_BABY);
716  a_Pkt.WriteBool(Chicken.IsBaby());
717  break;
718  } // case mtChicken
719 
720  case mtCow:
721  {
722  auto & Cow = static_cast<const cCow &>(a_Mob);
723 
724  a_Pkt.WriteBEUInt8(AGEABLE_BABY);
726  a_Pkt.WriteBool(Cow.IsBaby());
727  break;
728  } // case mtCow
729 
730  case mtCreeper:
731  {
732  auto & Creeper = static_cast<const cCreeper &>(a_Mob);
733  a_Pkt.WriteBEUInt8(CREEPER_STATE); // (idle or "blowing")
735  a_Pkt.WriteVarInt32(Creeper.IsBlowing() ? 1 : static_cast<UInt32>(-1));
736 
739  a_Pkt.WriteBool(Creeper.IsCharged());
740 
743  a_Pkt.WriteBool(Creeper.IsBurnedWithFlintAndSteel());
744  break;
745  } // case mtCreeper
746 
747  case mtEnderman:
748  {
749  auto & Enderman = static_cast<const cEnderman &>(a_Mob);
752  UInt32 Carried = 0;
753  Carried |= static_cast<UInt32>(Enderman.GetCarriedBlock() << 4);
754  Carried |= Enderman.GetCarriedMeta();
755  a_Pkt.WriteVarInt32(Carried);
756 
759  a_Pkt.WriteBool(Enderman.IsScreaming());
760  break;
761  } // case mtEnderman
762 
763  case mtGhast:
764  {
765  auto & Ghast = static_cast<const cGhast &>(a_Mob);
768  a_Pkt.WriteBool(Ghast.IsCharging());
769  break;
770  } // case mtGhast
771 
772  case mtHorse:
773  {
774  auto & Horse = static_cast<const cHorse &>(a_Mob);
775  Int8 Flags = 0;
776  if (Horse.IsTame())
777  {
778  Flags |= 0x02;
779  }
780  if (Horse.IsSaddled())
781  {
782  Flags |= 0x04;
783  }
784  if (Horse.IsChested())
785  {
786  Flags |= 0x08;
787  }
788  if (Horse.IsEating())
789  {
790  Flags |= 0x20;
791  }
792  if (Horse.IsRearing())
793  {
794  Flags |= 0x40;
795  }
796  if (Horse.IsMthOpen())
797  {
798  Flags |= 0x80;
799  }
800  a_Pkt.WriteBEUInt8(HORSE_STATUS);
802  a_Pkt.WriteBEInt8(Flags);
803 
804  a_Pkt.WriteBEUInt8(HORSE_TYPE);
806  a_Pkt.WriteVarInt32(static_cast<UInt32>(Horse.GetHorseType()));
807 
808  a_Pkt.WriteBEUInt8(HORSE_VARIANT); // Color / style
810  int Appearance = 0;
811  Appearance = Horse.GetHorseColor();
812  Appearance |= Horse.GetHorseStyle() << 8;
813  a_Pkt.WriteVarInt32(static_cast<UInt32>(Appearance));
814 
815  a_Pkt.WriteBEUInt8(HORSE_ARMOR);
817  a_Pkt.WriteVarInt32(static_cast<UInt32>(Horse.GetHorseArmour()));
818 
819  a_Pkt.WriteBEUInt8(AGEABLE_BABY);
821  a_Pkt.WriteBool(Horse.IsBaby());
822  break;
823  } // case mtHorse
824 
825  case mtMagmaCube:
826  {
827  auto & MagmaCube = static_cast<const cMagmaCube &>(a_Mob);
828  a_Pkt.WriteBEUInt8(SLIME_SIZE);
830  a_Pkt.WriteVarInt32(static_cast<UInt32>(MagmaCube.GetSize()));
831  break;
832  } // case mtMagmaCube
833 
834  case mtOcelot:
835  {
836  auto & Ocelot = static_cast<const cOcelot &>(a_Mob);
837 
838  a_Pkt.WriteBEUInt8(AGEABLE_BABY);
840  a_Pkt.WriteBool(Ocelot.IsBaby());
841  break;
842  } // case mtOcelot
843 
844  case mtPig:
845  {
846  auto & Pig = static_cast<const cPig &>(a_Mob);
847 
848  a_Pkt.WriteBEUInt8(AGEABLE_BABY);
850  a_Pkt.WriteBool(Pig.IsBaby());
851 
854  a_Pkt.WriteBool(Pig.IsSaddled());
855 
856  break;
857  } // case mtPig
858 
859  case mtRabbit:
860  {
861  auto & Rabbit = static_cast<const cRabbit &>(a_Mob);
862  a_Pkt.WriteBEUInt8(AGEABLE_BABY);
864  a_Pkt.WriteBool(Rabbit.IsBaby());
865 
866  a_Pkt.WriteBEUInt8(RABBIT_TYPE);
868  a_Pkt.WriteVarInt32(static_cast<UInt32>(Rabbit.GetRabbitType()));
869  break;
870  } // case mtRabbit
871 
872  case mtSheep:
873  {
874  auto & Sheep = static_cast<const cSheep &>(a_Mob);
875 
876  a_Pkt.WriteBEUInt8(AGEABLE_BABY);
878  a_Pkt.WriteBool(Sheep.IsBaby());
879 
880  a_Pkt.WriteBEUInt8(SHEEP_STATUS);
882  Int8 SheepMetadata = 0;
883  SheepMetadata = static_cast<Int8>(Sheep.GetFurColor());
884  if (Sheep.IsSheared())
885  {
886  SheepMetadata |= 0x10;
887  }
888  a_Pkt.WriteBEInt8(SheepMetadata);
889  break;
890  } // case mtSheep
891 
892  case mtSkeleton:
893  {
894  auto & Skeleton = static_cast<const cSkeleton &>(a_Mob);
897  a_Pkt.WriteVarInt32(Skeleton.IsWither() ? 1 : 0);
898  break;
899  } // case mtSkeleton
900 
901  case mtSlime:
902  {
903  auto & Slime = static_cast<const cSlime &>(a_Mob);
904  a_Pkt.WriteBEUInt8(SLIME_SIZE);
906  a_Pkt.WriteVarInt32(static_cast<UInt32>(Slime.GetSize()));
907  break;
908  } // case mtSlime
909 
910  case mtVillager:
911  {
912  auto & Villager = static_cast<const cVillager &>(a_Mob);
913  a_Pkt.WriteBEUInt8(AGEABLE_BABY);
915  a_Pkt.WriteBool(Villager.IsBaby());
916 
919  a_Pkt.WriteVarInt32(static_cast<UInt32>(Villager.GetVilType()));
920  break;
921  } // case mtVillager
922 
923  case mtWitch:
924  {
925  auto & Witch = static_cast<const cWitch &>(a_Mob);
928  a_Pkt.WriteBool(Witch.IsAngry());
929  break;
930  } // case mtWitch
931 
932  case mtWither:
933  {
934  auto & Wither = static_cast<const cWither &>(a_Mob);
937  a_Pkt.WriteVarInt32(Wither.GetWitherInvulnerableTicks());
938 
939  // TODO: Use boss bar packet for health
940  break;
941  } // case mtWither
942 
943  case mtWolf:
944  {
945  auto & Wolf = static_cast<const cWolf &>(a_Mob);
946  a_Pkt.WriteBEUInt8(AGEABLE_BABY);
948  a_Pkt.WriteBool(Wolf.IsBaby());
949 
950  Int8 WolfStatus = 0;
951  if (Wolf.IsSitting())
952  {
953  WolfStatus |= 0x1;
954  }
955  if (Wolf.IsAngry())
956  {
957  WolfStatus |= 0x2;
958  }
959  if (Wolf.IsTame())
960  {
961  WolfStatus |= 0x4;
962  }
965  a_Pkt.WriteBEInt8(WolfStatus);
966 
969  a_Pkt.WriteBEFloat(static_cast<float>(a_Mob.GetHealth())); // TODO Not use the current health
970 
971  a_Pkt.WriteBEUInt8(WOLF_BEGGING);
973  a_Pkt.WriteBool(Wolf.IsBegging());
974 
977  a_Pkt.WriteVarInt32(static_cast<UInt32>(Wolf.GetCollarColor()));
978  break;
979  } // case mtWolf
980 
981  case mtZombie:
982  {
983  auto & Zombie = static_cast<const cZombie &>(a_Mob);
986  a_Pkt.WriteBool(Zombie.IsBaby());
987 
988  a_Pkt.WriteBEUInt8(ZOMBIE_TYPE);
990  a_Pkt.WriteVarInt32(Zombie.IsVillagerZombie() ? 1 : 0); // TODO: This actually encodes the zombie villager profession, but that isn't implemented yet.
991 
994  a_Pkt.WriteBool(Zombie.IsConverting());
995  break;
996  } // case mtZombie
997 
998  case mtZombiePigman:
999  {
1000  auto & ZombiePigman = static_cast<const cZombiePigman &>(a_Mob);
1001  a_Pkt.WriteBEUInt8(AGEABLE_BABY);
1003  a_Pkt.WriteBool(ZombiePigman.IsBaby());
1004  break;
1005  } // case mtZombiePigman
1006 
1007  default: break;
1008  } // switch (a_Mob.GetType())
1009 }
virtual void WriteEntityMetadata(cPacketizer &a_Pkt, const cEntity &a_Entity) override
Writes the metadata for the specified entity, not including the terminating 0xff. ...
UInt32 m_State
State of the protocol.
Definition: Protocol_1_9.h:154
Definition: Rabbit.h:25
void WriteBEInt8(Int8 a_Value)
Definition: Packetizer.h:56
void EndList(void)
Definition: FastNBT.cpp:519
eEntityType GetEntityType(void) const
Definition: Entity.h:168
eMonsterType GetMobType(void) const
Definition: Monster.h:68
Definition: Witch.h:10
BLOCKTYPE GetBlockType() const
Definition: BlockEntity.h:111
short m_ItemDamage
Definition: Item.h:211
signed char Int8
Definition: Globals.h:110
const AString & GetCustomName(void) const
Gets the custom name of the monster.
Definition: Monster.h:162
Definition: Boat.h:18
void WriteBuf(const char *a_Data, size_t a_Size)
Definition: Packetizer.h:122
virtual void WriteItem(cPacketizer &a_Pkt, const cItem &a_Item)
Writes the item data into a packet.
void AddShort(const AString &a_Name, Int16 a_Value)
Definition: FastNBT.cpp:544
Definition: Player.h:27
Definition: Ocelot.h:11
virtual void HandlePacketStatusRequest(cByteBuffer &a_ByteBuffer) override
bool IsEmpty(void) const
Definition: Item.h:116
Definition: Cow.h:10
Definition: Bat.h:10
virtual bool IsOnFire(void) const
Definition: Entity.h:486
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
void AddByte(const AString &a_Name, unsigned char a_Value)
Definition: FastNBT.cpp:534
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
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 bool IsInvisible(void) const
Definition: Entity.h:491
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
Definition: Pig.h:10
virtual void WriteBlockEntity(cPacketizer &a_Pkt, const cBlockEntity &a_BlockEntity) override
Writes the block entity data for the specified block entity into the packet.
size_t GetMaxPlayers(void) const
Definition: Server.h:70
void EndCompound(void)
Definition: FastNBT.cpp:482
AString & Printf(AString &str, const char *format, fmt::ArgList args)
Output the formatted text into the string.
Definition: StringUtils.cpp:55
virtual void SendSoundEffect(const AString &a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch) override
float GetHealth(void) const
Returns the health of this entity.
Definition: Entity.h:380
#define ASSERT(x)
Definition: Globals.h:335
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
virtual void WriteMobMetadata(cPacketizer &a_Pkt, const cMonster &a_Mob) override
Writes the mob-specific metadata for the specified mob.
float GetMaxHealth(void) const
Definition: Entity.h:417
unsigned short UInt16
Definition: Globals.h:114
const AString & GetResult(void) const
Definition: FastNBT.h:342
virtual bool IsSprinting(void) const
Definition: Entity.h:489
std::string AString
Definition: StringUtils.h:13
cServer * GetServer(void)
Definition: Root.h:69
Composes an individual packet in the protocol&#39;s m_OutPacketBuffer; sends it just before being destruc...
Definition: Packetizer.h:28
void ForgeAugmentServerListPing(Json::Value &a_Response)
Add the Forge mod list to the server ping response.
Definition: ClientHandle.h:270
static cRoot * Get()
Definition: Root.h:51
void AddString(const AString &a_Name, const AString &a_Value)
Definition: FastNBT.cpp:599
void WriteVarInt32(UInt32 a_Value)
Definition: Packetizer.h:110
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
void AddInt(const AString &a_Name, Int32 a_Value)
Definition: FastNBT.cpp:555
Definition: Wolf.h:12
cProtocol_1_10_0(cClientHandle *a_Client, const AString &a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State)
short m_ItemType
Definition: Item.h:209
Definition: Wither.h:10
void Finish(void)
Definition: FastNBT.cpp:645
void WriteBool(bool a_Value)
Definition: Packetizer.h:45
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
void BeginList(const AString &a_Name, eTagType a_ChildrenType)
Definition: FastNBT.cpp:495
static AString MobTypeToVanillaName(eMonsterType a_MobType)
Translates MobType enum to the vanilla name of the mob, empty string if unknown.
Definition: Monster.cpp:932
Definition: Item.h:36
void BeginCompound(const AString &a_Name)
Definition: FastNBT.cpp:464
Definition: Zombie.h:9
cPluginManager * GetPluginManager(void)
Definition: Root.h:114