summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/Blocks/BroadcastInterface.h4
-rw-r--r--src/Broadcaster.cpp28
-rw-r--r--src/ClientHandle.cpp20
-rw-r--r--src/ClientHandle.h4
-rw-r--r--src/Defines.h82
-rw-r--r--src/Entities/Entity.cpp14
-rw-r--r--src/Entities/Entity.h41
-rw-r--r--src/Entities/FireworkEntity.cpp2
-rw-r--r--src/Entities/Pawn.cpp2
-rw-r--r--src/Entities/Player.cpp5
-rw-r--r--src/Mobs/Monster.cpp2
-rw-r--r--src/Mobs/Ocelot.cpp6
-rw-r--r--src/Mobs/Sheep.cpp2
-rw-r--r--src/Mobs/Villager.cpp2
-rw-r--r--src/Mobs/Wolf.cpp6
-rw-r--r--src/Protocol/Protocol.h4
-rw-r--r--src/Protocol/Protocol_1_11.cpp53
-rw-r--r--src/Protocol/Protocol_1_11.h2
-rw-r--r--src/Protocol/Protocol_1_12.cpp14
-rw-r--r--src/Protocol/Protocol_1_12.h1
-rw-r--r--src/Protocol/Protocol_1_13.cpp13
-rw-r--r--src/Protocol/Protocol_1_13.h2
-rw-r--r--src/Protocol/Protocol_1_14.cpp51
-rw-r--r--src/Protocol/Protocol_1_14.h3
-rw-r--r--src/Protocol/Protocol_1_8.cpp381
-rw-r--r--src/Protocol/Protocol_1_8.h23
-rw-r--r--src/Protocol/Protocol_1_9.cpp44
-rw-r--r--src/Protocol/Protocol_1_9.h4
-rw-r--r--src/World.h4
29 files changed, 506 insertions, 313 deletions
diff --git a/src/Blocks/BroadcastInterface.h b/src/Blocks/BroadcastInterface.h
index ab756fe88..6c52a5156 100644
--- a/src/Blocks/BroadcastInterface.h
+++ b/src/Blocks/BroadcastInterface.h
@@ -42,9 +42,8 @@ public:
virtual void BroadcastEntityLook (const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr) = 0;
virtual void BroadcastEntityMetadata (const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr) = 0;
virtual void BroadcastEntityPosition (const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr) = 0;
- virtual void BroadcastEntityStatus (const cEntity & a_Entity, Int8 a_Status, const cClientHandle * a_Exclude = nullptr) = 0;
virtual void BroadcastEntityVelocity (const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr) = 0;
- virtual void BroadcastEntityAnimation (const cEntity & a_Entity, Int8 a_Animation, const cClientHandle * a_Exclude = nullptr) = 0;
+ virtual void BroadcastEntityAnimation (const cEntity & a_Entity, EntityAnimation a_Animation, const cClientHandle * a_Exclude = nullptr) = 0;
virtual void BroadcastLeashEntity (const cEntity & a_Entity, const cEntity & a_EntityLeashedTo) = 0;
virtual void BroadcastParticleEffect (const AString & a_ParticleName, Vector3f a_Src, Vector3f a_Offset, float a_ParticleData, int a_ParticleAmount, const cClientHandle * a_Exclude = nullptr) = 0;
virtual void BroadcastParticleEffect (const AString & a_ParticleName, Vector3f a_Src, Vector3f a_Offset, float a_ParticleData, int a_ParticleAmount, std::array<int, 2> a_Data, const cClientHandle * a_Exclude = nullptr) = 0;
@@ -64,6 +63,5 @@ public:
virtual void BroadcastThunderbolt (Vector3i a_BlockPos, const cClientHandle * a_Exclude = nullptr) = 0;
virtual void BroadcastTimeUpdate (const cClientHandle * a_Exclude = nullptr) = 0;
virtual void BroadcastUnleashEntity (const cEntity & a_Entity) = 0;
- virtual void BroadcastUseBed (const cEntity & a_Entity, Vector3i a_BedPos) = 0;
virtual void BroadcastWeather (eWeather a_Weather, const cClientHandle * a_Exclude = nullptr) = 0;
};
diff --git a/src/Broadcaster.cpp b/src/Broadcaster.cpp
index 770a3987c..0a8f17930 100644
--- a/src/Broadcaster.cpp
+++ b/src/Broadcaster.cpp
@@ -358,19 +358,6 @@ void cWorld::BroadcastEntityProperties(const cEntity & a_Entity)
-void cWorld::BroadcastEntityStatus(const cEntity & a_Entity, Int8 a_Status, const cClientHandle * a_Exclude)
-{
- ForClientsWithEntity(a_Entity, *this, a_Exclude, [&](cClientHandle & a_Client)
- {
- a_Client.SendEntityStatus(a_Entity, a_Status);
- }
- );
-}
-
-
-
-
-
void cWorld::BroadcastEntityVelocity(const cEntity & a_Entity, const cClientHandle * a_Exclude)
{
ForClientsWithEntity(a_Entity, *this, a_Exclude, [&](cClientHandle & a_Client)
@@ -384,7 +371,7 @@ void cWorld::BroadcastEntityVelocity(const cEntity & a_Entity, const cClientHand
-void cWorld::BroadcastEntityAnimation(const cEntity & a_Entity, Int8 a_Animation, const cClientHandle * a_Exclude)
+void cWorld::BroadcastEntityAnimation(const cEntity & a_Entity, EntityAnimation a_Animation, const cClientHandle * a_Exclude)
{
ForClientsWithEntity(a_Entity, *this, a_Exclude, [&](cClientHandle & a_Client)
{
@@ -631,19 +618,6 @@ void cWorld::BroadcastUnleashEntity(const cEntity & a_Entity)
-void cWorld::BroadcastUseBed(const cEntity & a_Entity, Vector3i a_BedPos)
-{
- ForClientsWithChunkAtPos(a_BedPos, *this, nullptr, [&](cClientHandle & a_Client)
- {
- a_Client.SendUseBed(a_Entity, a_BedPos.x, a_BedPos.y, a_BedPos.z);
- }
- );
-}
-
-
-
-
-
void cWorld::BroadcastWeather(eWeather a_Weather, const cClientHandle * a_Exclude)
{
ForClientsInWorld(*this, a_Exclude, [&](cClientHandle & a_Client)
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index 2050fd1ed..d356b524a 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -2537,15 +2537,6 @@ void cClientHandle::SendEntityProperties(const cEntity & a_Entity)
-void cClientHandle::SendEntityStatus(const cEntity & a_Entity, char a_Status)
-{
- m_Protocol->SendEntityStatus(a_Entity, a_Status);
-}
-
-
-
-
-
void cClientHandle::SendEntityVelocity(const cEntity & a_Entity)
{
m_Protocol->SendEntityVelocity(a_Entity);
@@ -2674,7 +2665,7 @@ void cClientHandle::SendPaintingSpawn(const cPainting & a_Painting)
-void cClientHandle::SendEntityAnimation(const cEntity & a_Entity, char a_Animation)
+void cClientHandle::SendEntityAnimation(const cEntity & a_Entity, EntityAnimation a_Animation)
{
m_Protocol->SendEntityAnimation(a_Entity, a_Animation);
}
@@ -3064,15 +3055,6 @@ void cClientHandle::SendUpdateSign(
-void cClientHandle::SendUseBed(const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ)
-{
- m_Protocol->SendUseBed(a_Entity, a_BlockX, a_BlockY, a_BlockZ);
-}
-
-
-
-
-
void cClientHandle::SendUnlockRecipe(UInt32 a_RecipeId)
{
m_Protocol->SendUnlockRecipe(a_RecipeId);
diff --git a/src/ClientHandle.h b/src/ClientHandle.h
index 971edfb8a..cb0ea508a 100644
--- a/src/ClientHandle.h
+++ b/src/ClientHandle.h
@@ -162,7 +162,7 @@ public: // tolua_export
void SendDisconnect (const AString & a_Reason);
void SendDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display);
void SendEditSign (int a_BlockX, int a_BlockY, int a_BlockZ);
- void SendEntityAnimation (const cEntity & a_Entity, char a_Animation); // tolua_export
+ void SendEntityAnimation (const cEntity & a_Entity, EntityAnimation a_Animation); // tolua_export
void SendEntityEffect (const cEntity & a_Entity, int a_EffectID, int a_Amplifier, int a_Duration);
void SendEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item);
void SendEntityHeadLook (const cEntity & a_Entity);
@@ -170,7 +170,6 @@ public: // tolua_export
void SendEntityMetadata (const cEntity & a_Entity);
void SendEntityPosition (const cEntity & a_Entity);
void SendEntityProperties (const cEntity & a_Entity);
- void SendEntityStatus (const cEntity & a_Entity, char a_Status);
void SendEntityVelocity (const cEntity & a_Entity);
void SendExperience (void);
void SendExperienceOrb (const cExpOrb & a_ExpOrb);
@@ -221,7 +220,6 @@ public: // tolua_export
void SendUnloadChunk (int a_ChunkX, int a_ChunkZ);
void SendUpdateBlockEntity (cBlockEntity & a_BlockEntity);
void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4);
- void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ);
/** Send a newly discovered recipe to show the notification and unlock in the recipe book */
void SendUnlockRecipe (UInt32 a_RecipeId);
diff --git a/src/Defines.h b/src/Defines.h
index 417f28a42..a1c1d1cf8 100644
--- a/src/Defines.h
+++ b/src/Defines.h
@@ -467,9 +467,91 @@ enum class BossBarDivisionType
TwentyNotches
};
+// tolua_end
+
+
+enum class EntityAnimation
+{
+ AnimalFallsInLove,
+ ArmorStandGetsHit,
+ ArrowTipSparkles,
+ DolphinShowsHappiness,
+ EggCracks,
+ EntityGetsCriticalHit,
+ EntityGetsMagicalCriticalHit,
+ EntityTrailsHoney,
+ EvokerFangsAttacks,
+ FireworkRocketExplodes,
+ // FishingHookReels,
+ FoxChews,
+ GuardianAttacks,
+ HoglinAttacks,
+ HorseTamingFails,
+ HorseTamingSucceeds,
+ IronGolemAttacks,
+ IronGolemOffersGift,
+ IronGolemStashesGift,
+ MinecartSpawnerDelayResets,
+ MinecartTNTIgnites,
+ MobSpawns,
+ OcelotTrusts,
+ OcelotDistrusts,
+ PawnBerryBushPricks,
+ PawnBurns,
+ PawnChestEquipmentBreaks,
+ PawnDies,
+ PawnDrowns,
+ PawnFeetEquipmentBreaks,
+ PawnHandItemSwaps,
+ PawnHeadEquipmentBreaks,
+ PawnHurts,
+ PawnLegsEquipmentBreaks,
+ PawnMainHandEquipmentBreaks,
+ PawnOffHandEquipmentBreaks,
+ PawnShieldBlocks,
+ PawnShieldBreaks,
+ PawnTeleports,
+ PawnThornsPricks,
+ PawnTotemActivates,
+ PlayerBadOmenActivates,
+ PlayerEntersBed,
+ PlayerFinishesEating,
+ PlayerLeavesBed,
+ PlayerMainHandSwings,
+ // PlayerReducedDebugScreenDisables,
+ // PlayerReducedDebugScreenEnables,
+ // PlayerSetsOperatorLevelFour,
+ // PlayerSetsOperatorLevelOne,
+ // PlayerSetsOperatorLevelThree,
+ // PlayerSetsOperatorLevelTwo,
+ // PlayerSetsOperatorLevelZero,
+ PlayerOffHandSwings,
+ RabbitJumps,
+ RavagerAttacks,
+ RavagerBecomesStunned,
+ SheepEatsGrass,
+ SnowballPoofs,
+ // SquidResetsRotation,
+ VillagerKisses,
+ VillagerShowsAnger,
+ VillagerShowsHappiness,
+ VillagerSweats,
+ WitchMagicks,
+ WolfShakesWater,
+ WolfTamingFails,
+ WolfTamingSucceeds,
+ ZoglinAttacks,
+ ZombieVillagerCureFinishes
+};
+
+
+
+
+
+// tolua_begin
/** Returns a textual representation of the click action. */
const char * ClickActionToString(int a_ClickAction);
diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp
index c8a6b8ef9..7bb53bd2a 100644
--- a/src/Entities/Entity.cpp
+++ b/src/Entities/Entity.cpp
@@ -525,7 +525,15 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI)
SetSpeed(a_TDI.Knockback);
}
- m_World->BroadcastEntityStatus(*this, esGenericHurt);
+ m_World->BroadcastEntityAnimation(*this, [&a_TDI]
+ {
+ switch (a_TDI.DamageType)
+ {
+ case eDamageType::dtBurning: return EntityAnimation::PawnBurns;
+ case eDamageType::dtDrowning: return EntityAnimation::PawnDrowns;
+ default: return EntityAnimation::PawnHurts;
+ }
+ }());
m_InvulnerableTicks = 10;
@@ -797,7 +805,7 @@ void cEntity::KilledBy(TakeDamageInfo & a_TDI)
// If the victim is a player the hook is handled by the cPlayer class
if (!IsPlayer())
{
- AString emptystring = AString("");
+ AString emptystring;
cRoot::Get()->GetPluginManager()->CallHookKilled(*this, a_TDI, emptystring);
}
@@ -813,7 +821,7 @@ void cEntity::KilledBy(TakeDamageInfo & a_TDI)
m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ());
}
- m_World->BroadcastEntityStatus(*this, esGenericDead);
+ m_World->BroadcastEntityAnimation(*this, EntityAnimation::PawnDies);
}
diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h
index c3ccaa228..db526045e 100644
--- a/src/Entities/Entity.h
+++ b/src/Entities/Entity.h
@@ -109,47 +109,6 @@ public:
// tolua_end
- enum eEntityStatus
- {
- // TODO: Investigate 0, 1, and 5 as Wiki.vg is not certain
-
- // Entity becomes coloured red
- esGenericHurt = 2,
- // Entity plays death animation (entity falls to ground)
- esGenericDead = 3,
- // Iron Golem plays attack animation (arms lift and fall)
- esIronGolemAttacking = 4,
- // Wolf taming particles spawn (smoke)
- esWolfTaming = 6,
- // Wolf tamed particles spawn (hearts)
- esWolfTamed = 7,
- // Wolf plays water removal animation (shaking and water particles)
- esWolfDryingWater = 8,
- // Informs client that eating was accepted
- esPlayerEatingAccepted = 9,
- // Sheep plays eating animation (head lowers to ground)
- esSheepEating = 10,
- // Iron Golem holds gift to villager children
- esIronGolemGivingPlant = 11,
- // Villager spawns heart particles
- esVillagerBreeding = 12,
- // Villager spawns thunderclound particles
- esVillagerAngry = 13,
- // Villager spawns green crosses
- esVillagerHappy = 14,
- // Witch spawns magic particle (TODO: investigation into what this is)
- esWitchMagicking = 15,
-
- // It seems 16 (zombie conversion) is now done with metadata
-
- // Informs client to explode a firework based on its metadata
- esFireworkExploding = 17,
- // Passive mob is in "love mode"
- esMobInLove = 18,
- // Plays totem of undying animation and sound
- esTotemOfUndying = 35,
- } ;
-
static const int FIRE_TICKS_PER_DAMAGE = 10; ///< Ticks to wait between damaging an entity when it stands in fire
static const int FIRE_DAMAGE = 1; ///< Damage to deal when standing in fire
static const int LAVA_TICKS_PER_DAMAGE = 10; ///< Ticks to wait between damaging an entity when it stands in lava
diff --git a/src/Entities/FireworkEntity.cpp b/src/Entities/FireworkEntity.cpp
index eb386cdfc..03db96d91 100644
--- a/src/Entities/FireworkEntity.cpp
+++ b/src/Entities/FireworkEntity.cpp
@@ -74,7 +74,7 @@ void cFireworkEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
if (m_TicksToExplosion <= 0)
{
// TODO: Notify the plugins
- m_World->BroadcastEntityStatus(*this, esFireworkExploding);
+ m_World->BroadcastEntityAnimation(*this, EntityAnimation::FireworkRocketExplodes);
Destroy();
return;
}
diff --git a/src/Entities/Pawn.cpp b/src/Entities/Pawn.cpp
index cc11323e1..5476db468 100644
--- a/src/Entities/Pawn.cpp
+++ b/src/Entities/Pawn.cpp
@@ -115,7 +115,7 @@ void cPawn::KilledBy(TakeDamageInfo & a_TDI)
// Is death eligible for totem reanimation?
if (DeductTotem(a_TDI.DamageType))
{
- m_World->BroadcastEntityStatus(*this, esTotemOfUndying);
+ m_World->BroadcastEntityAnimation(*this, EntityAnimation::PawnTotemActivates);
AddEntityEffect(cEntityEffect::effAbsorption, 100, 1);
AddEntityEffect(cEntityEffect::effRegeneration, 900, 1);
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index 8c047c533..563a1cb97 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -498,8 +498,7 @@ void cPlayer::StartEating(void)
// Set the timer:
m_EatingFinishTick = m_World->GetWorldAge() + EATING_TICKS;
- // Send the packets:
- m_World->BroadcastEntityAnimation(*this, 3);
+ // Send the packet:
m_World->BroadcastEntityMetadata(*this);
}
@@ -513,7 +512,7 @@ void cPlayer::FinishEating(void)
m_EatingFinishTick = -1_tick;
// Send the packets:
- m_ClientHandle->SendEntityStatus(*this, esPlayerEatingAccepted);
+ m_ClientHandle->SendEntityAnimation(*this, EntityAnimation::PlayerFinishesEating);
m_World->BroadcastEntityMetadata(*this);
// consume the item:
diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp
index 1537a8a74..c1a244a9f 100644
--- a/src/Mobs/Monster.cpp
+++ b/src/Mobs/Monster.cpp
@@ -1463,7 +1463,7 @@ void cMonster::RightClickFeed(cPlayer & a_Player)
a_Player.GetInventory().RemoveOneEquippedItem();
}
m_LoveTimer = TPS * 30; // half a minute
- m_World->BroadcastEntityStatus(*this, esMobInLove);
+ m_World->BroadcastEntityAnimation(*this, EntityAnimation::AnimalFallsInLove);
}
}
// If a player holding my spawn egg right-clicked me, spawn a new baby
diff --git a/src/Mobs/Ocelot.cpp b/src/Mobs/Ocelot.cpp
index 329c17527..4b731154d 100644
--- a/src/Mobs/Ocelot.cpp
+++ b/src/Mobs/Ocelot.cpp
@@ -166,14 +166,12 @@ void cOcelot::OnRightClicked(cPlayer & a_Player)
SetIsTame(true);
SetOwner(a_Player.GetName(), a_Player.GetUUID());
SetCatType(static_cast<eCatType>(Random.RandInt<int>(1, 3)));
- m_World->BroadcastEntityStatus(*this, esWolfTamed);
- m_World->BroadcastParticleEffect("heart", static_cast<Vector3f>(GetPosition()), Vector3f{}, 0, 5);
+ m_World->BroadcastEntityAnimation(*this, EntityAnimation::OcelotTrusts);
}
else
{
// Taming failed
- m_World->BroadcastEntityStatus(*this, esWolfTaming);
- m_World->BroadcastParticleEffect("smoke", static_cast<Vector3f>(GetPosition()), Vector3f{}, 0, 5);
+ m_World->BroadcastEntityAnimation(*this, EntityAnimation::OcelotDistrusts);
}
}
}
diff --git a/src/Mobs/Sheep.cpp b/src/Mobs/Sheep.cpp
index 7808d3181..156046c74 100644
--- a/src/Mobs/Sheep.cpp
+++ b/src/Mobs/Sheep.cpp
@@ -129,7 +129,7 @@ void cSheep::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
if (m_World->GetBlock({ PosX, PosY, PosZ }) == E_BLOCK_GRASS)
{
- m_World->BroadcastEntityStatus(*this, esSheepEating);
+ m_World->BroadcastEntityAnimation(*this, EntityAnimation::SheepEatsGrass);
m_TimeToStopEating = 40;
}
}
diff --git a/src/Mobs/Villager.cpp b/src/Mobs/Villager.cpp
index 156515880..46dd613f1 100644
--- a/src/Mobs/Villager.cpp
+++ b/src/Mobs/Villager.cpp
@@ -34,7 +34,7 @@ bool cVillager::DoTakeDamage(TakeDamageInfo & a_TDI)
{
if (GetRandomProvider().RandBool(1.0 / 6.0))
{
- m_World->BroadcastEntityStatus(*this, esVillagerAngry);
+ m_World->BroadcastEntityAnimation(*this, EntityAnimation::VillagerShowsAnger);
}
}
diff --git a/src/Mobs/Wolf.cpp b/src/Mobs/Wolf.cpp
index 85d2a5a1b..0a3a12ea7 100644
--- a/src/Mobs/Wolf.cpp
+++ b/src/Mobs/Wolf.cpp
@@ -185,14 +185,12 @@ void cWolf::OnRightClicked(cPlayer & a_Player)
SetMaxHealth(20);
SetIsTame(true);
SetOwner(a_Player.GetName(), a_Player.GetUUID());
- m_World->BroadcastEntityStatus(*this, esWolfTamed);
- m_World->BroadcastParticleEffect("heart", static_cast<Vector3f>(GetPosition()), Vector3f{}, 0, 5);
+ m_World->BroadcastEntityAnimation(*this, EntityAnimation::WolfTamingSucceeds);
}
else
{
// Taming failed
- m_World->BroadcastEntityStatus(*this, esWolfTaming);
- m_World->BroadcastParticleEffect("smoke", static_cast<Vector3f>(GetPosition()), Vector3f{}, 0, 5);
+ m_World->BroadcastEntityAnimation(*this, EntityAnimation::WolfTamingFails);
}
}
}
diff --git a/src/Protocol/Protocol.h b/src/Protocol/Protocol.h
index 0f615f4dc..75ebb92d4 100644
--- a/src/Protocol/Protocol.h
+++ b/src/Protocol/Protocol.h
@@ -381,14 +381,13 @@ public:
virtual void SendDisconnect (const AString & a_Reason) = 0;
virtual void SendEditSign (int a_BlockX, int a_BlockY, int a_BlockZ) = 0; ///< Request the client to open up the sign editor for the sign (1.6+)
virtual void SendEntityEffect (const cEntity & a_Entity, int a_EffectID, int a_Amplifier, int a_Duration) = 0;
- virtual void SendEntityAnimation (const cEntity & a_Entity, char a_Animation) = 0;
+ virtual void SendEntityAnimation (const cEntity & a_Entity, EntityAnimation a_Animation) = 0;
virtual void SendEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) = 0;
virtual void SendEntityHeadLook (const cEntity & a_Entity) = 0;
virtual void SendEntityLook (const cEntity & a_Entity) = 0;
virtual void SendEntityMetadata (const cEntity & a_Entity) = 0;
virtual void SendEntityPosition (const cEntity & a_Entity) = 0;
virtual void SendEntityProperties (const cEntity & a_Entity) = 0;
- virtual void SendEntityStatus (const cEntity & a_Entity, char a_Status) = 0;
virtual void SendEntityVelocity (const cEntity & a_Entity) = 0;
virtual void SendExplosion (Vector3f a_Position, float a_Power) = 0;
virtual void SendGameMode (eGameMode a_GameMode) = 0;
@@ -441,7 +440,6 @@ public:
virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) = 0;
virtual void SendUpdateBlockEntity (cBlockEntity & a_BlockEntity) = 0;
virtual void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) = 0;
- virtual void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ) = 0;
virtual void SendUnlockRecipe (UInt32 a_RecipeID) = 0;
virtual void SendInitRecipes (UInt32 a_RecipeID) = 0;
virtual void SendWeather (eWeather a_Weather) = 0;
diff --git a/src/Protocol/Protocol_1_11.cpp b/src/Protocol/Protocol_1_11.cpp
index db4ed5502..e2436e04c 100644
--- a/src/Protocol/Protocol_1_11.cpp
+++ b/src/Protocol/Protocol_1_11.cpp
@@ -346,6 +346,41 @@ void cProtocol_1_11_0::SendCollectEntity(const cEntity & a_Collected, const cEnt
+void cProtocol_1_11_0::SendEntityAnimation(const cEntity & a_Entity, const EntityAnimation a_Animation)
+{
+ switch (a_Animation)
+ {
+ case EntityAnimation::EggCracks:
+ case EntityAnimation::SnowballPoofs:
+ {
+ // Vanilla stopped doing clientside prediction for thrown projectile particle effects (for some reason).
+ // But they're still doing motion prediction, and latency exists, hence re-send the server position to avoid particle effects happening inside a block:
+ SendEntityPosition(a_Entity);
+ break;
+ }
+ case EntityAnimation::PawnChestEquipmentBreaks:
+ case EntityAnimation::PawnFeetEquipmentBreaks:
+ case EntityAnimation::PawnHeadEquipmentBreaks:
+ case EntityAnimation::PawnLegsEquipmentBreaks:
+ case EntityAnimation::PawnMainHandEquipmentBreaks:
+ case EntityAnimation::PawnOffHandEquipmentBreaks:
+ {
+ const auto Position = a_Entity.GetPosition();
+
+ // 1.11 dropped the automatic particle effect + sound on item break. Emulate at least some of it:
+ SendSoundEffect("entity.item.break", Position.x, Position.y, Position.z, 1, 0.75f + ((a_Entity.GetUniqueID() * 23) % 32) / 64.f);
+ break;
+ }
+ default: break;
+ }
+
+ Super::SendEntityAnimation(a_Entity, a_Animation);
+}
+
+
+
+
+
void cProtocol_1_11_0::SendHideTitle(void)
{
ASSERT(m_State == 3); // In game mode?
@@ -526,6 +561,23 @@ UInt32 cProtocol_1_11_0::GetProtocolMobType(const eMonsterType a_MobType)
+signed char cProtocol_1_11_0::GetProtocolEntityStatus(const EntityAnimation a_Animation) const
+{
+ switch (a_Animation)
+ {
+ case EntityAnimation::EggCracks: return 3;
+ case EntityAnimation::EvokerFangsAttacks: return 4;
+ case EntityAnimation::IronGolemStashesGift: return 34;
+ case EntityAnimation::PawnTotemActivates: return 35;
+ case EntityAnimation::SnowballPoofs: return 3;
+ default: return Super::GetProtocolEntityStatus(a_Animation);
+ }
+}
+
+
+
+
+
void cProtocol_1_11_0::HandlePacketBlockPlace(cByteBuffer & a_ByteBuffer)
{
int BlockX, BlockY, BlockZ;
@@ -539,6 +591,7 @@ void cProtocol_1_11_0::HandlePacketBlockPlace(cByteBuffer & a_ByteBuffer)
HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, CursorX);
HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, CursorY);
HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, CursorZ);
+
m_Client->HandleRightClick(BlockX, BlockY, BlockZ, FaceIntToBlockFace(Face), FloorC(CursorX * 16), FloorC(CursorY * 16), FloorC(CursorZ * 16), HandIntToEnum(Hand));
}
diff --git a/src/Protocol/Protocol_1_11.h b/src/Protocol/Protocol_1_11.h
index 6cd4d7607..f5ed73187 100644
--- a/src/Protocol/Protocol_1_11.h
+++ b/src/Protocol/Protocol_1_11.h
@@ -33,6 +33,7 @@ public:
protected:
virtual void SendCollectEntity (const cEntity & a_Collected, const cEntity & a_Collector, unsigned a_Count) override;
+ virtual void SendEntityAnimation (const cEntity & a_Entity, EntityAnimation a_Animation) override;
virtual void SendHideTitle (void) override;
virtual void SendResetTitle (void) override;
virtual void SendSpawnMob (const cMonster & a_Mob) override;
@@ -44,6 +45,7 @@ protected:
/** Converts eMonsterType to protocol-specific mob IDs */
virtual UInt32 GetProtocolMobType(eMonsterType a_MobType) override;
+ virtual signed char GetProtocolEntityStatus(EntityAnimation a_Animation) const override;
virtual void HandlePacketBlockPlace (cByteBuffer & a_ByteBuffer) override;
diff --git a/src/Protocol/Protocol_1_12.cpp b/src/Protocol/Protocol_1_12.cpp
index b340d87f5..31daa96f7 100644
--- a/src/Protocol/Protocol_1_12.cpp
+++ b/src/Protocol/Protocol_1_12.cpp
@@ -1070,6 +1070,20 @@ cProtocol::Version cProtocol_1_12::GetProtocolVersion()
+signed char cProtocol_1_12::GetProtocolEntityStatus(EntityAnimation a_Animation) const
+{
+ switch (a_Animation)
+ {
+ case EntityAnimation::PawnBurns: return 37;
+ case EntityAnimation::PawnDrowns: return 36;
+ default: return Super::GetProtocolEntityStatus(a_Animation);
+ }
+}
+
+
+
+
+
UInt32 cProtocol_1_12::GetProtocolMobType(const eMonsterType a_MobType)
{
switch (a_MobType)
diff --git a/src/Protocol/Protocol_1_12.h b/src/Protocol/Protocol_1_12.h
index 7a92c156f..65bc23bcd 100644
--- a/src/Protocol/Protocol_1_12.h
+++ b/src/Protocol/Protocol_1_12.h
@@ -36,6 +36,7 @@ protected:
virtual UInt32 GetPacketID(ePacketType a_Packet) override;
virtual Version GetProtocolVersion() override;
+ virtual signed char GetProtocolEntityStatus(EntityAnimation a_Animation) const override;
virtual UInt32 GetProtocolMobType(eMonsterType a_MobType) override;
virtual bool HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType) override;
virtual void HandlePacketAdvancementTab(cByteBuffer & a_ByteBuffer);
diff --git a/src/Protocol/Protocol_1_13.cpp b/src/Protocol/Protocol_1_13.cpp
index 28b6c26f9..a802f0074 100644
--- a/src/Protocol/Protocol_1_13.cpp
+++ b/src/Protocol/Protocol_1_13.cpp
@@ -403,6 +403,19 @@ UInt32 cProtocol_1_13::GetPacketID(ePacketType a_PacketType)
+signed char cProtocol_1_13::GetProtocolEntityStatus(const EntityAnimation a_Animation) const
+{
+ switch (a_Animation)
+ {
+ case EntityAnimation::DolphinShowsHappiness: return 38;
+ default: return Super::GetProtocolEntityStatus(a_Animation);
+ }
+}
+
+
+
+
+
UInt32 cProtocol_1_13::GetProtocolMobType(eMonsterType a_MobType)
{
switch (a_MobType)
diff --git a/src/Protocol/Protocol_1_13.h b/src/Protocol/Protocol_1_13.h
index d515306e3..53de8bbc1 100644
--- a/src/Protocol/Protocol_1_13.h
+++ b/src/Protocol/Protocol_1_13.h
@@ -49,6 +49,8 @@ protected:
/** Translates outgoing packet types. */
virtual UInt32 GetPacketID(ePacketType a_PacketType) override;
+ virtual signed char GetProtocolEntityStatus(EntityAnimation a_Animation) const override;
+
/** Returns 1.13. */
virtual Version GetProtocolVersion() override;
diff --git a/src/Protocol/Protocol_1_14.cpp b/src/Protocol/Protocol_1_14.cpp
index bc0e68d94..77918c7eb 100644
--- a/src/Protocol/Protocol_1_14.cpp
+++ b/src/Protocol/Protocol_1_14.cpp
@@ -48,6 +48,22 @@ void cProtocol_1_14::SendEditSign(int a_BlockX, int a_BlockY, int a_BlockZ)
+void cProtocol_1_14::SendEntityAnimation(const cEntity & a_Entity, EntityAnimation a_Animation)
+{
+ if (a_Animation == EntityAnimation::PlayerEntersBed)
+ {
+ // Use Bed packet removed, through metadata instead:
+ SendEntityMetadata(a_Entity);
+ return;
+ }
+
+ Super::SendEntityAnimation(a_Entity, a_Animation);
+}
+
+
+
+
+
void cProtocol_1_14::SendLogin(const cPlayer & a_Player, const cWorld & a_World)
{
// Send the Join Game packet:
@@ -115,14 +131,6 @@ void cProtocol_1_14::SendUpdateSign(int a_BlockX, int a_BlockY, int a_BlockZ, co
-void cProtocol_1_14::SendUseBed(const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ)
-{
-}
-
-
-
-
-
UInt32 cProtocol_1_14::GetPacketID(ePacketType a_PacketType)
{
switch (a_PacketType)
@@ -203,6 +211,33 @@ UInt32 cProtocol_1_14::GetProtocolBlockType(BLOCKTYPE a_BlockType, NIBBLETYPE a_
+signed char cProtocol_1_14::GetProtocolEntityStatus(EntityAnimation a_Animation) const
+{
+ switch (a_Animation)
+ {
+ case EntityAnimation::FoxChews: return 45;
+ case EntityAnimation::OcelotTrusts: return 40;
+ case EntityAnimation::OcelotDistrusts: return 41;
+ case EntityAnimation::PawnBerryBushPricks: return 44;
+ case EntityAnimation::PawnChestEquipmentBreaks: return 50;
+ case EntityAnimation::PawnFeetEquipmentBreaks: return 52;
+ case EntityAnimation::PawnHeadEquipmentBreaks: return 49;
+ case EntityAnimation::PawnLegsEquipmentBreaks: return 51;
+ case EntityAnimation::PawnMainHandEquipmentBreaks: return 47;
+ case EntityAnimation::PawnOffHandEquipmentBreaks: return 48;
+ case EntityAnimation::PawnTeleports: return 46;
+ case EntityAnimation::PlayerBadOmenActivates: return 43;
+ case EntityAnimation::RavagerAttacks: return 4;
+ case EntityAnimation::RavagerBecomesStunned: return 39;
+ case EntityAnimation::VillagerSweats: return 42;
+ default: return Super::GetProtocolEntityStatus(a_Animation);
+ }
+}
+
+
+
+
+
UInt32 cProtocol_1_14::GetProtocolItemType(short a_ItemID, short a_ItemDamage)
{
return Palette_1_14::From(PaletteUpgrade::FromItem(a_ItemID, a_ItemDamage));
diff --git a/src/Protocol/Protocol_1_14.h b/src/Protocol/Protocol_1_14.h
index 3f328bbac..d1e5b5a4f 100644
--- a/src/Protocol/Protocol_1_14.h
+++ b/src/Protocol/Protocol_1_14.h
@@ -33,17 +33,18 @@ protected:
virtual void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) override;
virtual void SendBlockBreakAnim (UInt32 a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage) override;
virtual void SendEditSign (int a_BlockX, int a_BlockY, int a_BlockZ) override; ///< Request the client to open up the sign editor for the sign (1.6+)
+ virtual void SendEntityAnimation (const cEntity & a_Entity, EntityAnimation a_Animation) override;
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override;
virtual void SendPaintingSpawn (const cPainting & a_Painting) override;
virtual void SendSoundParticleEffect (const EffectID a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override;
virtual void SendUpdateBlockEntity (cBlockEntity & a_BlockEntity) override;
virtual void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) override;
- virtual void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ) override;
virtual UInt32 GetPacketID(ePacketType a_PacketType) override;
virtual Version GetProtocolVersion() override;
virtual std::pair<short, short> GetItemFromProtocolID(UInt32 a_ProtocolID) override;
virtual UInt32 GetProtocolBlockType(BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override;
+ virtual signed char GetProtocolEntityStatus(EntityAnimation a_Animation) const override;
virtual UInt32 GetProtocolItemType(short a_ItemID, short a_ItemDamage) override;
virtual UInt32 GetProtocolStatisticType(Statistic a_Statistic) override;
diff --git a/src/Protocol/Protocol_1_8.cpp b/src/Protocol/Protocol_1_8.cpp
index 179e2b2ea..f815bbd29 100644
--- a/src/Protocol/Protocol_1_8.cpp
+++ b/src/Protocol/Protocol_1_8.cpp
@@ -472,13 +472,35 @@ void cProtocol_1_8_0::SendEditSign(int a_BlockX, int a_BlockY, int a_BlockZ)
-void cProtocol_1_8_0::SendEntityAnimation(const cEntity & a_Entity, char a_Animation)
+void cProtocol_1_8_0::SendEntityAnimation(const cEntity & a_Entity, const EntityAnimation a_Animation)
{
ASSERT(m_State == 3); // In game mode?
- cPacketizer Pkt(*this, pktEntityAnimation);
- Pkt.WriteVarInt32(a_Entity.GetUniqueID());
- Pkt.WriteBEInt8(a_Animation);
+ if (a_Animation == EntityAnimation::PlayerEntersBed)
+ {
+ ASSERT(a_Entity.IsPlayer());
+ const auto BedPosition = static_cast<const cPlayer &>(a_Entity).GetLastBedPos();
+
+ cPacketizer Pkt(*this, pktUseBed);
+ Pkt.WriteVarInt32(a_Entity.GetUniqueID());
+ Pkt.WriteXYZPosition64(BedPosition.x, BedPosition.y, BedPosition.z);
+ return;
+ }
+
+ if (const auto AnimationID = GetProtocolEntityAnimation(a_Animation); AnimationID != static_cast<unsigned char>(-1))
+ {
+ cPacketizer Pkt(*this, pktEntityAnimation);
+ Pkt.WriteVarInt32(a_Entity.GetUniqueID());
+ Pkt.WriteBEUInt8(AnimationID);
+ return;
+ }
+
+ if (const auto StatusID = GetProtocolEntityStatus(a_Animation); StatusID != -1)
+ {
+ cPacketizer Pkt(*this, pktEntityStatus);
+ Pkt.WriteBEUInt32(a_Entity.GetUniqueID());
+ Pkt.WriteBEInt8(StatusID);
+ }
}
@@ -616,19 +638,6 @@ void cProtocol_1_8_0::SendEntityProperties(const cEntity & a_Entity)
-void cProtocol_1_8_0::SendEntityStatus(const cEntity & a_Entity, char a_Status)
-{
- ASSERT(m_State == 3); // In game mode?
-
- cPacketizer Pkt(*this, pktEntityStatus);
- Pkt.WriteBEUInt32(a_Entity.GetUniqueID());
- Pkt.WriteBEInt8(a_Status);
-}
-
-
-
-
-
void cProtocol_1_8_0::SendEntityVelocity(const cEntity & a_Entity)
{
ASSERT(m_State == 3); // In game mode?
@@ -942,10 +951,9 @@ void cProtocol_1_8_0::SendPlayerAbilities(void)
void cProtocol_1_8_0::SendParticleEffect(const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmount)
{
ASSERT(m_State == 3); // In game mode?
- int ParticleID = GetParticleID(a_ParticleName);
cPacketizer Pkt(*this, pktParticleEffect);
- Pkt.WriteBEInt32(ParticleID);
+ Pkt.WriteBEInt32(GetProtocolParticleID(a_ParticleName));
Pkt.WriteBool(false);
Pkt.WriteBEFloat(a_SrcX);
Pkt.WriteBEFloat(a_SrcY);
@@ -964,7 +972,8 @@ void cProtocol_1_8_0::SendParticleEffect(const AString & a_ParticleName, float a
void cProtocol_1_8_0::SendParticleEffect(const AString & a_ParticleName, Vector3f a_Src, Vector3f a_Offset, float a_ParticleData, int a_ParticleAmount, std::array<int, 2> a_Data)
{
ASSERT(m_State == 3); // In game mode?
- int ParticleID = GetParticleID(a_ParticleName);
+
+ const auto ParticleID = GetProtocolParticleID(a_ParticleName);
cPacketizer Pkt(*this, pktParticleEffect);
Pkt.WriteBEInt32(ParticleID);
@@ -977,6 +986,7 @@ void cProtocol_1_8_0::SendParticleEffect(const AString & a_ParticleName, Vector3
Pkt.WriteBEFloat(a_Offset.z);
Pkt.WriteBEFloat(a_ParticleData);
Pkt.WriteBEInt32(a_ParticleAmount);
+
switch (ParticleID)
{
// iconcrack
@@ -1624,19 +1634,6 @@ void cProtocol_1_8_0::SendUpdateSign(int a_BlockX, int a_BlockY, int a_BlockZ, c
-void cProtocol_1_8_0::SendUseBed(const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ)
-{
- ASSERT(m_State == 3); // In game mode?
-
- cPacketizer Pkt(*this, pktUseBed);
- Pkt.WriteVarInt32(a_Entity.GetUniqueID());
- Pkt.WriteXYZPosition64(a_BlockX, a_BlockY, a_BlockZ);
-}
-
-
-
-
-
void cProtocol_1_8_0::SendUnlockRecipe(UInt32 a_RecipeID)
{
// Client doesn't support this feature
@@ -1835,136 +1832,6 @@ void cProtocol_1_8_0::CompressPacket(CircularBufferCompressor & a_Packet, Contig
-int cProtocol_1_8_0::GetParticleID(const AString & a_ParticleName)
-{
- static const std::unordered_map<AString, int> ParticleMap
- {
- // Initialize the ParticleMap:
- { "explode", 0 },
- { "largeexplode", 1 },
- { "hugeexplosion", 2 },
- { "fireworksspark", 3 },
- { "bubble", 4 },
- { "splash", 5 },
- { "wake", 6 },
- { "suspended", 7 },
- { "depthsuspend", 8 },
- { "crit", 9 },
- { "magiccrit", 10 },
- { "smoke", 11 },
- { "largesmoke", 12 },
- { "spell", 13 },
- { "instantspell", 14 },
- { "mobspell", 15 },
- { "mobspellambient", 16 },
- { "witchmagic", 17 },
- { "dripwater", 18 },
- { "driplava", 19 },
- { "angryvillager", 20 },
- { "happyvillager", 21 },
- { "townaura", 22 },
- { "note", 23 },
- { "portal", 24 },
- { "enchantmenttable", 25 },
- { "flame", 26 },
- { "lava", 27 },
- { "footstep", 28 },
- { "cloud", 29 },
- { "reddust", 30 },
- { "snowballpoof", 31 },
- { "snowshovel", 32 },
- { "slime", 33 },
- { "heart", 34 },
- { "barrier", 35 },
- { "iconcrack", 36 },
- { "blockcrack", 37 },
- { "blockdust", 38 },
- { "droplet", 39 },
- { "take", 40 },
- { "mobappearance", 41 },
- { "dragonbreath", 42 },
- { "endrod", 43 },
- { "damageindicator", 44 },
- { "sweepattack", 45 },
- { "fallingdust", 46 },
- { "totem", 47 },
- { "spit", 48 }
- };
-
- const auto ParticleName = StrToLower(a_ParticleName);
- const auto FindResult = ParticleMap.find(ParticleName);
- if (FindResult == ParticleMap.end())
- {
- LOGWARNING("Unknown particle: %s", a_ParticleName.c_str());
- ASSERT(!"Unknown particle");
- return 0;
- }
-
- return FindResult->second;
-}
-
-
-
-
-
-UInt32 cProtocol_1_8_0::GetProtocolMobType(const eMonsterType a_MobType)
-{
- switch (a_MobType)
- {
- // Map invalid type to Giant for easy debugging (if this ever spawns, something has gone very wrong)
- case mtInvalidType: return 53;
- case mtBat: return 65;
- case mtBlaze: return 61;
- case mtCaveSpider: return 59;
- case mtChicken: return 93;
- case mtCow: return 92;
- case mtCreeper: return 50;
- case mtEnderDragon: return 63;
- case mtEnderman: return 58;
- case mtEndermite: return 67;
- case mtGhast: return 56;
- case mtGiant: return 53;
- case mtGuardian: return 68;
- case mtHorse: return 100;
- case mtIronGolem: return 99;
- case mtMagmaCube: return 62;
- case mtMooshroom: return 96;
- case mtOcelot: return 98;
- case mtPig: return 90;
- case mtRabbit: return 101;
- case mtSheep: return 91;
- case mtSilverfish: return 60;
- case mtSkeleton: return 51;
- case mtSlime: return 55;
- case mtSnowGolem: return 97;
- case mtSpider: return 52;
- case mtSquid: return 94;
- case mtVillager: return 120;
- case mtWitch: return 66;
- case mtWither: return 64;
- case mtWitherSkeleton: return 51;
- case mtWolf: return 95;
- case mtZombie: return 54;
- case mtZombiePigman: return 57;
- case mtZombieVillager: return 27;
-
- // Mobs that get replaced with another because they were added later
- case mtCat: return GetProtocolMobType(mtOcelot);
- case mtDonkey: return GetProtocolMobType(mtHorse);
- case mtMule: return GetProtocolMobType(mtHorse);
- case mtSkeletonHorse: return GetProtocolMobType(mtHorse);
- case mtZombieHorse: return GetProtocolMobType(mtHorse);
- case mtStray: return GetProtocolMobType(mtSkeleton);
- case mtHusk: return GetProtocolMobType(mtZombie);
-
- default: return 0;
- }
-}
-
-
-
-
-
UInt32 cProtocol_1_8_0::GetPacketID(ePacketType a_PacketType)
{
switch (a_PacketType)
@@ -2065,6 +1932,122 @@ cProtocol::Version cProtocol_1_8_0::GetProtocolVersion()
+unsigned char cProtocol_1_8_0::GetProtocolEntityAnimation(const EntityAnimation a_Animation) const
+{
+ switch (a_Animation)
+ {
+ case EntityAnimation::EntityGetsCriticalHit: return 4;
+ case EntityAnimation::EntityGetsMagicalCriticalHit: return 5;
+ case EntityAnimation::PlayerLeavesBed: return 2;
+ case EntityAnimation::PlayerMainHandSwings: return 0;
+ case EntityAnimation::PlayerOffHandSwings: return 0;
+ default: return static_cast<unsigned char>(-1);
+ }
+}
+
+
+
+
+
+signed char cProtocol_1_8_0::GetProtocolEntityStatus(const EntityAnimation a_Animation) const
+{
+ switch (a_Animation)
+ {
+ case EntityAnimation::AnimalFallsInLove: return 18;
+ case EntityAnimation::FireworkRocketExplodes: return 17;
+ case EntityAnimation::GuardianAttacks: return 21;
+ case EntityAnimation::HorseTamingFails: return 6;
+ case EntityAnimation::HorseTamingSucceeds: return 7;
+ case EntityAnimation::IronGolemAttacks: return 4;
+ case EntityAnimation::IronGolemOffersGift: return 11;
+ case EntityAnimation::MinecartSpawnerDelayResets: return 1;
+ case EntityAnimation::MinecartTNTIgnites: return 10;
+ case EntityAnimation::MobSpawns: return 20;
+ case EntityAnimation::OcelotTrusts: return 6;
+ case EntityAnimation::OcelotDistrusts: return 7;
+ case EntityAnimation::PawnBerryBushPricks: return 2;
+ case EntityAnimation::PawnBurns: return 2;
+ case EntityAnimation::PawnDies: return 3;
+ case EntityAnimation::PawnDrowns: return 2;
+ case EntityAnimation::PawnHurts: return 2;
+ case EntityAnimation::PawnThornsPricks: return 2;
+ case EntityAnimation::PlayerFinishesEating: return 9;
+ case EntityAnimation::RabbitJumps: return 1;
+ case EntityAnimation::SheepEatsGrass: return 10;
+ case EntityAnimation::VillagerKisses: return 12;
+ case EntityAnimation::VillagerShowsAnger: return 13;
+ case EntityAnimation::VillagerShowsHappiness: return 14;
+ case EntityAnimation::WitchMagicks: return 15;
+ case EntityAnimation::WolfShakesWater: return 8;
+ case EntityAnimation::WolfTamingFails: return 6;
+ case EntityAnimation::WolfTamingSucceeds: return 7;
+ case EntityAnimation::ZombieVillagerCureFinishes: return 16;
+ default: return -1;
+ }
+}
+
+
+
+
+
+UInt32 cProtocol_1_8_0::GetProtocolMobType(const eMonsterType a_MobType)
+{
+ switch (a_MobType)
+ {
+ // Map invalid type to Giant for easy debugging (if this ever spawns, something has gone very wrong)
+ case mtInvalidType: return 53;
+ case mtBat: return 65;
+ case mtBlaze: return 61;
+ case mtCaveSpider: return 59;
+ case mtChicken: return 93;
+ case mtCow: return 92;
+ case mtCreeper: return 50;
+ case mtEnderDragon: return 63;
+ case mtEnderman: return 58;
+ case mtEndermite: return 67;
+ case mtGhast: return 56;
+ case mtGiant: return 53;
+ case mtGuardian: return 68;
+ case mtHorse: return 100;
+ case mtIronGolem: return 99;
+ case mtMagmaCube: return 62;
+ case mtMooshroom: return 96;
+ case mtOcelot: return 98;
+ case mtPig: return 90;
+ case mtRabbit: return 101;
+ case mtSheep: return 91;
+ case mtSilverfish: return 60;
+ case mtSkeleton: return 51;
+ case mtSlime: return 55;
+ case mtSnowGolem: return 97;
+ case mtSpider: return 52;
+ case mtSquid: return 94;
+ case mtVillager: return 120;
+ case mtWitch: return 66;
+ case mtWither: return 64;
+ case mtWitherSkeleton: return 51;
+ case mtWolf: return 95;
+ case mtZombie: return 54;
+ case mtZombiePigman: return 57;
+ case mtZombieVillager: return 27;
+
+ // Mobs that get replaced with another because they were added later
+ case mtCat: return GetProtocolMobType(mtOcelot);
+ case mtDonkey: return GetProtocolMobType(mtHorse);
+ case mtMule: return GetProtocolMobType(mtHorse);
+ case mtSkeletonHorse: return GetProtocolMobType(mtHorse);
+ case mtZombieHorse: return GetProtocolMobType(mtHorse);
+ case mtStray: return GetProtocolMobType(mtSkeleton);
+ case mtHusk: return GetProtocolMobType(mtZombie);
+
+ default: return 0;
+ }
+}
+
+
+
+
+
bool cProtocol_1_8_0::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType)
{
switch (m_State)
@@ -4079,6 +4062,78 @@ UInt8 cProtocol_1_8_0::GetProtocolEntityType(const cEntity & a_Entity)
+int cProtocol_1_8_0::GetProtocolParticleID(const AString & a_ParticleName)
+{
+ static const std::unordered_map<AString, int> ParticleMap
+ {
+ // Initialize the ParticleMap:
+ { "explode", 0 },
+ { "largeexplode", 1 },
+ { "hugeexplosion", 2 },
+ { "fireworksspark", 3 },
+ { "bubble", 4 },
+ { "splash", 5 },
+ { "wake", 6 },
+ { "suspended", 7 },
+ { "depthsuspend", 8 },
+ { "crit", 9 },
+ { "magiccrit", 10 },
+ { "smoke", 11 },
+ { "largesmoke", 12 },
+ { "spell", 13 },
+ { "instantspell", 14 },
+ { "mobspell", 15 },
+ { "mobspellambient", 16 },
+ { "witchmagic", 17 },
+ { "dripwater", 18 },
+ { "driplava", 19 },
+ { "angryvillager", 20 },
+ { "happyvillager", 21 },
+ { "townaura", 22 },
+ { "note", 23 },
+ { "portal", 24 },
+ { "enchantmenttable", 25 },
+ { "flame", 26 },
+ { "lava", 27 },
+ { "footstep", 28 },
+ { "cloud", 29 },
+ { "reddust", 30 },
+ { "snowballpoof", 31 },
+ { "snowshovel", 32 },
+ { "slime", 33 },
+ { "heart", 34 },
+ { "barrier", 35 },
+ { "iconcrack", 36 },
+ { "blockcrack", 37 },
+ { "blockdust", 38 },
+ { "droplet", 39 },
+ { "take", 40 },
+ { "mobappearance", 41 },
+ { "dragonbreath", 42 },
+ { "endrod", 43 },
+ { "damageindicator", 44 },
+ { "sweepattack", 45 },
+ { "fallingdust", 46 },
+ { "totem", 47 },
+ { "spit", 48 }
+ };
+
+ const auto ParticleName = StrToLower(a_ParticleName);
+ const auto FindResult = ParticleMap.find(ParticleName);
+ if (FindResult == ParticleMap.end())
+ {
+ LOGWARNING("Unknown particle: %s", a_ParticleName.c_str());
+ ASSERT(!"Unknown particle");
+ return 0;
+ }
+
+ return FindResult->second;
+}
+
+
+
+
+
const char * cProtocol_1_8_0::GetProtocolStatisticName(Statistic a_Statistic)
{
switch (a_Statistic)
diff --git a/src/Protocol/Protocol_1_8.h b/src/Protocol/Protocol_1_8.h
index 44168e499..d4aa0c899 100644
--- a/src/Protocol/Protocol_1_8.h
+++ b/src/Protocol/Protocol_1_8.h
@@ -62,7 +62,7 @@ public:
virtual void SendDetachEntity (const cEntity & a_Entity, const cEntity & a_PreviousVehicle) override;
virtual void SendDisconnect (const AString & a_Reason) override;
virtual void SendEditSign (int a_BlockX, int a_BlockY, int a_BlockZ) override; ///< Request the client to open up the sign editor for the sign (1.6+)
- virtual void SendEntityAnimation (const cEntity & a_Entity, char a_Animation) override;
+ virtual void SendEntityAnimation (const cEntity & a_Entity, EntityAnimation a_Animation) override;
virtual void SendEntityEffect (const cEntity & a_Entity, int a_EffectID, int a_Amplifier, int a_Duration) override;
virtual void SendEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) override;
virtual void SendEntityHeadLook (const cEntity & a_Entity) override;
@@ -70,7 +70,6 @@ public:
virtual void SendEntityMetadata (const cEntity & a_Entity) override;
virtual void SendEntityPosition (const cEntity & a_Entity) override;
virtual void SendEntityProperties (const cEntity & a_Entity) override;
- virtual void SendEntityStatus (const cEntity & a_Entity, char a_Status) override;
virtual void SendEntityVelocity (const cEntity & a_Entity) override;
virtual void SendExperience (void) override;
virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) override;
@@ -123,7 +122,6 @@ public:
virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) override;
virtual void SendUpdateBlockEntity (cBlockEntity & a_BlockEntity) override;
virtual void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) override;
- virtual void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ) override;
virtual void SendUnlockRecipe (UInt32 a_RecipeID) override;
virtual void SendInitRecipes (UInt32 a_RecipeID) override;
virtual void SendWeather (eWeather a_Weather) override;
@@ -138,26 +136,30 @@ public:
a_Compressed will be set to the compressed packet includes packet length and data length. */
static void CompressPacket(CircularBufferCompressor & a_Packet, ContiguousByteBuffer & a_Compressed);
- /** The 1.8 protocol use a particle id instead of a string. This function converts the name to the id. If the name is incorrect, it returns 0. */
- static int GetParticleID(const AString & a_ParticleName);
-
protected:
/** State of the protocol. */
State m_State;
- /** Nobody inherits 1.8, so it doesn't use this method */
+ /** Get the packet ID for a given packet. */
virtual UInt32 GetPacketID(ePacketType a_Packet) override;
/** Returns 1.8. */
virtual Version GetProtocolVersion() override;
+ /** Converts an animation into an ID suitable for use with the Entity Animation packet.
+ Returns (uchar)-1 if the protocol version doesn't support this animation. */
+ virtual unsigned char GetProtocolEntityAnimation(EntityAnimation a_Animation) const;
+
+ /** Converts an animation into an ID suitable for use with the Entity Status packet.
+ Returns -1 if the protocol version doesn't support this animation. */
+ virtual signed char GetProtocolEntityStatus(EntityAnimation a_Animation) const;
+
/** Converts eMonsterType to protocol-specific mob types */
virtual UInt32 GetProtocolMobType(eMonsterType a_MobType);
/** Reads and handles the packet. The packet length and type have already been read.
- Returns true if the packet was understood, false if it was an unknown packet
- */
+ Returns true if the packet was understood, false if it was an unknown packet. */
virtual bool HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType);
// Packet handlers while in the Status state (m_State == 1):
@@ -269,6 +271,9 @@ private:
Only entities that the Send Spawn Entity packet supports are valid inputs to this method */
static UInt8 GetProtocolEntityType(const cEntity & a_Entity);
+ /** The 1.8 protocol use a particle id instead of a string. This function converts the name to the id. If the name is incorrect, it returns 0. */
+ static int GetProtocolParticleID(const AString & a_ParticleName);
+
/** Converts a statistic to a protocol-specific string.
Protocols <= 1.12 use strings, hence this is a static as the string-mapping was append-only for the versions that used it.
Returns an empty string, handled correctly by the client, for newer, unsupported statistics. */
diff --git a/src/Protocol/Protocol_1_9.cpp b/src/Protocol/Protocol_1_9.cpp
index 0ae451117..6b240b235 100644
--- a/src/Protocol/Protocol_1_9.cpp
+++ b/src/Protocol/Protocol_1_9.cpp
@@ -367,19 +367,6 @@ void cProtocol_1_9_0::SendEntityPosition(const cEntity & a_Entity)
-void cProtocol_1_9_0::SendEntityStatus(const cEntity & a_Entity, char a_Status)
-{
- ASSERT(m_State == 3); // In game mode?
-
- cPacketizer Pkt(*this, pktEntityStatus);
- Pkt.WriteBEUInt32(a_Entity.GetUniqueID());
- Pkt.WriteBEInt8(a_Status);
-}
-
-
-
-
-
void cProtocol_1_9_0::SendExperienceOrb(const cExpOrb & a_ExpOrb)
{
ASSERT(m_State == 3); // In game mode?
@@ -708,6 +695,37 @@ UInt32 cProtocol_1_9_0::GetPacketID(cProtocol::ePacketType a_Packet)
+unsigned char cProtocol_1_9_0::GetProtocolEntityAnimation(const EntityAnimation a_Animation) const
+{
+ if (a_Animation == EntityAnimation::PlayerOffHandSwings)
+ {
+ return 3;
+ }
+
+ return Super::GetProtocolEntityAnimation(a_Animation);
+}
+
+
+
+
+
+signed char cProtocol_1_9_0::GetProtocolEntityStatus(const EntityAnimation a_Animation) const
+{
+ switch (a_Animation)
+ {
+ case EntityAnimation::ArmorStandGetsHit: return 32;
+ case EntityAnimation::ArrowTipSparkles: return 0;
+ case EntityAnimation::PawnShieldBlocks: return 29;
+ case EntityAnimation::PawnShieldBreaks: return 30;
+ case EntityAnimation::PawnThornsPricks: return 33;
+ default: return Super::GetProtocolEntityStatus(a_Animation);
+ }
+}
+
+
+
+
+
cProtocol::Version cProtocol_1_9_0::GetProtocolVersion()
{
return Version::v1_9_0;
diff --git a/src/Protocol/Protocol_1_9.h b/src/Protocol/Protocol_1_9.h
index 190b20005..00d6c477a 100644
--- a/src/Protocol/Protocol_1_9.h
+++ b/src/Protocol/Protocol_1_9.h
@@ -51,7 +51,6 @@ public:
virtual void SendEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) override;
virtual void SendEntityMetadata (const cEntity & a_Entity) override;
virtual void SendEntityPosition (const cEntity & a_Entity) override;
- virtual void SendEntityStatus (const cEntity & a_Entity, char a_Status) override;
virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) override;
virtual void SendKeepAlive (UInt32 a_PingID) override;
virtual void SendLeashEntity (const cEntity & a_Entity, const cEntity & a_EntityLeashedTo) override;
@@ -74,6 +73,9 @@ protected:
/** Get the packet ID for a given packet. */
virtual UInt32 GetPacketID(ePacketType a_Packet) override;
+ virtual unsigned char GetProtocolEntityAnimation(EntityAnimation a_Animation) const override;
+ virtual signed char GetProtocolEntityStatus(EntityAnimation a_Animation) const override;
+
/** Returns 1.9. */
virtual Version GetProtocolVersion() override;
diff --git a/src/World.h b/src/World.h
index 8db9a9e9d..958154bf0 100644
--- a/src/World.h
+++ b/src/World.h
@@ -176,9 +176,8 @@ public:
virtual void BroadcastEntityMetadata (const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr) override;
virtual void BroadcastEntityPosition (const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr) override;
void BroadcastEntityProperties (const cEntity & a_Entity);
- virtual void BroadcastEntityStatus (const cEntity & a_Entity, Int8 a_Status, const cClientHandle * a_Exclude = nullptr) override;
virtual void BroadcastEntityVelocity (const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr) override;
- virtual void BroadcastEntityAnimation (const cEntity & a_Entity, Int8 a_Animation, const cClientHandle * a_Exclude = nullptr) override; // tolua_export
+ virtual void BroadcastEntityAnimation (const cEntity & a_Entity, EntityAnimation a_Animation, const cClientHandle * a_Exclude = nullptr) override; // tolua_export
virtual void BroadcastLeashEntity (const cEntity & a_Entity, const cEntity & a_EntityLeashedTo) override;
virtual void BroadcastParticleEffect (const AString & a_ParticleName, Vector3f a_Src, Vector3f a_Offset, float a_ParticleData, int a_ParticleAmount, const cClientHandle * a_Exclude = nullptr) override; // Exported in ManualBindings_World.cpp
virtual void BroadcastParticleEffect (const AString & a_ParticleName, Vector3f a_Src, Vector3f a_Offset, float a_ParticleData, int a_ParticleAmount, std::array<int, 2> a_Data, const cClientHandle * a_Exclude = nullptr) override; // Exported in ManualBindings_World.cpp
@@ -198,7 +197,6 @@ public:
virtual void BroadcastThunderbolt (Vector3i a_BlockPos, const cClientHandle * a_Exclude = nullptr) override;
virtual void BroadcastTimeUpdate (const cClientHandle * a_Exclude = nullptr) override;
virtual void BroadcastUnleashEntity (const cEntity & a_Entity) override;
- virtual void BroadcastUseBed (const cEntity & a_Entity, Vector3i a_BlockPos) override;
virtual void BroadcastWeather (eWeather a_Weather, const cClientHandle * a_Exclude = nullptr) override;
virtual cBroadcastInterface & GetBroadcastManager(void) override