1
0

blockheight mechanism

This commit is contained in:
Gargaj
2015-11-10 14:02:07 +01:00
parent fec522aa03
commit 66e6589883
16 changed files with 294 additions and 128 deletions

View File

@@ -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)