From 41a38e8d9098d6627cd26351577cf032e6996c87 Mon Sep 17 00:00:00 2001 From: "madmaxoft@gmail.com" Date: Sun, 14 Oct 2012 18:30:16 +0000 Subject: [PATCH] Floody fluid simulator now dries up correctly, too. git-svn-id: http://mc-server.googlecode.com/svn/trunk@964 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- source/Blocks/BlockFluid.h | 21 +++++- source/Blocks/BlockHandler.cpp | 22 ++++++ source/Blocks/BlockHandler.h | 6 ++ source/Chunk.cpp | 88 ++++++++++++++++++----- source/Chunk.h | 4 ++ source/ChunkMap.cpp | 79 ++++++++++++-------- source/ChunkMap.h | 3 + source/Simulator/FloodyFluidSimulator.cpp | 10 ++- 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); }