1
0
Fork 0

Fix lilypad displacing block above (#5056)

* Fix lilypad displacing block above

Side fixes:
* Fix lilypad displacing half slabs
* Fix lilypad being placed on flowing water and non-water blocks in
general

Co-authored-by: Tiger Wang <ziwei.tiger@outlook.com>
This commit is contained in:
Derek Qu 2020-11-27 20:01:47 -05:00 committed by GitHub
parent 280f7a81f4
commit 7027b2279f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 61 additions and 39 deletions

View File

@ -44,10 +44,35 @@ public:
eBlockFace a_ClickedBlockFace
) override
{
if (a_ClickedBlockFace > BLOCK_FACE_NONE)
// The client sends BLOCK_FACE_NONE when it determines it should do a tracing-based placement.
// Otherwise, a normal block face is sent.
if (a_ClickedBlockFace != BLOCK_FACE_NONE)
{
// Clicked on a face of a submerged block; vanilla allows placement, so should we
auto PlacePos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace);
// The position the client wants the lilypad placed.
const auto PlacePos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace);
// Lilypad should not replace non air and non water blocks:
if (
const auto BlockToReplace = a_World->GetBlock(PlacePos);
(BlockToReplace != E_BLOCK_AIR) &&
(BlockToReplace != E_BLOCK_WATER) &&
(BlockToReplace != E_BLOCK_STATIONARY_WATER)
)
{
return false;
}
// Lilypad should be placed only if there is a water block below
if (
const auto BlockBelow = a_World->GetBlock(PlacePos.addedY(-1));
(BlockBelow != E_BLOCK_WATER) &&
(BlockBelow != E_BLOCK_STATIONARY_WATER)
)
{
return false;
}
a_World->SetBlock(PlacePos, E_BLOCK_LILY_PAD, 0);
if (!a_Player->IsGameModeCreative())
{
@ -61,53 +86,50 @@ public:
{
public:
cCallbacks():
m_HasHitFluid(false)
{
}
virtual bool OnNextBlock(Vector3i a_CBBlockPos, BLOCKTYPE a_CBBlockType, NIBBLETYPE a_CBBlockMeta, eBlockFace a_CBEntryFace) override
{
if (IsBlockWater(a_CBBlockType))
if (
!IsBlockWater(a_CBBlockType) ||
(a_CBBlockMeta != 0) // The hit block should be a source
)
{
if ((a_CBBlockMeta != 0) || (a_CBEntryFace == BLOCK_FACE_NONE)) // The hit block should be a source. The FACE_NONE check is clicking whilst submerged
{
return false;
}
a_CBBlockPos = AddFaceDirection(a_CBBlockPos, BLOCK_FACE_YP); // Always place pad at top of water block
if (
!IsBlockWater(a_CBBlockType) &&
cBlockInfo::FullyOccupiesVoxel(a_CBBlockType)
)
{
// Can't place lilypad on air / in another block!
return true;
}
m_HasHitFluid = true;
m_Pos = a_CBBlockPos;
return true;
// TODO: Vanilla stops the trace. However, we need to continue the trace, to work around our lack of block bounding box support
// which would otherwise mean we misbehave when clicking through the voxel a (e.g.) button occupies. Now, however, we misbehave
// when clicking on a block near water... Nonetheless, the former would cause ghost blocks, so continue for now.
// Ignore and continue trace:
return false;
}
return false;
Position = AddFaceDirection(a_CBBlockPos, BLOCK_FACE_YP); // Always place pad at top of water block
return true;
}
Vector3i m_Pos;
bool m_HasHitFluid;
Vector3i Position;
} Callbacks;
auto Start = a_Player->GetEyePosition() + a_Player->GetLookVector();
auto End = a_Player->GetEyePosition() + a_Player->GetLookVector() * 5;
cLineBlockTracer::Trace(*a_Player->GetWorld(), Callbacks, Start, End);
if (Callbacks.m_HasHitFluid)
const auto EyePosition = a_Player->GetEyePosition();
const auto End = EyePosition + a_Player->GetLookVector() * 5;
if (cLineBlockTracer::Trace(*a_Player->GetWorld(), Callbacks, EyePosition, End))
{
a_World->SetBlock(Callbacks.m_Pos, E_BLOCK_LILY_PAD, 0);
if (!a_Player->IsGameModeCreative())
{
a_Player->GetInventory().RemoveOneEquippedItem();
}
return true;
// The line traced to completion; no suitable water was found:
return false;
}
return false;
const auto BlockToReplace = a_World->GetBlock(Callbacks.Position);
if (BlockToReplace != E_BLOCK_AIR)
{
// Lilypad should not replace non air blocks:
return false;
}
a_World->SetBlock(Callbacks.Position, E_BLOCK_LILY_PAD, 0);
if (!a_Player->IsGameModeCreative())
{
a_Player->GetInventory().RemoveOneEquippedItem();
}
return true;
}
};