2014-03-05 08:54:38 -05:00
|
|
|
|
|
|
|
// VanillaFluidSimulator.cpp
|
|
|
|
|
|
|
|
#include "Globals.h"
|
|
|
|
|
|
|
|
#include "VanillaFluidSimulator.h"
|
|
|
|
#include "../World.h"
|
|
|
|
#include "../Chunk.h"
|
|
|
|
#include "../BlockArea.h"
|
|
|
|
#include "../Blocks/BlockHandler.h"
|
|
|
|
#include "../BlockInServerPluginInterface.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static const int InfiniteCost = 100;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cVanillaFluidSimulator::cVanillaFluidSimulator(
|
|
|
|
cWorld & a_World,
|
|
|
|
BLOCKTYPE a_Fluid,
|
|
|
|
BLOCKTYPE a_StationaryFluid,
|
|
|
|
NIBBLETYPE a_Falloff,
|
|
|
|
int a_TickDelay,
|
|
|
|
int a_NumNeighborsForSource
|
|
|
|
) : super(a_World, a_Fluid, a_StationaryFluid, a_Falloff, a_TickDelay, a_NumNeighborsForSource)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-05-02 16:07:30 -04:00
|
|
|
void cVanillaFluidSimulator::SpreadXZ(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta)
|
2014-03-05 08:54:38 -05:00
|
|
|
{
|
2014-05-02 16:07:30 -04:00
|
|
|
// Calculate the distance to the nearest "hole" in each direction:
|
2014-03-05 08:54:38 -05:00
|
|
|
int Cost[4];
|
|
|
|
Cost[0] = CalculateFlowCost(a_Chunk, a_RelX + 1, a_RelY, a_RelZ, X_PLUS);
|
|
|
|
Cost[1] = CalculateFlowCost(a_Chunk, a_RelX - 1, a_RelY, a_RelZ, X_MINUS);
|
|
|
|
Cost[2] = CalculateFlowCost(a_Chunk, a_RelX, a_RelY, a_RelZ + 1, Z_PLUS);
|
|
|
|
Cost[3] = CalculateFlowCost(a_Chunk, a_RelX, a_RelY, a_RelZ - 1, Z_MINUS);
|
|
|
|
|
2014-05-02 16:07:30 -04:00
|
|
|
// Find the minimum distance:
|
2014-03-05 08:54:38 -05:00
|
|
|
int MinCost = InfiniteCost;
|
|
|
|
for (unsigned int i = 0; i < ARRAYCOUNT(Cost); ++i)
|
|
|
|
{
|
|
|
|
if (Cost[i] < MinCost)
|
|
|
|
{
|
|
|
|
MinCost = Cost[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-02 16:07:30 -04:00
|
|
|
// Spread in all directions where the distance matches the minimum:
|
2014-03-05 08:54:38 -05:00
|
|
|
if (Cost[0] == MinCost)
|
|
|
|
{
|
|
|
|
SpreadToNeighbor(a_Chunk, a_RelX + 1, a_RelY, a_RelZ, a_NewMeta);
|
|
|
|
}
|
|
|
|
if (Cost[1] == MinCost)
|
|
|
|
{
|
|
|
|
SpreadToNeighbor(a_Chunk, a_RelX - 1, a_RelY, a_RelZ, a_NewMeta);
|
|
|
|
}
|
|
|
|
if (Cost[2] == MinCost)
|
|
|
|
{
|
|
|
|
SpreadToNeighbor(a_Chunk, a_RelX, a_RelY, a_RelZ + 1, a_NewMeta);
|
|
|
|
}
|
|
|
|
if (Cost[3] == MinCost)
|
|
|
|
{
|
|
|
|
SpreadToNeighbor(a_Chunk, a_RelX, a_RelY, a_RelZ - 1, a_NewMeta);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int cVanillaFluidSimulator::CalculateFlowCost(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, Direction a_Dir, unsigned a_Iteration)
|
|
|
|
{
|
|
|
|
int Cost = InfiniteCost;
|
|
|
|
|
|
|
|
BLOCKTYPE BlockType;
|
|
|
|
NIBBLETYPE BlockMeta;
|
|
|
|
|
|
|
|
// Check if block is passable
|
|
|
|
if (!a_Chunk->UnboundedRelGetBlock(a_RelX, a_RelY, a_RelZ, BlockType, BlockMeta))
|
|
|
|
{
|
|
|
|
return Cost;
|
|
|
|
}
|
2014-05-02 16:07:30 -04:00
|
|
|
if (
|
|
|
|
!IsPassableForFluid(BlockType) || // The block cannot be passed by the liquid ...
|
|
|
|
(IsAllowedBlock(BlockType) && (BlockMeta == 0)) // ... or if it is liquid, it is a source block
|
|
|
|
)
|
2014-03-05 08:54:38 -05:00
|
|
|
{
|
|
|
|
return Cost;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if block below is passable
|
2014-08-29 07:58:41 -04:00
|
|
|
if ((a_RelY > 0) && !a_Chunk->UnboundedRelGetBlock(a_RelX, a_RelY - 1, a_RelZ, BlockType, BlockMeta))
|
2014-03-05 08:54:38 -05:00
|
|
|
{
|
|
|
|
return Cost;
|
|
|
|
}
|
2014-05-03 13:23:59 -04:00
|
|
|
if (IsPassableForFluid(BlockType) || IsBlockLiquid(BlockType))
|
2014-03-05 08:54:38 -05:00
|
|
|
{
|
|
|
|
// Path found, exit
|
2015-05-19 14:32:10 -04:00
|
|
|
return static_cast<int>(a_Iteration);
|
2014-03-05 08:54:38 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// 5 blocks away, bail out
|
|
|
|
if (a_Iteration > 3)
|
|
|
|
{
|
|
|
|
return Cost;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Recurse
|
|
|
|
if (a_Dir != X_MINUS)
|
|
|
|
{
|
|
|
|
int NextCost = CalculateFlowCost(a_Chunk, a_RelX + 1, a_RelY, a_RelZ, X_PLUS, a_Iteration + 1);
|
|
|
|
if (NextCost < Cost)
|
|
|
|
{
|
|
|
|
Cost = NextCost;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (a_Dir != X_PLUS)
|
|
|
|
{
|
|
|
|
int NextCost = CalculateFlowCost(a_Chunk, a_RelX - 1, a_RelY, a_RelZ, X_MINUS, a_Iteration + 1);
|
|
|
|
if (NextCost < Cost)
|
|
|
|
{
|
|
|
|
Cost = NextCost;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (a_Dir != Z_MINUS)
|
|
|
|
{
|
|
|
|
int NextCost = CalculateFlowCost(a_Chunk, a_RelX, a_RelY, a_RelZ + 1, Z_PLUS, a_Iteration + 1);
|
|
|
|
if (NextCost < Cost)
|
|
|
|
{
|
|
|
|
Cost = NextCost;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (a_Dir != Z_PLUS)
|
|
|
|
{
|
|
|
|
int NextCost = CalculateFlowCost(a_Chunk, a_RelX, a_RelY, a_RelZ - 1, Z_MINUS, a_Iteration + 1);
|
|
|
|
if (NextCost < Cost)
|
|
|
|
{
|
|
|
|
Cost = NextCost;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Cost;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|