summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/BlockInfo.cpp2
-rw-r--r--src/Blocks/BlockFarmland.h6
-rw-r--r--src/Entities/Pawn.cpp87
-rw-r--r--src/Entities/Pawn.h3
4 files changed, 64 insertions, 34 deletions
diff --git a/src/BlockInfo.cpp b/src/BlockInfo.cpp
index 9f29d3b31..556f8081f 100644
--- a/src/BlockInfo.cpp
+++ b/src/BlockInfo.cpp
@@ -1164,7 +1164,7 @@ float cBlockInfo::GetBlockHeight(const BLOCKTYPE Block)
case E_BLOCK_DARK_OAK_FENCE: return 1.5;
case E_BLOCK_DARK_OAK_FENCE_GATE: return 1.5;
case E_BLOCK_ENCHANTMENT_TABLE: return 0.75; // 12 pixels
- case E_BLOCK_FARMLAND: return 0.9375; // 15 pixels
+ // case E_BLOCK_FARMLAND: return 0.9375; // prevents trampling for mobs (#2015) and older clients (MC-85162)
case E_BLOCK_FENCE: return 1.5;
case E_BLOCK_JUNGLE_FENCE: return 1.5;
case E_BLOCK_JUNGLE_FENCE_GATE: return 1.5;
diff --git a/src/Blocks/BlockFarmland.h b/src/Blocks/BlockFarmland.h
index 3da27de43..9a458a1d6 100644
--- a/src/Blocks/BlockFarmland.h
+++ b/src/Blocks/BlockFarmland.h
@@ -46,8 +46,10 @@ public:
*/
static void TurnToDirt(cChunk & a_Chunk, const Vector3i a_AbsPos, const Vector3i a_RelPos)
{
- static const auto FarmlandHeight = cBlockInfo::GetBlockHeight(E_BLOCK_FARMLAND);
- static const auto FullHeightDelta = 1 - FarmlandHeight;
+ // Use cBlockInfo::GetBlockHeight when it doesn't break trampling for
+ // mobs and older clients anymore
+ static const auto FarmlandHeight = 0.9375;
+ static const auto FullHeightDelta = 0.0625;
a_Chunk.ForEachEntityInBox(
cBoundingBox(Vector3d(0.5, FarmlandHeight, 0.5) + a_AbsPos, 0.5, FullHeightDelta),
diff --git a/src/Entities/Pawn.cpp b/src/Entities/Pawn.cpp
index cf2dd274f..4e7ef206f 100644
--- a/src/Entities/Pawn.cpp
+++ b/src/Entities/Pawn.cpp
@@ -321,7 +321,7 @@ void cPawn::HandleFalling(void)
With this in mind, we first check the block at the player's feet, then the one below that (because fences),
and decide which behaviour we want to go with.
*/
- BLOCKTYPE BlockAtFoot = (cChunkDef::IsValidHeight(POS_TOINT)) ? GetWorld()->GetBlock(POS_TOINT) : static_cast<BLOCKTYPE>(E_BLOCK_AIR);
+ const auto BlockAtFoot = (cChunkDef::IsValidHeight(POS_TOINT)) ? GetWorld()->GetBlock(POS_TOINT) : static_cast<BLOCKTYPE>(E_BLOCK_AIR);
/* We initialize these with what the foot is really IN, because for sampling we will move down with the epsilon above */
bool IsFootInWater = IsBlockWater(BlockAtFoot);
@@ -431,9 +431,12 @@ void cPawn::HandleFalling(void)
if (OnGround)
{
- auto FallHeight = m_LastGroundHeight - GetPosY();
+ const auto FallHeight = m_LastGroundHeight - GetPosY();
auto Damage = static_cast<int>(FallHeight - 3.0);
+ const auto Below = POS_TOINT.addedY(-1);
+ const auto BlockBelow = (cChunkDef::IsValidHeight(Below)) ? GetWorld()->GetBlock(Below) : static_cast<BLOCKTYPE>(E_BLOCK_AIR);
+
if ((Damage > 0) && !FallDamageAbsorbed)
{
if (IsElytraFlying())
@@ -441,26 +444,22 @@ void cPawn::HandleFalling(void)
Damage = static_cast<int>(static_cast<float>(Damage) * 0.33);
}
- if (const auto Below = POS_TOINT.addedY(-1); Below.y >= 0)
+ if (BlockBelow == E_BLOCK_HAY_BALE)
{
- const auto BlockBelow = GetWorld()->GetBlock(Below);
-
- if (BlockBelow == E_BLOCK_HAY_BALE)
- {
- Damage = std::clamp(static_cast<int>(static_cast<float>(Damage) * 0.2), 1, 20);
- }
-
- // Fall particles
- GetWorld()->BroadcastParticleEffect(
- "blockdust",
- GetPosition(),
- { 0, 0, 0 },
- (Damage - 1.f) * ((0.3f - 0.1f) / (15.f - 1.f)) + 0.1f, // Map damage (1 - 15) to particle speed (0.1 - 0.3)
- static_cast<int>((Damage - 1.f) * ((50.f - 20.f) / (15.f - 1.f)) + 20.f), // Map damage (1 - 15) to particle quantity (20 - 50)
- { { BlockBelow, 0 } }
- );
+ Damage = std::clamp(static_cast<int>(static_cast<float>(Damage) * 0.2), 1, 20);
}
+ // Fall particles
+ // TODO: falling on a partial (e.g. slab) block shouldn't broadcast particles of the block below
+ GetWorld()->BroadcastParticleEffect(
+ "blockdust",
+ GetPosition(),
+ { 0, 0, 0 },
+ (Damage - 1.f) * ((0.3f - 0.1f) / (15.f - 1.f)) + 0.1f, // Map damage (1 - 15) to particle speed (0.1 - 0.3)
+ static_cast<int>((Damage - 1.f) * ((50.f - 20.f) / (15.f - 1.f)) + 20.f), // Map damage (1 - 15) to particle quantity (20 - 50)
+ { { BlockBelow, 0 } }
+ );
+
TakeDamage(dtFalling, nullptr, Damage, static_cast<float>(Damage), 0);
}
@@ -469,11 +468,9 @@ void cPawn::HandleFalling(void)
// Farmland trampling. Mobs smaller than 0.512 cubic blocks won't trample (Java Edition's behavior)
// We only have width and height, so we have to calculate Width^2
- if (GetWorld()->IsFarmlandTramplingEnabled() &&
- (BlockAtFoot == E_BLOCK_FARMLAND) &&
- (GetWidth() * GetWidth() * GetHeight() >= 0.512))
+ if (GetWorld()->IsFarmlandTramplingEnabled())
{
- HandleFarmlandTrampling(FallHeight);
+ HandleFarmlandTrampling(FallHeight, BlockAtFoot, BlockBelow);
}
}
else
@@ -490,18 +487,49 @@ void cPawn::HandleFalling(void)
-void cPawn::HandleFarmlandTrampling(double a_FallHeight)
+void cPawn::HandleFarmlandTrampling(const double a_FallHeight, const BLOCKTYPE a_BlockAtFoot, const BLOCKTYPE a_BlockBelow)
{
- bool ShouldTrample = true;
- auto & Random = GetRandomProvider();
-
// No trampling if FallHeight <= 0.6875
if (a_FallHeight <= 0.6875)
{
- ShouldTrample = false;
+ return;
}
+ // No trampling for mobs smaller than 0.512 cubic blocks
+ if (GetWidth() * GetWidth() * GetHeight() < 0.512)
+ {
+ return;
+ }
+
+ auto AbsPos = POS_TOINT;
+
+ // Check if the foot is "inside" a farmland - for 1.10.1 and newer clients
+ // If it isn't, check if the block below is a farmland - for mobs and older clients
+ if (a_BlockAtFoot != E_BLOCK_FARMLAND)
+ {
+ // These are probably the only blocks which:
+ // - can be placed on a farmland and shouldn't destroy it
+ // - will stop the player from falling down further
+ // - are less than 1 block high
+ if ((a_BlockAtFoot == E_BLOCK_HEAD) || (a_BlockAtFoot == E_BLOCK_FLOWER_POT))
+ {
+ return;
+ }
+
+ // Finally, check whether the block below is farmland
+ if (a_BlockBelow != E_BLOCK_FARMLAND)
+ {
+ return;
+ }
+
+ // If we haven't returned, decrease the height
+ AbsPos.y -= 1;
+ }
+
+ bool ShouldTrample = true;
+ auto & Random = GetRandomProvider();
+
// For FallHeight <= 1.5625 we need to get a random bool
- else if (a_FallHeight <= 1.0625)
+ if (a_FallHeight <= 1.0625)
{
ShouldTrample = Random.RandBool(0.25);
}
@@ -513,7 +541,6 @@ void cPawn::HandleFarmlandTrampling(double a_FallHeight)
if (ShouldTrample)
{
- auto AbsPos = GetPosition().Floor();
GetWorld()->DoWithChunkAt(AbsPos, [&](cChunk & Chunk)
{
cBlockFarmlandHandler::TurnToDirt(Chunk, AbsPos);
diff --git a/src/Entities/Pawn.h b/src/Entities/Pawn.h
index c0801ebb3..5aae1c21f 100644
--- a/src/Entities/Pawn.h
+++ b/src/Entities/Pawn.h
@@ -40,8 +40,9 @@ public:
fall height > 1.0625 and <= 1.5625: 66% chance of trampling
fall height > 1.5625: always trample
The values may differ from vanilla, they were determined experimentally.
+ Additionaly, mobs smaller than 0.512 cubic blocks won't trample.
*/
- void HandleFarmlandTrampling(double a_FallHeight);
+ void HandleFarmlandTrampling(double a_FallHeight, BLOCKTYPE a_BlockAtFoot, BLOCKTYPE a_BlockBelow);
/** Tells all pawns which are targeting us to stop targeting us. */
void StopEveryoneFromTargetingMe();