Cuberite
A lightweight, fast and extensible game server for Minecraft
SandSimulator.cpp
Go to the documentation of this file.
1 
2 #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
3 
4 #include "SandSimulator.h"
5 #include "../BlockInfo.h"
6 #include "../World.h"
7 #include "../Defines.h"
8 #include "../Entities/FallingBlock.h"
9 #include "../Chunk.h"
10 #include "../IniFile.h"
11 #include "../EffectID.h"
12 
13 
14 
15 
16 
18  cSimulator(a_World),
19  m_TotalBlocks(0)
20 {
21  m_IsInstantFall = a_IniFile.GetValueSetB("Physics", "SandInstantFall", false);
22 }
23 
24 
25 
26 
27 
28 void cSandSimulator::SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk)
29 {
30  cSandSimulatorChunkData & ChunkData = a_Chunk->GetSandSimulatorData();
31  if (ChunkData.empty())
32  {
33  return;
34  }
35 
36  int BaseX = a_Chunk->GetPosX() * cChunkDef::Width;
37  int BaseZ = a_Chunk->GetPosZ() * cChunkDef::Width;
38  for (cSandSimulatorChunkData::const_iterator itr = ChunkData.begin(), end = ChunkData.end(); itr != end; ++itr)
39  {
40  BLOCKTYPE BlockType = a_Chunk->GetBlock(itr->x, itr->y, itr->z);
41  if (!IsAllowedBlock(BlockType) || (itr->y <= 0))
42  {
43  continue;
44  }
45 
46  BLOCKTYPE BlockBelow = (itr->y > 0) ? a_Chunk->GetBlock(itr->x, itr->y - 1, itr->z) : static_cast<BLOCKTYPE>(E_BLOCK_AIR);
47  if (CanStartFallingThrough(BlockBelow))
48  {
49  if (m_IsInstantFall)
50  {
51  DoInstantFall(a_Chunk, itr->x, itr->y, itr->z);
52  continue;
53  }
54  Vector3i Pos;
55  Pos.x = itr->x + BaseX;
56  Pos.y = itr->y;
57  Pos.z = itr->z + BaseZ;
58  /*
59  FLOGD(
60  "Creating a falling block at {0} of type {1}, block below: {2}",
61  Pos, ItemTypeToString(BlockType), ItemTypeToString(BlockBelow)
62  );
63  */
64 
65  m_World.SpawnFallingBlock(Pos, BlockType, a_Chunk->GetMeta(itr->x, itr->y, itr->z));
66  a_Chunk->SetBlock({itr->x, itr->y, itr->z}, E_BLOCK_AIR, 0);
67  }
68  }
69  m_TotalBlocks -= static_cast<int>(ChunkData.size());
70  ChunkData.clear();
71 }
72 
73 
74 
75 
76 
77 void cSandSimulator::AddBlock(cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_Block)
78 {
79  if (!IsAllowedBlock(a_Block))
80  {
81  return;
82  }
83 
84  // Check for duplicates:
85  cSandSimulatorChunkData & ChunkData = a_Chunk.GetSandSimulatorData();
86  for (cSandSimulatorChunkData::iterator itr = ChunkData.begin(); itr != ChunkData.end(); ++itr)
87  {
88  if ((itr->x == a_Position.x) && (itr->y == a_Position.y) && (itr->z == a_Position.z))
89  {
90  return;
91  }
92  }
93 
94  m_TotalBlocks += 1;
95  ChunkData.emplace_back(a_Position.x, a_Position.y, a_Position.z);
96 }
97 
98 
99 
100 
101 
103 {
104  // Please keep the list alpha-sorted
105  switch (a_BlockType)
106  {
107  case E_BLOCK_AIR:
108  case E_BLOCK_FIRE:
109  case E_BLOCK_LAVA:
110  case E_BLOCK_SNOW:
113  case E_BLOCK_WATER:
114  {
115  return true;
116  }
117  }
118  return false;
119 }
120 
121 
122 
123 
124 
126 {
127  // Please keep the list alpha-sorted
128  switch (a_BlockType)
129  {
130  case E_BLOCK_AIR:
131  case E_BLOCK_BEETROOTS:
133  case E_BLOCK_CARROTS:
134  case E_BLOCK_COBWEB:
135  case E_BLOCK_CROPS:
136  case E_BLOCK_DEAD_BUSH:
138  case E_BLOCK_FIRE:
139  case E_BLOCK_FLOWER_POT:
142  case E_BLOCK_LAVA:
143  case E_BLOCK_LEVER:
146  case E_BLOCK_MELON_STEM:
155  case E_BLOCK_RED_ROSE:
156  case E_BLOCK_SIGN_POST:
157  case E_BLOCK_SNOW:
163  case E_BLOCK_TALL_GRASS:
164  case E_BLOCK_TORCH:
165  case E_BLOCK_TRAPDOOR:
166  case E_BLOCK_TRIPWIRE:
168  case E_BLOCK_WALL_BANNER:
169  case E_BLOCK_WALLSIGN:
170  case E_BLOCK_WATER:
174  {
175  return true;
176  }
177  }
178  return false;
179 }
180 
181 
182 
183 
184 
186 {
187  // Please keep the list alpha-sorted
188  switch (a_BlockType)
189  {
190  case E_BLOCK_AIR:
193  case E_BLOCK_DEAD_BUSH:
194  case E_BLOCK_FIRE:
195  case E_BLOCK_LAVA:
196  case E_BLOCK_SNOW:
200  case E_BLOCK_TALL_GRASS:
201  case E_BLOCK_WATER:
202  {
203  return true;
204  }
205  }
206  return false;
207 }
208 
209 
210 
211 
212 
214 {
215  switch (a_BlockType)
216  {
217  case E_BLOCK_PURPUR_SLAB:
219  case E_BLOCK_STONE_SLAB:
220  case E_BLOCK_WOODEN_SLAB:
221  {
222  return ((a_BlockMeta & 0x08) == 0); // Only a bottom-slab breaks the block
223  }
224  }
225  return false;
226 }
227 
228 
229 
230 
231 
233  cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ,
234  BLOCKTYPE a_FallingBlockType, NIBBLETYPE a_FallingBlockMeta
235 )
236 {
237  ASSERT(a_BlockY < cChunkDef::Height);
238 
239  BLOCKTYPE CurrentBlockType = a_World->GetBlock({ a_BlockX, a_BlockY, a_BlockZ });
240  if ((a_FallingBlockType == E_BLOCK_ANVIL) || IsReplacedOnRematerialization(CurrentBlockType))
241  {
242  // Rematerialize the material here:
243  a_World->SetBlock({ a_BlockX, a_BlockY, a_BlockZ }, a_FallingBlockType, a_FallingBlockMeta);
244  if (a_FallingBlockType == E_BLOCK_ANVIL)
245  {
246  a_World->BroadcastSoundParticleEffect(EffectID::SFX_RANDOM_ANVIL_LAND, {a_BlockX, a_BlockY, a_BlockZ}, 0);
247  }
248  return;
249  }
250 
251  // Create a pickup instead:
252  cItems Pickups;
253  Pickups.Add(static_cast<ENUM_ITEM_TYPE>(a_FallingBlockType), 1, a_FallingBlockMeta);
254  a_World->SpawnItemPickups(
255  Pickups,
256  static_cast<double>(a_BlockX) + 0.5,
257  static_cast<double>(a_BlockY) + 0.5,
258  static_cast<double>(a_BlockZ) + 0.5
259  );
260 }
261 
262 
263 
264 
265 
267 {
268  switch (a_BlockType)
269  {
270  case E_BLOCK_ANVIL:
272  case E_BLOCK_DRAGON_EGG:
273  case E_BLOCK_GRAVEL:
274  case E_BLOCK_SAND:
275  {
276  return true;
277  }
278  default:
279  {
280  return false;
281  }
282  }
283 }
284 
285 
286 
287 
288 
289 void cSandSimulator::DoInstantFall(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ)
290 {
291  // Remove the original block:
292  BLOCKTYPE FallingBlockType;
293  NIBBLETYPE FallingBlockMeta;
294  a_Chunk->GetBlockTypeMeta(a_RelX, a_RelY, a_RelZ, FallingBlockType, FallingBlockMeta);
295  a_Chunk->SetBlock({a_RelX, a_RelY, a_RelZ}, E_BLOCK_AIR, 0);
296 
297  // Search for a place to put it:
298  for (int y = a_RelY - 1; y >= 0; y--)
299  {
301  NIBBLETYPE BlockMeta;
302  a_Chunk->GetBlockTypeMeta(a_RelX, y, a_RelZ, BlockType, BlockMeta);
303  int BlockY;
304  if (DoesBreakFallingThrough(BlockType, BlockMeta))
305  {
306  BlockY = y;
307  }
309  {
310  BlockY = y + 1;
311  }
312  else if ((FallingBlockType == E_BLOCK_CONCRETE_POWDER) && IsBlockWater(BlockType))
313  {
314  FallingBlockType = E_BLOCK_CONCRETE;
315  BlockY = y;
316  }
317  else
318  {
319  // Can fall further down
320  continue;
321  }
322 
323  // Finish the fall at the found bottom:
324  int BlockX = a_RelX + a_Chunk->GetPosX() * cChunkDef::Width;
325  int BlockZ = a_RelZ + a_Chunk->GetPosZ() * cChunkDef::Width;
326  FinishFalling(&m_World, BlockX, BlockY, BlockZ, FallingBlockType, FallingBlockMeta);
327  return;
328  }
329 
330  // The block just "fell off the world" without leaving a trace
331 }
332 
333 
334 
335 
bool IsBlockWater(BLOCKTYPE a_BlockType)
Definition: BlockInfo.cpp:10
@ E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE
Definition: BlockType.h:163
@ E_BLOCK_WOODEN_BUTTON
Definition: BlockType.h:158
@ E_BLOCK_CARROTS
Definition: BlockType.h:156
@ E_BLOCK_REDSTONE_TORCH_ON
Definition: BlockType.h:90
@ E_BLOCK_STONE_PRESSURE_PLATE
Definition: BlockType.h:84
@ E_BLOCK_DEAD_BUSH
Definition: BlockType.h:42
@ E_BLOCK_MELON_STEM
Definition: BlockType.h:120
@ E_BLOCK_STANDING_BANNER
Definition: BlockType.h:195
@ E_BLOCK_REDSTONE_REPEATER_ON
Definition: BlockType.h:109
@ E_BLOCK_DRAGON_EGG
Definition: BlockType.h:137
@ E_BLOCK_WATER
Definition: BlockType.h:18
@ E_BLOCK_TRAPDOOR
Definition: BlockType.h:111
@ E_BLOCK_CHORUS_PLANT
Definition: BlockType.h:218
@ E_BLOCK_STATIONARY_LAVA
Definition: BlockType.h:21
@ E_BLOCK_AIR
Definition: BlockType.h:10
@ E_BLOCK_CHORUS_FLOWER
Definition: BlockType.h:219
@ E_BLOCK_STRUCTURE_VOID
Definition: BlockType.h:236
@ E_BLOCK_SIGN_POST
Definition: BlockType.h:76
@ E_BLOCK_CROPS
Definition: BlockType.h:71
@ E_BLOCK_FIRE
Definition: BlockType.h:61
@ E_BLOCK_CONCRETE
Definition: BlockType.h:270
@ E_BLOCK_COBWEB
Definition: BlockType.h:40
@ E_BLOCK_STONE_SLAB
Definition: BlockType.h:54
@ E_BLOCK_BEETROOTS
Definition: BlockType.h:226
@ E_BLOCK_MINECART_TRACKS
Definition: BlockType.h:80
@ E_BLOCK_LEVER
Definition: BlockType.h:83
@ E_BLOCK_TRIPWIRE
Definition: BlockType.h:147
@ E_BLOCK_POWERED_RAIL
Definition: BlockType.h:37
@ E_BLOCK_YELLOW_FLOWER
Definition: BlockType.h:283
@ E_BLOCK_SNOW
Definition: BlockType.h:92
@ E_BLOCK_BROWN_MUSHROOM
Definition: BlockType.h:49
@ E_BLOCK_DETECTOR_RAIL
Definition: BlockType.h:38
@ E_BLOCK_GRAVEL
Definition: BlockType.h:23
@ E_BLOCK_REDSTONE_WIRE
Definition: BlockType.h:65
@ E_BLOCK_CONCRETE_POWDER
Definition: BlockType.h:271
@ E_BLOCK_ANVIL
Definition: BlockType.h:160
@ E_BLOCK_WOODEN_PRESSURE_PLATE
Definition: BlockType.h:86
@ E_BLOCK_RED_ROSE
Definition: BlockType.h:284
@ E_BLOCK_TORCH
Definition: BlockType.h:60
@ E_BLOCK_REDSTONE_TORCH_OFF
Definition: BlockType.h:89
@ E_BLOCK_WOODEN_SLAB
Definition: BlockType.h:141
@ E_BLOCK_RED_MUSHROOM
Definition: BlockType.h:50
@ E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE
Definition: BlockType.h:162
@ E_BLOCK_REDSTONE_REPEATER_OFF
Definition: BlockType.h:108
@ E_BLOCK_SAND
Definition: BlockType.h:22
@ E_BLOCK_IRON_TRAPDOOR
Definition: BlockType.h:186
@ E_BLOCK_STONE_BUTTON
Definition: BlockType.h:91
@ E_BLOCK_PUMPKIN_STEM
Definition: BlockType.h:119
@ E_BLOCK_FLOWER_POT
Definition: BlockType.h:155
@ E_BLOCK_TRIPWIRE_HOOK
Definition: BlockType.h:146
@ E_BLOCK_STATIONARY_WATER
Definition: BlockType.h:19
@ E_BLOCK_PURPUR_SLAB
Definition: BlockType.h:224
@ E_BLOCK_RED_SANDSTONE_SLAB
Definition: BlockType.h:201
@ E_BLOCK_WALLSIGN
Definition: BlockType.h:82
@ E_BLOCK_LAVA
Definition: BlockType.h:20
@ E_BLOCK_WALL_BANNER
Definition: BlockType.h:196
@ E_BLOCK_TALL_GRASS
Definition: BlockType.h:41
ENUM_ITEM_TYPE
Definition: BlockType.h:295
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
@ SFX_RANDOM_ANVIL_LAND
#define ASSERT(x)
Definition: Globals.h:276
BlockType
Definition: BlockTypes.h:4
cCoordWithIntList cSandSimulatorChunkData
Per-chunk data for the simulator, specified individual chunks to simulate; Data is not used.
Definition: SandSimulator.h:12
Definition: Chunk.h:36
NIBBLETYPE GetMeta(int a_RelX, int a_RelY, int a_RelZ) const
Definition: Chunk.h:279
int GetPosX(void) const
Definition: Chunk.h:131
BLOCKTYPE GetBlock(int a_RelX, int a_RelY, int a_RelZ) const
Definition: Chunk.h:146
void SetBlock(Vector3i a_RelBlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
Definition: Chunk.cpp:1263
cSandSimulatorChunkData & GetSandSimulatorData(void)
Definition: Chunk.h:415
int GetPosZ(void) const
Definition: Chunk.h:132
void GetBlockTypeMeta(Vector3i a_RelPos, BLOCKTYPE &a_BlockType, NIBBLETYPE &a_BlockMeta) const
Definition: Chunk.cpp:1757
static const int Width
Definition: ChunkDef.h:124
static const int Height
Definition: ChunkDef.h:125
bool GetValueSetB(const AString &keyname, const AString &valuename, const bool defValue=false) override
Definition: IniFile.h:150
This class bridges a vector of cItem for safe access via Lua.
Definition: Item.h:215
void Add(const cItem &a_Item)
Definition: Item.h:233
void DoInstantFall(cChunk *a_Chunk, int a_RelX, int a_RelY, int a_RelZ)
Performs the instant fall of the block - removes it from top, Finishes it at the bottom.
virtual void AddBlock(cChunk &a_Chunk, Vector3i a_Position, BLOCKTYPE a_Block) override
Called to simulate a new block.
static bool IsReplacedOnRematerialization(BLOCKTYPE a_BlockType)
Returns true if the falling block rematerializing will replace the specified block type (e.
static bool CanContinueFallThrough(BLOCKTYPE a_BlockType)
Returns true if an already-falling block can pass through the specified block type (e.
static void FinishFalling(cWorld *a_World, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_FallingBlockType, NIBBLETYPE a_FallingBlockMeta)
Called when a block finishes falling at the specified coords, either by insta-fall,...
static bool IsAllowedBlock(BLOCKTYPE a_BlockType)
static bool CanStartFallingThrough(BLOCKTYPE a_BlockType)
Returns true if a falling-able block can start falling through the specified block type.
cSandSimulator(cWorld &a_World, cIniFile &a_IniFile)
static bool DoesBreakFallingThrough(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
Returns true if the specified block breaks falling blocks while they fall through it (e.
virtual void SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, int a_ChunkZ, cChunk *a_Chunk) override
Base class for all block-based physics simulators (such as fluid, fire, falling blocks etc....
Definition: Simulator.h:22
cWorld & m_World
Definition: Simulator.h:71
T x
Definition: Vector3.h:17
T y
Definition: Vector3.h:17
T z
Definition: Vector3.h:17
Definition: World.h:53
BLOCKTYPE GetBlock(Vector3i a_BlockPos) const
Returns the block type at the specified position.
Definition: World.h:363
virtual void BroadcastSoundParticleEffect(const EffectID a_EffectID, Vector3i a_SrcPos, int a_Data, const cClientHandle *a_Exclude=nullptr) override
void SpawnItemPickups(const cItems &a_Pickups, Vector3i a_BlockPos, double a_FlyAwaySpeed=1.0, bool a_IsPlayerCreated=false)
Spawns item pickups for each item in the list.
Definition: World.cpp:1806
UInt32 SpawnFallingBlock(Vector3d a_Pos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
Spawns an falling block entity at the given position.
Definition: World.cpp:1878
void SetBlock(Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
Sets the block at the specified coords to the specified value.
Definition: World.cpp:1743