Merge branch 'master' into awesometnt
This commit is contained in:
@@ -20,7 +20,7 @@
|
||||
bool cDelayedFluidSimulatorChunkData::cSlot::Add(int a_RelX, int a_RelY, int a_RelZ)
|
||||
{
|
||||
ASSERT(a_RelZ >= 0);
|
||||
ASSERT(a_RelZ < ARRAYCOUNT(m_Blocks));
|
||||
ASSERT(a_RelZ < static_cast<int>(ARRAYCOUNT(m_Blocks)));
|
||||
|
||||
cCoordWithIntVector & Blocks = m_Blocks[a_RelZ];
|
||||
int Index = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ);
|
||||
|
||||
@@ -54,14 +54,23 @@ void cFloodyFluidSimulator::SimulateBlock(cChunk * a_Chunk, int a_RelX, int a_Re
|
||||
a_Chunk->GetMeta(a_RelX, a_RelY, a_RelZ)
|
||||
);
|
||||
|
||||
NIBBLETYPE MyMeta = a_Chunk->GetMeta(a_RelX, a_RelY, a_RelZ);
|
||||
if (!IsAnyFluidBlock(a_Chunk->GetBlock(a_RelX, a_RelY, a_RelZ)))
|
||||
BLOCKTYPE MyBlock; NIBBLETYPE MyMeta;
|
||||
a_Chunk->GetBlockTypeMeta(a_RelX, a_RelY, a_RelZ, MyBlock, MyMeta);
|
||||
|
||||
if (!IsAnyFluidBlock(MyBlock))
|
||||
{
|
||||
// Can happen - if a block is scheduled for simulating and gets replaced in the meantime.
|
||||
FLOG(" BadBlockType exit");
|
||||
return;
|
||||
}
|
||||
|
||||
// When in contact with water, lava should harden
|
||||
if (HardenBlock(a_Chunk, a_RelX, a_RelY, a_RelZ, MyBlock, MyMeta))
|
||||
{
|
||||
// Block was changed, bail out
|
||||
return;
|
||||
}
|
||||
|
||||
if (MyMeta != 0)
|
||||
{
|
||||
// Source blocks aren't checked for tributaries, others are.
|
||||
@@ -86,7 +95,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 +119,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 +130,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:
|
||||
@@ -296,6 +318,8 @@ void cFloodyFluidSimulator::SpreadToNeighbor(cChunk * a_NearChunk, int a_RelX, i
|
||||
a_NewMeta
|
||||
);
|
||||
a_NearChunk->UnboundedRelSetBlock(a_RelX, a_RelY, a_RelZ, m_FluidBlock, a_NewMeta);
|
||||
|
||||
HardenBlock(a_NearChunk, a_RelX, a_RelY, a_RelZ, m_FluidBlock, a_NewMeta);
|
||||
}
|
||||
|
||||
|
||||
@@ -348,3 +372,56 @@ bool cFloodyFluidSimulator::CheckNeighborsForSource(cChunk * a_Chunk, int a_RelX
|
||||
|
||||
|
||||
|
||||
|
||||
bool cFloodyFluidSimulator::HardenBlock(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta)
|
||||
{
|
||||
// Only lava blocks can harden
|
||||
if (!IsBlockLava(a_BlockType))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ShouldHarden = false;
|
||||
|
||||
BLOCKTYPE BlockType;
|
||||
NIBBLETYPE BlockMeta;
|
||||
static const Vector3i Coords[] =
|
||||
{
|
||||
Vector3i( 1, 0, 0),
|
||||
Vector3i(-1, 0, 0),
|
||||
Vector3i( 0, 0, 1),
|
||||
Vector3i( 0, 0, -1),
|
||||
};
|
||||
for (size_t i = 0; i < ARRAYCOUNT(Coords); i++)
|
||||
{
|
||||
if (!a_Chunk->UnboundedRelGetBlock(a_RelX + Coords[i].x, a_RelY, a_RelZ + Coords[i].z, BlockType, BlockMeta))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (IsBlockWater(BlockType))
|
||||
{
|
||||
ShouldHarden = true;
|
||||
}
|
||||
} // for i - Coords[]
|
||||
|
||||
if (ShouldHarden)
|
||||
{
|
||||
if (a_Meta == 0)
|
||||
{
|
||||
// Source lava block
|
||||
a_Chunk->UnboundedRelSetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_OBSIDIAN, 0);
|
||||
return true;
|
||||
}
|
||||
// Ignore last lava level
|
||||
else if (a_Meta <= 4)
|
||||
{
|
||||
a_Chunk->UnboundedRelSetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_COBBLESTONE, 0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -38,14 +38,26 @@ 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);
|
||||
|
||||
/** Checks if the specified block should harden (Water/Lava interaction) and if so, converts it to a suitable block.
|
||||
*
|
||||
* Returns whether the block was changed or not.
|
||||
*/
|
||||
bool HardenBlock(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta);
|
||||
|
||||
/** 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);
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
@@ -937,17 +937,15 @@ void cIncrementalRedstoneSimulator::HandleTrapdoor(int a_BlockX, int a_BlockY, i
|
||||
{
|
||||
if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, true))
|
||||
{
|
||||
m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) | 0x4);
|
||||
m_World.BroadcastSoundParticleEffect(1003, a_BlockX, a_BlockY, a_BlockZ, 0);
|
||||
m_World.SetTrapdoorOpen(a_BlockX, a_BlockY, a_BlockZ, true);
|
||||
SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, false))
|
||||
{
|
||||
m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0xB); // Take into account that the fourth bit is needed for trapdoors too
|
||||
m_World.BroadcastSoundParticleEffect(1003, a_BlockX, a_BlockY, a_BlockZ, 0);
|
||||
m_World.SetTrapdoorOpen(a_BlockX, a_BlockY, a_BlockZ, false);
|
||||
SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, false);
|
||||
}
|
||||
}
|
||||
|
||||
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) && !IsBlockLiquid(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) || IsBlockLiquid(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);
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user