summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormadmaxoft@gmail.com <madmaxoft@gmail.com@0a769ca7-a7f5-676a-18bf-c427514a06d6>2012-10-14 20:30:16 +0200
committermadmaxoft@gmail.com <madmaxoft@gmail.com@0a769ca7-a7f5-676a-18bf-c427514a06d6>2012-10-14 20:30:16 +0200
commit41a38e8d9098d6627cd26351577cf032e6996c87 (patch)
tree34d53e6291c6d353a9c3a37a472b933f9fa5e57d
parentInitial Floody fluid simulator. (diff)
downloadcuberite-41a38e8d9098d6627cd26351577cf032e6996c87.tar
cuberite-41a38e8d9098d6627cd26351577cf032e6996c87.tar.gz
cuberite-41a38e8d9098d6627cd26351577cf032e6996c87.tar.bz2
cuberite-41a38e8d9098d6627cd26351577cf032e6996c87.tar.lz
cuberite-41a38e8d9098d6627cd26351577cf032e6996c87.tar.xz
cuberite-41a38e8d9098d6627cd26351577cf032e6996c87.tar.zst
cuberite-41a38e8d9098d6627cd26351577cf032e6996c87.zip
Diffstat (limited to '')
-rw-r--r--source/Blocks/BlockFluid.h21
-rw-r--r--source/Blocks/BlockHandler.cpp22
-rw-r--r--source/Blocks/BlockHandler.h6
-rw-r--r--source/Chunk.cpp88
-rw-r--r--source/Chunk.h4
-rw-r--r--source/ChunkMap.cpp79
-rw-r--r--source/ChunkMap.h3
-rw-r--r--source/Simulator/FloodyFluidSimulator.cpp10
8 files changed, 184 insertions, 49 deletions
diff --git a/source/Blocks/BlockFluid.h b/source/Blocks/BlockFluid.h
index 40ff621e4..a8cd9c497 100644
--- a/source/Blocks/BlockFluid.h
+++ b/source/Blocks/BlockFluid.h
@@ -10,6 +10,8 @@
class cBlockFluidHandler :
public cBlockHandler
{
+ typedef cBlockHandler super;
+
public:
cBlockFluidHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType)
@@ -23,7 +25,24 @@ public:
return true;
}
- // TODO: Implement proper fluid physics here
+
+ virtual void Check(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ) 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));
+ 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));
+ break;
+ }
+ }
+ super::Check(a_World, a_BlockX, a_BlockY, a_BlockZ);
+ }
} ;
diff --git a/source/Blocks/BlockHandler.cpp b/source/Blocks/BlockHandler.cpp
index 977bff87f..eb7a40d62 100644
--- a/source/Blocks/BlockHandler.cpp
+++ b/source/Blocks/BlockHandler.cpp
@@ -387,3 +387,25 @@ bool cBlockHandler::DoesDropOnUnsuitable(void)
+
+void cBlockHandler::Check(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ)
+{
+ if (!CanBeAt(a_World, a_BlockX, a_BlockY, a_BlockZ))
+ {
+ if (DoesDropOnUnsuitable())
+ {
+ DropBlock(a_World, a_BlockX, a_BlockY, a_BlockZ);
+ }
+
+ a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
+ }
+ else
+ {
+ // Wake up the simulators:
+ a_World->GetSimulatorManager()->WakeUp(a_BlockX, a_BlockY, a_BlockZ);
+ }
+}
+
+
+
+
diff --git a/source/Blocks/BlockHandler.h b/source/Blocks/BlockHandler.h
index bfe92b676..c2884fe7d 100644
--- a/source/Blocks/BlockHandler.h
+++ b/source/Blocks/BlockHandler.h
@@ -91,6 +91,12 @@ public:
/// Does this block drop if it gets destroyed by an unsuitable situation? Default: true
virtual bool DoesDropOnUnsuitable(void);
+ /** Called when one of the neighbors gets set; equivalent to MC block update.
+ 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);
+
/// Get the blockhandler for a specific block id
static cBlockHandler * GetBlockHandler(BLOCKTYPE a_BlockType);
diff --git a/source/Chunk.cpp b/source/Chunk.cpp
index aaea4bf71..fa9cb91d3 100644
--- a/source/Chunk.cpp
+++ b/source/Chunk.cpp
@@ -480,15 +480,7 @@ void cChunk::CheckBlocks(void)
Vector3i WorldPos = PositionToWorldPosition( BlockPos );
cBlockHandler * Handler = BlockHandler(GetBlock(index));
- if (!Handler->CanBeAt(m_World, WorldPos.x, WorldPos.y, WorldPos.z))
- {
- if (Handler->DoesDropOnUnsuitable())
- {
- Handler->DropBlock(m_World, WorldPos.x, WorldPos.y, WorldPos.z);
- }
-
- m_World->SetBlock(WorldPos.x, WorldPos.y, WorldPos.z, E_BLOCK_AIR, 0);
- }
+ Handler->Check(m_World, WorldPos.x, WorldPos.y, WorldPos.z);
} // for itr - ToTickBlocks[]
}
@@ -918,13 +910,8 @@ void cChunk::SetBlock( int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType
}
}
- m_ToTickBlocks.push_back( MakeIndex( a_RelX, a_RelY, a_RelZ ) );
- m_ToTickBlocks.push_back( MakeIndex( a_RelX + 1, a_RelY, a_RelZ ) );
- m_ToTickBlocks.push_back( MakeIndex( a_RelX - 1, a_RelY, a_RelZ ) );
- m_ToTickBlocks.push_back( MakeIndex( a_RelX, a_RelY + 1, a_RelZ ) );
- m_ToTickBlocks.push_back( MakeIndex( a_RelX, a_RelY - 1, a_RelZ ) );
- m_ToTickBlocks.push_back( MakeIndex( a_RelX, a_RelY, a_RelZ + 1 ) );
- m_ToTickBlocks.push_back( MakeIndex( a_RelX, a_RelY, a_RelZ - 1 ) );
+ m_ToTickBlocks.push_back(index);
+ CheckNeighbors(a_RelX, a_RelY, a_RelZ);
Vector3i WorldPos = PositionToWorldPosition( a_RelX, a_RelY, a_RelZ );
cBlockEntity* BlockEntity = GetBlockEntity( WorldPos );
@@ -964,6 +951,75 @@ void cChunk::SetBlock( int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType
+void cChunk::CheckNeighbors(int a_RelX, int a_RelY, int a_RelZ)
+{
+ int BlockX = m_PosX * cChunkDef::Width + a_RelX;
+ int BlockZ = m_PosZ * cChunkDef::Width + a_RelZ;
+ if (a_RelX < cChunkDef::Width)
+ {
+ m_ToTickBlocks.push_back(MakeIndexNoCheck(a_RelX + 1, a_RelY, a_RelZ));
+ }
+ else
+ {
+ m_ChunkMap->CheckBlock(BlockX + 1, a_RelY, BlockZ);
+ }
+
+ if (a_RelX > 0)
+ {
+ m_ToTickBlocks.push_back( MakeIndexNoCheck(a_RelX - 1, a_RelY, a_RelZ));
+ }
+ else
+ {
+ m_ChunkMap->CheckBlock(BlockX - 1, a_RelY, BlockZ);
+ }
+
+ if (a_RelY < cChunkDef::Height - 1)
+ {
+ m_ToTickBlocks.push_back(MakeIndexNoCheck(a_RelX, a_RelY + 1, a_RelZ));
+ }
+
+ if (a_RelY > 0)
+ {
+ m_ToTickBlocks.push_back(MakeIndexNoCheck(a_RelX, a_RelY - 1, a_RelZ));
+ }
+
+ if (a_RelZ < cChunkDef::Width - 1)
+ {
+ m_ToTickBlocks.push_back(MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ + 1));
+ }
+ else
+ {
+ m_ChunkMap->CheckBlock(BlockX, a_RelY, BlockZ + 1);
+ }
+
+ if (a_RelZ > 0)
+ {
+ m_ToTickBlocks.push_back(MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ - 1));
+ }
+ else
+ {
+ m_ChunkMap->CheckBlock(BlockX, a_RelY, BlockZ - 1);
+ }
+}
+
+
+
+
+
+void cChunk::CheckBlock(int a_RelX, int a_RelY, int a_RelZ)
+{
+ if (!IsValid())
+ {
+ return;
+ }
+
+ m_ToTickBlocks.push_back(MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ));
+}
+
+
+
+
+
void cChunk::FastSetBlock( int a_X, int a_Y, int a_Z, BLOCKTYPE a_BlockType, BLOCKTYPE a_BlockMeta)
{
ASSERT(!((a_X < 0 || a_X >= Width || a_Y < 0 || a_Y >= Height || a_Z < 0 || a_Z >= Width)));
diff --git a/source/Chunk.h b/source/Chunk.h
index 0a51e99d2..9b0602f0b 100644
--- a/source/Chunk.h
+++ b/source/Chunk.h
@@ -130,11 +130,15 @@ public:
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
void SetBlock( const Vector3i & a_RelBlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta ) { SetBlock( a_RelBlockPos.x, a_RelBlockPos.y, a_RelBlockPos.z, a_BlockType, a_BlockMeta ); }
+ void CheckBlock(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 );
void GetBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta);
+ /// Queues all 6 neighbors of the specified block for checking. If outside the chunk, relays the checking to the neighboring chunk
+ void CheckNeighbors(int a_RelX, int a_RelY, int a_RelZ);
+
EMCSBiome GetBiomeAt(int a_RelX, int a_RelZ) const {return cChunkDef::GetBiome(m_BiomeMap, a_RelX, a_RelZ); }
void CollectPickupsByPlayer(cPlayer * a_Player);
diff --git a/source/ChunkMap.cpp b/source/ChunkMap.cpp
index 671eac708..a616cf63d 100644
--- a/source/ChunkMap.cpp
+++ b/source/ChunkMap.cpp
@@ -898,18 +898,19 @@ BLOCKTYPE cChunkMap::GetBlockSkyLight(int a_X, int a_Y, int a_Z)
-void cChunkMap::SetBlockMeta(int a_X, int a_Y, int a_Z, NIBBLETYPE a_BlockMeta)
+void cChunkMap::SetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_BlockMeta)
{
int ChunkX, ChunkZ;
- cChunkDef::AbsoluteToRelative( a_X, a_Y, a_Z, ChunkX, ChunkZ );
+ cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ);
+ // a_BlockXYZ now contains relative coords!
cCSLock Lock(m_CSLayers);
- cChunkPtr Chunk = GetChunk( ChunkX, ZERO_CHUNK_Y, ChunkZ );
- if ((Chunk != NULL) && Chunk->IsValid() )
+ cChunkPtr Chunk = GetChunk(ChunkX, ZERO_CHUNK_Y, ChunkZ);
+ if ((Chunk != NULL) && Chunk->IsValid())
{
- Chunk->SetMeta(a_X, a_Y, a_Z, a_BlockMeta);
+ Chunk->SetMeta(a_BlockX, a_BlockY, a_BlockZ, a_BlockMeta);
Chunk->MarkDirty();
- Chunk->SendBlockTo( a_X, a_Y, a_Z, NULL );
+ Chunk->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, NULL);
}
}
@@ -1657,6 +1658,48 @@ void cChunkMap::SaveAllChunks(void)
+int cChunkMap::GetNumChunks(void)
+{
+ cCSLock Lock(m_CSLayers);
+ int NumChunks = 0;
+ for (cChunkLayerList::iterator itr = m_Layers.begin(); itr != m_Layers.end(); ++itr)
+ {
+ NumChunks += (*itr)->GetNumChunksLoaded();
+ }
+ return NumChunks;
+}
+
+
+
+
+
+void cChunkMap::ChunkValidated(void)
+{
+ m_evtChunkValid.Set();
+}
+
+
+
+
+
+void cChunkMap::CheckBlock(int a_BlockX, int a_BlockY, int a_BlockZ)
+{
+ int ChunkX, ChunkZ;
+ cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ);
+ // a_BlockXYZ now contains relative coords!
+
+ cCSLock Lock(m_CSLayers);
+ cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ZERO_CHUNK_Y, ChunkZ);
+ if (Chunk != NULL)
+ {
+ Chunk->CheckBlock(a_BlockX, a_BlockY, a_BlockZ);
+ }
+}
+
+
+
+
+
////////////////////////////////////////////////////////////////////////////////
// cChunkMap::cChunkLayer:
@@ -1817,30 +1860,6 @@ void cChunkMap::cChunkLayer::UnloadUnusedChunks(void)
-int cChunkMap::GetNumChunks(void)
-{
- cCSLock Lock(m_CSLayers);
- int NumChunks = 0;
- for (cChunkLayerList::iterator itr = m_Layers.begin(); itr != m_Layers.end(); ++itr)
- {
- NumChunks += (*itr)->GetNumChunksLoaded();
- }
- return NumChunks;
-}
-
-
-
-
-
-void cChunkMap::ChunkValidated(void)
-{
- m_evtChunkValid.Set();
-}
-
-
-
-
-
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cChunkStay:
diff --git a/source/ChunkMap.h b/source/ChunkMap.h
index bfdbc889b..98b1e2d7e 100644
--- a/source/ChunkMap.h
+++ b/source/ChunkMap.h
@@ -245,6 +245,9 @@ public:
int GetNumChunks(void);
void ChunkValidated(void); // Called by chunks that have become valid
+
+ /// Schedules the specified block for checking (block update)
+ void CheckBlock(int a_BlockX, int a_BlockY, int a_BlockZ);
private:
diff --git a/source/Simulator/FloodyFluidSimulator.cpp b/source/Simulator/FloodyFluidSimulator.cpp
index 7dcd4edca..ae382d0a6 100644
--- a/source/Simulator/FloodyFluidSimulator.cpp
+++ b/source/Simulator/FloodyFluidSimulator.cpp
@@ -39,6 +39,11 @@ void cFloodyFluidSimulator::SimulateBlock(int a_BlockX, int a_BlockY, int a_Bloc
int y = (a_BlockY > 0) ? 1 : 0; // Relative y-coord of this block in Area
NIBBLETYPE MyMeta = Area.GetRelBlockMeta(1, y, 1);
+ if (!IsAnyFluidBlock(Area.GetRelBlockType(1, y, 1)))
+ {
+ // Can happen - if a block is scheduled for simulating and gets replaced in the meantime.
+ return;
+ }
if (MyMeta != 0)
{
@@ -121,6 +126,9 @@ bool cFloodyFluidSimulator::CheckTributaries(int a_BlockX, int a_BlockY, int a_B
void cFloodyFluidSimulator::SpreadToNeighbor(int a_BlockX, int a_BlockY, int a_BlockZ, const cBlockArea & a_Area, NIBBLETYPE a_NewMeta)
{
+ ASSERT(a_NewMeta <= 8); // Invalid meta values
+ ASSERT(a_NewMeta > 0); // Source blocks aren't spread
+
BLOCKTYPE Block = a_Area.GetBlockType(a_BlockX, a_BlockY, a_BlockZ);
if (IsAnyFluidBlock(Block))
@@ -149,8 +157,6 @@ void cFloodyFluidSimulator::SpreadToNeighbor(int a_BlockX, int a_BlockY, int a_B
}
// Spread:
- LOGD("Fluid: spreading to block {%d, %d, %d}, meta %d", a_BlockX, a_BlockY, a_BlockZ, a_NewMeta);
-
m_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, m_FluidBlock, a_NewMeta);
}