From 5402b214b31af60bc96cd4e47e9211715c3e99f5 Mon Sep 17 00:00:00 2001 From: Lane Kolbly Date: Fri, 28 Jul 2017 11:59:21 -0500 Subject: Check for intersection between placed blocks and entities. (#3850) * Check for intersection between placed blocks and entities. + Implemented GetPlacementCollisionBox, to permit custom placement collision boxes for blocks. * Factored block-entity placement checking into another function in cPlayer. - Removed vector min/max functions * Use GetWorld to get the world in DoesPlacingBlocksIntersectEntity. + Added block height checks, allow different cEntity subclasses to decide whether they will prevent block placement. --- src/Blocks/BlockDoor.cpp | 10 ++++++ src/Blocks/BlockDoor.h | 2 ++ src/Blocks/BlockFence.h | 80 +++++++++++++++++++++++++++++++++++++++++++++ src/Blocks/BlockHandler.cpp | 23 ++++++++++++- src/Blocks/BlockHandler.h | 7 ++++ src/Blocks/CMakeLists.txt | 1 + 6 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 src/Blocks/BlockFence.h (limited to 'src/Blocks') 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 -- cgit v1.2.3