diff options
Diffstat (limited to 'src')
84 files changed, 791 insertions, 592 deletions
diff --git a/src/Blocks/BlockAnvil.h b/src/Blocks/BlockAnvil.h index bc031216a..eb8053af1 100644 --- a/src/Blocks/BlockAnvil.h +++ b/src/Blocks/BlockAnvil.h @@ -2,7 +2,7 @@ #pragma once #include "BlockHandler.h" -#include "Mixins.h" +#include "Mixins/Mixins.h" #include "../Entities/Player.h" #include "../UI/AnvilWindow.h" diff --git a/src/Blocks/BlockBed.h b/src/Blocks/BlockBed.h index a6b2814b9..fcf7d58a0 100644 --- a/src/Blocks/BlockBed.h +++ b/src/Blocks/BlockBed.h @@ -6,7 +6,7 @@ #include "BlockEntity.h" #include "ChunkInterface.h" #include "Entities/Player.h" -#include "Mixins.h" +#include "Mixins/Mixins.h" diff --git a/src/Blocks/BlockBigFlower.h b/src/Blocks/BlockBigFlower.h index 1b2c0d735..d8270dc6c 100644 --- a/src/Blocks/BlockBigFlower.h +++ b/src/Blocks/BlockBigFlower.h @@ -25,9 +25,10 @@ private: if (IsMetaTopPart(a_Meta)) { BLOCKTYPE BottomType; + const auto BottomPosition = a_Position.addedY(-1); if ( - (a_Position.y < 1) || - !a_World.GetBlockTypeMeta(a_Position - Vector3i(0, 1, 0), BottomType, a_Meta) || + !cChunkDef::IsValidHeight(BottomPosition) || + !a_World.GetBlockTypeMeta(BottomPosition, BottomType, a_Meta) || (BottomType != E_BLOCK_BIG_FLOWER) ) { @@ -104,7 +105,7 @@ private: // Both parts can only that they're rooted in grass. const auto RootPosition = a_Position.addedY(IsMetaTopPart(a_Meta) ? -2 : -1); - return (RootPosition.y >= 0) && IsBlockTypeOfDirt(a_Chunk.GetBlock(RootPosition)); + return cChunkDef::IsValidHeight(RootPosition) && IsBlockTypeOfDirt(a_Chunk.GetBlock(RootPosition)); } diff --git a/src/Blocks/BlockBrewingStand.h b/src/Blocks/BlockBrewingStand.h index d1595c690..5f41525d7 100644 --- a/src/Blocks/BlockBrewingStand.h +++ b/src/Blocks/BlockBrewingStand.h @@ -1,7 +1,7 @@ #pragma once -#include "Mixins.h" +#include "Mixins/Mixins.h" diff --git a/src/Blocks/BlockButton.h b/src/Blocks/BlockButton.h index 1a141eff3..e8affb290 100644 --- a/src/Blocks/BlockButton.h +++ b/src/Blocks/BlockButton.h @@ -7,7 +7,7 @@ #include "../Chunk.h" #include "Defines.h" #include "Entities/Player.h" -#include "Mixins.h" +#include "Mixins/Mixins.h" #include "ChunkInterface.h" #include "World.h" diff --git a/src/Blocks/BlockCactus.h b/src/Blocks/BlockCactus.h index 23c4d3421..9b1461cb8 100644 --- a/src/Blocks/BlockCactus.h +++ b/src/Blocks/BlockCactus.h @@ -20,11 +20,12 @@ private: virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - if (a_Position.y <= 0) + const auto SurfacePosition = a_Position.addedY(-1); + if (!cChunkDef::IsValidHeight(SurfacePosition)) { return false; } - BLOCKTYPE Surface = a_Chunk.GetBlock(a_Position.addedY(-1)); + BLOCKTYPE Surface = a_Chunk.GetBlock(SurfacePosition); if ((Surface != E_BLOCK_SAND) && (Surface != E_BLOCK_CACTUS)) { // Cactus can only be placed on sand and itself @@ -75,25 +76,25 @@ private: virtual int Grow(cChunk & a_Chunk, Vector3i a_RelPos, int a_NumStages = 1) const override { // Check the total height of the cacti blocks here: - int top = a_RelPos.y + 1; + auto Top = a_RelPos.addedY(1); while ( - (top < cChunkDef::Height) && - (a_Chunk.GetBlock({a_RelPos.x, top, a_RelPos.z}) == E_BLOCK_CACTUS) + cChunkDef::IsValidHeight(Top) && + (a_Chunk.GetBlock(Top) == E_BLOCK_CACTUS) ) { - ++top; + Top.y++; } - int bottom = a_RelPos.y - 1; + auto Bottom = a_RelPos.addedY(-1); while ( - (bottom > 0) && - (a_Chunk.GetBlock({a_RelPos.x, bottom, a_RelPos.z}) == E_BLOCK_CACTUS) + cChunkDef::IsValidHeight(Bottom) && + (a_Chunk.GetBlock(Bottom) == E_BLOCK_CACTUS) ) { - --bottom; + --Bottom.y; } // Refuse if already too high: - auto numToGrow = std::min(a_NumStages, a_Chunk.GetWorld()->GetMaxCactusHeight() + 1 - (top - bottom)); + auto numToGrow = std::min(a_NumStages, a_Chunk.GetWorld()->GetMaxCactusHeight() + 1 - (Top.y - Bottom.y)); if (numToGrow <= 0) { return 0; @@ -102,14 +103,14 @@ private: BLOCKTYPE blockType; for (int i = 0; i < numToGrow; ++i) { - Vector3i pos(a_RelPos.x, top + i, a_RelPos.z); - if (!a_Chunk.UnboundedRelGetBlockType(pos, blockType) || (blockType != E_BLOCK_AIR)) + auto NewTop = Top.addedY(i); + if (!a_Chunk.UnboundedRelGetBlockType(NewTop, blockType) || (blockType != E_BLOCK_AIR)) { // Cannot grow there return i; } - a_Chunk.UnboundedRelFastSetBlock(pos, E_BLOCK_CACTUS, 0); + a_Chunk.UnboundedRelFastSetBlock(NewTop, E_BLOCK_CACTUS, 0); // Check surroundings. Cacti may ONLY be surrounded by non-solid blocks; if they aren't, drop as pickup and bail out the growing static const Vector3i neighborOffsets[] = @@ -122,7 +123,7 @@ private: for (const auto & ofs: neighborOffsets) { if ( - a_Chunk.UnboundedRelGetBlockType(pos + ofs, blockType) && + a_Chunk.UnboundedRelGetBlockType(NewTop + ofs, blockType) && ( cBlockInfo::IsSolid(blockType) || (blockType == E_BLOCK_LAVA) || @@ -131,7 +132,7 @@ private: ) { // Remove the cactus - auto absPos = a_Chunk.RelativeToAbsolute(pos); + auto absPos = a_Chunk.RelativeToAbsolute(NewTop); a_Chunk.GetWorld()->DropBlockAsPickups(absPos); return i + 1; } @@ -143,7 +144,8 @@ private: virtual PlantAction CanGrow(cChunk & a_Chunk, Vector3i a_RelPos) const override { // Only allow growing if there's an air block above: - if (((a_RelPos.y + 1) < cChunkDef::Height) && (a_Chunk.GetBlock(a_RelPos.addedY(1)) == E_BLOCK_AIR)) + const auto RelPosAbove = a_RelPos.addedY(1); + if (cChunkDef::IsValidHeight(RelPosAbove) && (a_Chunk.GetBlock(RelPosAbove) == E_BLOCK_AIR)) { return Super::CanGrow(a_Chunk, a_RelPos); } diff --git a/src/Blocks/BlockCarpet.h b/src/Blocks/BlockCarpet.h index 841e94b11..2477ee344 100644 --- a/src/Blocks/BlockCarpet.h +++ b/src/Blocks/BlockCarpet.h @@ -27,7 +27,8 @@ private: virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - return (a_Position.y > 0) && (a_Chunk.GetBlock(a_Position.addedY(-1)) != E_BLOCK_AIR); + const auto PosBelow = a_Position.addedY(-1); + return cChunkDef::IsValidHeight(PosBelow) && (a_Chunk.GetBlock(PosBelow) != E_BLOCK_AIR); } diff --git a/src/Blocks/BlockChest.h b/src/Blocks/BlockChest.h index 119216d00..99a95e692 100644 --- a/src/Blocks/BlockChest.h +++ b/src/Blocks/BlockChest.h @@ -3,7 +3,7 @@ #include "../BlockArea.h" #include "../Entities/Player.h" -#include "Mixins.h" +#include "Mixins/Mixins.h" diff --git a/src/Blocks/BlockCocoaPod.h b/src/Blocks/BlockCocoaPod.h index e018388c5..7906a1888 100644 --- a/src/Blocks/BlockCocoaPod.h +++ b/src/Blocks/BlockCocoaPod.h @@ -43,7 +43,12 @@ private: auto LogPos = AddFaceDirection(a_Position, BlockFace, true); BLOCKTYPE BlockType; NIBBLETYPE BlockMeta; - a_Chunk.UnboundedRelGetBlock(LogPos, BlockType, BlockMeta); + if (!a_Chunk.UnboundedRelGetBlock(LogPos, BlockType, BlockMeta)) + { + // Don't pop if chunk not loaded. + return true; + } + return ((BlockType == E_BLOCK_LOG) && ((BlockMeta & 0x03) == E_META_LOG_JUNGLE)); } diff --git a/src/Blocks/BlockComparator.h b/src/Blocks/BlockComparator.h index 18aa2a8b9..9ce9d3dbd 100644 --- a/src/Blocks/BlockComparator.h +++ b/src/Blocks/BlockComparator.h @@ -2,17 +2,17 @@ #pragma once #include "BlockHandler.h" -#include "BlockRedstoneRepeater.h" -#include "Mixins.h" +#include "Mixins/Mixins.h" +#include "Mixins/SolidSurfaceUnderneath.h" class cBlockComparatorHandler final : - public cYawRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03> + public cSolidSurfaceUnderneath<cYawRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03>> { - using Super = cYawRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03>; + using Super = cSolidSurfaceUnderneath<cYawRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03>>; public: @@ -152,41 +152,6 @@ private: - virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override - { - if (a_Position.y <= 0) - { - return false; - } - - BLOCKTYPE BelowBlock; - NIBBLETYPE BelowBlockMeta; - a_Chunk.GetBlockTypeMeta(a_Position.addedY(-1), BelowBlock, BelowBlockMeta); - - if (cBlockInfo::FullyOccupiesVoxel(BelowBlock)) - { - return true; - } - - // upside down slabs - if (cBlockSlabHandler::IsAnySlabType(BelowBlock)) - { - return BelowBlockMeta & E_META_WOODEN_SLAB_UPSIDE_DOWN; - } - - // upside down stairs - if (cBlockStairsHandler::IsAnyStairType(BelowBlock)) - { - return BelowBlockMeta & E_BLOCK_STAIRS_UPSIDE_DOWN; - } - - return false; - } - - - - - virtual cItems ConvertToPickups(const NIBBLETYPE a_BlockMeta, const cItem * const a_Tool) const override { return cItem(E_ITEM_COMPARATOR, 1, 0); diff --git a/src/Blocks/BlockCrops.h b/src/Blocks/BlockCrops.h index b323ace10..59413ba08 100644 --- a/src/Blocks/BlockCrops.h +++ b/src/Blocks/BlockCrops.h @@ -118,7 +118,14 @@ private: virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - return (a_Position.y > 0) && (a_Chunk.GetBlock(a_Position.addedY(-1)) == E_BLOCK_FARMLAND); + const auto BlockBelow = a_Position.addedY(-1); + + if (!cChunkDef::IsValidHeight(BlockBelow)) + { + return false; + } + + return a_Chunk.GetBlock(BlockBelow) == E_BLOCK_FARMLAND; } diff --git a/src/Blocks/BlockDeadBush.h b/src/Blocks/BlockDeadBush.h index 080dd150c..884b6f686 100644 --- a/src/Blocks/BlockDeadBush.h +++ b/src/Blocks/BlockDeadBush.h @@ -29,12 +29,13 @@ private: virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - if (a_Position.y <= 0) + const auto PosBelow = a_Position.addedY(-1); + if (!cChunkDef::IsValidHeight(PosBelow)) { return false; } - BLOCKTYPE BelowBlock = a_Chunk.GetBlock(a_Position.addedY(-1)); + BLOCKTYPE BelowBlock = a_Chunk.GetBlock(PosBelow); switch (BelowBlock) { case E_BLOCK_CLAY: diff --git a/src/Blocks/BlockDoor.h b/src/Blocks/BlockDoor.h index 1b5c33d46..c394bda39 100644 --- a/src/Blocks/BlockDoor.h +++ b/src/Blocks/BlockDoor.h @@ -5,7 +5,7 @@ #include "../BlockInfo.h" #include "../Entities/Player.h" #include "../Chunk.h" -#include "Mixins.h" +#include "Mixins/Mixins.h" #include "ChunkInterface.h" #include "BlockSlab.h" @@ -191,14 +191,18 @@ private: virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { // CanBeAt is also called on placement, so the top part can't check for the bottom part. - // Both parts can only that their base is a valid block. + // Both parts can only check that the base of the door (i.e. -2 for a door top) is a valid block. + const auto BasePosition = a_Position.addedY(((a_Meta & 0x8) == 0x8) ? -2 : -1); + if (!cChunkDef::IsValidHeight(BasePosition)) + { + return false; + } BLOCKTYPE BlockType; NIBBLETYPE BlockMeta; - const auto BasePosition = a_Position.addedY(((a_Meta & 0x8) == 0x8) ? -2 : -1); a_Chunk.GetBlockTypeMeta(BasePosition, BlockType, BlockMeta); - return (BasePosition.y >= 0) && CanBeOn(BlockType, BlockMeta); + return CanBeOn(BlockType, BlockMeta); } @@ -216,9 +220,10 @@ private: if ((Meta & 0x08) != 0) { // The coords are pointing at the top part of the door - if (a_BlockPos.y > 0) + const auto BottomPos = a_BlockPos.addedY(-1); + if (cChunkDef::IsValidHeight(BottomPos)) { - NIBBLETYPE DownMeta = a_ChunkInterface.GetBlockMeta(a_BlockPos.addedY(-1)); + NIBBLETYPE DownMeta = a_ChunkInterface.GetBlockMeta(BottomPos); 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: @@ -227,9 +232,10 @@ private: else { // The coords are pointing at the bottom part of the door - if (a_BlockPos.y < cChunkDef::Height - 1) + const auto TopPos = a_BlockPos.addedY(1); + if (cChunkDef::IsValidHeight(TopPos)) { - NIBBLETYPE UpMeta = a_ChunkInterface.GetBlockMeta(a_BlockPos.addedY(1)); + NIBBLETYPE UpMeta = a_ChunkInterface.GetBlockMeta(TopPos); 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: diff --git a/src/Blocks/BlockDropSpenser.h b/src/Blocks/BlockDropSpenser.h index 050adf0f1..7b18eb8da 100644 --- a/src/Blocks/BlockDropSpenser.h +++ b/src/Blocks/BlockDropSpenser.h @@ -5,7 +5,7 @@ #pragma once -#include "Mixins.h" +#include "Mixins/Mixins.h" diff --git a/src/Blocks/BlockEnderChest.h b/src/Blocks/BlockEnderChest.h index 2e0da0f17..a944ab263 100644 --- a/src/Blocks/BlockEnderChest.h +++ b/src/Blocks/BlockEnderChest.h @@ -1,7 +1,7 @@ #pragma once -#include "Mixins.h" +#include "Mixins/Mixins.h" diff --git a/src/Blocks/BlockFenceGate.h b/src/Blocks/BlockFenceGate.h index f52d8df9c..75a0ded06 100644 --- a/src/Blocks/BlockFenceGate.h +++ b/src/Blocks/BlockFenceGate.h @@ -2,7 +2,7 @@ #pragma once #include "BlockHandler.h" -#include "Mixins.h" +#include "Mixins/Mixins.h" #include "../EffectID.h" diff --git a/src/Blocks/BlockFlower.h b/src/Blocks/BlockFlower.h index 023ba4a37..aaa532c0c 100644 --- a/src/Blocks/BlockFlower.h +++ b/src/Blocks/BlockFlower.h @@ -2,15 +2,16 @@ #pragma once #include "BlockHandler.h" +#include "Mixins/DirtLikeUnderneath.h" class cBlockFlowerHandler final : - public cBlockHandler + public cDirtLikeUnderneath<cBlockHandler> { - using Super = cBlockHandler; + using Super = cDirtLikeUnderneath<cBlockHandler>; public: @@ -28,15 +29,6 @@ private: - virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override - { - return (a_Position.y > 0) && IsBlockTypeOfDirt(a_Chunk.GetBlock(a_Position.addedY(-1))); - } - - - - - virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) const override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockFurnace.h b/src/Blocks/BlockFurnace.h index 8cdc9489a..968ea398c 100644 --- a/src/Blocks/BlockFurnace.h +++ b/src/Blocks/BlockFurnace.h @@ -1,7 +1,7 @@ #pragma once -#include "Mixins.h" +#include "Mixins/Mixins.h" diff --git a/src/Blocks/BlockGlazedTerracotta.h b/src/Blocks/BlockGlazedTerracotta.h index 0975f1ecd..21206ab77 100644 --- a/src/Blocks/BlockGlazedTerracotta.h +++ b/src/Blocks/BlockGlazedTerracotta.h @@ -1,7 +1,7 @@ #pragma once -#include "Mixins.h" +#include "Mixins/Mixins.h" diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp index 4b0d7e5ec..6691f151f 100644 --- a/src/Blocks/BlockHandler.cpp +++ b/src/Blocks/BlockHandler.cpp @@ -7,7 +7,6 @@ #include "BlockPluginInterface.h" #include "BlockAir.h" #include "BlockAnvil.h" -#include "BlockBanner.h" #include "BlockBed.h" #include "BlockBigFlower.h" #include "BlockBookShelf.h" @@ -89,6 +88,7 @@ #include "BlockSnow.h" #include "BlockSponge.h" #include "BlockStairs.h" +#include "BlockStandingBanner.h" #include "BlockStems.h" #include "BlockStone.h" #include "BlockSugarCane.h" @@ -99,6 +99,7 @@ #include "BlockTripwire.h" #include "BlockTripwireHook.h" #include "BlockVines.h" +#include "BlockWallBanner.h" #include "BlockWallSign.h" #include "BlockWorkbench.h" @@ -413,7 +414,7 @@ namespace constexpr cDefaultBlockHandler BlockStainedClayHandler (E_BLOCK_STAINED_CLAY); constexpr cBlockGlassHandler BlockStainedGlassHandler (E_BLOCK_STAINED_GLASS); constexpr cBlockGlassHandler BlockStainedGlassPaneHandler (E_BLOCK_STAINED_GLASS_PANE); - constexpr cBlockBannerHandler BlockStandingBannerHandler (E_BLOCK_STANDING_BANNER); + constexpr cBlockStandingBannerHandler BlockStandingBannerHandler (E_BLOCK_STANDING_BANNER); constexpr cBlockLavaHandler BlockStationaryLavaHandler (E_BLOCK_STATIONARY_LAVA); constexpr cBlockWaterHandler BlockStationaryWaterHandler (E_BLOCK_STATIONARY_WATER); constexpr cBlockPistonHandler BlockStickyPistonHandler (E_BLOCK_STICKY_PISTON); @@ -434,7 +435,7 @@ namespace constexpr cBlockTripwireHandler BlockTripwireHandler (E_BLOCK_TRIPWIRE); constexpr cBlockTripwireHookHandler BlockTripwireHookHandler (E_BLOCK_TRIPWIRE_HOOK); constexpr cBlockVinesHandler BlockVinesHandler (E_BLOCK_VINES); - constexpr cBlockBannerHandler BlockWallBannerHandler (E_BLOCK_WALL_BANNER); + constexpr cBlockWallBannerHandler BlockWallBannerHandler (E_BLOCK_WALL_BANNER); constexpr cBlockWallSignHandler BlockWallsignHandler (E_BLOCK_WALLSIGN); constexpr cBlockWaterHandler BlockWaterHandler (E_BLOCK_WATER); constexpr cBlockGlazedTerracottaHandler BlockWhiteGlazedTerracottaHandler (E_BLOCK_WHITE_GLAZED_TERRACOTTA); diff --git a/src/Blocks/BlockHopper.h b/src/Blocks/BlockHopper.h index 930f1e0bc..91ad91bff 100644 --- a/src/Blocks/BlockHopper.h +++ b/src/Blocks/BlockHopper.h @@ -3,7 +3,7 @@ // Declares the cBlockHopperHandler class representing the handler for the Hopper block -#include "Mixins.h" +#include "Mixins/Mixins.h" diff --git a/src/Blocks/BlockJukebox.h b/src/Blocks/BlockJukebox.h index 970f10fc1..79475d30b 100644 --- a/src/Blocks/BlockJukebox.h +++ b/src/Blocks/BlockJukebox.h @@ -2,7 +2,7 @@ #pragma once #include "BlockEntity.h" -#include "Mixins.h" +#include "Mixins/Mixins.h" diff --git a/src/Blocks/BlockLadder.h b/src/Blocks/BlockLadder.h index bab51b2d3..4bca19930 100644 --- a/src/Blocks/BlockLadder.h +++ b/src/Blocks/BlockLadder.h @@ -3,7 +3,7 @@ #include "BlockHandler.h" #include "BlockInfo.h" -#include "Mixins.h" +#include "Mixins/Mixins.h" diff --git a/src/Blocks/BlockLever.h b/src/Blocks/BlockLever.h index 60db4ddee..2a676ce00 100644 --- a/src/Blocks/BlockLever.h +++ b/src/Blocks/BlockLever.h @@ -5,7 +5,7 @@ #include "Blocks/BlockStairs.h" #include "ChunkDef.h" #include "Defines.h" -#include "Mixins.h" +#include "Mixins/Mixins.h" #include "BlockSlab.h" diff --git a/src/Blocks/BlockMushroom.h b/src/Blocks/BlockMushroom.h index bed16c557..9e4378d4e 100644 --- a/src/Blocks/BlockMushroom.h +++ b/src/Blocks/BlockMushroom.h @@ -23,14 +23,15 @@ private: virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - if (a_Position.y <= 0) + const auto BasePos = a_Position.addedY(-1); + if (!cChunkDef::IsValidHeight(BasePos)) { return false; } // TODO: Cannot be at too much daylight - switch (a_Chunk.GetBlock(a_Position.addedY(-1))) + switch (a_Chunk.GetBlock(BasePos)) { case E_BLOCK_GLASS: case E_BLOCK_CACTUS: diff --git a/src/Blocks/BlockNetherWart.h b/src/Blocks/BlockNetherWart.h index 43081d511..c0686afc6 100644 --- a/src/Blocks/BlockNetherWart.h +++ b/src/Blocks/BlockNetherWart.h @@ -60,7 +60,8 @@ private: virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { // Needs to be placed on top of a Soulsand block: - return (a_Position.y > 0) && (a_Chunk.GetBlock(a_Position.addedY(-1)) == E_BLOCK_SOULSAND); + const auto BasePos = a_Position.addedY(-1); + return cChunkDef::IsValidHeight(BasePos) && (a_Chunk.GetBlock(BasePos) == E_BLOCK_SOULSAND); } diff --git a/src/Blocks/BlockObserver.h b/src/Blocks/BlockObserver.h index 13ffa4631..c2cab3068 100644 --- a/src/Blocks/BlockObserver.h +++ b/src/Blocks/BlockObserver.h @@ -2,7 +2,7 @@ #pragma once #include "BlockHandler.h" -#include "Mixins.h" +#include "Mixins/Mixins.h" class cBlockObserverHandler final : diff --git a/src/Blocks/BlockPiston.cpp b/src/Blocks/BlockPiston.cpp index 124757b44..568e2eaa5 100644 --- a/src/Blocks/BlockPiston.cpp +++ b/src/Blocks/BlockPiston.cpp @@ -48,8 +48,12 @@ void cBlockPistonHandler::ExtendPiston(Vector3i a_BlockPos, cWorld & a_World) BLOCKTYPE pistonBlock; NIBBLETYPE pistonMeta; - a_World.GetBlockTypeMeta(a_BlockPos, pistonBlock, pistonMeta); - a_World.BroadcastBlockAction(a_BlockPos, PistonExtendAction, pistonMeta, pistonBlock); + if (a_World.GetBlockTypeMeta(a_BlockPos, pistonBlock, pistonMeta)) + { + a_World.BroadcastBlockAction( + a_BlockPos, PistonExtendAction, pistonMeta, pistonBlock + ); + } } // Client expects the server to "play" the animation before setting the final blocks @@ -60,9 +64,12 @@ void cBlockPistonHandler::ExtendPiston(Vector3i a_BlockPos, cWorld & a_World) { BLOCKTYPE pistonBlock; NIBBLETYPE pistonMeta; - World.GetBlockTypeMeta(a_BlockPos, pistonBlock, pistonMeta); - if ((pistonBlock != E_BLOCK_PISTON) && !IsSticky(pistonBlock)) + + if ( + !World.GetBlockTypeMeta(a_BlockPos, pistonBlock, pistonMeta) || + ((pistonBlock != E_BLOCK_PISTON) && !IsSticky(pistonBlock)) + ) { // Ensure we operate on a piston to avoid spurious behaviour // Note that the scheduled task may result in the block type of a_BlockPos changing @@ -104,17 +111,23 @@ void cBlockPistonHandler::RetractPiston(Vector3i a_BlockPos, cWorld & a_World) { BLOCKTYPE pistonBlock; NIBBLETYPE pistonMeta; - a_World.GetBlockTypeMeta(a_BlockPos, pistonBlock, pistonMeta); - a_World.BroadcastBlockAction(a_BlockPos, PistonRetractAction, pistonMeta, pistonBlock); + if (a_World.GetBlockTypeMeta(a_BlockPos, pistonBlock, pistonMeta)) + { + a_World.BroadcastBlockAction( + a_BlockPos, PistonRetractAction, pistonMeta, pistonBlock + ); + } } a_World.ScheduleTask(1_tick, [a_BlockPos](cWorld & World) { BLOCKTYPE pistonBlock; NIBBLETYPE pistonMeta; - World.GetBlockTypeMeta(a_BlockPos, pistonBlock, pistonMeta); - if ((pistonBlock != E_BLOCK_PISTON) && !IsSticky(pistonBlock)) + if ( + !World.GetBlockTypeMeta(a_BlockPos, pistonBlock, pistonMeta) || + ((pistonBlock != E_BLOCK_PISTON) && !IsSticky(pistonBlock)) + ) { // Ensure we operate on a piston to avoid spurious behaviour // Note that the scheduled task may result in the block type of a_BlockPos changing @@ -189,19 +202,20 @@ void cBlockPistonHandler::PushBlocks( NIBBLETYPE moveMeta; for (auto & moveBlockPos : sortedBlocks) { - a_World.GetBlockTypeMeta(moveBlockPos, moveBlock, moveMeta); - - if (cBlockInfo::IsPistonBreakable(moveBlock)) - { - // Block is breakable, drop it: - a_World.DropBlockAsPickups(moveBlockPos, nullptr, nullptr); - } - else + if (a_World.GetBlockTypeMeta(moveBlockPos, moveBlock, moveMeta)) { - // Not breakable, just move it - a_World.SetBlock(moveBlockPos, E_BLOCK_AIR, 0); - moveBlockPos += a_PushDir; - a_World.SetBlock(moveBlockPos, moveBlock, moveMeta); + if (cBlockInfo::IsPistonBreakable(moveBlock)) + { + // Block is breakable, drop it: + a_World.DropBlockAsPickups(moveBlockPos, nullptr, nullptr); + } + else + { + // Not breakable, just move it + a_World.SetBlock(moveBlockPos, E_BLOCK_AIR, 0); + moveBlockPos += a_PushDir; + a_World.SetBlock(moveBlockPos, moveBlock, moveMeta); + } } } } @@ -232,7 +246,10 @@ bool cBlockPistonHandler::CanPushBlock( BLOCKTYPE currBlock; NIBBLETYPE currMeta; - a_World.GetBlockTypeMeta(a_BlockPos, currBlock, currMeta); + if (!a_World.GetBlockTypeMeta(a_BlockPos, currBlock, currMeta)) + { + return !a_RequirePushable; + } if (currBlock == E_BLOCK_AIR) { diff --git a/src/Blocks/BlockPiston.h b/src/Blocks/BlockPiston.h index 4afeb4767..275214036 100644 --- a/src/Blocks/BlockPiston.h +++ b/src/Blocks/BlockPiston.h @@ -2,7 +2,7 @@ #pragma once #include "BlockHandler.h" -#include "Mixins.h" +#include "Mixins/Mixins.h" #include "../Item.h" diff --git a/src/Blocks/BlockPortal.h b/src/Blocks/BlockPortal.h index 05daa9337..f4b5a50bd 100644 --- a/src/Blocks/BlockPortal.h +++ b/src/Blocks/BlockPortal.h @@ -51,9 +51,9 @@ private: virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - if ((a_Position.y <= 0) || (a_Position.y >= cChunkDef::Height - 1)) + if (!cChunkDef::IsValidHeight(a_Position.addedY(-1)) || !cChunkDef::IsValidHeight(a_Position.addedY(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. + return false; // Must be 1 away from the boundary, there will always be another portal or an obsidian between the portal block and the boundary. } switch (a_Meta) diff --git a/src/Blocks/BlockPressurePlate.h b/src/Blocks/BlockPressurePlate.h index 6d852bfc0..d69234cee 100644 --- a/src/Blocks/BlockPressurePlate.h +++ b/src/Blocks/BlockPressurePlate.h @@ -22,14 +22,15 @@ private: virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - if (a_Position.y <= 0) + const auto PosBelow = a_Position.addedY(-1); + if (!cChunkDef::IsValidHeight(PosBelow)) { return false; } BLOCKTYPE Block; NIBBLETYPE BlockMeta; - a_Chunk.GetBlockTypeMeta(a_Position.addedY(-1), Block, BlockMeta); + a_Chunk.GetBlockTypeMeta(PosBelow, Block, BlockMeta); // upside down slabs if (cBlockSlabHandler::IsAnySlabType(Block)) diff --git a/src/Blocks/BlockPumpkin.h b/src/Blocks/BlockPumpkin.h index e627eeaee..fa73db56a 100644 --- a/src/Blocks/BlockPumpkin.h +++ b/src/Blocks/BlockPumpkin.h @@ -1,7 +1,7 @@ #pragma once #include "BlockHandler.h" -#include "Mixins.h" +#include "Mixins/Mixins.h" diff --git a/src/Blocks/BlockRail.h b/src/Blocks/BlockRail.h index 4e2e6211f..dea84296f 100644 --- a/src/Blocks/BlockRail.h +++ b/src/Blocks/BlockRail.h @@ -1,10 +1,9 @@ #pragma once #include "BlockHandler.h" -#include "BlockSlab.h" -#include "BlockStairs.h" #include "BlockType.h" -#include "Blocks/Mixins.h" +#include "Mixins/Mixins.h" +#include "Mixins/SolidSurfaceUnderneath.h" #include "../BlockInfo.h" #include "../Chunk.h" #include "ChunkDef.h" @@ -25,9 +24,9 @@ enum ENUM_PURE class cBlockRailHandler final : - public cClearMetaOnDrop<cBlockHandler> + public cSolidSurfaceUnderneath<cClearMetaOnDrop<cBlockHandler>> { - using Super = cClearMetaOnDrop<cBlockHandler>; + using Super = cSolidSurfaceUnderneath<cClearMetaOnDrop<cBlockHandler>>; public: @@ -162,26 +161,9 @@ public: private: - static bool CanBeSupportedBy(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) - { - if (cBlockSlabHandler::IsAnySlabType(a_BlockType)) - { - return (a_BlockMeta & E_META_WOODEN_SLAB_UPSIDE_DOWN); - } - else if (cBlockStairsHandler::IsAnyStairType(a_BlockType)) - { - return (a_BlockMeta & E_BLOCK_STAIRS_UPSIDE_DOWN); - } - return cBlockInfo::FullyOccupiesVoxel(a_BlockType); - } - virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, NIBBLETYPE a_Meta) const override { - BLOCKTYPE BelowBlock; - NIBBLETYPE BelowBlockMeta; - a_Chunk.GetBlockTypeMeta(a_Position.addedY(-1), BelowBlock, BelowBlockMeta); - - if ((a_Position.y <= 0) || !CanBeSupportedBy(BelowBlock, BelowBlockMeta)) + if (!Super::CanBeAt(a_Chunk, a_Position, a_Meta)) { return false; } diff --git a/src/Blocks/BlockRedstoneRepeater.h b/src/Blocks/BlockRedstoneRepeater.h index 893691d7b..92b4b3917 100644 --- a/src/Blocks/BlockRedstoneRepeater.h +++ b/src/Blocks/BlockRedstoneRepeater.h @@ -3,10 +3,9 @@ #include "BlockHandler.h" #include "BlockType.h" -#include "Mixins.h" +#include "Mixins/Mixins.h" +#include "Mixins/SolidSurfaceUnderneath.h" #include "ChunkInterface.h" -#include "BlockSlab.h" -#include "BlockStairs.h" #include "../Chunk.h" @@ -14,9 +13,9 @@ class cBlockRedstoneRepeaterHandler final : - public cYawRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03> + public cSolidSurfaceUnderneath<cYawRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03>> { - using Super = cYawRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03>; + using Super = cSolidSurfaceUnderneath<cYawRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03>>; public: @@ -107,41 +106,6 @@ private: - virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override - { - if (a_Position.y <= 0) - { - return false; - } - - BLOCKTYPE BelowBlock; - NIBBLETYPE BelowBlockMeta; - a_Chunk.GetBlockTypeMeta(a_Position.addedY(-1), BelowBlock, BelowBlockMeta); - - if (cBlockInfo::FullyOccupiesVoxel(BelowBlock)) - { - return true; - } - - // upside down slabs - if (cBlockSlabHandler::IsAnySlabType(BelowBlock)) - { - return BelowBlockMeta & E_META_WOODEN_SLAB_UPSIDE_DOWN; - } - - // upside down stairs - if (cBlockStairsHandler::IsAnyStairType(BelowBlock)) - { - return BelowBlockMeta & E_BLOCK_STAIRS_UPSIDE_DOWN; - } - - return false; - } - - - - - virtual cItems ConvertToPickups(const NIBBLETYPE a_BlockMeta, const cItem * const a_Tool) const override { return cItem(E_ITEM_REDSTONE_REPEATER, 1, 0); diff --git a/src/Blocks/BlockRedstoneWire.h b/src/Blocks/BlockRedstoneWire.h index de8e59a40..edea704f4 100644 --- a/src/Blocks/BlockRedstoneWire.h +++ b/src/Blocks/BlockRedstoneWire.h @@ -2,17 +2,15 @@ #pragma once #include "BlockHandler.h" -#include "BlockSlab.h" -#include "BlockStairs.h" -#include "../Chunk.h" +#include "Mixins/SolidSurfaceUnderneath.h" class cBlockRedstoneWireHandler final : - public cBlockHandler + public cSolidSurfaceUnderneath<cBlockHandler> { - using Super = cBlockHandler; + using Super = cSolidSurfaceUnderneath<cBlockHandler>; public: @@ -20,41 +18,6 @@ public: private: - virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override - { - if (a_Position.y <= 0) - { - return false; - } - - BLOCKTYPE BelowBlock; - NIBBLETYPE BelowBlockMeta; - a_Chunk.GetBlockTypeMeta(a_Position.addedY(-1), BelowBlock, BelowBlockMeta); - - if (cBlockInfo::FullyOccupiesVoxel(BelowBlock)) - { - return true; - } - - // upside down slabs - if (cBlockSlabHandler::IsAnySlabType(BelowBlock)) - { - return BelowBlockMeta & E_META_WOODEN_SLAB_UPSIDE_DOWN; - } - - // upside down stairs - if (cBlockStairsHandler::IsAnyStairType(BelowBlock)) - { - return BelowBlockMeta & E_BLOCK_STAIRS_UPSIDE_DOWN; - } - - return false; - } - - - - - virtual cItems ConvertToPickups(const NIBBLETYPE a_BlockMeta, const cItem * const a_Tool) const override { return cItem(E_ITEM_REDSTONE_DUST, 1, 0); diff --git a/src/Blocks/BlockSapling.h b/src/Blocks/BlockSapling.h index d32b9b449..db953946a 100644 --- a/src/Blocks/BlockSapling.h +++ b/src/Blocks/BlockSapling.h @@ -3,15 +3,16 @@ #include "BlockHandler.h" #include "../FastRandom.h" +#include "Mixins/DirtLikeUnderneath.h" class cBlockSaplingHandler final : - public cBlockHandler + public cDirtLikeUnderneath<cBlockHandler> { - using Super = cBlockHandler; + using Super = cDirtLikeUnderneath<cBlockHandler>; public: @@ -29,15 +30,6 @@ private: - virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override - { - return (a_Position.y > 0) && IsBlockTypeOfDirt(a_Chunk.GetBlock(a_Position.addedY(-1))); - } - - - - - virtual void OnUpdate( cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, diff --git a/src/Blocks/BlockSignPost.h b/src/Blocks/BlockSignPost.h index b96498cbd..89da77fbb 100644 --- a/src/Blocks/BlockSignPost.h +++ b/src/Blocks/BlockSignPost.h @@ -30,12 +30,13 @@ private: virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - if (a_Position.y <= 0) + const auto BelowPos = a_Position.addedY(-1); + if (!cChunkDef::IsValidHeight(BelowPos)) { return false; } - BLOCKTYPE Type = a_Chunk.GetBlock(a_Position.addedY(-1)); + BLOCKTYPE Type = a_Chunk.GetBlock(BelowPos); return (Type == E_BLOCK_SIGN_POST) || (Type == E_BLOCK_WALLSIGN) || cBlockInfo::IsSolid(Type); } diff --git a/src/Blocks/BlockSnow.h b/src/Blocks/BlockSnow.h index f3fa87a1b..51361ce17 100644 --- a/src/Blocks/BlockSnow.h +++ b/src/Blocks/BlockSnow.h @@ -69,11 +69,11 @@ private: virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - if (a_Position.y <= 0) + const auto BelowPos = a_Position.addedY(-1); + if (!cChunkDef::IsValidHeight(BelowPos)) { return false; } - auto BelowPos = a_Position.addedY(-1); auto BlockBelow = a_Chunk.GetBlock(BelowPos); auto MetaBelow = a_Chunk.GetMeta(BelowPos); return CanBeOn(BlockBelow, MetaBelow); diff --git a/src/Blocks/BlockStairs.h b/src/Blocks/BlockStairs.h index 76614bb62..6c37a8464 100644 --- a/src/Blocks/BlockStairs.h +++ b/src/Blocks/BlockStairs.h @@ -2,7 +2,7 @@ #pragma once #include "BlockHandler.h" -#include "Mixins.h" +#include "Mixins/Mixins.h" diff --git a/src/Blocks/BlockBanner.h b/src/Blocks/BlockStandingBanner.h index e6a159bd4..0cc7c28eb 100644 --- a/src/Blocks/BlockBanner.h +++ b/src/Blocks/BlockStandingBanner.h @@ -1,19 +1,20 @@ -// BlockBanner.h +// BlockStandingBanner.h #pragma once #include "../BlockInfo.h" #include "BlockEntity.h" +#include "Mixins/SolidSurfaceUnderneath.h" -class cBlockBannerHandler final : - public cBlockEntityHandler +class cBlockStandingBannerHandler final : + public cSolidSurfaceUnderneath<cBlockEntityHandler> { - using Super = cBlockEntityHandler; + using Super = cSolidSurfaceUnderneath<cBlockEntityHandler>; public: @@ -29,20 +30,6 @@ public: - virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override - { - if (a_Position.y < 1) - { - return false; - } - - return cBlockInfo::IsSolid(a_Chunk.GetBlock(a_Position.addedY(-1))); - } - - - - - virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) const override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockStems.h b/src/Blocks/BlockStems.h index 11cd83967..9d598003d 100644 --- a/src/Blocks/BlockStems.h +++ b/src/Blocks/BlockStems.h @@ -58,7 +58,8 @@ private: virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - return (a_Position.y > 0) && (a_Chunk.GetBlock(a_Position.addedY(-1)) == E_BLOCK_FARMLAND); + const auto BelowPos = a_Position.addedY(-1); + return cChunkDef::IsValidHeight(BelowPos) && (a_Chunk.GetBlock(BelowPos) == E_BLOCK_FARMLAND); } diff --git a/src/Blocks/BlockSugarCane.h b/src/Blocks/BlockSugarCane.h index cffe667e5..1f6c8a8fa 100644 --- a/src/Blocks/BlockSugarCane.h +++ b/src/Blocks/BlockSugarCane.h @@ -29,12 +29,13 @@ private: virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - if (a_Position.y <= 0) + const auto BelowPos = a_Position.addedY(-1); + if (!cChunkDef::IsValidHeight(BelowPos)) { return false; } - switch (a_Chunk.GetBlock(a_Position.addedY(-1))) + switch (a_Chunk.GetBlock(BelowPos)) { case E_BLOCK_DIRT: case E_BLOCK_GRASS: @@ -43,16 +44,16 @@ private: { static const Vector3i Coords[] = { - {-1, -1, 0}, - { 1, -1, 0}, - { 0, -1, -1}, - { 0, -1, 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_Position + Coords[i], BlockType, BlockMeta)) + if (!a_Chunk.UnboundedRelGetBlock(BelowPos + Coords[i], BlockType, BlockMeta)) { // Too close to the edge, cannot simulate return true; @@ -90,31 +91,36 @@ private: virtual int Grow(cChunk & a_Chunk, Vector3i a_RelPos, int a_NumStages = 1) const override { // Check the total height of the sugarcane blocks here: - int top = a_RelPos.y + 1; + auto top = a_RelPos.addedY(1); while ( - (top < cChunkDef::Height) && - (a_Chunk.GetBlock({a_RelPos.x, top, a_RelPos.z}) == E_BLOCK_SUGARCANE) + cChunkDef::IsValidHeight(top) && + (a_Chunk.GetBlock(top) == E_BLOCK_SUGARCANE) ) { - ++top; + ++top.y; } - int bottom = a_RelPos.y - 1; + auto bottom = a_RelPos.addedY(-1); while ( - (bottom > 0) && - (a_Chunk.GetBlock({a_RelPos.x, bottom, a_RelPos.z}) == E_BLOCK_SUGARCANE) + cChunkDef::IsValidHeight(bottom) && + (a_Chunk.GetBlock(bottom) == E_BLOCK_SUGARCANE) ) { - --bottom; + --bottom.y; } // Grow by at most a_NumStages, but no more than max height: - auto toGrow = std::min(a_NumStages, a_Chunk.GetWorld()->GetMaxSugarcaneHeight() + 1 - (top - bottom)); - Vector3i topPos(a_RelPos.x, top, a_RelPos.z); + auto toGrow = std::min(a_NumStages, a_Chunk.GetWorld()->GetMaxSugarcaneHeight() + 1 - (top.y - bottom.y)); for (int i = 0; i < toGrow; i++) { - if (a_Chunk.GetBlock(topPos.addedY(i)) == E_BLOCK_AIR) + const auto NewTop = top.addedY(i); + if (!cChunkDef::IsValidHeight(NewTop)) { - a_Chunk.SetBlock(topPos.addedY(i), E_BLOCK_SUGARCANE, 0); + return i; + } + + if (a_Chunk.GetBlock(NewTop) == E_BLOCK_AIR) + { + a_Chunk.SetBlock(NewTop, E_BLOCK_SUGARCANE, 0); } else { diff --git a/src/Blocks/BlockTallGrass.h b/src/Blocks/BlockTallGrass.h index ea638c878..47ad2f93d 100644 --- a/src/Blocks/BlockTallGrass.h +++ b/src/Blocks/BlockTallGrass.h @@ -2,6 +2,7 @@ #pragma once #include "BlockHandler.h" +#include "Mixins/DirtLikeUnderneath.h" #include "ChunkInterface.h" @@ -10,9 +11,9 @@ /** Handles the grass that is 1 block tall */ class cBlockTallGrassHandler final : - public cBlockHandler + public cDirtLikeUnderneath<cBlockHandler> { - using Super = cBlockHandler; + using Super = cDirtLikeUnderneath<cBlockHandler>; public: @@ -52,25 +53,11 @@ private: - virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override - { - if (a_Position.y <= 0) - { - return false; - } - - BLOCKTYPE BelowBlock = a_Chunk.GetBlock(a_Position.addedY(-1)); - return IsBlockTypeOfDirt(BelowBlock); - } - - - - - /** Growing a tall grass produces a big flower (2-block high fern or double-tall grass). */ virtual int Grow(cChunk & a_Chunk, Vector3i a_RelPos, int a_NumStages = 1) const override { - if (a_RelPos.y > (cChunkDef::Height - 2)) + const auto TopPos = a_RelPos.addedY(1); + if (!cChunkDef::IsValidHeight(TopPos)) { return 0; } @@ -83,7 +70,7 @@ private: default: return 0; } a_Chunk.SetBlock(a_RelPos, E_BLOCK_BIG_FLOWER, largeFlowerMeta); - a_Chunk.SetBlock(a_RelPos.addedY(1), E_BLOCK_BIG_FLOWER, E_META_BIG_FLOWER_TOP); + a_Chunk.SetBlock(TopPos, E_BLOCK_BIG_FLOWER, E_META_BIG_FLOWER_TOP); return 1; } diff --git a/src/Blocks/BlockTorch.h b/src/Blocks/BlockTorch.h index ad69cf5eb..99f685cb6 100644 --- a/src/Blocks/BlockTorch.h +++ b/src/Blocks/BlockTorch.h @@ -7,7 +7,7 @@ #include "BlockType.h" #include "ChunkInterface.h" #include "Defines.h" -#include "Mixins.h" +#include "Mixins/Mixins.h" @@ -126,7 +126,7 @@ private: NIBBLETYPE NeighborBlockMeta; if (!a_Chunk.UnboundedRelGetBlock(NeighborRelPos, NeighborBlockType, NeighborBlockMeta)) { - // Neighbor in an unloaded chunk, bail out without changint this. + // Neighbor in an unloaded chunk, bail out without changing this. return false; } diff --git a/src/Blocks/BlockTrapdoor.h b/src/Blocks/BlockTrapdoor.h index 7f6f70e1e..3fb4f4ca3 100644 --- a/src/Blocks/BlockTrapdoor.h +++ b/src/Blocks/BlockTrapdoor.h @@ -2,7 +2,7 @@ #pragma once #include "BlockHandler.h" -#include "Mixins.h" +#include "Mixins/Mixins.h" #include "../EffectID.h" diff --git a/src/Blocks/BlockTripwireHook.h b/src/Blocks/BlockTripwireHook.h index ae553d66f..ede6ca311 100644 --- a/src/Blocks/BlockTripwireHook.h +++ b/src/Blocks/BlockTripwireHook.h @@ -1,7 +1,7 @@ #pragma once #include "BlockHandler.h" -#include "Mixins.h" +#include "Mixins/Mixins.h" diff --git a/src/Blocks/BlockVines.h b/src/Blocks/BlockVines.h index a23ba1489..edbd30f36 100644 --- a/src/Blocks/BlockVines.h +++ b/src/Blocks/BlockVines.h @@ -119,15 +119,16 @@ private: } // Check if vine above us, add its meta to MaxMeta: - if ((a_Position.y < cChunkDef::Height - 1) && (a_Chunk.GetBlock(a_Position.addedY(1)) == E_BLOCK_VINES)) + const auto AbovePos = a_Position.addedY(1); + if (cChunkDef::IsValidHeight(AbovePos) && (a_Chunk.GetBlock(AbovePos) == E_BLOCK_VINES)) { - MaxMeta |= a_Chunk.GetMeta(a_Position.addedY(1)); + MaxMeta |= a_Chunk.GetMeta(AbovePos); } NIBBLETYPE Common = a_CurrentMeta & MaxMeta; // Neighbors that we have and are legal. if (Common != a_CurrentMeta) { - bool HasTop = (a_Position.y < (cChunkDef::Height - 1)) && IsBlockAttachable(a_Chunk.GetBlock(a_Position.addedY(1))); + bool HasTop = cChunkDef::IsValidHeight(AbovePos) && IsBlockAttachable(a_Chunk.GetBlock(AbovePos)); if ((Common == 0) && !HasTop) // Meta equals 0 also means top. Make a last-ditch attempt to save the vine. { return VINE_LOST_SUPPORT; diff --git a/src/Blocks/BlockWallBanner.h b/src/Blocks/BlockWallBanner.h new file mode 100644 index 000000000..e0ebb8eee --- /dev/null +++ b/src/Blocks/BlockWallBanner.h @@ -0,0 +1,64 @@ + +// BlockWallBanner.h + +#pragma once + +#include "../BlockInfo.h" +#include "BlockEntity.h" + + + + + +class cBlockWallBannerHandler final : + public cBlockEntityHandler +{ + using Super = cBlockEntityHandler; + +public: + + using Super::Super; + + virtual cItems ConvertToPickups(const NIBBLETYPE a_BlockMeta, const cItem * const a_Tool) const override + { + // Drops handled by the block entity: + return {}; + } + + + + + + virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override + { + Vector3i Offset; + + switch (a_Meta) + { + case BLOCK_FACE_ZM: Offset = Vector3i( 0, 0, 1); break; + case BLOCK_FACE_ZP: Offset = Vector3i( 0, 0, -1); break; + case BLOCK_FACE_XM: Offset = Vector3i( 1, 0, 0); break; + case BLOCK_FACE_XP: Offset = Vector3i(-1, 0, 0); break; + default: return false; + } + + auto NeighborPos = a_Position + Offset; + BLOCKTYPE NeighborType; + if (!a_Chunk.UnboundedRelGetBlockType(NeighborPos, NeighborType)) + { + // The neighbour is not accessible (unloaded chunk), we'll allow it for now. + return true; + } + return cBlockInfo::IsSolid(NeighborType); + } + + + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) const override + { + UNUSED(a_Meta); + return 0; + } +} ; diff --git a/src/Blocks/CMakeLists.txt b/src/Blocks/CMakeLists.txt index a7dd7b675..7e3047451 100644 --- a/src/Blocks/CMakeLists.txt +++ b/src/Blocks/CMakeLists.txt @@ -9,7 +9,6 @@ target_sources( BlockAir.h BlockAnvil.h - BlockBanner.h BlockBed.h BlockBigFlower.h BlockBookShelf.h @@ -94,6 +93,7 @@ target_sources( BlockSnow.h BlockSponge.h BlockStairs.h + BlockStandingBanner.h BlockStems.h BlockStone.h BlockSugarCane.h @@ -104,11 +104,12 @@ target_sources( BlockTripwire.h BlockTripwireHook.h BlockVines.h + BlockWallBanner.h BlockWallSign.h BlockWorkbench.h BroadcastInterface.h ChunkInterface.h GetHandlerCompileTimeTemplate.h - Mixins.h + Mixins/Mixins.h WorldInterface.h ) diff --git a/src/Blocks/Mixins/DirtLikeUnderneath.h b/src/Blocks/Mixins/DirtLikeUnderneath.h new file mode 100644 index 000000000..909f1601e --- /dev/null +++ b/src/Blocks/Mixins/DirtLikeUnderneath.h @@ -0,0 +1,42 @@ + +#pragma once + +#include "../../Chunk.h" + +/** Mixin to ensure the block has a dirt-like block underneath. */ +template <class Base> +class cDirtLikeUnderneath : + public Base +{ + using Super = Base; +public: + + using Super::Super; + + constexpr cDirtLikeUnderneath(BLOCKTYPE a_BlockType): + Base(a_BlockType) + { + } + +protected: + + ~cDirtLikeUnderneath() = default; + +protected: + + virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override + { + if (!Super::CanBeAt(a_Chunk, a_Position, a_Meta)) + { + return false; + } + + const auto BelowPos = a_Position.addedY(-1); + if (!cChunkDef::IsValidHeight(BelowPos)) + { + return false; + } + + return IsBlockTypeOfDirt(a_Chunk.GetBlock(BelowPos)); + } +}; diff --git a/src/Blocks/Mixins.h b/src/Blocks/Mixins/Mixins.h index fa8985737..d9a233bad 100644 --- a/src/Blocks/Mixins.h +++ b/src/Blocks/Mixins/Mixins.h @@ -9,7 +9,7 @@ class cBlockLadder: public cMetaRotator<cClearMetaOnDrop, ...> #pragma once -#include "../Item.h" +#include "../../Item.h" diff --git a/src/Blocks/Mixins/SolidSurfaceUnderneath.h b/src/Blocks/Mixins/SolidSurfaceUnderneath.h new file mode 100644 index 000000000..c54c064d6 --- /dev/null +++ b/src/Blocks/Mixins/SolidSurfaceUnderneath.h @@ -0,0 +1,65 @@ + +#pragma once + +#include "../../Chunk.h" +#include "../BlockSlab.h" +#include "../BlockStairs.h" + +/** Mixin to ensure the block has a solid surface underneath. */ +template <class Base> +class cSolidSurfaceUnderneath : + public Base +{ + using Super = Base; +public: + + using Super::Super; + + constexpr cSolidSurfaceUnderneath(BLOCKTYPE a_BlockType): + Base(a_BlockType) + { + } + +protected: + + ~cSolidSurfaceUnderneath() = default; + +protected: + + virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override + { + if (!Super::CanBeAt(a_Chunk, a_Position, a_Meta)) + { + return false; + } + + const auto BelowPos = a_Position.addedY(-1); + if (!cChunkDef::IsValidHeight(BelowPos)) + { + return false; + } + + BLOCKTYPE BelowBlock; + NIBBLETYPE BelowBlockMeta; + a_Chunk.GetBlockTypeMeta(BelowPos, BelowBlock, BelowBlockMeta); + + if (cBlockInfo::FullyOccupiesVoxel(BelowBlock)) + { + return true; + } + + // upside down slabs + if (cBlockSlabHandler::IsAnySlabType(BelowBlock)) + { + return BelowBlockMeta & E_META_WOODEN_SLAB_UPSIDE_DOWN; + } + + // upside down stairs + if (cBlockStairsHandler::IsAnyStairType(BelowBlock)) + { + return BelowBlockMeta & E_BLOCK_STAIRS_UPSIDE_DOWN; + } + + return false; + } +}; diff --git a/src/ByteBuffer.cpp b/src/ByteBuffer.cpp index 8121fc3ef..c5fe0a7c0 100644 --- a/src/ByteBuffer.cpp +++ b/src/ByteBuffer.cpp @@ -285,10 +285,9 @@ bool cByteBuffer::ReadBEInt16(Int16 & a_Value) CHECK_THREAD CheckValid(); NEEDBYTES(2); - UInt16 val; - ReadBuf(&val, 2); - val = ntohs(val); - memcpy(&a_Value, &val, 2); + Bytes<Int16> bytes; + ReadBuf(bytes.data(), bytes.size()); + a_Value = NetworkToHost<Int16>(bytes); return true; } @@ -301,8 +300,9 @@ bool cByteBuffer::ReadBEUInt16(UInt16 & a_Value) CHECK_THREAD CheckValid(); NEEDBYTES(2); - ReadBuf(&a_Value, 2); - a_Value = ntohs(a_Value); + Bytes<UInt16> bytes; + ReadBuf(bytes.data(), bytes.size()); + a_Value = NetworkToHost<UInt16>(bytes); return true; } @@ -315,10 +315,9 @@ bool cByteBuffer::ReadBEInt32(Int32 & a_Value) CHECK_THREAD CheckValid(); NEEDBYTES(4); - UInt32 val; - ReadBuf(&val, 4); - val = ntohl(val); - memcpy(&a_Value, &val, 4); + Bytes<Int32> bytes; + ReadBuf(bytes.data(), bytes.size()); + a_Value = NetworkToHost<Int32>(bytes); return true; } @@ -331,8 +330,9 @@ bool cByteBuffer::ReadBEUInt32(UInt32 & a_Value) CHECK_THREAD CheckValid(); NEEDBYTES(4); - ReadBuf(&a_Value, 4); - a_Value = ntohl(a_Value); + Bytes<UInt32> bytes; + ReadBuf(bytes.data(), bytes.size()); + a_Value = NetworkToHost<UInt32>(bytes); return true; } @@ -345,8 +345,9 @@ bool cByteBuffer::ReadBEInt64(Int64 & a_Value) CHECK_THREAD CheckValid(); NEEDBYTES(8); - ReadBuf(&a_Value, 8); - a_Value = NetworkToHostLong8(&a_Value); + Bytes<Int64> bytes; + ReadBuf(bytes.data(), bytes.size()); + a_Value = NetworkToHost<Int64>(bytes); return true; } @@ -359,8 +360,9 @@ bool cByteBuffer::ReadBEUInt64(UInt64 & a_Value) CHECK_THREAD CheckValid(); NEEDBYTES(8); - ReadBuf(&a_Value, 8); - a_Value = NetworkToHostULong8(&a_Value); + Bytes<UInt64> bytes; + ReadBuf(bytes.data(), bytes.size()); + a_Value = NetworkToHost<UInt64>(bytes); return true; } @@ -373,8 +375,9 @@ bool cByteBuffer::ReadBEFloat(float & a_Value) CHECK_THREAD CheckValid(); NEEDBYTES(4); - ReadBuf(&a_Value, 4); - a_Value = NetworkToHostFloat4(&a_Value); + Bytes<float> bytes; + ReadBuf(bytes.data(), bytes.size()); + a_Value = NetworkToHost<float>(bytes); return true; } @@ -387,8 +390,9 @@ bool cByteBuffer::ReadBEDouble(double & a_Value) CHECK_THREAD CheckValid(); NEEDBYTES(8); - ReadBuf(&a_Value, 8); - a_Value = NetworkToHostDouble8(&a_Value); + Bytes<double> bytes; + ReadBuf(bytes.data(), bytes.size()); + a_Value = NetworkToHost<double>(bytes); return true; } @@ -629,10 +633,8 @@ bool cByteBuffer::WriteBEInt16(Int16 a_Value) CHECK_THREAD CheckValid(); PUTBYTES(2); - UInt16 val; - memcpy(&val, &a_Value, 2); - val = htons(val); - return WriteBuf(&val, 2); + auto Converted = HostToNetwork(a_Value); + return WriteBuf(Converted.data(), Converted.size()); } @@ -644,8 +646,8 @@ bool cByteBuffer::WriteBEUInt16(UInt16 a_Value) CHECK_THREAD CheckValid(); PUTBYTES(2); - a_Value = htons(a_Value); - return WriteBuf(&a_Value, 2); + auto Converted = HostToNetwork(a_Value); + return WriteBuf(Converted.data(), Converted.size()); } @@ -657,8 +659,8 @@ bool cByteBuffer::WriteBEInt32(Int32 a_Value) CHECK_THREAD CheckValid(); PUTBYTES(4); - UInt32 Converted = HostToNetwork4(&a_Value); - return WriteBuf(&Converted, 4); + auto Converted = HostToNetwork(a_Value); + return WriteBuf(Converted.data(), Converted.size()); } @@ -670,8 +672,8 @@ bool cByteBuffer::WriteBEUInt32(UInt32 a_Value) CHECK_THREAD CheckValid(); PUTBYTES(4); - UInt32 Converted = HostToNetwork4(&a_Value); - return WriteBuf(&Converted, 4); + auto Converted = HostToNetwork(a_Value); + return WriteBuf(Converted.data(), Converted.size()); } @@ -683,8 +685,8 @@ bool cByteBuffer::WriteBEInt64(Int64 a_Value) CHECK_THREAD CheckValid(); PUTBYTES(8); - UInt64 Converted = HostToNetwork8(&a_Value); - return WriteBuf(&Converted, 8); + auto Converted = HostToNetwork(a_Value); + return WriteBuf(Converted.data(), Converted.size()); } @@ -696,8 +698,8 @@ bool cByteBuffer::WriteBEUInt64(UInt64 a_Value) CHECK_THREAD CheckValid(); PUTBYTES(8); - UInt64 Converted = HostToNetwork8(&a_Value); - return WriteBuf(&Converted, 8); + auto Converted = HostToNetwork(a_Value); + return WriteBuf(Converted.data(), Converted.size()); } @@ -709,8 +711,8 @@ bool cByteBuffer::WriteBEFloat(float a_Value) CHECK_THREAD CheckValid(); PUTBYTES(4); - UInt32 Converted = HostToNetwork4(&a_Value); - return WriteBuf(&Converted, 4); + auto Converted = HostToNetwork(a_Value); + return WriteBuf(Converted.data(), Converted.size()); } @@ -722,8 +724,8 @@ bool cByteBuffer::WriteBEDouble(double a_Value) CHECK_THREAD CheckValid(); PUTBYTES(8); - UInt64 Converted = HostToNetwork8(&a_Value); - return WriteBuf(&Converted, 8); + auto Converted = HostToNetwork(a_Value); + return WriteBuf(Converted.data(), Converted.size()); } diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp index a2bc50fe9..d982d0cf3 100644 --- a/src/ChunkMap.cpp +++ b/src/ChunkMap.cpp @@ -474,6 +474,11 @@ void cChunkMap::CollectPickupsByEntity(cEntity & a_Entity) BLOCKTYPE cChunkMap::GetBlock(Vector3i a_BlockPos) const { + if (!cChunkDef::IsValidHeight(a_BlockPos)) + { + return 0; + } + auto chunkPos = cChunkDef::BlockToChunk(a_BlockPos); auto relPos = cChunkDef::AbsoluteToRelative(a_BlockPos, chunkPos); @@ -493,6 +498,11 @@ BLOCKTYPE cChunkMap::GetBlock(Vector3i a_BlockPos) const NIBBLETYPE cChunkMap::GetBlockMeta(Vector3i a_BlockPos) const { + if (!cChunkDef::IsValidHeight(a_BlockPos)) + { + return 0; + } + auto chunkPos = cChunkDef::BlockToChunk(a_BlockPos); auto relPos = cChunkDef::AbsoluteToRelative(a_BlockPos, chunkPos); @@ -585,6 +595,14 @@ void cChunkMap::SetBlock(Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE bool cChunkMap::GetBlockTypeMeta(Vector3i a_BlockPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) const { + if (!cChunkDef::IsValidHeight(a_BlockPos)) + { + // Initialise the params to fulfil our contract. + a_BlockType = 0; + a_BlockMeta = 0; + return false; + } + auto chunkCoord = cChunkDef::BlockToChunk(a_BlockPos); auto relPos = cChunkDef::AbsoluteToRelative(a_BlockPos, chunkCoord); @@ -595,6 +613,10 @@ bool cChunkMap::GetBlockTypeMeta(Vector3i a_BlockPos, BLOCKTYPE & a_BlockType, N Chunk->GetBlockTypeMeta(relPos, a_BlockType, a_BlockMeta); return true; } + + // Initialise the params to fulfil our contract. + a_BlockType = 0; + a_BlockMeta = 0; return false; } diff --git a/src/ChunkMap.h b/src/ChunkMap.h index 578c49b8a..8538b7624 100644 --- a/src/ChunkMap.h +++ b/src/ChunkMap.h @@ -115,6 +115,10 @@ public: void SetBlockMeta(Vector3i a_BlockPos, NIBBLETYPE a_BlockMeta); void SetBlock (Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); + /** Get the block type and meta at the specified coords + Will always initialise a_BlockType and a_BlockMeta if called. + Returns false if the data could not be retrieved, either because the chunk is invalid or the height is invalid. + Otherwise, returns true. */ bool GetBlockTypeMeta (Vector3i a_BlockPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) const; bool GetBlockInfo (Vector3i, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_Meta, NIBBLETYPE & a_SkyLight, NIBBLETYPE & a_BlockLight) const; diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index b726e5c6f..2b32c5c07 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -74,6 +74,7 @@ cClientHandle::cClientHandle(const AString & a_IPString, int a_ViewDistance) : m_IPString(a_IPString), m_Player(nullptr), m_CachedSentChunk(std::numeric_limits<decltype(m_CachedSentChunk.m_ChunkX)>::max(), std::numeric_limits<decltype(m_CachedSentChunk.m_ChunkZ)>::max()), + m_ProxyConnection(false), m_HasSentDC(false), m_LastStreamedChunkX(std::numeric_limits<decltype(m_LastStreamedChunkX)>::max()), // bogus chunk coords to force streaming upon login m_LastStreamedChunkZ(std::numeric_limits<decltype(m_LastStreamedChunkZ)>::max()), @@ -1253,7 +1254,10 @@ void cClientHandle::HandleBlockDigStarted(Vector3i a_BlockPos, eBlockFace a_Bloc BLOCKTYPE DiggingBlock; NIBBLETYPE DiggingMeta; - m_Player->GetWorld()->GetBlockTypeMeta(a_BlockPos, DiggingBlock, DiggingMeta); + if (!m_Player->GetWorld()->GetBlockTypeMeta(a_BlockPos, DiggingBlock, DiggingMeta)) + { + return; + } if ( m_Player->IsGameModeCreative() && @@ -1321,7 +1325,10 @@ void cClientHandle::HandleBlockDigFinished(Vector3i a_BlockPos, eBlockFace a_Blo BLOCKTYPE DugBlock; NIBBLETYPE DugMeta; - m_Player->GetWorld()->GetBlockTypeMeta(a_BlockPos, DugBlock, DugMeta); + if (!m_Player->GetWorld()->GetBlockTypeMeta(a_BlockPos, DugBlock, DugMeta)) + { + return; + } if (!m_Player->IsGameModeCreative()) { diff --git a/src/Endianness.h b/src/Endianness.h index 0e8bc8e99..c75698587 100644 --- a/src/Endianness.h +++ b/src/Endianness.h @@ -1,86 +1,143 @@ - #pragma once -#undef ntohll -#define ntohll(x) (((static_cast<UInt64>(ntohl(static_cast<UInt32>(x)))) << 32) + ntohl(x >> 32)) - - - - - -// Changes endianness -inline UInt64 HostToNetwork8(const void * a_Value) +#include <array> +template <typename T> +using Bytes = std::array<std::byte, sizeof(T)>; + +// bit_cast used for going between ulong, float, etc. It's a new C++20 feature +#ifdef __cpp_lib_bit_cast +#include <bit> +using std::bit_cast; + +// Fallback in case we're using C++17 +#else +// bit-for-bit convert one type to another. In C++ the only non-UB way to do this is *memcpy*. Nearly every other +// option is a strict aliasing violation. +template<class To, class From> +std::enable_if_t< + sizeof(To) == sizeof(From), + To> +bit_cast(const From &src) noexcept { - UInt64 buf; - memcpy( &buf, a_Value, sizeof( buf)); - buf = (( ( static_cast<UInt64>(htonl(static_cast<UInt32>(buf)))) << 32) + htonl(buf >> 32)); - return buf; + To dst; + std::memcpy(&dst, &src, sizeof(To)); + return dst; } +#endif - - - -inline UInt32 HostToNetwork4(const void * a_Value) +/** Converts a 16-bit host integer or float value to bytes in big-endian (Network) order. +@tparam Value The host 16-bit type (Int16, UInt16). Usually inferred. +@param a_Value The input integer or float value. +@return The resulting bytes. */ +template<typename Value, std::enable_if_t<sizeof(Value) == 2, bool> = true> +inline Bytes<Value> HostToNetwork(Value a_Value) { - UInt32 buf; - memcpy( &buf, a_Value, sizeof( buf)); - buf = ntohl( buf); - return buf; + UInt16 Bits = bit_cast<UInt16>(a_Value); + return + { + std::byte(Bits >> 8), + std::byte(Bits) + }; } - - - - -inline double NetworkToHostDouble8(const void * a_Value) +/** Converts a 32-bit host integer or float value to bytes in big-endian (Network) order. +@tparam Value The host 32-bit type (Int32, UInt32, float). Usually inferred. +@param a_Value The input integer or float value. +@return The resulting bytes. */ +template<typename Value, std::enable_if_t<sizeof(Value) == 4, bool> = true> +inline Bytes<Value> HostToNetwork(Value a_Value) { - UInt64 buf = 0; - memcpy(&buf, a_Value, 8); - buf = ntohll(buf); - double x; - memcpy(&x, &buf, sizeof(double)); - return x; + UInt32 Bits = bit_cast<UInt32>(a_Value); + return + { + std::byte(Bits >> 24), + std::byte(Bits >> 16), + std::byte(Bits >> 8), + std::byte(Bits) + }; } - - - - -inline Int64 NetworkToHostLong8(const void * a_Value) +/** Converts a 64-bit host integer or float value to bytes in big-endian (Network) order. +@tparam Value The host 64-bit type (Int64, UInt64, double). Usually inferred. +@param a_Value The input integer or float value. +@return The resulting bytes. */ +template<typename Value, std::enable_if_t<sizeof(Value) == 8, bool> = true> +inline Bytes<Value> HostToNetwork(Value a_Value) { - UInt64 buf; - memcpy(&buf, a_Value, 8); - buf = ntohll(buf); - return *reinterpret_cast<Int64 *>(&buf); + UInt64 Bits = bit_cast<UInt64>(a_Value); + return + { + std::byte(Bits >> 56), + std::byte(Bits >> 48), + std::byte(Bits >> 40), + std::byte(Bits >> 32), + std::byte(Bits >> 24), + std::byte(Bits >> 16), + std::byte(Bits >> 8), + std::byte(Bits) + }; } - - - - -inline UInt64 NetworkToHostULong8(const void * a_Value) +/** Reads a 16-bit integer or float value from big-endian (Network) bytes. +@tparam Value The desired 16-bit type (Int16, UInt16) +@param a_Value The input bytes. +@return The resulting integer or float value. */ +template<typename Value, std::enable_if_t<sizeof(Value) == 2, bool> = true> +inline Value NetworkToHost(Bytes<Value> a_Value) { - UInt64 buf; - memcpy(&buf, a_Value, 8); - buf = ntohll(buf); - return buf; + UInt16 val = UInt16( + UInt16(a_Value[0]) << 8 | + UInt16(a_Value[1])); + return bit_cast<Value>(val); } - - - - -inline float NetworkToHostFloat4(const void * a_Value) +/** Reads a 32-bit integer or float value from big-endian (Network) bytes. +@tparam Value The desired 32-bit type (Int32, UInt32, float) +@param a_Value The input bytes. +@return The resulting integer or float value. */ +template<typename Value, std::enable_if_t<sizeof(Value) == 4, bool> = true> +inline Value NetworkToHost(Bytes<Value> a_Value) { - UInt32 buf; - float x; - memcpy(&buf, a_Value, 4); - buf = ntohl(buf); - memcpy(&x, &buf, sizeof(float)); - return x; + UInt32 val = UInt32( + UInt32(a_Value[0]) << 24 | + UInt32(a_Value[1]) << 16 | + UInt32(a_Value[2]) << 8 | + UInt32(a_Value[3])); + return bit_cast<Value>(val); } +/** Reads a 64-bit integer or float value from big-endian (Network) bytes. +@tparam Value The desired 64-bit type (Int64, UInt64, double) +@param a_Value The input bytes. +@return The resulting integer or float value. */ +template<typename Value, std::enable_if_t<sizeof(Value) == 8, bool> = true> +inline Value NetworkToHost(Bytes<Value> a_Value) +{ + UInt64 val = UInt64( + UInt64(a_Value[0]) << 56 | + UInt64(a_Value[1]) << 48 | + UInt64(a_Value[2]) << 40 | + UInt64(a_Value[3]) << 32 | + UInt64(a_Value[4]) << 24 | + UInt64(a_Value[5]) << 16 | + UInt64(a_Value[6]) << 8 | + UInt64(a_Value[7])); + return bit_cast<Value>(val); +} +/** Reads an integer or float type from its big-endian (Network) bytes. +@tparam Value The desired result type (Int16 / 32 / 64, UInt16 / 32 / 64, float, double). +@param a_Mem A pointer to the first input byte. Length is inferred from the result type. +@return The resulting integer or float value. - +Consider using NetworkToHost when the data is owned since it provides additional type safety (length is known). */ +template<typename Value> +inline Value NetworkBufToHost(const std::byte* a_Mem) +{ + // Copy unfortunately needed to add the length information required by the rest of the API. + // Gets completely optimised out in my testing. + Bytes<Value> bytes; + std::copy(a_Mem, a_Mem + sizeof(Value), bytes.begin()); + return NetworkToHost<Value>(bytes); +} diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index c580d8293..50fd034a5 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -982,6 +982,13 @@ void cPlayer::Respawn(void) TeleportToCoords(m_RespawnPosition.x, m_RespawnPosition.y, m_RespawnPosition.z); } + // The Notchian client enters a weird glitched state when trying to "resurrect" dead players + // To prevent that, destroy the existing client-side entity, and create a new one with the same ID + // This does not make any difference to more modern clients + m_World->BroadcastDestroyEntity(*this, &*m_ClientHandle); + m_World->BroadcastSpawnEntity(*this, &*m_ClientHandle); + + SetVisible(true); } @@ -2587,9 +2594,10 @@ bool cPlayer::IsInsideWater() BLOCKTYPE Block; NIBBLETYPE Meta; - m_World->GetBlockTypeMeta(EyePos, Block, Meta); - - if ((Block != E_BLOCK_WATER) && (Block != E_BLOCK_STATIONARY_WATER)) + if ( + !m_World->GetBlockTypeMeta(GetEyePosition().Floor(), Block, Meta) || + ((Block != E_BLOCK_WATER) && (Block != E_BLOCK_STATIONARY_WATER)) + ) { return false; } diff --git a/src/Generating/CompoGenBiomal.cpp b/src/Generating/CompoGenBiomal.cpp index 967a4a89c..fb7b89422 100644 --- a/src/Generating/CompoGenBiomal.cpp +++ b/src/Generating/CompoGenBiomal.cpp @@ -456,7 +456,10 @@ protected: } HasHadWater = true; } // for y - a_ChunkDesc.SetBlockType(a_RelX, 0, a_RelZ, E_BLOCK_BEDROCK); + if (a_ShapeColumn[0] > 0) + { + a_ChunkDesc.SetBlockType(a_RelX, 0, a_RelZ, E_BLOCK_BEDROCK); + } } diff --git a/src/Items/ItemBed.h b/src/Items/ItemBed.h index a2e254171..77818e7c7 100644 --- a/src/Items/ItemBed.h +++ b/src/Items/ItemBed.h @@ -27,7 +27,10 @@ public: auto & World = *a_Player.GetWorld(); BLOCKTYPE HeadType; NIBBLETYPE HeadMeta; - World.GetBlockTypeMeta(HeadPosition, HeadType, HeadMeta); + if (!World.GetBlockTypeMeta(HeadPosition, HeadType, HeadMeta)) + { + return false; + } // Vanilla only allows beds to be placed into air. // Check if there is empty space for the "head" block: diff --git a/src/Items/ItemBigFlower.h b/src/Items/ItemBigFlower.h index cbdecbed7..a135a220d 100644 --- a/src/Items/ItemBigFlower.h +++ b/src/Items/ItemBigFlower.h @@ -29,7 +29,10 @@ public: const auto TopPos = a_PlacePosition.addedY(1); BLOCKTYPE TopType; NIBBLETYPE TopMeta; - World.GetBlockTypeMeta(TopPos, TopType, TopMeta); + if (!World.GetBlockTypeMeta(TopPos, TopType, TopMeta)) + { + return false; + } if (!cBlockHandler::For(TopType).DoesIgnoreBuildCollision(World, a_HeldItem, TopPos, TopMeta, a_ClickedBlockFace, false)) { diff --git a/src/Items/ItemDoor.h b/src/Items/ItemDoor.h index 6538a5bef..f28d3ad36 100644 --- a/src/Items/ItemDoor.h +++ b/src/Items/ItemDoor.h @@ -54,7 +54,10 @@ public: { BLOCKTYPE TopType; NIBBLETYPE TopMeta; - World.GetBlockTypeMeta(UpperBlockPosition, TopType, TopMeta); + if (!World.GetBlockTypeMeta(UpperBlockPosition, TopType, TopMeta)) + { + return false; + } if (!cBlockHandler::For(TopType).DoesIgnoreBuildCollision(World, a_HeldItem, UpperBlockPosition, TopMeta, a_ClickedBlockFace, false)) { diff --git a/src/Items/ItemDye.h b/src/Items/ItemDye.h index 636a1b477..b0f00b9ba 100644 --- a/src/Items/ItemDye.h +++ b/src/Items/ItemDye.h @@ -54,10 +54,12 @@ public: // Cocoa (brown dye) can be planted on jungle logs: BLOCKTYPE BlockType; NIBBLETYPE 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 & 0x03) != E_META_LOG_JUNGLE)) + if ( + !a_World->GetBlockTypeMeta(a_ClickedBlockPos, BlockType, BlockMeta) || + ((BlockType != E_BLOCK_LOG) || ((BlockMeta & 0x03) != E_META_LOG_JUNGLE)) + ) { return false; } diff --git a/src/Items/ItemEyeOfEnder.h b/src/Items/ItemEyeOfEnder.h index fc6fac336..414d81c39 100644 --- a/src/Items/ItemEyeOfEnder.h +++ b/src/Items/ItemEyeOfEnder.h @@ -35,8 +35,8 @@ public: { BLOCKTYPE FacingBlock; NIBBLETYPE FacingMeta; - a_World->GetBlockTypeMeta(a_ClickedBlockPos, FacingBlock, FacingMeta); - if (FacingBlock == E_BLOCK_END_PORTAL_FRAME) + + if (a_World->GetBlockTypeMeta(a_ClickedBlockPos, FacingBlock, FacingMeta) && (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) diff --git a/src/Items/ItemHoe.h b/src/Items/ItemHoe.h index 2bca5f5ca..503047328 100644 --- a/src/Items/ItemHoe.h +++ b/src/Items/ItemHoe.h @@ -46,7 +46,10 @@ public: // Can only transform dirt or grass blocks: BLOCKTYPE BlockType; NIBBLETYPE BlockMeta; - a_World->GetBlockTypeMeta(a_ClickedBlockPos, BlockType, BlockMeta); + if (!a_World->GetBlockTypeMeta(a_ClickedBlockPos, BlockType, BlockMeta)) + { + return false; + } if ((BlockType != E_BLOCK_DIRT) && (BlockType != E_BLOCK_GRASS)) { return false; diff --git a/src/Items/ItemShears.h b/src/Items/ItemShears.h index 5f8e9e2f1..00504884c 100644 --- a/src/Items/ItemShears.h +++ b/src/Items/ItemShears.h @@ -32,7 +32,10 @@ public: { BLOCKTYPE Block; NIBBLETYPE BlockMeta; - a_World->GetBlockTypeMeta(a_ClickedBlockPos, Block, BlockMeta); + if (!a_World->GetBlockTypeMeta(a_ClickedBlockPos, Block, BlockMeta)) + { + return false; + } if ((Block == E_BLOCK_LEAVES) || (Block == E_BLOCK_NEW_LEAVES)) { diff --git a/src/Map.cpp b/src/Map.cpp index 9e3c364b1..3691d0ab0 100644 --- a/src/Map.cpp +++ b/src/Map.cpp @@ -23,6 +23,7 @@ cMap::cMap(unsigned int a_ID, cWorld * a_World): m_Scale(3), m_CenterX(0), m_CenterZ(0), + m_Dirty(false), // This constructor is for an empty map object which will be filled by the caller with the correct values - it does not need saving. m_World(a_World), m_Name(fmt::format(FMT_STRING("map_{}"), m_ID)) { @@ -40,6 +41,7 @@ cMap::cMap(unsigned int a_ID, int a_CenterX, int a_CenterZ, cWorld * a_World, un m_Scale(a_Scale), m_CenterX(a_CenterX), m_CenterZ(a_CenterZ), + m_Dirty(true), // This constructor is for creating a brand new map in game, it will always need saving. m_World(a_World), m_Name(fmt::format(FMT_STRING("map_{}"), m_ID)) { @@ -223,7 +225,13 @@ bool cMap::SetPixel(unsigned int a_X, unsigned int a_Z, cMap::ColorID a_Data) { if ((a_X < m_Width) && (a_Z < m_Height)) { - m_Data[a_Z * m_Width + a_X] = a_Data; + auto index = a_Z * m_Width + a_X; + + if (m_Data[index] != a_Data) + { + m_Data[index] = a_Data; + m_Dirty = true; + } return true; } @@ -185,6 +185,8 @@ private: int m_CenterX; int m_CenterZ; + bool m_Dirty; + /** Column-major array of colours */ cColorList m_Data; @@ -196,6 +198,7 @@ private: AString m_Name; + friend class cMapManager; friend class cMapSerializer; }; // tolua_export diff --git a/src/MapManager.cpp b/src/MapManager.cpp index ae020d800..f7b393648 100644 --- a/src/MapManager.cpp +++ b/src/MapManager.cpp @@ -12,8 +12,16 @@ -cMapManager::cMapManager(cWorld * a_World) - : m_World(a_World) +// 6000 ticks or 5 minutes +#define MAP_DATA_SAVE_INTERVAL 6000 + + + + + +cMapManager::cMapManager(cWorld * a_World) : + m_World(a_World), + m_TicksUntilNextSave(MAP_DATA_SAVE_INTERVAL) { ASSERT(m_World != nullptr); } @@ -49,6 +57,16 @@ void cMapManager::TickMaps() { Map.Tick(); } + + if (m_TicksUntilNextSave == 0) + { + m_TicksUntilNextSave = MAP_DATA_SAVE_INTERVAL; + SaveMapData(); + } + else + { + m_TicksUntilNextSave--; + } } @@ -149,11 +167,18 @@ void cMapManager::SaveMapData(void) { cMap & Map = *it; - cMapSerializer Serializer(m_World->GetDataPath(), &Map); - - if (!Serializer.Save()) + if (Map.m_Dirty) { - LOGWARN("Could not save map #%i", Map.GetID()); + cMapSerializer Serializer(m_World->GetDataPath(), &Map); + + if (Serializer.Save()) + { + Map.m_Dirty = false; + } + else + { + LOGWARN("Could not save map #%i", Map.GetID()); + } } } } diff --git a/src/MapManager.h b/src/MapManager.h index 8959b1d8b..d20fe6683 100644 --- a/src/MapManager.h +++ b/src/MapManager.h @@ -64,6 +64,10 @@ private: cWorld * m_World; + /** How long till the map data will be saved + Default save interval is #defined in MAP_DATA_SAVE_INTERVAL */ + unsigned int m_TicksUntilNextSave; + }; // tolua_export diff --git a/src/Noise/InterpolNoise.h b/src/Noise/InterpolNoise.h index 447796739..12b167dbe 100644 --- a/src/Noise/InterpolNoise.h +++ b/src/Noise/InterpolNoise.h @@ -427,28 +427,37 @@ public: // Calculate query values using Cell: int FromZ = 0; - for (int z = 0; z < NumSameZ; z++) + for (int z = 0; z < NumSameZ;) { int ToZ = FromZ + SameZ[z]; int CurFloorZ = FloorZ[FromZ]; int FromY = 0; - for (int y = 0; y < NumSameY; y++) + for (int y = 0; y < NumSameY;) { int ToY = FromY + SameY[y]; int CurFloorY = FloorY[FromY]; int FromX = 0; - for (int x = 0; x < NumSameX; x++) + for (int x = 0; x < NumSameX;) { int ToX = FromX + SameX[x]; Cell.Generate(FromX, ToX, FromY, ToY, FromZ, ToZ); - Cell.Move(FloorX[ToX], CurFloorY, CurFloorZ); - FromX = ToX; + if (++x < NumSameX) // Call Move() every time except for the last loop iteration + { + Cell.Move(FloorX[ToX], CurFloorY, CurFloorZ); + FromX = ToX; + } + } + if (++y < NumSameY) // Call Move() every time except for the last loop iteration + { + Cell.Move(FloorX[0], FloorY[ToY], CurFloorZ); + FromY = ToY; } - Cell.Move(FloorX[0], FloorY[ToY], CurFloorZ); - FromY = ToY; } // for y - Cell.Move(FloorX[0], FloorY[0], FloorZ[ToZ]); - FromZ = ToZ; + if (++z < NumSameZ) // Call Move() every time except for the last loop iteration + { + Cell.Move(FloorX[0], FloorY[0], FloorZ[ToZ]); + FromZ = ToZ; + } } // for z } diff --git a/src/Noise/Noise.cpp b/src/Noise/Noise.cpp index cbdc6bc72..136d124a0 100644 --- a/src/Noise/Noise.cpp +++ b/src/Noise/Noise.cpp @@ -734,20 +734,26 @@ void cCubicNoise::Generate2D( // Calculate query values using Cell: int FromY = 0; - for (int y = 0; y < NumSameY; y++) + for (int y = 0; y < NumSameY;) { int ToY = FromY + SameY[y]; int FromX = 0; int CurFloorY = FloorY[FromY]; - for (int x = 0; x < NumSameX; x++) + for (int x = 0; x < NumSameX;) { int ToX = FromX + SameX[x]; Cell.Generate(FromX, ToX, FromY, ToY); - Cell.Move(FloorX[ToX], CurFloorY); - FromX = ToX; + if (++x < NumSameX) // Call Move() every time except for the last loop iteration + { + Cell.Move(FloorX[ToX], CurFloorY); + FromX = ToX; + } + } + if (++y < NumSameY) // Call Move() every time except for the last loop iteration + { + Cell.Move(FloorX[0], FloorY[ToY]); + FromY = ToY; } - Cell.Move(FloorX[0], FloorY[ToY]); - FromY = ToY; } } @@ -795,28 +801,37 @@ void cCubicNoise::Generate3D( // Calculate query values using Cell: int FromZ = 0; - for (int z = 0; z < NumSameZ; z++) + for (int z = 0; z < NumSameZ;) { int ToZ = FromZ + SameZ[z]; int CurFloorZ = FloorZ[FromZ]; int FromY = 0; - for (int y = 0; y < NumSameY; y++) + for (int y = 0; y < NumSameY;) { int ToY = FromY + SameY[y]; int CurFloorY = FloorY[FromY]; int FromX = 0; - for (int x = 0; x < NumSameX; x++) + for (int x = 0; x < NumSameX;) { int ToX = FromX + SameX[x]; Cell.Generate(FromX, ToX, FromY, ToY, FromZ, ToZ); - Cell.Move(FloorX[ToX], CurFloorY, CurFloorZ); - FromX = ToX; + if (++x < NumSameX) // Call Move() every time except for the last loop iteration + { + Cell.Move(FloorX[ToX], CurFloorY, CurFloorZ); + FromX = ToX; + } + } + if (++y < NumSameY) // Call Move() every time except for the last loop iteration + { + Cell.Move(FloorX[0], FloorY[ToY], CurFloorZ); + FromY = ToY; } - Cell.Move(FloorX[0], FloorY[ToY], CurFloorZ); - FromY = ToY; } // for y - Cell.Move(FloorX[0], FloorY[0], FloorZ[ToZ]); - FromZ = ToZ; + if (++z < NumSameZ) // Call Move() every time except for the last loop iteration + { + Cell.Move(FloorX[0], FloorY[0], FloorZ[ToZ]); + FromZ = ToZ; + } } // for z } diff --git a/src/Protocol/ChunkDataSerializer.cpp b/src/Protocol/ChunkDataSerializer.cpp index cfabc6e31..6b5553ee7 100644 --- a/src/Protocol/ChunkDataSerializer.cpp +++ b/src/Protocol/ChunkDataSerializer.cpp @@ -502,7 +502,7 @@ inline void cChunkDataSerializer::Serialize477(const int a_ChunkX, const int a_C // Write each chunk section... ChunkDef_ForEachSection(a_BlockData, a_LightData, { - m_Packet.WriteBEInt16(-1); + m_Packet.WriteBEInt16(ChunkBlockData::SectionBlockCount); // a temp fix to make sure sections don't disappear m_Packet.WriteBEUInt8(BitsPerEntry); m_Packet.WriteVarInt32(static_cast<UInt32>(ChunkSectionDataArraySize)); WriteBlockSectionSeamless<&Palette477>(Blocks, Metas, BitsPerEntry); diff --git a/src/StringUtils.cpp b/src/StringUtils.cpp index e6d5e3812..cf4a69319 100644 --- a/src/StringUtils.cpp +++ b/src/StringUtils.cpp @@ -5,13 +5,9 @@ #include "Globals.h" +#include "Endianness.h" #include "fmt/printf.h" -#ifdef _MSC_VER - // Under MSVC, link to WinSock2 (needed by RawBEToUTF8's byteswapping) - #pragma comment(lib, "ws2_32.lib") -#endif - @@ -339,13 +335,14 @@ void ReplaceURL(AString & iHayStack, const AString & iNeedle, const AString & iR -AString & RawBEToUTF8(const char * a_RawData, size_t a_NumShorts, AString & a_UTF8) +AString & RawBEUTF16ToUTF8(const char * a_RawData, size_t a_NumShorts, AString & a_UTF8) { a_UTF8.clear(); a_UTF8.reserve(3 * a_NumShorts / 2); // a quick guess of the resulting size for (size_t i = 0; i < a_NumShorts; i++) { - a_UTF8.append(UnicodeCharToUtf8(GetBEUShort(&a_RawData[i * 2]))); + auto UTF16 = NetworkBufToHost<UInt16>(reinterpret_cast<const std::byte *>(&a_RawData[i * 2])); + a_UTF8.append(UnicodeCharToUtf8(UTF16)); } return a_UTF8; } @@ -946,54 +943,6 @@ AString Base64Encode(const AString & a_Input) -short GetBEShort(const std::byte * const a_Mem) -{ - return static_cast<short>( - (static_cast<short>(a_Mem[0]) << 8) | - static_cast<short>(a_Mem[1]) - ); -} - - - - - -unsigned short GetBEUShort(const char * a_Mem) -{ - const Byte * Bytes = reinterpret_cast<const Byte *>(a_Mem); - return static_cast<unsigned short>((Bytes[0] << 8) | Bytes[1]); -} - - - - - -int GetBEInt(const std::byte * const a_Mem) -{ - return - (static_cast<int>(a_Mem[0]) << 24) | - (static_cast<int>(a_Mem[1]) << 16) | - (static_cast<int>(a_Mem[2]) << 8) | - static_cast<int>(a_Mem[3]) - ; -} - - - - - -void SetBEInt(std::byte * a_Mem, Int32 a_Value) -{ - a_Mem[0] = std::byte(a_Value >> 24); - a_Mem[1] = std::byte((a_Value >> 16) & 0xff); - a_Mem[2] = std::byte((a_Value >> 8) & 0xff); - a_Mem[3] = std::byte(a_Value & 0xff); -} - - - - - bool SplitZeroTerminatedStrings(const AString & a_Strings, AStringVector & a_Output) { a_Output.clear(); diff --git a/src/StringUtils.h b/src/StringUtils.h index efb6a8566..f096d9b66 100644 --- a/src/StringUtils.h +++ b/src/StringUtils.h @@ -67,7 +67,7 @@ extern void ReplaceString(AString & iHayStack, const AString & iNeedle, const AS extern void ReplaceURL(AString & iHayStack, const AString & iNeedle, const AString & iReplaceWith); /** Converts a stream of BE shorts into UTF-8 string; returns a_UTF8. */ -extern AString & RawBEToUTF8(const char * a_RawData, size_t a_NumShorts, AString & a_UTF8); +extern AString & RawBEUTF16ToUTF8(const char * a_RawData, size_t a_NumShorts, AString & a_UTF8); /** Converts a unicode character to its UTF8 representation. */ extern AString UnicodeCharToUtf8(unsigned a_UnicodeChar); @@ -101,18 +101,6 @@ extern AString Base64Decode(const AString & a_Base64String); // Exported manual /** Encodes a string into Base64 */ extern AString Base64Encode(const AString & a_Input); // Exported manually due to embedded NULs and extra parameter -/** Reads two bytes from the specified memory location and interprets them as BigEndian short */ -extern short GetBEShort(const std::byte * a_Mem); - -/** Reads two bytes from the specified memory location and interprets them as BigEndian unsigned short */ -extern unsigned short GetBEUShort(const char * a_Mem); - -/** Reads four bytes from the specified memory location and interprets them as BigEndian int */ -extern int GetBEInt(const std::byte * a_Mem); - -/** Writes four bytes to the specified memory location so that they interpret as BigEndian int */ -extern void SetBEInt(std::byte * a_Mem, Int32 a_Value); - /** Splits a string that has embedded \0 characters, on those characters. a_Output is first cleared and then each separate string is pushed back into a_Output. Returns true if there are at least two strings in a_Output (there was at least one \0 separator). */ diff --git a/src/UI/SlotArea.cpp b/src/UI/SlotArea.cpp index 4085dc816..ef5f7382e 100644 --- a/src/UI/SlotArea.cpp +++ b/src/UI/SlotArea.cpp @@ -1065,9 +1065,12 @@ void cSlotAreaAnvil::OnTakeResult(cPlayer & a_Player) BLOCKTYPE Block; NIBBLETYPE BlockMeta; - a_Player.GetWorld()->GetBlockTypeMeta(BlockPos, Block, BlockMeta); - if (!a_Player.IsGameModeCreative() && (Block == E_BLOCK_ANVIL) && GetRandomProvider().RandBool(0.12)) + if ( + a_Player.GetWorld()->GetBlockTypeMeta(BlockPos, Block, BlockMeta) && + !a_Player.IsGameModeCreative() && (Block == E_BLOCK_ANVIL) && + GetRandomProvider().RandBool(0.12) + ) { NIBBLETYPE Orientation = BlockMeta & 0x3; NIBBLETYPE AnvilDamage = BlockMeta >> 2; diff --git a/src/Vector3.h b/src/Vector3.h index 0e275e9b3..5df14b3ac 100644 --- a/src/Vector3.h +++ b/src/Vector3.h @@ -30,13 +30,20 @@ public: // tolua_end // Conversion constructors where U is not the same as T leaving the copy-constructor implicitly generated - template <typename U, typename = typename std::enable_if<!std::is_same<U, T>::value>::type> + template <typename U, std::enable_if_t<(!std::is_same<U, T>::value) && ((!std::is_integral<T>::value) || (std::is_integral<U>::value)), bool> = true> constexpr Vector3(const Vector3<U> & a_Rhs): x(static_cast<T>(a_Rhs.x)), y(static_cast<T>(a_Rhs.y)), z(static_cast<T>(a_Rhs.z)) { } + template <typename U, std::enable_if_t<(!std::is_same<U, T>::value) && ((std::is_integral<T>::value) && (!std::is_integral<U>::value)), bool> = true> + constexpr Vector3(const Vector3<U> & a_Rhs): + x(static_cast<T>(std::floor(a_Rhs.x))), + y(static_cast<T>(std::floor(a_Rhs.y))), + z(static_cast<T>(std::floor(a_Rhs.z))) + { + } // tolua_begin inline void Set(T a_x, T a_y, T a_z) diff --git a/src/World.cpp b/src/World.cpp index 2f92020bf..781d44c3a 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -1539,8 +1539,7 @@ bool cWorld::GetLargeTreeAdjustment(Vector3i & a_BlockPos, NIBBLETYPE a_Meta) { NIBBLETYPE meta; BLOCKTYPE type; - GetBlockTypeMeta(a_BlockPos.addedXZ(x, z), type, meta); - IsLarge = IsLarge && (type == E_BLOCK_SAPLING) && ((meta & 0x07) == a_Meta); + IsLarge = IsLarge && GetBlockTypeMeta(a_BlockPos.addedXZ(x, z), type, meta) && (type == E_BLOCK_SAPLING) && ((meta & 0x07) == a_Meta); } } @@ -1557,8 +1556,7 @@ bool cWorld::GetLargeTreeAdjustment(Vector3i & a_BlockPos, NIBBLETYPE a_Meta) { NIBBLETYPE meta; BLOCKTYPE type; - GetBlockTypeMeta(a_BlockPos.addedXZ(x, z), type, meta); - IsLarge = IsLarge && (type == E_BLOCK_SAPLING) && ((meta & 0x07) == a_Meta); + IsLarge = IsLarge && GetBlockTypeMeta(a_BlockPos.addedXZ(x, z), type, meta) && (type == E_BLOCK_SAPLING) && ((meta & 0x07) == a_Meta); } } @@ -1576,8 +1574,7 @@ bool cWorld::GetLargeTreeAdjustment(Vector3i & a_BlockPos, NIBBLETYPE a_Meta) { NIBBLETYPE meta; BLOCKTYPE type; - GetBlockTypeMeta(a_BlockPos.addedXZ(x, z), type, meta); - IsLarge = IsLarge && (type == E_BLOCK_SAPLING) && ((meta & 0x07) == a_Meta); + IsLarge = IsLarge && GetBlockTypeMeta(a_BlockPos.addedXZ(x, z), type, meta) && (type == E_BLOCK_SAPLING) && ((meta & 0x07) == a_Meta); } } @@ -1596,8 +1593,7 @@ bool cWorld::GetLargeTreeAdjustment(Vector3i & a_BlockPos, NIBBLETYPE a_Meta) { NIBBLETYPE meta; BLOCKTYPE type; - GetBlockTypeMeta(a_BlockPos.addedXZ(x, z), type, meta); - IsLarge = IsLarge && (type == E_BLOCK_SAPLING) && ((meta & 0x07) == a_Meta); + IsLarge = IsLarge && GetBlockTypeMeta(a_BlockPos.addedXZ(x, z), type, meta) && (type == E_BLOCK_SAPLING) && ((meta & 0x07) == a_Meta); } } @@ -2044,7 +2040,10 @@ void cWorld::PlaceBlock(const Vector3i a_Position, const BLOCKTYPE a_BlockType, { BLOCKTYPE BlockType; NIBBLETYPE BlockMeta; - GetBlockTypeMeta(a_Position, BlockType, BlockMeta); + if (!GetBlockTypeMeta(a_Position, BlockType, BlockMeta)) + { + return; + } SetBlock(a_Position, a_BlockType, a_BlockMeta); @@ -2070,7 +2069,10 @@ bool cWorld::DigBlock(Vector3i a_BlockPos, const cEntity * a_Digger) { BLOCKTYPE BlockType; NIBBLETYPE BlockMeta; - GetBlockTypeMeta(a_BlockPos, BlockType, BlockMeta); + if (!GetBlockTypeMeta(a_BlockPos, BlockType, BlockMeta)) + { + return false; + } if (!m_ChunkMap.DigBlock(a_BlockPos)) { @@ -2617,7 +2619,11 @@ bool cWorld::IsTrapdoorOpen(int a_BlockX, int a_BlockY, int a_BlockZ) { BLOCKTYPE Block; NIBBLETYPE Meta; - GetBlockTypeMeta({ a_BlockX, a_BlockY, a_BlockZ }, Block, Meta); + if (!GetBlockTypeMeta({ a_BlockX, a_BlockY, a_BlockZ }, Block, Meta)) + { + return false; + } + if ((Block != E_BLOCK_TRAPDOOR) && (Block != E_BLOCK_IRON_TRAPDOOR)) { return false; @@ -2634,7 +2640,11 @@ bool cWorld::SetTrapdoorOpen(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_Op { BLOCKTYPE Block; NIBBLETYPE Meta; - GetBlockTypeMeta({ a_BlockX, a_BlockY, a_BlockZ }, Block, Meta); + if (!GetBlockTypeMeta({ a_BlockX, a_BlockY, a_BlockZ }, Block, Meta)) + { + return false; + } + if ((Block != E_BLOCK_TRAPDOOR) && (Block != E_BLOCK_IRON_TRAPDOOR)) { return false; diff --git a/src/WorldStorage/FastNBT.cpp b/src/WorldStorage/FastNBT.cpp index df93e21e4..030300387 100644 --- a/src/WorldStorage/FastNBT.cpp +++ b/src/WorldStorage/FastNBT.cpp @@ -189,7 +189,7 @@ eNBTParseError cParsedNBT::ReadString(size_t & a_StringStart, size_t & a_StringL { NEEDBYTES(2, eNBTParseError::npStringMissingLength); a_StringStart = m_Pos + 2; - a_StringLen = static_cast<size_t>(GetBEShort(m_Data.data() + m_Pos)); + a_StringLen = static_cast<size_t>(NetworkBufToHost<UInt16>(m_Data.data() + m_Pos)); NEEDBYTES(2 + a_StringLen, eNBTParseError::npStringInvalidLength); m_Pos += 2 + a_StringLen; return eNBTParseError::npSuccess; @@ -247,7 +247,7 @@ eNBTParseError cParsedNBT::ReadList(eTagType a_ChildrenType) // Read the count: NEEDBYTES(4, eNBTParseError::npListMissingLength); - int Count = GetBEInt(m_Data.data() + m_Pos); + int Count = NetworkBufToHost<int>(m_Data.data() + m_Pos); m_Pos += 4; auto MinChildSize = GetMinTagSize(a_ChildrenType); if ((Count < 0) || (Count > static_cast<int>((m_Data.size() - m_Pos) / MinChildSize))) @@ -311,7 +311,7 @@ eNBTParseError cParsedNBT::ReadTag(void) case TAG_ByteArray: { NEEDBYTES(4, eNBTParseError::npArrayMissingLength); - int len = GetBEInt(m_Data.data() + m_Pos); + int len = NetworkBufToHost<int>(m_Data.data() + m_Pos); m_Pos += 4; if (len < 0) { @@ -343,7 +343,7 @@ eNBTParseError cParsedNBT::ReadTag(void) case TAG_IntArray: { NEEDBYTES(4, eNBTParseError::npArrayMissingLength); - int len = GetBEInt(m_Data.data() + m_Pos); + int len = NetworkBufToHost<int>(m_Data.data() + m_Pos); m_Pos += 4; if (len < 0) { @@ -539,7 +539,8 @@ void cFastNBTWriter::EndList(void) ASSERT(m_Stack[m_CurrentStack].m_Type == TAG_List); // Update the list count: - SetBEInt(m_Result.data() + m_Stack[m_CurrentStack].m_Pos, m_Stack[m_CurrentStack].m_Count); + auto Value = HostToNetwork(m_Stack[m_CurrentStack].m_Count); + std::copy(Value.begin(), Value.end(), m_Result.data() + m_Stack[m_CurrentStack].m_Pos); --m_CurrentStack; } @@ -561,8 +562,8 @@ void cFastNBTWriter::AddByte(const AString & a_Name, unsigned char a_Value) void cFastNBTWriter::AddShort(const AString & a_Name, Int16 a_Value) { TagCommon(a_Name, TAG_Short); - UInt16 Value = htons(static_cast<UInt16>(a_Value)); - m_Result.append(reinterpret_cast<const std::byte *>(&Value), 2); + auto Value = HostToNetwork(a_Value); + m_Result.append(Value.begin(), Value.end()); } @@ -572,8 +573,8 @@ void cFastNBTWriter::AddShort(const AString & a_Name, Int16 a_Value) void cFastNBTWriter::AddInt(const AString & a_Name, Int32 a_Value) { TagCommon(a_Name, TAG_Int); - UInt32 Value = htonl(static_cast<UInt32>(a_Value)); - m_Result.append(reinterpret_cast<const std::byte *>(&Value), 4); + auto Value = HostToNetwork(a_Value); + m_Result.append(Value.begin(), Value.end()); } @@ -583,8 +584,8 @@ void cFastNBTWriter::AddInt(const AString & a_Name, Int32 a_Value) void cFastNBTWriter::AddLong(const AString & a_Name, Int64 a_Value) { TagCommon(a_Name, TAG_Long); - UInt64 Value = HostToNetwork8(&a_Value); - m_Result.append(reinterpret_cast<const std::byte *>(&Value), 8); + auto Value = HostToNetwork(a_Value); + m_Result.append(Value.begin(), Value.end()); } @@ -594,8 +595,8 @@ void cFastNBTWriter::AddLong(const AString & a_Name, Int64 a_Value) void cFastNBTWriter::AddFloat(const AString & a_Name, float a_Value) { TagCommon(a_Name, TAG_Float); - UInt32 Value = HostToNetwork4(&a_Value); - m_Result.append(reinterpret_cast<const std::byte *>(&Value), 4); + auto Value = HostToNetwork(a_Value); + m_Result.append(Value.begin(), Value.end()); } @@ -605,8 +606,8 @@ void cFastNBTWriter::AddFloat(const AString & a_Name, float a_Value) void cFastNBTWriter::AddDouble(const AString & a_Name, double a_Value) { TagCommon(a_Name, TAG_Double); - UInt64 Value = HostToNetwork8(&a_Value); - m_Result.append(reinterpret_cast<const std::byte *>(&Value), 8); + auto Value = HostToNetwork(a_Value); + m_Result.append(Value.begin(), Value.end()); } @@ -616,8 +617,8 @@ void cFastNBTWriter::AddDouble(const AString & a_Name, double a_Value) void cFastNBTWriter::AddString(const AString & a_Name, const std::string_view a_Value) { TagCommon(a_Name, TAG_String); - const UInt16 Length = htons(static_cast<UInt16>(a_Value.size())); - m_Result.append(reinterpret_cast<const std::byte *>(&Length), sizeof(Length)); + auto Length = HostToNetwork(static_cast<UInt16>(a_Value.size())); + m_Result.append(Length.begin(), Length.end()); m_Result.append({ reinterpret_cast<const std::byte *>(a_Value.data()), a_Value.size() }); } @@ -628,8 +629,8 @@ void cFastNBTWriter::AddString(const AString & a_Name, const std::string_view a_ void cFastNBTWriter::AddByteArray(const AString & a_Name, const char * a_Value, size_t a_NumElements) { TagCommon(a_Name, TAG_ByteArray); - UInt32 len = htonl(static_cast<UInt32>(a_NumElements)); - m_Result.append(reinterpret_cast<const std::byte *>(&len), 4); + auto Length = HostToNetwork(static_cast<UInt32>(a_NumElements)); + m_Result.append(Length.begin(), Length.end()); m_Result.append(reinterpret_cast<const std::byte *>(a_Value), a_NumElements); } @@ -640,8 +641,8 @@ void cFastNBTWriter::AddByteArray(const AString & a_Name, const char * a_Value, void cFastNBTWriter::AddByteArray(const AString & a_Name, size_t a_NumElements, unsigned char a_Value) { TagCommon(a_Name, TAG_ByteArray); - UInt32 len = htonl(static_cast<UInt32>(a_NumElements)); - m_Result.append(reinterpret_cast<const std::byte *>(&len), 4); + auto Length = HostToNetwork(static_cast<UInt32>(a_NumElements)); + m_Result.append(Length.begin(), Length.end()); m_Result.append(a_NumElements, std::byte(a_Value)); } @@ -652,18 +653,18 @@ void cFastNBTWriter::AddByteArray(const AString & a_Name, size_t a_NumElements, void cFastNBTWriter::AddIntArray(const AString & a_Name, const Int32 * a_Value, size_t a_NumElements) { TagCommon(a_Name, TAG_IntArray); - UInt32 len = htonl(static_cast<UInt32>(a_NumElements)); + auto Length = HostToNetwork(static_cast<UInt32>(a_NumElements)); size_t cap = m_Result.capacity(); size_t size = m_Result.length(); if ((cap - size) < (4 + a_NumElements * 4)) { m_Result.reserve(size + 4 + (a_NumElements * 4)); } - m_Result.append(reinterpret_cast<const std::byte *>(&len), sizeof(len)); + m_Result.append(Length.begin(), Length.end()); for (size_t i = 0; i < a_NumElements; i++) { - UInt32 Element = htonl(static_cast<UInt32>(a_Value[i])); - m_Result.append(reinterpret_cast<const std::byte *>(&Element), sizeof(Element)); + auto Element = HostToNetwork(a_Value[i]); + m_Result.append(Element.begin(), Element.end()); } } @@ -684,7 +685,7 @@ void cFastNBTWriter::Finish(void) void cFastNBTWriter::WriteString(const std::string_view a_Data) { // TODO check size <= short max - UInt16 Len = htons(static_cast<unsigned short>(a_Data.size())); - m_Result.append(reinterpret_cast<const std::byte *>(&Len), sizeof(Len)); + auto Length = HostToNetwork(static_cast<UInt16>(a_Data.size())); + m_Result.append(Length.begin(), Length.end()); m_Result.append(reinterpret_cast<const std::byte *>(a_Data.data()), a_Data.size()); } diff --git a/src/WorldStorage/FastNBT.h b/src/WorldStorage/FastNBT.h index d9c388179..b2eb851d7 100644 --- a/src/WorldStorage/FastNBT.h +++ b/src/WorldStorage/FastNBT.h @@ -227,21 +227,21 @@ public: inline Int16 GetShort(int a_Tag) const { ASSERT(m_Tags[static_cast<size_t>(a_Tag)].m_Type == TAG_Short); - return GetBEShort(GetData(a_Tag)); + return NetworkBufToHost<Int16>(GetData(a_Tag)); } /** Returns the value stored in an Int tag. Not valid for any other tag type. */ inline Int32 GetInt(int a_Tag) const { ASSERT(m_Tags[static_cast<size_t>(a_Tag)].m_Type == TAG_Int); - return GetBEInt(GetData(a_Tag)); + return NetworkBufToHost<Int32>(GetData(a_Tag)); } /** Returns the value stored in a Long tag. Not valid for any other tag type. */ inline Int64 GetLong(int a_Tag) const { ASSERT(m_Tags[static_cast<size_t>(a_Tag)].m_Type == TAG_Long); - return NetworkToHostLong8(GetData(a_Tag)); + return NetworkBufToHost<Int64>(GetData(a_Tag)); } /** Returns the value stored in a Float tag. Not valid for any other tag type. */ @@ -256,10 +256,7 @@ public: UNUSED_VAR(Check1); UNUSED_VAR(Check2); - Int32 i = GetBEInt(GetData(a_Tag)); - float f; - memcpy(&f, &i, sizeof(f)); - return f; + return NetworkBufToHost<float>(GetData(a_Tag)); } /** Returns the value stored in a Double tag. Not valid for any other tag type. */ @@ -273,7 +270,7 @@ public: UNUSED_VAR(Check2); ASSERT(m_Tags[static_cast<size_t>(a_Tag)].m_Type == TAG_Double); - return NetworkToHostDouble8(GetData(a_Tag)); + return NetworkBufToHost<double>(GetData(a_Tag)); } /** Returns the value stored in a String tag. Not valid for any other tag type. */ diff --git a/src/WorldStorage/FireworksSerializer.cpp b/src/WorldStorage/FireworksSerializer.cpp index f0fe7e48e..6616196e2 100644 --- a/src/WorldStorage/FireworksSerializer.cpp +++ b/src/WorldStorage/FireworksSerializer.cpp @@ -108,7 +108,7 @@ void cFireworkItem::ParseFromNBT(cFireworkItem & a_FireworkItem, const cParsedNB const auto * ColourData = (a_NBT.GetData(explosiontag)); for (size_t i = 0; i < DataLength; i += 4) { - a_FireworkItem.m_Colours.push_back(GetBEInt(ColourData + i)); + a_FireworkItem.m_Colours.push_back(NetworkBufToHost<Int32>(ColourData + i)); } } else if (ExplosionName == "FadeColors") @@ -124,7 +124,7 @@ void cFireworkItem::ParseFromNBT(cFireworkItem & a_FireworkItem, const cParsedNB const auto * FadeColourData = (a_NBT.GetData(explosiontag)); for (size_t i = 0; i < DataLength; i += 4) { - a_FireworkItem.m_FadeColours.push_back(GetBEInt(FadeColourData + i)); + a_FireworkItem.m_FadeColours.push_back(NetworkBufToHost<Int32>(FadeColourData + i)); } } } diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp index 6b425c4dc..0f91b033b 100644 --- a/src/WorldStorage/WSSAnvil.cpp +++ b/src/WorldStorage/WSSAnvil.cpp @@ -510,7 +510,7 @@ bool cWSSAnvil::LoadHeightMapFromNBT(cChunkDef::HeightMap & a_HeightMap, const c for (int RelX = 0; RelX < cChunkDef::Width; RelX++) { const int Index = 4 * (RelX + RelZ * cChunkDef::Width); - const int Height = GetBEInt(HeightData + Index); + const int Height = NetworkBufToHost<Int32>(HeightData + Index); if (Height > std::numeric_limits<HEIGHTTYPE>::max()) { diff --git a/src/mbedTLS++/CryptoKey.cpp b/src/mbedTLS++/CryptoKey.cpp index 742d9c73c..ea01bfc80 100644 --- a/src/mbedTLS++/CryptoKey.cpp +++ b/src/mbedTLS++/CryptoKey.cpp @@ -124,15 +124,18 @@ int cCryptoKey::ParsePrivate(const void * a_Data, size_t a_NumBytes, const AStri if (a_Password.empty()) { - return mbedtls_pk_parse_key(&m_Pk, reinterpret_cast<const unsigned char *>(keyData.data()), a_NumBytes + 1, nullptr, 0, mbedtls_ctr_drbg_random, m_CtrDrbg.GetInternal()); + return mbedtls_pk_parse_key( + &m_Pk, + reinterpret_cast<const unsigned char *>(keyData.data()), a_NumBytes + 1, + nullptr, 0 + ); } else { return mbedtls_pk_parse_key( &m_Pk, reinterpret_cast<const unsigned char *>(keyData.data()), a_NumBytes + 1, - reinterpret_cast<const unsigned char *>(a_Password.c_str()), a_Password.size(), - mbedtls_ctr_drbg_random, m_CtrDrbg.GetInternal() + reinterpret_cast<const unsigned char *>(a_Password.c_str()), a_Password.size() ); } } diff --git a/src/mbedTLS++/RsaPrivateKey.cpp b/src/mbedTLS++/RsaPrivateKey.cpp index d0c5b7c8b..81cd2db44 100644 --- a/src/mbedTLS++/RsaPrivateKey.cpp +++ b/src/mbedTLS++/RsaPrivateKey.cpp @@ -11,7 +11,7 @@ cRsaPrivateKey::cRsaPrivateKey(void) { - mbedtls_rsa_init(&m_Rsa); + mbedtls_rsa_init(&m_Rsa, MBEDTLS_RSA_PKCS_V15, 0); m_CtrDrbg.Initialize("RSA", 3); } @@ -21,7 +21,7 @@ cRsaPrivateKey::cRsaPrivateKey(void) cRsaPrivateKey::cRsaPrivateKey(const cRsaPrivateKey & a_Other) { - mbedtls_rsa_init(&m_Rsa); + mbedtls_rsa_init(&m_Rsa, MBEDTLS_RSA_PKCS_V15, 0); mbedtls_rsa_copy(&m_Rsa, &a_Other.m_Rsa); m_CtrDrbg.Initialize("RSA", 3); } @@ -122,7 +122,7 @@ int cRsaPrivateKey::Decrypt(const ContiguousByteBufferView a_EncryptedData, Byte } size_t DecryptedLength; int res = mbedtls_rsa_pkcs1_decrypt( - &m_Rsa, mbedtls_ctr_drbg_random, m_CtrDrbg.GetInternal(), &DecryptedLength, + &m_Rsa, mbedtls_ctr_drbg_random, m_CtrDrbg.GetInternal(), MBEDTLS_RSA_PRIVATE, &DecryptedLength, reinterpret_cast<const unsigned char *>(a_EncryptedData.data()), a_DecryptedData, a_DecryptedMaxLength ); if (res != 0) |