1
0

Implemented vanilla-like fluid simulator

This commit is contained in:
andrew
2014-03-05 15:54:38 +02:00
parent d25e4d4179
commit 1ea17c0a75
6 changed files with 238 additions and 17 deletions

View File

@@ -86,7 +86,12 @@ void cFloodyFluidSimulator::SimulateBlock(cChunk * a_Chunk, int a_RelX, int a_Re
{
// Spread only down, possibly washing away what's there or turning lava to stone / cobble / obsidian:
SpreadToNeighbor(a_Chunk, a_RelX, a_RelY - 1, a_RelZ, 8);
SpreadFurther = false;
// Source blocks spread both downwards and sideways
if (MyMeta != 0)
{
SpreadFurther = false;
}
}
// If source creation is on, check for it here:
else if (
@@ -105,10 +110,7 @@ void cFloodyFluidSimulator::SimulateBlock(cChunk * a_Chunk, int a_RelX, int a_Re
if (SpreadFurther && (NewMeta < 8))
{
// Spread to the neighbors:
SpreadToNeighbor(a_Chunk, a_RelX - 1, a_RelY, a_RelZ, NewMeta);
SpreadToNeighbor(a_Chunk, a_RelX + 1, a_RelY, a_RelZ, NewMeta);
SpreadToNeighbor(a_Chunk, a_RelX, a_RelY, a_RelZ - 1, NewMeta);
SpreadToNeighbor(a_Chunk, a_RelX, a_RelY, a_RelZ + 1, NewMeta);
Spread(a_Chunk, a_RelX, a_RelY, a_RelZ, NewMeta);
}
// Mark as processed:
@@ -119,6 +121,17 @@ void cFloodyFluidSimulator::SimulateBlock(cChunk * a_Chunk, int a_RelX, int a_Re
void cFloodyFluidSimulator::Spread(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta)
{
SpreadToNeighbor(a_Chunk, a_RelX - 1, a_RelY, a_RelZ, a_NewMeta);
SpreadToNeighbor(a_Chunk, a_RelX + 1, a_RelY, a_RelZ, a_NewMeta);
SpreadToNeighbor(a_Chunk, a_RelX, a_RelY, a_RelZ - 1, a_NewMeta);
SpreadToNeighbor(a_Chunk, a_RelX, a_RelY, a_RelZ + 1, a_NewMeta);
}
bool cFloodyFluidSimulator::CheckTributaries(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_MyMeta)
{
// If we have a section above, check if there's fluid above this block that would feed it:

View File

@@ -38,14 +38,20 @@ protected:
// cDelayedFluidSimulator overrides:
virtual void SimulateBlock(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override;
/// Checks tributaries, if not fed, decreases the block's level and returns true
/** Checks tributaries, if not fed, decreases the block's level and returns true. */
bool CheckTributaries(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_MyMeta);
/// Spreads into the specified block, if the blocktype there allows. a_Area is for checking.
/** Spreads into the specified block, if the blocktype there allows. a_Area is for checking. */
void SpreadToNeighbor(cChunk * a_NearChunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta);
/// Checks if there are enough neighbors to create a source at the coords specified; turns into source and returns true if so
/** Checks if there are enough neighbors to create a source at the coords specified; turns into source and returns true if so. */
bool CheckNeighborsForSource(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ);
/** Spread water to neighbors.
*
* May be overridden to provide more sophisticated algorithms.
*/
virtual void Spread(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta);
} ;

View File

@@ -0,0 +1,150 @@
// 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)
{
}
void cVanillaFluidSimulator::Spread(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta)
{
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);
int MinCost = InfiniteCost;
for (unsigned int i = 0; i < ARRAYCOUNT(Cost); ++i)
{
if (Cost[i] < MinCost)
{
MinCost = Cost[i];
}
}
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;
}
if (!IsPassableForFluid(BlockType))
{
return Cost;
}
// Check if block below is passable
if (!a_Chunk->UnboundedRelGetBlock(a_RelX, a_RelY - 1, a_RelZ, BlockType, BlockMeta))
{
return Cost;
}
if (IsPassableForFluid(BlockType))
{
// Path found, exit
return a_Iteration;
}
// 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;
}

View File

@@ -0,0 +1,42 @@
// VanillaFluidSimulator.h
#pragma once
#include "FloodyFluidSimulator.h"
// fwd:
class cBlockArea;
class cVanillaFluidSimulator :
public cFloodyFluidSimulator
{
typedef cFloodyFluidSimulator super;
public:
cVanillaFluidSimulator(cWorld & a_World, BLOCKTYPE a_Fluid, BLOCKTYPE a_StationaryFluid, NIBBLETYPE a_Falloff, int a_TickDelay, int a_NumNeighborsForSource);
protected:
// cFloodyFluidSimulator overrides:
virtual void Spread(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta) override;
/** Recursively calculates the minimum number of blocks needed to descend a level. */
int CalculateFlowCost(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, Direction a_Dir, unsigned a_Iteration = 0);
} ;