summaryrefslogtreecommitdiffstats
path: root/src/Entities
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/Entities/Entity.h3
-rw-r--r--src/Entities/Pickup.h2
-rw-r--r--src/Entities/Player.cpp95
-rw-r--r--src/Entities/Player.h3
4 files changed, 103 insertions, 0 deletions
diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h
index d55955b0c..fb3103abc 100644
--- a/src/Entities/Entity.h
+++ b/src/Entities/Entity.h
@@ -191,6 +191,9 @@ public:
/** Returns the topmost class's parent class name for the object. cEntity returns an empty string (no parent). */
virtual const char * GetParentClass(void) const;
+ /** Returns whether blocks can be placed intersecting this entities' hitbox */
+ virtual bool DoesPreventBlockPlacement(void) const { return true; }
+
cWorld * GetWorld(void) const { return m_World; }
double GetHeadYaw (void) const { return m_HeadYaw; } // In degrees
diff --git a/src/Entities/Pickup.h b/src/Entities/Pickup.h
index c2fcbd7f2..61e433e07 100644
--- a/src/Entities/Pickup.h
+++ b/src/Entities/Pickup.h
@@ -36,6 +36,8 @@ public:
virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
+ virtual bool DoesPreventBlockPlacement(void) const override { return false; }
+
/** Returns whether this pickup is allowed to combine with other similar pickups */
bool CanCombine(void) const { return m_bCanCombine; } // tolua_export
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index afeb8fa04..f66f2b73d 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -2641,8 +2641,103 @@ void cPlayer::SendBlocksAround(int a_BlockX, int a_BlockY, int a_BlockZ, int a_R
+bool cPlayer::DoesPlacingBlocksIntersectEntity(const sSetBlockVector & a_Blocks)
+{
+ // Compute the bounding box for each block to be placed
+ std::vector<cBoundingBox> PlacementBoxes;
+ cBoundingBox PlacingBounds(0, 0, 0, 0, 0, 0);
+ bool HasInitializedBounds = false;
+ for (auto blk: a_Blocks)
+ {
+ cBlockHandler * BlockHandler = cBlockInfo::GetHandler(blk.m_BlockType);
+ int x = blk.GetX();
+ int y = blk.GetY();
+ int z = blk.GetZ();
+ cBoundingBox BlockBox = BlockHandler->GetPlacementCollisionBox(
+ m_World->GetBlock(x - 1, y, z),
+ m_World->GetBlock(x + 1, y, z),
+ (y == 0) ? E_BLOCK_AIR : m_World->GetBlock(x, y - 1, z),
+ (y == cChunkDef::Height - 1) ? E_BLOCK_AIR : m_World->GetBlock(x, y + 1, z),
+ m_World->GetBlock(x, y, z - 1),
+ m_World->GetBlock(x, y, z + 1)
+ );
+ BlockBox.Move(x, y, z);
+
+ PlacementBoxes.push_back(BlockBox);
+
+ if (HasInitializedBounds)
+ {
+ PlacingBounds = PlacingBounds.Union(BlockBox);
+ }
+ else
+ {
+ PlacingBounds = BlockBox;
+ HasInitializedBounds = true;
+ }
+ }
+
+ cWorld * World = GetWorld();
+
+ // Check to see if any entity intersects any block being placed
+ class DoesIntersectBlock : public cEntityCallback
+ {
+ public:
+ const std::vector<cBoundingBox> & m_BoundingBoxes;
+
+ // The distance inside the block the entity can still be.
+ const double EPSILON = 0.0005;
+
+ DoesIntersectBlock(const std::vector<cBoundingBox> & a_BoundingBoxes) :
+ m_BoundingBoxes(a_BoundingBoxes)
+ {
+ }
+
+ virtual bool Item(cEntity * a_Entity) override
+ {
+ if (!a_Entity->DoesPreventBlockPlacement())
+ {
+ return false;
+ }
+ cBoundingBox EntBox(a_Entity->GetPosition(), a_Entity->GetWidth() / 2, a_Entity->GetHeight());
+ for (auto BlockBox: m_BoundingBoxes)
+ {
+
+ // Put in a little bit of wiggle room
+ BlockBox.Expand(-EPSILON, -EPSILON, -EPSILON);
+ if (EntBox.DoesIntersect(BlockBox))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+ } Callback(PlacementBoxes);
+
+ // See if any entities in that bounding box collide with anyone
+ if (!World->ForEachEntityInBox(PlacingBounds, Callback))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+
+
+
+
bool cPlayer::PlaceBlocks(const sSetBlockVector & a_Blocks)
{
+ if (DoesPlacingBlocksIntersectEntity(a_Blocks))
+ {
+ // Abort - re-send all the current blocks in the a_Blocks' coords to the client:
+ for (auto blk2: a_Blocks)
+ {
+ m_World->SendBlockTo(blk2.GetX(), blk2.GetY(), blk2.GetZ(), this);
+ }
+ return false;
+ }
+
// Call the "placing" hooks; if any fail, abort:
cPluginManager * pm = cPluginManager::Get();
for (auto blk: a_Blocks)
diff --git a/src/Entities/Player.h b/src/Entities/Player.h
index 8ad803998..c00dbc7f1 100644
--- a/src/Entities/Player.h
+++ b/src/Entities/Player.h
@@ -485,6 +485,9 @@ public:
/** Update movement-related statistics. */
void UpdateMovementStats(const Vector3d & a_DeltaPos, bool a_PreviousIsOnGround);
+ /** Whether placing the given blocks would intersect any entitiy */
+ bool DoesPlacingBlocksIntersectEntity(const sSetBlockVector & a_Blocks);
+
// tolua_begin
/** Returns wheter the player can fly or not. */