Cuberite
A lightweight, fast and extensible game server for Minecraft
VanillaFluidSimulator.cpp
Go to the documentation of this file.
1 
2 // VanillaFluidSimulator.cpp
3 
4 #include "Globals.h"
5 
7 #include "../World.h"
8 #include "../Chunk.h"
9 #include "../BlockArea.h"
10 #include "../Blocks/BlockHandler.h"
11 #include "../BlockInServerPluginInterface.h"
12 
13 
14 
15 
16 
17 static const int InfiniteCost = 100;
18 
19 
20 
21 
22 
24  cWorld & a_World,
25  BLOCKTYPE a_Fluid,
26  BLOCKTYPE a_StationaryFluid,
27  NIBBLETYPE a_Falloff,
28  int a_TickDelay,
29  int a_NumNeighborsForSource
30 ) : super(a_World, a_Fluid, a_StationaryFluid, a_Falloff, a_TickDelay, a_NumNeighborsForSource)
31 {
32 }
33 
34 
35 
36 
37 
38 void cVanillaFluidSimulator::SpreadXZ(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta)
39 {
40  // Calculate the distance to the nearest "hole" in each direction:
41  int Cost[4];
42  Cost[0] = CalculateFlowCost(a_Chunk, a_RelX + 1, a_RelY, a_RelZ, X_PLUS);
43  Cost[1] = CalculateFlowCost(a_Chunk, a_RelX - 1, a_RelY, a_RelZ, X_MINUS);
44  Cost[2] = CalculateFlowCost(a_Chunk, a_RelX, a_RelY, a_RelZ + 1, Z_PLUS);
45  Cost[3] = CalculateFlowCost(a_Chunk, a_RelX, a_RelY, a_RelZ - 1, Z_MINUS);
46 
47  // Find the minimum distance:
48  int MinCost = InfiniteCost;
49  for (unsigned int i = 0; i < ARRAYCOUNT(Cost); ++i)
50  {
51  if (Cost[i] < MinCost)
52  {
53  MinCost = Cost[i];
54  }
55  }
56 
57  // Spread in all directions where the distance matches the minimum:
58  if (Cost[0] == MinCost)
59  {
60  SpreadToNeighbor(a_Chunk, a_RelX + 1, a_RelY, a_RelZ, a_NewMeta);
61  }
62  if (Cost[1] == MinCost)
63  {
64  SpreadToNeighbor(a_Chunk, a_RelX - 1, a_RelY, a_RelZ, a_NewMeta);
65  }
66  if (Cost[2] == MinCost)
67  {
68  SpreadToNeighbor(a_Chunk, a_RelX, a_RelY, a_RelZ + 1, a_NewMeta);
69  }
70  if (Cost[3] == MinCost)
71  {
72  SpreadToNeighbor(a_Chunk, a_RelX, a_RelY, a_RelZ - 1, a_NewMeta);
73  }
74 }
75 
76 
77 
78 
79 
80 int cVanillaFluidSimulator::CalculateFlowCost(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, Direction a_Dir, unsigned a_Iteration)
81 {
82  int Cost = InfiniteCost;
83 
84  BLOCKTYPE BlockType;
85  NIBBLETYPE BlockMeta;
86 
87  // Check if block is passable
88  if (!a_Chunk->UnboundedRelGetBlock(a_RelX, a_RelY, a_RelZ, BlockType, BlockMeta))
89  {
90  return Cost;
91  }
92  if (
93  !IsPassableForFluid(BlockType) || // The block cannot be passed by the liquid ...
94  (IsAllowedBlock(BlockType) && (BlockMeta == 0)) // ... or if it is liquid, it is a source block
95  )
96  {
97  return Cost;
98  }
99 
100  // Check if block below is passable
101  if ((a_RelY > 0) && !a_Chunk->UnboundedRelGetBlock(a_RelX, a_RelY - 1, a_RelZ, BlockType, BlockMeta))
102  {
103  return Cost;
104  }
105  if (IsPassableForFluid(BlockType) || IsBlockLiquid(BlockType))
106  {
107  // Path found, exit
108  return static_cast<int>(a_Iteration);
109  }
110 
111  // 5 blocks away, bail out
112  if (a_Iteration > 3)
113  {
114  return Cost;
115  }
116 
117  // Recurse
118  if (a_Dir != X_MINUS)
119  {
120  int NextCost = CalculateFlowCost(a_Chunk, a_RelX + 1, a_RelY, a_RelZ, X_PLUS, a_Iteration + 1);
121  if (NextCost < Cost)
122  {
123  Cost = NextCost;
124  }
125  }
126  if (a_Dir != X_PLUS)
127  {
128  int NextCost = CalculateFlowCost(a_Chunk, a_RelX - 1, a_RelY, a_RelZ, X_MINUS, a_Iteration + 1);
129  if (NextCost < Cost)
130  {
131  Cost = NextCost;
132  }
133  }
134  if (a_Dir != Z_MINUS)
135  {
136  int NextCost = CalculateFlowCost(a_Chunk, a_RelX, a_RelY, a_RelZ + 1, Z_PLUS, a_Iteration + 1);
137  if (NextCost < Cost)
138  {
139  Cost = NextCost;
140  }
141  }
142  if (a_Dir != Z_PLUS)
143  {
144  int NextCost = CalculateFlowCost(a_Chunk, a_RelX, a_RelY, a_RelZ - 1, Z_MINUS, a_Iteration + 1);
145  if (NextCost < Cost)
146  {
147  Cost = NextCost;
148  }
149  }
150 
151  return Cost;
152 }
153 
154 
155 
156 
virtual bool IsAllowedBlock(BLOCKTYPE a_BlockType) override
Returns true if the specified block type is "interesting" for this simulator.
unsigned char BLOCKTYPE
The datatype used by blockdata.
Definition: ChunkDef.h:42
bool IsPassableForFluid(BLOCKTYPE a_BlockType)
virtual void SpreadXZ(cChunk *a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta) override
Spread fluid to XZ neighbors.
unsigned char NIBBLETYPE
The datatype used by nibbledata (meta, light, skylight)
Definition: ChunkDef.h:45
cVanillaFluidSimulator(cWorld &a_World, BLOCKTYPE a_Fluid, BLOCKTYPE a_StationaryFluid, NIBBLETYPE a_Falloff, int a_TickDelay, int a_NumNeighborsForSource)
Definition: Chunk.h:49
bool IsBlockLiquid(BLOCKTYPE a_BlockType)
Definition: Defines.h:484
Direction
Definition: World.h:65
bool UnboundedRelGetBlock(Vector3i a_RelCoords, BLOCKTYPE &a_BlockType, NIBBLETYPE &a_BlockMeta) const
Same as GetBlock(), but relative coords needn&#39;t be in this chunk (uses m_Neighbor-s or m_ChunkMap in ...
Definition: Chunk.cpp:997
void SpreadToNeighbor(cChunk *a_NearChunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta)
Spreads into the specified block, if the blocktype there allows.
static const int InfiniteCost
int CalculateFlowCost(cChunk *a_Chunk, int a_RelX, int a_RelY, int a_RelZ, Direction a_Dir, unsigned a_Iteration=0)
Recursively calculates the minimum number of blocks needed to descend a level.
#define ARRAYCOUNT(X)
Evaluates to the number of elements in an array (compile-time!)
Definition: Globals.h:290