Implemented vanilla-like fluid simulator
This commit is contained in:
parent
d25e4d4179
commit
1ea17c0a75
@ -506,7 +506,7 @@ bool cScoreboard::ForEachObjective(cObjectiveCallback& a_Callback)
|
|||||||
|
|
||||||
bool cScoreboard::ForEachTeam(cTeamCallback& a_Callback)
|
bool cScoreboard::ForEachTeam(cTeamCallback& a_Callback)
|
||||||
{
|
{
|
||||||
cCSLock Lock(m_CSObjectives);
|
cCSLock Lock(m_CSTeams);
|
||||||
|
|
||||||
for (cTeamMap::iterator it = m_Teams.begin(); it != m_Teams.end(); ++it)
|
for (cTeamMap::iterator it = m_Teams.begin(); it != m_Teams.end(); ++it)
|
||||||
{
|
{
|
||||||
|
@ -86,8 +86,13 @@ 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:
|
// 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);
|
SpreadToNeighbor(a_Chunk, a_RelX, a_RelY - 1, a_RelZ, 8);
|
||||||
|
|
||||||
|
// Source blocks spread both downwards and sideways
|
||||||
|
if (MyMeta != 0)
|
||||||
|
{
|
||||||
SpreadFurther = false;
|
SpreadFurther = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// If source creation is on, check for it here:
|
// If source creation is on, check for it here:
|
||||||
else if (
|
else if (
|
||||||
(m_NumNeighborsForSource > 0) && // Source creation is on
|
(m_NumNeighborsForSource > 0) && // Source creation is on
|
||||||
@ -105,10 +110,7 @@ void cFloodyFluidSimulator::SimulateBlock(cChunk * a_Chunk, int a_RelX, int a_Re
|
|||||||
if (SpreadFurther && (NewMeta < 8))
|
if (SpreadFurther && (NewMeta < 8))
|
||||||
{
|
{
|
||||||
// Spread to the neighbors:
|
// Spread to the neighbors:
|
||||||
SpreadToNeighbor(a_Chunk, a_RelX - 1, a_RelY, a_RelZ, NewMeta);
|
Spread(a_Chunk, a_RelX, 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark as processed:
|
// 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)
|
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:
|
// If we have a section above, check if there's fluid above this block that would feed it:
|
||||||
|
@ -38,14 +38,20 @@ protected:
|
|||||||
// cDelayedFluidSimulator overrides:
|
// cDelayedFluidSimulator overrides:
|
||||||
virtual void SimulateBlock(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override;
|
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);
|
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);
|
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);
|
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);
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
150
src/Simulator/VanillaFluidSimulator.cpp
Normal file
150
src/Simulator/VanillaFluidSimulator.cpp
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
42
src/Simulator/VanillaFluidSimulator.h
Normal file
42
src/Simulator/VanillaFluidSimulator.h
Normal 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);
|
||||||
|
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -34,6 +34,7 @@
|
|||||||
#include "Simulator/NoopRedstoneSimulator.h"
|
#include "Simulator/NoopRedstoneSimulator.h"
|
||||||
#include "Simulator/SandSimulator.h"
|
#include "Simulator/SandSimulator.h"
|
||||||
#include "Simulator/IncrementalRedstoneSimulator.h"
|
#include "Simulator/IncrementalRedstoneSimulator.h"
|
||||||
|
#include "Simulator/VanillaFluidSimulator.h"
|
||||||
#include "Simulator/VaporizeFluidSimulator.h"
|
#include "Simulator/VaporizeFluidSimulator.h"
|
||||||
|
|
||||||
// Mobs:
|
// Mobs:
|
||||||
@ -2987,8 +2988,8 @@ cFluidSimulator * cWorld::InitializeFluidSimulator(cIniFile & a_IniFile, const c
|
|||||||
AString SimulatorName = a_IniFile.GetValueSet("Physics", SimulatorNameKey, "");
|
AString SimulatorName = a_IniFile.GetValueSet("Physics", SimulatorNameKey, "");
|
||||||
if (SimulatorName.empty())
|
if (SimulatorName.empty())
|
||||||
{
|
{
|
||||||
LOGWARNING("[Physics] %s not present or empty in %s, using the default of \"Floody\".", SimulatorNameKey.c_str(), GetIniFileName().c_str());
|
LOGWARNING("[Physics] %s not present or empty in %s, using the default of \"Vanilla\".", SimulatorNameKey.c_str(), GetIniFileName().c_str());
|
||||||
SimulatorName = "Floody";
|
SimulatorName = "Vanilla";
|
||||||
}
|
}
|
||||||
|
|
||||||
cFluidSimulator * res = NULL;
|
cFluidSimulator * res = NULL;
|
||||||
@ -3012,16 +3013,25 @@ cFluidSimulator * cWorld::InitializeFluidSimulator(cIniFile & a_IniFile, const c
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (NoCaseCompare(SimulatorName, "floody") != 0)
|
|
||||||
{
|
|
||||||
// The simulator name doesn't match anything we have, issue a warning:
|
|
||||||
LOGWARNING("%s [Physics]:%s specifies an unknown simulator, using the default \"Floody\".", GetIniFileName().c_str(), SimulatorNameKey.c_str());
|
|
||||||
}
|
|
||||||
int Falloff = a_IniFile.GetValueSetI(SimulatorSectionName, "Falloff", IsWater ? 1 : 2);
|
int Falloff = a_IniFile.GetValueSetI(SimulatorSectionName, "Falloff", IsWater ? 1 : 2);
|
||||||
int TickDelay = a_IniFile.GetValueSetI(SimulatorSectionName, "TickDelay", IsWater ? 5 : 30);
|
int TickDelay = a_IniFile.GetValueSetI(SimulatorSectionName, "TickDelay", IsWater ? 5 : 30);
|
||||||
int NumNeighborsForSource = a_IniFile.GetValueSetI(SimulatorSectionName, "NumNeighborsForSource", IsWater ? 2 : -1);
|
int NumNeighborsForSource = a_IniFile.GetValueSetI(SimulatorSectionName, "NumNeighborsForSource", IsWater ? 2 : -1);
|
||||||
|
|
||||||
|
if (NoCaseCompare(SimulatorName, "floody") == 0)
|
||||||
|
{
|
||||||
res = new cFloodyFluidSimulator(*this, a_SimulateBlock, a_StationaryBlock, Falloff, TickDelay, NumNeighborsForSource);
|
res = new cFloodyFluidSimulator(*this, a_SimulateBlock, a_StationaryBlock, Falloff, TickDelay, NumNeighborsForSource);
|
||||||
}
|
}
|
||||||
|
else if (NoCaseCompare(SimulatorName, "vanilla") == 0)
|
||||||
|
{
|
||||||
|
res = new cVanillaFluidSimulator(*this, a_SimulateBlock, a_StationaryBlock, Falloff, TickDelay, NumNeighborsForSource);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// The simulator name doesn't match anything we have, issue a warning:
|
||||||
|
LOGWARNING("%s [Physics]:%s specifies an unknown simulator, using the default \"Vanilla\".", GetIniFileName().c_str(), SimulatorNameKey.c_str());
|
||||||
|
res = new cVanillaFluidSimulator(*this, a_SimulateBlock, a_StationaryBlock, Falloff, TickDelay, NumNeighborsForSource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
m_SimulatorManager->RegisterSimulator(res, Rate);
|
m_SimulatorManager->RegisterSimulator(res, Rate);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user