1
0

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
This commit is contained in:
madmaxoft@gmail.com 2013-03-15 20:18:11 +00:00
parent 57e56ae561
commit 8090c13cde
22 changed files with 419 additions and 227 deletions

View File

@ -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
static const struct
{
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_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)
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;
}

View File

@ -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));
}

View File

@ -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));
}

View File

@ -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));
}

View File

@ -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);
}
} ;

View File

@ -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);
}
}

View File

@ -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

View File

@ -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);
}

View File

@ -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:

View File

@ -8,6 +8,7 @@
/// Meta values for the rail
enum ENUM_RAIL_DIRECTIONS
{
E_RAIL_NORTH_SOUTH = 0,
@ -19,9 +20,25 @@ enum ENUM_RAIL_DIRECTIONS
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
{
E_PURE_UPDOWN = 0,
@ -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;
@ -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;
}
}

View File

@ -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)]);
}

View File

@ -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));
}

View File

@ -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));
}

View File

@ -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)];
}

View File

@ -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));
}

View File

@ -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:
{

View File

@ -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));
}

View File

@ -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);
}

View File

@ -25,45 +25,98 @@ public:
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) override
{
a_BlockType = m_BlockType;
// 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;
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)
{
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
{
int x, z;
int Bit;
} Coords[] =
{
{ 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_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)
a_Chunk.UnboundedRelGetBlock(a_RelX + Coords[i].x, a_RelY, a_RelZ + Coords[i].z, BlockType, BlockMeta) &&
IsBlockAttachable(BlockType)
)
{
return true;
res |= Coords[i].Bit;
}
}
return res;
}
BLOCKTYPE TopBlock = a_World->GetBlock( a_BlockX, a_BlockY + 1, a_BlockZ);
if (g_BlockIsSolid[TopBlock] || (TopBlock == E_BLOCK_LEAVES))
void Check(int a_RelX, int a_RelY, int a_RelZ, cChunk & a_Chunk) override
{
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))
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))
{
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, false);
a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_VINES, 0);
}
return true;
MaxMeta |= a_Chunk.GetMeta(a_RelX, a_RelY + 1, a_RelZ);
}
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));
}
virtual bool CanBeAt(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ) override
NIBBLETYPE Common = CurMeta & MaxMeta; // Neighbors that we have and are legal
if (Common != CurMeta)
{
char Dir = cVine::MetaDataToDirection(a_World->GetBlockMeta( a_BlockX, a_BlockY, a_BlockZ));
return CanBePlacedAt(a_World, a_BlockX, a_BlockY, a_BlockZ, Dir);
// 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);
}
}

View File

