Rewritten SandSimulator to use direct chunk access; and sand falling on torches now creates a pickup.
git-svn-id: http://mc-server.googlecode.com/svn/trunk@1240 0a769ca7-a7f5-676a-18bf-c427514a06d6
This commit is contained in:
@@ -12,60 +12,72 @@
|
||||
|
||||
|
||||
|
||||
cSandSimulator::cSandSimulator(cWorld & a_World)
|
||||
: cSimulator(a_World)
|
||||
, m_Blocks(new BlockList)
|
||||
, m_Buffer(new BlockList)
|
||||
cSandSimulator::cSandSimulator(cWorld & a_World, cIniFile & a_IniFile) :
|
||||
cSimulator(a_World),
|
||||
m_TotalBlocks(0)
|
||||
{
|
||||
|
||||
m_IsInstantFall = a_IniFile.GetValueSetB("Physics", "SandInstantFall", false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cSandSimulator::~cSandSimulator()
|
||||
void cSandSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk)
|
||||
{
|
||||
delete m_Buffer;
|
||||
delete m_Blocks;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cSandSimulator::Simulate(float a_Dt)
|
||||
{
|
||||
m_Buffer->clear();
|
||||
std::swap( m_Blocks, m_Buffer );
|
||||
|
||||
for( BlockList::iterator itr = m_Buffer->begin(); itr != m_Buffer->end(); ++itr )
|
||||
cSandSimulatorChunkData & ChunkData = a_Chunk->GetSandSimulatorData();
|
||||
if (ChunkData.empty())
|
||||
{
|
||||
Vector3i Pos = *itr;
|
||||
BLOCKTYPE BlockID = m_World.GetBlock(Pos.x, Pos.y, Pos.z);
|
||||
if(!IsAllowedBlock(BlockID))
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
|
||||
BLOCKTYPE BottomBlock = m_World.GetBlock( Pos.x, Pos.y - 1, Pos.z );
|
||||
|
||||
if( IsPassable(BottomBlock) )
|
||||
int BaseX = a_Chunk->GetPosX() * cChunkDef::Width;
|
||||
int BaseZ = a_Chunk->GetPosZ() * cChunkDef::Width;
|
||||
for (cSandSimulatorChunkData::const_iterator itr = ChunkData.begin(), end = ChunkData.end(); itr != end; ++itr)
|
||||
{
|
||||
BLOCKTYPE BlockType = a_Chunk->GetBlock(itr->x, itr->y, itr->z);
|
||||
if (!IsAllowedBlock(BlockType) || (itr->y <= 0))
|
||||
{
|
||||
cFallingBlock * FallingBlock = new cFallingBlock(Pos, BlockID);
|
||||
continue;
|
||||
}
|
||||
|
||||
BLOCKTYPE BlockBelow = (itr->y > 0) ? a_Chunk->GetBlock(itr->x, itr->y - 1, itr->z) : E_BLOCK_AIR;
|
||||
if (CanStartFallingThrough(BlockBelow))
|
||||
{
|
||||
if (m_IsInstantFall)
|
||||
{
|
||||
DoInstantFall(a_Chunk, itr->x, itr->y, itr->z);
|
||||
continue;
|
||||
}
|
||||
Vector3i Pos;
|
||||
Pos.x = itr->x + BaseX;
|
||||
Pos.y = itr->y;
|
||||
Pos.z = itr->z + BaseZ;
|
||||
cFallingBlock * FallingBlock = new cFallingBlock(Pos, BlockType, a_Chunk->GetMeta(itr->x, itr->y, itr->z));
|
||||
FallingBlock->Initialize(&m_World);
|
||||
m_World.SetBlock( Pos.x, Pos.y, Pos.z, E_BLOCK_AIR, 0 );
|
||||
a_Chunk->SetBlock(itr->x, itr->y, itr->z, E_BLOCK_AIR, 0);
|
||||
}
|
||||
}
|
||||
|
||||
m_TotalBlocks -= ChunkData.size();
|
||||
ChunkData.clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cSandSimulator::IsAllowedBlock( BLOCKTYPE a_BlockType )
|
||||
bool cSandSimulator::IsAllowedBlock(BLOCKTYPE a_BlockType)
|
||||
{
|
||||
return a_BlockType == E_BLOCK_SAND
|
||||
|| a_BlockType == E_BLOCK_GRAVEL;
|
||||
switch (a_BlockType)
|
||||
{
|
||||
case E_BLOCK_SAND:
|
||||
case E_BLOCK_GRAVEL:
|
||||
case E_BLOCK_ANVIL:
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -74,40 +86,169 @@ bool cSandSimulator::IsAllowedBlock( BLOCKTYPE a_BlockType )
|
||||
|
||||
void cSandSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk)
|
||||
{
|
||||
// TODO: Optimize this by passing the block type along
|
||||
int RelX = a_BlockX;
|
||||
int RelY = a_BlockY;
|
||||
int RelZ = a_BlockZ;
|
||||
int ChunkX, ChunkZ;
|
||||
cChunkDef::AbsoluteToRelative(RelX, RelY, RelZ, ChunkX, ChunkZ);
|
||||
if (!IsAllowedBlock(a_Chunk->GetBlock(RelX, RelY, RelZ)))
|
||||
if (a_Chunk == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int RelX = a_BlockX - a_Chunk->GetPosX() * cChunkDef::Width;
|
||||
int RelZ = a_BlockZ - a_Chunk->GetPosZ() * cChunkDef::Width;
|
||||
if (!IsAllowedBlock(a_Chunk->GetBlock(RelX, a_BlockY, RelZ)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Vector3i Block(a_BlockX, a_BlockY, a_BlockZ);
|
||||
|
||||
//check for duplicates
|
||||
for (BlockList::iterator itr = m_Blocks->begin(); itr != m_Blocks->end(); ++itr)
|
||||
// Check for duplicates:
|
||||
cSandSimulatorChunkData & ChunkData = a_Chunk->GetSandSimulatorData();
|
||||
for (cSandSimulatorChunkData::iterator itr = ChunkData.begin(); itr != ChunkData.end(); ++itr)
|
||||
{
|
||||
Vector3i Pos = *itr;
|
||||
if ((Pos.x == a_BlockX) && (Pos.y == a_BlockY) && (Pos.z == a_BlockZ))
|
||||
if ((itr->x == RelX) && (itr->y == a_BlockY) && (itr->z == a_BlockZ))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_Blocks->push_back(Block);
|
||||
m_TotalBlocks += 1;
|
||||
ChunkData.push_back(cCoordWithInt(RelX, a_BlockY, RelZ));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cSandSimulator::IsPassable(BLOCKTYPE a_BlockType)
|
||||
bool cSandSimulator::CanStartFallingThrough(BLOCKTYPE a_BlockType)
|
||||
{
|
||||
return (a_BlockType == E_BLOCK_AIR)
|
||||
|| IsBlockWater(a_BlockType)
|
||||
|| IsBlockLava(a_BlockType)
|
||||
|| (a_BlockType == E_BLOCK_FIRE);
|
||||
switch (a_BlockType)
|
||||
{
|
||||
case E_BLOCK_AIR:
|
||||
case E_BLOCK_FIRE:
|
||||
case E_BLOCK_WATER:
|
||||
case E_BLOCK_STATIONARY_WATER:
|
||||
case E_BLOCK_LAVA:
|
||||
case E_BLOCK_STATIONARY_LAVA:
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cSandSimulator::CanContinueFallThrough(BLOCKTYPE a_BlockType)
|
||||
{
|
||||
switch (a_BlockType)
|
||||
{
|
||||
case E_BLOCK_AIR:
|
||||
case E_BLOCK_FIRE:
|
||||
case E_BLOCK_WATER:
|
||||
case E_BLOCK_STATIONARY_WATER:
|
||||
case E_BLOCK_LAVA:
|
||||
case E_BLOCK_STATIONARY_LAVA:
|
||||
case E_BLOCK_POWERED_RAIL:
|
||||
case E_BLOCK_DETECTOR_RAIL:
|
||||
case E_BLOCK_COBWEB:
|
||||
case E_BLOCK_TALL_GRASS:
|
||||
case E_BLOCK_DEAD_BUSH:
|
||||
case E_BLOCK_YELLOW_FLOWER:
|
||||
case E_BLOCK_RED_ROSE:
|
||||
case E_BLOCK_BROWN_MUSHROOM:
|
||||
case E_BLOCK_RED_MUSHROOM:
|
||||
case E_BLOCK_TORCH:
|
||||
case E_BLOCK_REDSTONE_WIRE:
|
||||
case E_BLOCK_CROPS:
|
||||
case E_BLOCK_PUMPKIN_STEM:
|
||||
case E_BLOCK_MELON_STEM:
|
||||
case E_BLOCK_REDSTONE_TORCH_OFF:
|
||||
case E_BLOCK_REDSTONE_TORCH_ON:
|
||||
case E_BLOCK_STONE_BUTTON:
|
||||
case E_BLOCK_STONE_PRESSURE_PLATE:
|
||||
case E_BLOCK_WOODEN_BUTTON:
|
||||
case E_BLOCK_WOODEN_PRESSURE_PLATE:
|
||||
case E_BLOCK_REDSTONE_REPEATER_OFF:
|
||||
case E_BLOCK_REDSTONE_REPEATER_ON:
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cSandSimulator::IsReplacedOnRematerialization(BLOCKTYPE a_BlockType)
|
||||
{
|
||||
switch (a_BlockType)
|
||||
{
|
||||
case E_BLOCK_AIR:
|
||||
case E_BLOCK_FIRE:
|
||||
case E_BLOCK_WATER:
|
||||
case E_BLOCK_STATIONARY_WATER:
|
||||
case E_BLOCK_LAVA:
|
||||
case E_BLOCK_STATIONARY_LAVA:
|
||||
case E_BLOCK_TALL_GRASS:
|
||||
case E_BLOCK_DEAD_BUSH:
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cSandSimulator::DoesBreakFallingThrough(BLOCKTYPE a_BlockType)
|
||||
{
|
||||
switch (a_BlockType)
|
||||
{
|
||||
case E_BLOCK_STONE_SLAB:
|
||||
case E_BLOCK_WOODEN_SLAB:
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cSandSimulator::FinishFalling(
|
||||
cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ,
|
||||
BLOCKTYPE a_FallingBlockType, NIBBLETYPE a_FallingBlockMeta
|
||||
)
|
||||
{
|
||||
ASSERT(a_BlockY < cChunkDef::Height);
|
||||
|
||||
BLOCKTYPE CurrentBlockType = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
|
||||
if ((a_FallingBlockType == E_BLOCK_ANVIL) || IsReplacedOnRematerialization(CurrentBlockType))
|
||||
{
|
||||
// Rematerialize the material here:
|
||||
a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, a_FallingBlockType, a_FallingBlockMeta);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a pickup instead:
|
||||
cItems Pickups;
|
||||
Pickups.Add((ENUM_ITEM_ID)a_FallingBlockType, 1, a_FallingBlockMeta);
|
||||
a_World->SpawnItemPickups(Pickups, (double)a_BlockX + 0.5, (double)a_BlockY + 0.5, (double)a_BlockZ + 0.5, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cSandSimulator::DoInstantFall(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user