Initial Floody fluid simulator.
Can spread, cannot dry. git-svn-id: http://mc-server.googlecode.com/svn/trunk@963 0a769ca7-a7f5-676a-18bf-c427514a06d6
This commit is contained in:
parent
dd554175a4
commit
5b7de82a79
@ -1018,6 +1018,14 @@
|
|||||||
RelativePath="..\source\Simulator\ClassicFluidSimulator.h"
|
RelativePath="..\source\Simulator\ClassicFluidSimulator.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\source\Simulator\DelayedFluidSimulator.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\source\Simulator\DelayedFluidSimulator.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\source\Simulator\FireSimulator.cpp"
|
RelativePath="..\source\Simulator\FireSimulator.cpp"
|
||||||
>
|
>
|
||||||
@ -1026,6 +1034,14 @@
|
|||||||
RelativePath="..\source\Simulator\FireSimulator.h"
|
RelativePath="..\source\Simulator\FireSimulator.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\source\Simulator\FloodyFluidSimulator.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\source\Simulator\FloodyFluidSimulator.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\source\Simulator\FluidSimulator.cpp"
|
RelativePath="..\source\Simulator\FluidSimulator.cpp"
|
||||||
>
|
>
|
||||||
|
@ -300,15 +300,6 @@ void cClassicFluidSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cClassicFluidSimulator::IsAllowedBlock(BLOCKTYPE a_BlockType)
|
|
||||||
{
|
|
||||||
return ((a_BlockType == m_FluidBlock) || (a_BlockType == m_StationaryFluidBlock));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
NIBBLETYPE cClassicFluidSimulator::GetHighestLevelAround(int a_BlockX, int a_BlockY, int a_BlockZ)
|
NIBBLETYPE cClassicFluidSimulator::GetHighestLevelAround(int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||||
{
|
{
|
||||||
NIBBLETYPE Max = m_MaxHeight + m_Falloff;
|
NIBBLETYPE Max = m_MaxHeight + m_Falloff;
|
||||||
|
@ -25,7 +25,6 @@ public:
|
|||||||
// cSimulator overrides:
|
// cSimulator overrides:
|
||||||
virtual void Simulate(float a_Dt) override;
|
virtual void Simulate(float a_Dt) override;
|
||||||
virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ) override;
|
virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ) override;
|
||||||
virtual bool IsAllowedBlock(BLOCKTYPE a_BlockType) override;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
NIBBLETYPE GetHighestLevelAround(int a_BlockX, int a_BlockY, int a_BlockZ);
|
NIBBLETYPE GetHighestLevelAround(int a_BlockX, int a_BlockY, int a_BlockZ);
|
||||||
|
92
source/Simulator/DelayedFluidSimulator.cpp
Normal file
92
source/Simulator/DelayedFluidSimulator.cpp
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
|
||||||
|
// DelayedFluidSimulator.cpp
|
||||||
|
|
||||||
|
// Interfaces to the cDelayedFluidSimulator class representing a fluid simulator that has a configurable delay
|
||||||
|
// before simulating a block. Each tick it takes a consecutive delay "slot" and simulates only blocks in that slot.
|
||||||
|
|
||||||
|
#include "Globals.h"
|
||||||
|
|
||||||
|
#include "DelayedFluidSimulator.h"
|
||||||
|
#include "../World.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cDelayedFluidSimulator::cDelayedFluidSimulator(cWorld * a_World, BLOCKTYPE a_Fluid, BLOCKTYPE a_StationaryFluid, int a_TickDelay) :
|
||||||
|
super(a_World, a_Fluid, a_StationaryFluid),
|
||||||
|
m_TickDelay(a_TickDelay),
|
||||||
|
m_Slots(NULL),
|
||||||
|
m_CurrentSlotNum(a_TickDelay - 1)
|
||||||
|
{
|
||||||
|
m_Slots = new CoordsArray[a_TickDelay];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cDelayedFluidSimulator::~cDelayedFluidSimulator()
|
||||||
|
{
|
||||||
|
delete[] m_Slots;
|
||||||
|
m_Slots = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cDelayedFluidSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||||
|
{
|
||||||
|
if ((a_BlockY < 0) || (a_BlockY >= cChunkDef::Height))
|
||||||
|
{
|
||||||
|
// Not inside the world (may happen when rclk with a full bucket - the client sends Y = -1)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BLOCKTYPE BlockType = m_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
|
||||||
|
if (BlockType != m_FluidBlock)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CoordsArray & Blocks = m_Slots[m_CurrentSlotNum];
|
||||||
|
|
||||||
|
// Check for duplicates:
|
||||||
|
for (CoordsArray::iterator itr = Blocks.begin(), end = Blocks.end(); itr != end; ++itr)
|
||||||
|
{
|
||||||
|
if ((itr->x == a_BlockX) && (itr->y == a_BlockY) && (itr->z == a_BlockZ))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Blocks.push_back(Vector3i(a_BlockX, a_BlockY, a_BlockZ));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cDelayedFluidSimulator::Simulate(float a_Dt)
|
||||||
|
{
|
||||||
|
CoordsArray & Blocks = m_Slots[m_CurrentSlotNum];
|
||||||
|
|
||||||
|
// First move to the next slot, so that simulated blocks can write another batch of scheduled blocks:
|
||||||
|
m_CurrentSlotNum += 1;
|
||||||
|
if (m_CurrentSlotNum >= m_TickDelay)
|
||||||
|
{
|
||||||
|
m_CurrentSlotNum = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simulate the blocks in the scheduled slot:
|
||||||
|
for (CoordsArray::iterator itr = Blocks.begin(), end = Blocks.end(); itr != end; ++itr)
|
||||||
|
{
|
||||||
|
SimulateBlock(itr->x, itr->y, itr->z);
|
||||||
|
}
|
||||||
|
Blocks.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
44
source/Simulator/DelayedFluidSimulator.h
Normal file
44
source/Simulator/DelayedFluidSimulator.h
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
|
||||||
|
// DelayedFluidSimulator.h
|
||||||
|
|
||||||
|
// Interfaces to the cDelayedFluidSimulator class representing a fluid simulator that has a configurable delay
|
||||||
|
// before simulating a block. Each tick it takes a consecutive delay "slot" and simulates only blocks in that slot.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "FluidSimulator.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class cDelayedFluidSimulator :
|
||||||
|
public cFluidSimulator
|
||||||
|
{
|
||||||
|
typedef cFluidSimulator super;
|
||||||
|
|
||||||
|
public:
|
||||||
|
cDelayedFluidSimulator(cWorld * a_World, BLOCKTYPE a_Fluid, BLOCKTYPE a_StationaryFluid, int a_TickDelay);
|
||||||
|
virtual ~cDelayedFluidSimulator();
|
||||||
|
|
||||||
|
// cSimulator overrides:
|
||||||
|
virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ) override;
|
||||||
|
virtual void Simulate(float a_Dt) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
typedef std::vector<Vector3i> CoordsArray;
|
||||||
|
|
||||||
|
int m_TickDelay; // Count of the m_Slots array
|
||||||
|
CoordsArray * m_Slots; // Slots, one for each delay tick
|
||||||
|
int m_CurrentSlotNum; // Index into m_Slots[] where to insert new blocks
|
||||||
|
|
||||||
|
/// Called from Simulate() to simulate each block in one slot of blocks. Descendants override this method to provide custom simulation.
|
||||||
|
virtual void SimulateBlock(int a_BlockX, int a_BlockY, int a_BlockZ) = 0;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -47,8 +47,10 @@ void cFireSimulator::Simulate( float a_Dt )
|
|||||||
if(!IsAllowedBlock(BlockID)) //Check wheather the block is still burning
|
if(!IsAllowedBlock(BlockID)) //Check wheather the block is still burning
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if(BurnBlockAround(Pos.x, Pos.y, Pos.z)) //Burn single block and if there was one -> next time again
|
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);
|
{
|
||||||
|
m_Blocks->push_back(Pos);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
if(!IsForeverBurnable(m_World->GetBlock(Pos.x, Pos.y - 1, Pos.z)) && !FiresForever(BlockID))
|
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);
|
m_World->SetBlock(Pos.x, Pos.y, Pos.z, E_BLOCK_AIR, 0);
|
||||||
@ -61,42 +63,34 @@ void cFireSimulator::Simulate( float a_Dt )
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cFireSimulator::IsAllowedBlock( BLOCKTYPE a_BlockType )
|
bool cFireSimulator::IsAllowedBlock(BLOCKTYPE a_BlockType)
|
||||||
{
|
{
|
||||||
return a_BlockType == E_BLOCK_FIRE
|
return (a_BlockType == E_BLOCK_FIRE) || IsBlockLava(a_BlockType);
|
||||||
|| IsBlockLava(a_BlockType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cFireSimulator::AddBlock(int a_X, int a_Y, int a_Z)
|
void cFireSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||||
{
|
{
|
||||||
char BlockID = m_World->GetBlock(a_X, a_Y, a_Z);
|
BLOCKTYPE BlockType = m_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
|
||||||
if(!IsAllowedBlock(BlockID)) //This should save very much time because it doesn´t have to iterate through all blocks
|
if (!IsAllowedBlock(BlockType))
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//check for duplicates
|
// Check for duplicates:
|
||||||
for( BlockList::iterator itr = m_Blocks->begin(); itr != m_Blocks->end(); ++itr )
|
for (BlockList::iterator itr = m_Blocks->begin(); itr != m_Blocks->end(); ++itr )
|
||||||
{
|
{
|
||||||
Vector3i Pos = *itr;
|
Vector3i Pos = *itr;
|
||||||
if( Pos.x == a_X && Pos.y == a_Y && Pos.z == a_Z )
|
if ((Pos.x == a_BlockX) && (Pos.y == a_BlockY) && (Pos.z == a_BlockZ))
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_AddBlock(a_X, a_Y, a_Z);
|
m_Blocks->push_back(Vector3i(a_BlockX, a_BlockY, a_BlockZ));
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cFireSimulator::_AddBlock(int a_X, int a_Y, int a_Z)
|
|
||||||
{
|
|
||||||
m_Blocks->push_back( Vector3i(a_X, a_Y, a_Z) );
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -24,7 +24,6 @@ public:
|
|||||||
|
|
||||||
protected:
|
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) 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 BurnBlockAround(int a_X, int a_Y, int a_Z);
|
||||||
virtual bool BurnBlock(int a_X, int a_Y, int a_Z);
|
virtual bool BurnBlock(int a_X, int a_Y, int a_Z);
|
||||||
|
|
||||||
|
159
source/Simulator/FloodyFluidSimulator.cpp
Normal file
159
source/Simulator/FloodyFluidSimulator.cpp
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
|
||||||
|
// FloodyFluidSimulator.cpp
|
||||||
|
|
||||||
|
// Interfaces to the cFloodyFluidSimulator that represents a fluid simulator that tries to flood everything :)
|
||||||
|
// http://forum.mc-server.org/showthread.php?tid=565
|
||||||
|
|
||||||
|
#include "Globals.h"
|
||||||
|
|
||||||
|
#include "FloodyFluidSimulator.h"
|
||||||
|
#include "../World.h"
|
||||||
|
#include "../BlockArea.h"
|
||||||
|
#include "../Blocks/BlockHandler.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cFloodyFluidSimulator::cFloodyFluidSimulator(cWorld * a_World, BLOCKTYPE a_Fluid, BLOCKTYPE a_StationaryFluid, NIBBLETYPE a_Falloff, int a_TickDelay) :
|
||||||
|
super(a_World, a_Fluid, a_StationaryFluid, a_TickDelay),
|
||||||
|
m_Falloff(a_Falloff)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cFloodyFluidSimulator::SimulateBlock(int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||||
|
{
|
||||||
|
cBlockArea Area;
|
||||||
|
int MinBlockY = std::max(0, a_BlockY - 1);
|
||||||
|
int MaxBlockY = std::min(cChunkDef::Height, a_BlockY + 1);
|
||||||
|
if (!Area.Read(m_World, a_BlockX - 1, a_BlockX + 1, MinBlockY, MaxBlockY, a_BlockZ - 1, a_BlockZ + 1))
|
||||||
|
{
|
||||||
|
// Cannot read the immediate neighborhood, probably too close to an unloaded chunk. Bail out.
|
||||||
|
// TODO: Shouldn't we re-schedule?
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int y = (a_BlockY > 0) ? 1 : 0; // Relative y-coord of this block in Area
|
||||||
|
|
||||||
|
NIBBLETYPE MyMeta = Area.GetRelBlockMeta(1, y, 1);
|
||||||
|
|
||||||
|
if (MyMeta != 0)
|
||||||
|
{
|
||||||
|
if (CheckTributaries(a_BlockX, a_BlockY, a_BlockZ, Area, MyMeta))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// New meta for the spreading to neighbors:
|
||||||
|
// If this is a source block or was falling, the new meta is just the falloff
|
||||||
|
// Otherwise it is the current meta plus falloff (may be larger than max height, will be checked later)
|
||||||
|
NIBBLETYPE NewMeta = ((MyMeta == 0) || ((MyMeta & 0x08) != 0)) ? m_Falloff : (MyMeta + m_Falloff);
|
||||||
|
|
||||||
|
BLOCKTYPE Below = Area.GetRelBlockType(1, 0, 1);
|
||||||
|
if ((a_BlockY > 0) && IsPassableForFluid(Below))
|
||||||
|
{
|
||||||
|
// Spread only down, possibly washing away what's there:
|
||||||
|
SpreadToNeighbor(a_BlockX, a_BlockY - 1, a_BlockZ, Area, 8);
|
||||||
|
}
|
||||||
|
else if (NewMeta < 8) // Can reach there
|
||||||
|
{
|
||||||
|
// Spread to the neighbors:
|
||||||
|
SpreadToNeighbor(a_BlockX - 1, a_BlockY, a_BlockZ, Area, NewMeta);
|
||||||
|
SpreadToNeighbor(a_BlockX + 1, a_BlockY, a_BlockZ, Area, NewMeta);
|
||||||
|
SpreadToNeighbor(a_BlockX, a_BlockY, a_BlockZ - 1, Area, NewMeta);
|
||||||
|
SpreadToNeighbor(a_BlockX, a_BlockY, a_BlockZ + 1, Area, NewMeta);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark as processed:
|
||||||
|
m_World->FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, m_StationaryFluidBlock, MyMeta);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cFloodyFluidSimulator::CheckTributaries(int a_BlockX, int a_BlockY, int a_BlockZ, const cBlockArea & a_Area, NIBBLETYPE a_MyMeta)
|
||||||
|
{
|
||||||
|
bool IsFed = false;
|
||||||
|
int y = (a_BlockY > 0) ? 1 : 0; // Relative y-coord of this block in Area
|
||||||
|
|
||||||
|
// If we have a section above, check if there's fluid above this block that would feed it:
|
||||||
|
if (a_BlockY < cChunkDef::Height - 1)
|
||||||
|
{
|
||||||
|
IsFed = IsAnyFluidBlock(a_Area.GetRelBlockType(1, 2, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If not fed from above, check if there's a feed from the side:
|
||||||
|
if (!IsFed)
|
||||||
|
{
|
||||||
|
IsFed = (
|
||||||
|
(IsAnyFluidBlock(a_Area.GetRelBlockType(0, y, 1)) && IsHigherMeta(a_Area.GetRelBlockMeta(0, y, 1), a_MyMeta)) ||
|
||||||
|
(IsAnyFluidBlock(a_Area.GetRelBlockType(2, y, 1)) && IsHigherMeta(a_Area.GetRelBlockMeta(2, y, 1), a_MyMeta)) ||
|
||||||
|
(IsAnyFluidBlock(a_Area.GetRelBlockType(1, y, 0)) && IsHigherMeta(a_Area.GetRelBlockMeta(1, y, 0), a_MyMeta)) ||
|
||||||
|
(IsAnyFluidBlock(a_Area.GetRelBlockType(1, y, 2)) && IsHigherMeta(a_Area.GetRelBlockMeta(1, y, 2), a_MyMeta))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If not fed, decrease by m_Falloff levels:
|
||||||
|
if (!IsFed)
|
||||||
|
{
|
||||||
|
a_MyMeta += m_Falloff;
|
||||||
|
if (a_MyMeta < 8)
|
||||||
|
{
|
||||||
|
m_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, m_StationaryFluidBlock, a_MyMeta);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cFloodyFluidSimulator::SpreadToNeighbor(int a_BlockX, int a_BlockY, int a_BlockZ, const cBlockArea & a_Area, NIBBLETYPE a_NewMeta)
|
||||||
|
{
|
||||||
|
BLOCKTYPE Block = a_Area.GetBlockType(a_BlockX, a_BlockY, a_BlockZ);
|
||||||
|
|
||||||
|
if (IsAnyFluidBlock(Block))
|
||||||
|
{
|
||||||
|
NIBBLETYPE Meta = a_Area.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
|
||||||
|
if (!IsHigherMeta(a_NewMeta, Meta))
|
||||||
|
{
|
||||||
|
// Don't spread there, there's already a higher level there
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!IsPassableForFluid(Block))
|
||||||
|
{
|
||||||
|
// Can't spread there
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wash away the block there, if possible:
|
||||||
|
if (CanWashAway(Block))
|
||||||
|
{
|
||||||
|
cBlockHandler * Handler = BlockHandler(Block);
|
||||||
|
if (Handler->DoesDropOnUnsuitable())
|
||||||
|
{
|
||||||
|
Handler->DropBlock(m_World, a_BlockX, a_BlockY, a_BlockZ);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spread:
|
||||||
|
LOGD("Fluid: spreading to block {%d, %d, %d}, meta %d", a_BlockX, a_BlockY, a_BlockZ, a_NewMeta);
|
||||||
|
|
||||||
|
m_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, m_FluidBlock, a_NewMeta);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
49
source/Simulator/FloodyFluidSimulator.h
Normal file
49
source/Simulator/FloodyFluidSimulator.h
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
|
||||||
|
// FloodyFluidSimulator.h
|
||||||
|
|
||||||
|
// Interfaces to the cFloodyFluidSimulator that represents a fluid simulator that tries to flood everything :)
|
||||||
|
// http://forum.mc-server.org/showthread.php?tid=565
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "DelayedFluidSimulator.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// fwd:
|
||||||
|
class cBlockArea;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class cFloodyFluidSimulator :
|
||||||
|
public cDelayedFluidSimulator
|
||||||
|
{
|
||||||
|
typedef cDelayedFluidSimulator super;
|
||||||
|
|
||||||
|
public:
|
||||||
|
cFloodyFluidSimulator(cWorld * a_World, BLOCKTYPE a_Fluid, BLOCKTYPE a_StationaryFluid, NIBBLETYPE a_Falloff, int a_TickDelay);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
NIBBLETYPE m_Falloff;
|
||||||
|
|
||||||
|
// cDelayedFluidSimulator overrides:
|
||||||
|
virtual void SimulateBlock(int a_BlockX, int a_BlockY, int a_BlockZ) override;
|
||||||
|
|
||||||
|
/// Checks tributaries, if not fed, decreases the block's level and returns true
|
||||||
|
bool CheckTributaries(int a_BlockX, int a_BlockY, int a_BlockZ, const cBlockArea & a_Area, NIBBLETYPE a_MyMeta);
|
||||||
|
|
||||||
|
/// Spreads into the specified block, if the block there allows. a_Area is for checking.
|
||||||
|
void SpreadToNeighbor(int a_BlockX, int a_BlockY, int a_BlockZ, const cBlockArea & a_Area, NIBBLETYPE a_NewMeta);
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -19,14 +19,9 @@ cFluidSimulator::cFluidSimulator(cWorld * a_World, BLOCKTYPE a_Fluid, BLOCKTYPE
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cFluidSimulator::IsPassableForFluid(BLOCKTYPE a_BlockType)
|
bool cFluidSimulator::IsAllowedBlock(BLOCKTYPE a_BlockType)
|
||||||
{
|
{
|
||||||
return (
|
return ((a_BlockType == m_FluidBlock) || (a_BlockType == m_StationaryFluidBlock));
|
||||||
(a_BlockType == E_BLOCK_AIR) ||
|
|
||||||
(a_BlockType == E_BLOCK_FIRE) ||
|
|
||||||
IsAllowedBlock(a_BlockType) ||
|
|
||||||
CanWashAway(a_BlockType)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -65,6 +60,52 @@ bool cFluidSimulator::IsSolidBlock(BLOCKTYPE a_BlockType)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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::IsHigherMeta(NIBBLETYPE a_Meta1, NIBBLETYPE a_Meta2)
|
||||||
|
{
|
||||||
|
if (a_Meta1 == 0)
|
||||||
|
{
|
||||||
|
// Source block is higher than anything, even itself.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if ((a_Meta1 & 0x08) != 0)
|
||||||
|
{
|
||||||
|
// Falling fluid is higher than anything, including self
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a_Meta2 == 0)
|
||||||
|
{
|
||||||
|
// Second block is a source and first block isn't
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((a_Meta2 & 0x08) != 0)
|
||||||
|
{
|
||||||
|
// Second block is falling and the first one is neither a source nor falling
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// All special cases have been handled, now it's just a raw comparison:
|
||||||
|
return (a_Meta1 < a_Meta2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// TODO Not working very well yet :s
|
// TODO Not working very well yet :s
|
||||||
Direction cFluidSimulator::GetFlowingDirection(int a_X, int a_Y, int a_Z, bool a_Over)
|
Direction cFluidSimulator::GetFlowingDirection(int a_X, int a_Y, int a_Z, bool a_Over)
|
||||||
{
|
{
|
||||||
|
@ -30,17 +30,24 @@ class cFluidSimulator :
|
|||||||
public:
|
public:
|
||||||
cFluidSimulator(cWorld * a_World, BLOCKTYPE a_Fluid, BLOCKTYPE a_StationaryFluid);
|
cFluidSimulator(cWorld * a_World, BLOCKTYPE a_Fluid, BLOCKTYPE a_StationaryFluid);
|
||||||
|
|
||||||
|
// cSimulator overrides:
|
||||||
|
virtual bool IsAllowedBlock(BLOCKTYPE a_BlockType) override;
|
||||||
|
|
||||||
/// Gets the flowing direction. If a_Over is true also the block over the current block affects the direction (standard)
|
/// 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);
|
virtual Direction GetFlowingDirection(int a_X, int a_Y, int a_Z, bool a_Over = true);
|
||||||
|
|
||||||
bool IsFluidBlock (BLOCKTYPE a_BlockType) const { return (a_BlockType == m_FluidBlock); }
|
bool IsFluidBlock (BLOCKTYPE a_BlockType) const { return (a_BlockType == m_FluidBlock); }
|
||||||
bool IsStationaryFluidBlock(BLOCKTYPE a_BlockType) const { return (a_BlockType == m_StationaryFluidBlock); }
|
bool IsStationaryFluidBlock(BLOCKTYPE a_BlockType) const { return (a_BlockType == m_StationaryFluidBlock); }
|
||||||
|
bool IsAnyFluidBlock (BLOCKTYPE a_BlockType) const { return ((a_BlockType == m_FluidBlock) || (a_BlockType == m_StationaryFluidBlock)); }
|
||||||
|
|
||||||
static bool CanWashAway(BLOCKTYPE a_BlockType);
|
static bool CanWashAway(BLOCKTYPE a_BlockType);
|
||||||
|
|
||||||
bool IsSolidBlock (BLOCKTYPE a_BlockType);
|
bool IsSolidBlock (BLOCKTYPE a_BlockType);
|
||||||
bool IsPassableForFluid(BLOCKTYPE a_BlockType);
|
bool IsPassableForFluid(BLOCKTYPE a_BlockType);
|
||||||
|
|
||||||
|
/// Returns true if a_Meta1 is a higher fluid than a_Meta2. Takes source blocks into account.
|
||||||
|
bool IsHigherMeta(NIBBLETYPE a_Meta1, NIBBLETYPE a_Meta2);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
BLOCKTYPE m_FluidBlock; // The fluid block type that needs simulating
|
BLOCKTYPE m_FluidBlock; // The fluid block type that needs simulating
|
||||||
BLOCKTYPE m_StationaryFluidBlock; // The fluid block type that indicates no simulation is needed
|
BLOCKTYPE m_StationaryFluidBlock; // The fluid block type that indicates no simulation is needed
|
||||||
|
@ -28,6 +28,7 @@ public:
|
|||||||
virtual bool IsAllowedBlock(BLOCKTYPE a_BlockType) = 0;
|
virtual bool IsAllowedBlock(BLOCKTYPE a_BlockType) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
/// Called to simulate a new block
|
||||||
virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ) = 0;
|
virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ) = 0;
|
||||||
|
|
||||||
cWorld * m_World;
|
cWorld * m_World;
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
// Simulators:
|
// Simulators:
|
||||||
#include "Simulator/SimulatorManager.h"
|
#include "Simulator/SimulatorManager.h"
|
||||||
#include "Simulator/ClassicFluidSimulator.h"
|
#include "Simulator/ClassicFluidSimulator.h"
|
||||||
|
#include "Simulator/FloodyFluidSimulator.h"
|
||||||
#include "Simulator/FluidSimulator.h"
|
#include "Simulator/FluidSimulator.h"
|
||||||
#include "Simulator/FireSimulator.h"
|
#include "Simulator/FireSimulator.h"
|
||||||
#include "Simulator/SandSimulator.h"
|
#include "Simulator/SandSimulator.h"
|
||||||
@ -252,15 +253,10 @@ cWorld::cWorld( const AString & a_WorldName )
|
|||||||
m_IsPumpkinBonemealable = IniFile.GetValueSetB("Plants", "IsPumpkinBonemealable", false);
|
m_IsPumpkinBonemealable = IniFile.GetValueSetB("Plants", "IsPumpkinBonemealable", false);
|
||||||
m_IsSugarcaneBonemealable = IniFile.GetValueSetB("Plants", "IsSugarcaneBonemealable", false);
|
m_IsSugarcaneBonemealable = IniFile.GetValueSetB("Plants", "IsSugarcaneBonemealable", false);
|
||||||
m_IsCactusBonemealable = IniFile.GetValueSetB("Plants", "IsCactusBonemealable", false);
|
m_IsCactusBonemealable = IniFile.GetValueSetB("Plants", "IsCactusBonemealable", false);
|
||||||
m_bEnabledPVP = IniFile.GetValueSetB("PVP", "Enabled", true);
|
m_bEnabledPVP = IniFile.GetValueSetB("PVP", "Enabled", true);
|
||||||
|
|
||||||
m_GameMode = (eGameMode)IniFile.GetValueSetI("GameMode", "GameMode", m_GameMode );
|
m_GameMode = (eGameMode)IniFile.GetValueSetI("GameMode", "GameMode", m_GameMode );
|
||||||
|
|
||||||
if (!IniFile.WriteFile())
|
|
||||||
{
|
|
||||||
LOG("WARNING: Could not write to %s", m_IniFileName.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
m_Lighting.Start(this);
|
m_Lighting.Start(this);
|
||||||
m_Storage.Start(this, StorageSchema);
|
m_Storage.Start(this, StorageSchema);
|
||||||
m_Generator.Start(this, IniFile);
|
m_Generator.Start(this, IniFile);
|
||||||
@ -286,7 +282,7 @@ cWorld::cWorld( const AString & a_WorldName )
|
|||||||
m_LastSave = 0;
|
m_LastSave = 0;
|
||||||
m_LastUnload = 0;
|
m_LastUnload = 0;
|
||||||
|
|
||||||
//preallocate some memory for ticking blocks so we don´t need to allocate that often
|
// preallocate some memory for ticking blocks so we don´t need to allocate that often
|
||||||
m_BlockTickQueue.reserve(1000);
|
m_BlockTickQueue.reserve(1000);
|
||||||
m_BlockTickQueueCopy.reserve(1000);
|
m_BlockTickQueueCopy.reserve(1000);
|
||||||
|
|
||||||
@ -303,6 +299,12 @@ cWorld::cWorld( const AString & a_WorldName )
|
|||||||
m_SimulatorManager->RegisterSimulator(m_SandSimulator, 1);
|
m_SimulatorManager->RegisterSimulator(m_SandSimulator, 1);
|
||||||
m_SimulatorManager->RegisterSimulator(m_FireSimulator, 10);
|
m_SimulatorManager->RegisterSimulator(m_FireSimulator, 10);
|
||||||
m_SimulatorManager->RegisterSimulator(m_RedstoneSimulator, 1);
|
m_SimulatorManager->RegisterSimulator(m_RedstoneSimulator, 1);
|
||||||
|
|
||||||
|
// Save any changes that the defaults may have done to the ini file:
|
||||||
|
if (!IniFile.WriteFile())
|
||||||
|
{
|
||||||
|
LOG("WARNING: Could not write to %s", m_IniFileName.c_str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2161,7 +2163,7 @@ cFluidSimulator * cWorld::InitializeFluidSimulator(cIniFile & a_IniFile, const c
|
|||||||
Printf(SimulatorNameKey, "%sSimulator", a_FluidName);
|
Printf(SimulatorNameKey, "%sSimulator", a_FluidName);
|
||||||
AString SimulatorSectionName;
|
AString SimulatorSectionName;
|
||||||
Printf(SimulatorSectionName, "%sSimulator", a_FluidName);
|
Printf(SimulatorSectionName, "%sSimulator", a_FluidName);
|
||||||
AString SimulatorName = a_IniFile.GetValue("Physics", SimulatorNameKey, "");
|
AString SimulatorName = a_IniFile.GetValueSet("Physics", SimulatorNameKey, "");
|
||||||
if (SimulatorName.empty())
|
if (SimulatorName.empty())
|
||||||
{
|
{
|
||||||
LOGWARNING("%s [Physics]:%s not present or empty, using the default of \"Classic\".", GetIniFileName().c_str(), SimulatorNameKey.c_str());
|
LOGWARNING("%s [Physics]:%s not present or empty, using the default of \"Classic\".", GetIniFileName().c_str(), SimulatorNameKey.c_str());
|
||||||
@ -2169,15 +2171,13 @@ cFluidSimulator * cWorld::InitializeFluidSimulator(cIniFile & a_IniFile, const c
|
|||||||
}
|
}
|
||||||
|
|
||||||
cFluidSimulator * res = NULL;
|
cFluidSimulator * res = NULL;
|
||||||
/*
|
|
||||||
// TODO: other fluid simulators
|
// TODO: other fluid simulators
|
||||||
if (NoCaseCompare(SimulatorName, "floody") == 0)
|
if (NoCaseCompare(SimulatorName, "floody") == 0)
|
||||||
{
|
{
|
||||||
// TODO: Floody simulator params
|
// TODO: Floody simulator params
|
||||||
res = new cFloodyFluidSimulator(this, a_SimulateBlock, a_StationaryBlock);
|
res = new cFloodyFluidSimulator(this, a_SimulateBlock, a_StationaryBlock, 1, 5);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
*/
|
|
||||||
{
|
{
|
||||||
if (NoCaseCompare(SimulatorName, "classic") != 0)
|
if (NoCaseCompare(SimulatorName, "classic") != 0)
|
||||||
{
|
{
|
||||||
@ -2186,8 +2186,8 @@ cFluidSimulator * cWorld::InitializeFluidSimulator(cIniFile & a_IniFile, const c
|
|||||||
}
|
}
|
||||||
int DefaultFalloff = (strcmp(a_FluidName, "Water") == 0) ? 1 : 2;
|
int DefaultFalloff = (strcmp(a_FluidName, "Water") == 0) ? 1 : 2;
|
||||||
int DefaultMaxHeight = (strcmp(a_FluidName, "Water") == 0) ? 7 : 6;
|
int DefaultMaxHeight = (strcmp(a_FluidName, "Water") == 0) ? 7 : 6;
|
||||||
int Falloff = a_IniFile.GetValueI(SimulatorSectionName, "Falloff", DefaultFalloff);
|
int Falloff = a_IniFile.GetValueSetI(SimulatorSectionName, "Falloff", DefaultFalloff);
|
||||||
int MaxHeight = a_IniFile.GetValueI(SimulatorSectionName, "MaxHeight", DefaultMaxHeight);
|
int MaxHeight = a_IniFile.GetValueSetI(SimulatorSectionName, "MaxHeight", DefaultMaxHeight);
|
||||||
res = new cClassicFluidSimulator(this, a_SimulateBlock, a_StationaryBlock, MaxHeight, Falloff);
|
res = new cClassicFluidSimulator(this, a_SimulateBlock, a_StationaryBlock, MaxHeight, Falloff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user