1
0

Add 1.11 entity metadata (#3601)

This commit is contained in:
Pokechu22 2017-03-03 01:59:17 -08:00 committed by Mattes D
parent 6ee0e4cafa
commit 19094e7aa6
4 changed files with 845 additions and 5 deletions

View File

@ -28,9 +28,10 @@ SET (HDRS
)
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
set_source_files_properties(Protocol_1_9.cpp PROPERTIES COMPILE_FLAGS "-Wno-error=switch-enum -Wno-error=switch")
set_source_files_properties(Protocol_1_8.cpp PROPERTIES COMPILE_FLAGS "-Wno-error=switch-enum -Wno-error=switch")
set_source_files_properties(Protocol_1_9.cpp PROPERTIES COMPILE_FLAGS "-Wno-error=switch")
set_source_files_properties(Protocol_1_8.cpp PROPERTIES COMPILE_FLAGS "-Wno-error=switch")
set_source_files_properties(Protocol_1_10.cpp PROPERTIES COMPILE_FLAGS "-Wno-error=switch")
set_source_files_properties(Protocol_1_11.cpp PROPERTIES COMPILE_FLAGS "-Wno-error=switch")
endif()
if (NOT MSVC)

View File

@ -865,7 +865,7 @@ void cProtocol_1_10_0::WriteMobMetadata(cPacketizer & a_Pkt, const cMonster & a_
case mtZombie:
{
auto & Zombie = reinterpret_cast<const cZombie &>(a_Mob);
a_Pkt.WriteBEUInt8(AGEABLE_BABY);
a_Pkt.WriteBEUInt8(ZOMBIE_IS_BABY);
a_Pkt.WriteBEUInt8(METADATA_TYPE_BOOL);
a_Pkt.WriteBool(Zombie.IsBaby());

View File

@ -13,13 +13,297 @@ Implements the 1.11 protocol classes:
#include "ProtocolRecognizer.h"
#include "Packetizer.h"
#include "../Entities/Boat.h"
#include "../Entities/ExpOrb.h"
#include "../Entities/Minecart.h"
#include "../Entities/FallingBlock.h"
#include "../Entities/Painting.h"
#include "../Entities/Pickup.h"
#include "../Entities/Player.h"
#include "../Entities/ItemFrame.h"
#include "../Entities/ArrowEntity.h"
#include "../Entities/FireworkEntity.h"
#include "../Entities/SplashPotionEntity.h"
#include "../Mobs/IncludeAllMonsters.h"
#include "../Root.h"
#include "../Server.h"
#include "../ClientHandle.h"
#include "../CompositeChat.h"
#include "../Bindings/PluginManager.h"
#include "../Entities/Player.h"
#include "../Mobs/Monster.h"
// The disabled error is intended, since the Metadata have overlapping indexes
// based on the type of the Entity.
//
// IMPORTANT: The enum is used to automate the sequential counting of the
// Metadata indexes. Adding a new enum value causes the following values to
// increase their index. Therefore the ordering of the enum values is VERY important!
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wduplicate-enum"
#endif
namespace Metadata
{
enum Metadata_Index
{
// Entity
ENTITY_FLAGS,
ENTITY_AIR,
ENTITY_CUSTOM_NAME,
ENTITY_CUSTOM_NAME_VISIBLE,
ENTITY_SILENT,
ENTITY_NO_GRAVITY,
_ENTITY_NEXT, // Used by descendants
// Potion
POTION_THROWN = _ENTITY_NEXT,
// FallingBlock
FALLING_BLOCK_POSITION = _ENTITY_NEXT,
// AreaEffectCloud
AREA_EFFECT_CLOUD_RADIUS = _ENTITY_NEXT,
AREA_EFFECT_CLOUD_COLOR,
AREA_EFFECT_CLOUD_SINGLE_POINT_EFFECT,
AREA_EFFECT_CLOUD_PARTICLE_ID,
AREA_EFFECT_CLOUD_PARTICLE_PARAMETER1,
AREA_EFFECT_CLOUD_PARTICLE_PARAMETER2,
// Arrow
ARROW_CRITICAL = _ENTITY_NEXT,
_ARROW_NEXT,
// TippedArrow
TIPPED_ARROW_COLOR = _ARROW_NEXT,
// Boat
BOAT_LAST_HIT_TIME = _ENTITY_NEXT,
BOAT_FORWARD_DIRECTION,
BOAT_DAMAGE_TAKEN,
BOAT_TYPE,
BOAT_RIGHT_PADDLE_TURNING,
BOAT_LEFT_PADDLE_TURNING,
// EnderCrystal
ENDER_CRYSTAL_BEAM_TARGET = _ENTITY_NEXT,
ENDER_CRYSTAL_SHOW_BOTTOM,
// Fireball
_FIREBALL_NEXT = _ENTITY_NEXT,
// WitherSkull
WITHER_SKULL_INVULNERABLE = _FIREBALL_NEXT,
// Fireworks
FIREWORK_INFO = _ENTITY_NEXT,
FIREWORK_BOOSTED_ENTITY_ID, // 1.11.1 only
// Hanging
_HANGING_NEXT = _ENTITY_NEXT,
// ItemFrame
ITEM_FRAME_ITEM = _HANGING_NEXT,
ITEM_FRAME_ROTATION,
// Item
ITEM_ITEM = _ENTITY_NEXT,
// Living
LIVING_ACTIVE_HAND = _ENTITY_NEXT,
LIVING_HEALTH,
LIVING_POTION_EFFECT_COLOR,
LIVING_POTION_EFFECT_AMBIENT,
LIVING_NUMBER_OF_ARROWS,
_LIVING_NEXT,
// Player
PLAYER_ADDITIONAL_HEARTHS = _LIVING_NEXT,
PLAYER_SCORE,
PLAYER_DISPLAYED_SKIN_PARTS,
PLAYER_MAIN_HAND,
// ArmorStand
ARMOR_STAND_STATUS = _LIVING_NEXT,
ARMOR_STAND_HEAD_ROTATION,
ARMOR_STAND_BODY_ROTATION,
ARMOR_STAND_LEFT_ARM_ROTATION,
ARMOR_STAND_RIGHT_ARM_ROTATION,
ARMOR_STAND_LEFT_LEG_ROTATION,
ARMOR_STAND_RIGHT_LEG_ROTATION,
// Insentient
INSENTIENT_STATUS = _LIVING_NEXT,
_INSENTIENT_NEXT,
// Ambient
_AMBIENT_NEXT = _INSENTIENT_NEXT,
// Bat
BAT_HANGING = _AMBIENT_NEXT,
// Creature
_CREATURE_NEXT = _INSENTIENT_NEXT,
// Ageable
AGEABLE_BABY = _CREATURE_NEXT,
_AGEABLE_NEXT,
// PolarBear
POLAR_BEAR_STANDING = _AGEABLE_NEXT,
// Animal
_ANIMAL_NEXT = _AGEABLE_NEXT,
// Abstract horse
ABSTRACT_HORSE_STATUS = _ANIMAL_NEXT,
ABSTRACT_HORSE_OWNER,
_ABSTRACT_HORSE_NEXT,
// Horse
HORSE_VARIANT = _ABSTRACT_HORSE_NEXT,
HORSE_ARMOR,
// Chested horse
CHESTED_HORSE_CHESTED = _ABSTRACT_HORSE_NEXT,
_CHESTED_HORSE_NEXT,
// Llama
LLAMA_STRENGTH = _CHESTED_HORSE_NEXT,
LLAMA_CARPET_COLOR,
LLAMA_VARIANT,
// Pig
PIG_HAS_SADDLE = _ANIMAL_NEXT,
PIG_TOTAL_CARROT_ON_A_STICK_BOOST, // 1.11.1 only
// Rabbit
RABBIT_TYPE = _ANIMAL_NEXT,
// Sheep
SHEEP_STATUS = _ANIMAL_NEXT,
// TameableAnimal
TAMEABLE_ANIMAL_STATUS = _ANIMAL_NEXT,
TAMEABLE_ANIMAL_OWNER,
_TAMEABLE_NEXT,
// Ocelot
OCELOT_TYPE = _TAMEABLE_NEXT,
// Wolf
WOLF_DAMAGE_TAKEN = _TAMEABLE_NEXT,
WOLF_BEGGING,
WOLF_COLLAR_COLOR,
// Villager
VILLAGER_PROFESSION = _AGEABLE_NEXT,
// Golem
_GOLEM_NEXT = _CREATURE_NEXT,
// IronGolem
IRON_GOLEM_PLAYER_CREATED = _GOLEM_NEXT,
// Shulker
SHULKER_FACING_DIRECTION = _GOLEM_NEXT,
SHULKER_ATTACHMENT_FALLING_BLOCK_POSITION,
SHULKER_SHIELD_HEIGHT,
// Monster
_MONSTER_NEXT = _CREATURE_NEXT,
// Blaze
BLAZE_ON_FIRE = _MONSTER_NEXT,
// Creeper
CREEPER_STATE = _MONSTER_NEXT,
CREEPER_POWERED,
CREEPER_IGNITED,
// Guardian
GUARDIAN_STATUS = _MONSTER_NEXT,
GUARDIAN_TARGET,
// Abstract Skeleton
ABSTRACT_SKELETON_ARMS_SWINGING = _MONSTER_NEXT,
// Spider
SPIDER_CLIMBING = _MONSTER_NEXT,
// Witch
WITCH_AGGRESIVE = _MONSTER_NEXT,
// Wither
WITHER_FIRST_HEAD_TARGET = _MONSTER_NEXT,
WITHER_SECOND_HEAD_TARGET,
WITHER_THIRD_HEAD_TARGET,
WITHER_INVULNERABLE_TIMER,
// Zombie
ZOMBIE_IS_BABY = _MONSTER_NEXT,
ZOMBIE_UNUSED, // Was type
ZOMBIE_HANDS_RISED_UP,
_ZOMBIE_NEXT,
// Zombie villager
ZOMBIE_VILLAGER_CONVERTING = _ZOMBIE_NEXT,
ZOMBIE_VILLAGER_PROFESSION,
// Enderman
ENDERMAN_CARRIED_BLOCK = _MONSTER_NEXT,
ENDERMAN_SCREAMING,
// Evocation illager
EVOKER_SPELL = _MONSTER_NEXT,
// Vex
VEX_FLAGS = _MONSTER_NEXT,
// Vindication illager
VINDICATOR_FLAGS = _MONSTER_NEXT,
// EnderDragon
ENDER_DRAGON_DRAGON_PHASE = _INSENTIENT_NEXT,
// Flying
_FLYING_NEXT = _INSENTIENT_NEXT,
// Ghast
GHAST_ATTACKING = _FLYING_NEXT,
// Slime
SLIME_SIZE = _INSENTIENT_NEXT,
// Minecart
MINECART_SHAKING_POWER = _ENTITY_NEXT,
MINECART_SHAKING_DIRECTION,
MINECART_SHAKING_MULTIPLIER,
MINECART_BLOCK_ID_META,
MINECART_BLOCK_Y,
MINECART_SHOW_BLOCK,
_MINECART_NEXT,
// MinecartCommandBlock
MINECART_COMMAND_BLOCK_COMMAND = _MINECART_NEXT,
MINECART_COMMAND_BLOCK_LAST_OUTPUT,
// MinecartFurnace
MINECART_FURNACE_POWERED = _MINECART_NEXT,
// TNTPrimed
TNT_PRIMED_FUSE_TIME = _ENTITY_NEXT,
};
}
#ifdef __clang__
#pragma clang diagnostic pop // Restore ignored clang errors
#endif
@ -190,6 +474,558 @@ void cProtocol_1_11_0::HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer)
void cProtocol_1_11_0::WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a_Entity)
{
using namespace Metadata;
// Common metadata:
Int8 Flags = 0;
if (a_Entity.IsOnFire())
{
Flags |= 0x01;
}
if (a_Entity.IsCrouched())
{
Flags |= 0x02;
}
if (a_Entity.IsSprinting())
{
Flags |= 0x08;
}
if (a_Entity.IsRclking())
{
Flags |= 0x10;
}
if (a_Entity.IsInvisible())
{
Flags |= 0x20;
}
a_Pkt.WriteBEUInt8(ENTITY_FLAGS); // Index
a_Pkt.WriteBEUInt8(METADATA_TYPE_BYTE); // Type
a_Pkt.WriteBEInt8(Flags);
switch (a_Entity.GetEntityType())
{
case cEntity::etPlayer:
{
auto & Player = reinterpret_cast<const cPlayer &>(a_Entity);
// TODO Set player custom name to their name.
// Then it's possible to move the custom name of mobs to the entities
// and to remove the "special" player custom name.
a_Pkt.WriteBEUInt8(ENTITY_CUSTOM_NAME);
a_Pkt.WriteBEUInt8(METADATA_TYPE_STRING);
a_Pkt.WriteString(Player.GetName());
a_Pkt.WriteBEUInt8(LIVING_HEALTH);
a_Pkt.WriteBEUInt8(METADATA_TYPE_FLOAT);
a_Pkt.WriteBEFloat(static_cast<float>(Player.GetHealth()));
a_Pkt.WriteBEUInt8(PLAYER_DISPLAYED_SKIN_PARTS);
a_Pkt.WriteBEUInt8(METADATA_TYPE_BYTE);
a_Pkt.WriteBEUInt8(static_cast<UInt8>(Player.GetSkinParts()));
a_Pkt.WriteBEUInt8(PLAYER_MAIN_HAND);
a_Pkt.WriteBEUInt8(METADATA_TYPE_BYTE);
a_Pkt.WriteBEUInt8(static_cast<UInt8>(Player.GetMainHand()));
break;
}
case cEntity::etPickup:
{
a_Pkt.WriteBEUInt8(ITEM_ITEM);
a_Pkt.WriteBEUInt8(METADATA_TYPE_ITEM);
WriteItem(a_Pkt, reinterpret_cast<const cPickup &>(a_Entity).GetItem());
break;
}
case cEntity::etMinecart:
{
a_Pkt.WriteBEUInt8(MINECART_SHAKING_POWER);
a_Pkt.WriteBEUInt8(METADATA_TYPE_VARINT);
// The following expression makes Minecarts shake more with less health or higher damage taken
auto & Minecart = reinterpret_cast<const cMinecart &>(a_Entity);
auto maxHealth = a_Entity.GetMaxHealth();
auto curHealth = a_Entity.GetHealth();
a_Pkt.WriteVarInt32(static_cast<UInt32>((maxHealth - curHealth) * Minecart.LastDamage() * 4));
a_Pkt.WriteBEUInt8(MINECART_SHAKING_DIRECTION); // (doesn't seem to effect anything)
a_Pkt.WriteBEUInt8(METADATA_TYPE_VARINT);
a_Pkt.WriteVarInt32(1);
a_Pkt.WriteBEUInt8(MINECART_SHAKING_MULTIPLIER); // or damage taken
a_Pkt.WriteBEUInt8(METADATA_TYPE_FLOAT);
a_Pkt.WriteBEFloat(static_cast<float>(Minecart.LastDamage() + 10));
if (Minecart.GetPayload() == cMinecart::mpNone)
{
auto & RideableMinecart = reinterpret_cast<const cRideableMinecart &>(Minecart);
const cItem & MinecartContent = RideableMinecart.GetContent();
if (!MinecartContent.IsEmpty())
{
a_Pkt.WriteBEUInt8(MINECART_BLOCK_ID_META);
a_Pkt.WriteBEUInt8(METADATA_TYPE_VARINT);
int Content = MinecartContent.m_ItemType;
Content |= MinecartContent.m_ItemDamage << 8;
a_Pkt.WriteVarInt32(static_cast<UInt32>(Content));
a_Pkt.WriteBEUInt8(MINECART_BLOCK_Y);
a_Pkt.WriteBEUInt8(METADATA_TYPE_VARINT);
a_Pkt.WriteVarInt32(static_cast<UInt32>(RideableMinecart.GetBlockHeight()));
a_Pkt.WriteBEUInt8(MINECART_SHOW_BLOCK);
a_Pkt.WriteBEUInt8(METADATA_TYPE_BOOL);
a_Pkt.WriteBool(true);
}
}
else if (Minecart.GetPayload() == cMinecart::mpFurnace)
{
a_Pkt.WriteBEUInt8(MINECART_FURNACE_POWERED);
a_Pkt.WriteBEUInt8(METADATA_TYPE_BOOL);
a_Pkt.WriteBool(reinterpret_cast<const cMinecartWithFurnace &>(Minecart).IsFueled());
}
break;
} // case etMinecart
case cEntity::etProjectile:
{
auto & Projectile = reinterpret_cast<const cProjectileEntity &>(a_Entity);
switch (Projectile.GetProjectileKind())
{
case cProjectileEntity::pkArrow:
{
a_Pkt.WriteBEUInt8(ARROW_CRITICAL);
a_Pkt.WriteBEUInt8(METADATA_TYPE_BYTE);
a_Pkt.WriteBEInt8(reinterpret_cast<const cArrowEntity &>(Projectile).IsCritical() ? 1 : 0);
break;
}
case cProjectileEntity::pkFirework:
{
a_Pkt.WriteBEUInt8(FIREWORK_INFO); // Firework item used for this firework
a_Pkt.WriteBEUInt8(METADATA_TYPE_ITEM);
WriteItem(a_Pkt, reinterpret_cast<const cFireworkEntity &>(Projectile).GetItem());
// FIREWORK_BOOSTED_ENTITY_ID, in 1.11.1 only
break;
}
case cProjectileEntity::pkSplashPotion:
{
a_Pkt.WriteBEUInt8(POTION_THROWN); // Potion item which was thrown
a_Pkt.WriteBEUInt8(METADATA_TYPE_ITEM);
WriteItem(a_Pkt, reinterpret_cast<const cSplashPotionEntity &>(Projectile).GetItem());
}
default:
{
break;
}
}
break;
} // case etProjectile
case cEntity::etMonster:
{
WriteMobMetadata(a_Pkt, reinterpret_cast<const cMonster &>(a_Entity));
break;
}
case cEntity::etBoat:
{
auto & Boat = reinterpret_cast<const cBoat &>(a_Entity);
a_Pkt.WriteBEInt8(BOAT_LAST_HIT_TIME);
a_Pkt.WriteBEInt8(METADATA_TYPE_VARINT);
a_Pkt.WriteBEInt32(Boat.GetLastDamage());
a_Pkt.WriteBEInt8(BOAT_FORWARD_DIRECTION);
a_Pkt.WriteBEInt8(METADATA_TYPE_VARINT);
a_Pkt.WriteBEInt32(Boat.GetForwardDirection());
a_Pkt.WriteBEInt8(BOAT_DAMAGE_TAKEN);
a_Pkt.WriteBEInt8(METADATA_TYPE_FLOAT);
a_Pkt.WriteBEFloat(Boat.GetDamageTaken());
a_Pkt.WriteBEInt8(BOAT_TYPE);
a_Pkt.WriteBEInt8(METADATA_TYPE_VARINT);
a_Pkt.WriteBEInt32(Boat.GetType());
a_Pkt.WriteBEInt8(BOAT_RIGHT_PADDLE_TURNING);
a_Pkt.WriteBEInt8(METADATA_TYPE_BOOL);
a_Pkt.WriteBool(Boat.IsRightPaddleUsed());
a_Pkt.WriteBEInt8(BOAT_LEFT_PADDLE_TURNING);
a_Pkt.WriteBEInt8(METADATA_TYPE_BOOL);
a_Pkt.WriteBool(Boat.IsLeftPaddleUsed());
break;
} // case etBoat
case cEntity::etItemFrame:
{
auto & Frame = reinterpret_cast<const cItemFrame &>(a_Entity);
a_Pkt.WriteBEUInt8(ITEM_FRAME_ITEM);
a_Pkt.WriteBEUInt8(METADATA_TYPE_ITEM);
WriteItem(a_Pkt, Frame.GetItem());
a_Pkt.WriteBEUInt8(ITEM_FRAME_ROTATION);
a_Pkt.WriteBEUInt8(METADATA_TYPE_VARINT);
a_Pkt.WriteVarInt32(Frame.GetItemRotation());
break;
} // case etItemFrame
default:
{
break;
}
}
}
void cProtocol_1_11_0::WriteMobMetadata(cPacketizer & a_Pkt, const cMonster & a_Mob)
{
using namespace Metadata;
// Living Enitiy Metadata
if (a_Mob.HasCustomName())
{
// TODO: As of 1.9 _all_ entities can have custom names; should this be moved up?
a_Pkt.WriteBEUInt8(ENTITY_CUSTOM_NAME);
a_Pkt.WriteBEUInt8(METADATA_TYPE_STRING);
a_Pkt.WriteString(a_Mob.GetCustomName());
a_Pkt.WriteBEUInt8(ENTITY_CUSTOM_NAME_VISIBLE); // Custom name always visible
a_Pkt.WriteBEUInt8(METADATA_TYPE_BOOL);
a_Pkt.WriteBool(a_Mob.IsCustomNameAlwaysVisible());
}
a_Pkt.WriteBEUInt8(LIVING_HEALTH);
a_Pkt.WriteBEUInt8(METADATA_TYPE_FLOAT);
a_Pkt.WriteBEFloat(static_cast<float>(a_Mob.GetHealth()));
switch (a_Mob.GetMobType())
{
case mtBat:
{
auto & Bat = reinterpret_cast<const cBat &>(a_Mob);
a_Pkt.WriteBEUInt8(BAT_HANGING);
a_Pkt.WriteBEUInt8(METADATA_TYPE_BYTE);
a_Pkt.WriteBEInt8(Bat.IsHanging() ? 1 : 0);
break;
} // case mtBat
case mtCreeper:
{
auto & Creeper = reinterpret_cast<const cCreeper &>(a_Mob);
a_Pkt.WriteBEUInt8(CREEPER_STATE); // (idle or "blowing")
a_Pkt.WriteBEUInt8(METADATA_TYPE_VARINT);
a_Pkt.WriteVarInt32(Creeper.IsBlowing() ? 1 : static_cast<UInt32>(-1));
a_Pkt.WriteBEUInt8(CREEPER_POWERED);
a_Pkt.WriteBEUInt8(METADATA_TYPE_BOOL);
a_Pkt.WriteBool(Creeper.IsCharged());
a_Pkt.WriteBEUInt8(CREEPER_IGNITED);
a_Pkt.WriteBEUInt8(METADATA_TYPE_BOOL);
a_Pkt.WriteBool(Creeper.IsBurnedWithFlintAndSteel());
break;
} // case mtCreeper
case mtEnderman:
{
auto & Enderman = reinterpret_cast<const cEnderman &>(a_Mob);
a_Pkt.WriteBEUInt8(ENDERMAN_CARRIED_BLOCK);
a_Pkt.WriteBEUInt8(METADATA_TYPE_BLOCKID);
UInt32 Carried = 0;
Carried |= static_cast<UInt32>(Enderman.GetCarriedBlock() << 4);
Carried |= Enderman.GetCarriedMeta();
a_Pkt.WriteVarInt32(Carried);
a_Pkt.WriteBEUInt8(ENDERMAN_SCREAMING);
a_Pkt.WriteBEUInt8(METADATA_TYPE_BOOL);
a_Pkt.WriteBool(Enderman.IsScreaming());
break;
} // case mtEnderman
case mtGhast:
{
auto & Ghast = reinterpret_cast<const cGhast &>(a_Mob);
a_Pkt.WriteBEUInt8(GHAST_ATTACKING);
a_Pkt.WriteBEUInt8(METADATA_TYPE_BOOL);
a_Pkt.WriteBool(Ghast.IsCharging());
break;
} // case mtGhast
case mtHorse:
{
// XXX This behaves incorrectly with different varients; horses have different entity IDs now
// Abstract horse
auto & Horse = reinterpret_cast<const cHorse &>(a_Mob);
Int8 Flags = 0;
if (Horse.IsTame())
{
Flags |= 0x02;
}
if (Horse.IsSaddled())
{
Flags |= 0x04;
}
if (Horse.IsChested())
{
Flags |= 0x08;
}
if (Horse.IsEating())
{
Flags |= 0x20;
}
if (Horse.IsRearing())
{
Flags |= 0x40;
}
if (Horse.IsMthOpen())
{
Flags |= 0x80;
}
a_Pkt.WriteBEUInt8(ABSTRACT_HORSE_STATUS);
a_Pkt.WriteBEUInt8(METADATA_TYPE_BYTE);
a_Pkt.WriteBEInt8(Flags);
// This doesn't exist any more; it'll cause horses to all be the normal type
// a_Pkt.WriteBEUInt8(HORSE_TYPE);
// a_Pkt.WriteBEUInt8(METADATA_TYPE_VARINT);
// a_Pkt.WriteVarInt32(static_cast<UInt32>(Horse.GetHorseType()));
// Regular horses
a_Pkt.WriteBEUInt8(HORSE_VARIANT); // Color / style
a_Pkt.WriteBEUInt8(METADATA_TYPE_VARINT);
int Appearance = 0;
Appearance = Horse.GetHorseColor();
Appearance |= Horse.GetHorseStyle() << 8;
a_Pkt.WriteVarInt32(static_cast<UInt32>(Appearance));
a_Pkt.WriteBEUInt8(HORSE_ARMOR);
a_Pkt.WriteBEUInt8(METADATA_TYPE_VARINT);
a_Pkt.WriteVarInt32(static_cast<UInt32>(Horse.GetHorseArmour()));
a_Pkt.WriteBEUInt8(AGEABLE_BABY);
a_Pkt.WriteBEUInt8(METADATA_TYPE_BOOL);
a_Pkt.WriteBool(Horse.IsBaby());
break;
} // case mtHorse
case mtMagmaCube:
{
auto & MagmaCube = reinterpret_cast<const cMagmaCube &>(a_Mob);
a_Pkt.WriteBEUInt8(SLIME_SIZE);
a_Pkt.WriteBEUInt8(METADATA_TYPE_VARINT);
a_Pkt.WriteVarInt32(static_cast<UInt32>(MagmaCube.GetSize()));
break;
} // case mtMagmaCube
case mtOcelot:
{
auto & Ocelot = reinterpret_cast<const cOcelot &>(a_Mob);
a_Pkt.WriteBEUInt8(AGEABLE_BABY);
a_Pkt.WriteBEUInt8(METADATA_TYPE_BOOL);
a_Pkt.WriteBool(Ocelot.IsBaby());
break;
} // case mtOcelot
case mtCow:
{
auto & Cow = reinterpret_cast<const cCow &>(a_Mob);
a_Pkt.WriteBEUInt8(AGEABLE_BABY);
a_Pkt.WriteBEUInt8(METADATA_TYPE_BOOL);
a_Pkt.WriteBool(Cow.IsBaby());
break;
} // case mtCow
case mtChicken:
{
auto & Chicken = reinterpret_cast<const cChicken &>(a_Mob);
a_Pkt.WriteBEUInt8(AGEABLE_BABY);
a_Pkt.WriteBEUInt8(METADATA_TYPE_BOOL);
a_Pkt.WriteBool(Chicken.IsBaby());
break;
} // case mtChicken
case mtPig:
{
auto & Pig = reinterpret_cast<const cPig &>(a_Mob);
a_Pkt.WriteBEUInt8(AGEABLE_BABY);
a_Pkt.WriteBEUInt8(METADATA_TYPE_BOOL);
a_Pkt.WriteBool(Pig.IsBaby());
a_Pkt.WriteBEUInt8(PIG_HAS_SADDLE);
a_Pkt.WriteBEUInt8(METADATA_TYPE_BOOL);
a_Pkt.WriteBool(Pig.IsSaddled());
// PIG_TOTAL_CARROT_ON_A_STICK_BOOST in 1.11.1 only
break;
} // case mtPig
case mtSheep:
{
auto & Sheep = reinterpret_cast<const cSheep &>(a_Mob);
a_Pkt.WriteBEUInt8(AGEABLE_BABY);
a_Pkt.WriteBEUInt8(METADATA_TYPE_BOOL);
a_Pkt.WriteBool(Sheep.IsBaby());
a_Pkt.WriteBEUInt8(SHEEP_STATUS);
a_Pkt.WriteBEUInt8(METADATA_TYPE_BYTE);
Int8 SheepMetadata = 0;
SheepMetadata = static_cast<Int8>(Sheep.GetFurColor());
if (Sheep.IsSheared())
{
SheepMetadata |= 0x10;
}
a_Pkt.WriteBEInt8(SheepMetadata);
break;
} // case mtSheep
case mtRabbit:
{
auto & Rabbit = reinterpret_cast<const cRabbit &>(a_Mob);
a_Pkt.WriteBEUInt8(AGEABLE_BABY);
a_Pkt.WriteBEUInt8(METADATA_TYPE_BOOL);
a_Pkt.WriteBool(Rabbit.IsBaby());
a_Pkt.WriteBEUInt8(RABBIT_TYPE);
a_Pkt.WriteBEUInt8(METADATA_TYPE_VARINT);
a_Pkt.WriteVarInt32(static_cast<UInt32>(Rabbit.GetRabbitType()));
break;
} // case mtRabbit
case mtSkeleton:
{
// XXX Skeletons are separate entities; all skeletons are currently treated as regular ones
// auto & Skeleton = reinterpret_cast<const cSkeleton &>(a_Mob);
// a_Pkt.WriteBEUInt8(SKELETON_TYPE);
// a_Pkt.WriteBEUInt8(METADATA_TYPE_VARINT);
// a_Pkt.WriteVarInt32(Skeleton.IsWither() ? 1 : 0);
break;
} // case mtSkeleton
case mtSlime:
{
auto & Slime = reinterpret_cast<const cSlime &>(a_Mob);
a_Pkt.WriteBEUInt8(SLIME_SIZE);
a_Pkt.WriteBEUInt8(METADATA_TYPE_VARINT);
a_Pkt.WriteVarInt32(static_cast<UInt32>(Slime.GetSize()));
break;
} // case mtSlime
case mtVillager:
{
auto & Villager = reinterpret_cast<const cVillager &>(a_Mob);
a_Pkt.WriteBEUInt8(AGEABLE_BABY);
a_Pkt.WriteBEUInt8(METADATA_TYPE_BOOL);
a_Pkt.WriteBool(Villager.IsBaby());
a_Pkt.WriteBEUInt8(VILLAGER_PROFESSION);
a_Pkt.WriteBEUInt8(METADATA_TYPE_VARINT);
a_Pkt.WriteVarInt32(static_cast<UInt32>(Villager.GetVilType()));
break;
} // case mtVillager
case mtWitch:
{
auto & Witch = reinterpret_cast<const cWitch &>(a_Mob);
a_Pkt.WriteBEUInt8(WITCH_AGGRESIVE);
a_Pkt.WriteBEUInt8(METADATA_TYPE_BOOL);
a_Pkt.WriteBool(Witch.IsAngry());
break;
} // case mtWitch
case mtWither:
{
auto & Wither = reinterpret_cast<const cWither &>(a_Mob);
a_Pkt.WriteBEUInt8(WITHER_INVULNERABLE_TIMER);
a_Pkt.WriteBEUInt8(METADATA_TYPE_VARINT);
a_Pkt.WriteVarInt32(Wither.GetWitherInvulnerableTicks());
// TODO: Use boss bar packet for health
break;
} // case mtWither
case mtWolf:
{
auto & Wolf = reinterpret_cast<const cWolf &>(a_Mob);
a_Pkt.WriteBEUInt8(AGEABLE_BABY);
a_Pkt.WriteBEUInt8(METADATA_TYPE_BOOL);
a_Pkt.WriteBool(Wolf.IsBaby());
Int8 WolfStatus = 0;
if (Wolf.IsSitting())
{
WolfStatus |= 0x1;
}
if (Wolf.IsAngry())
{
WolfStatus |= 0x2;
}
if (Wolf.IsTame())
{
WolfStatus |= 0x4;
}
a_Pkt.WriteBEUInt8(TAMEABLE_ANIMAL_STATUS);
a_Pkt.WriteBEUInt8(METADATA_TYPE_BYTE);
a_Pkt.WriteBEInt8(WolfStatus);
a_Pkt.WriteBEUInt8(WOLF_DAMAGE_TAKEN);
a_Pkt.WriteBEUInt8(METADATA_TYPE_FLOAT);
a_Pkt.WriteBEFloat(static_cast<float>(a_Mob.GetHealth())); // TODO Not use the current health
a_Pkt.WriteBEUInt8(WOLF_BEGGING);
a_Pkt.WriteBEUInt8(METADATA_TYPE_BOOL);
a_Pkt.WriteBool(Wolf.IsBegging());
a_Pkt.WriteBEUInt8(WOLF_COLLAR_COLOR);
a_Pkt.WriteBEUInt8(METADATA_TYPE_VARINT);
a_Pkt.WriteVarInt32(static_cast<UInt32>(Wolf.GetCollarColor()));
break;
} // case mtWolf
case mtZombie:
{
// XXX Zombies were also split into new sublcasses; this doesn't handle that.
auto & Zombie = reinterpret_cast<const cZombie &>(a_Mob);
a_Pkt.WriteBEUInt8(ZOMBIE_IS_BABY);
a_Pkt.WriteBEUInt8(METADATA_TYPE_BOOL);
a_Pkt.WriteBool(Zombie.IsBaby());
// These don't exist
// a_Pkt.WriteBEUInt8(ZOMBIE_TYPE);
// a_Pkt.WriteBEUInt8(METADATA_TYPE_VARINT);
// a_Pkt.WriteVarInt32(Zombie.IsVillagerZombie() ? 1 : 0);
// a_Pkt.WriteBEUInt8(ZOMBIE_CONVERTING);
// a_Pkt.WriteBEUInt8(METADATA_TYPE_BOOL);
// a_Pkt.WriteBool(Zombie.IsConverting());
break;
} // case mtZombie
case mtZombiePigman:
{
auto & ZombiePigman = reinterpret_cast<const cZombiePigman &>(a_Mob);
a_Pkt.WriteBEUInt8(AGEABLE_BABY);
a_Pkt.WriteBEUInt8(METADATA_TYPE_BOOL);
a_Pkt.WriteBool(ZombiePigman.IsBaby());
break;
} // case mtZombiePigman
} // switch (a_Mob.GetType())
}
cProtocol_1_11_1::cProtocol_1_11_1(cClientHandle * a_Client, const AString & a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State) :
super(a_Client, a_ServerAddress, a_ServerPort, a_State)
{

View File

@ -38,6 +38,9 @@ protected:
virtual void HandlePacketBlockPlace (cByteBuffer & a_ByteBuffer) override;
virtual void HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer) override;
virtual void WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a_Entity) override;
virtual void WriteMobMetadata(cPacketizer & a_Pkt, const cMonster & a_Mob) override;
};