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