diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 90aefd082..11405d2fd 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -528,9 +528,9 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) Player->GetStatManager().AddValue(statDamageDealt, static_cast(floor(a_TDI.FinalDamage * 10 + 0.5))); } - m_Health -= static_cast(a_TDI.FinalDamage); + m_Health -= static_cast(a_TDI.FinalDamage); - m_Health = std::max(m_Health, 0); + m_Health = std::max(m_Health, 0.0f); // Add knockback: if ((IsMob() || IsPlayer()) && (a_TDI.Attacker != nullptr)) @@ -810,9 +810,9 @@ void cEntity::Heal(int a_HitPoints) -void cEntity::SetHealth(int a_Health) +void cEntity::SetHealth(float a_Health) { - m_Health = Clamp(a_Health, 0, m_MaxHealth); + m_Health = Clamp(a_Health, 0.0f, m_MaxHealth); } @@ -1782,7 +1782,7 @@ void cEntity::OnFinishedBurning(void) -void cEntity::SetMaxHealth(int a_MaxHealth) +void cEntity::SetMaxHealth(float a_MaxHealth) { m_MaxHealth = a_MaxHealth; diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h index 4174160bf..fae296ab4 100644 --- a/src/Entities/Entity.h +++ b/src/Entities/Entity.h @@ -368,10 +368,10 @@ public: virtual void Heal(int a_HitPoints); /** Returns the health of this entity */ - int GetHealth(void) const { return m_Health; } + float GetHealth(void) const { return m_Health; } /** Sets the health of this entity; doesn't broadcast any hurt animation */ - void SetHealth(int a_Health); + void SetHealth(float a_Health); // tolua_end @@ -403,9 +403,9 @@ public: // tolua_begin /** Sets the maximum value for the health */ - void SetMaxHealth(int a_MaxHealth); + void SetMaxHealth(float a_MaxHealth); - int GetMaxHealth(void) const { return m_MaxHealth; } + float GetMaxHealth(void) const { return m_MaxHealth; } /** Sets whether the entity is fireproof */ void SetIsFireproof(bool a_IsFireproof); @@ -556,8 +556,8 @@ protected: Note that the UniqueID is not persisted through storage. */ UInt32 m_UniqueID; - int m_Health; - int m_MaxHealth; + float m_Health; + float m_MaxHealth; /** The entity to which this entity is attached (vehicle), nullptr if none */ cEntity * m_AttachedTo; diff --git a/src/Entities/Minecart.cpp b/src/Entities/Minecart.cpp index 7c5ca49ce..4de53d716 100644 --- a/src/Entities/Minecart.cpp +++ b/src/Entities/Minecart.cpp @@ -1035,7 +1035,7 @@ bool cMinecart::DoTakeDamage(TakeDamageInfo & TDI) if ((TDI.Attacker != nullptr) && TDI.Attacker->IsPlayer() && static_cast(TDI.Attacker)->IsGameModeCreative()) { Destroy(); - TDI.FinalDamage = GetMaxHealth(); // Instant hit for creative + TDI.FinalDamage = static_cast(GetMaxHealth()); // Instant hit for creative SetInvulnerableTicks(0); return super::DoTakeDamage(TDI); // No drops for creative } diff --git a/src/Protocol/Protocol_1_8.cpp b/src/Protocol/Protocol_1_8.cpp index e7f197d3d..ec5a9440b 100644 --- a/src/Protocol/Protocol_1_8.cpp +++ b/src/Protocol/Protocol_1_8.cpp @@ -3310,7 +3310,7 @@ void cProtocol_1_8_0::WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a Health: 1 | 3 - (1 - 3) = 5 */ auto & Minecart = reinterpret_cast(a_Entity); - a_Pkt.WriteBEInt32((((a_Entity.GetMaxHealth() / 2) - (a_Entity.GetHealth() - (a_Entity.GetMaxHealth() / 2))) * Minecart.LastDamage()) * 4); + a_Pkt.WriteBEInt32(static_cast((((a_Entity.GetMaxHealth() / 2) - (a_Entity.GetHealth() - (a_Entity.GetMaxHealth() / 2))) * Minecart.LastDamage()) * 4)); a_Pkt.WriteBEUInt8(0x52); a_Pkt.WriteBEInt32(1); // Shaking direction, doesn't seem to affect anything a_Pkt.WriteBEUInt8(0x73); diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp index 12f767abf..78573572d 100644 --- a/src/WorldStorage/NBTChunkSerializer.cpp +++ b/src/WorldStorage/NBTChunkSerializer.cpp @@ -431,7 +431,7 @@ void cNBTChunkSerializer::AddBasicEntity(cEntity * a_Entity, const AString & a_C m_Writer.AddDouble("", a_Entity->GetYaw()); m_Writer.AddDouble("", a_Entity->GetPitch()); m_Writer.EndList(); - m_Writer.AddShort("Health", static_cast(a_Entity->GetHealth())); + m_Writer.AddFloat("Health", a_Entity->GetHealth()); } diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp index b47d3eddd..35fdaa8d8 100755 --- a/src/WorldStorage/WSSAnvil.cpp +++ b/src/WorldStorage/WSSAnvil.cpp @@ -3154,9 +3154,28 @@ bool cWSSAnvil::LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_N a_Entity.SetYaw(Rotation[0]); a_Entity.SetRoll(Rotation[1]); - // Load health: + // Depending on the Minecraft version, the entity's health is + // stored either as a float Health tag (HealF prior to 1.9) or + // as a short Health tag. The float tags should be preferred. int Health = a_NBT.FindChildByName(a_TagIdx, "Health"); - a_Entity.SetHealth(Health > 0 ? a_NBT.GetShort(Health) : a_Entity.GetMaxHealth()); + int HealF = a_NBT.FindChildByName(a_TagIdx, "HealF"); + + if (Health > 0 && a_NBT.GetType(Health) == TAG_Float) + { + a_Entity.SetHealth(a_NBT.GetFloat(Health)); + } + else if (HealF > 0) + { + a_Entity.SetHealth(a_NBT.GetFloat(HealF)); + } + else if (Health > 0) + { + a_Entity.SetHealth(static_cast(a_NBT.GetShort(Health))); + } + else + { + a_Entity.SetHealth(a_Entity.GetMaxHealth()); + } return true; }