diff --git a/Server/Plugins/APIDump/APIDesc.lua b/Server/Plugins/APIDump/APIDesc.lua index c3338b442..cdd724b14 100644 --- a/Server/Plugins/APIDump/APIDesc.lua +++ b/Server/Plugins/APIDump/APIDesc.lua @@ -15493,6 +15493,10 @@ end { Notes = "The player has swapped their held item with the item in their offhand slot (1.9)", }, + E_META_BIG_FLOWER_TOP = + { + Notes = "The metadata of a big flower block that indicates it is the top block.", + }, E_META_CONCRETE_BLACK = { Notes = "A flag in the metadata of concete that indicates that the concrete is black.", diff --git a/src/BlockID.h b/src/BlockID.h index 8454cd3da..96540bd6f 100644 --- a/src/BlockID.h +++ b/src/BlockID.h @@ -552,6 +552,8 @@ enum ENUM_BLOCK_META : NIBBLETYPE E_META_BIG_FLOWER_LARGE_FERN = 3, E_META_BIG_FLOWER_ROSE_BUSH = 4, E_META_BIG_FLOWER_PEONY = 5, + // 0x8 is supposedly a bit flag but all vanilla plants have this value + E_META_BIG_FLOWER_TOP = 10, // E_BLOCK_BREWING_STAND metas E_META_BREWING_STAND_FILLED_SLOT_XP = 1, diff --git a/src/Blocks/BlockBigFlower.h b/src/Blocks/BlockBigFlower.h index 3b3065f87..96139d656 100644 --- a/src/Blocks/BlockBigFlower.h +++ b/src/Blocks/BlockBigFlower.h @@ -18,19 +18,39 @@ public: { } - virtual bool DoesIgnoreBuildCollision(cPlayer * a_Player, NIBBLETYPE a_Meta) override + virtual bool DoesIgnoreBuildCollision(cChunkInterface & a_ChunkInterface, Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta) override { - return (((a_Meta & E_META_BIG_FLOWER_DOUBLE_TALL_GRASS) != 0) || (a_Meta & E_META_BIG_FLOWER_LARGE_FERN) != 0); + if (IsMetaTopPart(a_Meta)) + { + BLOCKTYPE BottomType; + if ( + (a_Pos.y < 1) || + !a_ChunkInterface.GetBlockTypeMeta(a_Pos.x, a_Pos.y - 1, a_Pos.z, BottomType, a_Meta) || + (BottomType != E_BLOCK_BIG_FLOWER) + ) + { + // Can't find the flower meta so assume grass + return true; + } + } + + NIBBLETYPE FlowerMeta = a_Meta & 0x07; + return ( + (FlowerMeta == E_META_BIG_FLOWER_DOUBLE_TALL_GRASS) || + (FlowerMeta == E_META_BIG_FLOWER_LARGE_FERN) + ); } virtual void DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, bool a_CanDrop) override { NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); int AlternateY = a_BlockY; + int BottomY = a_BlockY; if (Meta & 0x8) { --AlternateY; + --BottomY; } else { @@ -39,13 +59,18 @@ public: // also destroy the other block if it has a valid height and is a big flower if (cChunkDef::IsValidHeight(AlternateY) && a_ChunkInterface.GetBlock(a_BlockX, AlternateY, a_BlockZ) == E_BLOCK_BIG_FLOWER) { - super::DropBlock(a_ChunkInterface, a_WorldInterface, a_BlockPluginInterface, a_Digger, a_BlockX, a_BlockY, a_BlockZ, a_CanDrop); + super::DropBlock(a_ChunkInterface, a_WorldInterface, a_BlockPluginInterface, a_Digger, a_BlockX, BottomY, a_BlockZ, a_CanDrop); a_ChunkInterface.FastSetBlock(a_BlockX, AlternateY, a_BlockZ, E_BLOCK_AIR, 0); } } virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override { + if (IsMetaTopPart(a_BlockMeta)) + { + return; // No way to tell flower type + } + NIBBLETYPE Meta = a_BlockMeta & 0x7; if (Meta == E_META_BIG_FLOWER_DOUBLE_TALL_GRASS) { diff --git a/src/Blocks/BlockDeadBush.h b/src/Blocks/BlockDeadBush.h index f9ce9a9ff..799d3a2f2 100644 --- a/src/Blocks/BlockDeadBush.h +++ b/src/Blocks/BlockDeadBush.h @@ -17,7 +17,7 @@ public: { } - virtual bool DoesIgnoreBuildCollision(void) override + virtual bool DoesIgnoreBuildCollision(cChunkInterface & a_ChunkInterface, Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta) override { return true; } diff --git a/src/Blocks/BlockFire.h b/src/Blocks/BlockFire.h index 346167a26..f16347558 100644 --- a/src/Blocks/BlockFire.h +++ b/src/Blocks/BlockFire.h @@ -232,7 +232,7 @@ public: return (FoundFrameZP && FoundFrameZM); } - virtual bool DoesIgnoreBuildCollision(cPlayer * a_Player, NIBBLETYPE a_Meta) override + virtual bool DoesIgnoreBuildCollision(cChunkInterface & a_ChunkInterface, Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta) override { return true; } diff --git a/src/Blocks/BlockFluid.h b/src/Blocks/BlockFluid.h index 0a8b34145..c33427739 100644 --- a/src/Blocks/BlockFluid.h +++ b/src/Blocks/BlockFluid.h @@ -24,7 +24,7 @@ public: // No pickups } - virtual bool DoesIgnoreBuildCollision(void) override + virtual bool DoesIgnoreBuildCollision(cChunkInterface & a_ChunkInterface, Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta) override { return true; } diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp index 41e3561d1..40cc6b492 100644 --- a/src/Blocks/BlockHandler.cpp +++ b/src/Blocks/BlockHandler.cpp @@ -582,7 +582,7 @@ bool cBlockHandler::IsClickedThrough(void) -bool cBlockHandler::DoesIgnoreBuildCollision(void) +bool cBlockHandler::DoesIgnoreBuildCollision(cChunkInterface & a_ChunkInterface, Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta) { return (m_BlockType == E_BLOCK_AIR); } diff --git a/src/Blocks/BlockHandler.h b/src/Blocks/BlockHandler.h index 625def7d8..302fdbc4b 100644 --- a/src/Blocks/BlockHandler.h +++ b/src/Blocks/BlockHandler.h @@ -114,16 +114,11 @@ public: /** Checks if the player can build "inside" this block. For example blocks placed "on" snow will be placed at the same position. So: Snow ignores Build collision + @param a_Pos Position of the block + @param a_Player Player trying to build on the block + @param a_Meta Meta value of the block currently at a_Pos */ - virtual bool DoesIgnoreBuildCollision(void); - - /** Similar to DoesIgnoreBuildCollision(void), but is used for cases where block's meta or - player's item-in-hand is needed to determine collision (thin snow) */ - virtual bool DoesIgnoreBuildCollision(cPlayer *, NIBBLETYPE a_Meta) - { - UNUSED(a_Meta); - return DoesIgnoreBuildCollision(); - } + virtual bool DoesIgnoreBuildCollision(cChunkInterface & ChunkInterface, Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta); /** Returns if this block drops if it gets destroyed by an unsuitable situation. Default: true */ diff --git a/src/Blocks/BlockSnow.h b/src/Blocks/BlockSnow.h index d11c444b9..a502d82e4 100644 --- a/src/Blocks/BlockSnow.h +++ b/src/Blocks/BlockSnow.h @@ -41,9 +41,9 @@ public: return true; } - virtual bool DoesIgnoreBuildCollision(cPlayer * a_Player, NIBBLETYPE a_Meta) override + virtual bool DoesIgnoreBuildCollision(cChunkInterface & a_ChunkInterface, Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta) override { - if ((a_Player->GetEquippedItem().m_ItemType == E_BLOCK_SNOW) && (a_Meta < 7)) + if ((a_Player.GetEquippedItem().m_ItemType == E_BLOCK_SNOW) && (a_Meta < 7)) { return true; // If a player is holding a (thin) snow block and it's size can be increased, return collision ignored } diff --git a/src/Blocks/BlockTallGrass.h b/src/Blocks/BlockTallGrass.h index fb65bca65..8920bd7c9 100644 --- a/src/Blocks/BlockTallGrass.h +++ b/src/Blocks/BlockTallGrass.h @@ -18,7 +18,7 @@ public: { } - virtual bool DoesIgnoreBuildCollision(void) override + virtual bool DoesIgnoreBuildCollision(cChunkInterface & a_ChunkInterface, Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta) override { return true; } diff --git a/src/Blocks/BlockVine.h b/src/Blocks/BlockVine.h index 755161b12..a015c8ab3 100644 --- a/src/Blocks/BlockVine.h +++ b/src/Blocks/BlockVine.h @@ -163,7 +163,7 @@ public: } } - virtual bool DoesIgnoreBuildCollision(void) override + virtual bool DoesIgnoreBuildCollision(cChunkInterface & a_ChunkInterface, Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta) override { return true; } diff --git a/src/Chunk.cpp b/src/Chunk.cpp index 8a13fd20e..9ddee2343 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -1184,7 +1184,7 @@ bool cChunk::GrowTallGrass(int a_RelX, int a_RelY, int a_RelZ) default: return false; } return UnboundedRelFastSetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_BIG_FLOWER, LargeFlowerMeta) && - UnboundedRelFastSetBlock(a_RelX, a_RelY + 1, a_RelZ, E_BLOCK_BIG_FLOWER, 0x8 | LargeFlowerMeta); + UnboundedRelFastSetBlock(a_RelX, a_RelY + 1, a_RelZ, E_BLOCK_BIG_FLOWER, E_META_BIG_FLOWER_TOP); } diff --git a/src/Generating/FinishGen.cpp b/src/Generating/FinishGen.cpp index df8d0929d..f6d6a2ff1 100644 --- a/src/Generating/FinishGen.cpp +++ b/src/Generating/FinishGen.cpp @@ -260,7 +260,7 @@ void cFinishGenClumpTopBlock::TryPlaceFoliageClump(cChunkDesc & a_ChunkDesc, int a_ChunkDesc.SetBlockTypeMeta(x, Top + 1, z, a_BlockType, a_BlockMeta); if (a_IsDoubleTall) { - a_ChunkDesc.SetBlockTypeMeta(x, Top + 2, z, E_BLOCK_BIG_FLOWER, 0x8 | a_BlockMeta); + a_ChunkDesc.SetBlockTypeMeta(x, Top + 2, z, E_BLOCK_BIG_FLOWER, E_META_BIG_FLOWER_TOP); a_ChunkDesc.SetHeight(x, z, static_cast(Top + 2)); } else @@ -554,7 +554,7 @@ void cFinishGenTallGrass::GenFinish(cChunkDesc & a_ChunkDesc) { NIBBLETYPE Meta = (m_Noise.IntNoise2DInt(xx * 100, zz * 100) / 7 % 100) > 25 ? 2 : 3; a_ChunkDesc.SetBlockTypeMeta(x, y, z, E_BLOCK_BIG_FLOWER, Meta); - a_ChunkDesc.SetBlockTypeMeta(x, y + 1, z, E_BLOCK_BIG_FLOWER, 0x8 | Meta); + a_ChunkDesc.SetBlockTypeMeta(x, y + 1, z, E_BLOCK_BIG_FLOWER, E_META_BIG_FLOWER_TOP); a_ChunkDesc.SetHeight(x, z, static_cast(y + 1)); } } diff --git a/src/Items/ItemBigFlower.h b/src/Items/ItemBigFlower.h index f7171f2bc..81a1d54ce 100644 --- a/src/Items/ItemBigFlower.h +++ b/src/Items/ItemBigFlower.h @@ -34,17 +34,30 @@ public: sSetBlockVector & a_BlocksToSet ) override { - // Can only be placed on the floor: - if ((a_BlockY < 0) || (a_World.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ) == E_BLOCK_AIR)) + // Can only be placed on dirt: + if ((a_BlockY <= 0) || !IsBlockTypeOfDirt(a_World.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ))) { return false; } - a_BlocksToSet.emplace_back(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_BIG_FLOWER, a_EquippedItem.m_ItemDamage & 0x07); - if (a_BlockY < cChunkDef::Height - 1) + // Needs at least two free blocks to build in + if (a_BlockY >= cChunkDef::Height - 1) { - a_BlocksToSet.emplace_back(a_BlockX, a_BlockY + 1, a_BlockZ, E_BLOCK_BIG_FLOWER, (a_EquippedItem.m_ItemDamage & 0x07) | 0x08); + return false; } + + BLOCKTYPE TopType; + NIBBLETYPE TopMeta; + a_World.GetBlockTypeMeta(a_BlockX, a_BlockY + 1, a_BlockZ, TopType, TopMeta); + cChunkInterface ChunkInterface(a_World.GetChunkMap()); + + if (!BlockHandler(TopType)->DoesIgnoreBuildCollision(ChunkInterface, { a_BlockX, a_BlockY + 1, a_BlockZ }, a_Player, TopMeta)) + { + return false; + } + + a_BlocksToSet.emplace_back(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_BIG_FLOWER, a_EquippedItem.m_ItemDamage & 0x07); + a_BlocksToSet.emplace_back(a_BlockX, a_BlockY + 1, a_BlockZ, E_BLOCK_BIG_FLOWER, E_META_BIG_FLOWER_TOP); return true; } }; diff --git a/src/Items/ItemChest.h b/src/Items/ItemChest.h index d8cde2ae2..9f1a3f0d2 100644 --- a/src/Items/ItemChest.h +++ b/src/Items/ItemChest.h @@ -51,12 +51,9 @@ public: BLOCKTYPE ClickedBlock; NIBBLETYPE ClickedBlockMeta; a_World.GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, ClickedBlock, ClickedBlockMeta); - if ( - BlockHandler(ClickedBlock)->DoesIgnoreBuildCollision() || - BlockHandler(ClickedBlock)->DoesIgnoreBuildCollision(&a_Player, ClickedBlockMeta) - ) + cChunkInterface ChunkInterface(a_World.GetChunkMap()); + if (BlockHandler(ClickedBlock)->DoesIgnoreBuildCollision(ChunkInterface, { a_BlockX, a_BlockY, a_BlockZ }, a_Player, ClickedBlockMeta)) { - cChunkInterface ChunkInterface(a_World.GetChunkMap()); BlockHandler(ClickedBlock)->OnDestroyedByPlayer(ChunkInterface, a_World, &a_Player, a_BlockX, a_BlockY, a_BlockZ); } else @@ -75,10 +72,7 @@ public: // Clicked on side of block, make sure that placement won't be cancelled if there is a slab able to be double slabbed. // No need to do combinability (dblslab) checks, client will do that here. - if ( - !BlockHandler(PlaceBlock)->DoesIgnoreBuildCollision() && - !BlockHandler(PlaceBlock)->DoesIgnoreBuildCollision(&a_Player, PlaceMeta) - ) + if (BlockHandler(ClickedBlock)->DoesIgnoreBuildCollision(ChunkInterface, { a_BlockX, a_BlockY, a_BlockZ }, a_Player, ClickedBlockMeta)) { // Tried to place a block into another? // Happens when you place a block aiming at side of block with a torch on it or stem beside it diff --git a/src/Items/ItemHandler.cpp b/src/Items/ItemHandler.cpp index 8e3d79506..b430e83ef 100644 --- a/src/Items/ItemHandler.cpp +++ b/src/Items/ItemHandler.cpp @@ -357,14 +357,11 @@ bool cItemHandler::OnPlayerPlace( NIBBLETYPE ClickedBlockMeta; a_World.GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, ClickedBlock, ClickedBlockMeta); + cChunkInterface ChunkInterface(a_World.GetChunkMap()); // Check if the block ignores build collision (water, grass etc.): - if ( - BlockHandler(ClickedBlock)->DoesIgnoreBuildCollision() || - BlockHandler(ClickedBlock)->DoesIgnoreBuildCollision(&a_Player, ClickedBlockMeta) - ) + if (BlockHandler(ClickedBlock)->DoesIgnoreBuildCollision(ChunkInterface, { a_BlockX, a_BlockY, a_BlockZ }, a_Player, ClickedBlockMeta)) { - cChunkInterface ChunkInterface(a_World.GetChunkMap()); BlockHandler(ClickedBlock)->OnDestroyedByPlayer(ChunkInterface, a_World, &a_Player, a_BlockX, a_BlockY, a_BlockZ); } else @@ -383,10 +380,7 @@ bool cItemHandler::OnPlayerPlace( // Clicked on side of block, make sure that placement won't be cancelled if there is a slab able to be double slabbed. // No need to do combinability (dblslab) checks, client will do that here. - if ( - !BlockHandler(PlaceBlock)->DoesIgnoreBuildCollision() && - !BlockHandler(PlaceBlock)->DoesIgnoreBuildCollision(&a_Player, PlaceMeta) - ) + if (!BlockHandler(PlaceBlock)->DoesIgnoreBuildCollision(ChunkInterface, { a_BlockX, a_BlockY, a_BlockZ }, a_Player, PlaceMeta)) { // Tried to place a block into another? // Happens when you place a block aiming at side of block with a torch on it or stem beside it diff --git a/src/Items/ItemSign.h b/src/Items/ItemSign.h index 4c417947d..37ad4967b 100644 --- a/src/Items/ItemSign.h +++ b/src/Items/ItemSign.h @@ -32,7 +32,8 @@ public: BLOCKTYPE ClickedBlock; NIBBLETYPE ClickedBlockMeta; a_World.GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, ClickedBlock, ClickedBlockMeta); - bool isReplacingClickedBlock = BlockHandler(ClickedBlock)->DoesIgnoreBuildCollision() || BlockHandler(ClickedBlock)->DoesIgnoreBuildCollision(&a_Player, ClickedBlockMeta); + cChunkInterface ChunkInterface(a_World.GetChunkMap()); + bool isReplacingClickedBlock = BlockHandler(ClickedBlock)->DoesIgnoreBuildCollision(ChunkInterface, { a_BlockX, a_BlockY, a_BlockZ }, a_Player, ClickedBlockMeta); // If the regular placement doesn't work, do no further processing: if (!super::OnPlayerPlace(a_World, a_Player, a_EquippedItem, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ)) diff --git a/tests/Generating/Stubs.cpp b/tests/Generating/Stubs.cpp index 0a9f431f4..aadb92d0b 100644 --- a/tests/Generating/Stubs.cpp +++ b/tests/Generating/Stubs.cpp @@ -222,7 +222,7 @@ bool cBlockHandler::IsClickedThrough(void) -bool cBlockHandler::DoesIgnoreBuildCollision(void) +bool cBlockHandler::DoesIgnoreBuildCollision(cChunkInterface & a_ChunkInterface, Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta) { return (m_BlockType == E_BLOCK_AIR); } diff --git a/tests/LuaThreadStress/Stubs.cpp b/tests/LuaThreadStress/Stubs.cpp index 0a9f431f4..aadb92d0b 100644 --- a/tests/LuaThreadStress/Stubs.cpp +++ b/tests/LuaThreadStress/Stubs.cpp @@ -222,7 +222,7 @@ bool cBlockHandler::IsClickedThrough(void) -bool cBlockHandler::DoesIgnoreBuildCollision(void) +bool cBlockHandler::DoesIgnoreBuildCollision(cChunkInterface & a_ChunkInterface, Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta) { return (m_BlockType == E_BLOCK_AIR); } diff --git a/tests/SchematicFileSerializer/Stubs.cpp b/tests/SchematicFileSerializer/Stubs.cpp index 74898fe50..7261d7a14 100644 --- a/tests/SchematicFileSerializer/Stubs.cpp +++ b/tests/SchematicFileSerializer/Stubs.cpp @@ -150,7 +150,7 @@ bool cBlockHandler::IsClickedThrough(void) -bool cBlockHandler::DoesIgnoreBuildCollision(void) +bool cBlockHandler::DoesIgnoreBuildCollision(cChunkInterface & a_ChunkInterface, Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta) { return (m_BlockType == E_BLOCK_AIR); }