#pragma once #include "ItemHandler.h" #include "../World.h" #include "../Blocks/BlockDoor.h" class cItemDoorHandler final: public cItemHandler { using Super = cItemHandler; public: constexpr cItemDoorHandler(int a_ItemType): Super(a_ItemType) { } virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) const override { // Vanilla only allows door placement while clicking on the top face of the block below the door: if (a_ClickedBlockFace != BLOCK_FACE_TOP) { return false; } // Get the block type of the door to place: BLOCKTYPE BlockType; switch (m_ItemType) { case E_ITEM_WOODEN_DOOR: BlockType = E_BLOCK_OAK_DOOR; break; case E_ITEM_IRON_DOOR: BlockType = E_BLOCK_IRON_DOOR; break; case E_ITEM_SPRUCE_DOOR: BlockType = E_BLOCK_SPRUCE_DOOR; break; case E_ITEM_BIRCH_DOOR: BlockType = E_BLOCK_BIRCH_DOOR; break; case E_ITEM_JUNGLE_DOOR: BlockType = E_BLOCK_JUNGLE_DOOR; break; case E_ITEM_DARK_OAK_DOOR: BlockType = E_BLOCK_DARK_OAK_DOOR; break; case E_ITEM_ACACIA_DOOR: BlockType = E_BLOCK_ACACIA_DOOR; break; default: UNREACHABLE("Unhandled door type"); } const auto & World = *a_Player.GetWorld(); const auto UpperBlockPosition = a_PlacePosition.addedY(1); // Check the block that will get replaced by the door: { BLOCKTYPE TopType; NIBBLETYPE TopMeta; if (!World.GetBlockTypeMeta(UpperBlockPosition, TopType, TopMeta)) { return false; } if (!cBlockHandler::For(TopType).DoesIgnoreBuildCollision(World, a_HeldItem, UpperBlockPosition, TopMeta, a_ClickedBlockFace, false)) { return false; } } // Get the coords of the neighboring blocks: NIBBLETYPE LowerBlockMeta = cBlockDoorHandler::YawToMetaData(a_Player.GetYaw()); Vector3i RelDirToOutside = cBlockDoorHandler::GetRelativeDirectionToOutside(LowerBlockMeta); Vector3i LeftNeighborPos = RelDirToOutside; LeftNeighborPos.TurnCW(); LeftNeighborPos.Move(a_PlacePosition); Vector3i RightNeighborPos = RelDirToOutside; RightNeighborPos.TurnCCW(); RightNeighborPos.Move(a_PlacePosition); // Decide whether the hinge is on the left (default) or on the right: NIBBLETYPE UpperBlockMeta = 0x08; BLOCKTYPE LeftNeighborBlock = World.GetBlock(LeftNeighborPos); BLOCKTYPE RightNeighborBlock = World.GetBlock(RightNeighborPos); /* // DEBUG: FLOGD("Door being placed at {0}", a_PlacePosition); 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)); */ if ( cBlockDoorHandler::IsDoorBlockType(LeftNeighborBlock) || // The block to the left is a door block ( !cBlockInfo::IsSolid(LeftNeighborBlock) && // Prioritize hinge on the left side cBlockInfo::IsSolid(RightNeighborBlock) && // The block to the right is solid... !cBlockDoorHandler::IsDoorBlockType(RightNeighborBlock) // ... but not a door ) ) { // DEBUG: LOGD("Setting hinge to right side"); UpperBlockMeta = 0x09; // Upper block | hinge on right } // Set the blocks: return a_Player.PlaceBlocks( { { a_PlacePosition, BlockType, LowerBlockMeta }, { UpperBlockPosition, BlockType, UpperBlockMeta } }); } virtual bool IsPlaceable(void) const override { return true; } } ;