From 8090c13cde2d61a0330f1e262de7526318a0965d Mon Sep 17 00:00:00 2001 From: "madmaxoft@gmail.com" Date: Fri, 15 Mar 2013 20:18:11 +0000 Subject: Huge performance boost in blockhandlers, they have direct access to chunk data when blockchecking. Also fixed vines' placement. git-svn-id: http://mc-server.googlecode.com/svn/trunk@1278 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- source/Blocks/BlockCactus.h | 37 ++++-- source/Blocks/BlockCrops.h | 4 +- source/Blocks/BlockDoor.h | 4 +- source/Blocks/BlockFlower.h | 4 +- source/Blocks/BlockFluid.h | 8 +- source/Blocks/BlockHandler.cpp | 25 ++-- source/Blocks/BlockHandler.h | 9 +- source/Blocks/BlockLadder.h | 19 +-- source/Blocks/BlockMushroom.h | 11 +- source/Blocks/BlockRail.h | 212 +++++++++++++++++++++++----------- source/Blocks/BlockRedstone.h | 4 +- source/Blocks/BlockRedstoneRepeater.h | 4 +- source/Blocks/BlockSapling.h | 4 +- source/Blocks/BlockSnow.h | 5 +- source/Blocks/BlockStems.h | 4 +- source/Blocks/BlockSugarcane.h | 36 +++++- source/Blocks/BlockTallGrass.h | 4 +- source/Blocks/BlockTorch.h | 11 +- source/Blocks/BlockVine.h | 105 ++++++++++++----- 19 files changed, 344 insertions(+), 166 deletions(-) (limited to 'source/Blocks') diff --git a/source/Blocks/BlockCactus.h b/source/Blocks/BlockCactus.h index daa0e02c2..516f024d8 100644 --- a/source/Blocks/BlockCactus.h +++ b/source/Blocks/BlockCactus.h @@ -24,9 +24,13 @@ public: } - virtual bool CanBeAt(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ) override + virtual bool CanBeAt(int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { - BLOCKTYPE Surface = a_World->GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ); + if (a_RelY <= 0) + { + return false; + } + BLOCKTYPE Surface = a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ); if ((Surface != E_BLOCK_SAND) && (Surface != E_BLOCK_CACTUS)) { // Cactus can only be placed on sand and itself @@ -34,15 +38,28 @@ public: } // Check surroundings. Cacti may ONLY be surrounded by air - if ( - (a_World->GetBlock(a_BlockX - 1, a_BlockY, a_BlockZ) != E_BLOCK_AIR) || - (a_World->GetBlock(a_BlockX + 1, a_BlockY, a_BlockZ) != E_BLOCK_AIR) || - (a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ - 1) != E_BLOCK_AIR) || - (a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ + 1) != E_BLOCK_AIR) - ) + static const struct { - return false; - } + int x, z; + } Coords[] = + { + {-1, 0}, + { 1, 0}, + { 0, -1}, + { 0, 1}, + } ; + for (int i = 0; i < ARRAYCOUNT(Coords); i++) + { + BLOCKTYPE BlockType; + NIBBLETYPE BlockMeta; + if ( + a_Chunk.UnboundedRelGetBlock(a_RelX + Coords[i].x, a_RelY, a_RelZ + Coords[i].z, BlockType, BlockMeta) && + (BlockType != E_BLOCK_AIR) + ) + { + return false; + } + } // for i - Coords[] return true; } diff --git a/source/Blocks/BlockCrops.h b/source/Blocks/BlockCrops.h index 0a8017a91..a269c7c32 100644 --- a/source/Blocks/BlockCrops.h +++ b/source/Blocks/BlockCrops.h @@ -44,9 +44,9 @@ public: } - virtual bool CanBeAt(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ) override + virtual bool CanBeAt(int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { - return a_World->GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ) == E_BLOCK_FARMLAND; + return ((a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) == E_BLOCK_FARMLAND)); } diff --git a/source/Blocks/BlockDoor.h b/source/Blocks/BlockDoor.h index 0e4a5ff52..a988c2d4b 100644 --- a/source/Blocks/BlockDoor.h +++ b/source/Blocks/BlockDoor.h @@ -74,9 +74,9 @@ public: } - virtual bool CanBeAt(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ) override + virtual bool CanBeAt(int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { - return (a_World->GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ) != E_BLOCK_AIR); + return ((a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) != E_BLOCK_AIR)); } diff --git a/source/Blocks/BlockFlower.h b/source/Blocks/BlockFlower.h index 7db42c9fc..b46273c51 100644 --- a/source/Blocks/BlockFlower.h +++ b/source/Blocks/BlockFlower.h @@ -24,9 +24,9 @@ public: } - virtual bool CanBeAt(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ) override + virtual bool CanBeAt(int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { - return IsBlockTypeOfDirt(a_World->GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ)); + return (a_RelY > 0) && IsBlockTypeOfDirt(a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ)); } diff --git a/source/Blocks/BlockFluid.h b/source/Blocks/BlockFluid.h index a8cd9c497..b184a5b33 100644 --- a/source/Blocks/BlockFluid.h +++ b/source/Blocks/BlockFluid.h @@ -26,22 +26,22 @@ public: } - virtual void Check(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ) override + virtual void Check(int a_RelX, int a_RelY, int a_RelZ, cChunk & a_Chunk) override { switch (m_BlockType) { case E_BLOCK_STATIONARY_LAVA: { - a_World->FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_LAVA, a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ)); + a_Chunk.FastSetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_LAVA, a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ)); break; } case E_BLOCK_STATIONARY_WATER: { - a_World->FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_WATER, a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ)); + a_Chunk.FastSetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_WATER, a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ)); break; } } - super::Check(a_World, a_BlockX, a_BlockY, a_BlockZ); + super::Check(a_RelX, a_RelY, a_RelZ, a_Chunk); } } ; diff --git a/source/Blocks/BlockHandler.cpp b/source/Blocks/BlockHandler.cpp index 71d56f94d..991102aca 100644 --- a/source/Blocks/BlockHandler.cpp +++ b/source/Blocks/BlockHandler.cpp @@ -351,16 +351,7 @@ const char * cBlockHandler::GetStepSound() -bool cBlockHandler::CanBePlacedAt(cWorld *a_World, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Dir) -{ - return CanBeAt(a_World, a_BlockX, a_BlockY, a_BlockZ); -} - - - - - -bool cBlockHandler::CanBeAt(cWorld *a_World, int a_BlockX, int a_BlockY, int a_BlockZ) +bool cBlockHandler::CanBeAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cChunk & a_Chunk) { return true; } @@ -423,21 +414,25 @@ bool cBlockHandler::DoesDropOnUnsuitable(void) -void cBlockHandler::Check(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ) +void cBlockHandler::Check(int a_RelX, int a_RelY, int a_RelZ, cChunk & a_Chunk) { - if (!CanBeAt(a_World, a_BlockX, a_BlockY, a_BlockZ)) + if (!CanBeAt(a_RelX, a_RelY, a_RelZ, a_Chunk)) { if (DoesDropOnUnsuitable()) { - DropBlock(a_World, NULL, a_BlockX, a_BlockY, a_BlockZ); + int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width; + int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width; + DropBlock(a_Chunk.GetWorld(), NULL, BlockX, a_RelY, BlockZ); } - a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0); + a_Chunk.SetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_AIR, 0); } else { // Wake up the simulators for this block: - a_World->WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ); + int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width; + int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width; + a_Chunk.GetWorld()->GetSimulatorManager()->WakeUp(BlockX, a_RelY, BlockZ, &a_Chunk); } } diff --git a/source/Blocks/BlockHandler.h b/source/Blocks/BlockHandler.h index e551668f9..4c91463bc 100644 --- a/source/Blocks/BlockHandler.h +++ b/source/Blocks/BlockHandler.h @@ -3,6 +3,7 @@ #include "../Defines.h" #include "../Item.h" +#include "../Chunk.h" @@ -74,14 +75,14 @@ public: /// Returns step sound name of block virtual const char * GetStepSound(void); - /// Checks if the block can stay at the specified coords in the world - virtual bool CanBeAt(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ); + /// Checks if the block can stay at the specified relative coords in the chunk + virtual bool CanBeAt(int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk); /** Checks if the block can be placed at this point. Default: CanBeAt(...) NOTE: This call doesn't actually place the block */ - virtual bool CanBePlacedAt(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Dir); + // virtual bool CanBePlacedAt(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Dir); /// Called when the player tries to place a block on top of this block (Only if he aims directly on this block); return false to disallow virtual bool DoesAllowBlockOnTop(void); @@ -109,7 +110,7 @@ public: By default drops if position no more suitable (CanBeAt(), DoesDropOnUnsuitable(), Drop()), and wakes up all simulators on the block. */ - virtual void Check(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ); + virtual void Check(int a_RelX, int a_RelY, int a_RelZ, cChunk & a_Chunk); /// Get the blockhandler for a specific block id diff --git a/source/Blocks/BlockLadder.h b/source/Blocks/BlockLadder.h index 5f0b09737..280f0deb1 100644 --- a/source/Blocks/BlockLadder.h +++ b/source/Blocks/BlockLadder.h @@ -69,20 +69,13 @@ public: } - virtual bool CanBePlacedAt(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) override + virtual bool CanBeAt(int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { - if (LadderCanBePlacedAt(a_World, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace)) - { - return true; - } - return (FindSuitableBlockFace(a_World, a_BlockX, a_BlockY, a_BlockZ) != BLOCK_FACE_BOTTOM); - } - - - virtual bool CanBeAt(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ) override - { - char BlockFace = cLadder::MetaDataToDirection(a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ)); - return CanBePlacedAt(a_World, a_BlockX, a_BlockY, a_BlockZ, BlockFace); + // TODO: Use cTorch::AdjustCoordsByMeta(), then cChunk::UnboundedRelGetBlock() and finally some comparison + char BlockFace = cLadder::MetaDataToDirection(a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ)); + int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width; + int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width; + return LadderCanBePlacedAt(a_Chunk.GetWorld(), BlockX, a_RelY, BlockZ, BlockFace); } diff --git a/source/Blocks/BlockMushroom.h b/source/Blocks/BlockMushroom.h index 96bdbc310..62cc898c0 100644 --- a/source/Blocks/BlockMushroom.h +++ b/source/Blocks/BlockMushroom.h @@ -24,9 +24,16 @@ public: } - virtual bool CanBeAt(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ) override + virtual bool CanBeAt(int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { - switch (a_World->GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ)) + if (a_RelY <= 0) + { + return false; + } + + // TODO: Cannot be at too much daylight + + switch (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ)) { case E_BLOCK_GLASS: case E_BLOCK_CACTUS: diff --git a/source/Blocks/BlockRail.h b/source/Blocks/BlockRail.h index 733f92c8c..60865abf5 100644 --- a/source/Blocks/BlockRail.h +++ b/source/Blocks/BlockRail.h @@ -8,19 +8,36 @@ +/// Meta values for the rail enum ENUM_RAIL_DIRECTIONS { - E_RAIL_NORTH_SOUTH = 0, - E_RAIL_EAST_WEST = 1, - E_RAIL_ASCEND_EAST = 2, - E_RAIL_ASCEND_WEST = 3, - E_RAIL_ASCEND_NORTH = 4, - E_RAIL_ASCEND_SOUTH = 5, + E_RAIL_NORTH_SOUTH = 0, + E_RAIL_EAST_WEST = 1, + E_RAIL_ASCEND_EAST = 2, + E_RAIL_ASCEND_WEST = 3, + E_RAIL_ASCEND_NORTH = 4, + E_RAIL_ASCEND_SOUTH = 5, E_RAIL_CURVED_SOUTH_EAST = 6, E_RAIL_CURVED_SOUTH_WEST = 7, E_RAIL_CURVED_NORTH_WEST = 8, - E_RAIL_CURVED_NORTH_EAST = 9 -}; + E_RAIL_CURVED_NORTH_EAST = 9, + + // Some useful synonyms: + E_RAIL_DIR_X = E_RAIL_EAST_WEST, + E_RAIL_DIR_Z = E_RAIL_NORTH_SOUTH, + E_RAIL_ASCEND_XP = E_RAIL_ASCEND_EAST, + E_RAIL_ASCEND_XM = E_RAIL_ASCEND_WEST, + E_RAIL_ASCEND_ZM = E_RAIL_ASCEND_NORTH, + E_RAIL_ASCEND_ZP = E_RAIL_ASCEND_SOUTH, + E_RAIL_CURVED_XPZP = E_RAIL_CURVED_SOUTH_EAST, + E_RAIL_CURVED_XMZP = E_RAIL_CURVED_SOUTH_WEST, + E_RAIL_CURVED_XMZM = E_RAIL_CURVED_NORTH_WEST, + E_RAIL_CURVED_XPZM = E_RAIL_CURVED_NORTH_EAST, +} ; + + + + enum ENUM_PURE { @@ -65,46 +82,45 @@ public: } - virtual bool CanBeAt(cWorld *a_World, int a_BlockX, int a_BlockY, int a_BlockZ) override + virtual bool CanBeAt(int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { - if (!g_BlockIsSolid[a_World->GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ)]) + if (a_RelY <= 0) { return false; } - NIBBLETYPE Meta = a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); + if (!g_BlockIsSolid[a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ)]) + { + return false; + } + + NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ); switch (Meta) { case E_RAIL_ASCEND_EAST: - { - if (!g_BlockIsSolid[a_World->GetBlock(a_BlockX + 1, a_BlockY, a_BlockZ)]) - { - return false; - } - break; - } case E_RAIL_ASCEND_WEST: - { - if (!g_BlockIsSolid[a_World->GetBlock(a_BlockX - 1, a_BlockY, a_BlockZ)]) - { - return false; - } - break; - } case E_RAIL_ASCEND_NORTH: - { - if (!g_BlockIsSolid[a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ - 1)]) - { - return false; - } - break; - } case E_RAIL_ASCEND_SOUTH: { - if (!g_BlockIsSolid[a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ + 1)]) + // Mapping between the meta and the neighbors that need checking + Meta -= E_RAIL_ASCEND_EAST; // Base index at zero + static const struct { - return false; + int x, z; + } Coords[] = + { + { 1, 0}, // east, XP + {-1, 0}, // west, XM + { 0, -1}, // north, ZM + { 0, 1}, // south, ZP + } ; + BLOCKTYPE BlockType; + NIBBLETYPE BlockMeta; + if (!a_Chunk.UnboundedRelGetBlock(a_RelX + Coords[Meta].x, a_RelY, a_RelZ + Coords[Meta].z, BlockType, BlockMeta)) + { + // Too close to the edge, cannot simulate + return true; } - break; + return g_BlockIsSolid[BlockType]; } } return true; @@ -159,16 +175,16 @@ public: } if (RailsCnt > 1) { - if (Neighbors[3] && Neighbors[0]) return E_RAIL_CURVED_SOUTH_EAST; - else if(Neighbors[3] && Neighbors[1]) return E_RAIL_CURVED_SOUTH_WEST; - else if(Neighbors[2] && Neighbors[0]) return E_RAIL_CURVED_NORTH_EAST; - else if(Neighbors[2] && Neighbors[1]) return E_RAIL_CURVED_NORTH_WEST; - else if(Neighbors[7] && Neighbors[2]) return E_RAIL_ASCEND_SOUTH; - else if(Neighbors[3] && Neighbors[6]) return E_RAIL_ASCEND_NORTH; - else if(Neighbors[5] && Neighbors[0]) return E_RAIL_ASCEND_WEST; - else if(Neighbors[4] && Neighbors[1]) return E_RAIL_ASCEND_EAST; - else if(Neighbors[0] && Neighbors[1]) return E_RAIL_EAST_WEST; - else if(Neighbors[2] && Neighbors[3]) return E_RAIL_NORTH_SOUTH; + if (Neighbors[3] && Neighbors[0]) return E_RAIL_CURVED_SOUTH_EAST; + else if (Neighbors[3] && Neighbors[1]) return E_RAIL_CURVED_SOUTH_WEST; + else if (Neighbors[2] && Neighbors[0]) return E_RAIL_CURVED_NORTH_EAST; + else if (Neighbors[2] && Neighbors[1]) return E_RAIL_CURVED_NORTH_WEST; + else if (Neighbors[7] && Neighbors[2]) return E_RAIL_ASCEND_SOUTH; + else if (Neighbors[3] && Neighbors[6]) return E_RAIL_ASCEND_NORTH; + else if (Neighbors[5] && Neighbors[0]) return E_RAIL_ASCEND_WEST; + else if (Neighbors[4] && Neighbors[1]) return E_RAIL_ASCEND_EAST; + else if (Neighbors[0] && Neighbors[1]) return E_RAIL_EAST_WEST; + else if (Neighbors[2] && Neighbors[3]) return E_RAIL_NORTH_SOUTH; ASSERT(!"Weird neighbor count"); } return Meta; @@ -177,68 +193,130 @@ public: bool IsUnstable(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ) { - if (a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) != E_BLOCK_RAIL) return false; + if (a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) != E_BLOCK_RAIL) + { + return false; + } NIBBLETYPE Meta = a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); switch (Meta) { case E_RAIL_NORTH_SOUTH: { - if(IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_NORTH, E_PURE_DOWN) || - IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_SOUTH, E_PURE_DOWN)) return true; + if ( + IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_NORTH, E_PURE_DOWN) || + IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_SOUTH, E_PURE_DOWN) + ) + { + return true; + } break; } + case E_RAIL_EAST_WEST: { - if(IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_EAST, E_PURE_DOWN) || - IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_WEST, E_PURE_DOWN)) return true; + if ( + IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_EAST, E_PURE_DOWN) || + IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_WEST, E_PURE_DOWN) + ) + { + return true; + } break; } + case E_RAIL_ASCEND_EAST: { - if(IsNotConnected(a_World, a_BlockX, a_BlockY + 1, a_BlockZ, BLOCK_FACE_EAST) || - IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_WEST)) return true; + if ( + IsNotConnected(a_World, a_BlockX, a_BlockY + 1, a_BlockZ, BLOCK_FACE_EAST) || + IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_WEST) + ) + { + return true; + } break; } + case E_RAIL_ASCEND_WEST: { - if(IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_EAST) || - IsNotConnected(a_World, a_BlockX, a_BlockY + 1, a_BlockZ, BLOCK_FACE_WEST)) return true; + if ( + IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_EAST) || + IsNotConnected(a_World, a_BlockX, a_BlockY + 1, a_BlockZ, BLOCK_FACE_WEST) + ) + { + return true; + } break; } + case E_RAIL_ASCEND_NORTH: { - if(IsNotConnected(a_World, a_BlockX, a_BlockY + 1, a_BlockZ, BLOCK_FACE_NORTH) || - IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_SOUTH)) return true; + if ( + IsNotConnected(a_World, a_BlockX, a_BlockY + 1, a_BlockZ, BLOCK_FACE_NORTH) || + IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_SOUTH) + ) + { + return true; + } break; } + case E_RAIL_ASCEND_SOUTH: { - if(IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_NORTH) || - IsNotConnected(a_World, a_BlockX, a_BlockY + 1, a_BlockZ, BLOCK_FACE_SOUTH)) return true; + if ( + IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_NORTH) || + IsNotConnected(a_World, a_BlockX, a_BlockY + 1, a_BlockZ, BLOCK_FACE_SOUTH) + ) + { + return true; + } break; } + case E_RAIL_CURVED_SOUTH_EAST: { - if(IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_SOUTH) || - IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_EAST)) return true; + if ( + IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_SOUTH) || + IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_EAST) + ) + { + return true; + } break; } + case E_RAIL_CURVED_SOUTH_WEST: { - if(IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_SOUTH) || - IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_WEST)) return true; + if ( + IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_SOUTH) || + IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_WEST) + ) + { + return true; + } break; } + case E_RAIL_CURVED_NORTH_WEST: { - if(IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_NORTH) || - IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_WEST)) return true; + if ( + IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_NORTH) || + IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_WEST) + ) + { + return true; + } break; } + case E_RAIL_CURVED_NORTH_EAST: { - if(IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_NORTH) || - IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_EAST)) return true; + if ( + IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_NORTH) || + IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_EAST) + ) + { + return true; + } break; } } @@ -246,7 +324,7 @@ public: } - bool IsNotConnected(cWorld *a_World, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, char a_Pure = 0) + bool IsNotConnected(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, char a_Pure = 0) { AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, false); NIBBLETYPE Meta; diff --git a/source/Blocks/BlockRedstone.h b/source/Blocks/BlockRedstone.h index ce0ff64d5..3a4649d7e 100644 --- a/source/Blocks/BlockRedstone.h +++ b/source/Blocks/BlockRedstone.h @@ -22,9 +22,9 @@ public: } - virtual bool CanBeAt(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ) override + virtual bool CanBeAt(int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { - return g_BlockIsSolid[a_World->GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ)]; + return ((a_RelY > 0) && g_BlockIsSolid[a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ)]); } diff --git a/source/Blocks/BlockRedstoneRepeater.h b/source/Blocks/BlockRedstoneRepeater.h index fbd415160..4a16149fd 100644 --- a/source/Blocks/BlockRedstoneRepeater.h +++ b/source/Blocks/BlockRedstoneRepeater.h @@ -38,9 +38,9 @@ public: } - virtual bool CanBeAt(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ) override + virtual bool CanBeAt(int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { - return a_World->GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ) != E_BLOCK_AIR; + return ((a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) != E_BLOCK_AIR)); } diff --git a/source/Blocks/BlockSapling.h b/source/Blocks/BlockSapling.h index 18fdb9d05..957331886 100644 --- a/source/Blocks/BlockSapling.h +++ b/source/Blocks/BlockSapling.h @@ -25,9 +25,9 @@ public: } - virtual bool CanBeAt(cWorld *a_World, int a_BlockX, int a_BlockY, int a_BlockZ) override + virtual bool CanBeAt(int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { - return IsBlockTypeOfDirt(a_World->GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ)); + return (a_RelY > 0) && IsBlockTypeOfDirt(a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ)); } diff --git a/source/Blocks/BlockSnow.h b/source/Blocks/BlockSnow.h index 2a5009b69..f150f497c 100644 --- a/source/Blocks/BlockSnow.h +++ b/source/Blocks/BlockSnow.h @@ -29,10 +29,9 @@ public: } - virtual bool CanBeAt(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ) override + virtual bool CanBeAt(int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { - BLOCKTYPE UnderlyingBlock = a_World->GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ); - return g_BlockIsSnowable[UnderlyingBlock]; + return (a_RelY > 0) && g_BlockIsSnowable[a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ)]; } diff --git a/source/Blocks/BlockStems.h b/source/Blocks/BlockStems.h index ba93097f9..44c4d9cc9 100644 --- a/source/Blocks/BlockStems.h +++ b/source/Blocks/BlockStems.h @@ -41,9 +41,9 @@ public: } - virtual bool CanBeAt(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ) override + virtual bool CanBeAt(int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { - return a_World->GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ) == E_BLOCK_FARMLAND; + return ((a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) == E_BLOCK_FARMLAND)); } diff --git a/source/Blocks/BlockSugarcane.h b/source/Blocks/BlockSugarcane.h index 9470900f0..a9503ba37 100644 --- a/source/Blocks/BlockSugarcane.h +++ b/source/Blocks/BlockSugarcane.h @@ -23,16 +23,46 @@ public: } - virtual bool CanBeAt(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ) override + virtual bool CanBeAt(int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { - switch (a_World->GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ)) + if (a_RelY <= 0) + { + return false; + } + switch (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ)) { case E_BLOCK_DIRT: case E_BLOCK_GRASS: case E_BLOCK_FARMLAND: case E_BLOCK_SAND: { - return a_World->IsBlockDirectlyWatered(a_BlockX, a_BlockY - 1, a_BlockZ); + static const struct + { + int x, z; + } Coords[] = + { + {-1, 0}, + { 1, 0}, + { 0, -1}, + { 0, 1}, + } ; + a_RelY -= 1; + for (int i = 0; i < ARRAYCOUNT(Coords); i++) + { + BLOCKTYPE BlockType; + NIBBLETYPE BlockMeta; + if (!a_Chunk.UnboundedRelGetBlock(a_RelX + Coords[i].x, a_RelY, a_RelZ + Coords[i].z, BlockType, BlockMeta)) + { + // Too close to the edge, cannot simulate + return true; + } + if (IsBlockWater(BlockType)) + { + return true; + } + } // for i - Coords[] + // Not directly neighboring a water block + return false; } case E_BLOCK_SUGARCANE: { diff --git a/source/Blocks/BlockTallGrass.h b/source/Blocks/BlockTallGrass.h index 702ebf14c..eea629bf5 100644 --- a/source/Blocks/BlockTallGrass.h +++ b/source/Blocks/BlockTallGrass.h @@ -34,9 +34,9 @@ public: } - virtual bool CanBeAt(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ) override + virtual bool CanBeAt(int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { - return a_World->GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ) != E_BLOCK_AIR; + return ((a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) != E_BLOCK_AIR)); } diff --git a/source/Blocks/BlockTorch.h b/source/Blocks/BlockTorch.h index 43c5cdb4c..3cc487421 100644 --- a/source/Blocks/BlockTorch.h +++ b/source/Blocks/BlockTorch.h @@ -98,6 +98,7 @@ public: } + /* virtual bool CanBePlacedAt(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) override { if (TorchCanBePlacedAt(a_World, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace)) @@ -107,12 +108,16 @@ public: return (FindSuitableFace(a_World, a_BlockX, a_BlockY, a_BlockZ) != BLOCK_FACE_BOTTOM); } + */ - virtual bool CanBeAt(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ) override + virtual bool CanBeAt(int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { - char Face = cTorch::MetaDataToDirection(a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ)); - return TorchCanBePlacedAt(a_World, a_BlockX, a_BlockY, a_BlockZ, Face); + // TODO: Use cTorch::AdjustCoordsByMeta(), then cChunk::UnboundedRelGetBlock() and finally some comparison + char Face = cTorch::MetaDataToDirection(a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ)); + int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width; + int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width; + return TorchCanBePlacedAt(a_Chunk.GetWorld(), BlockX, a_RelY, BlockZ, Face); } diff --git a/source/Blocks/BlockVine.h b/source/Blocks/BlockVine.h index 2f35c11d9..88338e86d 100644 --- a/source/Blocks/BlockVine.h +++ b/source/Blocks/BlockVine.h @@ -25,45 +25,98 @@ public: BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { + // TODO: Disallow placement where the vine doesn't attach to something properly + BLOCKTYPE BlockType = 0; + NIBBLETYPE BlockMeta; + a_World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta); + if (BlockType == m_BlockType) + { + a_BlockMeta = BlockMeta | cVine::DirectionToMetaData(a_BlockFace); + } + else + { + a_BlockMeta = cVine::DirectionToMetaData(a_BlockFace); + } a_BlockType = m_BlockType; - a_BlockMeta = cVine::DirectionToMetaData(a_BlockFace); return true; } - virtual bool CanBePlacedAt(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) override + /// Returns true if the specified block type is good for vines to attach to + static bool IsBlockAttachable(BLOCKTYPE a_BlockType) { - if ( - (a_World->GetBlock( a_BlockX, a_BlockY + 1, a_BlockZ ) == E_BLOCK_VINES) && - (cVine::MetaDataToDirection(a_World->GetBlockMeta(a_BlockX, a_BlockY + 1, a_BlockZ)) == a_BlockFace) - ) + return (a_BlockType == E_BLOCK_LEAVES) || g_BlockIsSolid[a_BlockType]; + } + + + /// Returns the meta that has the maximum allowable sides of the vine, given the surroundings + NIBBLETYPE GetMaxMeta(cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) + { + static const struct { - return true; - } - - BLOCKTYPE TopBlock = a_World->GetBlock( a_BlockX, a_BlockY + 1, a_BlockZ); - if (g_BlockIsSolid[TopBlock] || (TopBlock == E_BLOCK_LEAVES)) + int x, z; + int Bit; + } Coords[] = { - AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, true); - BLOCKTYPE BaseBlock = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ); - if (!g_BlockIsSolid[BaseBlock] && (BaseBlock != E_BLOCK_LEAVES)) + { 0, 1, 1}, // south, ZP + {-1, 0, 2}, // west, XM + { 0, -1, 4}, // north, ZM + { 1, 0, 8}, // east, XP + } ; + int res = 0; + for (int i = 0; i < ARRAYCOUNT(Coords); i++) + { + BLOCKTYPE BlockType; + NIBBLETYPE BlockMeta; + if ( + a_Chunk.UnboundedRelGetBlock(a_RelX + Coords[i].x, a_RelY, a_RelZ + Coords[i].z, BlockType, BlockMeta) && + IsBlockAttachable(BlockType) + ) { - AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, false); - a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_VINES, 0); + res |= Coords[i].Bit; } - return true; } - - AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, true); - BLOCKTYPE BaseBlock = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ); - return (g_BlockIsSolid[BaseBlock] || (BaseBlock == E_BLOCK_LEAVES)); + return res; } - - - virtual bool CanBeAt(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ) override + + + void Check(int a_RelX, int a_RelY, int a_RelZ, cChunk & a_Chunk) override { - char Dir = cVine::MetaDataToDirection(a_World->GetBlockMeta( a_BlockX, a_BlockY, a_BlockZ)); - return CanBePlacedAt(a_World, a_BlockX, a_BlockY, a_BlockZ, Dir); + NIBBLETYPE CurMeta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ); + NIBBLETYPE MaxMeta = GetMaxMeta(a_Chunk, a_RelX, a_RelY, a_RelZ); + + // Check if vine above us, add its meta to MaxMeta + if ((a_RelY < cChunkDef::Height - 1) && (a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ) == m_BlockType)) + { + MaxMeta |= a_Chunk.GetMeta(a_RelX, a_RelY + 1, a_RelZ); + } + + NIBBLETYPE Common = CurMeta & MaxMeta; // Neighbors that we have and are legal + if (Common != CurMeta) + { + // There is a neighbor missing, need to update the meta or even destroy the block + bool HasTop = (a_RelY < cChunkDef::Height - 1) && IsBlockAttachable(a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ)); + if ((Common == 0) && !HasTop) + { + // The vine just lost all its support, destroy the block: + if (DoesDropOnUnsuitable()) + { + int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width; + int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width; + DropBlock(a_Chunk.GetWorld(), NULL, BlockX, a_RelY, BlockZ); + } + a_Chunk.SetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_AIR, 0); + return; + } + a_Chunk.SetBlock(a_RelX, a_RelY, a_RelZ, m_BlockType, Common); + } + else + { + // Wake up the simulators for this block: + int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width; + int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width; + a_Chunk.GetWorld()->GetSimulatorManager()->WakeUp(BlockX, a_RelY, BlockZ, &a_Chunk); + } } -- cgit v1.2.3