1
0

Rewrite explosion knock back ()

1. Base knockback on an entity's bounding box intersection with the explosion 
2. Armor blast protection reduces knockback
3. Don't apply knockback to players flying in creative mode

Fixes 
This commit is contained in:
changyong guo 2018-07-23 17:24:00 +08:00 committed by peterbell10
parent 7b0db672d1
commit 01e72ddb65
7 changed files with 129 additions and 20 deletions

@ -3231,6 +3231,16 @@ local Hash = cCryptoHash.sha1HexString("DataToHash")
}, },
Notes = "Returns the entity classname that this class implements. Each descendant overrides this function.", Notes = "Returns the entity classname that this class implements. Each descendant overrides this function.",
}, },
GetEnchantmentBlastKnockbackReduction =
{
Returns =
{
{
Type = "number",
},
},
Notes = "Returns explosion knock back reduction percent from blast protection level.",
},
GetEnchantmentCoverAgainst = GetEnchantmentCoverAgainst =
{ {
Params = Params =

@ -1814,10 +1814,21 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_
a_Entity.TakeDamage(dtExplosion, nullptr, static_cast<int>((1 / DistanceFromExplosion.Length()) * 6 * ExplosionSizeInt), 0); a_Entity.TakeDamage(dtExplosion, nullptr, static_cast<int>((1 / DistanceFromExplosion.Length()) * 6 * ExplosionSizeInt), 0);
} }
// Apply force to entities around the explosion - code modified from World.cpp DoExplosionAt() double Length = DistanceFromExplosion.Length();
if (Length <= ExplosionSizeInt) // Entity is impacted by explosion
{
float EntityExposure = a_Entity.GetExplosionExposureRate(ExplosionPos, ExplosionSizeInt);
// Exposure reduced by armor
EntityExposure = EntityExposure * (1.0f - a_Entity.GetEnchantmentBlastKnockbackReduction());
double Impact = (1 - ((Length / ExplosionSizeInt) / 2)) * EntityExposure;
DistanceFromExplosion.Normalize(); DistanceFromExplosion.Normalize();
DistanceFromExplosion *= ExplosionSizeInt * ExplosionSizeInt; DistanceFromExplosion *= Impact;
a_Entity.AddSpeed(DistanceFromExplosion); a_Entity.AddSpeed(DistanceFromExplosion);
}
return false; return false;
} }

@ -14,7 +14,7 @@
#include "Items/ItemHandler.h" #include "Items/ItemHandler.h"
#include "../FastRandom.h" #include "../FastRandom.h"
#include "../NetherPortalScanner.h" #include "../NetherPortalScanner.h"
#include "../BoundingBox.h"
@ -690,6 +690,33 @@ int cEntity::GetEnchantmentCoverAgainst(const cEntity * a_Attacker, eDamageType
float cEntity::GetEnchantmentBlastKnockbackReduction()
{
UInt32 MaxLevel = 0;
const cItem ArmorItems[] = { GetEquippedHelmet(), GetEquippedChestplate(), GetEquippedLeggings(), GetEquippedBoots() };
for (auto & Item : ArmorItems)
{
UInt32 Level = Item.m_Enchantments.GetLevel(cEnchantments::enchBlastProtection);
if (Level > MaxLevel)
{
// Get max blast protection
MaxLevel = Level;
}
}
// Max blast protect level is 4, each level provide 15% knock back reduction
MaxLevel = std::min<UInt32>(MaxLevel, 4);
return MaxLevel * 0.15f;
}
int cEntity::GetArmorCoverAgainst(const cEntity * a_Attacker, eDamageType a_DamageType, int a_Damage) int cEntity::GetArmorCoverAgainst(const cEntity * a_Attacker, eDamageType a_DamageType, int a_Damage)
{ {
// Returns the hitpoints out of a_RawDamage that the currently equipped armor would cover // Returns the hitpoints out of a_RawDamage that the currently equipped armor would cover
@ -2241,3 +2268,38 @@ void cEntity::RemoveLeashedMob(cMonster * a_Monster)
m_LeashedMobs.remove(a_Monster); m_LeashedMobs.remove(a_Monster);
} }
float cEntity::GetExplosionExposureRate(Vector3d a_ExplosionPosition, float a_ExlosionPower)
{
double EntitySize = m_Width * m_Width * m_Height;
if (EntitySize <= 0)
{
// Handle entity with invalid size
return 0;
}
cBoundingBox EntityBox(GetPosition(), m_Width / 2, m_Height);
cBoundingBox ExplosionBox(a_ExplosionPosition, a_ExlosionPower * 2.0);
cBoundingBox IntersectionBox(EntityBox);
bool Overlap = EntityBox.Intersect(ExplosionBox, IntersectionBox);
if (Overlap)
{
Vector3d Diff = IntersectionBox.GetMax() - IntersectionBox.GetMin();
double OverlapSize = Diff.x * Diff.y * Diff.z;
return static_cast<float>(OverlapSize / EntitySize);
}
else
{
return 0;
}
}

@ -333,6 +333,10 @@ public:
/** Returns the hitpoints that the currently equipped armor's enchantments would cover */ /** Returns the hitpoints that the currently equipped armor's enchantments would cover */
virtual int GetEnchantmentCoverAgainst(const cEntity * a_Attacker, eDamageType a_DamageType, int a_Damage); virtual int GetEnchantmentCoverAgainst(const cEntity * a_Attacker, eDamageType a_DamageType, int a_Damage);
/** Returns explosion knock back reduction percent from blast protection level
@return knock back reduce percent */
virtual float GetEnchantmentBlastKnockbackReduction();
/** Returns the knockback amount that the currently equipped items would cause to a_Receiver on a hit */ /** Returns the knockback amount that the currently equipped items would cause to a_Receiver on a hit */
virtual double GetKnockbackAmountAgainst(const cEntity & a_Receiver); virtual double GetKnockbackAmountAgainst(const cEntity & a_Receiver);
@ -545,6 +549,12 @@ public:
/** Returs whether the entity has any mob leashed to */ /** Returs whether the entity has any mob leashed to */
bool HasAnyMobLeashed() const { return m_LeashedMobs.size() > 0; } bool HasAnyMobLeashed() const { return m_LeashedMobs.size() > 0; }
/** a lightweight calculation approach to get explosion exposure rate
@param a_ExplosionPosition explosion position
@param a_ExlosionPower explosion power
@return exposure rate */
virtual float GetExplosionExposureRate(Vector3d a_ExplosionPosition, float a_ExlosionPower);
protected: protected:
/** Structure storing the portal delay timer and cooldown boolean */ /** Structure storing the portal delay timer and cooldown boolean */
struct sPortalCooldownData struct sPortalCooldownData
@ -714,5 +724,4 @@ private:
/** List of leashed mobs to this entity */ /** List of leashed mobs to this entity */
cMonsterList m_LeashedMobs; cMonsterList m_LeashedMobs;
} ; // tolua_export } ; // tolua_export

