diff options
Diffstat (limited to '')
100 files changed, 882 insertions, 656 deletions
diff --git a/src/BlockArea.h b/src/BlockArea.h index b672a18ec..2048bb563 100644 --- a/src/BlockArea.h +++ b/src/BlockArea.h @@ -163,7 +163,7 @@ public: /** Expands the internal contents by the specified amount of blocks from each border */ void Expand(int a_SubMinX, int a_AddMaxX, int a_SubMinY, int a_AddMaxY, int a_SubMinZ, int a_AddMaxZ); - /** Merges another block area into this one, using the specified block combinating strategy + /** Merges another block area into this one, using the specified block combining strategy This function combines another BlockArea into the current object. The a_RelX, a_RelY and a_RelZ parameters specify the coords of this BA where a_Src should be copied. If both areas contain baBlockEntities, the BEs are merged (with preference of keeping this' ones) (MergeBlockEntities()). @@ -236,7 +236,7 @@ public: */ void Merge(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_RelZ, eMergeStrategy a_Strategy); - /** Merges another block area into this one, using the specified block combinating strategy. + /** Merges another block area into this one, using the specified block combining strategy. See Merge() above for details. */ void Merge(const cBlockArea & a_Src, const Vector3i & a_RelMinCoords, eMergeStrategy a_Strategy); @@ -362,7 +362,7 @@ public: bool HasBlockMetas (void) const { return (m_BlockMetas != nullptr); } bool HasBlockLights (void) const { return (m_BlockLight != nullptr); } bool HasBlockSkyLights(void) const { return (m_BlockSkyLight != nullptr); } - bool HasBlockEntities (void) const { return (m_BlockEntities != nullptr); } + bool HasBlockEntities (void) const { return m_BlockEntities.operator bool(); } /** Returns the count of blocks that are not air. Returns 0 if blocktypes not available. Block metas are ignored (if present, air with any meta is still considered air). */ @@ -423,7 +423,8 @@ public: bool ForEachBlockEntity(cBlockEntityCallback a_Callback); /** Direct read-only access to block entities. */ - const cBlockEntities & GetBlockEntities(void) const { ASSERT(HasBlockEntities()); return *m_BlockEntities; } + const cBlockEntities & GetBlockEntities(void) const { ASSERT(HasBlockEntities()); return *m_BlockEntities.get(); } + cBlockEntities & GetBlockEntities(void) { ASSERT(HasBlockEntities()); return *m_BlockEntities.get(); } diff --git a/src/BlockEntities/BannerEntity.cpp b/src/BlockEntities/BannerEntity.cpp index f39263ac4..10f185bfd 100644 --- a/src/BlockEntities/BannerEntity.cpp +++ b/src/BlockEntities/BannerEntity.cpp @@ -13,18 +13,10 @@ -cBannerEntity::cBannerEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World) : - cBannerEntity(a_BlockType, a_BlockMeta, a_Pos, a_World, 1) -{ -} - - - - - -cBannerEntity::cBannerEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World, unsigned char a_BaseColor): +cBannerEntity::cBannerEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World, unsigned char a_BaseColor, AString a_CustomName): Super(a_BlockType, a_BlockMeta, a_Pos, a_World), - m_BaseColor(a_BaseColor) + m_BaseColor(a_BaseColor), + m_CustomName(std::move(a_CustomName)) { ASSERT((a_BlockType == E_BLOCK_WALL_BANNER) || (a_BlockType == E_BLOCK_STANDING_BANNER)); } @@ -33,27 +25,11 @@ cBannerEntity::cBannerEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vect -unsigned char cBannerEntity::GetBaseColor() const -{ - return m_BaseColor; -} - - - - - -void cBannerEntity::SetBaseColor(const unsigned char a_Color) -{ - m_BaseColor = a_Color; -} - - - - - cItems cBannerEntity::ConvertToPickups() const { - return cItem(E_ITEM_BANNER, 1, static_cast<NIBBLETYPE>(GetBaseColor())); + cItem Item(E_ITEM_BANNER, 1, static_cast<NIBBLETYPE>(GetBaseColor())); + Item.m_CustomName = m_CustomName; + return Item; } @@ -65,6 +41,7 @@ void cBannerEntity::CopyFrom(const cBlockEntity & a_Src) Super::CopyFrom(a_Src); auto & src = static_cast<const cBannerEntity &>(a_Src); m_BaseColor = src.m_BaseColor; + m_CustomName = src.m_CustomName; } diff --git a/src/BlockEntities/BannerEntity.h b/src/BlockEntities/BannerEntity.h index b6d27f53b..91ef87e8c 100644 --- a/src/BlockEntities/BannerEntity.h +++ b/src/BlockEntities/BannerEntity.h @@ -25,16 +25,20 @@ class cBannerEntity : public: - cBannerEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World); - cBannerEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World, unsigned char a_BaseColor); + cBannerEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World, unsigned char a_BaseColor = 1, AString a_CustomName = ""); - unsigned char GetBaseColor() const; - void SetBaseColor(unsigned char a_Color); + unsigned char GetBaseColor() const { return m_BaseColor; } + void SetBaseColor(unsigned char a_Color) { m_BaseColor = a_Color; } + + const AString & GetCustomName() const { return m_CustomName; } + void SetCustomName(const AString & a_CustomName) { m_CustomName = a_CustomName; } private: unsigned char m_BaseColor; + AString m_CustomName; + // cBlockEntity overrides: virtual cItems ConvertToPickups() const override; virtual void CopyFrom(const cBlockEntity & a_Src) override; 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/Chunk.cpp b/src/Chunk.cpp index fa7faf1f0..35d8a8819 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -370,15 +370,25 @@ void cChunk::SetAllData(SetChunkData && a_SetChunkData) m_BlockEntities = std::move(a_SetChunkData.BlockEntities); // Check that all block entities have a valid blocktype at their respective coords (DEBUG-mode only): -#ifndef NDEBUG + for (auto & KeyPair : m_BlockEntities) { +#ifndef NDEBUG cBlockEntity * Block = KeyPair.second.get(); BLOCKTYPE EntityBlockType = Block->GetBlockType(); BLOCKTYPE WorldBlockType = GetBlock(Block->GetRelX(), Block->GetPosY(), Block->GetRelZ()); ASSERT(WorldBlockType == EntityBlockType); - } #endif + // Reset Pointer + KeyPair.second->SetWorld(nullptr); + + auto Pos = cChunkDef::RelativeToAbsolute({KeyPair.second->GetRelX(), 0, KeyPair.second->GetRelZ()}, {m_PosX, m_PosZ}); + if ((Pos.x != KeyPair.second->GetPosX()) || (Pos.z != KeyPair.second->GetPosZ())) + { + KeyPair.second->SetPos(Pos.addedY(KeyPair.second->GetPosY())); + } + KeyPair.second->SetWorld(m_World); + } // Set the chunk data as valid. // This may be needed for some simulators that perform actions upon block adding (Vaporize), diff --git a/src/ChunkDataCallback.h b/src/ChunkDataCallback.h index 49b3f1e2b..3b47a54f9 100644 --- a/src/ChunkDataCallback.h +++ b/src/ChunkDataCallback.h @@ -18,7 +18,7 @@ /** Interface class used for getting data out of a chunk using the GetAllData() function. Implementation must use the pointers immediately and NOT store any of them for later use The virtual methods are called in the same order as they're declared here. */ -class cChunkDataCallback abstract +class cChunkDataCallback { public: @@ -44,7 +44,7 @@ public: /** Called for each entity in the chunk */ virtual void Entity(cEntity * a_Entity) { UNUSED(a_Entity); } - /** Called for each blockentity in the chunk */ + /** Called for each block entity in the chunk */ virtual void BlockEntity(cBlockEntity * a_Entity) { UNUSED(a_Entity); } } ; 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/ChunkDesc.cpp b/src/Generating/ChunkDesc.cpp index b2a332489..397220f4f 100644 --- a/src/Generating/ChunkDesc.cpp +++ b/src/Generating/ChunkDesc.cpp @@ -573,12 +573,12 @@ void cChunkDesc::RandomFillRelCuboid( cBlockEntity * cChunkDesc::GetBlockEntity(int a_RelX, int a_RelY, int a_RelZ) { const auto Idx = cChunkDef::MakeIndex(a_RelX, a_RelY, a_RelZ); - const auto itr = m_BlockEntities.find(Idx); + const auto Iterator = m_BlockArea.GetBlockEntities().find(Idx); - if (itr != m_BlockEntities.end()) + if (Iterator != m_BlockArea.GetBlockEntities().end()) { // Already in the list: - cBlockEntity * BlockEntity = itr->second.get(); + cBlockEntity * BlockEntity = Iterator->second.get(); if (BlockEntity->GetBlockType() == GetBlockType(a_RelX, a_RelY, a_RelZ)) { // Correct type, already present. Return it: @@ -587,7 +587,7 @@ cBlockEntity * cChunkDesc::GetBlockEntity(int a_RelX, int a_RelY, int a_RelZ) else { // Wrong type, the block type has been overwritten. Erase and create new: - m_BlockEntities.erase(itr); + m_BlockArea.GetBlockEntities().erase(Iterator); } } @@ -595,13 +595,13 @@ cBlockEntity * cChunkDesc::GetBlockEntity(int a_RelX, int a_RelY, int a_RelZ) int AbsZ = a_RelZ + m_Coords.m_ChunkZ * cChunkDef::Width; // The block entity is not created yet, try to create it and add to list: - auto be = cBlockEntity::CreateByBlockType(GetBlockType(a_RelX, a_RelY, a_RelZ), GetBlockMeta(a_RelX, a_RelY, a_RelZ), {AbsX, a_RelY, AbsZ}); - if (be == nullptr) + auto BlockEntity = cBlockEntity::CreateByBlockType(GetBlockType(a_RelX, a_RelY, a_RelZ), GetBlockMeta(a_RelX, a_RelY, a_RelZ), {AbsX, a_RelY, AbsZ}); + if (BlockEntity == nullptr) { // No block entity for this block type return nullptr; } - auto res = m_BlockEntities.emplace(Idx, std::move(be)); + auto res = m_BlockArea.GetBlockEntities().emplace(Idx, std::move(BlockEntity)); return res.first->second.get(); } diff --git a/src/Generating/ChunkDesc.h b/src/Generating/ChunkDesc.h index d066660f1..519dbe81c 100644 --- a/src/Generating/ChunkDesc.h +++ b/src/Generating/ChunkDesc.h @@ -238,7 +238,8 @@ public: inline BlockNibbleBytes & GetBlockMetasUncompressed(void) { return *(reinterpret_cast<BlockNibbleBytes *>(m_BlockArea.GetBlockMetas())); } inline cChunkDef::HeightMap & GetHeightMap (void) { return m_HeightMap; } inline cEntityList & GetEntities (void) { return m_Entities; } - inline cBlockEntities & GetBlockEntities (void) { return m_BlockEntities; } + inline const cBlockEntities & GetBlockEntities (void) const { return m_BlockArea.GetBlockEntities(); } + inline cBlockEntities & GetBlockEntities (void) { return m_BlockArea.GetBlockEntities(); } inline const cChunkDef::BiomeMap & GetBiomeMap() const { return m_BiomeMap; } inline const cChunkDef::BlockTypes & GetBlockTypes() const { return *(reinterpret_cast<cChunkDef::BlockTypes *>(m_BlockArea.GetBlockTypes())); } @@ -259,7 +260,6 @@ private: cBlockArea m_BlockArea; cChunkDef::HeightMap m_HeightMap; cEntityList m_Entities; - cBlockEntities m_BlockEntities; // Individual block entities are NOT owned by this object! bool m_bUseDefaultBiomes; bool m_bUseDefaultHeight; 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/Generating/MineShafts.cpp b/src/Generating/MineShafts.cpp index 189b28095..beb1e24a1 100644 --- a/src/Generating/MineShafts.cpp +++ b/src/Generating/MineShafts.cpp @@ -26,7 +26,7 @@ in a depth-first processing. Each of the descendants will branch randomly, if no -class cMineShaft abstract +class cMineShaft { public: enum eKind diff --git a/src/Generating/MineShafts.h b/src/Generating/MineShafts.h index 43eff2055..6c137fed8 100644 --- a/src/Generating/MineShafts.h +++ b/src/Generating/MineShafts.h @@ -35,7 +35,7 @@ protected: class cMineShaftSystem; // fwd: MineShafts.cpp int m_GridSize; ///< Average spacing of the systems - int m_MaxSystemSize; ///< Maximum blcok size of a mineshaft system + int m_MaxSystemSize; ///< Maximum block size of a mineshaft system int m_ProbLevelCorridor; ///< Probability level of a branch object being the corridor int m_ProbLevelCrossing; ///< Probability level of a branch object being the crossing, minus Corridor int m_ProbLevelStaircase; ///< Probability level of a branch object being the staircase, minus Crossing diff --git a/src/Items/ItemBanner.h b/src/Items/ItemBanner.h index a404af336..551c41429 100644 --- a/src/Items/ItemBanner.h +++ b/src/Items/ItemBanner.h @@ -40,7 +40,9 @@ private: { ASSERT((a_BlockEntity.GetBlockType() == E_BLOCK_STANDING_BANNER) || (a_BlockEntity.GetBlockType() == E_BLOCK_WALL_BANNER)); - static_cast<cBannerEntity &>(a_BlockEntity).SetBaseColor(static_cast<NIBBLETYPE>(a_HeldItem.m_ItemDamage)); + cBannerEntity & BannerEntity = static_cast<cBannerEntity &>(a_BlockEntity); + BannerEntity.SetBaseColor(static_cast<NIBBLETYPE>(a_HeldItem.m_ItemDamage)); + BannerEntity.SetCustomName(a_HeldItem.m_CustomName); return false; }); 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/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index 788d1b66f..d14746513 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -227,8 +227,18 @@ void cMonster::MoveToWayPoint(cChunk & a_Chunk) // Don't let the mob move too much if he's falling. Distance *= 0.25f; } - // Apply walk speed: - Distance *= m_RelativeWalkSpeed; + + if ((m_EMState == CHASING) || (m_EMState == ESCAPING)) + { + // Apply run speed: + Distance *= m_BaseRunSpeed * m_RelativeWalkSpeed; + } + else + { + // Apply walk speed: + Distance *= m_BaseWalkSpeed * m_RelativeWalkSpeed; + } + /* Reduced default speed. Close to Vanilla, easier for mobs to follow m_NextWayPointPositions, hence better pathfinding. */ diff --git a/src/Mobs/Monster.h b/src/Mobs/Monster.h index 0127ec4ce..24a1d189f 100644 --- a/src/Mobs/Monster.h +++ b/src/Mobs/Monster.h @@ -146,7 +146,10 @@ public: bool BurnsInDaylight() const { return m_BurnsInDaylight; } // tolua_export double GetRelativeWalkSpeed(void) const { return m_RelativeWalkSpeed; } // tolua_export - void SetRelativeWalkSpeed(double a_WalkSpeed) { m_RelativeWalkSpeed = a_WalkSpeed; } // tolua_export + void SetRelativeWalkSpeed(double a_Speed) { m_RelativeWalkSpeed = a_Speed; } // tolua_export + + void SetBaseWalkSpeed(double a_Speed) { m_BaseWalkSpeed = a_Speed; } + void SetBaseRunSpeed(double a_Speed) { m_BaseRunSpeed = a_Speed; } // Overridables to handle ageable mobs virtual bool IsTame (void) const { return false; } @@ -326,6 +329,8 @@ protected: bool WouldBurnAt(Vector3d a_Location, cChunk & a_Chunk); bool m_BurnsInDaylight; double m_RelativeWalkSpeed; + double m_BaseWalkSpeed; + double m_BaseRunSpeed; int m_AmbientSoundTimer; diff --git a/src/Mobs/Wolf.cpp b/src/Mobs/Wolf.cpp index 553ca1c73..edcb54075 100644 --- a/src/Mobs/Wolf.cpp +++ b/src/Mobs/Wolf.cpp @@ -20,7 +20,6 @@ cWolf::cWolf(void) : m_CollarColor(E_META_DYE_ORANGE), m_NotificationCooldown(0) { - m_RelativeWalkSpeed = 2; } diff --git a/src/MonsterConfig.cpp b/src/MonsterConfig.cpp index 271a72a7f..2ee7e7393 100644 --- a/src/MonsterConfig.cpp +++ b/src/MonsterConfig.cpp @@ -17,6 +17,8 @@ struct cMonsterConfig::sAttributesStruct double m_AttackRange; double m_AttackRate; double m_MaxHealth; + double m_BaseWalkSpeed; + double m_BaseRunSpeed; bool m_IsFireproof; bool m_BurnsInDaylight; }; @@ -71,10 +73,12 @@ void cMonsterConfig::Initialize() AString Name = MonstersIniFile.GetKeyName(i); Attributes.m_Name = Name; Attributes.m_AttackDamage = MonstersIniFile.GetValueI(Name, "AttackDamage", 0); - Attributes.m_AttackRange = MonstersIniFile.GetValueF(Name, "AttackRange", 0); + Attributes.m_AttackRange = MonstersIniFile.GetValueI(Name, "AttackRange", 0); Attributes.m_SightDistance = MonstersIniFile.GetValueI(Name, "SightDistance", 0); Attributes.m_AttackRate = MonstersIniFile.GetValueF(Name, "AttackRate", 0); Attributes.m_MaxHealth = MonstersIniFile.GetValueF(Name, "MaxHealth", 1); + Attributes.m_BaseWalkSpeed = MonstersIniFile.GetValueF(Name, "WalkSpeed", 1); + Attributes.m_BaseRunSpeed = MonstersIniFile.GetValueF(Name, "RunSpeed", Attributes.m_BaseWalkSpeed); Attributes.m_IsFireproof = MonstersIniFile.GetValueB(Name, "IsFireproof", false); Attributes.m_BurnsInDaylight = MonstersIniFile.GetValueB(Name, "BurnsInDaylight", false); m_pState->AttributesList.push_front(Attributes); @@ -97,6 +101,8 @@ void cMonsterConfig::AssignAttributes(cMonster * a_Monster, const AString & a_Na a_Monster->SetSightDistance (itr->m_SightDistance); a_Monster->SetAttackRate (static_cast<float>(itr->m_AttackRate)); a_Monster->SetMaxHealth (static_cast<float>(itr->m_MaxHealth)); + a_Monster->SetBaseWalkSpeed (itr->m_BaseWalkSpeed); + a_Monster->SetBaseRunSpeed (itr->m_BaseRunSpeed); a_Monster->SetIsFireproof (itr->m_IsFireproof); a_Monster->SetBurnsInDaylight(itr->m_BurnsInDaylight); return; @@ -107,4 +113,3 @@ void cMonsterConfig::AssignAttributes(cMonster * a_Monster, const AString & a_Na - 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/Resources/Cuberite.rc b/src/Resources/Cuberite.rc index 2f2b4fc93..13714f327 100644 --- a/src/Resources/Cuberite.rc +++ b/src/Resources/Cuberite.rc @@ -1,3 +1,5 @@ +#pragma code_page(65001) // UTF-8
+
#include "winres.h"
Favicon ICON "icon.ico"
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/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp index fb6459c88..c61e6d185 100644 --- a/src/WorldStorage/NBTChunkSerializer.cpp +++ b/src/WorldStorage/NBTChunkSerializer.cpp @@ -376,6 +376,10 @@ public: mWriter.BeginCompound(""); AddBasicTileEntity(a_Entity,"Banner"); mWriter.AddInt("Base", static_cast<int>(a_Entity->GetBaseColor())); + if (!a_Entity->GetCustomName().empty()) + { + mWriter.AddString("CustomName", a_Entity->GetCustomName()); + } mWriter.EndCompound(); } diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp index dec05f351..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()) { @@ -890,15 +890,23 @@ OwnedBlockEntity cWSSAnvil::LoadBannerFromNBT(const cParsedNBT & a_NBT, int a_Ta return nullptr; } + unsigned char Color = 15; + AString CustomName; + // Reads base color from NBT int CurrentLine = a_NBT.FindChildByName(a_TagIdx, "Base"); if (CurrentLine >= 0) { - const auto Color = static_cast<unsigned char>(a_NBT.GetInt(CurrentLine)); - return std::make_unique<cBannerEntity>(a_BlockType, a_BlockMeta, a_Pos, m_World, Color); + Color = static_cast<unsigned char>(a_NBT.GetInt(CurrentLine)); } - return nullptr; + CurrentLine = a_NBT.FindChildByName(a_TagIdx, "CustomName"); + if ((CurrentLine >= 0) && (a_NBT.GetType(CurrentLine) == TAG_String)) + { + CustomName = a_NBT.GetString(CurrentLine); + } + + return std::make_unique<cBannerEntity>(a_BlockType, a_BlockMeta, a_Pos, m_World, Color, CustomName); } @@ -3640,7 +3648,7 @@ bool cWSSAnvil::LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_N Rotation[1] = 0; } a_Entity.SetYaw(Rotation[0]); - a_Entity.SetRoll(Rotation[1]); + a_Entity.SetPitch(Rotation[1]); // Depending on the Minecraft version, the entity's health is // stored either as a float Health tag (HealF prior to 1.9) or 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) |