@ -509,18 +509,17 @@ void cChunk::CheckBlocks(void)
{
return;
}
std::deque< unsigned int > ToTickBlocks = m_ToTickBlocks;
m_ToTickBlocks.clear();
std::vector<unsigned int> ToTickBlocks;
std::swap(m_ToTickBlocks, ToTickBlocks);
Lock2.Unlock();
for (std::deque< unsigned int >::const_iterator itr = ToTickBlocks.begin(); itr != ToTickBlocks.end(); ++itr)
for (std::vector<unsigned int>::const_iterator itr = ToTickBlocks.begin(), end = ToTickBlocks.end(); itr != end; ++itr)
{
unsigned int index = (*itr);
Vector3i BlockPos = IndexToCoordinate(index);
Vector3i WorldPos = PositionToWorldPosition( BlockPos );
cBlockHandler * Handler = BlockHandler(GetBlock(index));
Handler->Check(m_World, WorldPos.x, WorldPos.y, WorldPos.z);
Handler->Check(BlockPos.x, BlockPos.y, BlockPos.z, *this);
} // for itr - ToTickBlocks[]
}
@ -827,9 +826,9 @@ void cChunk::GrowCactus(int a_RelX, int a_RelY, int a_RelZ, int a_NumBlocks)
bool cChunk::UnboundedRelGetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta)
bool cChunk::UnboundedRelGetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) const
{
if ((a_RelY < 0) || (a_RelY > cChunkDef::Height))
if ((a_RelY < 0) || (a_RelY >= cChunkDef::Height))
{
LOGWARNING("UnboundedRelGetBlock(): requesting a block with a_RelY out of range: %d", a_RelY);
return false;
@ -1821,20 +1820,33 @@ bool cChunk::GetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_
BLOCKTYPE cChunk::GetBlock( int a_X, int a_Y, int a_Z )
BLOCKTYPE cChunk::GetBlock(int a_RelX, int a_RelY, int a_RelZ) const
{
if ((a_X < 0) || (a_X >= Width) || (a_Y < 0) || (a_Y >= Height) || (a_Z < 0) || (a_Z >= Width)) return 0; // Clip
if (
(a_RelX < 0) || (a_RelX >= Width) ||
(a_RelY < 0) || (a_RelY >= Height) ||
(a_RelZ < 0) || (a_RelZ >= Width)
)
{
ASSERT(!"GetBlock(x, y, z) out of bounds!");
return 0; // Clip
}
return m_BlockTypes[ MakeIndexNoCheck( a_X, a_Y, a_Z ) ];
return m_BlockTypes[MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ)];
}
BLOCKTYPE cChunk::GetBlock( int a_BlockIdx )
BLOCKTYPE cChunk::GetBlock(int a_BlockIdx) const
{
if( a_BlockIdx < 0 || a_BlockIdx >= NumBlocks ) return 0;
if ((a_BlockIdx < 0) || (a_BlockIdx >= NumBlocks))
{
ASSERT(!"GetBlock(idx) out of bounds!");
return 0;
}
return m_BlockTypes[ a_BlockIdx ];
}

View File

@ -127,10 +127,11 @@ public:
void Tick(float a_Dt, MTRand & a_TickRandom);
int GetPosX() { return m_PosX; }
int GetPosY() { return m_PosY; }
int GetPosZ() { return m_PosZ; }
cWorld * GetWorld() { return m_World; }
int GetPosX(void) const { return m_PosX; }
int GetPosY(void) const { return m_PosY; }
int GetPosZ(void) const { return m_PosZ; }
cWorld * GetWorld(void) const { return m_World; }
void SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta );
// SetBlock() does a lot of work (heightmap, tickblocks, blockentities) so a BlockIdx version doesn't make sense
@ -143,8 +144,8 @@ public:
void QueueTickBlockNeighbors(int a_RelX, int a_RelY, int a_RelZ);
void FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, BLOCKTYPE a_BlockMeta ); // Doesn't force block updates on neighbors, use for simple changes such as grass growing etc.
BLOCKTYPE GetBlock( int a_X, int a_Y, int a_Z );
BLOCKTYPE GetBlock( int a_BlockIdx );
BLOCKTYPE GetBlock(int a_RelX, int a_RelY, int a_RelZ) const;
BLOCKTYPE GetBlock(int a_BlockIdx) const;
void GetBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta);
void GetBlockInfo (int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_Meta, NIBBLETYPE & a_SkyLight, NIBBLETYPE & a_BlockLight);
@ -252,16 +253,16 @@ public:
m_BlockTickZ = a_RelZ;
}
inline NIBBLETYPE GetMeta(int a_RelX, int a_RelY, int a_RelZ) {return cChunkDef::GetNibble(m_BlockMeta, a_RelX, a_RelY, a_RelZ); }
inline NIBBLETYPE GetMeta(int a_BlockIdx) {return cChunkDef::GetNibble(m_BlockMeta, a_BlockIdx); }
inline NIBBLETYPE GetMeta(int a_RelX, int a_RelY, int a_RelZ) const {return cChunkDef::GetNibble(m_BlockMeta, a_RelX, a_RelY, a_RelZ); }
inline NIBBLETYPE GetMeta(int a_BlockIdx) const {return cChunkDef::GetNibble(m_BlockMeta, a_BlockIdx); }
inline void SetMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Meta) { cChunkDef::SetNibble(m_BlockMeta, a_RelX, a_RelY, a_RelZ, a_Meta); }
inline void SetMeta(int a_BlockIdx, NIBBLETYPE a_Meta) { cChunkDef::SetNibble(m_BlockMeta, a_BlockIdx, a_Meta); }
inline NIBBLETYPE GetBlockLight(int a_RelX, int a_RelY, int a_RelZ) {return cChunkDef::GetNibble(m_BlockLight, a_RelX, a_RelY, a_RelZ); }
inline NIBBLETYPE GetSkyLight (int a_RelX, int a_RelY, int a_RelZ) {return cChunkDef::GetNibble(m_BlockSkyLight, a_RelX, a_RelY, a_RelZ); }
inline NIBBLETYPE GetBlockLight(int a_RelX, int a_RelY, int a_RelZ) const {return cChunkDef::GetNibble(m_BlockLight, a_RelX, a_RelY, a_RelZ); }
inline NIBBLETYPE GetSkyLight (int a_RelX, int a_RelY, int a_RelZ) const {return cChunkDef::GetNibble(m_BlockSkyLight, a_RelX, a_RelY, a_RelZ); }
/// Same as GetBlock(), but relative coords needn't be in this chunk (uses m_Neighbor-s or m_ChunkMap in such a case); returns true on success; only usable in Tick()
bool UnboundedRelGetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta);
bool UnboundedRelGetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) const;
/// Same as SetBlock(), but relative coords needn't be in this chunk (uses m_Neighbor-s or m_ChunkMap in such a case); returns true on success; only usable in Tick()
bool UnboundedRelSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
@ -286,7 +287,7 @@ private:
bool m_HasLoadFailed; // True if chunk failed to load and hasn't been generated yet since then
cCriticalSection m_CSBlockLists;
std::deque< unsigned int > m_ToTickBlocks;
std::vector<unsigned int> m_ToTickBlocks;
sSetBlockVector m_PendingSendBlocks; ///< Blocks that have changed and need to be sent to all clients
// A critical section is not needed, because all chunk access is protected by its parent ChunkMap's csLayers