@ -3069,3 +3069,31 @@ float cPlayer::GetPlayerRelativeBlockHardness(BLOCKTYPE a_Block)
// LOGD("blockHardness: %f, digSpeed: %f, canHarvestBlockDivisor: %f\n", blockHardness, digSpeed, canHarvestBlockDivisor); // LOGD("blockHardness: %f, digSpeed: %f, canHarvestBlockDivisor: %f\n", blockHardness, digSpeed, canHarvestBlockDivisor);
return (blockHardness < 0) ? 0 : ((digSpeed / blockHardness) / canHarvestBlockDivisor); return (blockHardness < 0) ? 0 : ((digSpeed / blockHardness) / canHarvestBlockDivisor);
} }
float cPlayer::GetExplosionExposureRate(Vector3d a_ExplosionPosition, float a_ExlosionPower)
{
if (
IsGameModeSpectator() ||
(IsGameModeCreative() && !IsOnGround())
)
{
return 0; // No impact from explosion
}
return super::GetExplosionExposureRate(a_ExplosionPosition, a_ExlosionPower);
}

@ -759,6 +759,8 @@ protected:
This can be used both for online and offline UUIDs. */ This can be used both for online and offline UUIDs. */
AString GetUUIDFileName(const cUUID & a_UUID); AString GetUUIDFileName(const cUUID & a_UUID);
/** get player explosion exposure rate */
virtual float GetExplosionExposureRate(Vector3d a_ExplosionPosition, float a_ExlosionPower) override;
private: private:
/** Pins the player to a_Location until Unfreeze() is called. /** Pins the player to a_Location until Unfreeze() is called.

@ -1430,7 +1430,6 @@ void cWorld::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_Blo
} }
// TODO: Implement block hardiness // TODO: Implement block hardiness
Vector3d explosion_pos = Vector3d(a_BlockX, a_BlockY, a_BlockZ);
cVector3iArray BlocksAffected; cVector3iArray BlocksAffected;
m_ChunkMap->DoExplosionAt(a_ExplosionSize, a_BlockX, a_BlockY, a_BlockZ, BlocksAffected); m_ChunkMap->DoExplosionAt(a_ExplosionSize, a_BlockX, a_BlockY, a_BlockZ, BlocksAffected);
BroadcastSoundEffect("entity.generic.explode", Vector3d(a_BlockX, a_BlockY, a_BlockZ), 1.0f, 0.6f); BroadcastSoundEffect("entity.generic.explode", Vector3d(a_BlockX, a_BlockY, a_BlockZ), 1.0f, 0.6f);
@ -1445,19 +1444,7 @@ void cWorld::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_Blo
continue; continue;
} }
Vector3d distance_explosion = (*itr)->GetPosition() - explosion_pos; ch->SendExplosion(a_BlockX, a_BlockY, a_BlockZ, static_cast<float>(a_ExplosionSize), BlocksAffected, (*itr)->GetSpeed());
if (distance_explosion.SqrLength() < 4096.0)
{
double real_distance = std::max(0.004, distance_explosion.Length());
double power = a_ExplosionSize / real_distance;
if (power <= 1)
{
power = 0;
}
distance_explosion.Normalize();
distance_explosion *= power;
ch->SendExplosion(a_BlockX, a_BlockY, a_BlockZ, static_cast<float>(a_ExplosionSize), BlocksAffected, distance_explosion);
}
} }
} }