From 26ac146f41091dc070d8075f5fc9de25b5a22578 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Fri, 17 Apr 2020 11:36:37 +0200 Subject: More Vector3 in cBlockHandler (#4644) * cBlockHandler.OnUpdate uses Vector3 params. Also slightly changed how block ticking works. --- src/Blocks/BlockCauldron.h | 38 +++++++-- src/Blocks/BlockCocoaPod.h | 10 ++- src/Blocks/BlockFarmland.h | 36 +++++---- src/Blocks/BlockFluid.h | 57 +++++++++----- src/Blocks/BlockGrass.h | 54 +++++++------ src/Blocks/BlockHandler.cpp | 8 +- src/Blocks/BlockHandler.h | 19 ++++- src/Blocks/BlockLeaves.h | 176 +++++++++++++++++++++--------------------- src/Blocks/BlockPlant.h | 17 ++-- src/Blocks/BlockPortal.h | 18 +++-- src/Blocks/BlockRedstoneOre.h | 9 ++- src/Blocks/BlockSapling.h | 21 +++-- src/Blocks/BlockVine.h | 18 +++-- src/Blocks/CMakeLists.txt | 1 + src/Blocks/WorldInterface.h | 4 + 15 files changed, 303 insertions(+), 183 deletions(-) (limited to 'src/Blocks') diff --git a/src/Blocks/BlockCauldron.h b/src/Blocks/BlockCauldron.h index 37f274f18..28c1dfda8 100644 --- a/src/Blocks/BlockCauldron.h +++ b/src/Blocks/BlockCauldron.h @@ -19,11 +19,19 @@ public: { } + + + + virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { return cItem(E_ITEM_CAULDRON, 1, 0); } + + + + virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override { NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta({a_BlockX, a_BlockY, a_BlockZ}); @@ -86,29 +94,45 @@ public: return true; } + + + + virtual bool IsUseable() override { return true; } - virtual void OnUpdate(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override + + + + + virtual void OnUpdate( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cBlockPluginInterface & a_PluginInterface, + cChunk & a_Chunk, + const Vector3i a_RelPos + ) override { - int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width; - int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width; - if (!a_WorldInterface.IsWeatherWetAt(BlockX, BlockZ) || (a_RelY != a_WorldInterface.GetHeight(BlockX, BlockZ))) + auto WorldPos = a_Chunk.RelativeToAbsolute(a_RelPos); + if (!a_WorldInterface.IsWeatherWetAtXYZ(WorldPos.addedY(1))) { // It's not raining at our current location or we do not have a direct view of the sky - // We cannot eat the rain :( return; } - NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ); + auto Meta = a_Chunk.GetMeta(a_RelPos); if (Meta < 3) { - a_Chunk.SetMeta(a_RelX, a_RelY, a_RelZ, Meta + 1); + a_Chunk.SetMeta(a_RelPos, Meta + 1); } } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockCocoaPod.h b/src/Blocks/BlockCocoaPod.h index 11190e0ba..74b7c3caa 100644 --- a/src/Blocks/BlockCocoaPod.h +++ b/src/Blocks/BlockCocoaPod.h @@ -38,11 +38,17 @@ public: - virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override + virtual void OnUpdate( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cBlockPluginInterface & a_PluginInterface, + cChunk & a_Chunk, + const Vector3i a_RelPos + ) override { if (GetRandomProvider().RandBool(0.20)) { - Grow(a_Chunk, {a_RelX, a_RelY, a_RelZ}); + Grow(a_Chunk, a_RelPos); } } diff --git a/src/Blocks/BlockFarmland.h b/src/Blocks/BlockFarmland.h index 20898b5e3..e5a55fcdd 100644 --- a/src/Blocks/BlockFarmland.h +++ b/src/Blocks/BlockFarmland.h @@ -41,26 +41,32 @@ public: - virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override + virtual void OnUpdate( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cBlockPluginInterface & a_PluginInterface, + cChunk & a_Chunk, + const Vector3i a_RelPos + ) override { - NIBBLETYPE BlockMeta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ); + auto BlockMeta = a_Chunk.GetMeta(a_RelPos); - if (IsWaterInNear(a_Chunk, a_RelX, a_RelY, a_RelZ)) + if (IsWaterInNear(a_Chunk, a_RelPos)) { // Water was found, set block meta to 7 - a_Chunk.FastSetBlock(a_RelX, a_RelY, a_RelZ, m_BlockType, 7); + a_Chunk.FastSetBlock(a_RelPos, m_BlockType, 7); return; } // Water wasn't found, de-hydrate block: if (BlockMeta > 0) { - a_Chunk.FastSetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_FARMLAND, --BlockMeta); + a_Chunk.FastSetBlock(a_RelPos, E_BLOCK_FARMLAND, --BlockMeta); return; } // Farmland too dry. If nothing is growing on top, turn back to dirt: - BLOCKTYPE UpperBlock = (a_RelY >= cChunkDef::Height - 1) ? static_cast(E_BLOCK_AIR) : a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ); + auto UpperBlock = cChunkDef::IsValidHeight(a_RelPos.y + 1) ? a_Chunk.GetBlock(a_RelPos.addedY(1)) : E_BLOCK_AIR; switch (UpperBlock) { case E_BLOCK_BEETROOTS: @@ -75,7 +81,7 @@ public: } default: { - a_Chunk.SetBlock({a_RelX, a_RelY, a_RelZ}, E_BLOCK_DIRT, 0); + a_Chunk.SetBlock(a_RelPos, E_BLOCK_DIRT, 0); break; } } @@ -111,11 +117,12 @@ public: - bool IsWaterInNear(cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) + /** Returns true if there's either a water source block close enough to hydrate the specified position, or it's raining there. */ + bool IsWaterInNear(cChunk & a_Chunk, const Vector3i a_RelPos) { - if (a_Chunk.GetWorld()->IsWeatherWetAt(a_RelX, a_RelZ)) + if (a_Chunk.GetWorld()->IsWeatherWetAtXYZ(a_RelPos)) { - // Rain hydrates farmland, too, except in Desert biomes. + // Rain hydrates farmland, too return true; } @@ -123,9 +130,8 @@ public: // Ref.: https://minecraft.gamepedia.com/Farmland#Hydration // TODO: Rewrite this to use the chunk and its neighbors directly cBlockArea Area; - int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width; - int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width; - if (!Area.Read(*a_Chunk.GetWorld(), BlockX - 4, BlockX + 4, a_RelY, a_RelY + 1, BlockZ - 4, BlockZ + 4)) + auto WorldPos = a_Chunk.RelativeToAbsolute(a_RelPos); + if (!Area.Read(*a_Chunk.GetWorld(), WorldPos - Vector3i(4, 0, 4), WorldPos + Vector3i(4, 1, 4))) { // Too close to the world edge, cannot check surroundings return false; @@ -144,6 +150,10 @@ public: return false; } + + + + virtual bool CanSustainPlant(BLOCKTYPE a_Plant) override { return ( diff --git a/src/Blocks/BlockFluid.h b/src/Blocks/BlockFluid.h index 36f363a92..e856dba38 100644 --- a/src/Blocks/BlockFluid.h +++ b/src/Blocks/BlockFluid.h @@ -80,6 +80,10 @@ public: return 0; } + + + + virtual bool CanSustainPlant(BLOCKTYPE a_Plant) override { return ( @@ -109,33 +113,47 @@ public: { } - /** Called to tick the block */ - virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override + + + + + virtual void OnUpdate( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cBlockPluginInterface & a_PluginInterface, + cChunk & a_Chunk, + const Vector3i a_RelPos + ) override { if (a_Chunk.GetWorld()->ShouldLavaSpawnFire()) { // Try to start up to 5 fires: for (int i = 0; i < 5; i++) { - TryStartFireNear(a_RelX, a_RelY, a_RelZ, a_Chunk); + TryStartFireNear(a_RelPos, a_Chunk); } } } + + + + /** Tries to start a fire near the lava at given coords. Returns true if fire started. */ - static bool TryStartFireNear(int a_RelX, int a_RelY, int a_RelZ, cChunk & a_Chunk) + static bool TryStartFireNear(const Vector3i a_RelPos, cChunk & a_Chunk) { - // Pick a block next to this lava block: + // Pick a random block next to this lava block: int rnd = a_Chunk.GetWorld()->GetTickRandomNumber(cChunkDef::NumBlocks * 8) / 7; int x = (rnd % 3) - 1; // -1 .. 1 int y = ((rnd / 4) % 4) - 1; // -1 .. 2 int z = ((rnd / 16) % 3) - 1; // -1 .. 1 + auto Pos = a_RelPos + Vector3i(x, y, z); // Check if it's fuel: BLOCKTYPE BlockType; if ( - ((a_RelY + y < 0) || (a_RelY + y >= cChunkDef::Height)) || - !a_Chunk.UnboundedRelGetBlockType(a_RelX + x, a_RelY + y, a_RelZ + z, BlockType) || + !cChunkDef::IsValidHeight(Pos.y) || + !a_Chunk.UnboundedRelGetBlockType(Pos, BlockType) || !cFireSimulator::IsFuel(BlockType) ) { @@ -143,10 +161,7 @@ public: } // Try to set it on fire: - static struct - { - int x, y, z; - } CrossCoords[] = + static Vector3i CrossCoords[] = { {-1, 0, 0}, { 1, 0, 0}, @@ -155,31 +170,37 @@ public: { 0, 0, -1}, { 0, 0, 1}, } ; - int RelX = a_RelX + x; - int RelY = a_RelY + y; - int RelZ = a_RelZ + z; for (size_t i = 0; i < ARRAYCOUNT(CrossCoords); i++) { + auto NeighborPos = Pos + CrossCoords[i]; if ( - ((RelY + CrossCoords[i].y >= 0) && (RelY + CrossCoords[i].y < cChunkDef::Height)) && - a_Chunk.UnboundedRelGetBlockType(RelX + CrossCoords[i].x, RelY + CrossCoords[i].y, RelZ + CrossCoords[i].z, BlockType) && + cChunkDef::IsValidHeight(NeighborPos.y) && + a_Chunk.UnboundedRelGetBlockType(NeighborPos, BlockType) && (BlockType == E_BLOCK_AIR) ) { - // This is an air block next to a fuel next to lava, light it up: - a_Chunk.UnboundedRelSetBlock(RelX + CrossCoords[i].x, RelY + CrossCoords[i].y, RelZ + CrossCoords[i].z, E_BLOCK_FIRE, 0); + // This is an air block next to a fuel next to lava, light the fuel block up: + a_Chunk.UnboundedRelSetBlock(NeighborPos, E_BLOCK_FIRE, 0); return true; } } // for i - CrossCoords[] return false; } + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); return 4; } + + + + virtual bool CanSustainPlant(BLOCKTYPE a_Plant) override { return false; diff --git a/src/Blocks/BlockGrass.h b/src/Blocks/BlockGrass.h index 0e54cb092..374fcceed 100644 --- a/src/Blocks/BlockGrass.h +++ b/src/Blocks/BlockGrass.h @@ -39,34 +39,39 @@ public: - virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override + virtual void OnUpdate( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cBlockPluginInterface & a_PluginInterface, + cChunk & a_Chunk, + const Vector3i a_RelPos + ) override { - // Make sure that there is enough light at the source block to spread if (!a_Chunk.GetWorld()->IsChunkLighted(a_Chunk.GetPosX(), a_Chunk.GetPosZ())) { a_Chunk.GetWorld()->QueueLightChunk(a_Chunk.GetPosX(), a_Chunk.GetPosZ()); return; } - else if ((a_RelY < cChunkDef::Height - 1)) + auto AbovePos = a_RelPos.addedY(1); + if (cChunkDef::IsValidHeight(AbovePos.y)) { - BLOCKTYPE above = a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ); - - // Grass turns back to dirt when the block above it is not transparent or water. - // It does not turn to dirt when a snow layer is above. - if ((above != E_BLOCK_SNOW) && - (!cBlockInfo::IsTransparent(above) || IsBlockWater(above))) + // Grass turns back to dirt when the block Above it is not transparent or water. + // It does not turn to dirt when a snow layer is Above. + auto Above = a_Chunk.GetBlock(AbovePos); + if ( + (Above != E_BLOCK_SNOW) && + (!cBlockInfo::IsTransparent(Above) || IsBlockWater(Above))) { - a_Chunk.FastSetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_DIRT, E_META_DIRT_NORMAL); + a_Chunk.FastSetBlock(a_RelPos, E_BLOCK_DIRT, E_META_DIRT_NORMAL); return; } - NIBBLETYPE light = std::max(a_Chunk.GetBlockLight(a_RelX, a_RelY + 1, a_RelZ), a_Chunk.GetTimeAlteredLight(a_Chunk.GetSkyLight(a_RelX, a_RelY + 1, a_RelZ))); - // Source block is not bright enough to spread + // Make sure that there is enough light at the source block to spread + auto light = std::max(a_Chunk.GetBlockLight(AbovePos), a_Chunk.GetTimeAlteredLight(a_Chunk.GetSkyLight(AbovePos))); if (light < 9) { return; } - } // Grass spreads to adjacent dirt blocks: @@ -79,37 +84,36 @@ public: BLOCKTYPE DestBlock; NIBBLETYPE DestMeta; - if (!cChunkDef::IsValidHeight(a_RelY + OfsY)) + auto Pos = a_RelPos + Vector3i(OfsX, OfsY, OfsZ); + if (!cChunkDef::IsValidHeight(Pos.y)) { // Y Coord out of range continue; } - Vector3i pos(a_RelX + OfsX, a_RelY + OfsY, a_RelZ + OfsZ); - auto chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(pos); + auto chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(Pos); if (chunk == nullptr) { // Unloaded chunk continue; } - chunk->GetBlockTypeMeta(pos, DestBlock, DestMeta); + chunk->GetBlockTypeMeta(Pos, DestBlock, DestMeta); if ((DestBlock != E_BLOCK_DIRT) || (DestMeta != E_META_DIRT_NORMAL)) { // Not a regular dirt block continue; } - auto abovePos = pos.addedY(1); - BLOCKTYPE above = chunk->GetBlock(abovePos); - NIBBLETYPE light = std::max(chunk->GetBlockLight(abovePos), chunk->GetTimeAlteredLight(chunk->GetSkyLight(abovePos))); + BLOCKTYPE Above = chunk->GetBlock(AbovePos); + NIBBLETYPE light = std::max(chunk->GetBlockLight(AbovePos), chunk->GetTimeAlteredLight(chunk->GetSkyLight(AbovePos))); if ((light > 4) && - cBlockInfo::IsTransparent(above) && - (!IsBlockLava(above)) && - (!IsBlockWaterOrIce(above)) + cBlockInfo::IsTransparent(Above) && + (!IsBlockLava(Above)) && + (!IsBlockWaterOrIce(Above)) ) { - auto absPos = chunk->RelativeToAbsolute(pos); + auto absPos = chunk->RelativeToAbsolute(Pos); if (!cRoot::Get()->GetPluginManager()->CallHookBlockSpread(*chunk->GetWorld(), absPos.x, absPos.y, absPos.z, ssGrassSpread)) { - chunk->FastSetBlock(pos, E_BLOCK_GRASS, 0); + chunk->FastSetBlock(Pos, E_BLOCK_GRASS, 0); } } } // for i - repeat twice diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp index b3c777b05..f1df4db44 100644 --- a/src/Blocks/BlockHandler.cpp +++ b/src/Blocks/BlockHandler.cpp @@ -421,7 +421,13 @@ bool cBlockHandler::GetPlacementBlockTypeMeta( -void cBlockHandler::OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_BlockX, int a_BlockY, int a_BlockZ) +void cBlockHandler::OnUpdate( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cBlockPluginInterface & a_PluginInterface, + cChunk & a_Chunk, + const Vector3i a_RelPos +) { } diff --git a/src/Blocks/BlockHandler.h b/src/Blocks/BlockHandler.h index 75f6610ce..f4a7fc674 100644 --- a/src/Blocks/BlockHandler.h +++ b/src/Blocks/BlockHandler.h @@ -30,8 +30,14 @@ public: virtual ~cBlockHandler() {} /** Called when the block gets ticked either by a random tick or by a queued tick. - Note that the coords are chunk-relative! */ - virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ); + Note that the coords in a_RelPos are chunk-relative! */ + virtual void OnUpdate( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cBlockPluginInterface & a_BlockPluginInterface, + cChunk & a_Chunk, + const Vector3i a_RelPos + ); /** Returns the relative bounding box that must be entity-free in order for the block to be placed. a_XM, a_XP, etc. stand for the @@ -108,7 +114,14 @@ public: static void NeighborChanged(cChunkInterface & a_ChunkInterface, Vector3i a_NeighborPos, eBlockFace a_WhichNeighbor); /** Called when the player starts digging the block. */ - virtual void OnDigging(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) {} + virtual void OnDigging( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cPlayer & a_Player, + int a_BlockX, int a_BlockY, int a_BlockZ + ) + { + } /** Called if the user right clicks the block and the block is useable returns true if the use was successful, return false to use the block as a "normal" block */ diff --git a/src/Blocks/BlockLeaves.h b/src/Blocks/BlockLeaves.h index 065c5ec19..c936e0405 100644 --- a/src/Blocks/BlockLeaves.h +++ b/src/Blocks/BlockLeaves.h @@ -10,29 +10,88 @@ // Leaves can be this many blocks that away (inclusive) from the log not to decay #define LEAVES_CHECK_DISTANCE 6 -#define PROCESS_NEIGHBOR(x, y, z) \ - do { \ - switch (a_Area.GetBlockType(x, y, z)) \ - { \ - case E_BLOCK_LEAVES: a_Area.SetBlockType(x, y, z, static_cast(E_BLOCK_SPONGE + i + 1)); break; \ - case E_BLOCK_LOG: return true; \ - case E_BLOCK_NEW_LEAVES: a_Area.SetBlockType(x, y, z, static_cast(E_BLOCK_SPONGE + i + 1)); break; \ - case E_BLOCK_NEW_LOG: return true; \ - } \ - } while (false) -bool HasNearLog(cBlockArea &a_Area, int a_BlockX, int a_BlockY, int a_BlockZ); - - -class cBlockLeavesHandler : +class cBlockLeavesHandler: public cBlockHandler { + using Super = cBlockHandler; + + /** Returns true if the area contains a continous path from the specified block to a log block entirely made out of leaves blocks. */ + static bool HasNearLog(cBlockArea & a_Area, const Vector3i a_BlockPos) + { + // Filter the blocks into a {leaves, log, other (air)} set: + auto * Types = a_Area.GetBlockTypes(); + for (size_t i = a_Area.GetBlockCount() - 1; i > 0; i--) + { + switch (Types[i]) + { + case E_BLOCK_LEAVES: + case E_BLOCK_LOG: + case E_BLOCK_NEW_LEAVES: + case E_BLOCK_NEW_LOG: + { + break; + } + default: + { + Types[i] = E_BLOCK_AIR; + break; + } + } + } // for i - Types[] + + // Perform a breadth-first search to see if there's a log connected within 4 blocks of the leaves block: + // Simply replace all reachable leaves blocks with a sponge block plus iteration (in the Area) and see if we can reach a log + a_Area.SetBlockType(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, E_BLOCK_SPONGE); + for (int i = 0; i < LEAVES_CHECK_DISTANCE; i++) + { + auto ProcessNeighbor = [&a_Area, i](int cbx, int cby, int cbz) -> bool + { + switch (a_Area.GetBlockType(cbx, cby, cbz)) + { + case E_BLOCK_LEAVES: a_Area.SetBlockType(cbx, cby, cbz, static_cast(E_BLOCK_SPONGE + i + 1)); break; + case E_BLOCK_LOG: return true; + case E_BLOCK_NEW_LEAVES: a_Area.SetBlockType(cbx, cby, cbz, static_cast(E_BLOCK_SPONGE + i + 1)); break; + case E_BLOCK_NEW_LOG: return true; + } + return false; + }; + for (int y = std::max(a_BlockPos.y - i, 0); y <= std::min(a_BlockPos.y + i, cChunkDef::Height - 1); y++) + { + for (int z = a_BlockPos.z - i; z <= a_BlockPos.z + i; z++) + { + for (int x = a_BlockPos.x - i; x <= a_BlockPos.x + i; x++) + { + if (a_Area.GetBlockType(x, y, z) != E_BLOCK_SPONGE + i) + { + continue; + } + if ( + ProcessNeighbor(x - 1, y, z) || + ProcessNeighbor(x + 1, y, z) || + ProcessNeighbor(x, y, z - 1) || + ProcessNeighbor(x, y, z + 1) || + ProcessNeighbor(x, y + 1, z) || + ProcessNeighbor(x, y - 1, z) + ) + { + return true; + } + } // for x + } // for z + } // for y + } // for i - BFS iterations + return false; + } + + public: - cBlockLeavesHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + + cBlockLeavesHandler(BLOCKTYPE a_BlockType): + Super(a_BlockType) { } @@ -104,30 +163,34 @@ public: - virtual void OnUpdate(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override + virtual void OnUpdate( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cBlockPluginInterface & a_PluginInterface, + cChunk & a_Chunk, + const Vector3i a_RelPos + ) override { - NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ); + auto Meta = a_Chunk.GetMeta(a_RelPos); if ((Meta & 0x04) != 0) { // Player-placed leaves, don't decay return; } - if ((Meta & 0x8) == 0) + if ((Meta & 0x08) == 0) { // These leaves have been checked for decay lately and nothing around them changed return; } // Get the data around the leaves: - int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width; - int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width; + auto worldPos = a_Chunk.RelativeToAbsolute(a_RelPos); cBlockArea Area; if (!Area.Read( *a_Chunk.GetWorld(), - BlockX - LEAVES_CHECK_DISTANCE, BlockX + LEAVES_CHECK_DISTANCE, - a_RelY - LEAVES_CHECK_DISTANCE, a_RelY + LEAVES_CHECK_DISTANCE, - BlockZ - LEAVES_CHECK_DISTANCE, BlockZ + LEAVES_CHECK_DISTANCE, + worldPos - Vector3i(LEAVES_CHECK_DISTANCE, LEAVES_CHECK_DISTANCE, LEAVES_CHECK_DISTANCE), + worldPos + Vector3i(LEAVES_CHECK_DISTANCE, LEAVES_CHECK_DISTANCE, LEAVES_CHECK_DISTANCE), cBlockArea::baTypes) ) { @@ -135,15 +198,15 @@ public: return; } - if (HasNearLog(Area, BlockX, a_RelY, BlockZ)) + if (HasNearLog(Area, worldPos)) { // Wood found, the leaves stay; unset the check bit - a_Chunk.SetMeta(a_RelX, a_RelY, a_RelZ, Meta ^ 0x08, true, false); + a_Chunk.SetMeta(a_RelPos, Meta ^ 0x08, true, false); return; } // Decay the leaves: - a_ChunkInterface.DropBlockAsPickups({BlockX, a_RelY, BlockZ}); + a_ChunkInterface.DropBlockAsPickups(worldPos); } @@ -156,62 +219,3 @@ public: return 7; } } ; - - - - - -bool HasNearLog(cBlockArea & a_Area, int a_BlockX, int a_BlockY, int a_BlockZ) -{ - // Filter the blocks into a {leaves, log, other (air)} set: - BLOCKTYPE * Types = a_Area.GetBlockTypes(); - for (size_t i = a_Area.GetBlockCount() - 1; i > 0; i--) - { - switch (Types[i]) - { - case E_BLOCK_LEAVES: - case E_BLOCK_LOG: - case E_BLOCK_NEW_LEAVES: - case E_BLOCK_NEW_LOG: - { - break; - } - default: - { - Types[i] = E_BLOCK_AIR; - break; - } - } - } // for i - Types[] - - // Perform a breadth-first search to see if there's a log connected within 4 blocks of the leaves block: - // Simply replace all reachable leaves blocks with a sponge block plus iteration (in the Area) and see if we can reach a log in 4 iterations - a_Area.SetBlockType(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_SPONGE); - for (int i = 0; i < LEAVES_CHECK_DISTANCE; i++) - { - for (int y = std::max(a_BlockY - i, 0); y <= std::min(a_BlockY + i, cChunkDef::Height - 1); y++) - { - for (int z = a_BlockZ - i; z <= a_BlockZ + i; z++) - { - for (int x = a_BlockX - i; x <= a_BlockX + i; x++) - { - if (a_Area.GetBlockType(x, y, z) != E_BLOCK_SPONGE + i) - { - continue; - } - PROCESS_NEIGHBOR(x - 1, y, z); - PROCESS_NEIGHBOR(x + 1, y, z); - PROCESS_NEIGHBOR(x, y, z - 1); - PROCESS_NEIGHBOR(x, y, z + 1); - PROCESS_NEIGHBOR(x, y + 1, z); - PROCESS_NEIGHBOR(x, y - 1, z); - } // for x - } // for z - } // for y - } // for i - BFS iterations - return false; -} - - - - diff --git a/src/Blocks/BlockPlant.h b/src/Blocks/BlockPlant.h index 589619b26..b0760528c 100644 --- a/src/Blocks/BlockPlant.h +++ b/src/Blocks/BlockPlant.h @@ -26,20 +26,25 @@ public: - virtual void OnUpdate(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override + virtual void OnUpdate( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cBlockPluginInterface & a_PluginInterface, + cChunk & a_Chunk, + const Vector3i a_RelPos + ) override { - Vector3i relPos(a_RelX, a_RelY, a_RelZ); - auto action = CanGrow(a_Chunk, relPos); - switch (action) + auto Action = CanGrow(a_Chunk, a_RelPos); + switch (Action) { case paGrowth: { - Grow(a_Chunk, relPos); + Grow(a_Chunk, a_RelPos); break; } case paDeath: { - a_ChunkInterface.DigBlock(a_WorldInterface, a_Chunk.RelativeToAbsolute(relPos)); + a_ChunkInterface.DigBlock(a_WorldInterface, a_Chunk.RelativeToAbsolute(a_RelPos)); break; } case paStay: break; // do nothing diff --git a/src/Blocks/BlockPortal.h b/src/Blocks/BlockPortal.h index 852a231b6..3f5d87155 100644 --- a/src/Blocks/BlockPortal.h +++ b/src/Blocks/BlockPortal.h @@ -46,18 +46,26 @@ public: - virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override + virtual void OnUpdate( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cBlockPluginInterface & a_PluginInterface, + cChunk & a_Chunk, + const Vector3i a_RelPos + ) override { + // Spawn zombie pigmen with a 0.05% chance: if (GetRandomProvider().RandBool(0.9995)) { return; } + auto WorldPos = a_Chunk.RelativeToAbsolute(a_RelPos); + a_WorldInterface.SpawnMob(WorldPos.x, WorldPos.y, WorldPos.z, mtZombiePigman, false); + } + + - int PosX = a_Chunk.GetPosX() * cChunkDef::Width + a_RelX; - int PosZ = a_Chunk.GetPosZ() * cChunkDef::Width + a_RelZ; - a_WorldInterface.SpawnMob(PosX, a_RelY, PosZ, mtZombiePigman, false); - } virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { diff --git a/src/Blocks/BlockRedstoneOre.h b/src/Blocks/BlockRedstoneOre.h index cb6f73733..4b570ab73 100644 --- a/src/Blocks/BlockRedstoneOre.h +++ b/src/Blocks/BlockRedstoneOre.h @@ -12,9 +12,10 @@ class cBlockRedstoneOreHandler : public cBlockOreHandler { using Super = cBlockOreHandler; + public: - using Super::Super; + using Super::Super; // Inherit constructor from base virtual bool OnUse( cChunkInterface & a_ChunkInterface, @@ -55,19 +56,19 @@ class cBlockGlowingRedstoneOreHandler: public cBlockOreHandler { using Super = cBlockOreHandler; + public: - using Super::Super; + using Super::Super; // Inherit constructor from base virtual void OnUpdate( cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cChunk & a_Chunk, - int a_RelX, int a_RelY, int a_RelZ + const Vector3i a_RelPos ) override { - const Vector3i a_RelPos{a_RelX, a_RelY, a_RelZ}; auto BlockPos = a_Chunk.RelativeToAbsolute(a_RelPos); a_ChunkInterface.SetBlock(BlockPos, E_BLOCK_REDSTONE_ORE, 0); } diff --git a/src/Blocks/BlockSapling.h b/src/Blocks/BlockSapling.h index b66587288..370353882 100644 --- a/src/Blocks/BlockSapling.h +++ b/src/Blocks/BlockSapling.h @@ -43,26 +43,31 @@ public: - virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override + virtual void OnUpdate( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cBlockPluginInterface & a_PluginInterface, + cChunk & a_Chunk, + const Vector3i a_RelPos + ) override { - NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ); - NIBBLETYPE Light = std::max(a_Chunk.GetBlockLight(a_RelX, a_RelY, a_RelZ), a_Chunk.GetTimeAlteredLight(a_Chunk.GetSkyLight(a_RelX, a_RelY, a_RelZ))); + auto Meta = a_Chunk.GetMeta(a_RelPos); + auto Light = std::max(a_Chunk.GetBlockLight(a_RelPos), a_Chunk.GetTimeAlteredLight(a_Chunk.GetSkyLight(a_RelPos))); // Only grow if we have the right amount of light if (Light > 8) { auto & random = GetRandomProvider(); // Only grow if we are in the right growth stage and have the right amount of space around them. - if (((Meta & 0x08) != 0) && random.RandBool(0.45) && CanGrowAt(a_Chunk, a_RelX, a_RelY, a_RelZ, Meta)) + if (((Meta & 0x08) != 0) && random.RandBool(0.45) && CanGrowAt(a_Chunk, a_RelPos.x, a_RelPos.y, a_RelPos.z, Meta)) { - int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width; - int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width; - a_Chunk.GetWorld()->GrowTree(BlockX, a_RelY, BlockZ); + auto WorldPos = a_Chunk.RelativeToAbsolute(a_RelPos); + a_Chunk.GetWorld()->GrowTree(WorldPos.x, WorldPos.y, WorldPos.z); } // Only move to the next growth stage if we haven't gone there yet else if (((Meta & 0x08) == 0) && random.RandBool(0.45)) { - a_Chunk.SetMeta(a_RelX, a_RelY, a_RelZ, Meta | 0x08); + a_Chunk.SetMeta(a_RelPos, Meta | 0x08); } } } diff --git a/src/Blocks/BlockVine.h b/src/Blocks/BlockVine.h index 9c3c1c53e..f8328f046 100644 --- a/src/Blocks/BlockVine.h +++ b/src/Blocks/BlockVine.h @@ -221,25 +221,33 @@ public: - virtual void OnUpdate(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override + virtual void OnUpdate( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cBlockPluginInterface & a_PluginInterface, + cChunk & a_Chunk, + const Vector3i a_RelPos + ) override { UNUSED(a_ChunkInterface); UNUSED(a_WorldInterface); // Vine cannot grow down if at the bottom: - if (a_RelY < 1) + auto GrowPos = a_RelPos.addedY(-1); + if (!cChunkDef::IsValidHeight(GrowPos.y)) { return; } // Grow one block down, if possible: BLOCKTYPE Block; - a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY - 1, a_RelZ, Block); + a_Chunk.UnboundedRelGetBlockType(GrowPos, Block); if (Block == E_BLOCK_AIR) { - if (!a_BlockPluginInterface.CallHookBlockSpread(a_RelX + a_Chunk.GetPosX() * cChunkDef::Width, a_RelY - 1, a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width, ssVineSpread)) + auto WorldPos = a_Chunk.RelativeToAbsolute(GrowPos); + if (!a_PluginInterface.CallHookBlockSpread(WorldPos.x, WorldPos.y, WorldPos.z, ssVineSpread)) { - a_Chunk.UnboundedRelSetBlock(a_RelX, a_RelY - 1, a_RelZ, E_BLOCK_VINES, a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ)); + a_Chunk.UnboundedRelSetBlock(GrowPos, E_BLOCK_VINES, a_Chunk.GetMeta(a_RelPos)); } } } diff --git a/src/Blocks/CMakeLists.txt b/src/Blocks/CMakeLists.txt index 24d0a20a6..dea14b7f1 100644 --- a/src/Blocks/CMakeLists.txt +++ b/src/Blocks/CMakeLists.txt @@ -47,6 +47,7 @@ SET (HDRS BlockFurnace.h BlockGlass.h BlockGlowstone.h + BlockGrass.h BlockGravel.h BlockHandler.h BlockHopper.h diff --git a/src/Blocks/WorldInterface.h b/src/Blocks/WorldInterface.h index b4dcfa4a9..0967e2bb8 100644 --- a/src/Blocks/WorldInterface.h +++ b/src/Blocks/WorldInterface.h @@ -73,6 +73,10 @@ public: /** Returns true if it is raining or storming at the specified location. This takes into account biomes. */ virtual bool IsWeatherWetAt(int a_BlockX, int a_BlockZ) = 0; + /** Returns true if it is raining or storming at the specified location, + and the rain reaches the specified block position. */ + virtual bool IsWeatherWetAtXYZ(Vector3i a_Pos) = 0; + /** Returns or sets the minumim or maximum netherportal width */ virtual int GetMinNetherPortalWidth(void) const = 0; virtual int GetMaxNetherPortalWidth(void) const = 0; -- cgit v1.2.3