From f7da7c2536b438db92bc28b88c4139d9af15e44f Mon Sep 17 00:00:00 2001 From: "madmaxoft@gmail.com" Date: Sat, 13 Oct 2012 09:53:28 +0000 Subject: Preparation for multiple fluid simulators. Moved all simulators into a subfolder. Replaced cWaterSimulator and cLavaSimulator with a generic cFluidSimulator. Moved original fluid simulation into cClassicFluidSimulator. Fluid simulator parameters (MaxHeight, Falloff) are read from the world.ini file (can have nether-like lava with lower falloff) git-svn-id: http://mc-server.googlecode.com/svn/trunk@956 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- VC2008/MCServer.vcproj | 38 +- source/Blocks/BlockRedstoneRepeater.cpp | 2 +- source/Chunk.cpp | 2 - source/FireSimulator.cpp | 133 ----- source/FireSimulator.h | 47 -- source/FluidSimulator.cpp | 692 ------------------------ source/FluidSimulator.h | 55 -- source/Globals.h | 2 + source/LavaSimulator.cpp | 20 - source/LavaSimulator.h | 12 - source/Pickup.cpp | 6 +- source/RedstoneSimulator.cpp | 886 ------------------------------- source/RedstoneSimulator.h | 82 --- source/SandSimulator.cpp | 102 ---- source/SandSimulator.h | 39 -- source/Simulator.cpp | 33 -- source/Simulator.h | 20 - source/Simulator/ClassicFluidSimulator.h | 58 ++ source/Simulator/FireSimulator.cpp | 178 +++++++ source/Simulator/FireSimulator.h | 40 ++ source/Simulator/FluidSimulator.cpp | 19 + source/Simulator/FluidSimulator.h | 47 ++ source/Simulator/LavaSimulator.cpp | 20 + source/Simulator/LavaSimulator.h | 12 + source/Simulator/RedstoneSimulator.cpp | 886 +++++++++++++++++++++++++++++++ source/Simulator/RedstoneSimulator.h | 81 +++ source/Simulator/SandSimulator.cpp | 101 ++++ source/Simulator/SandSimulator.h | 33 ++ source/Simulator/Simulator.cpp | 44 ++ source/Simulator/Simulator.h | 38 ++ source/Simulator/SimulatorManager.cpp | 67 +++ source/Simulator/SimulatorManager.h | 39 ++ source/Simulator/WaterSimulator.cpp | 22 + source/Simulator/WaterSimulator.h | 11 + source/SimulatorManager.cpp | 67 --- source/SimulatorManager.h | 39 -- source/WaterSimulator.cpp | 22 - source/WaterSimulator.h | 11 - source/World.cpp | 65 ++- source/World.h | 19 +- 40 files changed, 1781 insertions(+), 2309 deletions(-) delete mode 100644 source/FireSimulator.cpp delete mode 100644 source/FireSimulator.h delete mode 100644 source/FluidSimulator.cpp delete mode 100644 source/FluidSimulator.h delete mode 100644 source/LavaSimulator.cpp delete mode 100644 source/LavaSimulator.h delete mode 100644 source/RedstoneSimulator.cpp delete mode 100644 source/RedstoneSimulator.h delete mode 100644 source/SandSimulator.cpp delete mode 100644 source/SandSimulator.h delete mode 100644 source/Simulator.cpp delete mode 100644 source/Simulator.h create mode 100644 source/Simulator/ClassicFluidSimulator.h create mode 100644 source/Simulator/FireSimulator.cpp create mode 100644 source/Simulator/FireSimulator.h create mode 100644 source/Simulator/FluidSimulator.cpp create mode 100644 source/Simulator/FluidSimulator.h create mode 100644 source/Simulator/LavaSimulator.cpp create mode 100644 source/Simulator/LavaSimulator.h create mode 100644 source/Simulator/RedstoneSimulator.cpp create mode 100644 source/Simulator/RedstoneSimulator.h create mode 100644 source/Simulator/SandSimulator.cpp create mode 100644 source/Simulator/SandSimulator.h create mode 100644 source/Simulator/Simulator.cpp create mode 100644 source/Simulator/Simulator.h create mode 100644 source/Simulator/SimulatorManager.cpp create mode 100644 source/Simulator/SimulatorManager.h create mode 100644 source/Simulator/WaterSimulator.cpp create mode 100644 source/Simulator/WaterSimulator.h delete mode 100644 source/SimulatorManager.cpp delete mode 100644 source/SimulatorManager.h delete mode 100644 source/WaterSimulator.cpp delete mode 100644 source/WaterSimulator.h diff --git a/VC2008/MCServer.vcproj b/VC2008/MCServer.vcproj index 059b4b453..5ef341980 100644 --- a/VC2008/MCServer.vcproj +++ b/VC2008/MCServer.vcproj @@ -1008,70 +1008,62 @@ - - - - diff --git a/source/Blocks/BlockRedstoneRepeater.cpp b/source/Blocks/BlockRedstoneRepeater.cpp index 5af5edb1e..84a841fb0 100644 --- a/source/Blocks/BlockRedstoneRepeater.cpp +++ b/source/Blocks/BlockRedstoneRepeater.cpp @@ -4,7 +4,7 @@ #include "../Item.h" #include "../World.h" #include "../Player.h" -#include "../RedstoneSimulator.h" +#include "../Simulator/RedstoneSimulator.h" diff --git a/source/Chunk.cpp b/source/Chunk.cpp index 0dec50230..aaea4bf71 100644 --- a/source/Chunk.cpp +++ b/source/Chunk.cpp @@ -8,8 +8,6 @@ #include "Chunk.h" #include "World.h" -#include "WaterSimulator.h" -#include "LavaSimulator.h" #include "ClientHandle.h" #include "Server.h" #include "zlib.h" diff --git a/source/FireSimulator.cpp b/source/FireSimulator.cpp deleted file mode 100644 index 1dc104d0c..000000000 --- a/source/FireSimulator.cpp +++ /dev/null @@ -1,133 +0,0 @@ - -#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules - -#include "FireSimulator.h" -#include "World.h" -#include "Vector3i.h" -#include "BlockID.h" -#include "Defines.h" - -cFireSimulator::cFireSimulator( cWorld* a_World ) - : cSimulator(a_World) - , m_Blocks(new BlockList) - , m_Buffer(new BlockList) - , m_BurningBlocks(new BlockList) -{ - -} - -cFireSimulator::~cFireSimulator() -{ - delete m_Buffer; - delete m_Blocks; - delete m_BurningBlocks; -} - -void cFireSimulator::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 ) - { - Vector3i Pos = *itr; - - char BlockID = m_World->GetBlock(Pos.x, Pos.y, Pos.z); - - if(!IsAllowedBlock(BlockID)) //Check wheather the block is still burning - continue; - - if(BurnBlockAround(Pos.x, Pos.y, Pos.z)) //Burn single block and if there was one -> next time again - _AddBlock(Pos.x, Pos.y, Pos.z); - else - if(!IsForeverBurnable(m_World->GetBlock(Pos.x, Pos.y - 1, Pos.z)) && !FiresForever(BlockID)) - m_World->SetBlock(Pos.x, Pos.y, Pos.z, E_BLOCK_AIR, 0); - - } - -} - - -bool cFireSimulator::IsAllowedBlock( BLOCKTYPE a_BlockType ) -{ - return a_BlockType == E_BLOCK_FIRE - || IsBlockLava(a_BlockType); -} - -void cFireSimulator::AddBlock(int a_X, int a_Y, int a_Z) -{ - char BlockID = m_World->GetBlock(a_X, a_Y, a_Z); - if(!IsAllowedBlock(BlockID)) //This should save very much time because it doesn´t have to iterate through all blocks - return; - - //check for duplicates - for( BlockList::iterator itr = m_Blocks->begin(); itr != m_Blocks->end(); ++itr ) - { - Vector3i Pos = *itr; - if( Pos.x == a_X && Pos.y == a_Y && Pos.z == a_Z ) - return; - } - - _AddBlock(a_X, a_Y, a_Z); - -} - -void cFireSimulator::_AddBlock(int a_X, int a_Y, int a_Z) -{ - m_Blocks->push_back( Vector3i(a_X, a_Y, a_Z) ); - -} - -bool cFireSimulator::IsForeverBurnable( BLOCKTYPE a_BlockType ) -{ - return a_BlockType == E_BLOCK_BLOODSTONE; -} - -bool cFireSimulator::IsBurnable( BLOCKTYPE a_BlockType ) -{ - return a_BlockType == E_BLOCK_PLANKS - || a_BlockType == E_BLOCK_LEAVES - || a_BlockType == E_BLOCK_LOG - || a_BlockType == E_BLOCK_WOOL - || a_BlockType == E_BLOCK_BOOKCASE - || a_BlockType == E_BLOCK_FENCE - || a_BlockType == E_BLOCK_TNT - || a_BlockType == E_BLOCK_VINES; -} - -bool cFireSimulator::FiresForever( BLOCKTYPE a_BlockType ) -{ - return a_BlockType != E_BLOCK_FIRE; -} - -bool cFireSimulator::BurnBlockAround(int a_X, int a_Y, int a_Z) -{ - return BurnBlock(a_X + 1, a_Y, a_Z) - || BurnBlock(a_X - 1, a_Y, a_Z) - || BurnBlock(a_X, a_Y + 1, a_Z) - || BurnBlock(a_X, a_Y - 1, a_Z) - || BurnBlock(a_X, a_Y, a_Z + 1) - || BurnBlock(a_X, a_Y, a_Z - 1); -} - -bool cFireSimulator::BurnBlock(int a_X, int a_Y, int a_Z) -{ - char BlockID = m_World->GetBlock(a_X, a_Y, a_Z); - if(IsBurnable(BlockID)) - { - m_World->SetBlock(a_X, a_Y, a_Z, E_BLOCK_FIRE, 0); - return true; - } - if(IsForeverBurnable(BlockID)) - { - char BlockAbove = m_World->GetBlock(a_X, a_Y + 1, a_Z); - if(BlockAbove == E_BLOCK_AIR) - { - m_World->SetBlock(a_X, a_Y + 1, a_Z, E_BLOCK_FIRE, 0); //Doesn´t notify the simulator so it won´t go off - return true; - } - return false; - } - - return false; -} \ No newline at end of file diff --git a/source/FireSimulator.h b/source/FireSimulator.h deleted file mode 100644 index 90e6a6062..000000000 --- a/source/FireSimulator.h +++ /dev/null @@ -1,47 +0,0 @@ - -#pragma once - -#include "Simulator.h" -#include "BlockEntity.h" - - - - - -class Vector3i; -class cWorld; - - - - - -class cFireSimulator : public cSimulator -{ -public: - cFireSimulator( cWorld* a_World ); - ~cFireSimulator(); - - virtual void Simulate( float a_Dt ) override; - - virtual bool IsAllowedBlock( BLOCKTYPE a_BlockType ) override; - - virtual bool IsBurnable( BLOCKTYPE a_BlockType ); - virtual bool IsForeverBurnable( BLOCKTYPE a_BlockType ); - virtual bool FiresForever( BLOCKTYPE a_BlockType ); - -protected: - virtual void AddBlock(int a_X, int a_Y, int a_Z) override; - virtual void _AddBlock(int a_X, int a_Y, int a_Z); - virtual bool BurnBlockAround(int a_X, int a_Y, int a_Z); - virtual bool BurnBlock(int a_X, int a_Y, int a_Z); - - typedef std::list BlockList; - BlockList *m_Blocks; - BlockList *m_Buffer; - - BlockList *m_BurningBlocks; -}; - - - - diff --git a/source/FluidSimulator.cpp b/source/FluidSimulator.cpp deleted file mode 100644 index 8a6a760f3..000000000 --- a/source/FluidSimulator.cpp +++ /dev/null @@ -1,692 +0,0 @@ -#include "Globals.h" - -#include -#include - -#include "FluidSimulator.h" -#include "World.h" -#include "Vector3i.h" -#include "BlockID.h" -#include "Defines.h" -#include "Item.h" -#include "Blocks/BlockHandler.h" - - - - - -//#define DEBUG_FLUID -#ifdef DEBUG_FLUID -#define LOG_FLUID(...) LOGWARN( __VA_ARGS__ ) -#else -#define LOG_FLUID(...) -#endif - - - - - -class cFluidSimulator::FluidData -{ -public: - FluidData( cWorld* a_World, cFluidSimulator *a_Simulator ) - : m_ActiveFluid( new std::set < Vector3i >() ) - , m_Simulator (a_Simulator) - , m_Buffer( new std::set< Vector3i >() ) - , m_World( a_World ) - {} - - ~FluidData() - { - delete m_Buffer; - delete m_ActiveFluid; - } - - void UpdateWave(Vector3i a_LeftCorner, Vector3i a_CurBlock) - { - Vector3i LevelPoints [] = { - Vector3i( a_CurBlock.x-1, a_CurBlock.y, a_CurBlock.z ), - Vector3i( a_CurBlock.x+1, a_CurBlock.y, a_CurBlock.z ), - Vector3i( a_CurBlock.x, a_CurBlock.y, a_CurBlock.z-1 ), - Vector3i( a_CurBlock.x, a_CurBlock.y, a_CurBlock.z+1 ), - }; - - for(int i=0; i<4; i++) - { - Vector3i cur = LevelPoints[i]; - switch(m_Relief[cur.x][cur.z]) - { - case E_HOLE: - { - m_StartSide[cur.x][cur.z] = m_StartSide[a_CurBlock.x][a_CurBlock.z]; - m_CurResult|=m_StartSide[cur.x][cur.z]; - m_NearestHole = m_WayLength[a_CurBlock.x][a_CurBlock.z] + 1; - LOG_FLUID("Hole found: %d \t curResult: %d", int(m_StartSide[cur.x][cur.z]), int(m_CurResult) ); - LOG_FLUID("Coordinates: (%d, %d)", cur.x, cur.z); - }break; - - case E_BLOCK: - {}break; - - case E_PLAIN: - { - if (m_WayLength[cur.x][cur.z] > m_WayLength[a_CurBlock.x][a_CurBlock.z] + 1) - { - m_WayLength[cur.x][cur.z] = m_WayLength[a_CurBlock.x][a_CurBlock.z] + 1; - m_StartSide[cur.x][cur.z] = m_StartSide[a_CurBlock.x][a_CurBlock.z]; - m_WaveQueue.push(cur); - } - else if(m_WayLength[cur.x][cur.z] == m_WayLength[a_CurBlock.x][a_CurBlock.z] + 1) - { - m_StartSide[cur.x][cur.z] |= m_StartSide[a_CurBlock.x][a_CurBlock.z]; - } - LOG_FLUID("Plain step: (%d, %d) from %d", cur.x, cur.z, m_StartSide[cur.x][cur.z]); - } - } - } - } - - std::vector< Vector3i > GetLowestPoints( int a_X, int a_Y, int a_Z ) - { - - std::vector< Vector3i > Points; //result - - Vector3i CornerGlobal(a_X - AREA_WIDTH/2, a_Y, a_Z - AREA_WIDTH/2); - - //TODO: rewrite without relief, get blocks directly in algorithm - for(int x=0; xGetBlock( CornerGlobal.x + x, CornerGlobal.y, CornerGlobal.z + z ); - char DownBlock = m_World->GetBlock( CornerGlobal.x + x, CornerGlobal.y-1, CornerGlobal.z + z ); - - if(m_Simulator->IsSolidBlock(UpperBlock)||(m_Simulator->IsStationaryBlock(UpperBlock))) - { - m_Relief[x][z] = E_BLOCK; - } - else if(m_Simulator->IsSolidBlock(DownBlock)) - { - m_Relief[x][z] = E_PLAIN; - } - else - { - m_Relief[x][z] = E_HOLE; - } - m_WayLength[x][z] = 255; - m_StartSide[x][z] = E_SIDE_NONE; - } - LOG_FLUID("%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t", m_Relief[x][0], m_Relief[x][1], m_Relief[x][2], m_Relief[x][3], m_Relief[x][4], m_Relief[x][5], m_Relief[x][6], m_Relief[x][7], m_Relief[x][8], m_Relief[x][9], m_Relief[x][10]); - } - - m_NearestHole = 5; - m_CurResult = 0; - while(!m_WaveQueue.empty()) m_WaveQueue.pop(); - - int left = AREA_WIDTH/2 - 1; - int right = AREA_WIDTH/2 + 1; - int center = AREA_WIDTH/2; - - Vector3i r(right, 0, center); //right block - Vector3i l(left, 0, center); //left block - Vector3i f(center, 0, right); //front block - Vector3i b(center, 0, left); //back block - Vector3i c(center, 0, center); //center block - - m_WayLength[c.x][c.z] = 0; - - Vector3i Nearest[] = {r, l, f, b}; - unsigned char Sides[] = {E_SIDE_RIGHT, E_SIDE_LEFT, E_SIDE_FRONT, E_SIDE_BACK}; - - for(int i=0; i<4; i++) - { - Vector3i cur = Nearest[i]; - switch(m_Relief[cur.x][cur.z]) - { - case E_HOLE: - { - m_StartSide[cur.x][cur.z] = Sides[i]; - m_CurResult |= m_StartSide[cur.x][cur.z]; - m_NearestHole = 1; - LOG_FLUID("Hole found: %d \t curResult: %d", int(Sides[i]), int(m_CurResult) ); - }break; - - case E_BLOCK: - {}break; - - case E_PLAIN: - { - m_WaveQueue.push(cur); - m_StartSide[cur.x][cur.z] = Sides[i]; - m_WayLength[cur.x][cur.z] = 1; - LOG_FLUID("Plain found: %d", int(Sides[i])); - } - } - } - - Vector3i curBlock; - - bool bContinue = !m_WaveQueue.empty(); - - if(!m_WaveQueue.empty()) - { - curBlock = m_WaveQueue.front(); - bContinue = (m_WayLength[curBlock.x][curBlock.z] < m_NearestHole); - } - - while(bContinue) - { - LOG_FLUID("while iteration" ); - curBlock = m_WaveQueue.front(); - UpdateWave(CornerGlobal, curBlock); - m_WaveQueue.pop(); - - bContinue = ( (!m_WaveQueue.empty()) && (m_WayLength[m_WaveQueue.front().x][m_WaveQueue.front().z] < m_NearestHole) ); - } - - - - if(m_CurResult & E_SIDE_LEFT) Points.push_back(Vector3i( a_X-1, a_Y, a_Z )); - if(m_CurResult & E_SIDE_RIGHT) Points.push_back(Vector3i( a_X+1, a_Y, a_Z )); - if(m_CurResult & E_SIDE_FRONT) Points.push_back(Vector3i( a_X, a_Y, a_Z+1 )); - if(m_CurResult & E_SIDE_BACK) Points.push_back(Vector3i( a_X, a_Y, a_Z-1 )); - - if(Points.empty()) - { - Vector3i LevelPoints [] = { - Vector3i( a_X-1, a_Y, a_Z ), - Vector3i( a_X+1, a_Y, a_Z ), - Vector3i( a_X, a_Y, a_Z-1 ), - Vector3i( a_X, a_Y, a_Z+1 ), - }; - for( int i = 0; i < 4; ++i ) - { - char Block = m_World->GetBlock( LevelPoints[i].x, a_Y, LevelPoints[i].z ); - if( m_Simulator->IsPassableForFluid(Block) ) - Points.push_back( LevelPoints[i] ); - } - } - - return Points; - } - - std::set< Vector3i >* m_ActiveFluid; - std::set< Vector3i >* m_Buffer; - cWorld* m_World; - cFluidSimulator *m_Simulator; - - const static int AREA_WIDTH = 11; - - const static unsigned char E_SIDE_RIGHT = 0x10; - const static unsigned char E_SIDE_LEFT = 0x20; - const static unsigned char E_SIDE_FRONT = 0x40; - const static unsigned char E_SIDE_BACK = 0x80; - const static unsigned char E_SIDE_NONE = 0x00; - - enum eRelief {E_HOLE = 0, E_PLAIN = 1, E_BLOCK = 2}; - - eRelief m_Relief[AREA_WIDTH][AREA_WIDTH]; - unsigned char m_WayLength[AREA_WIDTH][AREA_WIDTH]; - unsigned char m_StartSide[AREA_WIDTH][AREA_WIDTH]; - - std::queue m_WaveQueue; - - int m_NearestHole; - unsigned char m_CurResult; -}; - - - - - -cFluidSimulator::cFluidSimulator( cWorld* a_World ) - : cSimulator(a_World) - , m_Data(0) -{ - m_Data = new FluidData(a_World, this); -} - - - - - -cFluidSimulator::~cFluidSimulator() -{ - delete m_Data; -} - - - - - -void cFluidSimulator::AddBlock( int a_X, int a_Y, int a_Z ) -{ - char BlockType = m_World->GetBlock(a_X, a_Y, a_Z); - if (!IsAllowedBlock(BlockType)) //This should save very much time because it doesn´t have to iterate through all blocks - { - return; - } - - std::set< Vector3i > & ActiveFluid = *m_Data->m_ActiveFluid; - ActiveFluid.insert( Vector3i( a_X, a_Y, a_Z ) ); -} - - - - - -char cFluidSimulator::GetHighestLevelAround( int a_X, int a_Y, int a_Z ) -{ - char Max = m_MaxHeight + m_FlowReduction; - -#define __HIGHLEVEL_CHECK__( x, y, z ) \ - if( IsAllowedBlock( m_World->GetBlock( x, y, z ) ) ) \ - { \ - char Meta; \ - if( (Meta = m_World->GetBlockMeta( x, y, z ) ) < Max ) Max = Meta; \ - else if( Meta == m_MaxHeight + m_FlowReduction ) Max = 0; \ - if( Max == 0 ) return 0; \ - } - - __HIGHLEVEL_CHECK__( a_X-1, a_Y, a_Z ); - __HIGHLEVEL_CHECK__( a_X+1, a_Y, a_Z ); - __HIGHLEVEL_CHECK__( a_X, a_Y, a_Z-1 ); - __HIGHLEVEL_CHECK__( a_X, a_Y, a_Z+1 ); - - return Max; -} - - - - - -void cFluidSimulator::Simulate( float a_Dt ) -{ - m_Timer += a_Dt; - - if (m_Data->m_ActiveFluid->empty()) //Nothing to do if there is no active fluid ;) saves very little time ;D - { - return; - } - - std::swap( m_Data->m_ActiveFluid, m_Data->m_Buffer ); // Swap so blocks can be added to empty ActiveFluid array - m_Data->m_ActiveFluid->clear(); - - std::set< Vector3i > & FluidBlocks = *m_Data->m_Buffer; - for( std::set< Vector3i >::iterator itr = FluidBlocks.begin(); itr != FluidBlocks.end(); ++itr ) - { - const Vector3i & pos = *itr; - - if(UniqueSituation(pos)) - { - continue; - } - - char BlockID = m_World->GetBlock( pos.x, pos.y, pos.z ); - if( IsAllowedBlock( BlockID ) ) // only care about own fluid - { - bool bIsFed = false; - char Meta = m_World->GetBlockMeta( pos.x, pos.y, pos.z ); - char Feed = Meta; - if( BlockID == m_StationaryFluidBlock) Meta = 0; - if( Meta == 8 ) // Falling fluid - { - if( IsAllowedBlock( m_World->GetBlock(pos.x, pos.y+1, pos.z) ) ) // Block above is fluid - { - bIsFed = true; - Meta = 0; // Make it a full block - } - } - else if( Meta < m_FlowReduction ) // It's a full block, so it's always fed - { - bIsFed = true; - } - else - { - if( (Feed = GetHighestLevelAround( pos.x, pos.y, pos.z )) < Meta ) - bIsFed = true; - } - - - if( bIsFed ) - { - char DownID = m_World->GetBlock(pos.x, pos.y - 1, pos.z); - bool bWashedAwayItem = CanWashAway(DownID); - if ((IsPassableForFluid(DownID) || bWashedAwayItem) && !IsStationaryBlock(DownID) ) // free for fluid - { - if (bWashedAwayItem) - { - cBlockHandler * Handler = BlockHandler(DownID); - if (Handler->DoesDropOnUnsuitable()) - { - Handler->DropBlock(m_World, pos.x, pos.y - 1, pos.z); - } - } - if (pos.y > 0) - { - m_World->FastSetBlock( pos.x, pos.y-1, pos.z, m_FluidBlock, 8 ); // falling - AddBlock( pos.x, pos.y-1, pos.z ); - ApplyUniqueToNearest(pos - Vector3i(0, 1, 0)); - } - } - if(IsSolidBlock(DownID)||( BlockID == m_StationaryFluidBlock)) // Not falling - { - if( Feed + m_FlowReduction < Meta ) - { - m_World->FastSetBlock( pos.x, pos.y, pos.z, m_FluidBlock, Feed + m_FlowReduction ); - AddBlock( pos.x, pos.y, pos.z ); - ApplyUniqueToNearest(pos); - } - else if(( Meta < m_MaxHeight )||( BlockID == m_StationaryFluidBlock)) // max is the lowest, so it cannot spread - { - std::vector< Vector3i > Points = m_Data->GetLowestPoints( pos.x, pos.y, pos.z ); - for( std::vector< Vector3i >::iterator itr = Points.begin(); itr != Points.end(); ++itr ) - { - Vector3i & p = *itr; - char BlockID = m_World->GetBlock( p.x, p.y, p.z ); - bool bWashedAwayItem = CanWashAway( BlockID ); - - if (!IsPassableForFluid(BlockID)) continue; - - if (!IsAllowedBlock(BlockID)) - { - if (bWashedAwayItem) - { - cBlockHandler * Handler = BlockHandler(DownID); - if (Handler->DoesDropOnUnsuitable()) - { - Handler->DropBlock(m_World, p.x, p.y, p.z); - } - } - - if (p.y == pos.y) - { - m_World->FastSetBlock(p.x, p.y, p.z, m_FluidBlock, Meta + m_FlowReduction); - } - else - { - m_World->FastSetBlock(p.x, p.y, p.z, m_FluidBlock, 8); - } - AddBlock( p.x, p.y, p.z ); - ApplyUniqueToNearest(p); - } - else // it's fluid - { - char PointMeta = m_World->GetBlockMeta( p.x, p.y, p.z ); - if( PointMeta > Meta + m_FlowReduction ) - { - AddBlock( p.x, p.y, p.z ); - ApplyUniqueToNearest(p); - } - } - } - } - } - } - else// not fed - { - m_World->FastSetBlock( pos.x, pos.y, pos.z, E_BLOCK_AIR, 0 ); - WakeUp( pos.x, pos.y, pos.z ); - } - } - } -} - - - - - -bool cFluidSimulator::IsPassableForFluid(BLOCKTYPE a_BlockType) -{ - return a_BlockType == E_BLOCK_AIR - || a_BlockType == E_BLOCK_FIRE - || IsAllowedBlock(a_BlockType) - || CanWashAway(a_BlockType); -} - - - - - -bool cFluidSimulator::IsStationaryBlock (BLOCKTYPE a_BlockType) -{ - return a_BlockType == m_StationaryFluidBlock; -} - - - - - -bool cFluidSimulator::CanWashAway( BLOCKTYPE a_BlockType ) -{ - switch( a_BlockType ) - { - case E_BLOCK_YELLOW_FLOWER: - case E_BLOCK_RED_ROSE: - case E_BLOCK_RED_MUSHROOM: - case E_BLOCK_BROWN_MUSHROOM: - case E_BLOCK_CACTUS: - return true; - default: - return false; - }; -} - - - - - -bool cFluidSimulator::IsSolidBlock( BLOCKTYPE a_BlockType ) -{ - return !(a_BlockType == E_BLOCK_AIR - || a_BlockType == E_BLOCK_FIRE - || IsBlockLava(a_BlockType) - || IsBlockWater(a_BlockType) - || CanWashAway(a_BlockType)); -} - - - - - -//TODO Not working very well yet :s -Direction cFluidSimulator::GetFlowingDirection(int a_X, int a_Y, int a_Z, bool a_Over) -{ - char BlockID = m_World->GetBlock(a_X, a_Y, a_Z); - if(!IsAllowedBlock(BlockID)) //No Fluid -> No Flowing direction :D - return NONE; - - - /* - Disabled because of causing problems and beeing useless atm - char BlockBelow = m_World->GetBlock(a_X, a_Y - 1, a_Z); //If there is nothing or fluid below it -> dominating flow is down :D - if(BlockBelow == E_BLOCK_AIR || IsAllowedBlock(BlockBelow)) - return Y_MINUS; - */ - - char LowestPoint = m_World->GetBlockMeta(a_X, a_Y, a_Z); //Current Block Meta so only lower points will be counted - int X = 0, Y = 0, Z = 0; //Lowest Pos will be stored here - - if(IsAllowedBlock(m_World->GetBlock(a_X, a_Y + 1, a_Z)) && a_Over) //check for upper block to flow because this also affects the flowing direction - { - return GetFlowingDirection(a_X, a_Y + 1, a_Z, false); - } - - std::vector< Vector3i * > Points; - - Points.reserve(4); //Already allocate 4 places :D - - //add blocks around the checking pos - Points.push_back(new Vector3i(a_X - 1, a_Y, a_Z)); - Points.push_back(new Vector3i(a_X + 1, a_Y, a_Z)); - Points.push_back(new Vector3i(a_X, a_Y, a_Z + 1)); - Points.push_back(new Vector3i(a_X, a_Y, a_Z - 1)); - - for(std::vector::iterator it = Points.begin(); it < Points.end(); it++) - { - Vector3i *Pos = (*it); - char BlockID = m_World->GetBlock(Pos->x, Pos->y, Pos->z); - if(IsAllowedBlock(BlockID)) - { - char Meta = m_World->GetBlockMeta(Pos->x, Pos->y, Pos->z); - - if(Meta > LowestPoint) - { - LowestPoint = Meta; - X = Pos->x; - Y = Pos->y; - Z = Pos->z; - } - }else if(BlockID == E_BLOCK_AIR) - { - LowestPoint = 9; //This always dominates - X = Pos->x; - Y = Pos->y; - Z = Pos->z; - - } - delete Pos; - } - - if(LowestPoint == m_World->GetBlockMeta(a_X, a_Y, a_Z)) - return NONE; - - if(a_X - X > 0) - { - return X_MINUS; - } - - if(a_X - X < 0) - { - return X_PLUS; - } - - if(a_Z - Z > 0) - { - return Z_MINUS; - } - - if(a_Z - Z < 0) - { - return Z_PLUS; - } - - return NONE; -} - - - - - -bool cFluidSimulator::UniqueSituation(Vector3i a_Pos) -{ - bool result = false; - - char BlockId = m_World->GetBlock( a_Pos.x, a_Pos.y, a_Pos.z ); - char Meta = m_World->GetBlockMeta( a_Pos.x, a_Pos.y, a_Pos.z ); - - if(IsBlockWater(BlockId)) - { - - char UpperBlock = m_World->GetBlock( a_Pos.x, a_Pos.y + 1, a_Pos.z ); - if(IsBlockLava(UpperBlock)) - { - m_World->SetBlock(a_Pos.x, a_Pos.y, a_Pos.z, E_BLOCK_STONE, 0); - } - - - if(BlockId != E_BLOCK_STATIONARY_WATER) - { - char DownBlockId = m_World->GetBlock( a_Pos.x, a_Pos.y-1, a_Pos.z ); - if(IsSolidBlock(DownBlockId)) - { - Vector3i LevelPoints [] = { - Vector3i( a_Pos.x-1, a_Pos.y, a_Pos.z ), - Vector3i( a_Pos.x+1, a_Pos.y, a_Pos.z ), - Vector3i( a_Pos.x, a_Pos.y, a_Pos.z-1 ), - Vector3i( a_Pos.x, a_Pos.y, a_Pos.z+1 ), - }; - int SourceBlocksCount = 0; - for(int i=0; i<4; i++) - { - if (m_World->GetBlock(LevelPoints[i].x, LevelPoints[i].y, LevelPoints[i].z)==E_BLOCK_STATIONARY_WATER) - { - SourceBlocksCount++; - } - } - if(SourceBlocksCount>=2) - { - m_World->SetBlock(a_Pos.x, a_Pos.y, a_Pos.z, E_BLOCK_STATIONARY_WATER, 0); - } - } - - } - } - - if(IsBlockLava(BlockId)) - { - bool bWater = false; - - char UpperBlock = m_World->GetBlock( a_Pos.x, a_Pos.y + 1, a_Pos.z ); - if (IsBlockWater(UpperBlock)) - { - bWater = true; - } - else - { - Vector3i LevelPoints [] = { - Vector3i( a_Pos.x-1, a_Pos.y, a_Pos.z ), - Vector3i( a_Pos.x+1, a_Pos.y, a_Pos.z ), - Vector3i( a_Pos.x, a_Pos.y, a_Pos.z-1 ), - Vector3i( a_Pos.x, a_Pos.y, a_Pos.z+1 ), - }; - - for(int i=0; i<4; i++) - { - if (IsBlockWater(m_World->GetBlock(LevelPoints[i].x, LevelPoints[i].y, LevelPoints[i].z))) - { - bWater = true; - } - } - } - - - if(bWater) - { - if(BlockId == E_BLOCK_STATIONARY_LAVA) - { - m_World->SetBlock(a_Pos.x, a_Pos.y, a_Pos.z, E_BLOCK_OBSIDIAN, 0); - } - else if (MetaSetBlock(a_Pos.x, a_Pos.y, a_Pos.z, E_BLOCK_COBBLESTONE, 0); - } - } - } - - return result; -} - - - - - -void cFluidSimulator::ApplyUniqueToNearest(Vector3i a_Pos) -{ - Vector3i NearPoints [] = { - Vector3i( a_Pos.x-1, a_Pos.y, a_Pos.z ), - Vector3i( a_Pos.x+1, a_Pos.y, a_Pos.z ), - Vector3i( a_Pos.x, a_Pos.y, a_Pos.z-1 ), - Vector3i( a_Pos.x, a_Pos.y, a_Pos.z+1 ), - Vector3i( a_Pos.x, a_Pos.y-1, a_Pos.z ) - }; - - for(int i=0; i<5; i++) - { - UniqueSituation(NearPoints[i]); - } -} - - - - diff --git a/source/FluidSimulator.h b/source/FluidSimulator.h deleted file mode 100644 index 09d9520ef..000000000 --- a/source/FluidSimulator.h +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once - -#include "Simulator.h" -#include "Vector3i.h" - - -//TODO This definitly needs a better naming :D but how? -enum Direction -{ - X_PLUS, - X_MINUS, - Y_PLUS, - Y_MINUS, - Z_PLUS, - Z_MINUS, - NONE -}; - -class Vector3i; -class cWorld; -class cFluidSimulator : public cSimulator -{ -public: - cFluidSimulator( cWorld* a_World ); - ~cFluidSimulator(); - - virtual void Simulate( float a_Dt ); - - //Gets the flowing direction. if a_Over is true also the block over the current block affects the direction (standard) - Direction GetFlowingDirection(int a_X, int a_Y, int a_Z, bool a_Over = true); - - virtual bool IsAllowedBlock( BLOCKTYPE a_BlockType ) = 0; - virtual bool IsStationaryBlock( BLOCKTYPE a_BlockType); - virtual bool IsPassableForFluid( BLOCKTYPE a_BlockType ); - bool CanWashAway( BLOCKTYPE a_BlockType ); - bool IsSolidBlock(BLOCKTYPE a_BlockType); -protected: - virtual void AddBlock( int a_X, int a_Y, int a_Z); - char GetHighestLevelAround( int a_X, int a_Y, int a_Z ); - - bool UniqueSituation(Vector3i a_Pos); //Applys special for this fluid rules like generation of water betwin sources, returns false if it is necessary to apply general rules - void ApplyUniqueToNearest(Vector3i a_Pos); - - float m_Timer; - - class FluidData; - FluidData* m_Data; - - //Customize - BLOCKTYPE m_FluidBlock; - BLOCKTYPE m_StationaryFluidBlock; - char m_MaxHeight; - char m_FlowReduction; - -}; \ No newline at end of file diff --git a/source/Globals.h b/source/Globals.h index 01b118cf8..40e80bd79 100644 --- a/source/Globals.h +++ b/source/Globals.h @@ -159,6 +159,8 @@ typedef unsigned short UInt16; #include #include #include +#include +#include diff --git a/source/LavaSimulator.cpp b/source/LavaSimulator.cpp deleted file mode 100644 index 726cc37e4..000000000 --- a/source/LavaSimulator.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "Globals.h" -#include "LavaSimulator.h" -#include "Defines.h" -#include "World.h" - - -cLavaSimulator::cLavaSimulator(cWorld *a_World) - : cFluidSimulator(a_World) -{ - m_FluidBlock = E_BLOCK_LAVA; - m_StationaryFluidBlock = E_BLOCK_STATIONARY_LAVA; - m_MaxHeight = 6; - m_FlowReduction = 2; -} - - -bool cLavaSimulator::IsAllowedBlock(BLOCKTYPE a_BlockType) -{ - return IsBlockLava(a_BlockType); -} \ No newline at end of file diff --git a/source/LavaSimulator.h b/source/LavaSimulator.h deleted file mode 100644 index d85b335b7..000000000 --- a/source/LavaSimulator.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include "FluidSimulator.h" - -class cLavaSimulator : public cFluidSimulator -{ -public: - cLavaSimulator( cWorld* a_World ); - - virtual bool IsAllowedBlock( BLOCKTYPE a_BlockType ) override; - - -}; \ No newline at end of file diff --git a/source/Pickup.cpp b/source/Pickup.cpp index 8a32a328b..ea1f603a4 100644 --- a/source/Pickup.cpp +++ b/source/Pickup.cpp @@ -9,7 +9,7 @@ #include "ClientHandle.h" #include "Inventory.h" #include "World.h" -#include "WaterSimulator.h" +#include "Simulator/FluidSimulator.h" #include "Server.h" #include "Player.h" #include "PluginManager.h" @@ -157,11 +157,9 @@ void cPickup::HandlePhysics(float a_Dt) if( fabs(m_Speed.z) < 0.05 ) m_Speed.z = 0; } - - //get flowing direction + // get flowing direction Direction WaterDir = World->GetWaterSimulator()->GetFlowingDirection((int) m_Pos.x - 1, (int) m_Pos.y, (int) m_Pos.z - 1); - m_WaterSpeed *= 0.9f; //Keep old speed but lower it switch(WaterDir) diff --git a/source/RedstoneSimulator.cpp b/source/RedstoneSimulator.cpp deleted file mode 100644 index 6c3e27228..000000000 --- a/source/RedstoneSimulator.cpp +++ /dev/null @@ -1,886 +0,0 @@ - -#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules - -#include "RedstoneSimulator.h" -#include "Piston.h" -#include "World.h" -#include "BlockID.h" -#include "Torch.h" - - - - - -cRedstoneSimulator::cRedstoneSimulator( cWorld* a_World ) - : super(a_World) -{ -} - - - - - -cRedstoneSimulator::~cRedstoneSimulator() -{ -} - - - - - -void cRedstoneSimulator::WakeUp( int a_X, int a_Y, int a_Z ) -{ - cCSLock Lock( m_CS ); - m_Blocks.push_back( Vector3i( a_X, a_Y, a_Z ) ); -} - - - - - -void cRedstoneSimulator::Simulate( float a_Dt ) -{ - // Toggle torches on/off - while( !m_RefreshTorchesAround.empty() ) - { - Vector3i pos = m_RefreshTorchesAround.front(); - m_RefreshTorchesAround.pop_front(); - - RefreshTorchesAround( pos ); - } - - // Set repeaters to correct values, and decrement ticks - for( RepeaterList::iterator itr = m_SetRepeaters.begin(); itr != m_SetRepeaters.end(); ) - { - (*itr).Ticks--; - if( (*itr).Ticks <= 0 ) - { - char Block = m_World->GetBlock( (*itr).Position ); - if( (*itr).bPowerOn == true && Block == E_BLOCK_REDSTONE_REPEATER_OFF ) - { - m_World->FastSetBlock( (*itr).Position.x, (*itr).Position.y, (*itr).Position.z, E_BLOCK_REDSTONE_REPEATER_ON, m_World->GetBlockMeta( (*itr).Position ) ); - m_Blocks.push_back( (*itr).Position ); - } - else if( (*itr).bPowerOn == false && Block == E_BLOCK_REDSTONE_REPEATER_ON ) - { - m_World->FastSetBlock( (*itr).Position.x, (*itr).Position.y, (*itr).Position.z, E_BLOCK_REDSTONE_REPEATER_OFF, m_World->GetBlockMeta( (*itr).Position ) ); - m_Blocks.push_back( (*itr).Position ); - } - - if( (*itr).bPowerOffNextTime ) - { - (*itr).bPowerOn = false; - (*itr).bPowerOffNextTime = false; - (*itr).Ticks = 10; // TODO: Look up actual ticks from block metadata - ++itr; - } - else - { - itr = m_SetRepeaters.erase( itr ); - } - } - else - { - ++itr; - } - } - - // Handle changed blocks - { - cCSLock Lock( m_CS ); - std::swap( m_Blocks, m_BlocksBuffer ); - } - for( BlockList::iterator itr = m_BlocksBuffer.begin(); itr != m_BlocksBuffer.end(); ++itr ) - { - HandleChange( *itr ); - } - m_BlocksBuffer.clear(); -} - - - - - -void cRedstoneSimulator::RefreshTorchesAround( const Vector3i & a_BlockPos ) -{ - static Vector3i Surroundings [] = { - Vector3i(-1, 0, 0), - Vector3i( 1, 0, 0), - Vector3i( 0, 0,-1), - Vector3i( 0, 0, 1), - Vector3i( 0, 1, 0), // Also toggle torch on top - }; - char TargetBlockID = E_BLOCK_REDSTONE_TORCH_ON; - char TargetRepeaterID = E_BLOCK_REDSTONE_REPEATER_OFF; - if( IsPowered( a_BlockPos, true ) ) - { - TargetBlockID = E_BLOCK_REDSTONE_TORCH_OFF; - TargetRepeaterID = E_BLOCK_REDSTONE_REPEATER_ON; - //if( m_World->GetBlock( a_BlockPos ) == E_BLOCK_DIRT ) - //{ - // m_World->FastSetBlock( a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, E_BLOCK_STONE, 0 ); - //} - } - else - { - //if( m_World->GetBlock( a_BlockPos ) == E_BLOCK_STONE ) - //{ - // m_World->FastSetBlock( a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, E_BLOCK_DIRT, 0 ); - //} - } - - for( unsigned int i = 0; i < ARRAYCOUNT( Surroundings ); ++i ) - { - Vector3i TorchPos = a_BlockPos + Surroundings[i]; - const char Block = m_World->GetBlock( TorchPos ); - switch( Block ) - { - case E_BLOCK_REDSTONE_TORCH_ON: - case E_BLOCK_REDSTONE_TORCH_OFF: - if( Block != TargetBlockID ) - { - char TorchMeta = m_World->GetBlockMeta( TorchPos ); - if( cTorch::IsAttachedTo( TorchPos, TorchMeta, a_BlockPos ) ) - { - m_World->FastSetBlock( TorchPos.x, TorchPos.y, TorchPos.z, TargetBlockID, m_World->GetBlockMeta( TorchPos ) ); - m_Blocks.push_back( TorchPos ); - } - } - break; - case E_BLOCK_REDSTONE_REPEATER_ON: - case E_BLOCK_REDSTONE_REPEATER_OFF: - if ((Block != TargetRepeaterID) && IsRepeaterPointingAway( TorchPos, m_World->GetBlockMeta( TorchPos ), a_BlockPos ) ) - { - SetRepeater( TorchPos, 10, TargetRepeaterID == E_BLOCK_REDSTONE_REPEATER_ON ); - } - break; - default: - break; - }; - } -} - - - - - -void cRedstoneSimulator::HandleChange( const Vector3i & a_BlockPos ) -{ - std::deque< Vector3i > SpreadStack; - - Vector3i Surroundings[] = { - Vector3i( 1, 0, 0 ), - Vector3i( 1, 1, 0 ), - Vector3i( 1,-1, 0 ), - Vector3i(-1, 0, 0 ), - Vector3i(-1, 1, 0 ), - Vector3i(-1,-1, 0 ), - Vector3i( 0, 0, 1 ), - Vector3i( 0, 1, 1 ), - Vector3i( 0,-1, 1 ), - Vector3i( 0, 0,-1 ), - Vector3i( 0, 1,-1 ), - Vector3i( 0,-1,-1 ), - Vector3i( 0,-1, 0 ), - }; - - char Block = m_World->GetBlock( a_BlockPos ); - - // First check whether torch should be on or off - if( Block == E_BLOCK_REDSTONE_TORCH_ON || Block == E_BLOCK_REDSTONE_TORCH_OFF ) - { - static Vector3i Surroundings [] = { - Vector3i(-1, 0, 0), - Vector3i( 1, 0, 0), - Vector3i( 0, 0,-1), - Vector3i( 0, 0, 1), - Vector3i( 0,-1, 0), - }; - for( unsigned int i = 0; i < ARRAYCOUNT( Surroundings ); ++i ) - { - Vector3i pos = a_BlockPos + Surroundings[i]; - char OtherBlock = m_World->GetBlock( pos ); - if( (OtherBlock != E_BLOCK_AIR) && (OtherBlock != E_BLOCK_REDSTONE_TORCH_ON) && (OtherBlock != E_BLOCK_REDSTONE_TORCH_OFF) ) - { - RefreshTorchesAround( pos ); - } - } - Block = m_World->GetBlock( a_BlockPos ); // Make sure we got the updated block - } - else if( Block == E_BLOCK_REDSTONE_REPEATER_ON || Block == E_BLOCK_REDSTONE_REPEATER_OFF ) // Check if repeater is powered by a 'powered block' (not wires/torch) - { - Vector3i Direction = GetRepeaterDirection( m_World->GetBlockMeta( a_BlockPos ) ); - Vector3i pos = a_BlockPos - Direction; // NOTE: It's minus Direction - char OtherBlock = m_World->GetBlock( pos ); - if( (OtherBlock != E_BLOCK_AIR) && (OtherBlock != E_BLOCK_REDSTONE_TORCH_ON) && (OtherBlock != E_BLOCK_REDSTONE_TORCH_OFF) && (OtherBlock != E_BLOCK_REDSTONE_WIRE) ) - { - RefreshTorchesAround( pos ); - } - else - { - SetRepeater( a_BlockPos, 10, IsPowered( a_BlockPos, false ) ); - } - Block = m_World->GetBlock( a_BlockPos ); - } - - BlockList Sources; - // If torch is still on, use it as a source - if( Block == E_BLOCK_REDSTONE_TORCH_ON ) - { - Sources.push_back( a_BlockPos ); - } - else if( Block == E_BLOCK_REDSTONE_REPEATER_ON ) - { - static Vector3i Surroundings [] = { // It only spreads right in front, and one block up - Vector3i( 0, 0, 0), - Vector3i( 0, 1, 0), - }; - Vector3i Direction = GetRepeaterDirection( m_World->GetBlockMeta( a_BlockPos ) ); - for( unsigned int i = 0; i < ARRAYCOUNT( Surroundings ); ++i ) - { - Vector3i pos = a_BlockPos + Direction + Surroundings[i]; - if( PowerBlock( pos, a_BlockPos, 0xf ) ) - { - SpreadStack.push_back( pos ); - } - } - } - - // Power all blocks legally connected to the sources - if( Block != E_BLOCK_REDSTONE_REPEATER_ON ) - { - BlockList NewSources = RemoveCurrent( a_BlockPos ); - Sources.insert( Sources.end(), NewSources.begin(), NewSources.end() ); - while( !Sources.empty() ) - { - Vector3i SourcePos = Sources.back(); - Sources.pop_back(); - - char Block = m_World->GetBlock( SourcePos ); - switch( Block ) - { - case E_BLOCK_REDSTONE_TORCH_OFF: - case E_BLOCK_REDSTONE_TORCH_ON: - { - static Vector3i Surroundings [] = { - Vector3i(-1, 0, 0), - Vector3i( 1, 0, 0), - Vector3i( 0, 0,-1), - Vector3i( 0, 0, 1), - }; - for( unsigned int i = 0; i < ARRAYCOUNT( Surroundings ); ++i ) - { - Vector3i OtherPos = SourcePos + Surroundings[i]; - if( PowerBlock( OtherPos, a_BlockPos, 0xf ) ) - { - SpreadStack.push_back( OtherPos ); // Changed, so add to stack - } - } - } - break; - case E_BLOCK_REDSTONE_REPEATER_OFF: - case E_BLOCK_REDSTONE_REPEATER_ON: - { - static Vector3i Surroundings [] = { - Vector3i( 0, 0, 0), - Vector3i( 0, 1, 0), - }; - Vector3i Direction = GetRepeaterDirection( m_World->GetBlockMeta( SourcePos ) ); - for( unsigned int i = 0; i < ARRAYCOUNT( Surroundings ); ++i ) - { - Vector3i pos = SourcePos + Direction + Surroundings[i]; - if( PowerBlock( pos, a_BlockPos, 0xf ) ) - { - SpreadStack.push_back( pos ); - } - } - } - break; - }; - - - } - } - - - // Do a floodfill - while( !SpreadStack.empty() ) - { - Vector3i pos = SpreadStack.back(); - SpreadStack.pop_back(); - - char Meta = m_World->GetBlockMeta( pos ); - - for( unsigned int i = 0; i < ARRAYCOUNT( Surroundings ); ++i ) - { - Vector3i OtherPos = pos + Surroundings[i]; - if( PowerBlock( OtherPos, pos, Meta-1 ) ) - { - SpreadStack.push_back( OtherPos ); // Changed, so add to stack - } - } - } - - // Only after a redstone area has been completely simulated the redstone entities can react - while( !m_RefreshPistons.empty() ) - { - Vector3i pos = m_RefreshPistons.back(); - m_RefreshPistons.pop_back(); - - char Block = m_World->GetBlock( pos ); - switch( Block ) - { - case E_BLOCK_PISTON: - case E_BLOCK_STICKY_PISTON: - if( IsPowered( pos ) ) - { - cPiston Piston( m_World ); - Piston.ExtendPiston( pos.x, pos.y, pos.z ); - } - else - { - cPiston Piston( m_World ); - Piston.RetractPiston( pos.x, pos.y, pos.z ); - } - break; - default: - break; - }; - } -} - - - - - -bool cRedstoneSimulator::PowerBlock( const Vector3i & a_BlockPos, const Vector3i & a_FromBlock, char a_Power ) -{ - char Block = m_World->GetBlock( a_BlockPos ); - switch( Block ) - { - case E_BLOCK_REDSTONE_WIRE: - { - if( m_World->GetBlockMeta( a_BlockPos ) < a_Power ) - { - m_World->SetBlockMeta( a_BlockPos, a_Power ); - return true; - } - } - break; - case E_BLOCK_PISTON: - case E_BLOCK_STICKY_PISTON: - { - m_RefreshPistons.push_back( a_BlockPos ); - } - break; - case E_BLOCK_REDSTONE_REPEATER_OFF: - case E_BLOCK_REDSTONE_REPEATER_ON: - { - if (IsRepeaterPointingAway( a_BlockPos, m_World->GetBlockMeta( a_BlockPos ), a_FromBlock )) - { - SetRepeater( a_BlockPos, 10, true ); - } - } - break; - default: - { - if( Block != E_BLOCK_AIR && Block != E_BLOCK_REDSTONE_TORCH_ON && Block != E_BLOCK_REDSTONE_TORCH_OFF ) - { - if( IsPowered( a_BlockPos, true ) ) - { - m_RefreshTorchesAround.push_back( a_BlockPos ); - } - } - } - break; - }; - - return false; -} - - - - - -int cRedstoneSimulator::UnPowerBlock( const Vector3i & a_BlockPos, const Vector3i & a_FromBlock) -{ - BLOCKTYPE BlockType = m_World->GetBlock(a_BlockPos); - switch (BlockType) - { - case E_BLOCK_REDSTONE_WIRE: - { - if( m_World->GetBlockMeta( a_BlockPos ) > 0 ) - { - m_World->SetBlockMeta( a_BlockPos, 0 ); - return 1; - } - break; - } - - case E_BLOCK_PISTON: - case E_BLOCK_STICKY_PISTON: - { - m_RefreshPistons.push_back( a_BlockPos ); - break; - } - - case E_BLOCK_REDSTONE_TORCH_ON: - { - return 2; - break; - } - - case E_BLOCK_REDSTONE_REPEATER_ON: - { - if ( - IsRepeaterPointingTo(a_BlockPos, m_World->GetBlockMeta(a_BlockPos), a_FromBlock ) || // Repeater is next to wire - IsRepeaterPointingTo(a_BlockPos, m_World->GetBlockMeta(a_BlockPos), a_FromBlock - Vector3i(0, 1, 0)) // Repeater is below wire - ) - { - return 2; - } - else if (IsRepeaterPointingAway( a_BlockPos, m_World->GetBlockMeta( a_BlockPos ), a_FromBlock ) ) - { - SetRepeater( a_BlockPos, 10, false ); - } - // fall-through: - } - - case E_BLOCK_REDSTONE_REPEATER_OFF: - { - if (IsRepeaterPointingAway( a_BlockPos, m_World->GetBlockMeta( a_BlockPos ), a_FromBlock )) - { - SetRepeater( a_BlockPos, 10, false ); - } - break; - } - - default: - { - if ((BlockType != E_BLOCK_AIR) && (BlockType != E_BLOCK_REDSTONE_TORCH_ON) && (BlockType != E_BLOCK_REDSTONE_TORCH_OFF)) - { - if (!IsPowered(a_BlockPos, true)) - { - m_RefreshTorchesAround.push_back( a_BlockPos ); - } - } - break; - } - } // switch (BlockType) - - return 0; -} - - - - - -// Removes current from all powered redstone wires until it reaches an energy source. -// Also returns all energy sources it encountered -cRedstoneSimulator::BlockList cRedstoneSimulator::RemoveCurrent( const Vector3i & a_BlockPos ) -{ - - - std::deque< Vector3i > SpreadStack; - std::deque< Vector3i > FoundSources; - - Vector3i Surroundings[] = { - Vector3i( 1, 0, 0 ), - Vector3i( 1, 1, 0 ), - Vector3i( 1,-1, 0 ), - Vector3i(-1, 0, 0 ), - Vector3i(-1, 1, 0 ), - Vector3i(-1,-1, 0 ), - Vector3i( 0, 0, 1 ), - Vector3i( 0, 1, 1 ), - Vector3i( 0,-1, 1 ), - Vector3i( 0, 0,-1 ), - Vector3i( 0, 1,-1 ), - Vector3i( 0,-1,-1 ), - Vector3i( 0,-1, 0 ), - }; - - char Block = m_World->GetBlock( a_BlockPos ); - if( Block == E_BLOCK_REDSTONE_REPEATER_ON || Block == E_BLOCK_REDSTONE_REPEATER_OFF ) - { - static Vector3i Surroundings [] = { // Repeaters only spread right in front and 1 block up - Vector3i( 0, 0, 0), - Vector3i( 0, 1, 0), - }; - Vector3i Direction = GetRepeaterDirection( m_World->GetBlockMeta( a_BlockPos ) ); - for( unsigned int i = 0; i < ARRAYCOUNT( Surroundings ); ++i ) - { - Vector3i pos = a_BlockPos + Direction + Surroundings[i]; - int RetVal = UnPowerBlock( pos, a_BlockPos ); - if( RetVal == 1 ) - { - SpreadStack.push_back( pos ); // Changed, so add to stack - } - else if( RetVal == 2 ) - { - FoundSources.push_back( pos ); - } - } - } - else if( Block == E_BLOCK_REDSTONE_TORCH_OFF || Block == E_BLOCK_REDSTONE_TORCH_ON ) - { - static Vector3i Surroundings [] = { // Torches only spread on the same level - Vector3i(-1, 0, 0), - Vector3i( 1, 0, 0), - Vector3i( 0, 0,-1), - Vector3i( 0, 0, 1), - }; - - for( unsigned int i = 0; i < ARRAYCOUNT( Surroundings ); ++i ) - { - Vector3i pos = Vector3i( a_BlockPos ) + Surroundings[i]; - int RetVal = UnPowerBlock( pos, a_BlockPos ); - if( RetVal == 1 ) - { - SpreadStack.push_back( pos ); // Changed, so add to stack - } - else if( RetVal == 2 ) - { - FoundSources.push_back( pos ); - } - } - } - else - { - SpreadStack.push_back( a_BlockPos ); - } - - - while( !SpreadStack.empty() ) - { - Vector3i pos = SpreadStack.back(); - SpreadStack.pop_back(); - - for( unsigned int i = 0; i < ARRAYCOUNT( Surroundings ); ++i ) - { - Vector3i OtherPos = pos + Surroundings[i]; - int RetVal = UnPowerBlock( OtherPos, pos ); - if( RetVal == 1 ) - { - SpreadStack.push_back( OtherPos ); // Changed, so add to stack - } - else if( RetVal == 2 ) - { - FoundSources.push_back( OtherPos ); - } - } - } - - return FoundSources; -} - - - - - -bool cRedstoneSimulator::IsPowering( const Vector3i & a_PowerPos, const Vector3i & a_BlockPos, eRedstoneDirection a_WireDirection, bool a_bOnlyByWire ) -{ - BLOCKTYPE PowerBlock = m_World->GetBlock( a_PowerPos ); - if (!a_bOnlyByWire && (PowerBlock == E_BLOCK_REDSTONE_TORCH_ON)) return true; - if (PowerBlock == E_BLOCK_REDSTONE_REPEATER_ON ) // A repeater pointing towards block is regarded as wire - { - if (IsRepeaterPointingTo( a_PowerPos, m_World->GetBlockMeta( a_PowerPos ), a_BlockPos ) ) - { - return true; - } - } - if (PowerBlock == E_BLOCK_REDSTONE_WIRE) - { - if (m_World->GetBlockMeta(a_PowerPos) > 0) - { - if (GetDirection(a_PowerPos) == a_WireDirection) - { - return true; - } - } - } - - return false; -} - - - - - -bool cRedstoneSimulator::IsPowered( const Vector3i & a_BlockPos, bool a_bOnlyByWire /* = false */ ) -{ - BLOCKTYPE Block = m_World->GetBlock( a_BlockPos ); - if ((Block == E_BLOCK_REDSTONE_REPEATER_OFF) || (Block == E_BLOCK_REDSTONE_REPEATER_ON)) - { - Vector3i Behind = a_BlockPos - GetRepeaterDirection( m_World->GetBlockMeta( a_BlockPos ) ); - BLOCKTYPE BehindBlock = m_World->GetBlock( Behind ); - if (BehindBlock == E_BLOCK_REDSTONE_TORCH_ON) - { - return true; - } - if (BehindBlock == E_BLOCK_REDSTONE_WIRE) - { - if( m_World->GetBlockMeta( Behind ) > 0 ) - { - return true; - } - } - if (BehindBlock == E_BLOCK_REDSTONE_REPEATER_ON) - { - if (IsRepeaterPointingTo( Behind, m_World->GetBlockMeta( Behind ), a_BlockPos)) - { - return true; - } - } - return false; - } - - if( IsPowering( Vector3i( a_BlockPos.x-1, a_BlockPos.y, a_BlockPos.z ), a_BlockPos, REDSTONE_X_POS, a_bOnlyByWire ) ) - return true; - if( IsPowering( Vector3i( a_BlockPos.x+1, a_BlockPos.y, a_BlockPos.z ), a_BlockPos, REDSTONE_X_NEG, a_bOnlyByWire ) ) - return true; - if( IsPowering( Vector3i( a_BlockPos.x, a_BlockPos.y, a_BlockPos.z-1 ), a_BlockPos, REDSTONE_Z_POS, a_bOnlyByWire ) ) - return true; - if( IsPowering( Vector3i( a_BlockPos.x, a_BlockPos.y, a_BlockPos.z+1 ), a_BlockPos, REDSTONE_Z_NEG, a_bOnlyByWire ) ) - return true; - - // Only wires can power the bottom block - char PosY = m_World->GetBlock( a_BlockPos.x, a_BlockPos.y+1, a_BlockPos.z ); - if( PosY == E_BLOCK_REDSTONE_WIRE ) - { - if( m_World->GetBlockMeta( a_BlockPos.x, a_BlockPos.y+1, a_BlockPos.z ) > 0 ) - { - return true; - } - } - - return false; -} - - - - -// Believe me, it works!! TODO: Add repeaters and low/high wires -cRedstoneSimulator::eRedstoneDirection cRedstoneSimulator::GetDirection( int a_X, int a_Y, int a_Z ) -{ - int Dir = REDSTONE_NONE; - - char NegX = m_World->GetBlock( a_X-1, a_Y, a_Z ); - if( NegX == E_BLOCK_REDSTONE_WIRE || NegX == E_BLOCK_REDSTONE_TORCH_ON ) - { - Dir |= (REDSTONE_X_POS); - } - char PosX = m_World->GetBlock( a_X+1, a_Y, a_Z ); - if( PosX == E_BLOCK_REDSTONE_WIRE || PosX == E_BLOCK_REDSTONE_TORCH_ON ) - { - Dir |= (REDSTONE_X_NEG); - } - char NegZ = m_World->GetBlock( a_X, a_Y, a_Z-1 ); - if( NegZ == E_BLOCK_REDSTONE_WIRE || NegZ == E_BLOCK_REDSTONE_TORCH_ON ) - { - if( (Dir & REDSTONE_X_POS) && !(Dir & REDSTONE_X_NEG ) ) //corner - { - Dir ^= REDSTONE_X_POS; - Dir |= REDSTONE_X_NEG; - } - if( (Dir & REDSTONE_X_NEG) && !(Dir & REDSTONE_X_POS ) ) //corner - { - Dir ^= REDSTONE_X_NEG; - Dir |= REDSTONE_X_POS; - } - Dir |= REDSTONE_Z_POS; - } - char PosZ = m_World->GetBlock( a_X, a_Y, a_Z+1 ); - if( PosZ == E_BLOCK_REDSTONE_WIRE || PosZ == E_BLOCK_REDSTONE_TORCH_ON ) - { - if( (Dir & REDSTONE_X_POS) && !(Dir & REDSTONE_X_NEG ) ) //corner - { - Dir ^= REDSTONE_X_POS; - Dir |= REDSTONE_X_NEG; - } - if( (Dir & REDSTONE_X_NEG) && !(Dir & REDSTONE_X_POS ) ) //corner - { - Dir ^= REDSTONE_X_NEG; - Dir |= REDSTONE_X_POS; - } - Dir |= REDSTONE_Z_NEG; - } - - return (eRedstoneDirection)Dir; -} - - - - - -bool cRedstoneSimulator::IsRepeaterPointingTo(const Vector3i & a_RepeaterPos, char a_MetaData, const Vector3i & a_BlockPos) -{ - switch (a_MetaData & 0x3) - { - case 0x0: - { - if( (a_RepeaterPos - a_BlockPos).Equals( Vector3i( 0, 0, 1 ) ) ) - { - return true; - } - break; - } - - case 0x1: - { - if( (a_RepeaterPos - a_BlockPos).Equals( Vector3i(-1, 0, 0 ) ) ) - { - return true; - } - break; - } - - case 0x2: - { - if( (a_RepeaterPos - a_BlockPos).Equals( Vector3i( 0, 0,-1 ) ) ) - { - return true; - } - break; - } - - case 0x3: - { - if( (a_RepeaterPos - a_BlockPos).Equals( Vector3i( 1, 0, 0 ) ) ) - { - return true; - } - break; - } - } - return false; -} - - - - - -bool cRedstoneSimulator::IsRepeaterPointingAway( const Vector3i & a_RepeaterPos, char a_MetaData, const Vector3i & a_BlockPos ) -{ - switch (a_MetaData & 0x3) - { - case 0x0: - { - if( (a_RepeaterPos - a_BlockPos).Equals( Vector3i( 0, 0,-1 ) ) ) - { - return true; - } - break; - } - - case 0x1: - { - if( (a_RepeaterPos - a_BlockPos).Equals( Vector3i( 1, 0, 0 ) ) ) - { - return true; - } - break; - } - - case 0x2: - { - if( (a_RepeaterPos - a_BlockPos).Equals( Vector3i( 0, 0, 1 ) ) ) - { - return true; - } - break; - } - - case 0x3: - { - if( (a_RepeaterPos - a_BlockPos).Equals( Vector3i(-1, 0, 0 ) ) ) - { - return true; - } - break; - } - } - return false; -} - - - - - -NIBBLETYPE cRedstoneSimulator::RepeaterRotationToMetaData(float a_Rotation) -{ - a_Rotation += 90 + 45; // So its not aligned with axis - if (a_Rotation > 360.f) - { - a_Rotation -= 360.f; - } - - if ((a_Rotation >= 0.f) && (a_Rotation < 90.f)) - { - return 0x1; - } - else if ((a_Rotation >= 180) && (a_Rotation < 270)) - { - return 0x3; - } - else if ((a_Rotation >= 90) && (a_Rotation < 180)) - { - return 0x2; - } - else - { - return 0x0; - } -} - - - - - -Vector3i cRedstoneSimulator::GetRepeaterDirection(NIBBLETYPE a_MetaData) -{ - switch (a_MetaData & 0x3) - { - case 0x0: return Vector3i( 0, 0,-1); - case 0x1: return Vector3i( 1, 0, 0); - case 0x2: return Vector3i( 0, 0, 1); - case 0x3: return Vector3i(-1, 0, 0); - } - return Vector3i(); -} - - - - - -void cRedstoneSimulator::SetRepeater( const Vector3i & a_Position, int a_Ticks, bool a_bPowerOn ) -{ - for( RepeaterList::iterator itr = m_SetRepeaters.begin(); itr != m_SetRepeaters.end(); ++itr ) - { - sRepeaterChange & Change = *itr; - if( Change.Position.Equals( a_Position ) ) - { - if( Change.bPowerOn && a_bPowerOn == false ) - { - Change.bPowerOffNextTime = true; - } - if( a_bPowerOn == true ) - { - Change.bPowerOffNextTime = false; - } - Change.bPowerOn |= a_bPowerOn; - return; - } - } - - sRepeaterChange RC; - RC.Position = a_Position; - RC.Ticks = a_Ticks; - RC.bPowerOn = a_bPowerOn; - RC.bPowerOffNextTime = false; - m_SetRepeaters.push_back( RC ); -} - - - - diff --git a/source/RedstoneSimulator.h b/source/RedstoneSimulator.h deleted file mode 100644 index c1996bb4e..000000000 --- a/source/RedstoneSimulator.h +++ /dev/null @@ -1,82 +0,0 @@ - -#pragma once - -#include "Simulator.h" -#include "Vector3i.h" - - - - - -class cRedstoneSimulator : - public cSimulator -{ - typedef cSimulator super; -public: - cRedstoneSimulator( cWorld* a_World ); - ~cRedstoneSimulator(); - - virtual void Simulate( float a_Dt ) override; - virtual bool IsAllowedBlock( BLOCKTYPE a_BlockType ) override { return true; } - - virtual void WakeUp( int a_X, int a_Y, int a_Z ) override; - - enum eRedstoneDirection - { - REDSTONE_NONE = 0, - REDSTONE_X_POS = 0x1, - REDSTONE_X_NEG = 0x2, - REDSTONE_Z_POS = 0x4, - REDSTONE_Z_NEG = 0x8, - }; - eRedstoneDirection GetDirection( int a_X, int a_Y, int a_Z ); - eRedstoneDirection GetDirection( const Vector3i & a_Pos ) { return GetDirection( a_Pos.x, a_Pos.y, a_Pos.z ); } - - static bool IsRepeaterPointingTo (const Vector3i & a_RepeaterPos, char a_MetaData, const Vector3i & a_BlockPos); - static bool IsRepeaterPointingAway(const Vector3i & a_RepeaterPos, char a_MetaData, const Vector3i & a_BlockPos); - static NIBBLETYPE RepeaterRotationToMetaData(float a_Rotation); - static Vector3i GetRepeaterDirection(NIBBLETYPE a_MetaData); - - -private: - struct sRepeaterChange - { - Vector3i Position; - int Ticks; - bool bPowerOn; - bool bPowerOffNextTime; - }; - - typedef std::deque BlockList; - - typedef std::deque< sRepeaterChange > RepeaterList; - RepeaterList m_SetRepeaters; - - void SetRepeater(const Vector3i & a_Position, int a_Ticks, bool a_bPowerOn); - - virtual void AddBlock(int a_X, int a_Y, int a_Z) {} - - void HandleChange( const Vector3i & a_BlockPos ); - BlockList RemoveCurrent( const Vector3i & a_BlockPos ); - - bool PowerBlock( const Vector3i & a_BlockPos, const Vector3i & a_FromBlock, char a_Power ); - int UnPowerBlock( const Vector3i & a_BlockPos, const Vector3i & a_FromBlock ); - - bool IsPowered( const Vector3i & a_BlockPos, bool a_bOnlyByWire = false ); - bool IsPowering( const Vector3i & a_PowerPos, const Vector3i & a_BlockPos, eRedstoneDirection a_WireDirection, bool a_bOnlyByWire ); - - BlockList m_Blocks; - BlockList m_BlocksBuffer; - - BlockList m_RefreshPistons; - - BlockList m_RefreshTorchesAround; - - void RefreshTorchesAround( const Vector3i & a_BlockPos ); - - cCriticalSection m_CS; -}; - - - - diff --git a/source/SandSimulator.cpp b/source/SandSimulator.cpp deleted file mode 100644 index a2e1dc4cb..000000000 --- a/source/SandSimulator.cpp +++ /dev/null @@ -1,102 +0,0 @@ - -#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules - -#include "SandSimulator.h" -#include "World.h" -#include "Vector3i.h" -#include "BlockID.h" -#include "Defines.h" -#include "FallingBlock.h" - - - - -cSandSimulator::cSandSimulator( cWorld* a_World ) - : cSimulator(a_World) - , m_Blocks(new BlockList) - , m_Buffer(new BlockList) -{ - -} - - - - - -cSandSimulator::~cSandSimulator() -{ - 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 ) - { - Vector3i Pos = *itr; - BLOCKTYPE BlockID = m_World->GetBlock(Pos.x, Pos.y, Pos.z); - if(!IsAllowedBlock(BlockID)) - continue; - - BLOCKTYPE BottomBlock = m_World->GetBlock( Pos.x, Pos.y - 1, Pos.z ); - - if( IsPassable(BottomBlock) ) - { - cFallingBlock * FallingBlock = new cFallingBlock( Pos, BlockID ); - FallingBlock->Initialize( m_World ); - m_World->SetBlock( Pos.x, Pos.y, Pos.z, E_BLOCK_AIR, 0 ); - } - } - -} - - - - - -bool cSandSimulator::IsAllowedBlock( BLOCKTYPE a_BlockType ) -{ - return a_BlockType == E_BLOCK_SAND - || a_BlockType == E_BLOCK_GRAVEL; -} - - - - - -void cSandSimulator::AddBlock(int a_X, int a_Y, int a_Z) -{ - if(!IsAllowedBlock(m_World->GetBlock(a_X, a_Y, a_Z))) - return; - - Vector3i Block(a_X, a_Y, a_Z); - - //check for duplicates - for( BlockList::iterator itr = m_Blocks->begin(); itr != m_Blocks->end(); ++itr ) - { - Vector3i Pos = *itr; - if( Pos.x == a_X && Pos.y == a_Y && Pos.z == a_Z ) - return; - } - - m_Blocks->push_back(Block); -} - - - - - -bool cSandSimulator::IsPassable( BLOCKTYPE a_BlockType ) -{ - return a_BlockType == E_BLOCK_AIR - || IsBlockWater(a_BlockType) - || IsBlockLava(a_BlockType) - || a_BlockType == E_BLOCK_FIRE; -} diff --git a/source/SandSimulator.h b/source/SandSimulator.h deleted file mode 100644 index ff39d62b2..000000000 --- a/source/SandSimulator.h +++ /dev/null @@ -1,39 +0,0 @@ - -#pragma once - -#include "Simulator.h" -#include "BlockEntity.h" -#include "Vector3i.h" - - - - - -class cWorld; - - - - - -class cSandSimulator : public cSimulator -{ -public: - cSandSimulator( cWorld* a_World ); - ~cSandSimulator(); - - virtual void Simulate( float a_Dt ) override; - - virtual bool IsAllowedBlock( BLOCKTYPE a_BlockType ) override; - virtual bool IsPassable( BLOCKTYPE a_BlockType ); - -protected: - virtual void AddBlock(int a_X, int a_Y, int a_Z) override; - - typedef std::list BlockList; - BlockList * m_Blocks; - BlockList * m_Buffer; -}; - - - - diff --git a/source/Simulator.cpp b/source/Simulator.cpp deleted file mode 100644 index e4608e150..000000000 --- a/source/Simulator.cpp +++ /dev/null @@ -1,33 +0,0 @@ - -#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules - -#include "Simulator.h" -#include "World.h" -#include "Vector3i.h" -#include "BlockID.h" -#include "Defines.h" - - - - - -cSimulator::cSimulator( cWorld* a_World ) - : m_World(a_World) -{ - -} - -cSimulator::~cSimulator() -{ -} - -void cSimulator::WakeUp( int a_X, int a_Y, int a_Z ) -{ - AddBlock( a_X, a_Y, a_Z ); - AddBlock( a_X-1, a_Y, a_Z ); - AddBlock( a_X+1, a_Y, a_Z ); - AddBlock( a_X, a_Y-1, a_Z ); - AddBlock( a_X, a_Y+1, a_Z ); - AddBlock( a_X, a_Y, a_Z-1 ); - AddBlock( a_X, a_Y, a_Z+1 ); -} diff --git a/source/Simulator.h b/source/Simulator.h deleted file mode 100644 index 00e1b5a0c..000000000 --- a/source/Simulator.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -class Vector3i; -class cWorld; -class cSimulator -{ -public: - cSimulator( cWorld* a_World ); - ~cSimulator(); - - virtual void Simulate( float a_Dt ) = 0; - virtual void WakeUp( int a_X, int a_Y, int a_Z ); - - virtual bool IsAllowedBlock( BLOCKTYPE a_BlockType ) = 0; - -protected: - virtual void AddBlock(int a_X, int a_Y, int a_Z) = 0; - - cWorld * m_World; -}; \ No newline at end of file diff --git a/source/Simulator/ClassicFluidSimulator.h b/source/Simulator/ClassicFluidSimulator.h new file mode 100644 index 000000000..ebccda487 --- /dev/null +++ b/source/Simulator/ClassicFluidSimulator.h @@ -0,0 +1,58 @@ + +// ClassicFluidSimulator.h + +// Interfaces to the cClassicFluidSimulator class representing the original MCServer's fluid simulator + + + + + +#pragma once + +#include "FluidSimulator.h" + + + + + +class cClassicFluidSimulator : + public cFluidSimulator +{ +public: + cClassicFluidSimulator(cWorld * a_World, BLOCKTYPE a_Fluid, BLOCKTYPE a_StationaryFluid, NIBBLETYPE a_MaxHeight, NIBBLETYPE a_Falloff); + ~cClassicFluidSimulator(); + + // cSimulator overrides: + virtual void Simulate(float a_Dt) override; + virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ) override; + virtual bool IsAllowedBlock(BLOCKTYPE a_BlockType) override; + + // cFluidSimulator overrides: + virtual Direction GetFlowingDirection(int a_X, int a_Y, int a_Z, bool a_Over = true) override; + + bool CanWashAway (BLOCKTYPE a_BlockType); + bool IsSolidBlock(BLOCKTYPE a_BlockType); + bool IsPassableForFluid(BLOCKTYPE a_BlockType); + +protected: + NIBBLETYPE GetHighestLevelAround(int a_BlockX, int a_BlockY, int a_BlockZ); + + /// Applies special rules such as generation of water between sources, returns false if it is necessary to apply general rules + bool UniqueSituation(Vector3i a_Pos); + + void ApplyUniqueToNearest(Vector3i a_Pos); + + float m_Timer; + + // fwd: ClassicFluidSimulator.cpp + class FluidData; + + FluidData * m_Data; + + NIBBLETYPE m_MaxHeight; + NIBBLETYPE m_Falloff; +} ; + + + + diff --git a/source/Simulator/FireSimulator.cpp b/source/Simulator/FireSimulator.cpp new file mode 100644 index 000000000..c2f22668b --- /dev/null +++ b/source/Simulator/FireSimulator.cpp @@ -0,0 +1,178 @@ + +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "FireSimulator.h" +#include "../World.h" +#include "../BlockID.h" +#include "../Defines.h" + + + + + +cFireSimulator::cFireSimulator( cWorld* a_World ) + : cSimulator(a_World) + , m_Blocks(new BlockList) + , m_Buffer(new BlockList) + , m_BurningBlocks(new BlockList) +{ +} + + + + + +cFireSimulator::~cFireSimulator() +{ + delete m_Buffer; + delete m_Blocks; + delete m_BurningBlocks; +} + + + + + +void cFireSimulator::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 ) + { + Vector3i Pos = *itr; + + char BlockID = m_World->GetBlock(Pos.x, Pos.y, Pos.z); + + if(!IsAllowedBlock(BlockID)) //Check wheather the block is still burning + continue; + + if(BurnBlockAround(Pos.x, Pos.y, Pos.z)) //Burn single block and if there was one -> next time again + _AddBlock(Pos.x, Pos.y, Pos.z); + else + if(!IsForeverBurnable(m_World->GetBlock(Pos.x, Pos.y - 1, Pos.z)) && !FiresForever(BlockID)) + m_World->SetBlock(Pos.x, Pos.y, Pos.z, E_BLOCK_AIR, 0); + + } + +} + + + + + +bool cFireSimulator::IsAllowedBlock( BLOCKTYPE a_BlockType ) +{ + return a_BlockType == E_BLOCK_FIRE + || IsBlockLava(a_BlockType); +} + + + + + +void cFireSimulator::AddBlock(int a_X, int a_Y, int a_Z) +{ + char BlockID = m_World->GetBlock(a_X, a_Y, a_Z); + if(!IsAllowedBlock(BlockID)) //This should save very much time because it doesn´t have to iterate through all blocks + return; + + //check for duplicates + for( BlockList::iterator itr = m_Blocks->begin(); itr != m_Blocks->end(); ++itr ) + { + Vector3i Pos = *itr; + if( Pos.x == a_X && Pos.y == a_Y && Pos.z == a_Z ) + return; + } + + _AddBlock(a_X, a_Y, a_Z); + +} + + + + + +void cFireSimulator::_AddBlock(int a_X, int a_Y, int a_Z) +{ + m_Blocks->push_back( Vector3i(a_X, a_Y, a_Z) ); + +} + + + + + +bool cFireSimulator::IsForeverBurnable( BLOCKTYPE a_BlockType ) +{ + return a_BlockType == E_BLOCK_BLOODSTONE; +} + + + + + +bool cFireSimulator::IsBurnable( BLOCKTYPE a_BlockType ) +{ + return a_BlockType == E_BLOCK_PLANKS + || a_BlockType == E_BLOCK_LEAVES + || a_BlockType == E_BLOCK_LOG + || a_BlockType == E_BLOCK_WOOL + || a_BlockType == E_BLOCK_BOOKCASE + || a_BlockType == E_BLOCK_FENCE + || a_BlockType == E_BLOCK_TNT + || a_BlockType == E_BLOCK_VINES; +} + + + + + +bool cFireSimulator::FiresForever( BLOCKTYPE a_BlockType ) +{ + return a_BlockType != E_BLOCK_FIRE; +} + + + + + +bool cFireSimulator::BurnBlockAround(int a_X, int a_Y, int a_Z) +{ + return BurnBlock(a_X + 1, a_Y, a_Z) + || BurnBlock(a_X - 1, a_Y, a_Z) + || BurnBlock(a_X, a_Y + 1, a_Z) + || BurnBlock(a_X, a_Y - 1, a_Z) + || BurnBlock(a_X, a_Y, a_Z + 1) + || BurnBlock(a_X, a_Y, a_Z - 1); +} + + + + + +bool cFireSimulator::BurnBlock(int a_X, int a_Y, int a_Z) +{ + char BlockID = m_World->GetBlock(a_X, a_Y, a_Z); + if(IsBurnable(BlockID)) + { + m_World->SetBlock(a_X, a_Y, a_Z, E_BLOCK_FIRE, 0); + return true; + } + if(IsForeverBurnable(BlockID)) + { + char BlockAbove = m_World->GetBlock(a_X, a_Y + 1, a_Z); + if(BlockAbove == E_BLOCK_AIR) + { + m_World->SetBlock(a_X, a_Y + 1, a_Z, E_BLOCK_FIRE, 0); //Doesn´t notify the simulator so it won´t go off + return true; + } + return false; + } + + return false; +} + + + + diff --git a/source/Simulator/FireSimulator.h b/source/Simulator/FireSimulator.h new file mode 100644 index 000000000..753259c2c --- /dev/null +++ b/source/Simulator/FireSimulator.h @@ -0,0 +1,40 @@ + +#pragma once + +#include "Simulator.h" +#include "../BlockEntity.h" + + + + + +class cFireSimulator : public cSimulator +{ +public: + cFireSimulator( cWorld* a_World ); + ~cFireSimulator(); + + virtual void Simulate( float a_Dt ) override; + + virtual bool IsAllowedBlock( BLOCKTYPE a_BlockType ) override; + + virtual bool IsBurnable( BLOCKTYPE a_BlockType ); + virtual bool IsForeverBurnable( BLOCKTYPE a_BlockType ); + virtual bool FiresForever( BLOCKTYPE a_BlockType ); + +protected: + virtual void AddBlock(int a_X, int a_Y, int a_Z) override; + virtual void _AddBlock(int a_X, int a_Y, int a_Z); // _X 2012_10_13: WTF? what kind of naming is this? Use proper names! + virtual bool BurnBlockAround(int a_X, int a_Y, int a_Z); + virtual bool BurnBlock(int a_X, int a_Y, int a_Z); + + typedef std::list BlockList; + BlockList *m_Blocks; + BlockList *m_Buffer; + + BlockList *m_BurningBlocks; +}; + + + + diff --git a/source/Simulator/FluidSimulator.cpp b/source/Simulator/FluidSimulator.cpp new file mode 100644 index 000000000..d352d5d4d --- /dev/null +++ b/source/Simulator/FluidSimulator.cpp @@ -0,0 +1,19 @@ + +#include "Globals.h" + +#include "FluidSimulator.h" + + + + + +cFluidSimulator::cFluidSimulator(cWorld * a_World, BLOCKTYPE a_Fluid, BLOCKTYPE a_StationaryFluid) : + super(a_World), + m_FluidBlock(a_Fluid), + m_StationaryFluidBlock(a_StationaryFluid) +{ +} + + + + diff --git a/source/Simulator/FluidSimulator.h b/source/Simulator/FluidSimulator.h new file mode 100644 index 000000000..f0b2b23ba --- /dev/null +++ b/source/Simulator/FluidSimulator.h @@ -0,0 +1,47 @@ + +#pragma once + +#include "Simulator.h" + + + + + +enum Direction +{ + X_PLUS, + X_MINUS, + Y_PLUS, + Y_MINUS, + Z_PLUS, + Z_MINUS, + NONE +}; + + + + + +class cFluidSimulator : + public cSimulator +{ + typedef cSimulator super; + +public: + cFluidSimulator(cWorld * a_World, BLOCKTYPE a_Fluid, BLOCKTYPE a_StationaryFluid); + + // Gets the flowing direction. If a_Over is true also the block over the current block affects the direction (standard) + virtual Direction GetFlowingDirection(int a_X, int a_Y, int a_Z, bool a_Over = true) = 0; + + bool IsFluidBlock (BLOCKTYPE a_BlockType) const { return (a_BlockType == m_FluidBlock); } + bool IsStationaryFluidBlock(BLOCKTYPE a_BlockType) const { return (a_BlockType == m_StationaryFluidBlock); } + +protected: + BLOCKTYPE m_FluidBlock; // The fluid block type that needs simulating + BLOCKTYPE m_StationaryFluidBlock; // The fluid block type that indicates no simulation is needed +} ; + + + + + diff --git a/source/Simulator/LavaSimulator.cpp b/source/Simulator/LavaSimulator.cpp new file mode 100644 index 000000000..726cc37e4 --- /dev/null +++ b/source/Simulator/LavaSimulator.cpp @@ -0,0 +1,20 @@ +#include "Globals.h" +#include "LavaSimulator.h" +#include "Defines.h" +#include "World.h" + + +cLavaSimulator::cLavaSimulator(cWorld *a_World) + : cFluidSimulator(a_World) +{ + m_FluidBlock = E_BLOCK_LAVA; + m_StationaryFluidBlock = E_BLOCK_STATIONARY_LAVA; + m_MaxHeight = 6; + m_FlowReduction = 2; +} + + +bool cLavaSimulator::IsAllowedBlock(BLOCKTYPE a_BlockType) +{ + return IsBlockLava(a_BlockType); +} \ No newline at end of file diff --git a/source/Simulator/LavaSimulator.h b/source/Simulator/LavaSimulator.h new file mode 100644 index 000000000..d85b335b7 --- /dev/null +++ b/source/Simulator/LavaSimulator.h @@ -0,0 +1,12 @@ +#pragma once +#include "FluidSimulator.h" + +class cLavaSimulator : public cFluidSimulator +{ +public: + cLavaSimulator( cWorld* a_World ); + + virtual bool IsAllowedBlock( BLOCKTYPE a_BlockType ) override; + + +}; \ No newline at end of file diff --git a/source/Simulator/RedstoneSimulator.cpp b/source/Simulator/RedstoneSimulator.cpp new file mode 100644 index 000000000..1c30be324 --- /dev/null +++ b/source/Simulator/RedstoneSimulator.cpp @@ -0,0 +1,886 @@ + +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "RedstoneSimulator.h" +#include "../Piston.h" +#include "../World.h" +#include "../BlockID.h" +#include "../Torch.h" + + + + + +cRedstoneSimulator::cRedstoneSimulator( cWorld* a_World ) + : super(a_World) +{ +} + + + + + +cRedstoneSimulator::~cRedstoneSimulator() +{ +} + + + + + +void cRedstoneSimulator::WakeUp( int a_X, int a_Y, int a_Z ) +{ + cCSLock Lock( m_CS ); + m_Blocks.push_back( Vector3i( a_X, a_Y, a_Z ) ); +} + + + + + +void cRedstoneSimulator::Simulate( float a_Dt ) +{ + // Toggle torches on/off + while( !m_RefreshTorchesAround.empty() ) + { + Vector3i pos = m_RefreshTorchesAround.front(); + m_RefreshTorchesAround.pop_front(); + + RefreshTorchesAround( pos ); + } + + // Set repeaters to correct values, and decrement ticks + for( RepeaterList::iterator itr = m_SetRepeaters.begin(); itr != m_SetRepeaters.end(); ) + { + (*itr).Ticks--; + if( (*itr).Ticks <= 0 ) + { + char Block = m_World->GetBlock( (*itr).Position ); + if( (*itr).bPowerOn == true && Block == E_BLOCK_REDSTONE_REPEATER_OFF ) + { + m_World->FastSetBlock( (*itr).Position.x, (*itr).Position.y, (*itr).Position.z, E_BLOCK_REDSTONE_REPEATER_ON, m_World->GetBlockMeta( (*itr).Position ) ); + m_Blocks.push_back( (*itr).Position ); + } + else if( (*itr).bPowerOn == false && Block == E_BLOCK_REDSTONE_REPEATER_ON ) + { + m_World->FastSetBlock( (*itr).Position.x, (*itr).Position.y, (*itr).Position.z, E_BLOCK_REDSTONE_REPEATER_OFF, m_World->GetBlockMeta( (*itr).Position ) ); + m_Blocks.push_back( (*itr).Position ); + } + + if( (*itr).bPowerOffNextTime ) + { + (*itr).bPowerOn = false; + (*itr).bPowerOffNextTime = false; + (*itr).Ticks = 10; // TODO: Look up actual ticks from block metadata + ++itr; + } + else + { + itr = m_SetRepeaters.erase( itr ); + } + } + else + { + ++itr; + } + } + + // Handle changed blocks + { + cCSLock Lock( m_CS ); + std::swap( m_Blocks, m_BlocksBuffer ); + } + for( BlockList::iterator itr = m_BlocksBuffer.begin(); itr != m_BlocksBuffer.end(); ++itr ) + { + HandleChange( *itr ); + } + m_BlocksBuffer.clear(); +} + + + + + +void cRedstoneSimulator::RefreshTorchesAround( const Vector3i & a_BlockPos ) +{ + static Vector3i Surroundings [] = { + Vector3i(-1, 0, 0), + Vector3i( 1, 0, 0), + Vector3i( 0, 0,-1), + Vector3i( 0, 0, 1), + Vector3i( 0, 1, 0), // Also toggle torch on top + }; + char TargetBlockID = E_BLOCK_REDSTONE_TORCH_ON; + char TargetRepeaterID = E_BLOCK_REDSTONE_REPEATER_OFF; + if( IsPowered( a_BlockPos, true ) ) + { + TargetBlockID = E_BLOCK_REDSTONE_TORCH_OFF; + TargetRepeaterID = E_BLOCK_REDSTONE_REPEATER_ON; + //if( m_World->GetBlock( a_BlockPos ) == E_BLOCK_DIRT ) + //{ + // m_World->FastSetBlock( a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, E_BLOCK_STONE, 0 ); + //} + } + else + { + //if( m_World->GetBlock( a_BlockPos ) == E_BLOCK_STONE ) + //{ + // m_World->FastSetBlock( a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, E_BLOCK_DIRT, 0 ); + //} + } + + for( unsigned int i = 0; i < ARRAYCOUNT( Surroundings ); ++i ) + { + Vector3i TorchPos = a_BlockPos + Surroundings[i]; + const char Block = m_World->GetBlock( TorchPos ); + switch( Block ) + { + case E_BLOCK_REDSTONE_TORCH_ON: + case E_BLOCK_REDSTONE_TORCH_OFF: + if( Block != TargetBlockID ) + { + char TorchMeta = m_World->GetBlockMeta( TorchPos ); + if( cTorch::IsAttachedTo( TorchPos, TorchMeta, a_BlockPos ) ) + { + m_World->FastSetBlock( TorchPos.x, TorchPos.y, TorchPos.z, TargetBlockID, m_World->GetBlockMeta( TorchPos ) ); + m_Blocks.push_back( TorchPos ); + } + } + break; + case E_BLOCK_REDSTONE_REPEATER_ON: + case E_BLOCK_REDSTONE_REPEATER_OFF: + if ((Block != TargetRepeaterID) && IsRepeaterPointingAway( TorchPos, m_World->GetBlockMeta( TorchPos ), a_BlockPos ) ) + { + SetRepeater( TorchPos, 10, TargetRepeaterID == E_BLOCK_REDSTONE_REPEATER_ON ); + } + break; + default: + break; + }; + } +} + + + + + +void cRedstoneSimulator::HandleChange( const Vector3i & a_BlockPos ) +{ + std::deque< Vector3i > SpreadStack; + + Vector3i Surroundings[] = { + Vector3i( 1, 0, 0 ), + Vector3i( 1, 1, 0 ), + Vector3i( 1,-1, 0 ), + Vector3i(-1, 0, 0 ), + Vector3i(-1, 1, 0 ), + Vector3i(-1,-1, 0 ), + Vector3i( 0, 0, 1 ), + Vector3i( 0, 1, 1 ), + Vector3i( 0,-1, 1 ), + Vector3i( 0, 0,-1 ), + Vector3i( 0, 1,-1 ), + Vector3i( 0,-1,-1 ), + Vector3i( 0,-1, 0 ), + }; + + char Block = m_World->GetBlock( a_BlockPos ); + + // First check whether torch should be on or off + if( Block == E_BLOCK_REDSTONE_TORCH_ON || Block == E_BLOCK_REDSTONE_TORCH_OFF ) + { + static Vector3i Surroundings [] = { + Vector3i(-1, 0, 0), + Vector3i( 1, 0, 0), + Vector3i( 0, 0,-1), + Vector3i( 0, 0, 1), + Vector3i( 0,-1, 0), + }; + for( unsigned int i = 0; i < ARRAYCOUNT( Surroundings ); ++i ) + { + Vector3i pos = a_BlockPos + Surroundings[i]; + char OtherBlock = m_World->GetBlock( pos ); + if( (OtherBlock != E_BLOCK_AIR) && (OtherBlock != E_BLOCK_REDSTONE_TORCH_ON) && (OtherBlock != E_BLOCK_REDSTONE_TORCH_OFF) ) + { + RefreshTorchesAround( pos ); + } + } + Block = m_World->GetBlock( a_BlockPos ); // Make sure we got the updated block + } + else if( Block == E_BLOCK_REDSTONE_REPEATER_ON || Block == E_BLOCK_REDSTONE_REPEATER_OFF ) // Check if repeater is powered by a 'powered block' (not wires/torch) + { + Vector3i Direction = GetRepeaterDirection( m_World->GetBlockMeta( a_BlockPos ) ); + Vector3i pos = a_BlockPos - Direction; // NOTE: It's minus Direction + char OtherBlock = m_World->GetBlock( pos ); + if( (OtherBlock != E_BLOCK_AIR) && (OtherBlock != E_BLOCK_REDSTONE_TORCH_ON) && (OtherBlock != E_BLOCK_REDSTONE_TORCH_OFF) && (OtherBlock != E_BLOCK_REDSTONE_WIRE) ) + { + RefreshTorchesAround( pos ); + } + else + { + SetRepeater( a_BlockPos, 10, IsPowered( a_BlockPos, false ) ); + } + Block = m_World->GetBlock( a_BlockPos ); + } + + BlockList Sources; + // If torch is still on, use it as a source + if( Block == E_BLOCK_REDSTONE_TORCH_ON ) + { + Sources.push_back( a_BlockPos ); + } + else if( Block == E_BLOCK_REDSTONE_REPEATER_ON ) + { + static Vector3i Surroundings [] = { // It only spreads right in front, and one block up + Vector3i( 0, 0, 0), + Vector3i( 0, 1, 0), + }; + Vector3i Direction = GetRepeaterDirection( m_World->GetBlockMeta( a_BlockPos ) ); + for( unsigned int i = 0; i < ARRAYCOUNT( Surroundings ); ++i ) + { + Vector3i pos = a_BlockPos + Direction + Surroundings[i]; + if( PowerBlock( pos, a_BlockPos, 0xf ) ) + { + SpreadStack.push_back( pos ); + } + } + } + + // Power all blocks legally connected to the sources + if( Block != E_BLOCK_REDSTONE_REPEATER_ON ) + { + BlockList NewSources = RemoveCurrent( a_BlockPos ); + Sources.insert( Sources.end(), NewSources.begin(), NewSources.end() ); + while( !Sources.empty() ) + { + Vector3i SourcePos = Sources.back(); + Sources.pop_back(); + + char Block = m_World->GetBlock( SourcePos ); + switch( Block ) + { + case E_BLOCK_REDSTONE_TORCH_OFF: + case E_BLOCK_REDSTONE_TORCH_ON: + { + static Vector3i Surroundings [] = { + Vector3i(-1, 0, 0), + Vector3i( 1, 0, 0), + Vector3i( 0, 0,-1), + Vector3i( 0, 0, 1), + }; + for( unsigned int i = 0; i < ARRAYCOUNT( Surroundings ); ++i ) + { + Vector3i OtherPos = SourcePos + Surroundings[i]; + if( PowerBlock( OtherPos, a_BlockPos, 0xf ) ) + { + SpreadStack.push_back( OtherPos ); // Changed, so add to stack + } + } + } + break; + case E_BLOCK_REDSTONE_REPEATER_OFF: + case E_BLOCK_REDSTONE_REPEATER_ON: + { + static Vector3i Surroundings [] = { + Vector3i( 0, 0, 0), + Vector3i( 0, 1, 0), + }; + Vector3i Direction = GetRepeaterDirection( m_World->GetBlockMeta( SourcePos ) ); + for( unsigned int i = 0; i < ARRAYCOUNT( Surroundings ); ++i ) + { + Vector3i pos = SourcePos + Direction + Surroundings[i]; + if( PowerBlock( pos, a_BlockPos, 0xf ) ) + { + SpreadStack.push_back( pos ); + } + } + } + break; + }; + + + } + } + + + // Do a floodfill + while( !SpreadStack.empty() ) + { + Vector3i pos = SpreadStack.back(); + SpreadStack.pop_back(); + + char Meta = m_World->GetBlockMeta( pos ); + + for( unsigned int i = 0; i < ARRAYCOUNT( Surroundings ); ++i ) + { + Vector3i OtherPos = pos + Surroundings[i]; + if( PowerBlock( OtherPos, pos, Meta-1 ) ) + { + SpreadStack.push_back( OtherPos ); // Changed, so add to stack + } + } + } + + // Only after a redstone area has been completely simulated the redstone entities can react + while( !m_RefreshPistons.empty() ) + { + Vector3i pos = m_RefreshPistons.back(); + m_RefreshPistons.pop_back(); + + char Block = m_World->GetBlock( pos ); + switch( Block ) + { + case E_BLOCK_PISTON: + case E_BLOCK_STICKY_PISTON: + if( IsPowered( pos ) ) + { + cPiston Piston( m_World ); + Piston.ExtendPiston( pos.x, pos.y, pos.z ); + } + else + { + cPiston Piston( m_World ); + Piston.RetractPiston( pos.x, pos.y, pos.z ); + } + break; + default: + break; + }; + } +} + + + + + +bool cRedstoneSimulator::PowerBlock( const Vector3i & a_BlockPos, const Vector3i & a_FromBlock, char a_Power ) +{ + char Block = m_World->GetBlock( a_BlockPos ); + switch( Block ) + { + case E_BLOCK_REDSTONE_WIRE: + { + if( m_World->GetBlockMeta( a_BlockPos ) < a_Power ) + { + m_World->SetBlockMeta( a_BlockPos, a_Power ); + return true; + } + } + break; + case E_BLOCK_PISTON: + case E_BLOCK_STICKY_PISTON: + { + m_RefreshPistons.push_back( a_BlockPos ); + } + break; + case E_BLOCK_REDSTONE_REPEATER_OFF: + case E_BLOCK_REDSTONE_REPEATER_ON: + { + if (IsRepeaterPointingAway( a_BlockPos, m_World->GetBlockMeta( a_BlockPos ), a_FromBlock )) + { + SetRepeater( a_BlockPos, 10, true ); + } + } + break; + default: + { + if( Block != E_BLOCK_AIR && Block != E_BLOCK_REDSTONE_TORCH_ON && Block != E_BLOCK_REDSTONE_TORCH_OFF ) + { + if( IsPowered( a_BlockPos, true ) ) + { + m_RefreshTorchesAround.push_back( a_BlockPos ); + } + } + } + break; + }; + + return false; +} + + + + + +int cRedstoneSimulator::UnPowerBlock( const Vector3i & a_BlockPos, const Vector3i & a_FromBlock) +{ + BLOCKTYPE BlockType = m_World->GetBlock(a_BlockPos); + switch (BlockType) + { + case E_BLOCK_REDSTONE_WIRE: + { + if( m_World->GetBlockMeta( a_BlockPos ) > 0 ) + { + m_World->SetBlockMeta( a_BlockPos, 0 ); + return 1; + } + break; + } + + case E_BLOCK_PISTON: + case E_BLOCK_STICKY_PISTON: + { + m_RefreshPistons.push_back( a_BlockPos ); + break; + } + + case E_BLOCK_REDSTONE_TORCH_ON: + { + return 2; + break; + } + + case E_BLOCK_REDSTONE_REPEATER_ON: + { + if ( + IsRepeaterPointingTo(a_BlockPos, m_World->GetBlockMeta(a_BlockPos), a_FromBlock ) || // Repeater is next to wire + IsRepeaterPointingTo(a_BlockPos, m_World->GetBlockMeta(a_BlockPos), a_FromBlock - Vector3i(0, 1, 0)) // Repeater is below wire + ) + { + return 2; + } + else if (IsRepeaterPointingAway( a_BlockPos, m_World->GetBlockMeta( a_BlockPos ), a_FromBlock ) ) + { + SetRepeater( a_BlockPos, 10, false ); + } + // fall-through: + } + + case E_BLOCK_REDSTONE_REPEATER_OFF: + { + if (IsRepeaterPointingAway( a_BlockPos, m_World->GetBlockMeta( a_BlockPos ), a_FromBlock )) + { + SetRepeater( a_BlockPos, 10, false ); + } + break; + } + + default: + { + if ((BlockType != E_BLOCK_AIR) && (BlockType != E_BLOCK_REDSTONE_TORCH_ON) && (BlockType != E_BLOCK_REDSTONE_TORCH_OFF)) + { + if (!IsPowered(a_BlockPos, true)) + { + m_RefreshTorchesAround.push_back( a_BlockPos ); + } + } + break; + } + } // switch (BlockType) + + return 0; +} + + + + + +// Removes current from all powered redstone wires until it reaches an energy source. +// Also returns all energy sources it encountered +cRedstoneSimulator::BlockList cRedstoneSimulator::RemoveCurrent( const Vector3i & a_BlockPos ) +{ + + + std::deque< Vector3i > SpreadStack; + std::deque< Vector3i > FoundSources; + + Vector3i Surroundings[] = { + Vector3i( 1, 0, 0 ), + Vector3i( 1, 1, 0 ), + Vector3i( 1,-1, 0 ), + Vector3i(-1, 0, 0 ), + Vector3i(-1, 1, 0 ), + Vector3i(-1,-1, 0 ), + Vector3i( 0, 0, 1 ), + Vector3i( 0, 1, 1 ), + Vector3i( 0,-1, 1 ), + Vector3i( 0, 0,-1 ), + Vector3i( 0, 1,-1 ), + Vector3i( 0,-1,-1 ), + Vector3i( 0,-1, 0 ), + }; + + char Block = m_World->GetBlock( a_BlockPos ); + if( Block == E_BLOCK_REDSTONE_REPEATER_ON || Block == E_BLOCK_REDSTONE_REPEATER_OFF ) + { + static Vector3i Surroundings [] = { // Repeaters only spread right in front and 1 block up + Vector3i( 0, 0, 0), + Vector3i( 0, 1, 0), + }; + Vector3i Direction = GetRepeaterDirection( m_World->GetBlockMeta( a_BlockPos ) ); + for( unsigned int i = 0; i < ARRAYCOUNT( Surroundings ); ++i ) + { + Vector3i pos = a_BlockPos + Direction + Surroundings[i]; + int RetVal = UnPowerBlock( pos, a_BlockPos ); + if( RetVal == 1 ) + { + SpreadStack.push_back( pos ); // Changed, so add to stack + } + else if( RetVal == 2 ) + { + FoundSources.push_back( pos ); + } + } + } + else if( Block == E_BLOCK_REDSTONE_TORCH_OFF || Block == E_BLOCK_REDSTONE_TORCH_ON ) + { + static Vector3i Surroundings [] = { // Torches only spread on the same level + Vector3i(-1, 0, 0), + Vector3i( 1, 0, 0), + Vector3i( 0, 0,-1), + Vector3i( 0, 0, 1), + }; + + for( unsigned int i = 0; i < ARRAYCOUNT( Surroundings ); ++i ) + { + Vector3i pos = Vector3i( a_BlockPos ) + Surroundings[i]; + int RetVal = UnPowerBlock( pos, a_BlockPos ); + if( RetVal == 1 ) + { + SpreadStack.push_back( pos ); // Changed, so add to stack + } + else if( RetVal == 2 ) + { + FoundSources.push_back( pos ); + } + } + } + else + { + SpreadStack.push_back( a_BlockPos ); + } + + + while( !SpreadStack.empty() ) + { + Vector3i pos = SpreadStack.back(); + SpreadStack.pop_back(); + + for( unsigned int i = 0; i < ARRAYCOUNT( Surroundings ); ++i ) + { + Vector3i OtherPos = pos + Surroundings[i]; + int RetVal = UnPowerBlock( OtherPos, pos ); + if( RetVal == 1 ) + { + SpreadStack.push_back( OtherPos ); // Changed, so add to stack + } + else if( RetVal == 2 ) + { + FoundSources.push_back( OtherPos ); + } + } + } + + return FoundSources; +} + + + + + +bool cRedstoneSimulator::IsPowering( const Vector3i & a_PowerPos, const Vector3i & a_BlockPos, eRedstoneDirection a_WireDirection, bool a_bOnlyByWire ) +{ + BLOCKTYPE PowerBlock = m_World->GetBlock( a_PowerPos ); + if (!a_bOnlyByWire && (PowerBlock == E_BLOCK_REDSTONE_TORCH_ON)) return true; + if (PowerBlock == E_BLOCK_REDSTONE_REPEATER_ON ) // A repeater pointing towards block is regarded as wire + { + if (IsRepeaterPointingTo( a_PowerPos, m_World->GetBlockMeta( a_PowerPos ), a_BlockPos ) ) + { + return true; + } + } + if (PowerBlock == E_BLOCK_REDSTONE_WIRE) + { + if (m_World->GetBlockMeta(a_PowerPos) > 0) + { + if (GetDirection(a_PowerPos) == a_WireDirection) + { + return true; + } + } + } + + return false; +} + + + + + +bool cRedstoneSimulator::IsPowered( const Vector3i & a_BlockPos, bool a_bOnlyByWire /* = false */ ) +{ + BLOCKTYPE Block = m_World->GetBlock( a_BlockPos ); + if ((Block == E_BLOCK_REDSTONE_REPEATER_OFF) || (Block == E_BLOCK_REDSTONE_REPEATER_ON)) + { + Vector3i Behind = a_BlockPos - GetRepeaterDirection( m_World->GetBlockMeta( a_BlockPos ) ); + BLOCKTYPE BehindBlock = m_World->GetBlock( Behind ); + if (BehindBlock == E_BLOCK_REDSTONE_TORCH_ON) + { + return true; + } + if (BehindBlock == E_BLOCK_REDSTONE_WIRE) + { + if( m_World->GetBlockMeta( Behind ) > 0 ) + { + return true; + } + } + if (BehindBlock == E_BLOCK_REDSTONE_REPEATER_ON) + { + if (IsRepeaterPointingTo( Behind, m_World->GetBlockMeta( Behind ), a_BlockPos)) + { + return true; + } + } + return false; + } + + if( IsPowering( Vector3i( a_BlockPos.x-1, a_BlockPos.y, a_BlockPos.z ), a_BlockPos, REDSTONE_X_POS, a_bOnlyByWire ) ) + return true; + if( IsPowering( Vector3i( a_BlockPos.x+1, a_BlockPos.y, a_BlockPos.z ), a_BlockPos, REDSTONE_X_NEG, a_bOnlyByWire ) ) + return true; + if( IsPowering( Vector3i( a_BlockPos.x, a_BlockPos.y, a_BlockPos.z-1 ), a_BlockPos, REDSTONE_Z_POS, a_bOnlyByWire ) ) + return true; + if( IsPowering( Vector3i( a_BlockPos.x, a_BlockPos.y, a_BlockPos.z+1 ), a_BlockPos, REDSTONE_Z_NEG, a_bOnlyByWire ) ) + return true; + + // Only wires can power the bottom block + char PosY = m_World->GetBlock( a_BlockPos.x, a_BlockPos.y+1, a_BlockPos.z ); + if( PosY == E_BLOCK_REDSTONE_WIRE ) + { + if( m_World->GetBlockMeta( a_BlockPos.x, a_BlockPos.y+1, a_BlockPos.z ) > 0 ) + { + return true; + } + } + + return false; +} + + + + +// Believe me, it works!! TODO: Add repeaters and low/high wires +cRedstoneSimulator::eRedstoneDirection cRedstoneSimulator::GetDirection( int a_X, int a_Y, int a_Z ) +{ + int Dir = REDSTONE_NONE; + + char NegX = m_World->GetBlock( a_X-1, a_Y, a_Z ); + if( NegX == E_BLOCK_REDSTONE_WIRE || NegX == E_BLOCK_REDSTONE_TORCH_ON ) + { + Dir |= (REDSTONE_X_POS); + } + char PosX = m_World->GetBlock( a_X+1, a_Y, a_Z ); + if( PosX == E_BLOCK_REDSTONE_WIRE || PosX == E_BLOCK_REDSTONE_TORCH_ON ) + { + Dir |= (REDSTONE_X_NEG); + } + char NegZ = m_World->GetBlock( a_X, a_Y, a_Z-1 ); + if( NegZ == E_BLOCK_REDSTONE_WIRE || NegZ == E_BLOCK_REDSTONE_TORCH_ON ) + { + if( (Dir & REDSTONE_X_POS) && !(Dir & REDSTONE_X_NEG ) ) //corner + { + Dir ^= REDSTONE_X_POS; + Dir |= REDSTONE_X_NEG; + } + if( (Dir & REDSTONE_X_NEG) && !(Dir & REDSTONE_X_POS ) ) //corner + { + Dir ^= REDSTONE_X_NEG; + Dir |= REDSTONE_X_POS; + } + Dir |= REDSTONE_Z_POS; + } + char PosZ = m_World->GetBlock( a_X, a_Y, a_Z+1 ); + if( PosZ == E_BLOCK_REDSTONE_WIRE || PosZ == E_BLOCK_REDSTONE_TORCH_ON ) + { + if( (Dir & REDSTONE_X_POS) && !(Dir & REDSTONE_X_NEG ) ) //corner + { + Dir ^= REDSTONE_X_POS; + Dir |= REDSTONE_X_NEG; + } + if( (Dir & REDSTONE_X_NEG) && !(Dir & REDSTONE_X_POS ) ) //corner + { + Dir ^= REDSTONE_X_NEG; + Dir |= REDSTONE_X_POS; + } + Dir |= REDSTONE_Z_NEG; + } + + return (eRedstoneDirection)Dir; +} + + + + + +bool cRedstoneSimulator::IsRepeaterPointingTo(const Vector3i & a_RepeaterPos, char a_MetaData, const Vector3i & a_BlockPos) +{ + switch (a_MetaData & 0x3) + { + case 0x0: + { + if( (a_RepeaterPos - a_BlockPos).Equals( Vector3i( 0, 0, 1 ) ) ) + { + return true; + } + break; + } + + case 0x1: + { + if( (a_RepeaterPos - a_BlockPos).Equals( Vector3i(-1, 0, 0 ) ) ) + { + return true; + } + break; + } + + case 0x2: + { + if( (a_RepeaterPos - a_BlockPos).Equals( Vector3i( 0, 0,-1 ) ) ) + { + return true; + } + break; + } + + case 0x3: + { + if( (a_RepeaterPos - a_BlockPos).Equals( Vector3i( 1, 0, 0 ) ) ) + { + return true; + } + break; + } + } + return false; +} + + + + + +bool cRedstoneSimulator::IsRepeaterPointingAway( const Vector3i & a_RepeaterPos, char a_MetaData, const Vector3i & a_BlockPos ) +{ + switch (a_MetaData & 0x3) + { + case 0x0: + { + if( (a_RepeaterPos - a_BlockPos).Equals( Vector3i( 0, 0,-1 ) ) ) + { + return true; + } + break; + } + + case 0x1: + { + if( (a_RepeaterPos - a_BlockPos).Equals( Vector3i( 1, 0, 0 ) ) ) + { + return true; + } + break; + } + + case 0x2: + { + if( (a_RepeaterPos - a_BlockPos).Equals( Vector3i( 0, 0, 1 ) ) ) + { + return true; + } + break; + } + + case 0x3: + { + if( (a_RepeaterPos - a_BlockPos).Equals( Vector3i(-1, 0, 0 ) ) ) + { + return true; + } + break; + } + } + return false; +} + + + + + +NIBBLETYPE cRedstoneSimulator::RepeaterRotationToMetaData(float a_Rotation) +{ + a_Rotation += 90 + 45; // So its not aligned with axis + if (a_Rotation > 360.f) + { + a_Rotation -= 360.f; + } + + if ((a_Rotation >= 0.f) && (a_Rotation < 90.f)) + { + return 0x1; + } + else if ((a_Rotation >= 180) && (a_Rotation < 270)) + { + return 0x3; + } + else if ((a_Rotation >= 90) && (a_Rotation < 180)) + { + return 0x2; + } + else + { + return 0x0; + } +} + + + + + +Vector3i cRedstoneSimulator::GetRepeaterDirection(NIBBLETYPE a_MetaData) +{ + switch (a_MetaData & 0x3) + { + case 0x0: return Vector3i( 0, 0,-1); + case 0x1: return Vector3i( 1, 0, 0); + case 0x2: return Vector3i( 0, 0, 1); + case 0x3: return Vector3i(-1, 0, 0); + } + return Vector3i(); +} + + + + + +void cRedstoneSimulator::SetRepeater( const Vector3i & a_Position, int a_Ticks, bool a_bPowerOn ) +{ + for( RepeaterList::iterator itr = m_SetRepeaters.begin(); itr != m_SetRepeaters.end(); ++itr ) + { + sRepeaterChange & Change = *itr; + if( Change.Position.Equals( a_Position ) ) + { + if( Change.bPowerOn && a_bPowerOn == false ) + { + Change.bPowerOffNextTime = true; + } + if( a_bPowerOn == true ) + { + Change.bPowerOffNextTime = false; + } + Change.bPowerOn |= a_bPowerOn; + return; + } + } + + sRepeaterChange RC; + RC.Position = a_Position; + RC.Ticks = a_Ticks; + RC.bPowerOn = a_bPowerOn; + RC.bPowerOffNextTime = false; + m_SetRepeaters.push_back( RC ); +} + + + + diff --git a/source/Simulator/RedstoneSimulator.h b/source/Simulator/RedstoneSimulator.h new file mode 100644 index 000000000..f26b6b46b --- /dev/null +++ b/source/Simulator/RedstoneSimulator.h @@ -0,0 +1,81 @@ + +#pragma once + +#include "Simulator.h" + + + + + +class cRedstoneSimulator : + public cSimulator +{ + typedef cSimulator super; +public: + cRedstoneSimulator( cWorld* a_World ); + ~cRedstoneSimulator(); + + virtual void Simulate( float a_Dt ) override; + virtual bool IsAllowedBlock( BLOCKTYPE a_BlockType ) override { return true; } + + virtual void WakeUp( int a_X, int a_Y, int a_Z ) override; + + enum eRedstoneDirection + { + REDSTONE_NONE = 0, + REDSTONE_X_POS = 0x1, + REDSTONE_X_NEG = 0x2, + REDSTONE_Z_POS = 0x4, + REDSTONE_Z_NEG = 0x8, + }; + eRedstoneDirection GetDirection( int a_X, int a_Y, int a_Z ); + eRedstoneDirection GetDirection( const Vector3i & a_Pos ) { return GetDirection( a_Pos.x, a_Pos.y, a_Pos.z ); } + + static bool IsRepeaterPointingTo (const Vector3i & a_RepeaterPos, char a_MetaData, const Vector3i & a_BlockPos); + static bool IsRepeaterPointingAway(const Vector3i & a_RepeaterPos, char a_MetaData, const Vector3i & a_BlockPos); + static NIBBLETYPE RepeaterRotationToMetaData(float a_Rotation); + static Vector3i GetRepeaterDirection(NIBBLETYPE a_MetaData); + + +private: + struct sRepeaterChange + { + Vector3i Position; + int Ticks; + bool bPowerOn; + bool bPowerOffNextTime; + }; + + typedef std::deque BlockList; + + typedef std::deque< sRepeaterChange > RepeaterList; + RepeaterList m_SetRepeaters; + + void SetRepeater(const Vector3i & a_Position, int a_Ticks, bool a_bPowerOn); + + virtual void AddBlock(int a_X, int a_Y, int a_Z) {} + + void HandleChange( const Vector3i & a_BlockPos ); + BlockList RemoveCurrent( const Vector3i & a_BlockPos ); + + bool PowerBlock( const Vector3i & a_BlockPos, const Vector3i & a_FromBlock, char a_Power ); + int UnPowerBlock( const Vector3i & a_BlockPos, const Vector3i & a_FromBlock ); + + bool IsPowered( const Vector3i & a_BlockPos, bool a_bOnlyByWire = false ); + bool IsPowering( const Vector3i & a_PowerPos, const Vector3i & a_BlockPos, eRedstoneDirection a_WireDirection, bool a_bOnlyByWire ); + + BlockList m_Blocks; + BlockList m_BlocksBuffer; + + BlockList m_RefreshPistons; + + BlockList m_RefreshTorchesAround; + + void RefreshTorchesAround( const Vector3i & a_BlockPos ); + + cCriticalSection m_CS; +}; + + + + diff --git a/source/Simulator/SandSimulator.cpp b/source/Simulator/SandSimulator.cpp new file mode 100644 index 000000000..69513afef --- /dev/null +++ b/source/Simulator/SandSimulator.cpp @@ -0,0 +1,101 @@ + +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "SandSimulator.h" +#include "../World.h" +#include "../BlockID.h" +#include "../Defines.h" +#include "../FallingBlock.h" + + + + +cSandSimulator::cSandSimulator( cWorld* a_World ) + : cSimulator(a_World) + , m_Blocks(new BlockList) + , m_Buffer(new BlockList) +{ + +} + + + + + +cSandSimulator::~cSandSimulator() +{ + 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 ) + { + Vector3i Pos = *itr; + BLOCKTYPE BlockID = m_World->GetBlock(Pos.x, Pos.y, Pos.z); + if(!IsAllowedBlock(BlockID)) + continue; + + BLOCKTYPE BottomBlock = m_World->GetBlock( Pos.x, Pos.y - 1, Pos.z ); + + if( IsPassable(BottomBlock) ) + { + cFallingBlock * FallingBlock = new cFallingBlock( Pos, BlockID ); + FallingBlock->Initialize( m_World ); + m_World->SetBlock( Pos.x, Pos.y, Pos.z, E_BLOCK_AIR, 0 ); + } + } + +} + + + + + +bool cSandSimulator::IsAllowedBlock( BLOCKTYPE a_BlockType ) +{ + return a_BlockType == E_BLOCK_SAND + || a_BlockType == E_BLOCK_GRAVEL; +} + + + + + +void cSandSimulator::AddBlock(int a_X, int a_Y, int a_Z) +{ + if(!IsAllowedBlock(m_World->GetBlock(a_X, a_Y, a_Z))) + return; + + Vector3i Block(a_X, a_Y, a_Z); + + //check for duplicates + for( BlockList::iterator itr = m_Blocks->begin(); itr != m_Blocks->end(); ++itr ) + { + Vector3i Pos = *itr; + if( Pos.x == a_X && Pos.y == a_Y && Pos.z == a_Z ) + return; + } + + m_Blocks->push_back(Block); +} + + + + + +bool cSandSimulator::IsPassable( BLOCKTYPE a_BlockType ) +{ + return a_BlockType == E_BLOCK_AIR + || IsBlockWater(a_BlockType) + || IsBlockLava(a_BlockType) + || a_BlockType == E_BLOCK_FIRE; +} diff --git a/source/Simulator/SandSimulator.h b/source/Simulator/SandSimulator.h new file mode 100644 index 000000000..928ea63fc --- /dev/null +++ b/source/Simulator/SandSimulator.h @@ -0,0 +1,33 @@ + +#pragma once + +#include "Simulator.h" +#include "../BlockEntity.h" +#include "../Vector3i.h" + + + + + +class cSandSimulator : public cSimulator +{ +public: + cSandSimulator( cWorld* a_World ); + ~cSandSimulator(); + + virtual void Simulate( float a_Dt ) override; + + virtual bool IsAllowedBlock( BLOCKTYPE a_BlockType ) override; + virtual bool IsPassable( BLOCKTYPE a_BlockType ); + +protected: + virtual void AddBlock(int a_X, int a_Y, int a_Z) override; + + typedef std::list BlockList; + BlockList * m_Blocks; + BlockList * m_Buffer; +}; + + + + diff --git a/source/Simulator/Simulator.cpp b/source/Simulator/Simulator.cpp new file mode 100644 index 000000000..86b37e989 --- /dev/null +++ b/source/Simulator/Simulator.cpp @@ -0,0 +1,44 @@ + +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "Simulator.h" +#include "../World.h" +#include "../Vector3i.h" +#include "../BlockID.h" +#include "../Defines.h" + + + + + +cSimulator::cSimulator( cWorld* a_World ) + : m_World(a_World) +{ +} + + + + + +cSimulator::~cSimulator() +{ +} + + + + + +void cSimulator::WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ) +{ + AddBlock(a_BlockX, a_BlockY, a_BlockZ); + AddBlock(a_BlockX - 1, a_BlockY, a_BlockZ); + AddBlock(a_BlockX + 1, a_BlockY, a_BlockZ); + AddBlock(a_BlockX, a_BlockY - 1, a_BlockZ); + AddBlock(a_BlockX, a_BlockY + 1, a_BlockZ); + AddBlock(a_BlockX, a_BlockY, a_BlockZ - 1); + AddBlock(a_BlockX, a_BlockY, a_BlockZ + 1); +} + + + + diff --git a/source/Simulator/Simulator.h b/source/Simulator/Simulator.h new file mode 100644 index 000000000..84a1630c2 --- /dev/null +++ b/source/Simulator/Simulator.h @@ -0,0 +1,38 @@ + +#pragma once + +#include "../Vector3i.h" + + + + + +class cWorld; + + + + + +class cSimulator +{ +public: + cSimulator(cWorld * a_World); + virtual ~cSimulator(); + + /// Called in each tick, a_Dt is the time passed since the last tick + virtual void Simulate(float a_Dt) = 0; + + /// Called when a block changes via cWorld::SetBlock() + virtual void WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ); + + virtual bool IsAllowedBlock(BLOCKTYPE a_BlockType) = 0; + +protected: + virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ) = 0; + + cWorld * m_World; +} ; + + + + diff --git a/source/Simulator/SimulatorManager.cpp b/source/Simulator/SimulatorManager.cpp new file mode 100644 index 000000000..1ab7a51b5 --- /dev/null +++ b/source/Simulator/SimulatorManager.cpp @@ -0,0 +1,67 @@ + +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "SimulatorManager.h" + + + + + +cSimulatorManager::cSimulatorManager() +{ + +} + + + + + +cSimulatorManager::~cSimulatorManager() +{ + for (cSimulators::iterator itr = m_Simulators.begin(); itr != m_Simulators.end(); ++itr ) + { + delete *itr; + } // for itr - m_Simulators[] +} + + + + + +void cSimulatorManager::Simulate( float a_Dt ) +{ + m_Ticks++; + for (cSimulators::iterator itr = m_Simulators.begin(); itr != m_Simulators.end(); ++itr ) + { + if(m_Ticks % (*itr)->second == 0) + (*itr)->first->Simulate(a_Dt); + } +} + + + + + +void cSimulatorManager::WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ) +{ + for (cSimulators::iterator itr = m_Simulators.begin(); itr != m_Simulators.end(); ++itr ) + { + (*itr)->first->WakeUp(a_BlockX, a_BlockY, a_BlockZ); + } +} + + + + + +void cSimulatorManager::RegisterSimulator(cSimulator *a_Simulator, short a_Rate) +{ + //TODO needs some checking + std::pair *Pair = new std::pair(a_Simulator, a_Rate); + + m_Simulators.push_back(Pair); +} + + + + diff --git a/source/Simulator/SimulatorManager.h b/source/Simulator/SimulatorManager.h new file mode 100644 index 000000000..e90acffab --- /dev/null +++ b/source/Simulator/SimulatorManager.h @@ -0,0 +1,39 @@ + +// cSimulatorManager.h + + + + +#pragma once + + + + +#include "Simulator.h" + + + + + +class cSimulatorManager +{ +public: + cSimulatorManager(); + ~cSimulatorManager(); + + void Simulate( float a_Dt ); + void WakeUp(int a_X, int a_Y, int a_Z); + + void RegisterSimulator(cSimulator * a_Simulator, short a_Rate); // Takes ownership of the simulator object! + +protected: + + typedef std::vector *> cSimulators; + + cSimulators m_Simulators; + long long m_Ticks; +}; + + + + diff --git a/source/Simulator/WaterSimulator.cpp b/source/Simulator/WaterSimulator.cpp new file mode 100644 index 000000000..c63135419 --- /dev/null +++ b/source/Simulator/WaterSimulator.cpp @@ -0,0 +1,22 @@ +#include "Globals.h" +#include "WaterSimulator.h" +#include "Defines.h" +#include "World.h" + + + +cWaterSimulator::cWaterSimulator(cWorld *a_World) + : cFluidSimulator(a_World) +{ + m_FluidBlock = E_BLOCK_WATER; + m_StationaryFluidBlock = E_BLOCK_STATIONARY_WATER; + m_MaxHeight = 7; + m_FlowReduction = 1; +} + + +bool cWaterSimulator::IsAllowedBlock(BLOCKTYPE a_BlockType) +{ + return IsBlockWater(a_BlockType); +} + diff --git a/source/Simulator/WaterSimulator.h b/source/Simulator/WaterSimulator.h new file mode 100644 index 000000000..4bc35b8f7 --- /dev/null +++ b/source/Simulator/WaterSimulator.h @@ -0,0 +1,11 @@ +#pragma once +#include "FluidSimulator.h" + +class cWaterSimulator : public cFluidSimulator +{ +public: + cWaterSimulator( cWorld* a_World ); + + virtual bool IsAllowedBlock( BLOCKTYPE a_BlockType ) override; + +}; \ No newline at end of file diff --git a/source/SimulatorManager.cpp b/source/SimulatorManager.cpp deleted file mode 100644 index 0aef1ec6c..000000000 --- a/source/SimulatorManager.cpp +++ /dev/null @@ -1,67 +0,0 @@ - -#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules - -#include "SimulatorManager.h" - - - - - -cSimulatorManager::cSimulatorManager() -{ - -} - - - - - -cSimulatorManager::~cSimulatorManager() -{ - for (cSimulators::iterator itr = m_Simulators.begin(); itr != m_Simulators.end(); ++itr ) - { - delete *itr; - } // for itr - m_Simulators[] -} - - - - - -void cSimulatorManager::Simulate( float a_Dt ) -{ - m_Ticks++; - for (cSimulators::iterator itr = m_Simulators.begin(); itr != m_Simulators.end(); ++itr ) - { - if(m_Ticks % (*itr)->second == 0) - (*itr)->first->Simulate(a_Dt); - } -} - - - - - -void cSimulatorManager::WakeUp(int a_X, int a_Y, int a_Z) -{ - for (cSimulators::iterator itr = m_Simulators.begin(); itr != m_Simulators.end(); ++itr ) - { - (*itr)->first->WakeUp(a_X, a_Y, a_Z); - } -} - - - - - -void cSimulatorManager::RegisterSimulator(cSimulator *a_Simulator, short a_Rate) -{ - //TODO needs some checking - std::pair *Pair = new std::pair(a_Simulator, a_Rate); - - m_Simulators.push_back(Pair); -} - - - - diff --git a/source/SimulatorManager.h b/source/SimulatorManager.h deleted file mode 100644 index e90acffab..000000000 --- a/source/SimulatorManager.h +++ /dev/null @@ -1,39 +0,0 @@ - -// cSimulatorManager.h - - - - -#pragma once - - - - -#include "Simulator.h" - - - - - -class cSimulatorManager -{ -public: - cSimulatorManager(); - ~cSimulatorManager(); - - void Simulate( float a_Dt ); - void WakeUp(int a_X, int a_Y, int a_Z); - - void RegisterSimulator(cSimulator * a_Simulator, short a_Rate); // Takes ownership of the simulator object! - -protected: - - typedef std::vector *> cSimulators; - - cSimulators m_Simulators; - long long m_Ticks; -}; - - - - diff --git a/source/WaterSimulator.cpp b/source/WaterSimulator.cpp deleted file mode 100644 index c63135419..000000000 --- a/source/WaterSimulator.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "Globals.h" -#include "WaterSimulator.h" -#include "Defines.h" -#include "World.h" - - - -cWaterSimulator::cWaterSimulator(cWorld *a_World) - : cFluidSimulator(a_World) -{ - m_FluidBlock = E_BLOCK_WATER; - m_StationaryFluidBlock = E_BLOCK_STATIONARY_WATER; - m_MaxHeight = 7; - m_FlowReduction = 1; -} - - -bool cWaterSimulator::IsAllowedBlock(BLOCKTYPE a_BlockType) -{ - return IsBlockWater(a_BlockType); -} - diff --git a/source/WaterSimulator.h b/source/WaterSimulator.h deleted file mode 100644 index 4bc35b8f7..000000000 --- a/source/WaterSimulator.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once -#include "FluidSimulator.h" - -class cWaterSimulator : public cFluidSimulator -{ -public: - cWaterSimulator( cWorld* a_World ); - - virtual bool IsAllowedBlock( BLOCKTYPE a_BlockType ) override; - -}; \ No newline at end of file diff --git a/source/World.cpp b/source/World.cpp index 7180213fe..f932c7c04 100644 --- a/source/World.cpp +++ b/source/World.cpp @@ -12,12 +12,14 @@ #include "Root.h" #include "../iniFile/iniFile.h" #include "ChunkMap.h" -#include "SimulatorManager.h" -#include "WaterSimulator.h" -#include "LavaSimulator.h" -#include "FireSimulator.h" -#include "SandSimulator.h" -#include "RedstoneSimulator.h" + +// Simulators: +#include "Simulator/SimulatorManager.h" +#include "Simulator/ClassicFluidSimulator.h" +#include "Simulator/FluidSimulator.h" +#include "Simulator/FireSimulator.h" +#include "Simulator/SandSimulator.h" +#include "Simulator/RedstoneSimulator.h" // Mobs: #include "Mobs/Chicken.h" @@ -288,11 +290,11 @@ cWorld::cWorld( const AString & a_WorldName ) m_BlockTickQueue.reserve(1000); m_BlockTickQueueCopy.reserve(1000); - //Simulators: - m_WaterSimulator = new cWaterSimulator( this ); - m_LavaSimulator = new cLavaSimulator( this ); - m_SandSimulator = new cSandSimulator(this); - m_FireSimulator = new cFireSimulator(this); + // Simulators: + m_WaterSimulator = InitializeFluidSimulator(IniFile, "Water", E_BLOCK_WATER, E_BLOCK_STATIONARY_WATER); + m_LavaSimulator = InitializeFluidSimulator(IniFile, "Lava", E_BLOCK_LAVA, E_BLOCK_STATIONARY_LAVA); + m_SandSimulator = new cSandSimulator(this); + m_FireSimulator = new cFireSimulator(this); m_RedstoneSimulator = new cRedstoneSimulator(this); m_SimulatorManager = new cSimulatorManager(); @@ -2153,3 +2155,44 @@ bool cWorld::IsBlockDirectlyWatered(int a_BlockX, int a_BlockY, int a_BlockZ) +cFluidSimulator * cWorld::InitializeFluidSimulator(cIniFile & a_IniFile, const char * a_FluidName, BLOCKTYPE a_SimulateBlock, BLOCKTYPE a_StationaryBlock) +{ + AString SimulatorNameKey; + Printf(SimulatorNameKey, "%sSimulator", a_FluidName); + AString SimulatorSectionName; + Printf(SimulatorSectionName, "%sSimulator", a_FluidName); + AString SimulatorName = a_IniFile.GetValue("Physics", SimulatorNameKey, ""); + if (SimulatorName.empty()) + { + LOGWARNING("%s [Physics]:%s not present or empty, using the default of \"Classic\".", GetIniFileName().c_str(), SimulatorNameKey.c_str()); + SimulatorName = "Classic"; + } + + cFluidSimulator * res = NULL; + /* + // TODO: other fluid simulators + if (NoCaseCompare(SimulatorName, "floody") == 0) + { + // TODO: Floody simulator params + res = new cFloodyFluidSimulator(this, a_SimulateBlock, a_StationaryBlock); + } + else + */ + { + if (NoCaseCompare(SimulatorName, "classic") != 0) + { + // The simulator name doesn't match anything we have, issue a warning: + LOGWARNING("%s [Physics]:%s specifies an unknown simulator, using the default \"Classic\".", GetIniFileName().c_str(), SimulatorNameKey.c_str()); + } + int DefaultFalloff = (strcmp(a_FluidName, "Water") == 0) ? 1 : 2; + int DefaultMaxHeight = (strcmp(a_FluidName, "Water") == 0) ? 7 : 6; + int Falloff = a_IniFile.GetValueI(SimulatorSectionName, "Falloff", DefaultFalloff); + int MaxHeight = a_IniFile.GetValueI(SimulatorSectionName, "MaxHeight", DefaultMaxHeight); + res = new cClassicFluidSimulator(this, a_SimulateBlock, a_StationaryBlock, MaxHeight, Falloff); + } + + return res; +} + + + diff --git a/source/World.h b/source/World.h index f3117fe55..913d28f5b 100644 --- a/source/World.h +++ b/source/World.h @@ -9,7 +9,7 @@ #define MAX_PLAYERS 65535 -#include "SimulatorManager.h" +#include "Simulator/SimulatorManager.h" #include "MersenneTwister.h" #include "ChunkMap.h" #include "WorldStorage/WorldStorage.h" @@ -27,8 +27,7 @@ class cRedstone; class cFireSimulator; -class cWaterSimulator; -class cLavaSimulator; +class cFluidSimulator; class cSandSimulator; class cRedstoneSimulator; class cItem; @@ -279,9 +278,10 @@ public: const double & GetSpawnY(void) const { return m_SpawnY; } // tolua_export const double & GetSpawnZ(void) const { return m_SpawnZ; } // tolua_export - inline cSimulatorManager *GetSimulatorManager() { return m_SimulatorManager; } - inline cWaterSimulator *GetWaterSimulator() { return m_WaterSimulator; } - inline cLavaSimulator *GetLavaSimulator() { return m_LavaSimulator; } + inline cSimulatorManager * GetSimulatorManager(void) { return m_SimulatorManager; } + + inline cFluidSimulator * GetWaterSimulator(void) { return m_WaterSimulator; } + inline cFluidSimulator * GetLavaSimulator (void) { return m_LavaSimulator; } /// Calls the callback for each chest in the specified chunk; returns true if all chests processed, false if the callback aborted by returning true bool ForEachChestInChunk (int a_ChunkX, int a_ChunkZ, cChestCallback & a_Callback); // Exported in ManualBindings.cpp @@ -429,8 +429,8 @@ private: cSimulatorManager * m_SimulatorManager; cSandSimulator * m_SandSimulator; - cWaterSimulator * m_WaterSimulator; - cLavaSimulator * m_LavaSimulator; + cFluidSimulator * m_WaterSimulator; + cFluidSimulator * m_LavaSimulator; cFireSimulator * m_FireSimulator; cRedstoneSimulator * m_RedstoneSimulator; @@ -488,6 +488,9 @@ private: void TickSpawnMobs(float a_Dt); // Handles mob spawning each tick void RemoveEntity( cEntity * a_Entity ); + + /// Creates a new fluid simulator, loads its settings from the inifile (a_FluidName section) + cFluidSimulator * InitializeFluidSimulator(cIniFile & a_IniFile, const char * a_FluidName, BLOCKTYPE a_SimulateBlock, BLOCKTYPE a_StationaryBlock); }; //tolua_export -- cgit v1.2.3