blockheight mechanism
This commit is contained in:
@@ -55,8 +55,6 @@ cPlayer::cPlayer(cClientHandlePtr a_Client, const AString & a_PlayerName) :
|
||||
m_FoodSaturationLevel(5.0),
|
||||
m_FoodTickTimer(0),
|
||||
m_FoodExhaustionLevel(0.0),
|
||||
m_LastGroundHeight(0),
|
||||
m_bTouchGround(false),
|
||||
m_Stance(0.0),
|
||||
m_Inventory(*this),
|
||||
m_EnderChestContents(9, 3),
|
||||
@@ -451,101 +449,6 @@ void cPlayer::SetTouchGround(bool a_bTouchGround)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Not pretty looking, and is more suited to wherever server-sided collision detection is implemented.
|
||||
The following condition sets on-ground-ness if
|
||||
The player isn't swimming or flying (client hardcoded conditions) and
|
||||
they're on a block (Y is exact) - ensure any they could be standing on (including on the edges) is solid or
|
||||
they're on a slab (Y significand is 0.5) - ditto with slab check
|
||||
they're on a snow layer (Y divisible by 0.125) - ditto with snow layer check
|
||||
*/
|
||||
|
||||
static const auto HalfWidth = GetWidth() / 2;
|
||||
static const auto EPS = 0.0001;
|
||||
|
||||
/* Since swimming is decided in a tick and is asynchronous to this, we have to check for dampeners ourselves.
|
||||
The behaviour as of 1.8.8 is the following:
|
||||
- Landing in water alleviates all fall damage
|
||||
- Passing through any liquid (water + lava) and cobwebs "slows" the player down,
|
||||
i.e. resets the fall distance to that block, but only after checking for fall damage
|
||||
(this means that plummeting into lava will still kill the player via fall damage, although cobwebs
|
||||
will slow players down enough to have multiple updates that keep them alive)
|
||||
|
||||
With this in mind, we first check the block at the player's feet, and decide which behaviour we want to go with.
|
||||
*/
|
||||
BLOCKTYPE BlockAtFoot = (cChunkDef::IsValidHeight(GetPosY())) ? GetWorld()->GetBlock(POS_TOINT) : E_BLOCK_AIR;
|
||||
bool IsFootInWater = IsBlockWater(BlockAtFoot);
|
||||
bool IsFootInLiquid = IsFootInWater || IsBlockLava(BlockAtFoot) || (BlockAtFoot == E_BLOCK_COBWEB); // okay so cobweb is not _technically_ a liquid...
|
||||
|
||||
if (
|
||||
!IsFlying() &&
|
||||
(
|
||||
(
|
||||
(cChunkDef::IsValidHeight(GetPosY()) && ((GetPosY() - POSY_TOINT) <= EPS)) &&
|
||||
(
|
||||
cBlockInfo::IsSolid(GetWorld()->GetBlock((GetPosition() + Vector3d(0, -1, 0)).Floor())) ||
|
||||
cBlockInfo::IsSolid(GetWorld()->GetBlock((GetPosition() + Vector3d(HalfWidth, -1, 0)).Floor())) ||
|
||||
cBlockInfo::IsSolid(GetWorld()->GetBlock((GetPosition() + Vector3d(-HalfWidth, -1, 0)).Floor())) ||
|
||||
cBlockInfo::IsSolid(GetWorld()->GetBlock((GetPosition() + Vector3d(0, -1, HalfWidth)).Floor())) ||
|
||||
cBlockInfo::IsSolid(GetWorld()->GetBlock((GetPosition() + Vector3d(0, -1, -HalfWidth)).Floor()))
|
||||
)
|
||||
) ||
|
||||
(
|
||||
(cChunkDef::IsValidHeight(GetPosY()) && (GetPosY() >= POSY_TOINT) && ((GetPosY() - (POSY_TOINT + 0.5)) <= EPS)) &&
|
||||
(
|
||||
cBlockSlabHandler::IsAnySlabType(GetWorld()->GetBlock((GetPosition() + Vector3d(0, 0, 0)).Floor())) ||
|
||||
cBlockSlabHandler::IsAnySlabType(GetWorld()->GetBlock((GetPosition() + Vector3d(HalfWidth, 0, 0)).Floor())) ||
|
||||
cBlockSlabHandler::IsAnySlabType(GetWorld()->GetBlock((GetPosition() + Vector3d(-HalfWidth, 0, 0)).Floor())) ||
|
||||
cBlockSlabHandler::IsAnySlabType(GetWorld()->GetBlock((GetPosition() + Vector3d(0, 0, HalfWidth)).Floor())) ||
|
||||
cBlockSlabHandler::IsAnySlabType(GetWorld()->GetBlock((GetPosition() + Vector3d(0, 0, -HalfWidth)).Floor()))
|
||||
)
|
||||
) ||
|
||||
(
|
||||
(cChunkDef::IsValidHeight(GetPosY()) && (fmod(GetPosY(), 0.125) <= EPS)) &&
|
||||
(
|
||||
(GetWorld()->GetBlock((GetPosition() + Vector3d(0, 0, 0)).Floor()) == E_BLOCK_SNOW) ||
|
||||
(GetWorld()->GetBlock((GetPosition() + Vector3d(HalfWidth, 0, 0)).Floor()) == E_BLOCK_SNOW) ||
|
||||
(GetWorld()->GetBlock((GetPosition() + Vector3d(-HalfWidth, 0, 0)).Floor()) == E_BLOCK_SNOW) ||
|
||||
(GetWorld()->GetBlock((GetPosition() + Vector3d(0, 0, HalfWidth)).Floor()) == E_BLOCK_SNOW) ||
|
||||
(GetWorld()->GetBlock((GetPosition() + Vector3d(0, 0, -HalfWidth)).Floor()) == E_BLOCK_SNOW)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
{
|
||||
auto Damage = static_cast<int>(m_LastGroundHeight - GetPosY() - 3.0);
|
||||
if ((Damage > 0) && !IsFootInWater)
|
||||
{
|
||||
// cPlayer makes sure damage isn't applied in creative, no need to check here
|
||||
TakeDamage(dtFalling, nullptr, Damage, Damage, 0);
|
||||
|
||||
// Fall particles
|
||||
Damage = std::min(15, Damage);
|
||||
GetClientHandle()->SendParticleEffect(
|
||||
"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)
|
||||
{ { GetWorld()->GetBlock(POS_TOINT - Vector3i(0, 1, 0)), 0 } }
|
||||
);
|
||||
}
|
||||
|
||||
m_bTouchGround = true;
|
||||
m_LastGroundHeight = GetPosY();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_bTouchGround = false;
|
||||
}
|
||||
|
||||
/* Note: it is currently possible to fall through lava and still die from fall damage
|
||||
because of the client skipping an update about the lava block. This can only be resolved by
|
||||
interpolating between positions. */
|
||||
if (IsFlying() || IsFootInLiquid || IsClimbing())
|
||||
{
|
||||
m_LastGroundHeight = GetPosY();
|
||||
}
|
||||
|
||||
UNUSED(a_bTouchGround);
|
||||
/* Unfortunately whatever the reason, there are still desyncs in on-ground status between the client and server. For example:
|
||||
1. Walking off a ledge (whatever height)
|
||||
|
||||
Reference in New Issue
Block a user