diff options
Diffstat (limited to '')
111 files changed, 2664 insertions, 1487 deletions
diff --git a/src/Blocks/BlockAnvil.h b/src/Blocks/BlockAnvil.h index f113f7905..ad6d216cd 100644 --- a/src/Blocks/BlockAnvil.h +++ b/src/Blocks/BlockAnvil.h @@ -35,21 +35,34 @@ public: - virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override + virtual bool OnUse( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cPlayer & a_Player, + const Vector3i a_BlockPos, + eBlockFace a_BlockFace, + const Vector3i a_CursorPos + ) override { - cWindow * Window = new cAnvilWindow(a_BlockX, a_BlockY, a_BlockZ); + cWindow * Window = new cAnvilWindow(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z); a_Player.OpenWindow(*Window); return true; } + + + + virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, cPlayer & a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + cChunkInterface & a_ChunkInterface, + cPlayer & a_Player, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { - if (!Super::GetPlacementBlockTypeMeta(a_ChunkInterface, a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, a_BlockType, a_BlockMeta)) + if (!Super::GetPlacementBlockTypeMeta(a_ChunkInterface, a_Player, a_PlacedBlockPos, a_ClickedBlockFace, a_CursorPos, a_BlockType, a_BlockMeta)) { return false; } @@ -58,11 +71,19 @@ public: return true; } + + + + virtual bool IsUseable() override { return true; } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockBed.cpp b/src/Blocks/BlockBed.cpp index 8b349ef5e..6d50e8c41 100644 --- a/src/Blocks/BlockBed.cpp +++ b/src/Blocks/BlockBed.cpp @@ -15,7 +15,11 @@ -void cBlockBedHandler::OnBroken(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta) +void cBlockBedHandler::OnBroken( + cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, + const Vector3i a_BlockPos, + BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta +) { auto Direction = MetaDataToDirection(a_OldBlockMeta & 0x03); if ((a_OldBlockMeta & 0x08) != 0) @@ -50,87 +54,97 @@ void cBlockBedHandler::OnBroken(cChunkInterface & a_ChunkInterface, cWorldInterf -bool cBlockBedHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) +bool cBlockBedHandler::OnUse( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cPlayer & a_Player, + const Vector3i a_BlockPos, + eBlockFace a_BlockFace, + const Vector3i a_CursorPos +) { - Vector3i Coords(a_BlockX, a_BlockY, a_BlockZ); + // Sleeping in bed only allowed in Overworld, beds explode elsewhere: if (a_WorldInterface.GetDimension() != dimOverworld) { - a_WorldInterface.DoExplosionAt(5, a_BlockX, a_BlockY, a_BlockZ, true, esBed, &Coords); + auto PosCopy = a_BlockPos; + a_WorldInterface.DoExplosionAt(5, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, true, esBed, &PosCopy); + return true; } - else if (!((a_WorldInterface.GetTimeOfDay() > 12541) && (a_WorldInterface.GetTimeOfDay() < 23458))) // Source: https://minecraft.gamepedia.com/Bed#Sleeping + + // Sleeping is allowed only during night: + // TODO: Also during thunderstorms + if (!((a_WorldInterface.GetTimeOfDay() > 12541) && (a_WorldInterface.GetTimeOfDay() < 23458))) // Source: https://minecraft.gamepedia.com/Bed#Sleeping { a_Player.SendMessageFailure("You can only sleep at night"); + return true; + } + + // Check if the bed is occupied: + auto Meta = a_ChunkInterface.GetBlockMeta(a_BlockPos); + if ((Meta & 0x04) == 0x04) + { + a_Player.SendMessageFailure("This bed is occupied"); + return true; + } + + // Cannot sleep if there are hostile mobs nearby: + auto FindMobs = [](cEntity & a_Entity) + { + return ( + (a_Entity.GetEntityType() == cEntity::etMonster) && + (static_cast<cMonster&>(a_Entity).GetMobFamily() == cMonster::mfHostile) + ); + }; + if (!a_Player.GetWorld()->ForEachEntityInBox(cBoundingBox(a_Player.GetPosition() - Vector3i(0, 5, 0), 8, 10), FindMobs)) + { + a_Player.SendMessageFailure("You may not rest now, there are monsters nearby"); + return true; + } + + // Broadcast the "Use bed" for the pillow block: + if ((Meta & 0x8) == 0x8) + { + // Is pillow + a_WorldInterface.GetBroadcastManager().BroadcastUseBed(a_Player, a_BlockPos); } else { - NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(Coords); - if ((Meta & 0x4) == 0x4) + // Is foot end + VERIFY((Meta & 0x04) != 0x04); // Occupied flag should never be set, else our compilator (intended) is broken + + auto PillowPos = a_BlockPos + MetaDataToDirection(Meta & 0x03); + if (a_ChunkInterface.GetBlock(PillowPos) == E_BLOCK_BED) // Must always use pillow location for sleeping { - a_Player.SendMessageFailure("This bed is occupied"); + a_WorldInterface.GetBroadcastManager().BroadcastUseBed(a_Player, PillowPos); } - else - { - auto FindMobs = [](cEntity & a_Entity) - { - return ( - (a_Entity.GetEntityType() == cEntity::etMonster) && - (static_cast<cMonster&>(a_Entity).GetMobFamily() == cMonster::mfHostile) - ); - }; + } - if (!a_Player.GetWorld()->ForEachEntityInBox(cBoundingBox(a_Player.GetPosition() - Vector3i(0, 5, 0), 8, 10), FindMobs)) - { - a_Player.SendMessageFailure("You may not rest now, there are monsters nearby"); - } - else + // Occupy the bed: + a_Player.SetBedPos(a_BlockPos); + SetBedOccupationState(a_ChunkInterface, a_Player.GetLastBedPos(), true); + a_Player.SetIsInBed(true); + a_Player.SendMessageSuccess("Home position set successfully"); + + // Fast-forward the time if all players in the world are in their beds: + auto TimeFastForwardTester = [](cPlayer & a_OtherPlayer) + { + if (!a_OtherPlayer.IsInBed()) + { + return true; + } + return false; + }; + if (a_WorldInterface.ForEachPlayer(TimeFastForwardTester)) + { + a_WorldInterface.ForEachPlayer([&](cPlayer & a_OtherPlayer) { - Vector3i PillowDirection(0, 0, 0); - - if ((Meta & 0x8) == 0x8) - { - // Is pillow - a_WorldInterface.GetBroadcastManager().BroadcastUseBed(a_Player, { a_BlockX, a_BlockY, a_BlockZ }); - } - else - { - // Is foot end - VERIFY((Meta & 0x4) != 0x4); // Occupied flag should never be set, else our compilator (intended) is broken - - PillowDirection = MetaDataToDirection(Meta & 0x3); - if (a_ChunkInterface.GetBlock(Coords + PillowDirection) == E_BLOCK_BED) // Must always use pillow location for sleeping - { - a_WorldInterface.GetBroadcastManager().BroadcastUseBed(a_Player, Vector3i{a_BlockX, a_BlockY, a_BlockZ} + PillowDirection); - } - } - - a_Player.SetBedPos(Coords); - SetBedOccupationState(a_ChunkInterface, a_Player.GetLastBedPos(), true); - a_Player.SetIsInBed(true); - a_Player.SendMessageSuccess("Home position set successfully"); - - auto TimeFastForwardTester = [](cPlayer & a_OtherPlayer) - { - if (!a_OtherPlayer.IsInBed()) - { - return true; - } - return false; - }; - - if (a_WorldInterface.ForEachPlayer(TimeFastForwardTester)) - { - a_WorldInterface.ForEachPlayer([&](cPlayer & a_OtherPlayer) - { - cBlockBedHandler::SetBedOccupationState(a_ChunkInterface, a_OtherPlayer.GetLastBedPos(), false); - a_OtherPlayer.SetIsInBed(false); - return false; - } - ); - a_WorldInterface.SetTimeOfDay(0); - a_ChunkInterface.SetBlockMeta({a_BlockX, a_BlockY, a_BlockZ}, Meta & 0x0b); // Clear the "occupied" bit of the bed's block - } + cBlockBedHandler::SetBedOccupationState(a_ChunkInterface, a_OtherPlayer.GetLastBedPos(), false); + a_OtherPlayer.SetIsInBed(false); + return false; } - } + ); + a_WorldInterface.SetTimeOfDay(0); + a_ChunkInterface.SetBlockMeta(a_BlockPos, Meta & 0x0b); // Clear the "occupied" bit of the bed's block } return true; } diff --git a/src/Blocks/BlockBed.h b/src/Blocks/BlockBed.h index 6793585b8..418d44ca5 100644 --- a/src/Blocks/BlockBed.h +++ b/src/Blocks/BlockBed.h @@ -32,10 +32,30 @@ public: // Overrides: - virtual void OnBroken(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta) override; - virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override; - virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override; - virtual void OnPlacedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, const sSetBlock & a_BlockChange) override; + virtual void OnBroken( + cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, + const Vector3i a_BlockPos, + BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta + ) override; + + virtual bool OnUse( + cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, + const Vector3i a_ClickedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos + ) override; + + virtual cItems ConvertToPickups( + NIBBLETYPE a_BlockMeta, + cBlockEntity * a_BlockEntity, + const cEntity * a_Digger, + const cItem * a_Tool + ) override; + + virtual void OnPlacedByPlayer( + cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, + const sSetBlock & a_BlockChange + ) override; diff --git a/src/Blocks/BlockBigFlower.h b/src/Blocks/BlockBigFlower.h index e7bd9b957..150ae6633 100644 --- a/src/Blocks/BlockBigFlower.h +++ b/src/Blocks/BlockBigFlower.h @@ -9,7 +9,7 @@ -class cBlockBigFlowerHandler : +class cBlockBigFlowerHandler: public cBlockHandler { using Super = cBlockHandler; @@ -95,15 +95,15 @@ public: - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override { - if (a_RelY <= 0) + if (a_RelPos.y <= 0) { return false; } BLOCKTYPE BlockType; NIBBLETYPE BlockMeta; - a_Chunk.GetBlockTypeMeta(a_RelX, a_RelY - 1, a_RelZ, BlockType, BlockMeta); + a_Chunk.GetBlockTypeMeta(a_RelPos.addedY(-1), BlockType, BlockMeta); return IsBlockTypeOfDirt(BlockType) || ((BlockType == E_BLOCK_BIG_FLOWER) && !IsMetaTopPart(BlockMeta)); } @@ -112,7 +112,7 @@ public: - virtual void OnBroken(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta) override + virtual void OnBroken(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, const Vector3i a_BlockPos, BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta) override { if ((a_OldBlockMeta & 0x8) != 0) { diff --git a/src/Blocks/BlockButton.h b/src/Blocks/BlockButton.h index c09dec56c..945c39b03 100644 --- a/src/Blocks/BlockButton.h +++ b/src/Blocks/BlockButton.h @@ -24,36 +24,40 @@ public: - virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override + virtual bool OnUse( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cPlayer & a_Player, + const Vector3i a_BlockPos, + eBlockFace a_BlockFace, + const Vector3i a_CursorPos + ) override { - Vector3i Pos(a_BlockX, a_BlockY, a_BlockZ); - NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(Pos); - - Vector3d SoundPos(Pos); + NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockPos); - // If button is already on do nothing + // If button is already on, do nothing: if (Meta & 0x08) { return false; } - // Set p the ON bit to on + // Set the ON bit to on Meta |= 0x08; - a_ChunkInterface.SetBlockMeta({a_BlockX, a_BlockY, a_BlockZ}, Meta, false); - a_WorldInterface.WakeUpSimulators(Pos); - a_WorldInterface.GetBroadcastManager().BroadcastSoundEffect("block.stone_button.click_on", SoundPos, 0.5f, 0.6f); + a_ChunkInterface.SetBlockMeta(a_BlockPos, Meta, false); + a_WorldInterface.WakeUpSimulators(a_BlockPos); + a_WorldInterface.GetBroadcastManager().BroadcastSoundEffect("block.stone_button.click_on", a_BlockPos, 0.5f, 0.6f); // Queue a button reset (unpress) auto TickDelay = (m_BlockType == E_BLOCK_STONE_BUTTON) ? 20 : 30; - a_Player.GetWorld()->ScheduleTask(TickDelay, [SoundPos, Pos, this](cWorld & a_World) + a_Player.GetWorld()->ScheduleTask(TickDelay, [a_BlockPos, this](cWorld & a_World) { - if (a_World.GetBlock(Pos) == m_BlockType) + if (a_World.GetBlock(a_BlockPos) == m_BlockType) { // Block hasn't change in the meantime; set its meta - a_World.SetBlockMeta(Pos.x, Pos.y, Pos.z, a_World.GetBlockMeta(Pos) & 0x07, false); - a_World.WakeUpSimulators(Pos); - a_World.BroadcastSoundEffect("block.stone_button.click_off", SoundPos, 0.5f, 0.5f); + a_World.SetBlockMeta(a_BlockPos, a_World.GetBlockMeta(a_BlockPos) & 0x07, false); + a_World.WakeUpSimulators(a_BlockPos); + a_World.BroadcastSoundEffect("block.stone_button.click_off", a_BlockPos, 0.5f, 0.5f); } } ); @@ -61,23 +65,38 @@ public: return true; } + + + + virtual bool IsUseable(void) override { return true; } + + + + virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, cPlayer & a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + cChunkInterface & a_ChunkInterface, + cPlayer & a_Player, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { a_BlockType = m_BlockType; - a_BlockMeta = BlockFaceToMetaData(a_BlockFace); + a_BlockMeta = BlockFaceToMetaData(a_ClickedBlockFace); return true; } + + + + + /** Converts the block face of the neighbor to which the button is attached, to the block meta for this button. */ inline static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_BlockFace) { switch (a_BlockFace) @@ -97,6 +116,11 @@ public: UNREACHABLE("Unsupported block face"); } + + + + + /** Converts the block meta of this button into a block face of the neighbor to which the button is attached. */ inline static eBlockFace BlockMetaDataToBlockFace(NIBBLETYPE a_Meta) { switch (a_Meta & 0x7) @@ -115,24 +139,39 @@ public: } } - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override - { - NIBBLETYPE Meta; - a_Chunk.UnboundedRelGetBlockMeta(a_RelX, a_RelY, a_RelZ, Meta); - AddFaceDirection(a_RelX, a_RelY, a_RelZ, BlockMetaDataToBlockFace(Meta), true); - BLOCKTYPE BlockIsOn; a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ, BlockIsOn); - return (a_RelY > 0) && (cBlockInfo::FullyOccupiesVoxel(BlockIsOn)); + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override + { + auto Meta = a_Chunk.GetMeta(a_RelPos); + auto SupportRelPos = AddFaceDirection(a_RelPos, BlockMetaDataToBlockFace(Meta), true); + if (!cChunkDef::IsValidHeight(SupportRelPos.y)) + { + return false; + } + BLOCKTYPE SupportBlockType; + a_Chunk.UnboundedRelGetBlockType(SupportRelPos, SupportBlockType); + + return cBlockInfo::FullyOccupiesVoxel(SupportBlockType); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); return 0; } - /** Extracts the ON bit from metadata and returns if true if it is set */ + + + + + /** Extracts the ON bit from metadata. */ static bool IsButtonOn(NIBBLETYPE a_BlockMeta) { return ((a_BlockMeta & 0x8) == 0x8); diff --git a/src/Blocks/BlockCactus.h b/src/Blocks/BlockCactus.h index db65ea15f..0c3577898 100644 --- a/src/Blocks/BlockCactus.h +++ b/src/Blocks/BlockCactus.h @@ -23,13 +23,13 @@ public: - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override { - if (a_RelY <= 0) + if (a_RelPos.y <= 0) { return false; } - BLOCKTYPE Surface = a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ); + BLOCKTYPE Surface = a_Chunk.GetBlock(a_RelPos.addedY(-1)); if ((Surface != E_BLOCK_SAND) && (Surface != E_BLOCK_CACTUS)) { // Cactus can only be placed on sand and itself @@ -37,22 +37,19 @@ public: } // Check surroundings. Cacti may ONLY be surrounded by non-solid blocks - static const struct + static const Vector3i Coords[] = { - int x, z; - } Coords[] = - { - {-1, 0}, - { 1, 0}, - { 0, -1}, - { 0, 1}, - } ; + {-1, 0, 0}, + { 1, 0, 0}, + { 0, 0, -1}, + { 0, 0, 1}, + }; for (size_t i = 0; i < ARRAYCOUNT(Coords); i++) { BLOCKTYPE BlockType; NIBBLETYPE BlockMeta; if ( - a_Chunk.UnboundedRelGetBlock(a_RelX + Coords[i].x, a_RelY, a_RelZ + Coords[i].z, BlockType, BlockMeta) && + a_Chunk.UnboundedRelGetBlock(a_RelPos + Coords[i], BlockType, BlockMeta) && ( cBlockInfo::IsSolid(BlockType) || (BlockType == E_BLOCK_LAVA) || diff --git a/src/Blocks/BlockCake.h b/src/Blocks/BlockCake.h index e30a79db1..dbcce5f17 100644 --- a/src/Blocks/BlockCake.h +++ b/src/Blocks/BlockCake.h @@ -20,9 +20,16 @@ public: - virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override + virtual bool OnUse( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cPlayer & a_Player, + const Vector3i a_BlockPos, + eBlockFace a_BlockFace, + const Vector3i a_CursorPos + ) override { - NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta({a_BlockX, a_BlockY, a_BlockZ}); + NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockPos); if (!a_Player.Feed(2, 0.4)) { @@ -31,11 +38,11 @@ public: if (Meta >= 5) { - a_ChunkInterface.DigBlock(a_WorldInterface, {a_BlockX, a_BlockY, a_BlockZ}); + a_ChunkInterface.DigBlock(a_WorldInterface, a_BlockPos); } else { - a_ChunkInterface.SetBlockMeta({a_BlockX, a_BlockY, a_BlockZ}, Meta + 1); + a_ChunkInterface.SetBlockMeta(a_BlockPos, Meta + 1); } return true; } diff --git a/src/Blocks/BlockCarpet.h b/src/Blocks/BlockCarpet.h index 9f315caa8..41e84c47b 100644 --- a/src/Blocks/BlockCarpet.h +++ b/src/Blocks/BlockCarpet.h @@ -14,14 +14,14 @@ -class cBlockCarpetHandler : +class cBlockCarpetHandler: public cBlockHandler { using Super = cBlockHandler; public: - cBlockCarpetHandler(BLOCKTYPE a_BlockType) : + cBlockCarpetHandler(BLOCKTYPE a_BlockType): Super(a_BlockType) { } @@ -31,9 +31,11 @@ public: virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, cPlayer & a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + cChunkInterface & a_ChunkInterface, + cPlayer & a_Player, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { @@ -46,9 +48,9 @@ public: - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override { - return (a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) != E_BLOCK_AIR); + return (a_RelPos.y > 0) && (a_Chunk.GetBlock(a_RelPos.addedY(-1)) != E_BLOCK_AIR); } diff --git a/src/Blocks/BlockCauldron.h b/src/Blocks/BlockCauldron.h index 28c1dfda8..da7c43860 100644 --- a/src/Blocks/BlockCauldron.h +++ b/src/Blocks/BlockCauldron.h @@ -32,9 +32,16 @@ public: - virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override + virtual bool OnUse( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cPlayer & a_Player, + const Vector3i a_BlockPos, + eBlockFace a_BlockFace, + const Vector3i a_CursorPos + ) override { - NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta({a_BlockX, a_BlockY, a_BlockZ}); + NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockPos); auto EquippedItem = a_Player.GetEquippedItem(); switch (EquippedItem.m_ItemType) { @@ -42,7 +49,7 @@ public: { if (Meta == 3) { - a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0); + a_ChunkInterface.SetBlockMeta(a_BlockPos, 0); // Give new bucket, filled with fluid when the gamemode is not creative: if (!a_Player.IsGameModeCreative()) { @@ -55,7 +62,7 @@ public: { if (Meta < 3) { - a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 3); + a_ChunkInterface.SetBlockMeta(a_BlockPos, 3); // Give empty bucket back when the gamemode is not creative: if (!a_Player.IsGameModeCreative()) { @@ -68,7 +75,7 @@ public: { if (Meta > 0) { - a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, --Meta); + a_ChunkInterface.SetBlockMeta(a_BlockPos, --Meta); // Give new potion when the gamemode is not creative: if (!a_Player.IsGameModeCreative()) { @@ -82,8 +89,8 @@ public: // Refill cauldron with water bottles. if ((Meta < 3) && (EquippedItem.m_ItemDamage == 0)) { - a_ChunkInterface.SetBlockMeta(Vector3i(a_BlockX, a_BlockY, a_BlockZ), ++Meta); - // Give empty bottle when the gamemode is not creative: + a_ChunkInterface.SetBlockMeta(Vector3i(a_BlockPos), ++Meta); + // Give back an empty bottle when the gamemode is not creative: if (!a_Player.IsGameModeCreative()) { a_Player.ReplaceOneEquippedItemTossRest(cItem(E_ITEM_GLASS_BOTTLE)); diff --git a/src/Blocks/BlockChest.h b/src/Blocks/BlockChest.h index aeb687abb..d28ea81fd 100644 --- a/src/Blocks/BlockChest.h +++ b/src/Blocks/BlockChest.h @@ -27,14 +27,16 @@ public: virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, cPlayer & a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + cChunkInterface & a_ChunkInterface, + cPlayer & a_Player, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { - // Is there a doublechest already next to this block? - if (!CanBeAt(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ)) + // Cannot place right next to double-chest: + if (!CanBeAt(a_ChunkInterface, a_PlacedBlockPos)) { // Yup, cannot form a triple-chest, refuse: return false; @@ -42,13 +44,13 @@ public: // Try to read double-chest information: cBlockArea Area; - if (!Area.Read(a_ChunkInterface, a_BlockX - 1, a_BlockX + 1, a_BlockY, a_BlockY, a_BlockZ - 1, a_BlockZ + 1)) + if (!Area.Read(a_ChunkInterface, a_PlacedBlockPos - Vector3i(1, 0, 1), a_PlacedBlockPos + Vector3i(1, 0, 1))) { return false; } // Get meta as if this was a single-chest: - if (!Super::GetPlacementBlockTypeMeta(a_ChunkInterface, a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, a_BlockType, a_BlockMeta)) + if (!Super::GetPlacementBlockTypeMeta(a_ChunkInterface, a_Player, a_PlacedBlockPos, a_ClickedBlockFace, a_CursorPos, a_BlockType, a_BlockMeta)) { return false; } @@ -80,21 +82,20 @@ public: - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override { - int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width; - int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width; - return CanBeAt(a_ChunkInterface, BlockX, a_RelY, BlockZ); + auto BlockPos = a_Chunk.RelativeToAbsolute(a_RelPos); + return CanBeAt(a_ChunkInterface, BlockPos); } - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ) + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_BlockPos) { cBlockArea Area; - if (!Area.Read(a_ChunkInterface, a_BlockX - 2, a_BlockX + 2, a_BlockY, a_BlockY, a_BlockZ - 2, a_BlockZ + 2)) + if (!Area.Read(a_ChunkInterface, a_BlockPos - Vector3i(2, 0, 2), a_BlockPos + Vector3i(2, 0, 2))) { // Cannot read the surroundings, probably at the edge of loaded chunks. Disallow. return false; diff --git a/src/Blocks/BlockCocoaPod.h b/src/Blocks/BlockCocoaPod.h index 74b7c3caa..955a2e3fc 100644 --- a/src/Blocks/BlockCocoaPod.h +++ b/src/Blocks/BlockCocoaPod.h @@ -22,16 +22,15 @@ public: - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override { - eBlockFace BlockFace = MetaToBlockFace(a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ)); - AddFaceDirection(a_RelX, a_RelY, a_RelZ, BlockFace, true); - + // Check that we're attached to a jungle log block: + eBlockFace BlockFace = MetaToBlockFace(a_Chunk.GetMeta(a_RelPos)); + auto LogPos = AddFaceDirection(a_RelPos, BlockFace, true); BLOCKTYPE BlockType; NIBBLETYPE BlockMeta; - a_Chunk.UnboundedRelGetBlock(a_RelX, a_RelY, a_RelZ, BlockType, BlockMeta); - - return ((BlockType == E_BLOCK_LOG) && ((BlockMeta & 0x3) == E_META_LOG_JUNGLE)); + a_Chunk.UnboundedRelGetBlock(LogPos, BlockType, BlockMeta); + return ((BlockType == E_BLOCK_LOG) && ((BlockMeta & 0x03) == E_META_LOG_JUNGLE)); } diff --git a/src/Blocks/BlockComparator.h b/src/Blocks/BlockComparator.h index 5e6b3eaa6..a2f2d430d 100644 --- a/src/Blocks/BlockComparator.h +++ b/src/Blocks/BlockComparator.h @@ -21,45 +21,114 @@ public: { } - virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override + + + + + virtual bool OnUse( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cPlayer & a_Player, + const Vector3i a_BlockPos, + eBlockFace a_BlockFace, + const Vector3i a_CursorPos + ) override { - NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta({a_BlockX, a_BlockY, a_BlockZ}); - Meta ^= 0x04; // Toggle 3rd (addition / subtraction) bit with XOR - a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta); + // Toggle the 3rd bit (addition / subtraction): + NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockPos); + Meta ^= 0x04; + a_ChunkInterface.SetBlockMeta(a_BlockPos, Meta); return true; } - virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override + + + + + virtual void OnCancelRightClick( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cPlayer & a_Player, + const Vector3i a_BlockPos, + eBlockFace a_BlockFace + ) override { UNUSED(a_ChunkInterface); - a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player); + UNUSED(a_BlockFace); + + a_WorldInterface.SendBlockTo(a_BlockPos, a_Player); } + + + + virtual bool IsUseable(void) override { return true; } - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override + + + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override { - return ((a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) != E_BLOCK_AIR)); + if (a_RelPos.y <= 0) + { + return false; + } + + BLOCKTYPE BelowBlock; + NIBBLETYPE BelowBlockMeta; + a_Chunk.GetBlockTypeMeta(a_RelPos.addedY(-1), BelowBlock, BelowBlockMeta); + + if (cBlockInfo::FullyOccupiesVoxel(BelowBlock)) + { + return true; + } + else if (cBlockSlabHandler::IsAnySlabType(BelowBlock)) + { + // Check if the slab is turned up side down + if ((BelowBlockMeta & 0x08) == 0x08) + { + return true; + } + } + return false; } + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { return cItem(E_ITEM_COMPARATOR, 1, 0); } + + + + inline static bool IsInSubtractionMode(NIBBLETYPE a_Meta) { return ((a_Meta & 0x4) == 0x4); } + + + + inline static bool IsOn(NIBBLETYPE a_Meta) { return ((a_Meta & 0x8) == 0x8); } + + + + inline static Vector3i GetSideCoordinate(Vector3i a_Position, NIBBLETYPE a_Meta, bool a_bInverse) { if (!a_bInverse) @@ -98,6 +167,10 @@ public: return a_Position; } + + + + inline static Vector3i GetRearCoordinate(Vector3i a_Position, NIBBLETYPE a_Meta) { switch (a_Meta) @@ -117,6 +190,10 @@ public: return a_Position; } + + + + inline static Vector3i GetFrontCoordinate(Vector3i a_Position, NIBBLETYPE a_Meta) { switch (a_Meta) @@ -136,6 +213,10 @@ public: return a_Position; } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockCrops.h b/src/Blocks/BlockCrops.h index 4622d1ad5..05bb0d2f1 100644 --- a/src/Blocks/BlockCrops.h +++ b/src/Blocks/BlockCrops.h @@ -108,13 +108,15 @@ public: - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override { - return ((a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) == E_BLOCK_FARMLAND)); + return ((a_RelPos.y > 0) && (a_Chunk.GetBlock(a_RelPos.addedY(-1)) == E_BLOCK_FARMLAND)); } + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockDeadBush.h b/src/Blocks/BlockDeadBush.h index 52c9ac594..9eb0c8e84 100644 --- a/src/Blocks/BlockDeadBush.h +++ b/src/Blocks/BlockDeadBush.h @@ -31,14 +31,14 @@ public: - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override { - if (a_RelY <= 0) + if (a_RelPos.y <= 0) { return false; } - BLOCKTYPE BelowBlock = a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ); + BLOCKTYPE BelowBlock = a_Chunk.GetBlock(a_RelPos.addedY(-1)); switch (BelowBlock) { case E_BLOCK_CLAY: diff --git a/src/Blocks/BlockDoor.cpp b/src/Blocks/BlockDoor.cpp index bb694e5b2..fcc4ddbe6 100644 --- a/src/Blocks/BlockDoor.cpp +++ b/src/Blocks/BlockDoor.cpp @@ -40,15 +40,20 @@ void cBlockDoorHandler::OnBroken(cChunkInterface & a_ChunkInterface, cWorldInter -bool cBlockDoorHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) +bool cBlockDoorHandler::OnUse( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cPlayer & a_Player, + const Vector3i a_BlockPos, + eBlockFace a_BlockFace, + const Vector3i a_CursorPos +) { UNUSED(a_WorldInterface); UNUSED(a_BlockFace); - UNUSED(a_CursorX); - UNUSED(a_CursorY); - UNUSED(a_CursorZ); + UNUSED(a_CursorPos); - switch (a_ChunkInterface.GetBlock({a_BlockX, a_BlockY, a_BlockZ})) + switch (a_ChunkInterface.GetBlock(a_BlockPos)) { default: { @@ -61,14 +66,14 @@ bool cBlockDoorHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterfac case E_BLOCK_SPRUCE_DOOR: case E_BLOCK_OAK_DOOR: { - ChangeDoor(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ); - a_Player.GetWorld()->BroadcastSoundParticleEffect(EffectID::SFX_RANDOM_WOODEN_DOOR_OPEN, {a_BlockX, a_BlockY, a_BlockZ}, 0, a_Player.GetClientHandle()); + ChangeDoor(a_ChunkInterface, a_BlockPos); + a_Player.GetWorld()->BroadcastSoundParticleEffect(EffectID::SFX_RANDOM_WOODEN_DOOR_OPEN, a_BlockPos, 0, a_Player.GetClientHandle()); break; } // Prevent iron door from opening on player click case E_BLOCK_IRON_DOOR: { - OnCancelRightClick(a_ChunkInterface, a_WorldInterface, a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); + OnCancelRightClick(a_ChunkInterface, a_WorldInterface, a_Player, a_BlockPos, a_BlockFace); break; } } @@ -80,22 +85,29 @@ bool cBlockDoorHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterfac -void cBlockDoorHandler::OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) +void cBlockDoorHandler::OnCancelRightClick( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cPlayer & a_Player, + const Vector3i a_BlockPos, + eBlockFace a_BlockFace +) { UNUSED(a_ChunkInterface); + UNUSED(a_BlockFace); - a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player); - NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta({a_BlockX, a_BlockY, a_BlockZ}); + a_WorldInterface.SendBlockTo(a_BlockPos, a_Player); + NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockPos); - if (Meta & 0x8) + if (Meta & 0x08) { - // Current block is top of the door - a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY - 1, a_BlockZ, a_Player); + // Current block is top of the door, send the bottom part: + a_WorldInterface.SendBlockTo(a_BlockPos.addedY(-1), a_Player); } else { - // Current block is bottom of the door - a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY + 1, a_BlockZ, a_Player); + // Current block is bottom of the door, send the top part: + a_WorldInterface.SendBlockTo(a_BlockPos.addedY(1), a_Player); } } diff --git a/src/Blocks/BlockDoor.h b/src/Blocks/BlockDoor.h index 48c761d05..a32649961 100644 --- a/src/Blocks/BlockDoor.h +++ b/src/Blocks/BlockDoor.h @@ -20,37 +20,63 @@ public: cBlockDoorHandler(BLOCKTYPE a_BlockType); - virtual void OnBroken(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta) override; - virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override; - virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override; + virtual void OnBroken( + cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, + Vector3i a_BlockPos, + BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta + ) override; + + virtual bool OnUse( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cPlayer & a_Player, + const Vector3i a_BlockPos, + eBlockFace a_BlockFace, + const Vector3i a_CursorPos + ) override; + + virtual void OnCancelRightClick( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cPlayer & a_Player, + const Vector3i a_BlockPos, + eBlockFace a_BlockFace + ) override; virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override; virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override; virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override; virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override; + + + + virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, cPlayer & a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + cChunkInterface & a_ChunkInterface, + cPlayer & a_Player, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { // If clicking a bottom face, place the door one block lower: - if (a_BlockFace == BLOCK_FACE_BOTTOM) + auto PlacedPos = a_PlacedBlockPos; + if (a_ClickedBlockFace == BLOCK_FACE_BOTTOM) { - a_BlockY--; + PlacedPos.y--; } if ( - !CanReplaceBlock(a_ChunkInterface.GetBlock({a_BlockX, a_BlockY, a_BlockZ})) || - !CanReplaceBlock(a_ChunkInterface.GetBlock({a_BlockX, a_BlockY + 1, a_BlockZ})) + !CanReplaceBlock(a_ChunkInterface.GetBlock(PlacedPos)) || + !CanReplaceBlock(a_ChunkInterface.GetBlock(PlacedPos.addedY(1))) ) { return false; } - return Super::GetPlacementBlockTypeMeta(a_ChunkInterface, a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, a_BlockType, a_BlockMeta); + return Super::GetPlacementBlockTypeMeta(a_ChunkInterface, a_Player, PlacedPos, a_ClickedBlockFace, a_CursorPos, a_BlockType, a_BlockMeta); } virtual cBoundingBox GetPlacementCollisionBox(BLOCKTYPE a_XM, BLOCKTYPE a_XP, BLOCKTYPE a_YM, BLOCKTYPE a_YP, BLOCKTYPE a_ZM, BLOCKTYPE a_ZP) override; @@ -93,11 +119,19 @@ public: return true; } - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override + + + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override { - return ((a_RelY > 0) && CanBeOn(a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ), a_Chunk.GetMeta(a_RelX, a_RelY - 1, a_RelZ))); + return ((a_RelPos.y > 0) && CanBeOn(a_Chunk.GetBlock(a_RelPos.addedY(-1)), a_Chunk.GetMeta(a_RelPos.addedY(-1)))); } + + + + /** Returns true if door can be placed on the specified block type. */ static bool CanBeOn(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { @@ -188,9 +222,9 @@ public: /** Returns true iff the door at the specified coords is open. The coords may point to either the top part or the bottom part of the door. */ - static NIBBLETYPE IsOpen(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ) + static NIBBLETYPE IsOpen(cChunkInterface & a_ChunkInterface, const Vector3i a_BlockPos) { - NIBBLETYPE Meta = GetCompleteDoorMeta(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ); + NIBBLETYPE Meta = GetCompleteDoorMeta(a_ChunkInterface, a_BlockPos); return ((Meta & 0x04) != 0); } @@ -201,17 +235,17 @@ public: /** Returns the complete meta composed from the both parts of the door as (TopMeta << 4) | BottomMeta The coords may point to either part of the door. The returned value has bit 3 (0x08) set iff the coords point to the top part of the door. - Fails gracefully for (invalid) doors on the world's top and bottom. */ - static NIBBLETYPE GetCompleteDoorMeta(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ) + Fails silently for (invalid) doors on the world's top and bottom. */ + static NIBBLETYPE GetCompleteDoorMeta(cChunkInterface & a_ChunkInterface, const Vector3i a_BlockPos) { - NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta({a_BlockX, a_BlockY, a_BlockZ}); + NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockPos); if ((Meta & 0x08) != 0) { // The coords are pointing at the top part of the door - if (a_BlockY > 0) + if (a_BlockPos.y > 0) { - NIBBLETYPE DownMeta = a_ChunkInterface.GetBlockMeta({a_BlockX, a_BlockY - 1, a_BlockZ}); + NIBBLETYPE DownMeta = a_ChunkInterface.GetBlockMeta(a_BlockPos.addedY(-1)); return static_cast<NIBBLETYPE>((DownMeta & 0x07) | 0x08 | (Meta << 4)); } // This is the top part of the door at the bottommost layer of the world, there's no bottom: @@ -220,9 +254,9 @@ public: else { // The coords are pointing at the bottom part of the door - if (a_BlockY < cChunkDef::Height - 1) + if (a_BlockPos.y < cChunkDef::Height - 1) { - NIBBLETYPE UpMeta = a_ChunkInterface.GetBlockMeta({a_BlockX, a_BlockY + 1, a_BlockZ}); + NIBBLETYPE UpMeta = a_ChunkInterface.GetBlockMeta(a_BlockPos.addedY(1)); return static_cast<NIBBLETYPE>(Meta | (UpMeta << 4)); } // This is the bottom part of the door at the topmost layer of the world, there's no top: @@ -235,15 +269,15 @@ public: /** Sets the door to the specified state. If the door is already in that state, does nothing. */ - static void SetOpen(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ, bool a_Open) + static void SetOpen(cChunkInterface & a_ChunkInterface, const Vector3i a_BlockPos, bool a_Open) { - BLOCKTYPE Block = a_ChunkInterface.GetBlock({a_BlockX, a_BlockY, a_BlockZ}); + BLOCKTYPE Block = a_ChunkInterface.GetBlock(a_BlockPos); if (!IsDoorBlockType(Block)) { return; } - NIBBLETYPE Meta = GetCompleteDoorMeta(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ); + NIBBLETYPE Meta = GetCompleteDoorMeta(a_ChunkInterface, a_BlockPos); bool IsOpened = ((Meta & 0x04) != 0); if (IsOpened == a_Open) { @@ -255,14 +289,14 @@ public: if ((Meta & 0x08) == 0) { // The block is the bottom part of the door - a_ChunkInterface.SetBlockMeta({a_BlockX, a_BlockY, a_BlockZ}, NewMeta); + a_ChunkInterface.SetBlockMeta(a_BlockPos, NewMeta); } else { // The block is the top part of the door, set the meta to the corresponding top part - if (a_BlockY > 0) + if (a_BlockPos.y > 0) { - a_ChunkInterface.SetBlockMeta({a_BlockX, a_BlockY - 1, a_BlockZ}, NewMeta); + a_ChunkInterface.SetBlockMeta(a_BlockPos.addedY(-1), NewMeta); } } } @@ -272,9 +306,9 @@ public: /** Changes the door at the specified coords from open to close or vice versa */ - static void ChangeDoor(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ) + static void ChangeDoor(cChunkInterface & a_ChunkInterface, const Vector3i a_BlockPos) { - SetOpen(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ, !IsOpen(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ)); + SetOpen(a_ChunkInterface, a_BlockPos, !IsOpen(a_ChunkInterface, a_BlockPos)); } diff --git a/src/Blocks/BlockEnchantmentTable.h b/src/Blocks/BlockEnchantmentTable.h index bfb0f521c..a981cf7a7 100644 --- a/src/Blocks/BlockEnchantmentTable.h +++ b/src/Blocks/BlockEnchantmentTable.h @@ -9,27 +9,49 @@ -class cBlockEnchantmentTableHandler : +class cBlockEnchantmentTableHandler: public cBlockHandler { + using Super = cBlockHandler; + public: - cBlockEnchantmentTableHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + + cBlockEnchantmentTableHandler(BLOCKTYPE a_BlockType): + Super(a_BlockType) { } - virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override + + + + + virtual bool OnUse( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cPlayer & a_Player, + const Vector3i a_BlockPos, + eBlockFace a_BlockFace, + const Vector3i a_CursorPos + ) override { - cWindow * Window = new cEnchantingWindow(a_BlockX, a_BlockY, a_BlockZ); + cWindow * Window = new cEnchantingWindow(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z); a_Player.OpenWindow(*Window); return true; } + + + + virtual bool IsUseable(void) override { return true; } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockEndPortalFrame.h b/src/Blocks/BlockEndPortalFrame.h index c35d13929..be67bb4f9 100644 --- a/src/Blocks/BlockEndPortalFrame.h +++ b/src/Blocks/BlockEndPortalFrame.h @@ -7,22 +7,26 @@ -class cBlockEndPortalFrameHandler : +class cBlockEndPortalFrameHandler: public cMetaRotator<cBlockHandler, 0x03, - E_META_END_PORTAL_FRAME_ZM, - E_META_END_PORTAL_FRAME_XP, - E_META_END_PORTAL_FRAME_ZP, - E_META_END_PORTAL_FRAME_XM + E_META_END_PORTAL_FRAME_ZM, + E_META_END_PORTAL_FRAME_XP, + E_META_END_PORTAL_FRAME_ZP, + E_META_END_PORTAL_FRAME_XM > { -public: - cBlockEndPortalFrameHandler(BLOCKTYPE a_BlockType): - cMetaRotator<cBlockHandler, 0x03, + using Super = cMetaRotator< + cBlockHandler, 0x03, E_META_END_PORTAL_FRAME_ZM, E_META_END_PORTAL_FRAME_XP, E_META_END_PORTAL_FRAME_ZP, E_META_END_PORTAL_FRAME_XM - >(a_BlockType) + >; + +public: + + cBlockEndPortalFrameHandler(BLOCKTYPE a_BlockType): + Super(a_BlockType) { } @@ -31,9 +35,11 @@ public: virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, cPlayer & a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + cChunkInterface & a_ChunkInterface, + cPlayer & a_Player, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { diff --git a/src/Blocks/BlockEntity.h b/src/Blocks/BlockEntity.h index 8e7f92913..9fbb77a1f 100644 --- a/src/Blocks/BlockEntity.h +++ b/src/Blocks/BlockEntity.h @@ -28,9 +28,16 @@ public: - virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override + virtual bool OnUse( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cPlayer & a_Player, + const Vector3i a_BlockPos, + eBlockFace a_BlockFace, + const Vector3i a_CursorPos + ) override { - return a_ChunkInterface.UseBlockEntity(&a_Player, a_BlockX, a_BlockY, a_BlockZ); + return a_ChunkInterface.UseBlockEntity(&a_Player, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z); } diff --git a/src/Blocks/BlockFence.h b/src/Blocks/BlockFence.h index 96a3d8d96..25ac85eed 100644 --- a/src/Blocks/BlockFence.h +++ b/src/Blocks/BlockFence.h @@ -10,21 +10,28 @@ -class cBlockFenceHandler : +class cBlockFenceHandler: public cBlockHandler { + using Super = 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) + cBlockFenceHandler(BLOCKTYPE a_BlockType): + Super(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); @@ -76,9 +83,20 @@ public: return PlacementBox; } - virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override + + + + + virtual bool OnUse( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cPlayer & a_Player, + const Vector3i a_BlockPos, + eBlockFace a_BlockFace, + const Vector3i a_CursorPos + ) override { - auto LeashKnot = cLeashKnot::FindKnotAtPos(*a_Player.GetWorld(), { a_BlockX, a_BlockY, a_BlockZ }); + auto LeashKnot = cLeashKnot::FindKnotAtPos(*a_Player.GetWorld(), a_BlockPos); auto KnotAlreadyExists = (LeashKnot != nullptr); if (KnotAlreadyExists) @@ -89,7 +107,7 @@ public: // New knot? needs to init and produce sound effect else { - auto NewLeashKnot = cpp14::make_unique<cLeashKnot>(a_BlockFace, Vector3i{a_BlockX, a_BlockY, a_BlockZ}); + auto NewLeashKnot = cpp14::make_unique<cLeashKnot>(a_BlockFace, a_BlockPos); auto NewLeashKnotPtr = NewLeashKnot.get(); NewLeashKnotPtr->TiePlayersLeashedMobs(a_Player, KnotAlreadyExists); @@ -112,11 +130,25 @@ public: return true; } - virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override + + + + + virtual void OnCancelRightClick( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cPlayer & a_Player, + const Vector3i a_BlockPos, + eBlockFace a_BlockFace + ) override { - a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player); + a_WorldInterface.SendBlockTo(a_BlockPos, a_Player); } + + + + virtual bool IsUseable(void) override { return true; diff --git a/src/Blocks/BlockFenceGate.h b/src/Blocks/BlockFenceGate.h index 5d89ae021..bba308230 100644 --- a/src/Blocks/BlockFenceGate.h +++ b/src/Blocks/BlockFenceGate.h @@ -20,36 +20,65 @@ public: { } - virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override + + + + + virtual bool OnUse( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cPlayer & a_Player, + const Vector3i a_BlockPos, + eBlockFace a_BlockFace, + const Vector3i a_CursorPos + ) override { - NIBBLETYPE OldMetaData = a_ChunkInterface.GetBlockMeta({a_BlockX, a_BlockY, a_BlockZ}); + NIBBLETYPE OldMetaData = a_ChunkInterface.GetBlockMeta(a_BlockPos); NIBBLETYPE NewMetaData = YawToMetaData(a_Player.GetYaw()); OldMetaData ^= 4; // Toggle the gate if ((OldMetaData & 1) == (NewMetaData & 1)) { // Standing in front of the gate - apply new direction - a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, (OldMetaData & 4) | (NewMetaData & 3)); + a_ChunkInterface.SetBlockMeta(a_BlockPos, (OldMetaData & 4) | (NewMetaData & 3)); } else { // Standing aside - use last direction - a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, OldMetaData); + a_ChunkInterface.SetBlockMeta(a_BlockPos, OldMetaData); } - a_Player.GetWorld()->BroadcastSoundParticleEffect(EffectID::SFX_RANDOM_FENCE_GATE_OPEN, {a_BlockX, a_BlockY, a_BlockZ}, 0, a_Player.GetClientHandle()); + a_Player.GetWorld()->BroadcastSoundParticleEffect(EffectID::SFX_RANDOM_FENCE_GATE_OPEN, a_BlockPos, 0, a_Player.GetClientHandle()); return true; } - virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override + + + + + virtual void OnCancelRightClick( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cPlayer & a_Player, + const Vector3i a_BlockPos, + eBlockFace a_BlockFace + ) override { - a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player); + a_WorldInterface.SendBlockTo(a_BlockPos, a_Player); } + + + + virtual bool IsUseable(void) override { return true; } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockFlower.h b/src/Blocks/BlockFlower.h index d88891d75..714ff9cab 100644 --- a/src/Blocks/BlockFlower.h +++ b/src/Blocks/BlockFlower.h @@ -7,12 +7,15 @@ -class cBlockFlowerHandler : +class cBlockFlowerHandler: public cBlockHandler { + using Super = cBlockHandler; + public: - cBlockFlowerHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + + cBlockFlowerHandler(BLOCKTYPE a_BlockType): + Super(a_BlockType) { } @@ -30,11 +33,15 @@ public: - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override { - return (a_RelY > 0) && IsBlockTypeOfDirt(a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ)); + return ((a_RelPos.y > 0) && IsBlockTypeOfDirt(a_Chunk.GetBlock(a_RelPos.addedY(-1)))); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockGrass.h b/src/Blocks/BlockGrass.h index 374fcceed..51a321b35 100644 --- a/src/Blocks/BlockGrass.h +++ b/src/Blocks/BlockGrass.h @@ -90,30 +90,31 @@ public: // Y Coord out of range continue; } - auto chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(Pos); - if (chunk == nullptr) + auto Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(Pos); + if (Chunk == nullptr) { // Unloaded chunk continue; } - chunk->GetBlockTypeMeta(Pos, DestBlock, DestMeta); + Chunk->GetBlockTypeMeta(Pos, DestBlock, DestMeta); if ((DestBlock != E_BLOCK_DIRT) || (DestMeta != E_META_DIRT_NORMAL)) { // Not a regular dirt block continue; } - BLOCKTYPE Above = chunk->GetBlock(AbovePos); - NIBBLETYPE light = std::max(chunk->GetBlockLight(AbovePos), chunk->GetTimeAlteredLight(chunk->GetSkyLight(AbovePos))); - if ((light > 4) && - cBlockInfo::IsTransparent(Above) && - (!IsBlockLava(Above)) && - (!IsBlockWaterOrIce(Above)) + auto AboveDestPos = Pos.addedY(1); + auto AboveBlockType = Chunk->GetBlock(AboveDestPos); + auto Light = std::max(Chunk->GetBlockLight(AboveDestPos), Chunk->GetTimeAlteredLight(Chunk->GetSkyLight(AboveDestPos))); + if ((Light > 4) && + cBlockInfo::IsTransparent(AboveBlockType) && + (!IsBlockLava(AboveBlockType)) && + (!IsBlockWaterOrIce(AboveBlockType)) ) { - auto absPos = chunk->RelativeToAbsolute(Pos); - if (!cRoot::Get()->GetPluginManager()->CallHookBlockSpread(*chunk->GetWorld(), absPos.x, absPos.y, absPos.z, ssGrassSpread)) + auto AbsPos = Chunk->RelativeToAbsolute(Pos); + if (!cRoot::Get()->GetPluginManager()->CallHookBlockSpread(*Chunk->GetWorld(), AbsPos.x, AbsPos.y, AbsPos.z, ssGrassSpread)) { - chunk->FastSetBlock(Pos, E_BLOCK_GRASS, 0); + Chunk->FastSetBlock(Pos, E_BLOCK_GRASS, 0); } } } // for i - repeat twice diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp index f1df4db44..5d6609836 100644 --- a/src/Blocks/BlockHandler.cpp +++ b/src/Blocks/BlockHandler.cpp @@ -406,8 +406,9 @@ cBlockHandler::cBlockHandler(BLOCKTYPE a_BlockType) bool cBlockHandler::GetPlacementBlockTypeMeta( cChunkInterface & a_ChunkInterface, cPlayer & a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + const Vector3i a_ClickedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) { @@ -437,7 +438,7 @@ void cBlockHandler::OnUpdate( void cBlockHandler::OnPlacedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, const sSetBlock & a_BlockChange) { - OnPlaced(a_ChunkInterface, a_WorldInterface, a_BlockChange.GetPos(), a_BlockChange.m_BlockType, a_BlockChange.m_BlockMeta); + OnPlaced(a_ChunkInterface, a_WorldInterface, a_BlockChange.GetAbsolutePos(), a_BlockChange.m_BlockType, a_BlockChange.m_BlockMeta); } @@ -509,7 +510,7 @@ cItems cBlockHandler::ConvertToPickups( -bool cBlockHandler::CanBeAt(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ, const cChunk & a_Chunk) +bool cBlockHandler::CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) { return true; } @@ -554,10 +555,10 @@ bool cBlockHandler::DoesDropOnUnsuitable(void) -/* default functionality: only test for height, since we assume full voxels with varying height */ -bool cBlockHandler::IsInsideBlock(Vector3d a_Position, const BLOCKTYPE a_BlockType, const NIBBLETYPE a_BlockMeta) +bool cBlockHandler::IsInsideBlock(const Vector3d a_RelPosition, const NIBBLETYPE a_BlockMeta) { - return a_Position.y < cBlockInfo::GetBlockHeight(a_BlockType); + // Default functionality: Test the height, since we assume full voxels with varying height + return (a_RelPosition.y < cBlockInfo::GetBlockHeight(m_BlockType)); } @@ -584,7 +585,7 @@ void cBlockHandler::Check( cChunk & a_Chunk ) { - if (!CanBeAt(a_ChunkInterface, a_RelPos.x, a_RelPos.y, a_RelPos.z, a_Chunk)) + if (!CanBeAt(a_ChunkInterface, a_RelPos, a_Chunk)) { if (DoesDropOnUnsuitable()) { diff --git a/src/Blocks/BlockHandler.h b/src/Blocks/BlockHandler.h index f4a7fc674..a582b8dc2 100644 --- a/src/Blocks/BlockHandler.h +++ b/src/Blocks/BlockHandler.h @@ -44,19 +44,28 @@ public: 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. + /** Called before a block is placed into a world by player, by cItemHandler::GetPlacementBlockTypeMeta(). 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. - Called by cItemHandler::GetPlacementBlockTypeMeta() if the item is a block */ + a_PlacedBlockPos is the coords of the block being placed + a_ClickedBlockFace is the face of the neighbor block clicked by the client to place this block. + a_CursorPos is the position of the cursor within the neighbor's face + The descendant handler should set a_BlockType and a_BlockMeta to correct values for the newly placed block. + The default handler uses the stored block type and meta copied from the lowest 4 bits of the player's equipped item's damage value. */ virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, cPlayer & a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + cChunkInterface & a_ChunkInterface, + cPlayer & a_Player, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ); /** Called by cWorld::SetBlock() after the block has been set */ - virtual void OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); + virtual void OnPlaced( + cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, + Vector3i a_BlockPos, + BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta + ); /** Called by cPlayer::PlaceBlocks() for each block after it has been set to the world. Called after OnPlaced(). */ virtual void OnPlacedByPlayer( @@ -118,18 +127,37 @@ public: cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ + const Vector3i a_BlockPos ) { } - /** Called if the user right clicks the block and the block is useable - returns true if the use was successful, return false to use the block as a "normal" block */ - virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) { return false; } + /** Called when the user right clicks the block and the block is useable. + a_CursorPos is the cursor position within the clicked block face. + Returns true if the use was successful, return false to use the block as a "normal" block */ + virtual bool OnUse( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cPlayer & a_Player, + const Vector3i a_BlockPos, + eBlockFace a_BlockFace, + const Vector3i a_CursorPos + ) + { + return false; + } /** Called when a right click to this block is cancelled. - It forces the server to send the real state of a block to the client to prevent client assuming the operation is successfull */ - virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) {} + Descendants should force the server to send the real state of a block to the client to prevent client assuming the operation was successfull. */ + virtual void OnCancelRightClick( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cPlayer & a_Player, + const Vector3i a_BlockPos, + eBlockFace a_BlockFace + ) + { + } /** Returns the pickups that would result if the block was mined by a_Digger using a_Tool. Doesn't do any actual block change / mining, only calculates the pickups. @@ -145,41 +173,37 @@ public: ); /** Checks if the block can stay at the specified relative coords in the chunk */ - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk); + virtual bool CanBeAt( + cChunkInterface & a_ChunkInterface, + const Vector3i a_RelPos, + const cChunk & a_Chunk + ); /** Checks whether the block has an effect on growing the plant */ virtual bool CanSustainPlant(BLOCKTYPE a_Plant) { return false; } - /** Checks if the block can be placed at this point. - Default: CanBeAt(...) - NOTE: This call doesn't actually place the block - */ - // virtual bool CanBePlacedAt(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Dir); - /** Called to check whether this block supports a rclk action. If it returns true, OnUse() is called */ virtual bool IsUseable(void); /** Indicates whether the client will click through this block. - For example digging a fire will hit the block below the fire so fire is clicked through - */ + For example digging a fire will hit the block below the fire so fire is clicked through. */ virtual bool IsClickedThrough(void); /** 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(cChunkInterface & ChunkInterface, Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta); + @param a_Meta Meta value of the block currently at a_Pos */ + virtual bool DoesIgnoreBuildCollision(cChunkInterface & ChunkInterface, const Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta); /** Returns if this block drops if it gets destroyed by an unsuitable situation. Default: true */ virtual bool DoesDropOnUnsuitable(void); - /** Tests if a_Position is inside the block where a_Position is relative to the origin of the block - Note that this is considered from a "top-down" perspective i.e. empty spaces on the bottom of a block don't matter */ - virtual bool IsInsideBlock(Vector3d a_Position, const BLOCKTYPE a_BlockType, const NIBBLETYPE a_BlockMeta); + /** Tests if a_RelPosition is inside the block, where a_RelPosition is relative to the origin of the block. + Coords in a_RelPosition are guaranteed to be in the [0..1] range. */ + virtual bool IsInsideBlock(const Vector3d a_RelPosition, const NIBBLETYPE a_BlockMeta); /** Called when one of the neighbors gets set; equivalent to MC block update. By default drops (DropBlockAsPickup() / SetBlock()) if the position is no longer suitable (CanBeAt(), DoesDropOnUnsuitable()), diff --git a/src/Blocks/BlockHopper.h b/src/Blocks/BlockHopper.h index a8d59440d..cb1ddf7d1 100644 --- a/src/Blocks/BlockHopper.h +++ b/src/Blocks/BlockHopper.h @@ -24,16 +24,18 @@ public: virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, cPlayer & a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + cChunkInterface & a_ChunkInterface, + cPlayer & a_Player, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { a_BlockType = m_BlockType; // Convert the blockface into meta: - switch (a_BlockFace) + switch (a_ClickedBlockFace) { case BLOCK_FACE_BOTTOM: a_BlockMeta = E_META_HOPPER_FACING_YM; break; case BLOCK_FACE_TOP: a_BlockMeta = E_META_HOPPER_FACING_YM; break; diff --git a/src/Blocks/BlockLadder.h b/src/Blocks/BlockLadder.h index c141faeb4..3f38d2c0c 100644 --- a/src/Blocks/BlockLadder.h +++ b/src/Blocks/BlockLadder.h @@ -8,7 +8,7 @@ -class cBlockLadderHandler : +class cBlockLadderHandler: public cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x07, 0x02, 0x05, 0x03, 0x04> > { using Super = cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x07, 0x02, 0x05, 0x03, 0x04>>; @@ -25,24 +25,26 @@ public: virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, cPlayer & a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + cChunkInterface & a_ChunkInterface, + cPlayer & a_Player, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { - if (!LadderCanBePlacedAt(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace)) + // Try finding a suitable neighbor block face for the ladder; start with the given one. + if (!LadderCanBePlacedAt(a_ChunkInterface, a_PlacedBlockPos, a_ClickedBlockFace)) { - a_BlockFace = FindSuitableBlockFace(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ); - - if (a_BlockFace == BLOCK_FACE_BOTTOM) + a_ClickedBlockFace = FindSuitableBlockFace(a_ChunkInterface, a_PlacedBlockPos); + if (a_ClickedBlockFace == BLOCK_FACE_NONE) { return false; } } a_BlockType = m_BlockType; - a_BlockMeta = DirectionToMetaData(a_BlockFace); + a_BlockMeta = BlockFaceToMetaData(a_ClickedBlockFace); return true; } @@ -50,9 +52,10 @@ public: - static NIBBLETYPE DirectionToMetaData(eBlockFace a_Direction) + /** Converts the block face of the neighbor to which the ladder is attached to the ladder block's meta. */ + static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_NeighborBlockFace) { - switch (a_Direction) + switch (a_NeighborBlockFace) { case BLOCK_FACE_ZM: return 0x2; case BLOCK_FACE_ZP: return 0x3; @@ -65,14 +68,15 @@ public: return 0x2; } } - UNREACHABLE("Unsupported block face"); + UNREACHABLE("Unsupported neighbor block face"); } - static eBlockFace MetaDataToDirection(NIBBLETYPE a_MetaData) + /** Converts the ladder block's meta to the block face of the neighbor to which the ladder is attached. */ + static eBlockFace MetaDataToBlockFace(NIBBLETYPE a_MetaData) { switch (a_MetaData) { @@ -88,47 +92,51 @@ public: - /** Finds a suitable Direction for the Ladder. Returns BLOCK_FACE_BOTTOM on failure */ - static eBlockFace FindSuitableBlockFace(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ) + /** Finds a suitable block face value for the Ladder. + The returned value is the block face of the neighbor of the specified block to which a ladder at a_LadderPos can be attached. + Returns BLOCK_FACE_NONE if no valid location is found */ + static eBlockFace FindSuitableBlockFace(cChunkInterface & a_ChunkInterface, const Vector3i a_LadderPos) { for (int FaceInt = BLOCK_FACE_ZM; FaceInt <= BLOCK_FACE_XP; FaceInt++) { eBlockFace Face = static_cast<eBlockFace>(FaceInt); - if (LadderCanBePlacedAt(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ, Face)) + if (LadderCanBePlacedAt(a_ChunkInterface, a_LadderPos, Face)) { return Face; } } - return BLOCK_FACE_BOTTOM; + return BLOCK_FACE_NONE; } - static bool LadderCanBePlacedAt(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) + /** Returns true if the ladder in the specified position will be supported by its neghbor through the specified neighbor's blockface. */ + static bool LadderCanBePlacedAt(cChunkInterface & a_ChunkInterface, const Vector3i a_LadderPos, eBlockFace a_NeighborBlockFace) { - if ((a_BlockFace == BLOCK_FACE_BOTTOM) || (a_BlockFace == BLOCK_FACE_TOP)) + if ( + (a_NeighborBlockFace == BLOCK_FACE_NONE) || + (a_NeighborBlockFace == BLOCK_FACE_BOTTOM) || + (a_NeighborBlockFace == BLOCK_FACE_TOP) + ) { return false; } - AddFaceDirection( a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, true); - - return cBlockInfo::IsSolid(a_ChunkInterface.GetBlock({a_BlockX, a_BlockY, a_BlockZ})); + auto NeighborPos = AddFaceDirection(a_LadderPos, a_NeighborBlockFace, true); + return cBlockInfo::IsSolid(a_ChunkInterface.GetBlock(NeighborPos)); } - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override { - // TODO: Use AdjustCoordsByMeta(), then cChunk::UnboundedRelGetBlock() and finally some comparison - eBlockFace BlockFace = MetaDataToDirection(a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ)); - int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width; - int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width; - return LadderCanBePlacedAt(a_ChunkInterface, BlockX, a_RelY, BlockZ, BlockFace); + auto NeighborBlockFace = MetaDataToBlockFace(a_Chunk.GetMeta(a_RelPos)); + auto LadderAbsPos = a_Chunk.RelativeToAbsolute(a_RelPos); + return LadderCanBePlacedAt(a_ChunkInterface, LadderAbsPos, NeighborBlockFace); } diff --git a/src/Blocks/BlockLever.h b/src/Blocks/BlockLever.h index 8425b6620..4a682322d 100644 --- a/src/Blocks/BlockLever.h +++ b/src/Blocks/BlockLever.h @@ -6,14 +6,14 @@ #include "BlockSlab.h" -class cBlockLeverHandler : +class cBlockLeverHandler: public cMetaRotator<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, false> { using Super = cMetaRotator<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, false>; public: - cBlockLeverHandler(BLOCKTYPE a_BlockType) : + cBlockLeverHandler(BLOCKTYPE a_BlockType): Super(a_BlockType) { } @@ -22,15 +22,21 @@ public: - virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override + virtual bool OnUse( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cPlayer & a_Player, + const Vector3i a_BlockPos, + eBlockFace a_BlockFace, + const Vector3i a_CursorPos + ) override { - Vector3i Coords(a_BlockX, a_BlockY, a_BlockZ); // Flip the ON bit on / off using the XOR bitwise operation - NIBBLETYPE Meta = (a_ChunkInterface.GetBlockMeta(Coords) ^ 0x08); + NIBBLETYPE Meta = (a_ChunkInterface.GetBlockMeta(a_BlockPos) ^ 0x08); - a_ChunkInterface.SetBlockMeta(Coords.x, Coords.y, Coords.z, Meta); - a_WorldInterface.WakeUpSimulators(Coords); - a_WorldInterface.GetBroadcastManager().BroadcastSoundEffect("block.lever.click", Vector3d(Coords), 0.5f, (Meta & 0x08) ? 0.6f : 0.5f); + a_ChunkInterface.SetBlockMeta(a_BlockPos, Meta); + a_WorldInterface.WakeUpSimulators(a_BlockPos); + a_WorldInterface.GetBroadcastManager().BroadcastSoundEffect("block.lever.click", a_BlockPos, 0.5f, (Meta & 0x08) ? 0.6f : 0.5f); return true; } @@ -58,14 +64,16 @@ public: virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, cPlayer & a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + cChunkInterface & a_ChunkInterface, + cPlayer & a_Player, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { a_BlockType = m_BlockType; - a_BlockMeta = LeverDirectionToMetaData(a_BlockFace); + a_BlockMeta = LeverDirectionToMetaData(a_ClickedBlockFace); return true; } @@ -73,6 +81,7 @@ public: + /** Converts the block face of the neighbor to which the lever is attached to the lever block's meta. */ inline static NIBBLETYPE LeverDirectionToMetaData(eBlockFace a_Dir) { // Determine lever direction: @@ -93,6 +102,7 @@ public: + /** Converts the leve block's meta to the block face of the neighbor to which the lever is attached. */ inline static eBlockFace BlockMetaDataToBlockFace(NIBBLETYPE a_Meta) { switch (a_Meta & 0x7) @@ -117,34 +127,33 @@ public: - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override { - NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ); - - eBlockFace Face = BlockMetaDataToBlockFace(Meta); - - AddFaceDirection(a_RelX, a_RelY, a_RelZ, Face, true); - - if ((a_RelY < 0) || (a_RelY >= cChunkDef::Height -1)) + // Find the type of block the lever is attached to: + auto Meta = a_Chunk.GetMeta(a_RelPos); + auto NeighborFace = BlockMetaDataToBlockFace(Meta); + auto NeighborPos = AddFaceDirection(a_RelPos, NeighborFace, true); + if (!cChunkDef::IsValidHeight(NeighborPos.y)) + { + return false; + } + BLOCKTYPE NeighborBlockType; + if (!a_Chunk.UnboundedRelGetBlock(NeighborPos, NeighborBlockType, Meta)) { return false; } - BLOCKTYPE BlockIsOn; - a_Chunk.UnboundedRelGetBlock(a_RelX, a_RelY, a_RelZ, BlockIsOn, Meta); - - - if (cBlockInfo::FullyOccupiesVoxel(BlockIsOn)) + // Allow any full block or the "good" side of a half-slab: + if (cBlockInfo::FullyOccupiesVoxel(NeighborBlockType)) { return true; } - else if (cBlockSlabHandler::IsAnySlabType(BlockIsOn)) + else if (cBlockSlabHandler::IsAnySlabType(NeighborBlockType)) { - // Check if the slab is turned up side down - if (((Meta & 0x08) == 0x08) && (Face == BLOCK_FACE_TOP)) - { - return true; - } + return ( + (((Meta & 0x08) == 0x08) && (NeighborFace == BLOCK_FACE_TOP)) || + (((Meta & 0x08) == 0) && (NeighborFace == BLOCK_FACE_BOTTOM)) + ); } return false; diff --git a/src/Blocks/BlockLilypad.h b/src/Blocks/BlockLilypad.h index c51eb0a3d..8ffc8fd20 100644 --- a/src/Blocks/BlockLilypad.h +++ b/src/Blocks/BlockLilypad.h @@ -19,6 +19,10 @@ public: { } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); @@ -26,15 +30,19 @@ public: } - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override + + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override { - if ((a_RelY < 1) || (a_RelY >= cChunkDef::Height)) + auto UnderPos = a_RelPos.addedY(-1); + if (!cChunkDef::IsValidHeight(UnderPos.y)) { return false; } BLOCKTYPE UnderType; NIBBLETYPE UnderMeta; - a_Chunk.GetBlockTypeMeta(a_RelX, a_RelY - 1, a_RelZ, UnderType, UnderMeta); + a_Chunk.GetBlockTypeMeta(UnderPos, UnderType, UnderMeta); return ( (((UnderType == E_BLOCK_STATIONARY_WATER) || (UnderType == E_BLOCK_WATER)) && (UnderMeta == 0)) || // A water source is below (UnderType == E_BLOCK_ICE) || (UnderType == E_BLOCK_FROSTED_ICE) // Or (frosted) ice diff --git a/src/Blocks/BlockMobSpawner.h b/src/Blocks/BlockMobSpawner.h index c8a1c5696..78fa9ec31 100644 --- a/src/Blocks/BlockMobSpawner.h +++ b/src/Blocks/BlockMobSpawner.h @@ -8,22 +8,38 @@ -class cBlockMobSpawnerHandler : +class cBlockMobSpawnerHandler: public cBlockHandler { + using Super = cBlockHandler; + public: - cBlockMobSpawnerHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + + cBlockMobSpawnerHandler(BLOCKTYPE a_BlockType): + Super(a_BlockType) { } - virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override + + + + virtual bool OnUse( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cPlayer & a_Player, + const Vector3i a_BlockPos, + eBlockFace a_BlockFace, + const Vector3i a_CursorPos + ) override { - return a_ChunkInterface.UseBlockEntity(&a_Player, a_BlockX, a_BlockY, a_BlockZ); + return a_ChunkInterface.UseBlockEntity(&a_Player, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z); } + + + virtual bool IsUseable() override { return true; diff --git a/src/Blocks/BlockMushroom.h b/src/Blocks/BlockMushroom.h index f44fbdc07..e40031465 100644 --- a/src/Blocks/BlockMushroom.h +++ b/src/Blocks/BlockMushroom.h @@ -7,6 +7,7 @@ +/** Handler for the small (singleblock) mushrooms. */ class cBlockMushroomHandler: public cClearMetaOnDrop<cBlockHandler> { @@ -19,18 +20,26 @@ public: { } + + + + // TODO: Add Mushroom Spread - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override + + + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override { - if (a_RelY <= 0) + if (a_RelPos.y <= 0) { return false; } // TODO: Cannot be at too much daylight - switch (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ)) + switch (a_Chunk.GetBlock(a_RelPos.addedY(-1))) { case E_BLOCK_GLASS: case E_BLOCK_CACTUS: @@ -45,6 +54,10 @@ public: return true; } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockNetherWart.h b/src/Blocks/BlockNetherWart.h index 40ab1d886..86e348cf1 100644 --- a/src/Blocks/BlockNetherWart.h +++ b/src/Blocks/BlockNetherWart.h @@ -8,7 +8,7 @@ -class cBlockNetherWartHandler : +class cBlockNetherWartHandler: public cBlockPlant<false> { using Super = cBlockPlant<false>; @@ -64,10 +64,10 @@ public: - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override { // Needs to be placed on top of a Soulsand block: - return ((a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) == E_BLOCK_SOULSAND)); + return ((a_RelPos.y > 0) && (a_Chunk.GetBlock(a_RelPos.addedY(-1)) == E_BLOCK_SOULSAND)); } diff --git a/src/Blocks/BlockPlanks.h b/src/Blocks/BlockPlanks.h index 556f700ee..ea7d91398 100644 --- a/src/Blocks/BlockPlanks.h +++ b/src/Blocks/BlockPlanks.h @@ -7,18 +7,28 @@ -class cBlockPlanksHandler : public cBlockHandler +class cBlockPlanksHandler: + public cBlockHandler { + using Super = cBlockHandler; + public: - cBlockPlanksHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + + cBlockPlanksHandler(BLOCKTYPE a_BlockType): + Super(a_BlockType) { } + + + + virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, cPlayer & a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + cChunkInterface & a_ChunkInterface, + cPlayer & a_Player, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { @@ -27,6 +37,10 @@ public: return true; } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { switch (a_Meta) diff --git a/src/Blocks/BlockPortal.h b/src/Blocks/BlockPortal.h index 3f5d87155..c18da10be 100644 --- a/src/Blocks/BlockPortal.h +++ b/src/Blocks/BlockPortal.h @@ -7,25 +7,33 @@ -class cBlockPortalHandler : +class cBlockPortalHandler: public cBlockHandler { + using Super = cBlockHandler; public: - cBlockPortalHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + + cBlockPortalHandler(BLOCKTYPE a_BlockType): + Super(a_BlockType) { } + + + + virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, cPlayer & a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + cChunkInterface & a_ChunkInterface, + cPlayer & a_Player, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { - // We set to zero so MCS doesn't stop you from building weird portals like vanilla does + // We set meta to zero so Cuberite doesn't stop a Creative-mode player from building custom portal shapes // CanBeAt doesn't do anything if meta is zero - // We set to zero because the client sends meta = 2 to the server (it calculates rotation itself) + // We set to zero because the client sends meta = 1 or 2 to the server (it calculates rotation itself) a_BlockType = m_BlockType; a_BlockMeta = 0; @@ -67,14 +75,14 @@ public: - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override { - if ((a_RelY <= 0) || (a_RelY >= cChunkDef::Height - 1)) + if ((a_RelPos.y <= 0) || (a_RelPos.y >= cChunkDef::Height - 1)) { return false; // In case someone places a portal with meta 1 or 2 at boundaries, and server tries to get invalid coords at Y - 1 or Y + 1 } - switch (a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ)) + switch (a_Chunk.GetMeta(a_RelPos)) { case 0x1: { @@ -91,8 +99,7 @@ public: for (const auto & Direction : PortalCheck) { BLOCKTYPE Block; - a_Chunk.UnboundedRelGetBlockType(a_RelX + Direction.x, a_RelY + Direction.y, a_RelZ + Direction.z, Block); - + a_Chunk.UnboundedRelGetBlockType(a_RelPos + Direction, Block); if ((Block != E_BLOCK_NETHER_PORTAL) && (Block != E_BLOCK_OBSIDIAN)) { return false; @@ -115,8 +122,7 @@ public: for (const auto & Direction : PortalCheck) { BLOCKTYPE Block; - a_Chunk.UnboundedRelGetBlockType(a_RelX + Direction.x, a_RelY + Direction.y, a_RelZ + Direction.z, Block); - + a_Chunk.UnboundedRelGetBlockType(a_RelPos + Direction, Block); if ((Block != E_BLOCK_NETHER_PORTAL) && (Block != E_BLOCK_OBSIDIAN)) { return false; @@ -128,6 +134,10 @@ public: return true; } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockPressurePlate.h b/src/Blocks/BlockPressurePlate.h index bac93675e..445ec9ff6 100644 --- a/src/Blocks/BlockPressurePlate.h +++ b/src/Blocks/BlockPressurePlate.h @@ -18,15 +18,19 @@ public: { } - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override + + + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override { - if (a_RelY - 1 <= 0) + if (a_RelPos.y <= 1) { return false; } // TODO: check if the block is upside-down slab or upside-down stairs - BLOCKTYPE Block = a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ); + auto Block = a_Chunk.GetBlock(a_RelPos.addedY(-1)); switch (Block) { case E_BLOCK_ACACIA_FENCE: @@ -47,6 +51,10 @@ public: } } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockQuartz.h b/src/Blocks/BlockQuartz.h index c87240cf1..27d6b9984 100644 --- a/src/Blocks/BlockQuartz.h +++ b/src/Blocks/BlockQuartz.h @@ -7,42 +7,57 @@ -class cBlockQuartzHandler : public cBlockHandler +class cBlockQuartzHandler: + public cBlockHandler { + using Super = cBlockHandler; + public: - cBlockQuartzHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + + cBlockQuartzHandler(BLOCKTYPE a_BlockType): + Super(a_BlockType) { } + + + + virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, cPlayer & a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + cChunkInterface & a_ChunkInterface, + cPlayer & a_Player, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { a_BlockType = m_BlockType; - NIBBLETYPE Meta = static_cast<NIBBLETYPE>(a_Player.GetEquippedItem().m_ItemDamage); + auto Meta = static_cast<NIBBLETYPE>(a_Player.GetEquippedItem().m_ItemDamage); - if (Meta != E_META_QUARTZ_PILLAR) // Check if the block is a pillar block. + // Pillar block needs additional direction in the metadata: + if (Meta != E_META_QUARTZ_PILLAR) { a_BlockMeta = Meta; return true; } - - a_BlockMeta = BlockFaceToMetaData(a_BlockFace, Meta); + a_BlockMeta = BlockFaceToMetaData(a_ClickedBlockFace); return true; } - inline static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_BlockFace, NIBBLETYPE a_QuartzMeta) + + + + + /** Converts the block face of the pillar block's "base" to the block's metadata. */ + inline static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_BlockFace) { switch (a_BlockFace) { case BLOCK_FACE_YM: case BLOCK_FACE_YP: { - return a_QuartzMeta; // Top or bottom, just return original + return E_META_QUARTZ_PILLAR; // Top or bottom } case BLOCK_FACE_ZP: @@ -57,15 +72,17 @@ public: return 0x3; // East or west } - case BLOCK_FACE_NONE: + default: { - ASSERT(!"Unhandled block face!"); - return a_QuartzMeta; // No idea, give a special meta (all sides the same) + return E_META_QUARTZ_PILLAR; } } - UNREACHABLE("Unsupported block face"); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockRail.h b/src/Blocks/BlockRail.h index 7ee98d576..f5cd7d8a2 100644 --- a/src/Blocks/BlockRail.h +++ b/src/Blocks/BlockRail.h @@ -28,21 +28,26 @@ public: { } + + + + virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, cPlayer & a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + cChunkInterface & a_ChunkInterface, + cPlayer & a_Player, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { a_BlockType = m_BlockType; - Vector3i Pos{ a_BlockX, a_BlockY, a_BlockZ }; - a_BlockMeta = FindMeta(a_ChunkInterface, Pos); - return a_Player.GetWorld()->DoWithChunkAt(Pos, - [this, Pos, &a_ChunkInterface](cChunk & a_Chunk) + a_BlockMeta = FindMeta(a_ChunkInterface, a_PlacedBlockPos); + return a_Player.GetWorld()->DoWithChunkAt(a_PlacedBlockPos, + [this, a_PlacedBlockPos, &a_ChunkInterface](cChunk & a_Chunk) { - auto RelPos = cChunkDef::AbsoluteToRelative(Pos); - return CanBeAt(a_ChunkInterface, RelPos.x, RelPos.y, RelPos.z, a_Chunk); + auto RelPos = cChunkDef::AbsoluteToRelative(a_PlacedBlockPos); + return CanBeAt(a_ChunkInterface, RelPos, a_Chunk); } ); } @@ -111,18 +116,18 @@ public: - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override { - if (a_RelY <= 0) + if (a_RelPos.y <= 0) { return false; } - if (!cBlockInfo::FullyOccupiesVoxel(a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ))) + if (!cBlockInfo::FullyOccupiesVoxel(a_Chunk.GetBlock(a_RelPos.addedY(-1)))) { return false; } - NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ); + NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelPos); switch (Meta) { case E_META_RAIL_ASCEND_XP: @@ -132,19 +137,16 @@ public: { // Mapping between the meta and the neighbors that need checking Meta -= E_META_RAIL_ASCEND_XP; // Base index at zero - static const struct - { - int x, z; - } Coords[] = + static const Vector3i Coords[] = { - { 1, 0}, // east, XP - {-1, 0}, // west, XM - { 0, -1}, // north, ZM - { 0, 1}, // south, ZP + { 1, 0, 0}, // east, XP + {-1, 0, 0}, // west, XM + { 0, 0, -1}, // north, ZM + { 0, 0, 1}, // south, ZP } ; BLOCKTYPE BlockType; NIBBLETYPE BlockMeta; - if (!a_Chunk.UnboundedRelGetBlock(a_RelX + Coords[Meta].x, a_RelY, a_RelZ + Coords[Meta].z, BlockType, BlockMeta)) + if (!a_Chunk.UnboundedRelGetBlock(a_RelPos + Coords[Meta], BlockType, BlockMeta)) { // Too close to the edge, cannot simulate return true; @@ -155,6 +157,10 @@ public: return true; } + + + + NIBBLETYPE FindMeta(cChunkInterface & a_ChunkInterface, Vector3i a_BlockPos) { NIBBLETYPE Meta = 0; diff --git a/src/Blocks/BlockRedstone.h b/src/Blocks/BlockRedstone.h index 14621948e..e91c605db 100644 --- a/src/Blocks/BlockRedstone.h +++ b/src/Blocks/BlockRedstone.h @@ -8,7 +8,7 @@ -class cBlockRedstoneHandler : +class cBlockRedstoneHandler: public cBlockHandler { using Super = cBlockHandler; @@ -20,16 +20,20 @@ public: { } - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override + + + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override { - if (a_RelY <= 0) + if (a_RelPos.y <= 0) { return false; } BLOCKTYPE BelowBlock; NIBBLETYPE BelowBlockMeta; - a_Chunk.GetBlockTypeMeta(a_RelX, a_RelY - 1, a_RelZ, BelowBlock, BelowBlockMeta); + a_Chunk.GetBlockTypeMeta(a_RelPos.addedY(-1), BelowBlock, BelowBlockMeta); if (cBlockInfo::FullyOccupiesVoxel(BelowBlock)) { @@ -46,11 +50,19 @@ public: return false; } + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { return cItem(E_ITEM_REDSTONE_DUST, 1, 0); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockRedstoneOre.h b/src/Blocks/BlockRedstoneOre.h index 4b570ab73..9042d7cc6 100644 --- a/src/Blocks/BlockRedstoneOre.h +++ b/src/Blocks/BlockRedstoneOre.h @@ -17,31 +17,39 @@ public: using Super::Super; // Inherit constructor from base + + + + virtual bool OnUse( - cChunkInterface & a_ChunkInterface, - cWorldInterface & a_WorldInterface, - cPlayer & a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, + cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, + const Vector3i a_BlockPos, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ + const Vector3i a_CursorPos ) override { - Vector3i BlockPos{a_BlockX, a_BlockY, a_BlockZ}; - a_ChunkInterface.SetBlock(BlockPos, E_BLOCK_REDSTONE_ORE_GLOWING, 0); + a_ChunkInterface.SetBlock(a_BlockPos, E_BLOCK_REDSTONE_ORE_GLOWING, 0); return false; } + + + + virtual void OnDigging( cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ + const Vector3i a_BlockPos ) override { - Vector3i BlockPos{a_BlockX, a_BlockY, a_BlockZ}; - a_ChunkInterface.SetBlock(BlockPos, E_BLOCK_REDSTONE_ORE_GLOWING, 0); + a_ChunkInterface.SetBlock(a_BlockPos, E_BLOCK_REDSTONE_ORE_GLOWING, 0); } + + + + virtual bool IsUseable() override { return true; @@ -61,6 +69,10 @@ public: using Super::Super; // Inherit constructor from base + + + + virtual void OnUpdate( cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, diff --git a/src/Blocks/BlockRedstoneRepeater.h b/src/Blocks/BlockRedstoneRepeater.h index 25aa9b795..e0b748821 100644 --- a/src/Blocks/BlockRedstoneRepeater.h +++ b/src/Blocks/BlockRedstoneRepeater.h @@ -23,33 +23,63 @@ public: { } - virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override + + + + + virtual bool OnUse( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cPlayer & a_Player, + const Vector3i a_BlockPos, + eBlockFace a_BlockFace, + const Vector3i a_CursorPos + ) override { - a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, ((a_ChunkInterface.GetBlockMeta({a_BlockX, a_BlockY, a_BlockZ}) + 0x04) & 0x0f)); + // Increment the delay setting: + a_ChunkInterface.SetBlockMeta(a_BlockPos, ((a_ChunkInterface.GetBlockMeta(a_BlockPos) + 0x04) & 0x0f)); return true; } - virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override + + + + + virtual void OnCancelRightClick( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cPlayer & a_Player, + const Vector3i a_BlockPos, + eBlockFace a_BlockFace + ) override { UNUSED(a_ChunkInterface); - a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player); + a_WorldInterface.SendBlockTo(a_BlockPos, a_Player); } + + + + virtual bool IsUseable(void) override { return true; } - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override + + + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override { - if (a_RelY <= 0) + if (a_RelPos.y <= 0) { return false; } BLOCKTYPE BelowBlock; NIBBLETYPE BelowBlockMeta; - a_Chunk.GetBlockTypeMeta(a_RelX, a_RelY - 1, a_RelZ, BelowBlock, BelowBlockMeta); + a_Chunk.GetBlockTypeMeta(a_RelPos.addedY(-1), BelowBlock, BelowBlockMeta); if (cBlockInfo::FullyOccupiesVoxel(BelowBlock)) { @@ -66,17 +96,29 @@ public: return false; } + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { return cItem(E_ITEM_REDSTONE_REPEATER, 1, 0); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); return 11; } + + + + inline static Vector3i GetLeftCoordinateOffset(NIBBLETYPE a_Meta) { switch (a_Meta & E_META_REDSTONE_REPEATER_FACING_MASK) // We only want the direction (bottom) bits @@ -95,11 +137,18 @@ public: } } + + + inline static Vector3i GetFrontCoordinateOffset(NIBBLETYPE a_Meta) { return -GetRearCoordinateOffset(a_Meta); } + + + + inline static Vector3i GetRearCoordinateOffset(NIBBLETYPE a_Meta) { switch (a_Meta & E_META_REDSTONE_REPEATER_FACING_MASK) // We only want the direction (bottom) bits diff --git a/src/Blocks/BlockSapling.h b/src/Blocks/BlockSapling.h index 370353882..86397d806 100644 --- a/src/Blocks/BlockSapling.h +++ b/src/Blocks/BlockSapling.h @@ -34,9 +34,9 @@ public: - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override { - return (a_RelY > 0) && IsBlockTypeOfDirt(a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ)); + return (a_RelPos.y > 0) && IsBlockTypeOfDirt(a_Chunk.GetBlock(a_RelPos.addedY(-1))); } diff --git a/src/Blocks/BlockSideways.h b/src/Blocks/BlockSideways.h index 5854f334c..b94b9f8f3 100644 --- a/src/Blocks/BlockSideways.h +++ b/src/Blocks/BlockSideways.h @@ -27,15 +27,17 @@ public: virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, cPlayer & a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + cChunkInterface & a_ChunkInterface, + cPlayer & a_Player, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { a_BlockType = m_BlockType; NIBBLETYPE Meta = static_cast<NIBBLETYPE>(a_Player.GetEquippedItem().m_ItemDamage); - a_BlockMeta = BlockFaceToMetaData(a_BlockFace, Meta); + a_BlockMeta = BlockFaceToMetaData(a_ClickedBlockFace, Meta); return true; } diff --git a/src/Blocks/BlockSignPost.h b/src/Blocks/BlockSignPost.h index 45fa7cad4..f493cb355 100644 --- a/src/Blocks/BlockSignPost.h +++ b/src/Blocks/BlockSignPost.h @@ -32,17 +32,21 @@ public: - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override { - if (a_RelY <= 0) + if (a_RelPos.y <= 0) { return false; } - BLOCKTYPE Type = a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ); - + BLOCKTYPE Type = a_Chunk.GetBlock(a_RelPos.addedY(-1)); return ((Type == E_BLOCK_SIGN_POST) || (Type == E_BLOCK_WALLSIGN) || cBlockInfo::IsSolid(Type)); } + + + + + /** Converts the (player) rotation to placed-signpost block meta. */ static NIBBLETYPE RotationToMetaData(double a_Rotation) { a_Rotation += 180 + (180 / 16); // So it's not aligned with axis @@ -56,16 +60,28 @@ public: return (static_cast<char>(a_Rotation)) % 16; } + + + + virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override { return (a_Meta + 4) & 0x0f; } + + + + virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override { return (a_Meta + 12) & 0x0f; } + + + + virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override { // Mirrors signs over the XY plane (North-South Mirroring) @@ -75,6 +91,10 @@ public: return (a_Meta < 0x08) ? (0x08 - a_Meta) : (0x18 - a_Meta); } + + + + virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override { // Mirrors signs over the YZ plane (East-West Mirroring) @@ -84,6 +104,10 @@ public: return 0x0f - a_Meta; } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockSlab.h b/src/Blocks/BlockSlab.h index bd9c0299a..c59dc6f06 100644 --- a/src/Blocks/BlockSlab.h +++ b/src/Blocks/BlockSlab.h @@ -44,9 +44,11 @@ public: virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, cPlayer & a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + cChunkInterface & a_ChunkInterface, + cPlayer & a_Player, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { @@ -54,18 +56,18 @@ public: NIBBLETYPE Meta = static_cast<NIBBLETYPE>(a_Player.GetEquippedItem().m_ItemDamage); // Set the correct metadata based on player equipped item (i.e. a_BlockMeta not initialised yet) - switch (a_BlockFace) + switch (a_ClickedBlockFace) { case BLOCK_FACE_TOP: { // Bottom half slab block - a_BlockMeta = Meta & 0x7; + a_BlockMeta = Meta & 0x07; break; } case BLOCK_FACE_BOTTOM: { // Top half slab block - a_BlockMeta = Meta | 0x8; + a_BlockMeta = Meta | 0x08; break; } case BLOCK_FACE_EAST: @@ -73,15 +75,15 @@ public: case BLOCK_FACE_SOUTH: case BLOCK_FACE_WEST: { - if (a_CursorY > 7) + if (a_CursorPos.y > 7) { // Cursor at top half of block, place top slab - a_BlockMeta = Meta | 0x8; break; + a_BlockMeta = Meta | 0x08; break; } else { // Cursor at bottom half of block, place bottom slab - a_BlockMeta = Meta & 0x7; break; + a_BlockMeta = Meta & 0x07; break; } } case BLOCK_FACE_NONE: return false; @@ -89,10 +91,10 @@ public: // Check if the block at the coordinates is a single slab. Eligibility for combining has already been processed in ClientHandle // Changed to-be-placed to a double slab if we are clicking on a single slab, as opposed to placing one for the first time - if (IsAnySlabType(a_ChunkInterface.GetBlock({a_BlockX, a_BlockY, a_BlockZ}))) + if (IsAnySlabType(a_ChunkInterface.GetBlock(a_PlacedBlockPos))) { a_BlockType = GetDoubleSlabType(m_BlockType); - a_BlockMeta = a_BlockMeta & 0x7; + a_BlockMeta = a_BlockMeta & 0x07; } return true; @@ -117,7 +119,13 @@ public: - virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override + virtual void OnCancelRightClick( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cPlayer & a_Player, + const Vector3i a_BlockPos, + eBlockFace a_BlockFace + ) override { if ((a_BlockFace == BLOCK_FACE_NONE) || (a_Player.GetEquippedItem().m_ItemType != static_cast<short>(m_BlockType))) { @@ -125,7 +133,7 @@ public: } // Sends the slab back to the client. It's to refuse a doubleslab placement. */ - a_Player.GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player); + a_Player.GetWorld()->SendBlockTo(a_BlockPos, a_Player); } @@ -222,13 +230,13 @@ public: - virtual bool IsInsideBlock(Vector3d a_Position, const BLOCKTYPE a_BlockType, const NIBBLETYPE a_BlockMeta) override + virtual bool IsInsideBlock(Vector3d a_Position, const NIBBLETYPE a_BlockMeta) override { - if (a_BlockMeta & 0x8) // top half + if (a_BlockMeta & 0x08) // top half { return true; } - return cBlockHandler::IsInsideBlock(a_Position, a_BlockType, a_BlockMeta); + return cBlockHandler::IsInsideBlock(a_Position, a_BlockMeta); } } ; @@ -236,7 +244,7 @@ public: -class cBlockDoubleSlabHandler : +class cBlockDoubleSlabHandler: public cBlockHandler { using Super = cBlockHandler; diff --git a/src/Blocks/BlockSnow.h b/src/Blocks/BlockSnow.h index 4972e61fe..9b9ee85c0 100644 --- a/src/Blocks/BlockSnow.h +++ b/src/Blocks/BlockSnow.h @@ -10,30 +10,40 @@ class cBlockSnowHandler : public cBlockHandler { + using Super = cBlockHandler; + public: + enum { FullBlockMeta = 7 // Meta value of a full-height snow block }; - cBlockSnowHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + + cBlockSnowHandler(BLOCKTYPE a_BlockType): + Super(a_BlockType) { } + + + + virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, cPlayer & a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + cChunkInterface & a_ChunkInterface, + cPlayer & a_Player, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { a_BlockType = m_BlockType; + // Check if incrementing existing snow height: BLOCKTYPE BlockBeforePlacement; NIBBLETYPE MetaBeforePlacement; - a_ChunkInterface.GetBlockTypeMeta({a_BlockX, a_BlockY, a_BlockZ}, BlockBeforePlacement, MetaBeforePlacement); - + a_ChunkInterface.GetBlockTypeMeta(a_PlacedBlockPos, BlockBeforePlacement, MetaBeforePlacement); if ((BlockBeforePlacement == E_BLOCK_SNOW) && (MetaBeforePlacement < FullBlockMeta)) { // Only increment if: @@ -45,16 +55,19 @@ public: // First time placement, check placement is valid a_BlockMeta = 0; - BLOCKTYPE BlockBelow; NIBBLETYPE MetaBelow; return ( - (a_BlockY > 0) && - a_ChunkInterface.GetBlockTypeMeta({a_BlockX, a_BlockY - 1, a_BlockZ}, BlockBelow, MetaBelow) && + (a_PlacedBlockPos.y > 0) && + a_ChunkInterface.GetBlockTypeMeta(a_PlacedBlockPos.addedY(-1), BlockBelow, MetaBelow) && CanBeOn(BlockBelow, MetaBelow) ); } + + + + 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 < FullBlockMeta)) @@ -97,35 +110,47 @@ public: - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override { - if (a_RelY > 0) + if (a_RelPos.y <= 0) { - BLOCKTYPE BlockBelow = a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ); - NIBBLETYPE MetaBelow = a_Chunk.GetMeta(a_RelX, a_RelY - 1, a_RelZ); - - return CanBeOn(BlockBelow, MetaBelow); + return false; } - - return false; + auto BelowPos = a_RelPos.addedY(-1); + auto BlockBelow = a_Chunk.GetBlock(BelowPos); + auto MetaBelow = a_Chunk.GetMeta(BelowPos); + return CanBeOn(BlockBelow, MetaBelow); } + + + + virtual bool DoesDropOnUnsuitable(void) override { return false; } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); return 14; } - virtual bool IsInsideBlock(Vector3d a_Position, const BLOCKTYPE a_BlockType, const NIBBLETYPE a_BlockMeta) override + + + + + virtual bool IsInsideBlock(const Vector3d a_RelPosition, const NIBBLETYPE a_BlockMeta) override { - return a_Position.y < (cBlockInfo::GetBlockHeight(a_BlockType) * (a_BlockMeta & 0x07)); + return a_RelPosition.y < (cBlockInfo::GetBlockHeight(m_BlockType) * (a_BlockMeta & 0x07)); } + private: /** Returns true if snow can be placed on top of a block with the given type and meta. */ diff --git a/src/Blocks/BlockStairs.h b/src/Blocks/BlockStairs.h index c9e36d535..d616f5d67 100644 --- a/src/Blocks/BlockStairs.h +++ b/src/Blocks/BlockStairs.h @@ -17,25 +17,27 @@ public: cBlockStairsHandler(BLOCKTYPE a_BlockType): Super(a_BlockType) { - } + + + + virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, cPlayer & a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + cChunkInterface & a_ChunkInterface, + cPlayer & a_Player, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { UNUSED(a_ChunkInterface); - UNUSED(a_BlockX); - UNUSED(a_BlockY); - UNUSED(a_BlockZ); - UNUSED(a_CursorX); - UNUSED(a_CursorZ); + UNUSED(a_PlacedBlockPos); + UNUSED(a_CursorPos); a_BlockType = m_BlockType; a_BlockMeta = RotationToMetaData(a_Player.GetYaw()); - switch (a_BlockFace) + switch (a_ClickedBlockFace) { case BLOCK_FACE_TOP: break; case BLOCK_FACE_BOTTOM: a_BlockMeta = a_BlockMeta | 0x4; break; // When placing onto a bottom face, always place an upside-down stairs block @@ -45,7 +47,7 @@ public: case BLOCK_FACE_WEST: { // When placing onto a sideways face, check cursor, if in top half, make it an upside-down stairs block - if (a_CursorY > 8) + if (a_CursorPos.y > 8) { a_BlockMeta |= 0x4; } @@ -56,6 +58,10 @@ public: return true; } + + + + static NIBBLETYPE RotationToMetaData(double a_Rotation) { a_Rotation += 90 + 45; // So its not aligned with axis @@ -81,12 +87,20 @@ public: } } + + + + virtual NIBBLETYPE MetaMirrorXZ(NIBBLETYPE a_Meta) override { // Toggle bit 3: return (a_Meta & 0x0b) | ((~a_Meta) & 0x04); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); @@ -114,12 +128,16 @@ public: } } + + + + /** EXCEPTION a.k.a. why is this removed: This collision-detection is actually more accurate than the client, but since the client itself sends inaccurate / sparse data, it's easier to just err on the side of the client and keep the two in sync by assuming that if a player hit ANY of the stair's bounding cube, it counts as the ground. */ #if 0 - bool IsInsideBlock(const Vector3d & a_Position, const BLOCKTYPE a_BlockType, const NIBBLETYPE a_BlockMeta) + bool IsInsideBlock(Vector3d a_RelPosition, const BLOCKTYPE a_BlockType, const NIBBLETYPE a_BlockMeta) { if (a_BlockMeta & 0x4) // upside down { @@ -127,19 +145,19 @@ public: } else if ((a_BlockMeta & 0x3) == 0) // tall side is east (+X) { - return a_Position.y < ((a_Position.x > 0.5) ? 1.0 : 0.5); + return (a_RelPosition.y < ((a_RelPosition.x > 0.5) ? 1.0 : 0.5)); } else if ((a_BlockMeta & 0x3) == 1) // tall side is west (-X) { - return a_Position.y < ((a_Position.x < 0.5) ? 1.0 : 0.5); + return (a_RelPosition.y < ((a_RelPosition.x < 0.5) ? 1.0 : 0.5)); } else if ((a_BlockMeta & 0x3) == 2) // tall side is south (+Z) { - return a_Position.y < ((a_Position.z > 0.5) ? 1.0 : 0.5); + return (a_RelPosition.y < ((a_RelPosition.z > 0.5) ? 1.0 : 0.5)); } else if ((a_BlockMeta & 0x3) == 3) // tall side is north (-Z) { - return a_Position.y < ((a_Position.z < 0.5) ? 1.0 : 0.5); + return (a_RelPosition.y < ((a_RelPosition.z < 0.5) ? 1.0 : 0.5)); } return false; } diff --git a/src/Blocks/BlockStems.h b/src/Blocks/BlockStems.h index bf0d7ce41..0e4b01c5a 100644 --- a/src/Blocks/BlockStems.h +++ b/src/Blocks/BlockStems.h @@ -36,9 +36,9 @@ public: - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override { - return ((a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) == E_BLOCK_FARMLAND)); + return ((a_RelPos.y > 0) && (a_Chunk.GetBlock(a_RelPos.addedY(-1)) == E_BLOCK_FARMLAND)); } diff --git a/src/Blocks/BlockSugarcane.h b/src/Blocks/BlockSugarcane.h index f45b312a8..fa153bd28 100644 --- a/src/Blocks/BlockSugarcane.h +++ b/src/Blocks/BlockSugarcane.h @@ -32,36 +32,32 @@ public: - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override { - if (a_RelY <= 0) + if (a_RelPos.y <= 0) { return false; } - switch (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ)) + switch (a_Chunk.GetBlock(a_RelPos.addedY(-1))) { case E_BLOCK_DIRT: case E_BLOCK_GRASS: case E_BLOCK_FARMLAND: case E_BLOCK_SAND: { - static const struct + static const Vector3i Coords[] = { - int x, z; - } Coords[] = - { - {-1, 0}, - { 1, 0}, - { 0, -1}, - { 0, 1}, + {-1, -1, 0}, + { 1, -1, 0}, + { 0, -1, -1}, + { 0, -1, 1}, } ; - a_RelY -= 1; for (size_t i = 0; i < ARRAYCOUNT(Coords); i++) { BLOCKTYPE BlockType; NIBBLETYPE BlockMeta; - if (!a_Chunk.UnboundedRelGetBlock(a_RelX + Coords[i].x, a_RelY, a_RelZ + Coords[i].z, BlockType, BlockMeta)) + if (!a_Chunk.UnboundedRelGetBlock(a_RelPos + Coords[i], BlockType, BlockMeta)) { // Too close to the edge, cannot simulate return true; diff --git a/src/Blocks/BlockTNT.h b/src/Blocks/BlockTNT.h index d8b50335a..fafa289da 100644 --- a/src/Blocks/BlockTNT.h +++ b/src/Blocks/BlockTNT.h @@ -10,17 +10,34 @@ class cBlockTNTHandler : public cBlockHandler { + using Super = cBlockHandler; + public: - cBlockTNTHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + + cBlockTNTHandler(BLOCKTYPE a_BlockType): + Super(a_BlockType) { } - virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override + + + + + virtual void OnCancelRightClick( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cPlayer & a_Player, + const Vector3i a_BlockPos, + eBlockFace a_BlockFace + ) override { - a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player); + a_WorldInterface.SendBlockTo(a_BlockPos, a_Player); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockTallGrass.h b/src/Blocks/BlockTallGrass.h index d09e9d496..4cf115efd 100644 --- a/src/Blocks/BlockTallGrass.h +++ b/src/Blocks/BlockTallGrass.h @@ -54,14 +54,14 @@ public: - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override { - if (a_RelY <= 0) + if (a_RelPos.y <= 0) { return false; } - BLOCKTYPE BelowBlock = a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ); + BLOCKTYPE BelowBlock = a_Chunk.GetBlock(a_RelPos.addedY(-1)); return IsBlockTypeOfDirt(BelowBlock); } diff --git a/src/Blocks/BlockTorch.h b/src/Blocks/BlockTorch.h index 93ca5e40d..e2a2dfcc9 100644 --- a/src/Blocks/BlockTorch.h +++ b/src/Blocks/BlockTorch.h @@ -8,7 +8,7 @@ -class cBlockTorchHandler : +class cBlockTorchHandler: public cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x7, 0x4, 0x1, 0x3, 0x2>> { using Super = cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x7, 0x4, 0x1, 0x3, 0x2>>; @@ -20,39 +20,46 @@ public: { } + + + + virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, cPlayer & a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + cChunkInterface & a_ChunkInterface, + cPlayer & a_Player, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { - BLOCKTYPE Block; - NIBBLETYPE Meta; - AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, true); // Set to clicked block - a_ChunkInterface.GetBlockTypeMeta({a_BlockX, a_BlockY, a_BlockZ}, Block, Meta); - - if (!CanBePlacedOn(Block, Meta, a_BlockFace)) // Try to preserve original direction + BLOCKTYPE ClickedBlockType; + NIBBLETYPE ClickedBlockMeta; + auto ClickedBlockPos = AddFaceDirection(a_PlacedBlockPos, a_ClickedBlockFace, true); + a_ChunkInterface.GetBlockTypeMeta(ClickedBlockPos, ClickedBlockType, ClickedBlockMeta); + if (!CanBePlacedOn(ClickedBlockType, ClickedBlockMeta, a_ClickedBlockFace)) { - // Torch couldn't be placed on whatever face was clicked, last ditch resort - find another face - - AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, false); // Reset to torch block - a_BlockFace = FindSuitableFace(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ); // Set a_BlockFace to a valid direction which will be converted later to a metadata - if (a_BlockFace == BLOCK_FACE_NONE) + // Couldn't be placed on whatever face was clicked, last ditch resort - find another face + a_ClickedBlockFace = FindSuitableFace(a_ChunkInterface, a_PlacedBlockPos); // Set a_BlockFace to a valid direction which will be converted later to a metadata + if (a_ClickedBlockFace == BLOCK_FACE_NONE) { // No attachable face found - don't place the torch return false; } } - a_BlockType = m_BlockType; - a_BlockMeta = DirectionToMetaData(a_BlockFace); + a_BlockMeta = BlockFaceToMetaData(a_ClickedBlockFace); return true; } - inline static NIBBLETYPE DirectionToMetaData(eBlockFace a_Direction) + + + + + /** Converts the block face of the neighbor to which the torch is attached, to the torch block's meta. */ + inline static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_NeighborBlockFace) { - switch (a_Direction) + switch (a_NeighborBlockFace) { case BLOCK_FACE_BOTTOM: ASSERT(!"Shouldn't be getting this face"); return 0; case BLOCK_FACE_TOP: return E_META_TORCH_FLOOR; @@ -69,7 +76,12 @@ public: return 0x0; } - inline static eBlockFace MetaDataToDirection(NIBBLETYPE a_MetaData) + + + + + /** Converts the torch block's meta to the block face of the neighbor to which the torch is attached. */ + inline static eBlockFace MetaDataToBlockFace(NIBBLETYPE a_MetaData) { switch (a_MetaData) { @@ -88,6 +100,11 @@ public: return BLOCK_FACE_TOP; } + + + + + /** Returns true if the torch can be placed on the specified block's face. */ static bool CanBePlacedOn(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, eBlockFace a_BlockFace) { switch (a_BlockType) @@ -115,7 +132,7 @@ public: case E_BLOCK_STONE_SLAB: case E_BLOCK_WOODEN_SLAB: { - // Toches can be placed on the top of these slabs only if the occupy the top half of the voxel + // Toches can be placed only on the top of top-half-slabs return ((a_BlockFace == BLOCK_FACE_YP) && ((a_BlockMeta & 0x08) == 0x08)); } case E_BLOCK_OAK_WOOD_STAIRS: @@ -146,45 +163,52 @@ public: } } - /** Finds a suitable face to place the torch, returning BLOCK_FACE_NONE on failure */ - static eBlockFace FindSuitableFace(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ) + + + + + /** Returns a suitable neighbor's blockface to place the torch at the specified pos + Returns BLOCK_FACE_NONE on failure */ + static eBlockFace FindSuitableFace(cChunkInterface & a_ChunkInterface, const Vector3i a_TorchPos) { - for (int i = BLOCK_FACE_YM; i <= BLOCK_FACE_XP; i++) // Loop through all directions + for (int i = BLOCK_FACE_YM; i <= BLOCK_FACE_XP; i++) // Loop through all faces { - eBlockFace Face = static_cast<eBlockFace>(i); - AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, Face, true); - BLOCKTYPE BlockInQuestion; - NIBBLETYPE BlockInQuestionMeta; - a_ChunkInterface.GetBlockTypeMeta({a_BlockX, a_BlockY, a_BlockZ}, BlockInQuestion, BlockInQuestionMeta); - - if (CanBePlacedOn(BlockInQuestion, BlockInQuestionMeta, Face)) + auto Face = static_cast<eBlockFace>(i); + auto NeighborPos = AddFaceDirection(a_TorchPos, Face, true); + BLOCKTYPE NeighborBlockType; + NIBBLETYPE NeighborBlockMeta; + a_ChunkInterface.GetBlockTypeMeta(NeighborPos, NeighborBlockType, NeighborBlockMeta); + if (CanBePlacedOn(NeighborBlockType, NeighborBlockMeta, Face)) { return Face; } - else - { - // Reset coords in preparation for next iteration - AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, Face, false); - } } return BLOCK_FACE_NONE; } - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override - { - eBlockFace Face = MetaDataToDirection(a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ)); - AddFaceDirection(a_RelX, a_RelY, a_RelZ, Face, true); - BLOCKTYPE BlockInQuestion; - NIBBLETYPE BlockInQuestionMeta; - if (!a_Chunk.UnboundedRelGetBlock(a_RelX, a_RelY, a_RelZ, BlockInQuestion, BlockInQuestionMeta)) + + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override + { + auto Face = MetaDataToBlockFace(a_Chunk.GetMeta(a_RelPos)); + auto NeighborRelPos = AddFaceDirection(a_RelPos, Face, true); + BLOCKTYPE NeighborBlockType; + NIBBLETYPE NeighborBlockMeta; + if (!a_Chunk.UnboundedRelGetBlock(NeighborRelPos, NeighborBlockType, NeighborBlockMeta)) { + // Neighbor in an unloaded chunk, bail out without changint this. return false; } - return CanBePlacedOn(BlockInQuestion, BlockInQuestionMeta, Face); + return CanBePlacedOn(NeighborBlockType, NeighborBlockMeta, Face); } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockTrapdoor.h b/src/Blocks/BlockTrapdoor.h index 0ad2c64f5..f0c821764 100644 --- a/src/Blocks/BlockTrapdoor.h +++ b/src/Blocks/BlockTrapdoor.h @@ -32,7 +32,14 @@ public: - virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override + virtual bool OnUse( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cPlayer & a_Player, + const Vector3i a_BlockPos, + eBlockFace a_BlockFace, + const Vector3i a_CursorPos + ) override { if (m_BlockType == E_BLOCK_IRON_TRAPDOOR) { @@ -41,36 +48,56 @@ public: } // Flip the ON bit on / off using the XOR bitwise operation - NIBBLETYPE Meta = (a_ChunkInterface.GetBlockMeta({a_BlockX, a_BlockY, a_BlockZ}) ^ 0x04); - a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta); - a_WorldInterface.GetBroadcastManager().BroadcastSoundParticleEffect(EffectID::SFX_RANDOM_FENCE_GATE_OPEN, { a_BlockX, a_BlockY, a_BlockZ }, 0, a_Player.GetClientHandle()); + NIBBLETYPE Meta = (a_ChunkInterface.GetBlockMeta(a_BlockPos) ^ 0x04); + a_ChunkInterface.SetBlockMeta(a_BlockPos, Meta); + a_WorldInterface.GetBroadcastManager().BroadcastSoundParticleEffect(EffectID::SFX_RANDOM_FENCE_GATE_OPEN, a_BlockPos, 0, a_Player.GetClientHandle()); return true; } - virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override + + + + + virtual void OnCancelRightClick( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cPlayer & a_Player, + const Vector3i a_BlockPos, + eBlockFace a_BlockFace + ) override { UNUSED(a_ChunkInterface); - a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player); + a_WorldInterface.SendBlockTo(a_BlockPos, a_Player); } + + + + virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, cPlayer & a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + cChunkInterface & a_ChunkInterface, + cPlayer & a_Player, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { a_BlockType = m_BlockType; - a_BlockMeta = BlockFaceToMetaData(a_BlockFace); + a_BlockMeta = BlockFaceToMetaData(a_ClickedBlockFace); - if (a_CursorY > 7) + if (a_CursorPos.y > 7) { a_BlockMeta |= 0x8; } return true; } + + + + inline static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_BlockFace) { switch (a_BlockFace) @@ -90,6 +117,10 @@ public: UNREACHABLE("Unsupported block face"); } + + + + inline static eBlockFace BlockMetaDataToBlockFace(NIBBLETYPE a_Meta) { switch (a_Meta & 0x3) @@ -106,6 +137,10 @@ public: } } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockTripwireHook.h b/src/Blocks/BlockTripwireHook.h index 797034ea0..766c0e404 100644 --- a/src/Blocks/BlockTripwireHook.h +++ b/src/Blocks/BlockTripwireHook.h @@ -24,14 +24,16 @@ public: virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, cPlayer & a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + cChunkInterface & a_ChunkInterface, + cPlayer & a_Player, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { a_BlockType = m_BlockType; - a_BlockMeta = DirectionToMetadata(a_BlockFace); + a_BlockMeta = DirectionToMetadata(a_ClickedBlockFace); return true; } @@ -79,16 +81,17 @@ public: - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override { - NIBBLETYPE Meta; - a_Chunk.UnboundedRelGetBlockMeta(a_RelX, a_RelY, a_RelZ, Meta); - - AddFaceDirection(a_RelX, a_RelY, a_RelZ, MetadataToDirection(Meta), true); - BLOCKTYPE BlockIsOn; - a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ, BlockIsOn); - - return ((a_RelY > 0) && cBlockInfo::FullyOccupiesVoxel(BlockIsOn)); + auto Meta = a_Chunk.GetMeta(a_RelPos); + auto NeighborPos = AddFaceDirection(a_RelPos, MetadataToDirection(Meta), true); + if (!cChunkDef::IsValidHeight(NeighborPos.y)) + { + return false; + } + BLOCKTYPE NeighborBlockType; + a_Chunk.UnboundedRelGetBlockType(a_RelPos, NeighborBlockType); + return cBlockInfo::FullyOccupiesVoxel(NeighborBlockType); } diff --git a/src/Blocks/BlockVine.h b/src/Blocks/BlockVine.h index f8328f046..2cf6e985c 100644 --- a/src/Blocks/BlockVine.h +++ b/src/Blocks/BlockVine.h @@ -23,23 +23,25 @@ public: virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, cPlayer & a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + cChunkInterface & a_ChunkInterface, + cPlayer & a_Player, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { // TODO: Disallow placement where the vine doesn't attach to something properly BLOCKTYPE BlockType = 0; NIBBLETYPE BlockMeta; - a_ChunkInterface.GetBlockTypeMeta({a_BlockX, a_BlockY, a_BlockZ}, BlockType, BlockMeta); + a_ChunkInterface.GetBlockTypeMeta(a_PlacedBlockPos, BlockType, BlockMeta); if (BlockType == m_BlockType) { - a_BlockMeta = BlockMeta | DirectionToMetaData(a_BlockFace); + a_BlockMeta = BlockMeta | DirectionToMetaData(a_ClickedBlockFace); } else { - a_BlockMeta = DirectionToMetaData(a_BlockFace); + a_BlockMeta = DirectionToMetaData(a_ClickedBlockFace); } a_BlockType = m_BlockType; return true; diff --git a/src/Blocks/BlockWallSign.h b/src/Blocks/BlockWallSign.h index 551107d88..87c0355a9 100644 --- a/src/Blocks/BlockWallSign.h +++ b/src/Blocks/BlockWallSign.h @@ -33,39 +33,45 @@ public: - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override { - int BlockX = (a_Chunk.GetPosX() * cChunkDef::Width) + a_RelX; - int BlockZ = (a_Chunk.GetPosZ() * cChunkDef::Width) + a_RelZ; - GetBlockCoordsBehindTheSign(a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ), BlockX, BlockZ); - BLOCKTYPE Type = a_ChunkInterface.GetBlock({BlockX, a_RelY, BlockZ}); - - return ((Type == E_BLOCK_WALLSIGN) || (Type == E_BLOCK_SIGN_POST) || cBlockInfo::IsSolid(Type)); + auto NeighborPos = a_RelPos + GetOffsetBehindTheSign(a_Chunk.GetMeta(a_RelPos)); + BLOCKTYPE NeighborType; + if (!a_Chunk.UnboundedRelGetBlockType(NeighborPos, NeighborType)) + { + // The neighbor is not accessible (unloaded chunk), bail out without changing this + return true; + } + return ((NeighborType == E_BLOCK_WALLSIGN) || (NeighborType == E_BLOCK_SIGN_POST) || cBlockInfo::IsSolid(NeighborType)); } - static void GetBlockCoordsBehindTheSign(NIBBLETYPE a_BlockMeta, int & a_BlockX, int & a_BlockZ) + /** Returns the offset from the sign coords to the block to which the wallsign is attached, based on the wallsign's block meta. + Asserts / returns a zero vector on wrong meta. */ + static Vector3i GetOffsetBehindTheSign(NIBBLETYPE a_BlockMeta) { switch (a_BlockMeta) { - case 2: a_BlockZ++; break; - case 3: a_BlockZ--; break; - case 4: a_BlockX++; break; - case 5: a_BlockX--; break; - default: break; + case 2: return Vector3i( 0, 0, 1); + case 3: return Vector3i( 0, 0, -1); + case 4: return Vector3i( 1, 0, 0); + case 5: return Vector3i(-1, 0, 0); } + ASSERT(!"Invalid wallsign block meta"); + return Vector3i(); } - static NIBBLETYPE DirectionToMetaData(eBlockFace a_Direction) + /** Converts the block face of the neighbor to which the wallsign is attached to the wallsign block's meta. */ + static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_NeighborBlockFace) { - switch (a_Direction) + switch (a_NeighborBlockFace) { case BLOCK_FACE_ZM: return 0x02; case BLOCK_FACE_ZP: return 0x03; diff --git a/src/Blocks/BlockWorkbench.h b/src/Blocks/BlockWorkbench.h index c5eb48657..608754158 100644 --- a/src/Blocks/BlockWorkbench.h +++ b/src/Blocks/BlockWorkbench.h @@ -12,24 +12,46 @@ class cBlockWorkbenchHandler: public cBlockHandler { + using Super = cBlockHandler; + public: - cBlockWorkbenchHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + + cBlockWorkbenchHandler(BLOCKTYPE a_BlockType): + Super(a_BlockType) { } - virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override + + + + + virtual bool OnUse( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cPlayer & a_Player, + const Vector3i a_BlockPos, + eBlockFace a_BlockFace, + const Vector3i a_CursorPos + ) override { - cWindow * Window = new cCraftingWindow(a_BlockX, a_BlockY, a_BlockZ); + cWindow * Window = new cCraftingWindow(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z); a_Player.OpenWindow(*Window); return true; } + + + + virtual bool IsUseable(void) override { return true; } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/Mixins.h b/src/Blocks/Mixins.h index cddbb4850..7e581c876 100644 --- a/src/Blocks/Mixins.h +++ b/src/Blocks/Mixins.h @@ -189,7 +189,8 @@ public: cYawRotator(BLOCKTYPE a_BlockType): Super(a_BlockType) - {} + { + } @@ -197,13 +198,14 @@ public: virtual bool GetPlacementBlockTypeMeta( cChunkInterface & a_ChunkInterface, cPlayer & a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + const Vector3i a_BlockPos, + eBlockFace a_BlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { NIBBLETYPE BaseMeta; - if (!Super::GetPlacementBlockTypeMeta(a_ChunkInterface, a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, a_BlockType, BaseMeta)) + if (!Super::GetPlacementBlockTypeMeta(a_ChunkInterface, a_Player, a_BlockPos, a_BlockFace, a_CursorPos, a_BlockType, BaseMeta)) { return false; } @@ -259,25 +261,29 @@ class cPitchYawRotator: public cYawRotator<Base, BitMask, North, East, South, West> { using Super = cYawRotator<Base, BitMask, North, East, South, West>; + public: cPitchYawRotator(BLOCKTYPE a_BlockType): Super(a_BlockType) - {} + { + } virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, cPlayer & a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + cChunkInterface & a_ChunkInterface, + cPlayer & a_Player, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { NIBBLETYPE BaseMeta; - if (!Super::GetPlacementBlockTypeMeta(a_ChunkInterface, a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, a_BlockType, BaseMeta)) + if (!Super::GetPlacementBlockTypeMeta(a_ChunkInterface, a_Player, a_PlacedBlockPos, a_ClickedBlockFace, a_CursorPos, a_BlockType, BaseMeta)) { return false; } diff --git a/src/Blocks/WorldInterface.h b/src/Blocks/WorldInterface.h index 0967e2bb8..2a39ffbc2 100644 --- a/src/Blocks/WorldInterface.h +++ b/src/Blocks/WorldInterface.h @@ -60,6 +60,12 @@ public: /** Sends the block on those coords to the player */ virtual void SendBlockTo(int a_BlockX, int a_BlockY, int a_BlockZ, cPlayer & a_Player) = 0; + /** Sends the block on those coords to the player */ + inline void SendBlockTo(const Vector3i a_BlockPos, cPlayer & a_Player) + { + SendBlockTo(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, a_Player); + } + /** Calls the callback for each player in the list; returns true if all players processed, false if the callback aborted by returning true */ virtual bool ForEachPlayer(cPlayerListCallback a_Callback) = 0; diff --git a/src/Chunk.h b/src/Chunk.h index bb6f2e5b5..96adf71d7 100644 --- a/src/Chunk.h +++ b/src/Chunk.h @@ -572,7 +572,7 @@ public: /** Converts the coord relative to this chunk into an absolute coord. Doesn't check relative coord validity. */ - Vector3i RelativeToAbsolute(Vector3i a_RelBlockPosition) + Vector3i RelativeToAbsolute(Vector3i a_RelBlockPosition) const { return cChunkDef::RelativeToAbsolute(a_RelBlockPosition, {m_PosX, m_PosZ}); } diff --git a/src/ChunkDef.h b/src/ChunkDef.h index f93fed249..8f46c5f8f 100644 --- a/src/ChunkDef.h +++ b/src/ChunkDef.h @@ -555,8 +555,17 @@ 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()); } + /** Returns the absolute coords of the stored block. */ + Vector3i GetAbsolutePos() const + { + return Vector3i(GetX(), GetY(), GetZ()); + } + + /** Returns the relative position of the stored block within its chunk. */ + Vector3i GetRelativePos() const + { + return Vector3i(m_RelX, m_RelY, m_RelZ); + } }; typedef std::list<sSetBlock> sSetBlockList; diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 5e9736371..30f7c986f 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -1165,7 +1165,7 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eB { ItemHandler = cItemHandler::GetItemHandler(m_Player->GetInventory().GetShieldSlot()); } - ItemHandler->OnItemShoot(m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); + ItemHandler->OnItemShoot(m_Player, {a_BlockX, a_BlockY, a_BlockZ}, a_BlockFace); } return; } @@ -1294,10 +1294,10 @@ void cClientHandle::HandleBlockDigStarted(int a_BlockX, int a_BlockY, int a_Bloc cWorld * World = m_Player->GetWorld(); cChunkInterface ChunkInterface(World->GetChunkMap()); cBlockHandler * Handler = cBlockInfo::GetHandler(a_OldBlock); - Handler->OnDigging(ChunkInterface, *World, *m_Player, a_BlockX, a_BlockY, a_BlockZ); + Handler->OnDigging(ChunkInterface, *World, *m_Player, {a_BlockX, a_BlockY, a_BlockZ}); cItemHandler * ItemHandler = cItemHandler::GetItemHandler(m_Player->GetEquippedItem()); - ItemHandler->OnDiggingBlock(World, m_Player, m_Player->GetEquippedItem(), a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); + ItemHandler->OnDiggingBlock(World, m_Player, m_Player->GetEquippedItem(), {a_BlockX, a_BlockY, a_BlockZ}, a_BlockFace); } @@ -1444,9 +1444,11 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e // TODO: This distance should be calculated from the point that the cursor pointing at, instead of the center of the block // Distance from the block's center to the player's eye height - double Dist = (Vector3d(a_BlockX, a_BlockY, a_BlockZ) + Vector3d(0.5, 0.5, 0.5) - m_Player->GetEyePosition()).Length(); - FLOGD("HandleRightClick: {0}, face {1}, Hand: {2}, HeldItem: {3}; Dist: {4:.02f}", - Vector3i{a_BlockX, a_BlockY, a_BlockZ}, a_BlockFace, a_Hand, ItemToFullString(HeldItem), Dist + auto ClickedBlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ); + auto CursorPos = Vector3i(a_CursorX, a_CursorY, a_CursorZ); + double Dist = (Vector3d(ClickedBlockPos) + Vector3d(0.5, 0.5, 0.5) - m_Player->GetEyePosition()).Length(); + FLOGD("HandleRightClick: {0}, face {1}, Cursor {2}, Hand: {3}, HeldItem: {4}; Dist: {5:.02f}", + ClickedBlockPos, a_BlockFace, CursorPos, a_Hand, ItemToFullString(HeldItem), Dist ); // Check the reach distance: @@ -1464,7 +1466,7 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e { BLOCKTYPE BlockType; NIBBLETYPE BlockMeta; - World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta); + World->GetBlockTypeMeta(ClickedBlockPos, BlockType, BlockMeta); cBlockHandler * BlockHandler = cBlockInfo::GetHandler(BlockType); bool Placeable = ItemHandler->IsPlaceable() && !m_Player->IsGameModeAdventure() && !m_Player->IsGameModeSpectator(); @@ -1476,7 +1478,7 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e cChunkInterface ChunkInterface(World->GetChunkMap()); if (!PlgMgr->CallHookPlayerUsingBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta)) { - if (BlockHandler->OnUse(ChunkInterface, *World, *m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ)) + if (BlockHandler->OnUse(ChunkInterface, *World, *m_Player, ClickedBlockPos, a_BlockFace, CursorPos)) { // block use was successful, we're done PlgMgr->CallHookPlayerUsedBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta); @@ -1487,14 +1489,14 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e if (!Success && Placeable) { // place a block - Success = ItemHandler->OnPlayerPlace(*World, *m_Player, HeldItem, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ); + Success = ItemHandler->OnPlayerPlace(*World, *m_Player, HeldItem, {a_BlockX, a_BlockY, a_BlockZ}, a_BlockFace, {a_CursorX, a_CursorY, a_CursorZ}); } } else { // TODO: OnCancelRightClick seems to do the same thing with updating blocks at the end of this function. Need to double check // A plugin doesn't agree with the action, replace the block on the client and quit: - BlockHandler->OnCancelRightClick(ChunkInterface, *World, *m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); + BlockHandler->OnCancelRightClick(ChunkInterface, *World, *m_Player, {a_BlockX, a_BlockY, a_BlockZ}, a_BlockFace); } } else if (Placeable) @@ -1507,7 +1509,7 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e return; } // place a block - Success = ItemHandler->OnPlayerPlace(*World, *m_Player, HeldItem, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ); + Success = ItemHandler->OnPlayerPlace(*World, *m_Player, HeldItem, {a_BlockX, a_BlockY, a_BlockZ}, a_BlockFace, {a_CursorX, a_CursorY, a_CursorZ}); } else { @@ -1516,7 +1518,7 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e { // All plugins agree with using the item cBlockInServerPluginInterface PluginInterface(*World); - ItemHandler->OnItemUse(World, m_Player, PluginInterface, HeldItem, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); + ItemHandler->OnItemUse(World, m_Player, PluginInterface, HeldItem, {a_BlockX, a_BlockY, a_BlockZ}, a_BlockFace); PlgMgr->CallHookPlayerUsedItem(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ); Success = true; } @@ -1827,7 +1829,7 @@ void cClientHandle::HandleUseItem(eHand a_Hand) { // All plugins agree with using the item cBlockInServerPluginInterface PluginInterface(*World); - ItemHandler->OnItemUse(World, m_Player, PluginInterface, HeldItem, -1, 255, -1, BLOCK_FACE_NONE); + ItemHandler->OnItemUse(World, m_Player, PluginInterface, HeldItem, {-1, 255, -1}, BLOCK_FACE_NONE); PlgMgr->CallHookPlayerUsedItem(*m_Player, -1, 255, -1, BLOCK_FACE_NONE, 0, 0, 0); } } @@ -2641,7 +2643,7 @@ void cClientHandle::SendEntityVelocity(const cEntity & a_Entity) -void cClientHandle::SendExplosion(double a_BlockX, double a_BlockY, double a_BlockZ, float a_Radius, const cVector3iArray & a_BlocksAffected, const Vector3d & a_PlayerMotion) +void cClientHandle::SendExplosion(const Vector3d a_Pos, float a_Radius, const cVector3iArray & a_BlocksAffected, const Vector3d a_PlayerMotion) { if (m_NumExplosionsThisTick > MAX_EXPLOSIONS_PER_TICK) { @@ -2652,7 +2654,7 @@ void cClientHandle::SendExplosion(double a_BlockX, double a_BlockY, double a_Blo // Update the statistics: m_NumExplosionsThisTick++; - m_Protocol->SendExplosion(a_BlockX, a_BlockY, a_BlockZ, a_Radius, a_BlocksAffected, a_PlayerMotion); + m_Protocol->SendExplosion(a_Pos.x, a_Pos.y, a_Pos.z, a_Radius, a_BlocksAffected, a_PlayerMotion); } diff --git a/src/ClientHandle.h b/src/ClientHandle.h index ecfe43977..dde521cbf 100644 --- a/src/ClientHandle.h +++ b/src/ClientHandle.h @@ -173,7 +173,7 @@ public: // tolua_export void SendEntityVelocity (const cEntity & a_Entity); void SendExperience (void); void SendExperienceOrb (const cExpOrb & a_ExpOrb); - void SendExplosion (double a_BlockX, double a_BlockY, double a_BlockZ, float a_Radius, const cVector3iArray & a_BlocksAffected, const Vector3d & a_PlayerMotion); + void SendExplosion (const Vector3d a_Pos, float a_Radius, const cVector3iArray & a_BlocksAffected, const Vector3d a_PlayerMotion); void SendGameMode (eGameMode a_GameMode); void SendHealth (void); void SendHeldItemChange (int a_ItemIndex); diff --git a/src/Entities/Pawn.cpp b/src/Entities/Pawn.cpp index 109a1c70e..6a69cf6e5 100644 --- a/src/Entities/Pawn.cpp +++ b/src/Entities/Pawn.cpp @@ -331,10 +331,7 @@ void cPawn::HandleFalling(void) /* The blocks we're interested in relative to the player to account for larger than 1 blocks. This can be extended to do additional checks in case there are blocks that are represented as one block in memory but have a hitbox larger than 1 (like fences) */ - static const struct - { - int x, y, z; - } BlockSampleOffsets[] = + static const Vector3i BlockSampleOffsets[] = { { 0, 0, 0 }, // TODO: something went wrong here (offset 0?) { 0, -1, 0 }, // Potentially causes mis-detection (IsFootInWater) when player stands on block diagonal to water (i.e. on side of pool) @@ -354,26 +351,26 @@ void cPawn::HandleFalling(void) /* We go through the blocks that we consider "relevant" */ for (size_t j = 0; j < ARRAYCOUNT(BlockSampleOffsets); j++) { - Vector3i BlockTestPosition = CrossTestPosition.Floor() + Vector3i(BlockSampleOffsets[j].x, BlockSampleOffsets[j].y, BlockSampleOffsets[j].z); + Vector3i BlockTestPosition = CrossTestPosition.Floor() + BlockSampleOffsets[j]; if (!cChunkDef::IsValidHeight(BlockTestPosition.y)) { continue; } - BLOCKTYPE Block = GetWorld()->GetBlock(BlockTestPosition); + BLOCKTYPE BlockType = GetWorld()->GetBlock(BlockTestPosition); NIBBLETYPE BlockMeta = GetWorld()->GetBlockMeta(BlockTestPosition); /* we do the cross-shaped sampling to check for water / liquids, but only on our level because water blocks are never bigger than unit voxels */ if (j == 0) { - IsFootInWater |= IsBlockWater(Block); - IsFootInLiquid |= IsFootInWater || IsBlockLava(Block) || (Block == E_BLOCK_COBWEB); // okay so cobweb is not _technically_ a liquid... - IsFootOnSlimeBlock |= (Block == E_BLOCK_SLIME_BLOCK); + IsFootInWater |= IsBlockWater(BlockType); + IsFootInLiquid |= IsFootInWater || IsBlockLava(BlockType) || (BlockType == E_BLOCK_COBWEB); // okay so cobweb is not _technically_ a liquid... + IsFootOnSlimeBlock |= (BlockType == E_BLOCK_SLIME_BLOCK); } /* If the block is solid, and the blockhandler confirms the block to be inside, we're officially on the ground. */ - if ((cBlockInfo::IsSolid(Block)) && (cBlockInfo::GetHandler(Block)->IsInsideBlock(CrossTestPosition - BlockTestPosition, Block, BlockMeta))) + if ((cBlockInfo::IsSolid(BlockType)) && (cBlockInfo::GetHandler(BlockType)->IsInsideBlock(CrossTestPosition - BlockTestPosition, BlockMeta))) { OnGround = true; } diff --git a/src/Items/ItemArmor.h b/src/Items/ItemArmor.h index d218c22b3..d91888d5b 100644 --- a/src/Items/ItemArmor.h +++ b/src/Items/ItemArmor.h @@ -8,43 +8,52 @@ -class cItemArmorHandler : +class cItemArmorHandler: public cItemHandler { + using Super = cItemHandler; + public: - cItemArmorHandler(int a_ItemType) : - cItemHandler(a_ItemType) + + cItemArmorHandler(int a_ItemType): + Super(a_ItemType) { } + + /** Move the armor to the armor slot of the player's inventory */ virtual bool OnItemUse( - cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace + cWorld * a_World, + cPlayer * a_Player, + cBlockPluginInterface & a_PluginInterface, + const cItem & a_HeldItem, + const Vector3i a_ClickedBlockPos, + eBlockFace a_ClickedBlockFace ) override { int SlotNum; - if (ItemCategory::IsHelmet(a_Item.m_ItemType)) + if (ItemCategory::IsHelmet(a_HeldItem.m_ItemType)) { SlotNum = 0; } - else if (ItemCategory::IsChestPlate(a_Item.m_ItemType)) + else if (ItemCategory::IsChestPlate(a_HeldItem.m_ItemType)) { SlotNum = 1; } - else if (ItemCategory::IsLeggings(a_Item.m_ItemType)) + else if (ItemCategory::IsLeggings(a_HeldItem.m_ItemType)) { SlotNum = 2; } - else if (ItemCategory::IsBoots(a_Item.m_ItemType)) + else if (ItemCategory::IsBoots(a_HeldItem.m_ItemType)) { SlotNum = 3; } else { - LOGWARNING("Used unknown armor: %i", a_Item.m_ItemType); + LOGWARNING("Used unknown armor: %i", a_HeldItem.m_ItemType); return false; } @@ -53,9 +62,9 @@ public: return false; } - a_Player->GetInventory().SetArmorSlot(SlotNum, a_Item.CopyOne()); + a_Player->GetInventory().SetArmorSlot(SlotNum, a_HeldItem.CopyOne()); - cItem Item(a_Item); + cItem Item(a_HeldItem); Item.m_ItemCount--; if (Item.m_ItemCount <= 0) { @@ -67,6 +76,8 @@ public: + + virtual bool CanRepairWithRawMaterial(short a_ItemType) override { switch (m_ItemType) diff --git a/src/Items/ItemBed.h b/src/Items/ItemBed.h index 0f085d489..9c79a134a 100644 --- a/src/Items/ItemBed.h +++ b/src/Items/ItemBed.h @@ -9,51 +9,60 @@ -class cItemBedHandler : +class cItemBedHandler: public cItemHandler { + using Super = cItemHandler; + public: - cItemBedHandler(int a_ItemType) : - cItemHandler(a_ItemType) + + cItemBedHandler(int a_ItemType): + Super(a_ItemType) { } + + + virtual bool IsPlaceable(void) override { return true; } + + + virtual bool GetBlocksToPlace( - cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + cWorld & a_World, + cPlayer & a_Player, + const cItem & a_EquippedItem, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, sSetBlockVector & a_BlocksToPlace ) override { // Can only be placed on the floor: - if (a_BlockFace != BLOCK_FACE_TOP) + if (a_ClickedBlockFace != BLOCK_FACE_TOP) { return false; } // The "foot" block: NIBBLETYPE BlockMeta = cBlockBedHandler::YawToMetaData(a_Player.GetYaw()); - a_BlocksToPlace.emplace_back(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_BED, BlockMeta); + a_BlocksToPlace.emplace_back(a_PlacedBlockPos, E_BLOCK_BED, BlockMeta); // Check if there is empty space for the "head" block: // (Vanilla only allows beds to be placed into air) - Vector3i Direction = cBlockBedHandler::MetaDataToDirection(BlockMeta); - if (a_World.GetBlock(a_BlockX + Direction.x, a_BlockY, a_BlockZ + Direction.z) != E_BLOCK_AIR) + auto Direction = cBlockBedHandler::MetaDataToDirection(BlockMeta); + auto HeadPos = a_PlacedBlockPos + Direction; + if (a_World.GetBlock(HeadPos) != E_BLOCK_AIR) { return false; } - a_BlocksToPlace.emplace_back(a_BlockX + Direction.x, a_BlockY, a_BlockZ + Direction.z, E_BLOCK_BED, BlockMeta | 0x08); + a_BlocksToPlace.emplace_back(HeadPos, E_BLOCK_BED, BlockMeta | 0x08); return true; } -} ; - - - - +}; diff --git a/src/Items/ItemBigFlower.h b/src/Items/ItemBigFlower.h index 81a9d3818..a126a72bc 100644 --- a/src/Items/ItemBigFlower.h +++ b/src/Items/ItemBigFlower.h @@ -15,43 +15,50 @@ class cItemBigFlowerHandler: public: - cItemBigFlowerHandler(void): + cItemBigFlowerHandler(): Super(E_BLOCK_BIG_FLOWER) { } + + + virtual bool GetBlocksToPlace( - cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, - sSetBlockVector & a_BlocksToSet + cWorld & a_World, + cPlayer & a_Player, + const cItem & a_EquippedItem, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, + sSetBlockVector & a_BlocksToPlace ) override { // Can only be placed on dirt: - if ((a_BlockY <= 0) || !IsBlockTypeOfDirt(a_World.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ))) + if ((a_PlacedBlockPos.y <= 0) || !IsBlockTypeOfDirt(a_World.GetBlock(a_PlacedBlockPos.addedY(-1)))) { return false; } // Needs at least two free blocks to build in - if (a_BlockY >= cChunkDef::Height - 1) + if (a_PlacedBlockPos.y >= cChunkDef::Height - 1) { return false; } + auto TopPos = a_PlacedBlockPos.addedY(1); BLOCKTYPE TopType; NIBBLETYPE TopMeta; - a_World.GetBlockTypeMeta(a_BlockX, a_BlockY + 1, a_BlockZ, TopType, TopMeta); + a_World.GetBlockTypeMeta(TopPos, TopType, TopMeta); cChunkInterface ChunkInterface(a_World.GetChunkMap()); - if (!BlockHandler(TopType)->DoesIgnoreBuildCollision(ChunkInterface, { a_BlockX, a_BlockY + 1, a_BlockZ }, a_Player, TopMeta)) + if (!BlockHandler(TopType)->DoesIgnoreBuildCollision(ChunkInterface, TopPos, 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); + a_BlocksToPlace.emplace_back(a_PlacedBlockPos, E_BLOCK_BIG_FLOWER, a_EquippedItem.m_ItemDamage & 0x07); + a_BlocksToPlace.emplace_back(TopPos, E_BLOCK_BIG_FLOWER, E_META_BIG_FLOWER_TOP); return true; } }; diff --git a/src/Items/ItemBoat.h b/src/Items/ItemBoat.h index 682b68ff2..b6af554c5 100644 --- a/src/Items/ItemBoat.h +++ b/src/Items/ItemBoat.h @@ -22,24 +22,32 @@ public: + + virtual bool OnItemUse( - cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace + cWorld * a_World, + cPlayer * a_Player, + cBlockPluginInterface & a_PluginInterface, + const cItem & a_HeldItem, + const Vector3i a_ClickedBlockPos, + eBlockFace a_ClickedBlockFace ) override { - if ((a_BlockFace != BLOCK_FACE_YM) && (a_BlockFace != BLOCK_FACE_NONE)) + // Only allow placing blocks on top of blocks, or when not in range of dest block: + if ((a_ClickedBlockFace != BLOCK_FACE_YM) && (a_ClickedBlockFace != BLOCK_FACE_NONE)) { return false; } - class cCallbacks : + // Find the actual placement position by tracing line of sight until non-air block: + class cCallbacks: public cBlockTracer::cCallbacks { public: Vector3d m_Pos; bool m_HasFound; - cCallbacks(void) : + cCallbacks(): m_HasFound(false) { } @@ -55,27 +63,21 @@ public: return false; } } Callbacks; - - cLineBlockTracer Tracer(*a_World, Callbacks); - Vector3d Start(a_Player->GetEyePosition() + a_Player->GetLookVector()); - Vector3d End(a_Player->GetEyePosition() + a_Player->GetLookVector() * 5); - - Tracer.Trace(Start.x, Start.y, Start.z, End.x, End.y, End.z); - + auto Start = a_Player->GetEyePosition() + a_Player->GetLookVector(); + auto End = a_Player->GetEyePosition() + a_Player->GetLookVector() * 5; + cLineBlockTracer::Trace(*a_World, Callbacks, Start, End); if (!Callbacks.m_HasFound) { return false; } - auto x = Callbacks.m_Pos.x; - auto y = Callbacks.m_Pos.y; - auto z = Callbacks.m_Pos.z; - auto bx = FloorC(x); - auto by = FloorC(y); - auto bz = FloorC(z); - // Block above must be air to spawn a boat (prevents spawning a boat underwater) - BLOCKTYPE BlockAbove = a_World->GetBlock(bx, by + 1, bz); + auto PosAbove = Callbacks.m_Pos.Floor().addedY(1); + if (!cChunkDef::IsValidHeight(PosAbove.y)) + { + return false; + } + BLOCKTYPE BlockAbove = a_World->GetBlock(PosAbove); if (BlockAbove != E_BLOCK_AIR) { return false; diff --git a/src/Items/ItemBottle.h b/src/Items/ItemBottle.h index 319bc708f..2f4d8f93f 100644 --- a/src/Items/ItemBottle.h +++ b/src/Items/ItemBottle.h @@ -9,19 +9,28 @@ -class cItemBottleHandler : +class cItemBottleHandler: public cItemHandler { + using Super = cItemHandler; + public: - cItemBottleHandler() : - cItemHandler(E_ITEM_GLASS_BOTTLE) + + cItemBottleHandler(): + Super(E_ITEM_GLASS_BOTTLE) { } + + + + /** Searches for a water source block in the line of sight. + Returns true and sets a_BlockPos if a water source block is found within line-of-sight. + Returns false if not. */ bool GetBlockFromTrace(cWorld * a_World, cPlayer * a_Player, Vector3i & a_BlockPos) { - class cCallbacks : + class cCallbacks: public cBlockTracer::cCallbacks { public: @@ -29,7 +38,7 @@ public: bool m_HasHitFluid; - cCallbacks(void) : + cCallbacks(): m_HasHitFluid(false) { } @@ -49,31 +58,32 @@ public: return false; } } Callbacks; - - cLineBlockTracer Tracer(*a_World, Callbacks); - Vector3d Start(a_Player->GetEyePosition() + a_Player->GetLookVector()); - Vector3d End(a_Player->GetEyePosition() + a_Player->GetLookVector() * 5); - - Tracer.Trace(Start.x, Start.y, Start.z, End.x, End.y, End.z); - + auto Start = a_Player->GetEyePosition() + a_Player->GetLookVector(); + auto End = a_Player->GetEyePosition() + a_Player->GetLookVector() * 5; + cLineBlockTracer::Trace(*a_World, Callbacks, Start, End); if (!Callbacks.m_HasHitFluid) { return false; } - a_BlockPos = Callbacks.m_Pos; return true; } + + virtual bool OnItemUse( - cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace - ) override + cWorld * a_World, + cPlayer * a_Player, + cBlockPluginInterface & a_PluginInterface, + const cItem & a_HeldItem, + const Vector3i a_ClickedBlockPos, + eBlockFace a_ClickedBlockFace + ) override { - if (a_BlockFace != BLOCK_FACE_NONE) + if (a_ClickedBlockFace != BLOCK_FACE_NONE) { return false; } diff --git a/src/Items/ItemBow.h b/src/Items/ItemBow.h index 81f012c7c..b7a9ef638 100644 --- a/src/Items/ItemBow.h +++ b/src/Items/ItemBow.h @@ -22,9 +22,15 @@ public: + + virtual bool OnItemUse( - cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace + cWorld * a_World, + cPlayer * a_Player, + cBlockPluginInterface & a_PluginInterface, + const cItem & a_HeldItem, + const Vector3i a_ClickedBlockPos, + eBlockFace a_ClickedBlockFace ) override { ASSERT(a_Player != nullptr); @@ -41,9 +47,10 @@ public: - virtual void OnItemShoot(cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override + virtual void OnItemShoot(cPlayer * a_Player, const Vector3i a_BlockPos, eBlockFace a_BlockFace) override { - // Actual shot - produce the arrow with speed based on the ticks that the bow was charged + // Actual shot - produce the arrow with speed based on the number of ticks that the bow was charged + UNUSED(a_BlockPos); ASSERT(a_Player != nullptr); int BowCharge = a_Player->FinishChargingBow(); @@ -88,7 +95,6 @@ public: a_Player->UseEquippedItem(); } - if (a_Player->GetEquippedItem().m_Enchantments.GetLevel(cEnchantments::enchFlame) > 0) { ArrowPtr->StartBurning(100); diff --git a/src/Items/ItemBrewingStand.h b/src/Items/ItemBrewingStand.h index 7be57763c..fdf53ff8f 100644 --- a/src/Items/ItemBrewingStand.h +++ b/src/Items/ItemBrewingStand.h @@ -7,12 +7,15 @@ -class cItemBrewingStandHandler : +class cItemBrewingStandHandler: public cItemHandler { + using Super = cItemHandler; + public: - cItemBrewingStandHandler(int a_ItemType) : - cItemHandler(a_ItemType) + + cItemBrewingStandHandler(int a_ItemType): + Super(a_ItemType) { } @@ -25,8 +28,9 @@ public: virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { diff --git a/src/Items/ItemBucket.h b/src/Items/ItemBucket.h index 7b837d449..d2a9b1884 100644 --- a/src/Items/ItemBucket.h +++ b/src/Items/ItemBucket.h @@ -16,25 +16,34 @@ class cItemBucketHandler : public cItemHandler { + using Super = cItemHandler; + public: - cItemBucketHandler(int a_ItemType) : - cItemHandler(a_ItemType) + + cItemBucketHandler(int a_ItemType): + Super(a_ItemType) { } + + virtual bool OnItemUse( - cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace + cWorld * a_World, + cPlayer * a_Player, + cBlockPluginInterface & a_PluginInterface, + const cItem & a_HeldItem, + const Vector3i a_ClickedBlockPos, + eBlockFace a_ClickedBlockFace ) override { switch (m_ItemType) { - case E_ITEM_BUCKET: return ScoopUpFluid(a_World, a_Player, a_Item, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); - case E_ITEM_LAVA_BUCKET: return PlaceFluid (a_World, a_Player, a_PluginInterface, a_Item, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, E_BLOCK_LAVA); - case E_ITEM_WATER_BUCKET: return PlaceFluid (a_World, a_Player, a_PluginInterface, a_Item, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, E_BLOCK_WATER); + case E_ITEM_BUCKET: return ScoopUpFluid(a_World, a_Player, a_HeldItem, a_ClickedBlockPos, a_ClickedBlockFace); + case E_ITEM_LAVA_BUCKET: return PlaceFluid (a_World, a_Player, a_PluginInterface, a_HeldItem, a_ClickedBlockPos, a_ClickedBlockFace, E_BLOCK_LAVA); + case E_ITEM_WATER_BUCKET: return PlaceFluid (a_World, a_Player, a_PluginInterface, a_HeldItem, a_ClickedBlockPos, a_ClickedBlockFace, E_BLOCK_WATER); default: { ASSERT(!"Unhandled ItemType"); @@ -45,7 +54,9 @@ public: - bool ScoopUpFluid(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) + + + bool ScoopUpFluid(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, const Vector3i a_ClickedBlockPos, eBlockFace a_ClickedBlockFace) { // Players can't pick up fluid while in adventure mode. if (a_Player->IsGameModeAdventure()) @@ -53,7 +64,8 @@ public: return false; } - if (a_BlockFace != BLOCK_FACE_NONE) + // Needs a valid clicked block: + if (a_ClickedBlockFace != BLOCK_FACE_NONE) { return false; } @@ -114,7 +126,7 @@ public: bool PlaceFluid( cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, BLOCKTYPE a_FluidBlock + const Vector3i a_BlockPos, eBlockFace a_BlockFace, BLOCKTYPE a_FluidBlock ) { // Players can't place fluid while in adventure mode. @@ -219,6 +231,8 @@ public: + + bool GetPlacementCoordsFromTrace(cWorld * a_World, cPlayer * a_Player, Vector3i & a_BlockPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta, eBlockFace & a_BlockFace) { class cCallbacks : diff --git a/src/Items/ItemCake.h b/src/Items/ItemCake.h index d1cb091b6..5751853f6 100644 --- a/src/Items/ItemCake.h +++ b/src/Items/ItemCake.h @@ -7,12 +7,15 @@ -class cItemCakeHandler : +class cItemCakeHandler: public cItemHandler { + using Super = cItemHandler; + public: - cItemCakeHandler(int a_ItemType) : - cItemHandler(a_ItemType) + + cItemCakeHandler(int a_ItemType): + Super(a_ItemType) { } @@ -25,8 +28,9 @@ public: virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { diff --git a/src/Items/ItemCauldron.h b/src/Items/ItemCauldron.h index 9617c30ef..7f2ccdeac 100644 --- a/src/Items/ItemCauldron.h +++ b/src/Items/ItemCauldron.h @@ -7,12 +7,15 @@ -class cItemCauldronHandler : +class cItemCauldronHandler: public cItemHandler { + using Super = cItemHandler; + public: - cItemCauldronHandler(int a_ItemType) : - cItemHandler(a_ItemType) + + cItemCauldronHandler(int a_ItemType): + Super(a_ItemType) { } @@ -25,8 +28,9 @@ public: virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { diff --git a/src/Items/ItemChest.h b/src/Items/ItemChest.h index b8807e5d8..014ccc3e6 100644 --- a/src/Items/ItemChest.h +++ b/src/Items/ItemChest.h @@ -25,56 +25,57 @@ public: /** We need an OnPlayerPlace override because we're processing neighbor chests and changing their metas, the parent class cannot do that. */ virtual bool OnPlayerPlace( - cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ + cWorld & a_World, + cPlayer & a_Player, + const cItem & a_EquippedItem, + const Vector3i a_ClickedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos ) override { - if (a_BlockFace < 0) + if (a_ClickedBlockFace < 0) { // Clicked in air return false; } - if ((a_BlockY < 0) || (a_BlockY >= cChunkDef::Height)) + if (!cChunkDef::IsValidHeight(a_ClickedBlockPos.y)) { // The clicked block is outside the world, ignore this call altogether (#128) return false; } // Check if the block ignores build collision (water, grass etc.): - BLOCKTYPE clickedBlock; - NIBBLETYPE clickedBlockMeta; - Vector3i blockPos(a_BlockX, a_BlockY, a_BlockZ); - a_World.GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, clickedBlock, clickedBlockMeta); + BLOCKTYPE ClickedBlockType; + NIBBLETYPE ClickedBlockMeta; + a_World.GetBlockTypeMeta(a_ClickedBlockPos, ClickedBlockType, ClickedBlockMeta); cChunkInterface ChunkInterface(a_World.GetChunkMap()); - auto blockHandler = BlockHandler(clickedBlock); - if (blockHandler->DoesIgnoreBuildCollision(ChunkInterface, blockPos, a_Player, clickedBlockMeta)) + auto blockHandler = BlockHandler(ClickedBlockType); + Vector3i PlacePos; + if (blockHandler->DoesIgnoreBuildCollision(ChunkInterface, a_ClickedBlockPos, a_Player, ClickedBlockMeta)) { - blockHandler->OnPlayerBreakingBlock(ChunkInterface, a_World, a_Player, blockPos); + blockHandler->OnPlayerBreakingBlock(ChunkInterface, a_World, a_Player, a_ClickedBlockPos); + PlacePos = a_ClickedBlockPos; } else { - AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); - - if ((a_BlockY < 0) || (a_BlockY >= cChunkDef::Height)) + PlacePos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace); + if (!cChunkDef::IsValidHeight(PlacePos.y)) { // The block is being placed outside the world, ignore this packet altogether (#128) return false; } - NIBBLETYPE PlaceMeta; + // Check if the chest can overwrite the block at PlacePos: BLOCKTYPE PlaceBlock; - a_World.GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, PlaceBlock, PlaceMeta); - - // 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->DoesIgnoreBuildCollision(ChunkInterface, blockPos, a_Player, clickedBlockMeta)) + NIBBLETYPE PlaceMeta; + a_World.GetBlockTypeMeta(PlacePos, PlaceBlock, PlaceMeta); + blockHandler = BlockHandler(PlaceBlock); + if (!blockHandler->DoesIgnoreBuildCollision(ChunkInterface, PlacePos, 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 return false; } + blockHandler->OnPlayerBreakingBlock(ChunkInterface, a_World, a_Player, PlacePos); } // Check that there is at most one single neighbor of the same chest type: @@ -88,7 +89,8 @@ public: int NeighborIdx = -1; for (size_t i = 0; i < ARRAYCOUNT(CrossCoords); i++) { - if (a_World.GetBlock(a_BlockX + CrossCoords[i].x, a_BlockY, a_BlockZ + CrossCoords[i].z) != m_ItemType) + auto NeighborPos = PlacePos + CrossCoords[i]; + if (a_World.GetBlock(NeighborPos) != m_ItemType) { continue; } @@ -100,12 +102,11 @@ public: NeighborIdx = static_cast<int>(i); // Check that this neighbor is a single chest: - int bx = a_BlockX + CrossCoords[i].x; - int bz = a_BlockZ + CrossCoords[i].z; for (size_t j = 0; j < ARRAYCOUNT(CrossCoords); j++) { - if (a_World.GetBlock(bx + CrossCoords[j].x, a_BlockY, bz + CrossCoords[j].z) == m_ItemType) + if (a_World.GetBlock(NeighborPos + CrossCoords[j]) == m_ItemType) { + // Trying to place next to a dblchest return false; } } // for j @@ -133,13 +134,14 @@ public: } default: { + // No neighbor, place based on yaw: Meta = cBlockChestHandler::PlayerYawToMetaData(yaw); break; } } // switch (NeighborIdx) // Place the new chest: - if (!a_Player.PlaceBlock(a_BlockX, a_BlockY, a_BlockZ, ChestBlockType, Meta)) + if (!a_Player.PlaceBlock(PlacePos.x, PlacePos.y, PlacePos.z, ChestBlockType, Meta)) { return false; } @@ -147,10 +149,10 @@ public: // Adjust the existing chest, if any: if (NeighborIdx != -1) { - a_World.FastSetBlock(a_BlockX + CrossCoords[NeighborIdx].x, a_BlockY, a_BlockZ + CrossCoords[NeighborIdx].z, ChestBlockType, Meta); + a_World.FastSetBlock(PlacePos + CrossCoords[NeighborIdx], ChestBlockType, Meta); } - // Remove the "placed" item: + // Remove the "placed" item from inventory: if (a_Player.IsGameModeSurvival()) { a_Player.GetInventory().RemoveOneEquippedItem(); diff --git a/src/Items/ItemComparator.h b/src/Items/ItemComparator.h index 6f32e229d..fbb61b317 100644 --- a/src/Items/ItemComparator.h +++ b/src/Items/ItemComparator.h @@ -8,24 +8,36 @@ -class cItemComparatorHandler : +class cItemComparatorHandler: public cItemHandler { + using Super = cItemHandler; + public: - cItemComparatorHandler(int a_ItemType) : + + cItemComparatorHandler(int a_ItemType): cItemHandler(a_ItemType) { } + + + + virtual bool IsPlaceable(void) override { return true; } + + + + virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { diff --git a/src/Items/ItemDoor.h b/src/Items/ItemDoor.h index 790e08ffc..aec6bc0fe 100644 --- a/src/Items/ItemDoor.h +++ b/src/Items/ItemDoor.h @@ -9,38 +9,45 @@ -class cItemDoorHandler : +class cItemDoorHandler: public cItemHandler { + using Super = cItemHandler; + public: - cItemDoorHandler(int a_ItemType) : - cItemHandler(a_ItemType) + + cItemDoorHandler(int a_ItemType): + Super(a_ItemType) { } + + virtual bool GetBlocksToPlace( cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, sSetBlockVector & a_BlocksToSet ) override { // Vanilla only allows door placement while clicking on the top face of the block below the door: - if (a_BlockFace != BLOCK_FACE_TOP) + if (a_ClickedBlockFace != BLOCK_FACE_TOP) { return false; } // Door (bottom block) can be placed in Y range of [1, 254]: - if ((a_BlockY < 1) || (a_BlockY >= cChunkDef::Height - 2)) + if ((a_PlacedBlockPos.y < 1) || (a_PlacedBlockPos.y >= cChunkDef::Height - 2)) { return false; } // The door needs a compatible block below it: - if (!cBlockDoorHandler::CanBeOn(a_World.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ), a_World.GetBlockMeta(a_BlockX, a_BlockY - 1, a_BlockZ))) + auto BelowPos = a_PlacedBlockPos.addedY(-1); + if (!cBlockDoorHandler::CanBeOn(a_World.GetBlock(BelowPos), a_World.GetBlockMeta(BelowPos))) { return false; } @@ -64,8 +71,9 @@ public: } // Check the two blocks that will get replaced by the door: - BLOCKTYPE LowerBlockType = a_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ); - BLOCKTYPE UpperBlockType = a_World.GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ); + auto UpperBlockPos = a_PlacedBlockPos.addedY(1); + BLOCKTYPE LowerBlockType = a_World.GetBlock(a_PlacedBlockPos); + BLOCKTYPE UpperBlockType = a_World.GetBlock(UpperBlockPos); if ( !cBlockDoorHandler::CanReplaceBlock(LowerBlockType) || !cBlockDoorHandler::CanReplaceBlock(UpperBlockType)) @@ -78,10 +86,10 @@ public: Vector3i RelDirToOutside = cBlockDoorHandler::GetRelativeDirectionToOutside(LowerBlockMeta); Vector3i LeftNeighborPos = RelDirToOutside; LeftNeighborPos.TurnCW(); - LeftNeighborPos.Move(a_BlockX, a_BlockY, a_BlockZ); + LeftNeighborPos.Move(a_PlacedBlockPos); Vector3i RightNeighborPos = RelDirToOutside; RightNeighborPos.TurnCCW(); - RightNeighborPos.Move(a_BlockX, a_BlockY, a_BlockZ); + RightNeighborPos.Move(a_PlacedBlockPos); // Decide whether the hinge is on the left (default) or on the right: NIBBLETYPE UpperBlockMeta = 0x08; @@ -89,7 +97,7 @@ public: BLOCKTYPE RightNeighborBlock = a_World.GetBlock(RightNeighborPos); /* // DEBUG: - FLOGD("Door being placed at {0}", Vector3i{a_BlockX, a_BlockY, a_BlockZ}); + FLOGD("Door being placed at {0}", a_PlacedBlockPos); FLOGD("RelDirToOutside: {0}", RelDirToOutside); FLOGD("Left neighbor at {0}: {1} ({2})", LeftNeighborPos, LeftNeighborBlock, ItemTypeToString(LeftNeighborBlock)); FLOGD("Right neighbor at {0}: {1} ({2})", RightNeighborPos, RightNeighborBlock, ItemTypeToString(RightNeighborBlock)); @@ -108,12 +116,14 @@ public: } // Set the blocks: - a_BlocksToSet.emplace_back(a_BlockX, a_BlockY, a_BlockZ, BlockType, LowerBlockMeta); - a_BlocksToSet.emplace_back(a_BlockX, a_BlockY + 1, a_BlockZ, BlockType, UpperBlockMeta); + a_BlocksToSet.emplace_back(a_PlacedBlockPos, BlockType, LowerBlockMeta); + a_BlocksToSet.emplace_back(UpperBlockPos, BlockType, UpperBlockMeta); return true; } + + virtual bool IsPlaceable(void) override { return true; diff --git a/src/Items/ItemDye.h b/src/Items/ItemDye.h index 890fcc9db..5e3088541 100644 --- a/src/Items/ItemDye.h +++ b/src/Items/ItemDye.h @@ -26,14 +26,18 @@ public: virtual bool OnItemUse( - cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace + cWorld * a_World, + cPlayer * a_Player, + cBlockPluginInterface & a_PluginInterface, + const cItem & a_HeldItem, + const Vector3i a_ClickedBlockPos, + eBlockFace a_ClickedBlockFace ) override { - if ((a_Item.m_ItemDamage == E_META_DYE_WHITE) && (a_BlockFace != BLOCK_FACE_NONE)) + if ((a_HeldItem.m_ItemDamage == E_META_DYE_WHITE) && (a_ClickedBlockFace != BLOCK_FACE_NONE)) { // Bonemeal (white dye) is used to fertilize plants: - if (fertilizePlant(*a_World, {a_BlockX, a_BlockY, a_BlockZ})) + if (FertilizePlant(*a_World, a_ClickedBlockPos)) { if (a_Player->IsGameModeSurvival()) { @@ -42,7 +46,7 @@ public: } } } - else if ((a_Item.m_ItemDamage == E_META_DYE_BROWN) && (a_BlockFace >= BLOCK_FACE_ZM) && (a_BlockFace <= BLOCK_FACE_XP)) + else if ((a_HeldItem.m_ItemDamage == E_META_DYE_BROWN) && (a_ClickedBlockFace >= BLOCK_FACE_ZM) && (a_ClickedBlockFace <= BLOCK_FACE_XP)) { // Players can't place blocks while in adventure mode. if (a_Player->IsGameModeAdventure()) @@ -53,25 +57,24 @@ public: // Cocoa (brown dye) can be planted on jungle logs: BLOCKTYPE BlockType; NIBBLETYPE BlockMeta; - a_World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta); + a_World->GetBlockTypeMeta(a_ClickedBlockPos, BlockType, BlockMeta); // Check if the block that the player clicked is a jungle log. - if ((BlockType != E_BLOCK_LOG) || ((BlockMeta & 0x3) != E_META_LOG_JUNGLE)) + if ((BlockType != E_BLOCK_LOG) || ((BlockMeta & 0x03) != E_META_LOG_JUNGLE)) { return false; } // Get the location from the new cocoa pod. - AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, false); - BlockMeta = cBlockCocoaPodHandler::BlockFaceToMeta(a_BlockFace); + auto CocoaPos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace, false); + BlockMeta = cBlockCocoaPodHandler::BlockFaceToMeta(a_ClickedBlockFace); - if (a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) != E_BLOCK_AIR) + // Place the cocoa pod: + if (a_World->GetBlock(CocoaPos) != E_BLOCK_AIR) { return false; } - - // Place the cocoa pod: - if (a_Player->PlaceBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_COCOA_POD, BlockMeta)) + if (a_Player->PlaceBlock(CocoaPos.x, CocoaPos.y, CocoaPos.z, E_BLOCK_COCOA_POD, BlockMeta)) { if (a_Player->IsGameModeSurvival()) { @@ -97,7 +100,7 @@ public: Returns true if the plant was fertilized successfully, false if not / not a plant. Note that successful fertilization doesn't mean successful growth - for blocks that have only a chance to grow, fertilization success is reported even in the case when the chance fails (bonemeal still needs to be consumed). */ - bool fertilizePlant(cWorld & a_World, Vector3i a_BlockPos) + bool FertilizePlant(cWorld & a_World, Vector3i a_BlockPos) { BLOCKTYPE blockType; NIBBLETYPE blockMeta; diff --git a/src/Items/ItemEmptyMap.h b/src/Items/ItemEmptyMap.h index fe7b03e23..ac5053107 100644 --- a/src/Items/ItemEmptyMap.h +++ b/src/Items/ItemEmptyMap.h @@ -23,15 +23,19 @@ public: + + virtual bool OnItemUse( - cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace + cWorld * a_World, + cPlayer * a_Player, + cBlockPluginInterface & a_PluginInterface, + const cItem & a_HeldItem, + const Vector3i a_ClickedBlockPos, + eBlockFace a_ClickedBlockFace ) override { - UNUSED(a_Item); - UNUSED(a_BlockX); - UNUSED(a_BlockZ); - UNUSED(a_BlockFace); + UNUSED(a_HeldItem); + UNUSED(a_ClickedBlockFace); // The map center is fixed at the central point of the 8x8 block of chunks you are standing in when you right-click it. @@ -40,22 +44,14 @@ public: int CenterX = FloorC(a_Player->GetPosX() / RegionWidth) * RegionWidth + (RegionWidth / 2); int CenterZ = FloorC(a_Player->GetPosZ() / RegionWidth) * RegionWidth + (RegionWidth / 2); - cMap * NewMap = a_World->GetMapManager().CreateMap(CenterX, CenterZ, DEFAULT_SCALE); - - // Remove empty map from inventory - if (!a_Player->GetInventory().RemoveOneEquippedItem()) - { - ASSERT(!"Inventory mismatch"); - return true; - } - + auto NewMap = a_World->GetMapManager().CreateMap(CenterX, CenterZ, DEFAULT_SCALE); if (NewMap == nullptr) { return true; } - a_Player->GetInventory().AddItem(cItem(E_ITEM_MAP, 1, static_cast<short>(NewMap->GetID() & 0x7fff))); - + // Replace map in the inventory: + a_Player->ReplaceOneEquippedItemTossRest(cItem(E_ITEM_MAP, 1, static_cast<short>(NewMap->GetID() & 0x7fff))); return true; } } ; diff --git a/src/Items/ItemEyeOfEnder.h b/src/Items/ItemEyeOfEnder.h index f911955a1..3849feb00 100644 --- a/src/Items/ItemEyeOfEnder.h +++ b/src/Items/ItemEyeOfEnder.h @@ -8,46 +8,53 @@ -class cItemEyeOfEnderHandler : +class cItemEyeOfEnderHandler: public cItemThrowableHandler { - typedef cItemThrowableHandler super; + using Super = cItemThrowableHandler; + public: - cItemEyeOfEnderHandler(void) : - super(E_ITEM_EYE_OF_ENDER, cProjectileEntity::pkSnowball, 30) + + cItemEyeOfEnderHandler(): + Super(E_ITEM_EYE_OF_ENDER, cProjectileEntity::pkSnowball, 30) { } + + + + virtual bool OnItemUse( cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace + const Vector3i a_ClickedBlockPos, + eBlockFace a_ClickedBlockFace ) override { - BLOCKTYPE FacingBlock; - NIBBLETYPE FacingMeta; - a_World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, FacingBlock, FacingMeta); - switch (FacingBlock) + // Try to fill an End Portal Frame block: + if (a_ClickedBlockFace != BLOCK_FACE_NONE) { - case E_BLOCK_END_PORTAL_FRAME: + BLOCKTYPE FacingBlock; + NIBBLETYPE FacingMeta; + a_World->GetBlockTypeMeta(a_ClickedBlockPos, FacingBlock, FacingMeta); + if (FacingBlock == E_BLOCK_END_PORTAL_FRAME) { // Fill the portal frame. E_META_END_PORTAL_EYE is the bit for holding the eye of ender. if ((FacingMeta & E_META_END_PORTAL_FRAME_EYE) != E_META_END_PORTAL_FRAME_EYE) { - a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_END_PORTAL_FRAME, FacingMeta | E_META_END_PORTAL_FRAME_EYE); + a_World->SetBlock(a_ClickedBlockPos, E_BLOCK_END_PORTAL_FRAME, FacingMeta | E_META_END_PORTAL_FRAME_EYE); if (!a_Player->IsGameModeCreative()) { a_Player->GetInventory().RemoveOneEquippedItem(); } + return true; } - break; - } - default: - { - // TODO: Create projectile for Eye Of Ender - // return cItemThrowableHandler::OnItemUse(a_World, a_Player, a_PluginInterface, a_Item, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); } + return false; } + // TODO: Create projectile for Eye Of Ender + // return Super::OnItemUse(a_World, a_Player, a_PluginInterface, a_Item, a_ClickedBlockPos, a_ClickedBlockFace); + return false; } diff --git a/src/Items/ItemFishingRod.h b/src/Items/ItemFishingRod.h index 48568ed69..8817c8c38 100644 --- a/src/Items/ItemFishingRod.h +++ b/src/Items/ItemFishingRod.h @@ -63,197 +63,245 @@ public: + + virtual bool OnItemUse( - cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace + cWorld * a_World, + cPlayer * a_Player, + cBlockPluginInterface & a_PluginInterface, + const cItem & a_HeldItem, + const Vector3i a_ClickedBlockPos, + eBlockFace a_ClickedBlockFace ) override { - if (a_BlockFace != BLOCK_FACE_NONE) + if (a_ClickedBlockFace != BLOCK_FACE_NONE) { return false; } - auto & Random = GetRandomProvider(); - if (a_Player->IsFishing()) { - cFloaterCallback FloaterInfo; - a_World->DoWithEntityByID(a_Player->GetFloaterID(), FloaterInfo); - a_Player->SetIsFishing(false); - - if (FloaterInfo.IsAttached()) + ReelIn(*a_World, *a_Player); + } + else + { + // Cast a hook: + auto & Random = GetRandomProvider(); + auto CountDownTime = Random.RandInt(100, 900) - static_cast<int>(a_Player->GetEquippedItem().m_Enchantments.GetLevel(cEnchantments::enchLure) * 100); + auto Floater = cpp14::make_unique<cFloater>( + a_Player->GetEyePosition(), a_Player->GetLookVector() * 15, + a_Player->GetUniqueID(), + CountDownTime + ); + auto FloaterPtr = Floater.get(); + if (!FloaterPtr->Initialize(std::move(Floater), *a_World)) { - a_World->DoWithEntityByID(FloaterInfo.GetAttachedMobID(), [=](cEntity & a_Entity) - { - Vector3d Speed = a_Player->GetPosition() - a_Entity.GetPosition(); - a_Entity.AddSpeed(Speed); - return true; - } - ); - a_Player->UseEquippedItem(5); + return false; } - else if (FloaterInfo.CanPickup()) + a_Player->SetIsFishing(true, FloaterPtr->GetUniqueID()); + } + return true; + } + + + + + + /** Reels back the fishing line, reeling any attached mob, or creating fished loot, or just breaking the fishing rod. */ + void ReelIn(cWorld & a_World, cPlayer & a_Player) + { + cFloaterCallback FloaterInfo; + a_World.DoWithEntityByID(a_Player.GetFloaterID(), FloaterInfo); + a_Player.SetIsFishing(false); + + // If attached to an entity, reel it in: + if (FloaterInfo.IsAttached()) + { + ReelInEntity(a_World, a_Player, FloaterInfo.GetAttachedMobID()); + return; + } + + // If loot can be caught, get it: + if (FloaterInfo.CanPickup()) + { + ReelInLoot(a_World, a_Player, FloaterInfo.GetBitePos()); + return; + } + + // Empty fishing rod, just damage it: + auto BlockType = a_World.GetBlock(FloaterInfo.GetPos() - Vector3d(0, 0.1, 0)); + if ((BlockType != E_BLOCK_AIR) && !IsBlockWater(BlockType)) + { + a_Player.UseEquippedItem(2); + } + } + + + + + /** Reels back the entity, specified by the ID, and damages the fishing rod accordingly. */ + void ReelInEntity(cWorld & a_World, cPlayer & a_Player, UInt32 a_EntityID) + { + auto PlayerPos = a_Player.GetPosition(); + a_World.DoWithEntityByID(a_EntityID, [=](cEntity & a_Entity) { - UInt32 LotSLevel = std::min(a_Player->GetEquippedItem().m_Enchantments.GetLevel(cEnchantments::enchLuckOfTheSea), 3u); + auto Speed = PlayerPos - a_Entity.GetPosition(); + a_Entity.AddSpeed(Speed); + return true; + } + ); + a_Player.UseEquippedItem(5); + } + + + + - // Chances for getting an item from the category for each level of Luck of the Sea (0 - 3) - const int TreasureChances[] = {50, 71, 92, 113}; // 5% | 7.1% | 9.2% | 11.3% - const int JunkChances[] = {100, 81, 61, 42}; // 10% | 8.1% | 6.1% | 4.2% + void ReelInLoot(cWorld & a_World, cPlayer & a_Player, const Vector3d a_FloaterBitePos) + { + auto LotSLevel = std::min(a_Player.GetEquippedItem().m_Enchantments.GetLevel(cEnchantments::enchLuckOfTheSea), 3u); + + // Chances for getting an item from the category for each level of Luck of the Sea (0 - 3) + const int TreasureChances[] = {50, 71, 92, 113}; // 5% | 7.1% | 9.2% | 11.3% + const int JunkChances[] = {100, 81, 61, 42}; // 10% | 8.1% | 6.1% | 4.2% - cItems Drops; - int ItemCategory = Random.RandInt(999); - if (ItemCategory < TreasureChances[LotSLevel]) + cItems Drops; + auto & Random = GetRandomProvider(); + int ItemCategory = Random.RandInt(999); + if (ItemCategory < TreasureChances[LotSLevel]) + { + switch (Random.RandInt(5)) // Each piece of treasure has an equal chance of 1 / 6 + { + case 0: { - switch (Random.RandInt(5)) // Each piece of treasure has an equal chance of 1 / 6 - { - case 0: - { - cItem Bow(E_ITEM_BOW, 1, Random.RandInt<short>(50)); - Bow.EnchantByXPLevels(Random.RandInt(22, 30)); - Drops.Add(Bow); - break; - } - case 1: - { - cItem Book(E_ITEM_BOOK); - Book.EnchantByXPLevels(30); - Drops.Add(Book); - break; - } - case 2: - { - cItem Rod(E_ITEM_FISHING_ROD, 1, Random.RandInt<short>(50)); - Rod.EnchantByXPLevels(Random.RandInt(22, 30)); - Drops.Add(Rod); - break; - } - case 3: - { - Drops.Add(cItem(E_ITEM_NAME_TAG)); - break; - } - case 4: - { - Drops.Add(cItem(E_ITEM_SADDLE)); - break; - } - case 5: - { - Drops.Add(cItem(E_BLOCK_LILY_PAD)); - break; - } - } - - a_Player->GetStatManager().AddValue(statTreasureFished, 1); + cItem Bow(E_ITEM_BOW, 1, Random.RandInt<short>(50)); + Bow.EnchantByXPLevels(Random.RandInt(22, 30)); + Drops.Add(Bow); + break; } - else if (ItemCategory < JunkChances[LotSLevel]) + case 1: { - int Junk = Random.RandInt(82); - if (Junk < 10) // 10 / 83 chance of spawning a bowl - { - Drops.Add(cItem(E_ITEM_BOWL)); - } - else if (Junk < 12) // 2 / 83 chance of spawning a fishing rod - { - // Fishing Rods caught from the Junk category will be 10%-100% damaged, and always unenchanted. - Drops.Add(cItem(E_ITEM_FISHING_ROD, 1, Random.RandInt<short>(7, 65))); - } - else if (Junk < 22) // 10 / 83 chance of spawning leather - { - Drops.Add(cItem(E_ITEM_LEATHER)); - } - else if (Junk < 32) // 10 / 83 chance of spawning leather boots - { - // Leather boots caught from the Junk category will be 10%-100% damaged, and always unenchanted. - Drops.Add(cItem(E_ITEM_LEATHER_BOOTS, 1, Random.RandInt<short>(7, 66))); - } - else if (Junk < 42) // 10 / 83 chance of spawning rotten flesh - { - Drops.Add(cItem(E_ITEM_ROTTEN_FLESH)); - } - else if (Junk < 47) // 5 / 83 chance of spawning a stick - { - Drops.Add(cItem(E_ITEM_STICK)); - } - else if (Junk < 52) // 5 / 83 chance of spawning string - { - Drops.Add(cItem(E_ITEM_STRING)); - } - else if (Junk < 62) // 10 / 83 chance of spawning a water bottle - { - Drops.Add(cItem(E_ITEM_POTION)); - } - else if (Junk < 72) // 10 / 83 chance of spawning a bone - { - Drops.Add(cItem(E_ITEM_BONE)); - } - else if (Junk < 73) // 1 / 83 chance of spawning an ink sac - { - Drops.Add(cItem(E_ITEM_DYE)); - } - else // 10 / 83 chance of spawning a tripwire hook - { - Drops.Add(cItem(E_BLOCK_TRIPWIRE_HOOK)); - } - - a_Player->GetStatManager().AddValue(statJunkFished, 1); + cItem Book(E_ITEM_BOOK); + Book.EnchantByXPLevels(30); + Drops.Add(Book); + break; } - else + case 2: { - int FishType = Random.RandInt(99); - if (FishType <= 1) // Clownfish has a 2% chance of spawning - { - Drops.Add(cItem(E_ITEM_RAW_FISH, 1, E_META_RAW_FISH_CLOWNFISH)); - } - else if (FishType <= 12) // Pufferfish has a 13% chance of spawning - { - Drops.Add(cItem(E_ITEM_RAW_FISH, 1, E_META_RAW_FISH_PUFFERFISH)); - } - else if (FishType <= 24) // Raw salmon has a 25% chance of spawning - { - Drops.Add(cItem(E_ITEM_RAW_FISH, 1, E_META_RAW_FISH_SALMON)); - } - else // Raw fish has a 60% chance of spawning - { - Drops.Add(cItem(E_ITEM_RAW_FISH, 1, E_META_RAW_FISH_FISH)); - } - - a_Player->GetStatManager().AddValue(statFishCaught, 1); + cItem Rod(E_ITEM_FISHING_ROD, 1, Random.RandInt<short>(50)); + Rod.EnchantByXPLevels(Random.RandInt(22, 30)); + Drops.Add(Rod); + break; } - - if (cRoot::Get()->GetPluginManager()->CallHookPlayerFishing(*a_Player, Drops)) + case 3: { - return true; + Drops.Add(cItem(E_ITEM_NAME_TAG)); + break; } - Vector3d FloaterPos = FloaterInfo.GetBitePos(); - FloaterPos.y += 0.5f; - const float FISH_SPEED_MULT = 2.25f; - - Vector3d FlyDirection = (a_Player->GetEyePosition() - FloaterPos).addedY(1.0f) * FISH_SPEED_MULT; - a_World->SpawnItemPickups(Drops, FloaterPos, FlyDirection); - a_World->SpawnExperienceOrb(a_Player->GetPosition(), Random.RandInt(1, 6)); - a_Player->UseEquippedItem(1); - cRoot::Get()->GetPluginManager()->CallHookPlayerFished(*a_Player, Drops); - } - else - { - BLOCKTYPE Block = a_World->GetBlock(FloaterInfo.GetPos() - Vector3d(0, 0.1, 0)); - if ((Block != E_BLOCK_AIR) && !IsBlockWater(Block)) + case 4: + { + Drops.Add(cItem(E_ITEM_SADDLE)); + break; + } + case 5: { - a_Player->UseEquippedItem(2); + Drops.Add(cItem(E_BLOCK_LILY_PAD)); + break; } } + + a_Player.GetStatManager().AddValue(statTreasureFished, 1); + } + else if (ItemCategory < JunkChances[LotSLevel]) + { + int Junk = Random.RandInt(82); + if (Junk < 10) // 10 / 83 chance of spawning a bowl + { + Drops.Add(cItem(E_ITEM_BOWL)); + } + else if (Junk < 12) // 2 / 83 chance of spawning a fishing rod + { + // Fishing Rods caught from the Junk category will be 10% .. 100% damaged, and always unenchanted. + Drops.Add(cItem(E_ITEM_FISHING_ROD, 1, Random.RandInt<short>(7, 65))); + } + else if (Junk < 22) // 10 / 83 chance of spawning leather + { + Drops.Add(cItem(E_ITEM_LEATHER)); + } + else if (Junk < 32) // 10 / 83 chance of spawning leather boots + { + // Leather boots caught from the Junk category will be 10% .. 100% damaged, and always unenchanted. + Drops.Add(cItem(E_ITEM_LEATHER_BOOTS, 1, Random.RandInt<short>(7, 66))); + } + else if (Junk < 42) // 10 / 83 chance of spawning rotten flesh + { + Drops.Add(cItem(E_ITEM_ROTTEN_FLESH)); + } + else if (Junk < 47) // 5 / 83 chance of spawning a stick + { + Drops.Add(cItem(E_ITEM_STICK)); + } + else if (Junk < 52) // 5 / 83 chance of spawning string + { + Drops.Add(cItem(E_ITEM_STRING)); + } + else if (Junk < 62) // 10 / 83 chance of spawning a water bottle + { + Drops.Add(cItem(E_ITEM_POTION)); + } + else if (Junk < 72) // 10 / 83 chance of spawning a bone + { + Drops.Add(cItem(E_ITEM_BONE)); + } + else if (Junk < 73) // 1 / 83 chance of spawning an ink sac + { + Drops.Add(cItem(E_ITEM_DYE)); + } + else // 10 / 83 chance of spawning a tripwire hook + { + Drops.Add(cItem(E_BLOCK_TRIPWIRE_HOOK)); + } + + a_Player.GetStatManager().AddValue(statJunkFished, 1); } else { - auto Floater = cpp14::make_unique<cFloater>(a_Player->GetEyePosition(), a_Player->GetLookVector() * 15, a_Player->GetUniqueID(), (Random.RandInt(100, 900) - static_cast<int>(a_Player->GetEquippedItem().m_Enchantments.GetLevel(cEnchantments::enchLure) * 100))); - auto FloaterPtr = Floater.get(); - if (!FloaterPtr->Initialize(std::move(Floater), *a_World)) + int FishType = Random.RandInt(99); + if (FishType <= 1) // Clownfish has a 2% chance of spawning { - return false; + Drops.Add(cItem(E_ITEM_RAW_FISH, 1, E_META_RAW_FISH_CLOWNFISH)); } - a_Player->SetIsFishing(true, FloaterPtr->GetUniqueID()); + else if (FishType <= 12) // Pufferfish has a 13% chance of spawning + { + Drops.Add(cItem(E_ITEM_RAW_FISH, 1, E_META_RAW_FISH_PUFFERFISH)); + } + else if (FishType <= 24) // Raw salmon has a 25% chance of spawning + { + Drops.Add(cItem(E_ITEM_RAW_FISH, 1, E_META_RAW_FISH_SALMON)); + } + else // Raw fish has a 60% chance of spawning + { + Drops.Add(cItem(E_ITEM_RAW_FISH, 1, E_META_RAW_FISH_FISH)); + } + + a_Player.GetStatManager().AddValue(statFishCaught, 1); } - return true; + + // Check with plugins if this loot is acceptable: + if (cRoot::Get()->GetPluginManager()->CallHookPlayerFishing(a_Player, Drops)) + { + return; + } + + // Spawn the loot and the experience orb: + auto FloaterPos = a_FloaterBitePos.addedY(0.5); + const float FISH_SPEED_MULT = 2.25f; + Vector3d FlyDirection = (a_Player.GetEyePosition() - FloaterPos).addedY(1.0f) * FISH_SPEED_MULT; + a_World.SpawnItemPickups(Drops, FloaterPos, FlyDirection); + a_World.SpawnExperienceOrb(a_Player.GetPosition(), Random.RandInt(1, 6)); + a_Player.UseEquippedItem(1); + + // Notify plugins + cRoot::Get()->GetPluginManager()->CallHookPlayerFished(a_Player, Drops); } } ; diff --git a/src/Items/ItemFlowerPot.h b/src/Items/ItemFlowerPot.h index 320dce997..655633785 100644 --- a/src/Items/ItemFlowerPot.h +++ b/src/Items/ItemFlowerPot.h @@ -7,26 +7,36 @@ -class cItemFlowerPotHandler : +class cItemFlowerPotHandler: public cItemHandler { + using Super = cItemHandler; + public: - cItemFlowerPotHandler(int a_ItemType) : - cItemHandler(a_ItemType) + + cItemFlowerPotHandler(int a_ItemType): + Super(a_ItemType) { } + + + virtual bool IsPlaceable(void) override { return true; } + + + virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { diff --git a/src/Items/ItemHandler.cpp b/src/Items/ItemHandler.cpp index 807be9393..c014ba794 100644 --- a/src/Items/ItemHandler.cpp +++ b/src/Items/ItemHandler.cpp @@ -346,41 +346,44 @@ cItemHandler::cItemHandler(int a_ItemType) bool cItemHandler::OnPlayerPlace( - cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ + cWorld & a_World, + cPlayer & a_Player, + const cItem & a_EquippedItem, + const Vector3i a_ClickedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos ) { - if (a_BlockFace < 0) + if (a_ClickedBlockFace == BLOCK_FACE_NONE) { - // Clicked in air + // Clicked in the air, no placement possible return false; } - if ((a_BlockY < 0) || (a_BlockY >= cChunkDef::Height)) + if (!cChunkDef::IsValidHeight(a_ClickedBlockPos.y)) { // The clicked block is outside the world, ignore this call altogether (#128) return false; } - BLOCKTYPE ClickedBlock; + BLOCKTYPE ClickedBlockType; NIBBLETYPE ClickedBlockMeta; - a_World.GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, ClickedBlock, ClickedBlockMeta); + a_World.GetBlockTypeMeta(a_ClickedBlockPos, ClickedBlockType, ClickedBlockMeta); cChunkInterface ChunkInterface(a_World.GetChunkMap()); // Check if the block ignores build collision (water, grass etc.): - auto blockHandler = BlockHandler(ClickedBlock); - Vector3i absPos(a_BlockX, a_BlockY, a_BlockZ); - if (blockHandler->DoesIgnoreBuildCollision(ChunkInterface, absPos, a_Player, ClickedBlockMeta)) + auto HandlerB = BlockHandler(ClickedBlockType); + auto PlacedBlockPos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace); + if (HandlerB->DoesIgnoreBuildCollision(ChunkInterface, a_ClickedBlockPos, a_Player, ClickedBlockMeta)) { - a_World.DropBlockAsPickups(absPos, &a_Player, nullptr); + // Replace the clicked block: + a_World.DropBlockAsPickups(a_ClickedBlockPos, &a_Player, nullptr); + PlacedBlockPos = a_ClickedBlockPos; } else { - AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); - - if ((a_BlockY < 0) || (a_BlockY >= cChunkDef::Height)) + if (!cChunkDef::IsValidHeight(PlacedBlockPos.y)) { // The block is being placed outside the world, ignore this packet altogether (#128) return false; @@ -388,11 +391,11 @@ bool cItemHandler::OnPlayerPlace( NIBBLETYPE PlaceMeta; BLOCKTYPE PlaceBlock; - a_World.GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, PlaceBlock, PlaceMeta); + a_World.GetBlockTypeMeta(PlacedBlockPos, PlaceBlock, PlaceMeta); // 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(ChunkInterface, { a_BlockX, a_BlockY, a_BlockZ }, a_Player, PlaceMeta)) + if (!BlockHandler(PlaceBlock)->DoesIgnoreBuildCollision(ChunkInterface, PlacedBlockPos, 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 @@ -402,14 +405,15 @@ bool cItemHandler::OnPlayerPlace( // Get all the blocks to place: sSetBlockVector blocks; - if (!GetBlocksToPlace(a_World, a_Player, a_EquippedItem, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, blocks)) + if (!GetBlocksToPlace(a_World, a_Player, a_EquippedItem, PlacedBlockPos, a_ClickedBlockFace, a_CursorPos, blocks)) { // Handler refused the placement, send that information back to the client: for (const auto & blk: blocks) { - a_World.SendBlockTo(blk.GetX(), blk.GetY(), blk.GetZ(), a_Player); + const auto & AbsPos = blk.GetAbsolutePos(); + a_World.SendBlockTo(AbsPos, a_Player); } - a_World.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player); + a_World.SendBlockTo(PlacedBlockPos, a_Player); a_Player.GetInventory().SendEquippedSlot(); return false; } @@ -436,18 +440,19 @@ bool cItemHandler::OnPlayerPlace( bool cItemHandler::GetBlocksToPlace( cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, sSetBlockVector & a_BlocksToSet ) { BLOCKTYPE BlockType; NIBBLETYPE BlockMeta; - if (!GetPlacementBlockTypeMeta(&a_World, &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta)) + if (!GetPlacementBlockTypeMeta(&a_World, &a_Player, a_PlacedBlockPos, a_ClickedBlockFace, a_CursorPos, BlockType, BlockMeta)) { return false; } - a_BlocksToSet.emplace_back(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta); + a_BlocksToSet.emplace_back(a_PlacedBlockPos, BlockType, BlockMeta); return true; } @@ -457,17 +462,15 @@ bool cItemHandler::GetBlocksToPlace( bool cItemHandler::OnItemUse( cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace + const Vector3i a_ClickedBlockPos, eBlockFace a_ClickedBlockFace ) { UNUSED(a_World); UNUSED(a_Player); UNUSED(a_PluginInterface); UNUSED(a_Item); - UNUSED(a_BlockX); - UNUSED(a_BlockY); - UNUSED(a_BlockZ); - UNUSED(a_BlockFace); + UNUSED(a_ClickedBlockPos); + UNUSED(a_ClickedBlockFace); return false; } @@ -476,15 +479,19 @@ bool cItemHandler::OnItemUse( -bool cItemHandler::OnDiggingBlock(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir) +bool cItemHandler::OnDiggingBlock( + cWorld * a_World, + cPlayer * a_Player, + const cItem & a_HeldItem, + const Vector3i a_ClickedBlockPos, + eBlockFace a_ClickedBlockFace +) { UNUSED(a_World); UNUSED(a_Player); - UNUSED(a_Item); - UNUSED(a_BlockX); - UNUSED(a_BlockY); - UNUSED(a_BlockZ); - UNUSED(a_Dir); + UNUSED(a_HeldItem); + UNUSED(a_ClickedBlockPos); + UNUSED(a_ClickedBlockFace); return false; } @@ -815,8 +822,8 @@ bool cItemHandler::CanHarvestBlock(BLOCKTYPE a_BlockType) bool cItemHandler::GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + const Vector3i a_PlacedBlockPos, eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) { @@ -832,8 +839,8 @@ bool cItemHandler::GetPlacementBlockTypeMeta( cChunkInterface ChunkInterface(a_World->GetChunkMap()); return BlockH->GetPlacementBlockTypeMeta( ChunkInterface, *a_Player, - a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, - a_CursorX, a_CursorY, a_CursorZ, + a_PlacedBlockPos, a_ClickedBlockFace, + a_CursorPos, a_BlockType, a_BlockMeta ); } diff --git a/src/Items/ItemHandler.h b/src/Items/ItemHandler.h index ea0684dd1..74de4eaa5 100644 --- a/src/Items/ItemHandler.h +++ b/src/Items/ItemHandler.h @@ -38,28 +38,39 @@ public: /** Called when the player tries to place the item (right mouse button, IsPlaceable() == true). - The block coords are for the block that has been clicked. + a_ClickedBlockPos is the (neighbor) block that has been clicked to place this item. + a_ClickedBlockFace is the face of the neighbor that has been clicked to place this item. + a_CursorPos is the position of the player's cursor within a_ClickedBlockFace. The default handler uses GetBlocksToPlace() and places the returned blocks. Override if the item needs advanced processing, such as spawning a mob based on the blocks being placed. If the block placement is refused inside this call, it will automatically revert the client-side changes. Returns true if the placement succeeded, false if the placement was aborted for any reason. */ virtual bool OnPlayerPlace( - cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ + cWorld & a_World, + cPlayer & a_Player, + const cItem & a_EquippedItem, + const Vector3i a_ClickedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos ); /** Called from OnPlayerPlace() to determine the blocks that the current placement operation should set. - The block coords are where the new (main) block should be placed. + a_PlacedBlockPos points to the location where the new block should be set. + a_ClickedBlockFace is the block face of the neighbor that was clicked to place this block. + a_CursorPos is the position of the mouse cursor within the clicked (neighbor's) block face. + The blocks in a_BlocksToPlace will be sent through cPlayer::PlaceBlocks() after returning from this function. The default handler uses GetPlacementBlockTypeMeta() and provides that as the single block at the specified coords. Returns true if the placement succeeded, false if the placement was aborted for any reason. If aborted, the server then sends all original blocks in the coords provided in a_BlocksToSet to the client. */ virtual bool GetBlocksToPlace( - cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, - sSetBlockVector & a_BlocksToSet + cWorld & a_World, + cPlayer & a_Player, + const cItem & a_EquippedItem, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, + sSetBlockVector & a_BlocksToPlace ); @@ -68,26 +79,29 @@ public: Returns true to allow placement, false to refuse. */ virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ); /** Called when the player tries to use the item (right mouse button). - Return false to abort the usage. DEFAULT: False */ + Descendants can return false to abort the usage (default behavior). */ virtual bool OnItemUse( - cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace + cWorld * a_World, + cPlayer * a_Player, + cBlockPluginInterface & a_PluginInterface, + const cItem & a_HeldItem, + const Vector3i a_ClickedBlockPos, + eBlockFace a_ClickedBlockFace ); - /** Called when the client sends the SHOOT status in the lclk packet */ - virtual void OnItemShoot(cPlayer *, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) + /** Called when the client sends the SHOOT status in the lclk packet (releasing the bow). */ + virtual void OnItemShoot(cPlayer *, const Vector3i a_BlockPos, eBlockFace a_BlockFace) { - UNUSED(a_BlockX); - UNUSED(a_BlockY); - UNUSED(a_BlockZ); + UNUSED(a_BlockPos); UNUSED(a_BlockFace); } @@ -100,9 +114,13 @@ public: } /** Called while the player digs a block using this item */ - virtual bool OnDiggingBlock(cWorld * a_World, cPlayer * a_Player, const cItem & a_HeldItem, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace); + virtual bool OnDiggingBlock( + cWorld * a_World, cPlayer * a_Player, const cItem & a_HeldItem, + const Vector3i a_ClickedBlockPos, + eBlockFace a_ClickedBlockFace + ); - /** Called when a player attacks a other entity. */ + /** Called when a player attacks an entity with this item in hand. */ virtual void OnEntityAttack(cPlayer * a_Attacker, cEntity * a_AttackedEntity); /** Called after the player has eaten this item. */ diff --git a/src/Items/ItemHoe.h b/src/Items/ItemHoe.h index a0bf44a93..b33ab6b90 100644 --- a/src/Items/ItemHoe.h +++ b/src/Items/ItemHoe.h @@ -9,64 +9,68 @@ -class cItemHoeHandler : +class cItemHoeHandler: public cItemHandler { + using Super = cItemHandler; + public: - cItemHoeHandler(int a_ItemType) - : cItemHandler(a_ItemType) + + cItemHoeHandler(int a_ItemType): + Super(a_ItemType) { } + + virtual bool OnItemUse( - cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace + cWorld * a_World, + cPlayer * a_Player, + cBlockPluginInterface & a_PluginInterface, + const cItem & a_HeldItem, + const Vector3i a_ClickedBlockPos, + eBlockFace a_ClickedBlockFace ) override { - if ((a_BlockFace == BLOCK_FACE_NONE) || (a_BlockY >= cChunkDef::Height)) + if ((a_ClickedBlockFace == BLOCK_FACE_NONE) || (a_ClickedBlockPos.y >= cChunkDef::Height)) { return false; } - BLOCKTYPE UpperBlock = a_World->GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ); - BLOCKTYPE Block; - NIBBLETYPE BlockMeta; - a_World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, Block, BlockMeta); + // Need air above the hoe-d block to transform it: + BLOCKTYPE UpperBlockType = a_World->GetBlock(a_ClickedBlockPos.addedY(1)); + if (UpperBlockType != E_BLOCK_AIR) + { + return false; + } - if (((Block == E_BLOCK_DIRT) || (Block == E_BLOCK_GRASS)) && (UpperBlock == E_BLOCK_AIR)) + // Can only transform dirt or grass blocks: + BLOCKTYPE BlockType; + NIBBLETYPE BlockMeta; + a_World->GetBlockTypeMeta(a_ClickedBlockPos, BlockType, BlockMeta); + if ((BlockType != E_BLOCK_DIRT) && (BlockType != E_BLOCK_GRASS)) + { + return false; + } + if ((BlockType == E_BLOCK_DIRT) && (BlockMeta == E_META_DIRT_PODZOL)) { - BLOCKTYPE NewBlock = E_BLOCK_FARMLAND; - if (Block == E_BLOCK_DIRT) - { - switch (BlockMeta) - { - case E_META_DIRT_COARSE: - { - // Transform to normal dirt - NewBlock = E_BLOCK_DIRT; - break; - } - case E_META_DIRT_PODZOL: - { - // You can't transform this block with a hoe in vanilla - return false; - } - default: break; - } - } - - a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, NewBlock, 0); - a_World->BroadcastSoundEffect("item.hoe.till", {a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5}, 1.0f, 0.8f); - a_Player->UseEquippedItem(); - return true; + return false; } - return false; + // Transform: + auto NewBlockType = ((BlockType == E_BLOCK_DIRT) && (BlockMeta == E_META_DIRT_COARSE)) ? E_BLOCK_DIRT : E_BLOCK_FARMLAND; + a_World->SetBlock(a_ClickedBlockPos, NewBlockType, 0); + a_World->BroadcastSoundEffect("item.hoe.till", a_ClickedBlockPos + Vector3d(0.5, 0.5, 0.5), 1.0f, 0.8f); + a_Player->UseEquippedItem(); + return true; } + + + virtual short GetDurabilityLossByAction(eDurabilityLostAction a_Action) override { switch (a_Action) diff --git a/src/Items/ItemItemFrame.h b/src/Items/ItemItemFrame.h index 7845701fe..bcc325701 100644 --- a/src/Items/ItemItemFrame.h +++ b/src/Items/ItemItemFrame.h @@ -9,51 +9,59 @@ -class cItemItemFrameHandler : +class cItemItemFrameHandler: public cItemHandler { + using Super = cItemHandler; + public: - cItemItemFrameHandler(int a_ItemType) - : cItemHandler(a_ItemType) - { + cItemItemFrameHandler(int a_ItemType): + Super(a_ItemType) + { } + + virtual bool OnItemUse( - cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace + cWorld * a_World, + cPlayer * a_Player, + cBlockPluginInterface & a_PluginInterface, + const cItem & a_HeldItem, + const Vector3i a_ClickedBlockPos, + eBlockFace a_ClickedBlockFace ) override { - if ((a_BlockFace == BLOCK_FACE_NONE) || (a_BlockFace == BLOCK_FACE_YP) || (a_BlockFace == BLOCK_FACE_YM)) + // Can only place on a side face: + if ((a_ClickedBlockFace == BLOCK_FACE_NONE) || (a_ClickedBlockFace == BLOCK_FACE_YP) || (a_ClickedBlockFace == BLOCK_FACE_YM)) { - // Client sends this if clicked on top or bottom face return false; } - AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); // Make sure block that will be occupied is free - BLOCKTYPE Block = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ); - AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, true); // We want the clicked block, so go back again - - if (Block == E_BLOCK_AIR) + // Make sure block that will be occupied by the item frame is free now: + auto PlacePos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace); + BLOCKTYPE Block = a_World->GetBlock(PlacePos); + if (Block != E_BLOCK_AIR) { - auto ItemFrame = cpp14::make_unique<cItemFrame>(a_BlockFace, Vector3i{a_BlockX, a_BlockY, a_BlockZ}); - auto ItemFramePtr = ItemFrame.get(); - if (!ItemFramePtr->Initialize(std::move(ItemFrame), *a_World)) - { - return false; - } - - if (!a_Player->IsGameModeCreative()) - { - a_Player->GetInventory().RemoveOneEquippedItem(); - } + return false; + } - return true; + // Place the item frame: + auto ItemFrame = cpp14::make_unique<cItemFrame>(a_ClickedBlockFace, a_ClickedBlockPos); + auto ItemFramePtr = ItemFrame.get(); + if (!ItemFramePtr->Initialize(std::move(ItemFrame), *a_World)) + { + return false; + } + if (!a_Player->IsGameModeCreative()) + { + a_Player->GetInventory().RemoveOneEquippedItem(); } - return false; + + return true; } }; diff --git a/src/Items/ItemLeaves.h b/src/Items/ItemLeaves.h index 59cc1429d..0233ed6a6 100644 --- a/src/Items/ItemLeaves.h +++ b/src/Items/ItemLeaves.h @@ -19,17 +19,23 @@ public: { } + + + + virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { bool res = Super::GetPlacementBlockTypeMeta( a_World, a_Player, - a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, - a_CursorX, a_CursorY, a_CursorZ, + a_PlacedBlockPos, + a_ClickedBlockFace, + a_CursorPos, a_BlockType, a_BlockMeta ); a_BlockMeta = a_BlockMeta | 0x4; // 0x4 bit set means this is a player-placed leaves block, not to be decayed diff --git a/src/Items/ItemLighter.h b/src/Items/ItemLighter.h index 241e0511e..d4469a31b 100644 --- a/src/Items/ItemLighter.h +++ b/src/Items/ItemLighter.h @@ -9,23 +9,32 @@ -class cItemLighterHandler : +class cItemLighterHandler: public cItemHandler { + using Super = cItemHandler; + public: - cItemLighterHandler(int a_ItemType) : - cItemHandler(a_ItemType) + + cItemLighterHandler(int a_ItemType): + Super(a_ItemType) { } + + virtual bool OnItemUse( - cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace + cWorld * a_World, + cPlayer * a_Player, + cBlockPluginInterface & a_PluginInterface, + const cItem & a_HeldItem, + const Vector3i a_ClickedBlockPos, + eBlockFace a_ClickedBlockFace ) override { - if (a_BlockFace < 0) + if (a_ClickedBlockFace < 0) { return false; } @@ -51,27 +60,27 @@ public: } } - switch (a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ)) + switch (a_World->GetBlock(a_ClickedBlockPos)) { case E_BLOCK_TNT: { // Activate the TNT: - a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0); - a_World->SpawnPrimedTNT({a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5}); // 80 ticks to boom + a_World->SetBlock(a_ClickedBlockPos, E_BLOCK_AIR, 0); + a_World->SpawnPrimedTNT(Vector3d(a_ClickedBlockPos) + Vector3d(0.5, 0.5, 0.5)); // 80 ticks to boom break; } default: { // Light a fire next to / on top of the block if air: - AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); - if ((a_BlockY < 0) || (a_BlockY >= cChunkDef::Height)) + auto FirePos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace); + if (!cChunkDef::IsValidHeight(FirePos.y)) { break; } - if (a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_AIR) + if (a_World->GetBlock(FirePos) == E_BLOCK_AIR) { - a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_FIRE, 0); - a_World->BroadcastSoundEffect("item.flintandsteel.use", Vector3d(a_BlockX, a_BlockY, a_BlockZ), 1.0F, 1.04F); + a_World->SetBlock(FirePos, E_BLOCK_FIRE, 0); + a_World->BroadcastSoundEffect("item.flintandsteel.use", FirePos, 1.0f, 1.04f); break; } } diff --git a/src/Items/ItemLilypad.h b/src/Items/ItemLilypad.h index 985da3ed5..1190e817b 100644 --- a/src/Items/ItemLilypad.h +++ b/src/Items/ItemLilypad.h @@ -23,6 +23,9 @@ public: } + + + virtual bool IsPlaceable(void) override { return false; // Set as not placeable so OnItemUse is called @@ -30,16 +33,22 @@ public: + + virtual bool OnItemUse( - cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace + cWorld * a_World, + cPlayer * a_Player, + cBlockPluginInterface & a_PluginInterface, + const cItem & a_HeldItem, + const Vector3i a_ClickedBlockPos, + eBlockFace a_ClickedBlockFace ) override { - if (a_BlockFace > BLOCK_FACE_NONE) + if (a_ClickedBlockFace > BLOCK_FACE_NONE) { - // Clicked on the side of a submerged block; vanilla allows placement, so should we - AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); - a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_LILY_PAD, 0); + // Clicked on a face of a submerged block; vanilla allows placement, so should we + auto PlacePos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace); + a_World->SetBlock(PlacePos, E_BLOCK_LILY_PAD, 0); if (!a_Player->IsGameModeCreative()) { a_Player->GetInventory().RemoveOneEquippedItem(); @@ -47,12 +56,12 @@ public: return true; } - class cCallbacks : + class cCallbacks: public cBlockTracer::cCallbacks { public: - cCallbacks(void) : + cCallbacks(): m_HasHitFluid(false) { } @@ -84,18 +93,14 @@ public: Vector3i m_Pos; bool m_HasHitFluid; - }; - - cCallbacks Callbacks; - cLineBlockTracer Tracer(*a_Player->GetWorld(), Callbacks); - Vector3d Start(a_Player->GetEyePosition() + a_Player->GetLookVector()); - Vector3d End(a_Player->GetEyePosition() + a_Player->GetLookVector() * 5); - - Tracer.Trace(Start.x, Start.y, Start.z, End.x, End.y, End.z); + } 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.x, Start.y, Start.z, End.x, End.y, End.z); if (Callbacks.m_HasHitFluid) { - a_World->SetBlock(Callbacks.m_Pos.x, Callbacks.m_Pos.y, Callbacks.m_Pos.z, E_BLOCK_LILY_PAD, 0); + a_World->SetBlock(Callbacks.m_Pos, E_BLOCK_LILY_PAD, 0); if (!a_Player->IsGameModeCreative()) { a_Player->GetInventory().RemoveOneEquippedItem(); diff --git a/src/Items/ItemMinecart.h b/src/Items/ItemMinecart.h index 603d3f9c5..d108c2ca8 100644 --- a/src/Items/ItemMinecart.h +++ b/src/Items/ItemMinecart.h @@ -1,8 +1,6 @@ #pragma once -#include "../Entities/Minecart.h" - @@ -21,18 +19,25 @@ public: + + virtual bool OnItemUse( - cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace + cWorld * a_World, + cPlayer * a_Player, + cBlockPluginInterface & a_PluginInterface, + const cItem & a_HeldItem, + const Vector3i a_ClickedBlockPos, + eBlockFace a_ClickedBlockFace ) override { - if (a_BlockFace < 0) + // Must be used on a block + if (a_ClickedBlockFace < 0) { return false; } // Check that there's rail in there: - BLOCKTYPE Block = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ); + BLOCKTYPE Block = a_World->GetBlock(a_ClickedBlockPos); switch (Block) { case E_BLOCK_MINECART_TRACKS: @@ -50,15 +55,14 @@ public: } } - double x = static_cast<double>(a_BlockX) + 0.5; - double y = static_cast<double>(a_BlockY) + 0.5; - double z = static_cast<double>(a_BlockZ) + 0.5; - - if (a_World->SpawnMinecart(x, y, z, m_ItemType) == cEntity::INVALID_ID) + // Spawn the minecart: + auto SpawnPos = Vector3d(a_ClickedBlockPos) + Vector3d(0.5, 0.5, 0.5); + if (a_World->SpawnMinecart(SpawnPos, m_ItemType) == cEntity::INVALID_ID) { return false; } + // Remove the item from inventory: if (!a_Player->IsGameModeCreative()) { a_Player->GetInventory().RemoveOneEquippedItem(); diff --git a/src/Items/ItemMobHead.h b/src/Items/ItemMobHead.h index d732327a5..036893c15 100644 --- a/src/Items/ItemMobHead.h +++ b/src/Items/ItemMobHead.h @@ -22,52 +22,60 @@ public: } + + + virtual bool OnPlayerPlace( - cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ + cWorld & a_World, + cPlayer & a_Player, + const cItem & a_EquippedItem, + const Vector3i a_ClickedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos ) override { // Cannot place a head at "no face" and from the bottom: - if ((a_BlockFace == BLOCK_FACE_NONE) || (a_BlockFace == BLOCK_FACE_BOTTOM)) + if ((a_ClickedBlockFace == BLOCK_FACE_NONE) || (a_ClickedBlockFace == BLOCK_FACE_BOTTOM)) { return true; } - auto placedX = a_BlockX, placedY = a_BlockY, placedZ = a_BlockZ; - AddFaceDirection(placedY, placedY, placedZ, a_BlockFace); + const auto PlacePos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace); // If the placed head is a wither, try to spawn the wither first: if (a_EquippedItem.m_ItemDamage == E_META_HEAD_WITHER) { - if (TrySpawnWitherAround(a_World, a_Player, {placedX, placedY, placedZ})) + if (TrySpawnWitherAround(a_World, a_Player, PlacePos)) { return true; } // Wither not created, proceed with regular head placement } - cItem itemCopy(a_EquippedItem); // Make a copy in case this is the player's last head item and OnPlayerPlace removes it - if (!Super::OnPlayerPlace(a_World, a_Player, a_EquippedItem, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ)) + cItem ItemCopy(a_EquippedItem); // Make a copy in case this is the player's last head item and OnPlayerPlace removes it + if (!Super::OnPlayerPlace(a_World, a_Player, a_EquippedItem, a_ClickedBlockPos, a_ClickedBlockFace, a_CursorPos)) { return false; } - RegularHeadPlaced(a_World, a_Player, itemCopy, placedX, placedY, placedZ, a_BlockFace); + RegularHeadPlaced(a_World, a_Player, ItemCopy, PlacePos, a_ClickedBlockFace); return true; } + + + /** Called after placing a regular head block with no mob spawning. Adjusts the mob head entity based on the equipped item's data. */ void RegularHeadPlaced( cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace + const Vector3i a_PlacePos, eBlockFace a_ClickedBlockFace ) { auto HeadType = static_cast<eMobHeadType>(a_EquippedItem.m_ItemDamage); - auto BlockMeta = static_cast<NIBBLETYPE>(a_BlockFace); + auto BlockMeta = static_cast<NIBBLETYPE>(a_ClickedBlockFace); // Use a callback to set the properties of the mob head block entity: - a_World.DoWithBlockEntityAt(a_BlockX, a_BlockY, a_BlockZ, [&](cBlockEntity & a_BlockEntity) + a_World.DoWithBlockEntityAt(a_PlacePos.x, a_PlacePos.y, a_PlacePos.z, [&](cBlockEntity & a_BlockEntity) { if (a_BlockEntity.GetBlockType() != E_BLOCK_HEAD) { @@ -90,11 +98,14 @@ public: } + + + /** Spawns a wither if the wither skull placed at the specified coords completes wither's spawning formula. Returns true if the wither was created. */ bool TrySpawnWitherAround( cWorld & a_World, cPlayer & a_Player, - Vector3i a_BlockPos + const Vector3i a_BlockPos ) { // No wither can be created at Y < 2 - not enough space for the formula: @@ -183,6 +194,9 @@ public: } + + + /** Tries to spawn a wither from the specified image at the specified offset from the placed head block. PlacedHead coords are used to override the block query - at those coords the block is not queried from the world, but assumed to be a head instead. @@ -265,6 +279,9 @@ public: } + + + /** Awards the achievement to all players close to the specified point. */ void AwardSpawnWitherAchievement(cWorld & a_World, Vector3i a_BlockPos) { @@ -283,6 +300,9 @@ public: } + + + /** Converts the block face of the placement (which face of the block was clicked to place the head) into the block's metadata value. */ static NIBBLETYPE BlockFaceToBlockMeta(int a_BlockFace) @@ -303,21 +323,28 @@ public: } + + + virtual bool IsPlaceable(void) override { return true; } + + + virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { a_BlockType = E_BLOCK_HEAD; - a_BlockMeta = BlockFaceToBlockMeta(a_BlockFace); + a_BlockMeta = BlockFaceToBlockMeta(a_ClickedBlockFace); return true; } } ; diff --git a/src/Items/ItemNetherWart.h b/src/Items/ItemNetherWart.h index 3586231b3..462ea61f9 100644 --- a/src/Items/ItemNetherWart.h +++ b/src/Items/ItemNetherWart.h @@ -8,47 +8,53 @@ -class cItemNetherWartHandler : +class cItemNetherWartHandler: public cItemHandler { + using Super = cItemHandler; + public: - cItemNetherWartHandler(int a_ItemType) : - cItemHandler(a_ItemType) - { + cItemNetherWartHandler(int a_ItemType): + Super(a_ItemType) + { } + + + + virtual bool IsPlaceable(void) override { return true; } + + + + virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { - if (a_BlockFace != BLOCK_FACE_TOP) + // Only allow planting nether wart onto the top side of the block: + if (a_ClickedBlockFace != BLOCK_FACE_TOP) { - // Only allow planting nether wart from the top side of the block return false; } - // Only allow placement on farmland - int X = a_BlockX; - int Y = a_BlockY; - int Z = a_BlockZ; - AddFaceDirection(X, Y, Z, a_BlockFace, true); - if (a_World->GetBlock(X, Y, Z) != E_BLOCK_SOULSAND) + // Only allow placement on soulsand + if ((a_PlacedBlockPos.y < 1) || (a_World->GetBlock(a_PlacedBlockPos.addedY(-1)) != E_BLOCK_SOULSAND)) { return false; } a_BlockMeta = 0; a_BlockType = E_BLOCK_NETHER_WART; - return true; } } ; diff --git a/src/Items/ItemPainting.h b/src/Items/ItemPainting.h index f9fa0a601..cc1d02ac4 100644 --- a/src/Items/ItemPainting.h +++ b/src/Items/ItemPainting.h @@ -10,82 +10,93 @@ -class cItemPaintingHandler : +class cItemPaintingHandler: public cItemHandler { + using Super = cItemHandler; + public: - cItemPaintingHandler(int a_ItemType) - : cItemHandler(a_ItemType) + + cItemPaintingHandler(int a_ItemType): + Super(a_ItemType) { } + + virtual bool OnItemUse( - cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace + cWorld * a_World, + cPlayer * a_Player, + cBlockPluginInterface & a_PluginInterface, + const cItem & a_HeldItem, + const Vector3i a_ClickedBlockPos, + eBlockFace a_ClickedBlockFace ) override { - if ((a_BlockFace == BLOCK_FACE_NONE) || (a_BlockFace == BLOCK_FACE_YM) || (a_BlockFace == BLOCK_FACE_YP)) + // Paintings can't be flatly placed: + if ( + (a_ClickedBlockFace == BLOCK_FACE_NONE) || + (a_ClickedBlockFace == BLOCK_FACE_YM) || + (a_ClickedBlockFace == BLOCK_FACE_YP) + ) { - // Paintings can't be flatly placed return false; } - AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); // Make sure block that will be occupied is free - BLOCKTYPE Block = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ); + // Make sure block that will be occupied is free: + auto PlacePos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace); + BLOCKTYPE PlaceBlockType = a_World->GetBlock(PlacePos); + if (PlaceBlockType != E_BLOCK_AIR) + { + return false; + } - if (Block == E_BLOCK_AIR) + // Define all the possible painting titles + static const AString gPaintingTitlesList[] = + { + { "Kebab" }, + { "Aztec" }, + { "Alban" }, + { "Aztec2" }, + { "Bomb" }, + { "Plant" }, + { "Wasteland" }, + { "Wanderer" }, + { "Graham" }, + { "Pool" }, + { "Courbet" }, + { "Sunset" }, + { "Sea" }, + { "Creebet" }, + { "Match" }, + { "Bust" }, + { "Stage" }, + { "Void" }, + { "SkullAndRoses" }, + { "Wither" }, + { "Fighters" }, + { "Skeleton" }, + { "DonkeyKong" }, + { "Pointer" }, + { "Pigscene" }, + { "BurningSkull" } + }; + + auto PaintingTitle = gPaintingTitlesList[a_World->GetTickRandomNumber(ARRAYCOUNT(gPaintingTitlesList) - 1)]; + auto Painting = cpp14::make_unique<cPainting>(PaintingTitle, a_ClickedBlockFace, PlacePos); + auto PaintingPtr = Painting.get(); + if (!PaintingPtr->Initialize(std::move(Painting), *a_World)) { - static const struct // Define all the possible painting titles - { - AString Title; - } gPaintingTitlesList[] = - { - { "Kebab" }, - { "Aztec" }, - { "Alban" }, - { "Aztec2" }, - { "Bomb" }, - { "Plant" }, - { "Wasteland" }, - { "Wanderer" }, - { "Graham" }, - { "Pool" }, - { "Courbet" }, - { "Sunset" }, - { "Sea" }, - { "Creebet" }, - { "Match" }, - { "Bust" }, - { "Stage" }, - { "Void" }, - { "SkullAndRoses" }, - { "Wither" }, - { "Fighters" }, - { "Skeleton" }, - { "DonkeyKong" }, - { "Pointer" }, - { "Pigscene" }, - { "BurningSkull" } - }; - - auto Painting = cpp14::make_unique<cPainting>(gPaintingTitlesList[a_World->GetTickRandomNumber(ARRAYCOUNT(gPaintingTitlesList) - 1)].Title, a_BlockFace, Vector3i{a_BlockX, a_BlockY, a_BlockZ}); - auto PaintingPtr = Painting.get(); - if (!PaintingPtr->Initialize(std::move(Painting), *a_World)) - { - return false; - } - - if (!a_Player->IsGameModeCreative()) - { - a_Player->GetInventory().RemoveOneEquippedItem(); - } - - return true; + return false; + } + if (!a_Player->IsGameModeCreative()) + { + a_Player->GetInventory().RemoveOneEquippedItem(); } - return false; + return true; } }; diff --git a/src/Items/ItemPotion.h b/src/Items/ItemPotion.h index 49fbfa0dd..875fbec02 100644 --- a/src/Items/ItemPotion.h +++ b/src/Items/ItemPotion.h @@ -17,6 +17,9 @@ public: } + + + // cItemHandler overrides: virtual bool IsDrinkable(short a_ItemDamage) override { @@ -26,12 +29,19 @@ public: } + + + virtual bool OnItemUse( - cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace + cWorld * a_World, + cPlayer * a_Player, + cBlockPluginInterface & a_PluginInterface, + const cItem & a_HeldItem, + const Vector3i a_ClickedBlockPos, + eBlockFace a_ClickedBlockFace ) override { - short PotionDamage = a_Item.m_ItemDamage; + short PotionDamage = a_HeldItem.m_ItemDamage; // Do not throw non-splash potions: if (cEntityEffect::IsPotionDrinkable(PotionDamage)) @@ -59,6 +69,9 @@ public: } + + + virtual bool EatItem(cPlayer * a_Player, cItem * a_Item) override { short PotionDamage = a_Item->m_ItemDamage; diff --git a/src/Items/ItemPumpkin.h b/src/Items/ItemPumpkin.h index b8038093c..33810b51f 100644 --- a/src/Items/ItemPumpkin.h +++ b/src/Items/ItemPumpkin.h @@ -20,44 +20,50 @@ public: } + + + virtual bool OnPlayerPlace( - cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ + cWorld & a_World, + cPlayer & a_Player, + const cItem & a_EquippedItem, + const Vector3i a_ClickedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos ) override { // First try spawning a snow golem or an iron golem: - int PlacedBlockX = a_BlockX; - int PlacedBlockY = a_BlockY; - int PlacedBlockZ = a_BlockZ; - AddFaceDirection(PlacedBlockX, PlacedBlockY, PlacedBlockZ, a_BlockFace); - if (TrySpawnGolem(a_World, a_Player, PlacedBlockX, PlacedBlockY, PlacedBlockZ)) + auto PlacePos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace); + if (TrySpawnGolem(a_World, a_Player, PlacePos)) { // The client thinks that they placed the pumpkin, let them know it's been replaced: - a_Player.SendBlocksAround(PlacedBlockX, PlacedBlockY, PlacedBlockZ); + a_Player.SendBlocksAround(PlacePos.x, PlacePos.y, PlacePos.z); return true; } // No golem at these coords, place the block normally: - return Super::OnPlayerPlace(a_World, a_Player, a_EquippedItem, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ); + return Super::OnPlayerPlace(a_World, a_Player, a_EquippedItem, a_ClickedBlockPos, a_ClickedBlockFace, a_CursorPos); } + + + /** Spawns a snow / iron golem if the shape matches the recipe, supposing that the block placed at the specified coords is a pumpkin. Returns true if the golem blocks are removed (for spawning), false if the recipe is not matched. */ - bool TrySpawnGolem(cWorld & a_World, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) + bool TrySpawnGolem(cWorld & a_World, cPlayer & a_Player, const Vector3i a_PumpkinPos) { // A golem can't form with a pumpkin below level 2 or above level 255 - if ((a_BlockY < 2) || (a_BlockY >= cChunkDef::Height)) + if ((a_PumpkinPos.y < 2) || (a_PumpkinPos.y >= cChunkDef::Height)) { return false; } // Decide which golem to try spawning based on the block below the placed pumpkin: - switch (a_World.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ)) + switch (a_World.GetBlock(a_PumpkinPos.addedY(-1))) { - case E_BLOCK_SNOW_BLOCK: return TrySpawnSnowGolem(a_World, a_Player, a_BlockX, a_BlockY, a_BlockZ); - case E_BLOCK_IRON_BLOCK: return TrySpawnIronGolem(a_World, a_Player, a_BlockX, a_BlockY, a_BlockZ); + case E_BLOCK_SNOW_BLOCK: return TrySpawnSnowGolem(a_World, a_Player, a_PumpkinPos); + case E_BLOCK_IRON_BLOCK: return TrySpawnIronGolem(a_World, a_Player, a_PumpkinPos); default: { // No golem here @@ -67,45 +73,59 @@ public: } + + + /** Spawns a snow golem if the shape matches the recipe, supposing that the block placed at the specified coords is a pumpkin. Returns true if the golem blocks are removed (for spawning), false if the recipe is not matched. Assumes that the block below the specified block has already been checked and is a snow block. */ - bool TrySpawnSnowGolem(cWorld & a_World, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) + bool TrySpawnSnowGolem(cWorld & a_World, cPlayer & a_Player, const Vector3i a_PumpkinPos) { + ASSERT(a_PumpkinPos.y > 1); + ASSERT(a_World.GetBlock(a_PumpkinPos.addedY(-1)) == E_BLOCK_SNOW); + // Need one more snow block 2 blocks below the pumpkin: - if (a_World.GetBlock(a_BlockX, a_BlockY - 2, a_BlockZ) != E_BLOCK_SNOW_BLOCK) + if (a_World.GetBlock(a_PumpkinPos.addedY(-2)) != E_BLOCK_SNOW_BLOCK) { return false; } // Try to place air blocks where the original recipe blocks were: sSetBlockVector AirBlocks; - AirBlocks.emplace_back(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0); // Head - AirBlocks.emplace_back(a_BlockX, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0); // Torso - AirBlocks.emplace_back(a_BlockX, a_BlockY - 2, a_BlockZ, E_BLOCK_AIR, 0); // Legs + AirBlocks.emplace_back(a_PumpkinPos, E_BLOCK_AIR, 0); // Head + AirBlocks.emplace_back(a_PumpkinPos.addedY(-1), E_BLOCK_AIR, 0); // Torso + AirBlocks.emplace_back(a_PumpkinPos.addedY(-2), E_BLOCK_AIR, 0); // Legs if (!a_Player.PlaceBlocks(AirBlocks)) { return false; } // Spawn the golem: - a_World.SpawnMob(static_cast<double>(a_BlockX) + 0.5, a_BlockY - 2, static_cast<double>(a_BlockZ) + 0.5, mtSnowGolem, false); + auto GolemPos = Vector3d(a_PumpkinPos) + Vector3d(0.5, -2, 0.5); + a_World.SpawnMob(GolemPos.x, GolemPos.y, GolemPos.z, mtSnowGolem, false); return true; } + + + /** Spawns an iron golem if the shape matches the recipe, supposing that the block placed at the specified coords is a pumpkin. Returns true if the golem blocks are removed (for spawning), false if the recipe is not matched. Assumes that the block below the specified block has already been checked and is an iron block. */ - bool TrySpawnIronGolem(cWorld & a_World, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) + bool TrySpawnIronGolem(cWorld & a_World, cPlayer & a_Player, const Vector3i a_PumpkinPos) { + ASSERT(a_PumpkinPos.y > 1); + ASSERT(a_World.GetBlock(a_PumpkinPos.addedY(-1)) == E_BLOCK_IRON_BLOCK); + // Need one more iron block 2 blocks below the pumpkin: - if (a_World.GetBlock(a_BlockX, a_BlockY - 2, a_BlockZ) != E_BLOCK_IRON_BLOCK) + if (a_World.GetBlock(a_PumpkinPos.addedY(-2)) != E_BLOCK_IRON_BLOCK) { return false; } // Check the two arm directions (X, Z) using a loop over two sets of offset vectors: + auto BodyPos = a_PumpkinPos.addedY(-1); static const Vector3i ArmOffsets[] = { {1, 0, 0}, @@ -115,8 +135,8 @@ public: { // If the arm blocks don't match, bail out of this loop repetition: if ( - (a_World.GetBlock(a_BlockX + ArmOffsets[i].x, a_BlockY - 1, a_BlockZ + ArmOffsets[i].z) != E_BLOCK_IRON_BLOCK) || - (a_World.GetBlock(a_BlockX - ArmOffsets[i].x, a_BlockY - 1, a_BlockZ - ArmOffsets[i].z) != E_BLOCK_IRON_BLOCK) + (a_World.GetBlock(BodyPos + ArmOffsets[i]) != E_BLOCK_IRON_BLOCK) || + (a_World.GetBlock(BodyPos - ArmOffsets[i]) != E_BLOCK_IRON_BLOCK) ) { continue; @@ -124,18 +144,19 @@ public: // Try to place air blocks where the original recipe blocks were: sSetBlockVector AirBlocks; - AirBlocks.emplace_back(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0); // Head - AirBlocks.emplace_back(a_BlockX, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0); // Torso - AirBlocks.emplace_back(a_BlockX, a_BlockY - 2, a_BlockZ, E_BLOCK_AIR, 0); // Legs - AirBlocks.emplace_back(a_BlockX + ArmOffsets[i].x, a_BlockY - 1, a_BlockZ + ArmOffsets[i].z, E_BLOCK_AIR, 0); // Arm - AirBlocks.emplace_back(a_BlockX - ArmOffsets[i].x, a_BlockY - 1, a_BlockZ - ArmOffsets[i].z, E_BLOCK_AIR, 0); // Arm + AirBlocks.emplace_back(a_PumpkinPos, E_BLOCK_AIR, 0); // Head + AirBlocks.emplace_back(BodyPos, E_BLOCK_AIR, 0); // Torso + AirBlocks.emplace_back(BodyPos.addedY(-1), E_BLOCK_AIR, 0); // Legs + AirBlocks.emplace_back(BodyPos + ArmOffsets[i], E_BLOCK_AIR, 0); // Arm + AirBlocks.emplace_back(BodyPos - ArmOffsets[i], E_BLOCK_AIR, 0); // Arm if (!a_Player.PlaceBlocks(AirBlocks)) { return false; } // Spawn the golem: - a_World.SpawnMob(static_cast<double>(a_BlockX) + 0.5, a_BlockY - 2, static_cast<double>(a_BlockZ) + 0.5, mtIronGolem, false); + auto GolemPos = Vector3d(a_PumpkinPos) + Vector3d(0.5, -2, 0.5); + a_World.SpawnMob(GolemPos.x, GolemPos.y, GolemPos.z, mtIronGolem, false); return true; } // for i - ArmOffsets[] diff --git a/src/Items/ItemRedstoneDust.h b/src/Items/ItemRedstoneDust.h index 87f351654..559be843d 100644 --- a/src/Items/ItemRedstoneDust.h +++ b/src/Items/ItemRedstoneDust.h @@ -7,36 +7,48 @@ -class cItemRedstoneDustHandler : public cItemHandler +class cItemRedstoneDustHandler: + public cItemHandler { + using Super = cItemHandler; + public: - cItemRedstoneDustHandler(int a_ItemType) - : cItemHandler(a_ItemType) + + cItemRedstoneDustHandler(int a_ItemType): + Super(a_ItemType) { } + + + + virtual bool IsPlaceable(void) override { return true; } + + + + virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { - // Check if coords are out of range: - if ((a_BlockY <= 0) || (a_BlockY >= cChunkDef::Height)) + // Check the block below, if it supports dust on top of it: + auto UnderPos = a_PlacedBlockPos.addedY(-1); + if (UnderPos.y < 0) { return false; } - - // Check the block below, if it supports dust on top of it: BLOCKTYPE BlockType; NIBBLETYPE BlockMeta; - if (!a_World->GetBlockTypeMeta(a_BlockX, a_BlockY - 1, a_BlockZ, BlockType, BlockMeta)) + if (!a_World->GetBlockTypeMeta(UnderPos, BlockType, BlockMeta)) { return false; } @@ -51,6 +63,9 @@ public: } + + + /** Returns true if the specified block type / meta is suitable to have redstone dust on top of it. */ static bool IsBlockTypeUnderSuitable(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { diff --git a/src/Items/ItemRedstoneRepeater.h b/src/Items/ItemRedstoneRepeater.h index 9b0fc1bcc..6b1635609 100644 --- a/src/Items/ItemRedstoneRepeater.h +++ b/src/Items/ItemRedstoneRepeater.h @@ -8,24 +8,36 @@ -class cItemRedstoneRepeaterHandler : +class cItemRedstoneRepeaterHandler: public cItemHandler { + using Super = cItemHandler; + public: - cItemRedstoneRepeaterHandler(int a_ItemType) - : cItemHandler(a_ItemType) + + cItemRedstoneRepeaterHandler(int a_ItemType): + Super(a_ItemType) { } + + + + virtual bool IsPlaceable() override { return true; } + + + + virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { diff --git a/src/Items/ItemSapling.h b/src/Items/ItemSapling.h index e8deb37a9..513f542f6 100644 --- a/src/Items/ItemSapling.h +++ b/src/Items/ItemSapling.h @@ -17,24 +17,29 @@ public: cItemSaplingHandler(int a_ItemType): Super(a_ItemType) { - } + + + + virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { bool res = Super::GetPlacementBlockTypeMeta( a_World, a_Player, - a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, - a_CursorX, a_CursorY, a_CursorZ, + a_PlacedBlockPos, a_ClickedBlockFace, + a_CursorPos, a_BlockType, a_BlockMeta ); - // Only the lowest 3 bits are important - a_BlockMeta = a_BlockMeta & 0x7; + + // Allow only the lowest 3 bits (top bit is for growth): + a_BlockMeta = a_BlockMeta & 0x07; return res; } } ; diff --git a/src/Items/ItemSeeds.h b/src/Items/ItemSeeds.h index 8338d1060..67d90362a 100644 --- a/src/Items/ItemSeeds.h +++ b/src/Items/ItemSeeds.h @@ -8,44 +8,53 @@ -class cItemSeedsHandler : +class cItemSeedsHandler: public cItemHandler { + using Super = cItemHandler; + public: - cItemSeedsHandler(int a_ItemType) : - cItemHandler(a_ItemType) + + cItemSeedsHandler(int a_ItemType): + Super(a_ItemType) { } + + + + virtual bool IsPlaceable(void) override { return true; } + + + + virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { - if (a_BlockFace != BLOCK_FACE_TOP) + // Only allow planting seeds from the top side of the block: + if ((a_ClickedBlockFace != BLOCK_FACE_TOP) || (a_PlacedBlockPos.y <= 0)) { - // Only allow planting seeds from the top side of the block return false; } // Only allow placement on farmland - int X = a_BlockX; - int Y = a_BlockY; - int Z = a_BlockZ; - AddFaceDirection(X, Y, Z, a_BlockFace, true); - if (a_World->GetBlock(X, Y, Z) != E_BLOCK_FARMLAND) + if (a_World->GetBlock(a_PlacedBlockPos.addedY(-1)) != E_BLOCK_FARMLAND) { return false; } + // Get the produce block based on the seed item: a_BlockMeta = 0; switch (m_ItemType) { diff --git a/src/Items/ItemShears.h b/src/Items/ItemShears.h index a100a52a3..140e26c5e 100644 --- a/src/Items/ItemShears.h +++ b/src/Items/ItemShears.h @@ -22,25 +22,33 @@ public: } + + + virtual bool IsTool(void) override { return true; } - virtual bool OnDiggingBlock(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir) override + + + + virtual bool OnDiggingBlock( + cWorld * a_World, + cPlayer * a_Player, + const cItem & a_HeldItem, + const Vector3i a_ClickedBlockPos, + eBlockFace a_ClickedBlockFace + ) override { BLOCKTYPE Block; NIBBLETYPE BlockMeta; - a_World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, Block, BlockMeta); + a_World->GetBlockTypeMeta(a_ClickedBlockPos, Block, BlockMeta); if ((Block == E_BLOCK_LEAVES) || (Block == E_BLOCK_NEW_LEAVES)) { - cItems Drops; - Drops.Add(Block, 1, BlockMeta & 3); - a_World->SpawnItemPickups(Drops, a_BlockX, a_BlockY, a_BlockZ); - - a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0); + a_World->DropBlockAsPickups(a_ClickedBlockPos, a_Player, &a_HeldItem); return true; } @@ -48,6 +56,9 @@ public: } + + + virtual bool CanHarvestBlock(BLOCKTYPE a_BlockType) override { switch (a_BlockType) @@ -63,6 +74,9 @@ public: } + + + virtual short GetDurabilityLossByAction(eDurabilityLostAction a_Action) override { switch (a_Action) @@ -93,5 +107,4 @@ public: return Super::GetBlockBreakingStrength(a_Block); } } - } ; diff --git a/src/Items/ItemSign.h b/src/Items/ItemSign.h index 21acd81ae..cb9136db1 100644 --- a/src/Items/ItemSign.h +++ b/src/Items/ItemSign.h @@ -24,58 +24,68 @@ public: } + + + virtual bool OnPlayerPlace( - cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ + cWorld & a_World, + cPlayer & a_Player, + const cItem & a_EquippedItem, + const Vector3i a_ClickedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos ) override { // Check if placing on something ignoring build collision to edit the correct sign later on: - BLOCKTYPE ClickedBlock; + BLOCKTYPE ClickedBlockType; NIBBLETYPE ClickedBlockMeta; - a_World.GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, ClickedBlock, ClickedBlockMeta); + a_World.GetBlockTypeMeta(a_ClickedBlockPos, ClickedBlockType, ClickedBlockMeta); cChunkInterface ChunkInterface(a_World.GetChunkMap()); - bool isReplacingClickedBlock = BlockHandler(ClickedBlock)->DoesIgnoreBuildCollision(ChunkInterface, { a_BlockX, a_BlockY, a_BlockZ }, a_Player, ClickedBlockMeta); + bool IsReplacingClickedBlock = BlockHandler(ClickedBlockType)->DoesIgnoreBuildCollision(ChunkInterface, a_ClickedBlockPos, 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)) + if (!Super::OnPlayerPlace(a_World, a_Player, a_EquippedItem, a_ClickedBlockPos, a_ClickedBlockFace, a_CursorPos)) { return false; } - // Use isReplacingClickedBlock to make sure we will edit the right sign: - if (!isReplacingClickedBlock) - { - AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); - } + // Use IsReplacingClickedBlock to make sure we will edit the right sign: + auto SignPos = IsReplacingClickedBlock ? a_ClickedBlockPos : AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace); // After successfully placing the sign, open the sign editor for the player: - a_Player.GetClientHandle()->SendEditSign(a_BlockX, a_BlockY, a_BlockZ); + a_Player.GetClientHandle()->SendEditSign(SignPos.x, SignPos.y, SignPos.z); return true; } + + + virtual bool IsPlaceable(void) override { return true; } + + + virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { - if (a_BlockFace == BLOCK_FACE_TOP) + if (a_ClickedBlockFace == BLOCK_FACE_TOP) { a_BlockMeta = cBlockSignPostHandler::RotationToMetaData(a_Player->GetYaw()); a_BlockType = E_BLOCK_SIGN_POST; } else { - a_BlockMeta = cBlockWallSignHandler::DirectionToMetaData(a_BlockFace); + a_BlockMeta = cBlockWallSignHandler::BlockFaceToMetaData(a_ClickedBlockFace); a_BlockType = E_BLOCK_WALLSIGN; } return true; diff --git a/src/Items/ItemSlab.h b/src/Items/ItemSlab.h index 0c7654113..944336f7e 100644 --- a/src/Items/ItemSlab.h +++ b/src/Items/ItemSlab.h @@ -23,47 +23,34 @@ public: } + + + // cItemHandler overrides: virtual bool OnPlayerPlace( - cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ + cWorld & a_World, + cPlayer & a_Player, + const cItem & a_EquippedItem, + const Vector3i a_ClickedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos ) override { - // Special slab handling - placing a slab onto another slab produces a dblslab instead: + // If clicking a slab, try combining it into a double-slab: BLOCKTYPE ClickedBlockType; NIBBLETYPE ClickedBlockMeta; - a_World.GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, ClickedBlockType, ClickedBlockMeta); - // If clicked on a half slab directly + a_World.GetBlockTypeMeta(a_ClickedBlockPos, ClickedBlockType, ClickedBlockMeta); if ( (ClickedBlockType == m_ItemType) && // Placing the same slab material ((ClickedBlockMeta & 0x07) == a_EquippedItem.m_ItemDamage) // Placing the same slab sub-kind (and existing slab is single) ) { - // If clicking the top side of a bottom-half slab, combine into a doubleslab: - if ( - (a_BlockFace == BLOCK_FACE_TOP) && - ((ClickedBlockMeta & 0x08) == 0) - ) - { - if (!a_Player.PlaceBlock(a_BlockX, a_BlockY, a_BlockZ, m_DoubleSlabBlockType, ClickedBlockMeta & 0x07)) - { - return false; - } - if (a_Player.IsGameModeSurvival()) - { - a_Player.GetInventory().RemoveOneEquippedItem(); - } - return true; - } - - // If clicking the bottom side of a top-half slab, combine into a doubleslab: if ( - (a_BlockFace == BLOCK_FACE_BOTTOM) && - ((ClickedBlockMeta & 0x08) != 0) + ((a_ClickedBlockFace == BLOCK_FACE_TOP) && ((ClickedBlockMeta & 0x08) == 0)) || // Top side of a bottom-half-slab + ((a_ClickedBlockFace == BLOCK_FACE_BOTTOM) && ((ClickedBlockMeta & 0x08) != 0)) // Bottom side of a top-half-slab ) { - if (!a_Player.PlaceBlock(a_BlockX, a_BlockY, a_BlockZ, m_DoubleSlabBlockType, ClickedBlockMeta & 0x07)) + if (!a_Player.PlaceBlock(a_ClickedBlockPos.x, a_ClickedBlockPos.y, a_ClickedBlockPos.z, m_DoubleSlabBlockType, ClickedBlockMeta & 0x07)) { return false; } @@ -75,18 +62,17 @@ public: } } - // Checking the type of block that should be placed - AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); + // If there's already a slab in the destination, combine it into a double-slab: + auto PlacePos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace); BLOCKTYPE PlaceBlockType; NIBBLETYPE PlaceBlockMeta; - a_World.GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, PlaceBlockType, PlaceBlockMeta); - // If it's a slab combine into a doubleslab (means that clicked on side, top or bottom of a block adjacent to a half slab) + a_World.GetBlockTypeMeta(PlacePos, PlaceBlockType, PlaceBlockMeta); if ( (PlaceBlockType == m_ItemType) && // Placing the same slab material ((PlaceBlockMeta & 0x07) == a_EquippedItem.m_ItemDamage) // Placing the same slab sub-kind (and existing slab is single) ) { - if (!a_Player.PlaceBlock(a_BlockX, a_BlockY, a_BlockZ, m_DoubleSlabBlockType, PlaceBlockMeta & 0x07)) + if (!a_Player.PlaceBlock(PlacePos.x, PlacePos.y, PlacePos.z, m_DoubleSlabBlockType, PlaceBlockMeta & 0x07)) { return false; } @@ -98,8 +84,7 @@ public: } // The slabs didn't combine, use the default handler to place the slab: - AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, true); - bool res = Super::OnPlayerPlace(a_World, a_Player, a_EquippedItem, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ); + bool res = Super::OnPlayerPlace(a_World, a_Player, a_EquippedItem, a_ClickedBlockPos, a_ClickedBlockFace, a_CursorPos); /* The client has a bug when a slab replaces snow and there's a slab above it. @@ -107,14 +92,17 @@ public: We send the block above the currently placed block back to the client to fix the bug. Ref.: https://forum.cuberite.org/thread-434-post-17388.html#pid17388 */ - if ((a_BlockFace == BLOCK_FACE_TOP) && (a_BlockY < cChunkDef::Height - 1)) + if ((a_ClickedBlockFace == BLOCK_FACE_TOP) && (a_ClickedBlockPos.y < cChunkDef::Height - 1)) { - a_Player.SendBlocksAround(a_BlockX, a_BlockY + 1, a_BlockZ, 1); + auto AbovePos = a_ClickedBlockPos.addedY(1); + a_Player.SendBlocksAround(AbovePos.x, AbovePos.y, AbovePos.z, 1); } return res; } + protected: + /** The block type to use when the slab combines into a doubleslab block. */ BLOCKTYPE m_DoubleSlabBlockType; }; diff --git a/src/Items/ItemSpawnEgg.h b/src/Items/ItemSpawnEgg.h index d57b93b2c..8408bd815 100644 --- a/src/Items/ItemSpawnEgg.h +++ b/src/Items/ItemSpawnEgg.h @@ -9,38 +9,47 @@ -class cItemSpawnEggHandler : public cItemHandler +class cItemSpawnEggHandler: + public cItemHandler { + using Super = cItemHandler; + public: - cItemSpawnEggHandler(int a_ItemType) : - cItemHandler(a_ItemType) - { + cItemSpawnEggHandler(int a_ItemType): + Super(a_ItemType) + { } + + virtual bool OnItemUse( - cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace + cWorld * a_World, + cPlayer * a_Player, + cBlockPluginInterface & a_PluginInterface, + const cItem & a_HeldItem, + const Vector3i a_ClickedBlockPos, + eBlockFace a_ClickedBlockFace ) override { - if (a_BlockFace < 0) + // Must click a valid block: + if (a_ClickedBlockFace < 0) { return false; } - AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); - - if (a_BlockFace == BLOCK_FACE_YM) + auto PlacementPos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace); + if (a_ClickedBlockFace == BLOCK_FACE_YM) { - a_BlockY--; + PlacementPos.y--; } - eMonsterType MonsterType = ItemDamageToMonsterType(a_Item.m_ItemDamage); + auto MonsterType = ItemDamageToMonsterType(a_HeldItem.m_ItemDamage); if ( (MonsterType != mtInvalidType) && // Valid monster type - (a_World->SpawnMob(a_BlockX + 0.5, a_BlockY, a_BlockZ + 0.5, MonsterType, false) != cEntity::INVALID_ID)) // Spawning succeeded + (a_World->SpawnMob(PlacementPos.x + 0.5, PlacementPos.y, PlacementPos.z + 0.5, MonsterType, false) != cEntity::INVALID_ID)) // Spawning succeeded { if (!a_Player->IsGameModeCreative()) { @@ -54,6 +63,9 @@ public: } + + + /** Converts the Spawn egg item damage to the monster type to spawn. Returns mtInvalidType for invalid damage values. */ static eMonsterType ItemDamageToMonsterType(short a_ItemDamage) diff --git a/src/Items/ItemString.h b/src/Items/ItemString.h index a97fbe0ce..e7c9617d4 100644 --- a/src/Items/ItemString.h +++ b/src/Items/ItemString.h @@ -7,26 +7,38 @@ -class cItemStringHandler : +class cItemStringHandler: public cItemHandler { + using Super = cItemHandler; + public: - cItemStringHandler(int a_ItemType) : - cItemHandler(a_ItemType) + + cItemStringHandler(int a_ItemType): + Super(a_ItemType) { } + + + + virtual bool IsPlaceable(void) override { return true; } + + + + virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta - ) override + ) override { a_BlockType = E_BLOCK_TRIPWIRE; a_BlockMeta = 0; diff --git a/src/Items/ItemSugarcane.h b/src/Items/ItemSugarcane.h index dd2e2ece3..b870f38f1 100644 --- a/src/Items/ItemSugarcane.h +++ b/src/Items/ItemSugarcane.h @@ -7,24 +7,36 @@ -class cItemSugarcaneHandler : +class cItemSugarcaneHandler: public cItemHandler { + using Super = cItemHandler; + public: - cItemSugarcaneHandler(int a_ItemType) : - cItemHandler(a_ItemType) + + cItemSugarcaneHandler(int a_ItemType): + Super(a_ItemType) { } + + + + virtual bool IsPlaceable(void) override { return true; } + + + + virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + const Vector3i a_PlacedBlockPos, + eBlockFace a_ClickedBlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { diff --git a/src/Items/ItemThrowable.h b/src/Items/ItemThrowable.h index daae7658c..606f655e9 100644 --- a/src/Items/ItemThrowable.h +++ b/src/Items/ItemThrowable.h @@ -23,22 +23,30 @@ public: + + virtual bool OnItemUse( - cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace + cWorld * a_World, + cPlayer * a_Player, + cBlockPluginInterface & a_PluginInterface, + const cItem & a_HeldItem, + const Vector3i a_ClickedBlockPos, + eBlockFace a_ClickedBlockFace ) override { - Vector3d Pos = a_Player->GetThrowStartPos(); - Vector3d Speed = a_Player->GetLookVector() * m_SpeedCoeff; - - // Play sound - a_World->BroadcastSoundEffect("entity.arrow.shoot", a_Player->GetPosition() - Vector3d(0, a_Player->GetHeight(), 0), 0.5f, 0.4f / GetRandomProvider().RandReal(0.8f, 1.2f)); + auto Pos = a_Player->GetThrowStartPos(); + auto Speed = a_Player->GetLookVector() * m_SpeedCoeff; + // Create the projectile: if (a_World->CreateProjectile(Pos.x, Pos.y, Pos.z, m_ProjectileKind, a_Player, &a_Player->GetEquippedItem(), &Speed) == cEntity::INVALID_ID) { return false; } + // Play sound: + a_World->BroadcastSoundEffect("entity.arrow.shoot", a_Player->GetPosition() - Vector3d(0, a_Player->GetHeight(), 0), 0.5f, 0.4f / GetRandomProvider().RandReal(0.8f, 1.2f)); + + // Remove from inventory if (!a_Player->IsGameModeCreative()) { a_Player->GetInventory().RemoveOneEquippedItem(); @@ -48,7 +56,11 @@ public: } protected: + + /** The kind of projectile to create when shooting */ cProjectileEntity::eKind m_ProjectileKind; + + /** The speed multiplier (to the player's normalized look vector) to set for the new projectile. */ double m_SpeedCoeff; } ; @@ -137,17 +149,23 @@ public: + + virtual bool OnItemUse( - cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace + cWorld * a_World, + cPlayer * a_Player, + cBlockPluginInterface & a_PluginInterface, + const cItem & a_HeldItem, + const Vector3i a_ClickedBlockPos, + eBlockFace a_ClickedBlockFace ) override { - if (a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_AIR) + if (a_World->GetBlock(a_ClickedBlockPos) == E_BLOCK_AIR) { return false; } - if (a_World->CreateProjectile(a_BlockX + 0.5, a_BlockY + 1, a_BlockZ + 0.5, m_ProjectileKind, a_Player, &a_Player->GetEquippedItem()) == 0) + if (a_World->CreateProjectile(Vector3d(a_ClickedBlockPos) + Vector3d(0.5, 1, 0.5), m_ProjectileKind, a_Player, &a_Player->GetEquippedItem()) == 0) { return false; } diff --git a/src/Simulator/IncrementalRedstoneSimulator/DoorHandler.h b/src/Simulator/IncrementalRedstoneSimulator/DoorHandler.h index ecd1d93b3..a22a6ff50 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/DoorHandler.h +++ b/src/Simulator/IncrementalRedstoneSimulator/DoorHandler.h @@ -26,6 +26,10 @@ public: return 0; } + + + + virtual unsigned char GetPowerLevel(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override { UNUSED(a_World); @@ -35,6 +39,10 @@ public: return 0; } + + + + virtual cVector3iArray Update(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override { // LOGD("Evaluating dori the door (%d %d %d)", a_Position.x, a_Position.y, a_Position.z); @@ -42,13 +50,17 @@ public: if (a_PoweringData != static_cast<cIncrementalRedstoneSimulator *>(a_World.GetRedstoneSimulator())->GetChunkData()->ExchangeUpdateOncePowerData(a_Position, a_PoweringData)) { cChunkInterface ChunkInterface(a_World.GetChunkMap()); - cBlockDoorHandler::SetOpen(ChunkInterface, a_Position.x, a_Position.y, a_Position.z, (a_PoweringData.PowerLevel != 0)); + cBlockDoorHandler::SetOpen(ChunkInterface, a_Position, (a_PoweringData.PowerLevel != 0)); a_World.BroadcastSoundParticleEffect(EffectID::SFX_RANDOM_WOODEN_DOOR_OPEN, a_Position, 0); } return {}; } + + + + virtual cVector3iArray GetValidSourcePositions(cWorld & a_World, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) const override { UNUSED(a_World); diff --git a/src/World.cpp b/src/World.cpp index eaed47e9c..c0838e1bf 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -1429,7 +1429,7 @@ void cWorld::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_Blo bool InRange = (Player->GetExplosionExposureRate(ExplosionPos, static_cast<float>(a_ExplosionSize)) > 0); auto Speed = InRange ? Player->GetSpeed() : Vector3d{}; - ch->SendExplosion(a_BlockX, a_BlockY, a_BlockZ, static_cast<float>(a_ExplosionSize), BlocksAffected, Speed); + ch->SendExplosion({a_BlockX, a_BlockY, a_BlockZ}, static_cast<float>(a_ExplosionSize), BlocksAffected, Speed); } auto Position = Vector3d(a_BlockX, a_BlockY - 0.5f, a_BlockZ); diff --git a/src/World.h b/src/World.h index 2d956bf49..51ec2b10e 100644 --- a/src/World.h +++ b/src/World.h @@ -696,6 +696,13 @@ public: virtual void SendBlockTo(int a_X, int a_Y, int a_Z, cPlayer & a_Player) override; + /** Sends the block at the specified coords to the player. + Used mainly when plugins disable block-placing or block-breaking, to restore the previous block. */ + void SendBlockTo(const Vector3i a_BlockPos, cPlayer & a_Player) + { + SendBlockTo(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, a_Player); + } + /** Set default spawn at the given coordinates. Returns false if the new spawn couldn't be stored in the INI file. */ bool SetSpawn(double a_X, double a_Y, double a_Z); diff --git a/tests/Generating/Stubs.cpp b/tests/Generating/Stubs.cpp index cd811a62c..736a34f55 100644 --- a/tests/Generating/Stubs.cpp +++ b/tests/Generating/Stubs.cpp @@ -120,8 +120,9 @@ cBoundingBox cBlockHandler::GetPlacementCollisionBox(BLOCKTYPE a_XM, BLOCKTYPE a bool cBlockHandler::GetPlacementBlockTypeMeta( cChunkInterface & a_ChunkInterface, cPlayer & a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + const Vector3i a_BlockPos, + eBlockFace a_BlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) { @@ -181,7 +182,7 @@ cItems cBlockHandler::ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_ -bool cBlockHandler::CanBeAt(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ, const cChunk & a_Chunk) +bool cBlockHandler::CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) { return true; } @@ -243,7 +244,7 @@ ColourID cBlockHandler::GetMapBaseColourID(NIBBLETYPE a_Meta) -bool cBlockHandler::IsInsideBlock(Vector3d a_Position, const BLOCKTYPE a_BlockType, const NIBBLETYPE a_BlockMeta) +bool cBlockHandler::IsInsideBlock(Vector3d a_Position, const NIBBLETYPE a_BlockMeta) { return true; } diff --git a/tests/LuaThreadStress/Stubs.cpp b/tests/LuaThreadStress/Stubs.cpp index 8010bff60..99f500cf7 100644 --- a/tests/LuaThreadStress/Stubs.cpp +++ b/tests/LuaThreadStress/Stubs.cpp @@ -145,8 +145,9 @@ cBoundingBox cBlockHandler::GetPlacementCollisionBox(BLOCKTYPE a_XM, BLOCKTYPE a bool cBlockHandler::GetPlacementBlockTypeMeta( cChunkInterface & a_ChunkInterface, cPlayer & a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + const Vector3i a_BlockPos, + eBlockFace a_BlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) { @@ -206,7 +207,7 @@ cItems cBlockHandler::ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_ -bool cBlockHandler::CanBeAt(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ, const cChunk & a_Chunk) +bool cBlockHandler::CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) { return true; } @@ -268,7 +269,7 @@ ColourID cBlockHandler::GetMapBaseColourID(NIBBLETYPE a_Meta) -bool cBlockHandler::IsInsideBlock(Vector3d a_Position, const BLOCKTYPE a_BlockType, const NIBBLETYPE a_BlockMeta) +bool cBlockHandler::IsInsideBlock(Vector3d a_Position, const NIBBLETYPE a_BlockMeta) { return true; } diff --git a/tests/SchematicFileSerializer/Stubs.cpp b/tests/SchematicFileSerializer/Stubs.cpp index 9334ca166..3ca411a09 100644 --- a/tests/SchematicFileSerializer/Stubs.cpp +++ b/tests/SchematicFileSerializer/Stubs.cpp @@ -72,8 +72,9 @@ cBoundingBox cBlockHandler::GetPlacementCollisionBox(BLOCKTYPE a_XM, BLOCKTYPE a bool cBlockHandler::GetPlacementBlockTypeMeta( cChunkInterface & a_ChunkInterface, cPlayer & a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, - int a_CursorX, int a_CursorY, int a_CursorZ, + const Vector3i a_BlockPos, + eBlockFace a_BlockFace, + const Vector3i a_CursorPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) { @@ -133,7 +134,7 @@ cItems cBlockHandler::ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_ -bool cBlockHandler::CanBeAt(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ, const cChunk & a_Chunk) +bool cBlockHandler::CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) { return true; } @@ -195,7 +196,7 @@ ColourID cBlockHandler::GetMapBaseColourID(NIBBLETYPE a_Meta) -bool cBlockHandler::IsInsideBlock(Vector3d a_Position, const BLOCKTYPE a_BlockType, const NIBBLETYPE a_BlockMeta) +bool cBlockHandler::IsInsideBlock(Vector3d a_Position, const NIBBLETYPE a_BlockMeta) { return true; } |