View File

@ -1,41 +1,42 @@
#pragma once
class cVine // tolua_export
{ // tolua_export
// tolua_begin
class cVine
{
public:
static NIBBLETYPE DirectionToMetaData( char a_Direction ) // tolua_export
{ // tolua_export
switch (a_Direction)
static NIBBLETYPE DirectionToMetaData(char a_BlockFace)
{
case 0x2:
return 0x1;
case 0x3:
return 0x4;
case 0x4:
return 0x8;
case 0x5:
return 0x2;
default:
return 0x0;
};
} // tolua_export
switch (a_BlockFace)
{
case BLOCK_FACE_NORTH: return 0x1;
case BLOCK_FACE_SOUTH: return 0x4;
case BLOCK_FACE_WEST: return 0x8;
case BLOCK_FACE_EAST: return 0x2;
default: return 0x0;
}
}
static char MetaDataToDirection(NIBBLETYPE a_MetaData ) // tolua_export
{ // tolua_export
static char MetaDataToDirection(NIBBLETYPE a_MetaData)
{
switch(a_MetaData)
{
case 0x1:
return 0x2;
case 0x4:
return 0x3;
case 0x8:
return 0x4;
case 0x2:
return 0x5;
default:
return 0x1;
case 0x1: return BLOCK_FACE_NORTH;
case 0x4: return BLOCK_FACE_SOUTH;
case 0x8: return BLOCK_FACE_WEST;
case 0x2: return BLOCK_FACE_EAST;
default: return BLOCK_FACE_TOP;
}
}
} ;
} // tolua_export
// tolua_end
}; // tolua_export