summaryrefslogtreecommitdiffstats
path: root/src/Blocks
diff options
context:
space:
mode:
Diffstat (limited to 'src/Blocks')
-rw-r--r--src/Blocks/BlockCauldron.h38
-rw-r--r--src/Blocks/BlockCocoaPod.h10
-rw-r--r--src/Blocks/BlockFarmland.h36
-rw-r--r--src/Blocks/BlockFluid.h57
-rw-r--r--src/Blocks/BlockGrass.h54
-rw-r--r--src/Blocks/BlockHandler.cpp8
-rw-r--r--src/Blocks/BlockHandler.h19
-rw-r--r--src/Blocks/BlockLeaves.h176
-rw-r--r--src/Blocks/BlockPlant.h17
-rw-r--r--src/Blocks/BlockPortal.h18
-rw-r--r--src/Blocks/BlockRedstoneOre.h9
-rw-r--r--src/Blocks/BlockSapling.h21
-rw-r--r--src/Blocks/BlockVine.h18
-rw-r--r--src/Blocks/CMakeLists.txt1
-rw-r--r--src/Blocks/WorldInterface.h4
15 files changed, 303 insertions, 183 deletions
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<BLOCKTYPE>(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<BLOCKTYPE>(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<BLOCKTYPE>(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<BLOCKTYPE>(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<BLOCKTYPE>(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;