summaryrefslogtreecommitdiffstats
path: root/src/Protocol/Protocol_1_9.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/Protocol/Protocol_1_9.cpp')
-rw-r--r--src/Protocol/Protocol_1_9.cpp433
1 files changed, 209 insertions, 224 deletions
diff --git a/src/Protocol/Protocol_1_9.cpp b/src/Protocol/Protocol_1_9.cpp
index 6b240b235..e6f774bdf 100644
--- a/src/Protocol/Protocol_1_9.cpp
+++ b/src/Protocol/Protocol_1_9.cpp
@@ -51,9 +51,11 @@ Implements the 1.9 protocol classes:
-/** Value for main hand in Hand parameter for Protocol 1.9. */
-static const UInt32 MAIN_HAND = 0;
-static const UInt32 OFF_HAND = 1;
+// Value for main hand in Hand parameter for Protocol 1.9.
+#define MAIN_HAND 0
+
+// Value for left hand in MainHand parameter for Protocol 1.9.
+#define LEFT_HAND 0
@@ -602,7 +604,7 @@ void cProtocol_1_9_0::SendUnloadChunk(int a_ChunkX, int a_ChunkZ)
-UInt32 cProtocol_1_9_0::GetPacketID(cProtocol::ePacketType a_Packet)
+UInt32 cProtocol_1_9_0::GetPacketID(cProtocol::ePacketType a_Packet) const
{
switch (a_Packet)
{
@@ -726,22 +728,22 @@ signed char cProtocol_1_9_0::GetProtocolEntityStatus(const EntityAnimation a_Ani
-cProtocol::Version cProtocol_1_9_0::GetProtocolVersion()
+UInt32 cProtocol_1_9_0::GetProtocolMobType(const eMonsterType a_MobType) const
{
- return Version::v1_9_0;
+ switch (a_MobType)
+ {
+ case mtShulker: return 69;
+ default: return Super::GetProtocolMobType(a_MobType);
+ }
}
-UInt32 cProtocol_1_9_0::GetProtocolMobType(const eMonsterType a_MobType)
+cProtocol::Version cProtocol_1_9_0::GetProtocolVersion() const
{
- switch (a_MobType)
- {
- case mtShulker: return 69;
- default: return Super::GetProtocolMobType(a_MobType);
- }
+ return Version::v1_9_0;
}
@@ -824,7 +826,7 @@ void cProtocol_1_9_0::HandlePacketAnimation(cByteBuffer & a_ByteBuffer)
{
HANDLE_READ(a_ByteBuffer, ReadVarInt, Int32, Hand);
- m_Client->HandleAnimation(0); // Packet exists solely for arm-swing notification
+ m_Client->HandleAnimation(Hand == MAIN_HAND); // Packet exists solely for arm-swing notification (main and off-hand).
}
@@ -862,7 +864,8 @@ void cProtocol_1_9_0::HandlePacketBlockPlace(cByteBuffer & a_ByteBuffer)
HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, CursorX);
HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, CursorY);
HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, CursorZ);
- m_Client->HandleRightClick(BlockX, BlockY, BlockZ, FaceIntToBlockFace(Face), CursorX, CursorY, CursorZ, HandIntToEnum(Hand));
+
+ m_Client->HandleRightClick(BlockX, BlockY, BlockZ, FaceIntToBlockFace(Face), CursorX, CursorY, CursorZ, Hand == MAIN_HAND);
}
@@ -899,12 +902,12 @@ void cProtocol_1_9_0::HandlePacketClientSettings(cByteBuffer & a_ByteBuffer)
HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, ChatFlags);
HANDLE_READ(a_ByteBuffer, ReadBool, bool, ChatColors);
HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, SkinParts);
- HANDLE_READ(a_ByteBuffer, ReadVarInt, UInt32, MainHand);
+ HANDLE_READ(a_ByteBuffer, ReadVarInt, UInt32, MainHand);
m_Client->SetLocale(Locale);
m_Client->SetViewDistance(ViewDistance);
m_Client->GetPlayer()->SetSkinParts(SkinParts);
- m_Client->GetPlayer()->SetMainHand(static_cast<eMainHand>(MainHand));
+ m_Client->GetPlayer()->SetLeftHanded(MainHand == LEFT_HAND);
// TODO: Handle chat flags and chat colors
}
@@ -964,7 +967,7 @@ void cProtocol_1_9_0::HandlePacketPlayerPos(cByteBuffer & a_ByteBuffer)
if (m_IsTeleportIdConfirmed)
{
- m_Client->HandlePlayerPos(PosX, PosY, PosZ, IsOnGround);
+ m_Client->HandlePlayerMove(PosX, PosY, PosZ, IsOnGround);
}
}
@@ -1065,6 +1068,7 @@ void cProtocol_1_9_0::HandlePacketUseEntity(cByteBuffer & a_ByteBuffer)
case 0:
{
HANDLE_READ(a_ByteBuffer, ReadVarInt, UInt32, Hand);
+
if (Hand == MAIN_HAND) // TODO: implement handling of off-hand actions; ignore them for now to avoid processing actions twice
{
m_Client->HandleUseEntity(EntityID, false);
@@ -1102,7 +1106,7 @@ void cProtocol_1_9_0::HandlePacketUseItem(cByteBuffer & a_ByteBuffer)
{
HANDLE_READ(a_ByteBuffer, ReadVarInt, Int32, Hand);
- m_Client->HandleUseItem(HandIntToEnum(Hand));
+ m_Client->HandleUseItem(Hand == MAIN_HAND);
}
@@ -1193,7 +1197,7 @@ void cProtocol_1_9_0::HandlePacketWindowClick(cByteBuffer & a_ByteBuffer)
-void cProtocol_1_9_0::ParseItemMetadata(cItem & a_Item, const ContiguousByteBufferView a_Metadata)
+void cProtocol_1_9_0::ParseItemMetadata(cItem & a_Item, const ContiguousByteBufferView a_Metadata) const
{
// Parse into NBT:
cParsedNBT NBT(a_Metadata);
@@ -1397,25 +1401,6 @@ void cProtocol_1_9_0::ParseItemMetadata(cItem & a_Item, const ContiguousByteBuff
-eHand cProtocol_1_9_0::HandIntToEnum(Int32 a_Hand)
-{
- // Convert hand parameter into eHand enum
- switch (a_Hand)
- {
- case MAIN_HAND: return eHand::hMain;
- case OFF_HAND: return eHand::hOff;
- default:
- {
- ASSERT(!"Unknown hand value");
- return eHand::hMain;
- }
- }
-}
-
-
-
-
-
void cProtocol_1_9_0::SendEntitySpawn(const cEntity & a_Entity, const UInt8 a_ObjectType, const Int32 a_ObjectData)
{
ASSERT(m_State == 3); // In game mode?
@@ -1443,7 +1428,7 @@ void cProtocol_1_9_0::SendEntitySpawn(const cEntity & a_Entity, const UInt8 a_Ob
-void cProtocol_1_9_0::WriteBlockEntity(cFastNBTWriter & a_Writer, const cBlockEntity & a_BlockEntity)
+void cProtocol_1_9_0::WriteBlockEntity(cFastNBTWriter & a_Writer, const cBlockEntity & a_BlockEntity) const
{
a_Writer.AddInt("x", a_BlockEntity.GetPosX());
a_Writer.AddInt("y", a_BlockEntity.GetPosY());
@@ -1467,177 +1452,7 @@ void cProtocol_1_9_0::WriteBlockEntity(cFastNBTWriter & a_Writer, const cBlockEn
-void cProtocol_1_9_0::WriteItem(cPacketizer & a_Pkt, const cItem & a_Item)
-{
- short ItemType = a_Item.m_ItemType;
- ASSERT(ItemType >= -1); // Check validity of packets in debug runtime
- if (ItemType <= 0)
- {
- // Fix, to make sure no invalid values are sent.
- ItemType = -1;
- }
-
- if (a_Item.IsEmpty())
- {
- a_Pkt.WriteBEInt16(-1);
- return;
- }
-
- if ((ItemType == E_ITEM_POTION) && ((a_Item.m_ItemDamage & 0x4000) != 0))
- {
- // Ugly special case for splash potion ids which changed in 1.9; this can be removed when the new 1.9 ids are implemented
- a_Pkt.WriteBEInt16(438); // minecraft:splash_potion
- }
- else
- {
- // Normal item
- a_Pkt.WriteBEInt16(ItemType);
- }
- a_Pkt.WriteBEInt8(a_Item.m_ItemCount);
- if ((ItemType == E_ITEM_POTION) || (ItemType == E_ITEM_SPAWN_EGG))
- {
- // These items lost their metadata; if it is sent they don't render correctly.
- a_Pkt.WriteBEInt16(0);
- }
- else
- {
- a_Pkt.WriteBEInt16(a_Item.m_ItemDamage);
- }
-
- if (a_Item.m_Enchantments.IsEmpty() && a_Item.IsBothNameAndLoreEmpty() && (ItemType != E_ITEM_FIREWORK_ROCKET) && (ItemType != E_ITEM_FIREWORK_STAR) && !a_Item.m_ItemColor.IsValid() && (ItemType != E_ITEM_POTION) && (ItemType != E_ITEM_SPAWN_EGG))
- {
- a_Pkt.WriteBEInt8(0);
- return;
- }
-
-
- // Send the enchantments and custom names:
- cFastNBTWriter Writer;
- if (a_Item.m_RepairCost != 0)
- {
- Writer.AddInt("RepairCost", a_Item.m_RepairCost);
- }
- if (!a_Item.m_Enchantments.IsEmpty())
- {
- const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench";
- EnchantmentSerializer::WriteToNBTCompound(a_Item.m_Enchantments, Writer, TagName);
- }
- if (!a_Item.IsBothNameAndLoreEmpty() || a_Item.m_ItemColor.IsValid())
- {
- Writer.BeginCompound("display");
- if (a_Item.m_ItemColor.IsValid())
- {
- Writer.AddInt("color", static_cast<Int32>(a_Item.m_ItemColor.m_Color));
- }
-
- if (!a_Item.IsCustomNameEmpty())
- {
- Writer.AddString("Name", a_Item.m_CustomName);
- }
- if (!a_Item.IsLoreEmpty())
- {
- Writer.BeginList("Lore", TAG_String);
-
- for (const auto & Line : a_Item.m_LoreTable)
- {
- Writer.AddString("", Line);
- }
-
- Writer.EndList();
- }
- Writer.EndCompound();
- }
- if ((a_Item.m_ItemType == E_ITEM_FIREWORK_ROCKET) || (a_Item.m_ItemType == E_ITEM_FIREWORK_STAR))
- {
- cFireworkItem::WriteToNBTCompound(a_Item.m_FireworkItem, Writer, static_cast<ENUM_ITEM_TYPE>(a_Item.m_ItemType));
- }
- if (a_Item.m_ItemType == E_ITEM_POTION)
- {
- // 1.9 potions use a different format. In the future (when only 1.9+ is supported) this should be its own class
- AString PotionID = "empty"; // Fallback of "Uncraftable potion" for unhandled cases
-
- cEntityEffect::eType Type = cEntityEffect::GetPotionEffectType(a_Item.m_ItemDamage);
- if (Type != cEntityEffect::effNoEffect)
- {
- switch (Type)
- {
- case cEntityEffect::effRegeneration: PotionID = "regeneration"; break;
- case cEntityEffect::effSpeed: PotionID = "swiftness"; break;
- case cEntityEffect::effFireResistance: PotionID = "fire_resistance"; break;
- case cEntityEffect::effPoison: PotionID = "poison"; break;
- case cEntityEffect::effInstantHealth: PotionID = "healing"; break;
- case cEntityEffect::effNightVision: PotionID = "night_vision"; break;
- case cEntityEffect::effWeakness: PotionID = "weakness"; break;
- case cEntityEffect::effStrength: PotionID = "strength"; break;
- case cEntityEffect::effSlowness: PotionID = "slowness"; break;
- case cEntityEffect::effJumpBoost: PotionID = "leaping"; break;
- case cEntityEffect::effInstantDamage: PotionID = "harming"; break;
- case cEntityEffect::effWaterBreathing: PotionID = "water_breathing"; break;
- case cEntityEffect::effInvisibility: PotionID = "invisibility"; break;
- default: ASSERT(!"Unknown potion effect"); break;
- }
- if (cEntityEffect::GetPotionEffectIntensity(a_Item.m_ItemDamage) == 1)
- {
- PotionID = "strong_" + PotionID;
- }
- else if (a_Item.m_ItemDamage & 0x40)
- {
- // Extended potion bit
- PotionID = "long_" + PotionID;
- }
- }
- else
- {
- // Empty potions: Water bottles and other base ones
- if (a_Item.m_ItemDamage == 0)
- {
- // No other bits set; thus it's a water bottle
- PotionID = "water";
- }
- else
- {
- switch (a_Item.m_ItemDamage & 0x3f)
- {
- case 0x00: PotionID = "mundane"; break;
- case 0x10: PotionID = "awkward"; break;
- case 0x20: PotionID = "thick"; break;
- }
- // Default cases will use "empty" from before.
- }
- }
-
- PotionID = "minecraft:" + PotionID;
-
- Writer.AddString("Potion", PotionID);
- }
- if (a_Item.m_ItemType == E_ITEM_SPAWN_EGG)
- {
- // Convert entity ID to the name.
- eMonsterType MonsterType = cItemSpawnEggHandler::ItemDamageToMonsterType(a_Item.m_ItemDamage);
- if (MonsterType != eMonsterType::mtInvalidType)
- {
- Writer.BeginCompound("EntityTag");
- Writer.AddString("id", "minecraft:" + cMonster::MobTypeToVanillaNBT(MonsterType));
- Writer.EndCompound();
- }
- }
-
- Writer.Finish();
-
- const auto Result = Writer.GetResult();
- if (Result.empty())
- {
- a_Pkt.WriteBEInt8(0);
- return;
- }
- a_Pkt.WriteBuf(Result);
-}
-
-
-
-
-
-void cProtocol_1_9_0::WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a_Entity)
+void cProtocol_1_9_0::WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a_Entity) const
{
// Common metadata:
Int8 Flags = 0;
@@ -1692,7 +1507,7 @@ void cProtocol_1_9_0::WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a
a_Pkt.WriteBEUInt8(13);
a_Pkt.WriteBEUInt8(METADATA_TYPE_BYTE);
- a_Pkt.WriteBEUInt8(static_cast<UInt8>(Player.GetMainHand()));
+ a_Pkt.WriteBEUInt8(Player.IsLeftHanded() ? 0 : 1);
break;
}
case cEntity::etPickup:
@@ -1859,7 +1674,177 @@ void cProtocol_1_9_0::WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a
-void cProtocol_1_9_0::WriteMobMetadata(cPacketizer & a_Pkt, const cMonster & a_Mob)
+void cProtocol_1_9_0::WriteItem(cPacketizer & a_Pkt, const cItem & a_Item) const
+{
+ short ItemType = a_Item.m_ItemType;
+ ASSERT(ItemType >= -1); // Check validity of packets in debug runtime
+ if (ItemType <= 0)
+ {
+ // Fix, to make sure no invalid values are sent.
+ ItemType = -1;
+ }
+
+ if (a_Item.IsEmpty())
+ {
+ a_Pkt.WriteBEInt16(-1);
+ return;
+ }
+
+ if ((ItemType == E_ITEM_POTION) && ((a_Item.m_ItemDamage & 0x4000) != 0))
+ {
+ // Ugly special case for splash potion ids which changed in 1.9; this can be removed when the new 1.9 ids are implemented
+ a_Pkt.WriteBEInt16(438); // minecraft:splash_potion
+ }
+ else
+ {
+ // Normal item
+ a_Pkt.WriteBEInt16(ItemType);
+ }
+ a_Pkt.WriteBEInt8(a_Item.m_ItemCount);
+ if ((ItemType == E_ITEM_POTION) || (ItemType == E_ITEM_SPAWN_EGG))
+ {
+ // These items lost their metadata; if it is sent they don't render correctly.
+ a_Pkt.WriteBEInt16(0);
+ }
+ else
+ {
+ a_Pkt.WriteBEInt16(a_Item.m_ItemDamage);
+ }
+
+ if (a_Item.m_Enchantments.IsEmpty() && a_Item.IsBothNameAndLoreEmpty() && (ItemType != E_ITEM_FIREWORK_ROCKET) && (ItemType != E_ITEM_FIREWORK_STAR) && !a_Item.m_ItemColor.IsValid() && (ItemType != E_ITEM_POTION) && (ItemType != E_ITEM_SPAWN_EGG))
+ {
+ a_Pkt.WriteBEInt8(0);
+ return;
+ }
+
+
+ // Send the enchantments and custom names:
+ cFastNBTWriter Writer;
+ if (a_Item.m_RepairCost != 0)
+ {
+ Writer.AddInt("RepairCost", a_Item.m_RepairCost);
+ }
+ if (!a_Item.m_Enchantments.IsEmpty())
+ {
+ const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench";
+ EnchantmentSerializer::WriteToNBTCompound(a_Item.m_Enchantments, Writer, TagName);
+ }
+ if (!a_Item.IsBothNameAndLoreEmpty() || a_Item.m_ItemColor.IsValid())
+ {
+ Writer.BeginCompound("display");
+ if (a_Item.m_ItemColor.IsValid())
+ {
+ Writer.AddInt("color", static_cast<Int32>(a_Item.m_ItemColor.m_Color));
+ }
+
+ if (!a_Item.IsCustomNameEmpty())
+ {
+ Writer.AddString("Name", a_Item.m_CustomName);
+ }
+ if (!a_Item.IsLoreEmpty())
+ {
+ Writer.BeginList("Lore", TAG_String);
+
+ for (const auto & Line : a_Item.m_LoreTable)
+ {
+ Writer.AddString("", Line);
+ }
+
+ Writer.EndList();
+ }
+ Writer.EndCompound();
+ }
+ if ((a_Item.m_ItemType == E_ITEM_FIREWORK_ROCKET) || (a_Item.m_ItemType == E_ITEM_FIREWORK_STAR))
+ {
+ cFireworkItem::WriteToNBTCompound(a_Item.m_FireworkItem, Writer, static_cast<ENUM_ITEM_TYPE>(a_Item.m_ItemType));
+ }
+ if (a_Item.m_ItemType == E_ITEM_POTION)
+ {
+ // 1.9 potions use a different format. In the future (when only 1.9+ is supported) this should be its own class
+ AString PotionID = "empty"; // Fallback of "Uncraftable potion" for unhandled cases
+
+ cEntityEffect::eType Type = cEntityEffect::GetPotionEffectType(a_Item.m_ItemDamage);
+ if (Type != cEntityEffect::effNoEffect)
+ {
+ switch (Type)
+ {
+ case cEntityEffect::effRegeneration: PotionID = "regeneration"; break;
+ case cEntityEffect::effSpeed: PotionID = "swiftness"; break;
+ case cEntityEffect::effFireResistance: PotionID = "fire_resistance"; break;
+ case cEntityEffect::effPoison: PotionID = "poison"; break;
+ case cEntityEffect::effInstantHealth: PotionID = "healing"; break;
+ case cEntityEffect::effNightVision: PotionID = "night_vision"; break;
+ case cEntityEffect::effWeakness: PotionID = "weakness"; break;
+ case cEntityEffect::effStrength: PotionID = "strength"; break;
+ case cEntityEffect::effSlowness: PotionID = "slowness"; break;
+ case cEntityEffect::effJumpBoost: PotionID = "leaping"; break;
+ case cEntityEffect::effInstantDamage: PotionID = "harming"; break;
+ case cEntityEffect::effWaterBreathing: PotionID = "water_breathing"; break;
+ case cEntityEffect::effInvisibility: PotionID = "invisibility"; break;
+ default: ASSERT(!"Unknown potion effect"); break;
+ }
+ if (cEntityEffect::GetPotionEffectIntensity(a_Item.m_ItemDamage) == 1)
+ {
+ PotionID = "strong_" + PotionID;
+ }
+ else if (a_Item.m_ItemDamage & 0x40)
+ {
+ // Extended potion bit
+ PotionID = "long_" + PotionID;
+ }
+ }
+ else
+ {
+ // Empty potions: Water bottles and other base ones
+ if (a_Item.m_ItemDamage == 0)
+ {
+ // No other bits set; thus it's a water bottle
+ PotionID = "water";
+ }
+ else
+ {
+ switch (a_Item.m_ItemDamage & 0x3f)
+ {
+ case 0x00: PotionID = "mundane"; break;
+ case 0x10: PotionID = "awkward"; break;
+ case 0x20: PotionID = "thick"; break;
+ }
+ // Default cases will use "empty" from before.
+ }
+ }
+
+ PotionID = "minecraft:" + PotionID;
+
+ Writer.AddString("Potion", PotionID);
+ }
+ if (a_Item.m_ItemType == E_ITEM_SPAWN_EGG)
+ {
+ // Convert entity ID to the name.
+ eMonsterType MonsterType = cItemSpawnEggHandler::ItemDamageToMonsterType(a_Item.m_ItemDamage);
+ if (MonsterType != eMonsterType::mtInvalidType)
+ {
+ Writer.BeginCompound("EntityTag");
+ Writer.AddString("id", "minecraft:" + cMonster::MobTypeToVanillaNBT(MonsterType));
+ Writer.EndCompound();
+ }
+ }
+
+ Writer.Finish();
+
+ const auto Result = Writer.GetResult();
+ if (Result.empty())
+ {
+ a_Pkt.WriteBEInt8(0);
+ return;
+ }
+ a_Pkt.WriteBuf(Result);
+}
+
+
+
+
+
+void cProtocol_1_9_0::WriteMobMetadata(cPacketizer & a_Pkt, const cMonster & a_Mob) const
{
// Living entity metadata
if (a_Mob.HasCustomName())
@@ -2294,7 +2279,7 @@ void cProtocol_1_9_1::SendLogin(const cPlayer & a_Player, const cWorld & a_World
-cProtocol::Version cProtocol_1_9_1::GetProtocolVersion()
+cProtocol::Version cProtocol_1_9_1::GetProtocolVersion() const
{
return Version::v1_9_1;
}
@@ -2306,7 +2291,7 @@ cProtocol::Version cProtocol_1_9_1::GetProtocolVersion()
////////////////////////////////////////////////////////////////////////////////
// cProtocol_1_9_2:
-cProtocol::Version cProtocol_1_9_2::GetProtocolVersion()
+cProtocol::Version cProtocol_1_9_2::GetProtocolVersion() const
{
return Version::v1_9_2;
}
@@ -2354,16 +2339,7 @@ void cProtocol_1_9_4::SendUpdateSign(int a_BlockX, int a_BlockY, int a_BlockZ, c
-cProtocol::Version cProtocol_1_9_4::GetProtocolVersion()
-{
- return Version::v1_9_4;
-}
-
-
-
-
-
-UInt32 cProtocol_1_9_4::GetPacketID(cProtocol::ePacketType a_Packet)
+UInt32 cProtocol_1_9_4::GetPacketID(cProtocol::ePacketType a_Packet) const
{
switch (a_Packet)
{
@@ -2376,3 +2352,12 @@ UInt32 cProtocol_1_9_4::GetPacketID(cProtocol::ePacketType a_Packet)
default: return Super::GetPacketID(a_Packet);
}
}
+
+
+
+
+
+cProtocol::Version cProtocol_1_9_4::GetProtocolVersion() const
+{
+ return Version::v1_9_4;
+}