diff options
Diffstat (limited to '')
-rw-r--r-- | src/Blocks/BlockDoor.cpp | 10 | ||||
-rw-r--r-- | src/Blocks/BlockDoor.h | 2 | ||||
-rw-r--r-- | src/Blocks/BlockFence.h | 80 | ||||
-rw-r--r-- | src/Blocks/BlockHandler.cpp | 23 | ||||
-rw-r--r-- | src/Blocks/BlockHandler.h | 7 | ||||
-rw-r--r-- | src/Blocks/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/BoundingBox.cpp | 15 | ||||
-rw-r--r-- | src/BoundingBox.h | 2 | ||||
-rw-r--r-- | src/ChunkDef.h | 3 | ||||
-rw-r--r-- | src/Entities/Entity.h | 3 | ||||
-rw-r--r-- | src/Entities/Pickup.h | 2 | ||||
-rw-r--r-- | src/Entities/Player.cpp | 95 | ||||
-rw-r--r-- | src/Entities/Player.h | 3 |
13 files changed, 243 insertions, 3 deletions
diff --git a/src/Blocks/BlockDoor.cpp b/src/Blocks/BlockDoor.cpp index c2b0f66d8..2662dc261 100644 --- a/src/Blocks/BlockDoor.cpp +++ b/src/Blocks/BlockDoor.cpp @@ -106,6 +106,16 @@ void cBlockDoorHandler::OnCancelRightClick(cChunkInterface & a_ChunkInterface, c +cBoundingBox cBlockDoorHandler::GetPlacementCollisionBox(BLOCKTYPE a_XM, BLOCKTYPE a_XP, BLOCKTYPE a_YM, BLOCKTYPE a_YP, BLOCKTYPE a_ZM, BLOCKTYPE a_ZP) +{ + // Doors can be placed inside the player + return cBoundingBox(0, 0, 0, 0, 0, 0); +} + + + + + NIBBLETYPE cBlockDoorHandler::MetaRotateCCW(NIBBLETYPE a_Meta) { if (a_Meta & 0x08) diff --git a/src/Blocks/BlockDoor.h b/src/Blocks/BlockDoor.h index a19cbdc40..4b9eaa320 100644 --- a/src/Blocks/BlockDoor.h +++ b/src/Blocks/BlockDoor.h @@ -52,6 +52,8 @@ public: return true; } + virtual cBoundingBox GetPlacementCollisionBox(BLOCKTYPE a_XM, BLOCKTYPE a_XP, BLOCKTYPE a_YM, BLOCKTYPE a_YP, BLOCKTYPE a_ZM, BLOCKTYPE a_ZP) override; + virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override { if ((a_BlockMeta & 0x08) != 0) // is top part of door diff --git a/src/Blocks/BlockFence.h b/src/Blocks/BlockFence.h new file mode 100644 index 000000000..92f52cbbe --- /dev/null +++ b/src/Blocks/BlockFence.h @@ -0,0 +1,80 @@ + +#pragma once + +#include "BlockHandler.h" +#include "BlockID.h" +#include "../BoundingBox.h" + + + + +class cBlockFenceHandler : + public cBlockHandler +{ +public: + // These are the min and max coordinates (X and Z) for a straight fence. + // 0.4 and 0.6 are really just guesses, but they seem pretty good. + // (0.4 to 0.6 is a fence that's 0.2 wide, down the center of the block) + const double MIN_COORD = 0.4; + const double MAX_COORD = 0.6; + + cBlockFenceHandler(BLOCKTYPE a_BlockType) + : cBlockHandler(a_BlockType) + { + } + + virtual cBoundingBox GetPlacementCollisionBox(BLOCKTYPE a_XM, BLOCKTYPE a_XP, BLOCKTYPE a_YM, BLOCKTYPE a_YP, BLOCKTYPE a_ZM, BLOCKTYPE a_ZP) override + { + bool XMSolid = cBlockInfo::IsSolid(a_XM); + bool XPSolid = cBlockInfo::IsSolid(a_XP); + bool ZMSolid = cBlockInfo::IsSolid(a_ZM); + bool ZPSolid = cBlockInfo::IsSolid(a_ZP); + + double FENCE_HEIGHT = cBlockInfo::GetBlockHeight(m_BlockType); + + // Entities can never be in the center + cBoundingBox PlacementBox(MIN_COORD, MAX_COORD, 0, FENCE_HEIGHT, MIN_COORD, MAX_COORD); + + // For each solid neighbor, the hitbox extends that way + if (XMSolid) + { + PlacementBox = PlacementBox.Union(cBoundingBox(0, 0.5, 0, FENCE_HEIGHT, MIN_COORD, MAX_COORD)); + } + if (XPSolid) + { + PlacementBox = PlacementBox.Union(cBoundingBox(0.5, 1.0, 0, FENCE_HEIGHT, MIN_COORD, MAX_COORD)); + } + if (ZMSolid) + { + PlacementBox = PlacementBox.Union(cBoundingBox(MIN_COORD, MAX_COORD, 0, FENCE_HEIGHT, 0.0, 0.5)); + } + if (ZPSolid) + { + PlacementBox = PlacementBox.Union(cBoundingBox(MIN_COORD, MAX_COORD, 0, FENCE_HEIGHT, 0.5, 1.0)); + } + + // For each corner, fill in the corner + if (XMSolid && ZMSolid) + { + PlacementBox = PlacementBox.Union(cBoundingBox(0, 0.5, 0, FENCE_HEIGHT, 0, 0.5)); + } + if (XPSolid && ZMSolid) + { + PlacementBox = PlacementBox.Union(cBoundingBox(0.5, 1.0, 0, FENCE_HEIGHT, 0, 0.5)); + } + if (XPSolid && ZPSolid) + { + PlacementBox = PlacementBox.Union(cBoundingBox(0.5, 1.0, 0, FENCE_HEIGHT, 0.5, 1.0)); + } + if (XMSolid && ZPSolid) + { + PlacementBox = PlacementBox.Union(cBoundingBox(0, 0.5, 0, FENCE_HEIGHT, 0.5, 1.0)); + } + + return PlacementBox; + } +}; + + + + diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp index 4b37d42ad..305676984 100644 --- a/src/Blocks/BlockHandler.cpp +++ b/src/Blocks/BlockHandler.cpp @@ -29,6 +29,7 @@ #include "BlockEnderchest.h" #include "BlockEntity.h" #include "BlockFarmland.h" +#include "BlockFence.h" #include "BlockFenceGate.h" #include "BlockFire.h" #include "BlockFlower.h" @@ -181,6 +182,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType) { // Block handlers, alphabetically sorted: case E_BLOCK_ACACIA_DOOR: return new cBlockDoorHandler (a_BlockType); + case E_BLOCK_ACACIA_FENCE: return new cBlockFenceHandler (a_BlockType); case E_BLOCK_ACACIA_FENCE_GATE: return new cBlockFenceGateHandler (a_BlockType); case E_BLOCK_ACACIA_WOOD_STAIRS: return new cBlockStairsHandler (a_BlockType); case E_BLOCK_ACTIVATOR_RAIL: return new cBlockRailHandler (a_BlockType); @@ -190,6 +192,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType) case E_BLOCK_BEETROOTS: return new cBlockCropsHandler<3> (a_BlockType); // 4 stages of growth case E_BLOCK_BIG_FLOWER: return new cBlockBigFlowerHandler (a_BlockType); case E_BLOCK_BIRCH_DOOR: return new cBlockDoorHandler (a_BlockType); + case E_BLOCK_BIRCH_FENCE: return new cBlockFenceHandler (a_BlockType); case E_BLOCK_BIRCH_FENCE_GATE: return new cBlockFenceGateHandler (a_BlockType); case E_BLOCK_BIRCH_WOOD_STAIRS: return new cBlockStairsHandler (a_BlockType); case E_BLOCK_BREWING_STAND: return new cBlockBrewingStandHandler (a_BlockType); @@ -212,6 +215,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType) case E_BLOCK_COBWEB: return new cBlockCobWebHandler (a_BlockType); case E_BLOCK_CROPS: return new cBlockCropsHandler<7> (a_BlockType); // 8 stages of growth case E_BLOCK_DARK_OAK_DOOR: return new cBlockDoorHandler (a_BlockType); + case E_BLOCK_DARK_OAK_FENCE: return new cBlockFenceHandler (a_BlockType); case E_BLOCK_DARK_OAK_FENCE_GATE: return new cBlockFenceGateHandler (a_BlockType); case E_BLOCK_DARK_OAK_WOOD_STAIRS: return new cBlockStairsHandler (a_BlockType); case E_BLOCK_DEAD_BUSH: return new cBlockDeadBushHandler (a_BlockType); @@ -227,6 +231,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType) case E_BLOCK_ENCHANTMENT_TABLE: return new cBlockEnchantmentTableHandler(a_BlockType); case E_BLOCK_ENDER_CHEST: return new cBlockEnderchestHandler (a_BlockType); case E_BLOCK_FARMLAND: return new cBlockFarmlandHandler (a_BlockType); + case E_BLOCK_FENCE: return new cBlockFenceHandler (a_BlockType); case E_BLOCK_FROSTED_ICE: return new cBlockIceHandler (a_BlockType); case E_BLOCK_FIRE: return new cBlockFireHandler (a_BlockType); case E_BLOCK_FLOWER_POT: return new cBlockFlowerPotHandler (a_BlockType); @@ -249,6 +254,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType) case E_BLOCK_JACK_O_LANTERN: return new cBlockPumpkinHandler (a_BlockType); case E_BLOCK_JUKEBOX: return new cBlockEntityHandler (a_BlockType); case E_BLOCK_JUNGLE_DOOR: return new cBlockDoorHandler (a_BlockType); + case E_BLOCK_JUNGLE_FENCE: return new cBlockFenceHandler (a_BlockType); case E_BLOCK_JUNGLE_FENCE_GATE: return new cBlockFenceGateHandler (a_BlockType); case E_BLOCK_JUNGLE_WOOD_STAIRS: return new cBlockStairsHandler (a_BlockType); case E_BLOCK_LADDER: return new cBlockLadderHandler (a_BlockType); @@ -264,6 +270,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType) case E_BLOCK_MELON_STEM: return new cBlockStemsHandler (a_BlockType); case E_BLOCK_MOB_SPAWNER: return new cBlockMobSpawnerHandler (a_BlockType); case E_BLOCK_MYCELIUM: return new cBlockMyceliumHandler (a_BlockType); + case E_BLOCK_NETHER_BRICK_FENCE: return new cBlockFenceHandler (a_BlockType); case E_BLOCK_NETHER_BRICK_STAIRS: return new cBlockStairsHandler (a_BlockType); case E_BLOCK_NETHER_PORTAL: return new cBlockPortalHandler (a_BlockType); case E_BLOCK_NETHER_WART: return new cBlockNetherWartHandler (a_BlockType); @@ -308,6 +315,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType) case E_BLOCK_SNOW: return new cBlockSnowHandler (a_BlockType); case E_BLOCK_SLIME_BLOCK: return new cBlockSlimeHandler (a_BlockType); case E_BLOCK_SPRUCE_DOOR: return new cBlockDoorHandler (a_BlockType); + case E_BLOCK_SPRUCE_FENCE: return new cBlockFenceHandler (a_BlockType); case E_BLOCK_SPRUCE_FENCE_GATE: return new cBlockFenceGateHandler (a_BlockType); case E_BLOCK_SPRUCE_WOOD_STAIRS: return new cBlockStairsHandler (a_BlockType); case E_BLOCK_STAINED_GLASS: return new cBlockGlassHandler (a_BlockType); @@ -555,7 +563,6 @@ void cBlockHandler::DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterfac - bool cBlockHandler::CanBeAt(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ, const cChunk & a_Chunk) { return true; @@ -611,6 +618,20 @@ bool cBlockHandler::IsInsideBlock(const Vector3d & a_Position, const BLOCKTYPE a +cBoundingBox cBlockHandler::GetPlacementCollisionBox(BLOCKTYPE a_XM, BLOCKTYPE a_XP, BLOCKTYPE a_YM, BLOCKTYPE a_YP, BLOCKTYPE a_ZM, BLOCKTYPE a_ZP) +{ + if (!cBlockInfo::IsSolid(m_BlockType)) + { + // Non-solid things can be placed within entities + return cBoundingBox(0, 0, 0, 0, 0, 0); + } + return cBoundingBox(0, 1, 0, cBlockInfo::GetBlockHeight(m_BlockType), 0, 1); +} + + + + + void cBlockHandler::Check(cChunkInterface & a_ChunkInterface, cBlockPluginInterface & a_PluginInterface, int a_RelX, int a_RelY, int a_RelZ, cChunk & a_Chunk) { if (!CanBeAt(a_ChunkInterface, a_RelX, a_RelY, a_RelZ, a_Chunk)) diff --git a/src/Blocks/BlockHandler.h b/src/Blocks/BlockHandler.h index 302fdbc4b..e67058830 100644 --- a/src/Blocks/BlockHandler.h +++ b/src/Blocks/BlockHandler.h @@ -3,6 +3,8 @@ #include "../Defines.h" +#include "../BoundingBox.h" + @@ -30,6 +32,11 @@ public: Note that the coords are chunk-relative! */ virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ); + /** Returns the relative bounding box that must be entity-free in + order for the block to be placed. a_XM, a_XP, etc. stand for the + blocktype of the minus-X neighbor, the positive-X neighbor, etc. */ + virtual cBoundingBox GetPlacementCollisionBox(BLOCKTYPE a_XM, BLOCKTYPE a_XP, BLOCKTYPE a_YM, BLOCKTYPE a_YP, BLOCKTYPE a_ZM, BLOCKTYPE a_ZP); + /** Called before a block is placed into a world. The handler should return true to allow placement, false to refuse. Also, the handler should set a_BlockType and a_BlockMeta to correct values for the newly placed block. diff --git a/src/Blocks/CMakeLists.txt b/src/Blocks/CMakeLists.txt index 9f46a6809..bc1b62290 100644 --- a/src/Blocks/CMakeLists.txt +++ b/src/Blocks/CMakeLists.txt @@ -35,6 +35,7 @@ SET (HDRS BlockEnderchest.h BlockEntity.h BlockFarmland.h + BlockFence.h BlockFenceGate.h BlockFire.h BlockFlower.h diff --git a/src/BoundingBox.cpp b/src/BoundingBox.cpp index ecf810fa8..3e32fd3ef 100644 --- a/src/BoundingBox.cpp +++ b/src/BoundingBox.cpp @@ -60,6 +60,17 @@ cBoundingBox::cBoundingBox(const cBoundingBox & a_Orig) : +cBoundingBox & cBoundingBox::operator=(const cBoundingBox & a_Other) +{ + m_Min = a_Other.m_Min; + m_Max = a_Other.m_Max; + return *this; +} + + + + + void cBoundingBox::Move(double a_OffX, double a_OffY, double a_OffZ) { m_Min.x += a_OffX; @@ -119,10 +130,10 @@ cBoundingBox cBoundingBox::Union(const cBoundingBox & a_Other) { return cBoundingBox( std::min(m_Min.x, a_Other.m_Min.x), - std::min(m_Min.y, a_Other.m_Min.y), - std::min(m_Min.z, a_Other.m_Min.z), std::max(m_Max.x, a_Other.m_Max.x), + std::min(m_Min.y, a_Other.m_Min.y), std::max(m_Max.y, a_Other.m_Max.y), + std::min(m_Min.z, a_Other.m_Min.z), std::max(m_Max.z, a_Other.m_Max.z) ); } diff --git a/src/BoundingBox.h b/src/BoundingBox.h index 38d567562..3641f4061 100644 --- a/src/BoundingBox.h +++ b/src/BoundingBox.h @@ -30,6 +30,8 @@ public: cBoundingBox(const Vector3d & a_Pos, double a_CubeLength); cBoundingBox(const cBoundingBox & a_Orig); + cBoundingBox & operator=(const cBoundingBox & a_Other); + /** Moves the entire boundingbox by the specified offset */ void Move(double a_OffX, double a_OffY, double a_OffZ); diff --git a/src/ChunkDef.h b/src/ChunkDef.h index 41ba44417..bf0f20514 100644 --- a/src/ChunkDef.h +++ b/src/ChunkDef.h @@ -402,6 +402,9 @@ struct sSetBlock /** Returns the absolute Z coord of the stored block. */ int GetZ(void) const { return m_RelZ + cChunkDef::Width * m_ChunkZ; } + + /** Returns the absolute position of the stored block. */ + Vector3i GetPos(void) const { return Vector3i(GetX(), GetY(), GetZ()); } }; typedef std::list<sSetBlock> sSetBlockList; 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. */ |