Cuberite
A lightweight, fast and extensible game server for Minecraft
ChunkMap.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 "ChunkMap.h"
5 #include "BlockInfo.h"
6 #include "World.h"
7 #include "Root.h"
8 #include "Entities/Player.h"
9 #include "Item.h"
10 #include "Chunk.h"
11 #include "Generating/Trees.h" // used in cChunkMap::ReplaceTreeBlocks() for tree block discrimination
12 #include "BlockArea.h"
13 #include "Bindings/PluginManager.h"
14 #include "Blocks/BlockHandler.h"
15 #include "MobCensus.h"
16 #include "MobSpawner.h"
17 #include "BoundingBox.h"
18 #include "SetChunkData.h"
19 #include "Blocks/ChunkInterface.h"
20 #include "Entities/Pickup.h"
21 #include "DeadlockDetect.h"
22 
23 
24 
25 
26 
28 // cChunkMap:
29 
31  m_World(a_World)
32 {
33 }
34 
35 
36 
37 
38 
39 cChunk & cChunkMap::ConstructChunk(int a_ChunkX, int a_ChunkZ)
40 {
41  // If not exists insert. Then, return the chunk at these coordinates:
42  return m_Chunks.try_emplace(
43  { a_ChunkX, a_ChunkZ },
44  a_ChunkX, a_ChunkZ, this, m_World
45  ).first->second;
46 }
47 
48 
49 
50 
51 
52 cChunk & cChunkMap::GetChunk(int a_ChunkX, int a_ChunkZ)
53 {
54  ASSERT(m_CSChunks.IsLockedByCurrentThread()); // m_CSChunks should already be locked by the operation that called us
55 
56  auto & Chunk = ConstructChunk(a_ChunkX, a_ChunkZ);
57  if (!Chunk.IsValid() && !Chunk.IsQueued())
58  {
59  Chunk.SetPresence(cChunk::cpQueued);
60  m_World->GetStorage().QueueLoadChunk(a_ChunkX, a_ChunkZ);
61  }
62  return Chunk;
63 }
64 
65 
66 
67 
68 
69 cChunk * cChunkMap::FindChunk(int a_ChunkX, int a_ChunkZ)
70 {
72 
73  const auto Chunk = m_Chunks.find({ a_ChunkX, a_ChunkZ });
74  return (Chunk == m_Chunks.end()) ? nullptr : &Chunk->second;
75 }
76 
77 
78 
79 
80 
81 const cChunk * cChunkMap::FindChunk(int a_ChunkX, int a_ChunkZ) const
82 {
84 
85  const auto Chunk = m_Chunks.find({ a_ChunkX, a_ChunkZ });
86  return (Chunk == m_Chunks.end()) ? nullptr : &Chunk->second;
87 }
88 
89 
90 
91 
92 
93 void cChunkMap::SendBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cClientHandle & a_Client)
94 {
95  cCSLock Lock(m_CSChunks);
96  int ChunkX, ChunkZ;
97  cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ);
98  const auto Chunk = FindChunk(ChunkX, ChunkZ);
99  if ((Chunk == nullptr) || !Chunk->IsValid())
100  {
101  return;
102  }
103  Chunk->SendBlockEntity(a_BlockX, a_BlockY, a_BlockZ, a_Client);
104 }
105 
106 
107 
108 
109 
110 bool cChunkMap::UseBlockEntity(cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ)
111 {
112  // a_Player rclked block entity at the coords specified, handle it
113  cCSLock Lock(m_CSChunks);
114  int ChunkX, ChunkZ;
115  cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ);
116  const auto Chunk = FindChunk(ChunkX, ChunkZ);
117  if ((Chunk == nullptr) || !Chunk->IsValid())
118  {
119  return false;
120  }
121  return Chunk->UseBlockEntity(a_Player, a_BlockX, a_BlockY, a_BlockZ);
122 }
123 
124 
125 
126 
127 
128 bool cChunkMap::DoWithChunk(int a_ChunkX, int a_ChunkZ, cChunkCallback a_Callback)
129 {
130  cCSLock Lock(m_CSChunks);
131  const auto Chunk = FindChunk(a_ChunkX, a_ChunkZ);
132  if ((Chunk == nullptr) || !Chunk->IsValid())
133  {
134  return false;
135  }
136  return a_Callback(*Chunk);
137 }
138 
139 
140 
141 
142 
144 {
145  const auto Position = cChunkDef::BlockToChunk(a_BlockPos);
146  return DoWithChunk(Position.m_ChunkX, Position.m_ChunkZ, a_Callback);
147 }
148 
149 
150 
151 
152 
154 {
155  cCSLock Lock(m_CSChunks);
156  const auto Position = cChunkDef::BlockToChunk(a_Block);
157  const auto Chunk = FindChunk(Position.m_ChunkX, Position.m_ChunkZ);
158  if ((Chunk == nullptr) || !Chunk->IsValid())
159  {
160  return;
161  }
162 
163  m_World->GetSimulatorManager()->WakeUp(*Chunk, cChunkDef::AbsoluteToRelative(a_Block, Position));
164 }
165 
166 
167 
168 
169 
170 void cChunkMap::MarkChunkDirty(int a_ChunkX, int a_ChunkZ)
171 {
172  cCSLock Lock(m_CSChunks);
173  const auto Chunk = FindChunk(a_ChunkX, a_ChunkZ);
174  if ((Chunk == nullptr) || !Chunk->IsValid())
175  {
176  return;
177  }
178  Chunk->MarkDirty();
179 }
180 
181 
182 
183 
184 
185 void cChunkMap::MarkChunkSaving(int a_ChunkX, int a_ChunkZ)
186 {
187  cCSLock Lock(m_CSChunks);
188  const auto Chunk = FindChunk(a_ChunkX, a_ChunkZ);
189  if ((Chunk == nullptr) || !Chunk->IsValid())
190  {
191  return;
192  }
193  Chunk->MarkSaving();
194 }
195 
196 
197 
198 
199 
200 void cChunkMap::MarkChunkSaved (int a_ChunkX, int a_ChunkZ)
201 {
202  cCSLock Lock(m_CSChunks);
203  const auto Chunk = FindChunk(a_ChunkX, a_ChunkZ);
204  if ((Chunk == nullptr) || !Chunk->IsValid())
205  {
206  return;
207  }
208  Chunk->MarkSaved();
209 }
210 
211 
212 
213 
214 
215 void cChunkMap::SetChunkData(struct SetChunkData && a_SetChunkData)
216 {
217  const int ChunkX = a_SetChunkData.Chunk.m_ChunkX;
218  const int ChunkZ = a_SetChunkData.Chunk.m_ChunkZ;
219  {
220  cCSLock Lock(m_CSChunks);
221  const auto Chunk = FindChunk(ChunkX, ChunkZ);
222  ASSERT(Chunk != nullptr); // Chunk cannot have unloaded since it is marked as queued
223  Chunk->SetAllData(std::move(a_SetChunkData));
224 
225  // Notify relevant ChunkStays:
226  cChunkStays ToBeDisabled;
227  for (cChunkStays::iterator itr = m_ChunkStays.begin(), end = m_ChunkStays.end(); itr != end; ++itr)
228  {
229  if ((*itr)->ChunkAvailable(ChunkX, ChunkZ))
230  {
231  // The chunkstay wants to be disabled, add it to a list of to-be-disabled chunkstays for later processing:
232  ToBeDisabled.push_back(*itr);
233  }
234  } // for itr - m_ChunkStays[]
235 
236  // Disable (and possibly remove) the chunkstays that chose to get disabled:
237  for (cChunkStays::iterator itr = ToBeDisabled.begin(), end = ToBeDisabled.end(); itr != end; ++itr)
238  {
239  (*itr)->Disable();
240  }
241  }
242 
243  // Notify plugins of the chunk becoming available
245 }
246 
247 
248 
249 
250 
252  int a_ChunkX, int a_ChunkZ,
253  const cChunkDef::BlockNibbles & a_BlockLight,
254  const cChunkDef::BlockNibbles & a_SkyLight
255 )
256 {
257  cCSLock Lock(m_CSChunks);
258  const auto Chunk = FindChunk(a_ChunkX, a_ChunkZ);
259  if (Chunk == nullptr)
260  {
261  // Chunk probably unloaded in the meantime
262  return;
263  }
264  Chunk->SetLight(a_BlockLight, a_SkyLight);
265 }
266 
267 
268 
269 
270 
271 bool cChunkMap::GetChunkData(cChunkCoords a_Coords, cChunkDataCallback & a_Callback) const
272 {
273  if (!a_Callback.Coords(a_Coords.m_ChunkX, a_Coords.m_ChunkZ))
274  {
275  // The callback doesn't want the data
276  return false;
277  }
278  cCSLock Lock(m_CSChunks);
279  const auto Chunk = FindChunk(a_Coords.m_ChunkX, a_Coords.m_ChunkZ);
280  if ((Chunk == nullptr) || !Chunk->IsValid())
281  {
282  // The chunk is not present
283  return false;
284  }
285  Chunk->GetAllData(a_Callback);
286  return true;
287 }
288 
289 
290 
291 
292 
293 bool cChunkMap::IsChunkQueued(int a_ChunkX, int a_ChunkZ) const
294 {
295  cCSLock Lock(m_CSChunks);
296  const auto Chunk = FindChunk(a_ChunkX, a_ChunkZ);
297  return (Chunk != nullptr) && Chunk->IsQueued();
298 }
299 
300 
301 
302 
303 
304 bool cChunkMap::IsWeatherSunnyAt(int a_BlockX, int a_BlockZ) const
305 {
306  int ChunkX, ChunkZ, BlockY = 0;
307  cChunkDef::AbsoluteToRelative(a_BlockX, BlockY, a_BlockZ, ChunkX, ChunkZ);
308 
309  cCSLock Lock(m_CSChunks);
310  const auto Chunk = FindChunk(ChunkX, ChunkZ);
311  if ((Chunk == nullptr) || !Chunk->IsValid())
312  {
313  return m_World->IsWeatherSunny();
314  }
315 
316  return Chunk->IsWeatherSunnyAt(a_BlockX, a_BlockZ);
317 }
318 
319 
320 
321 
322 
323 bool cChunkMap::IsWeatherWetAt(int a_BlockX, int a_BlockZ) const
324 {
325  int ChunkX, ChunkZ, BlockY = 0;
326  cChunkDef::AbsoluteToRelative(a_BlockX, BlockY, a_BlockZ, ChunkX, ChunkZ);
327 
328  cCSLock Lock(m_CSChunks);
329  const auto Chunk = FindChunk(ChunkX, ChunkZ);
330  if ((Chunk == nullptr) || !Chunk->IsValid())
331  {
332  return m_World->IsWeatherWet();
333  }
334 
335  return Chunk->IsWeatherWetAt(a_BlockX, a_BlockZ);
336 }
337 
338 
339 
340 
341 
342 bool cChunkMap::IsWeatherWetAt(const Vector3i a_Position) const
343 {
344  const auto ChunkPosition = cChunkDef::BlockToChunk(a_Position);
345  const auto Position = cChunkDef::AbsoluteToRelative(a_Position, ChunkPosition);
346 
347  cCSLock Lock(m_CSChunks);
348  const auto Chunk = FindChunk(ChunkPosition.m_ChunkX, ChunkPosition.m_ChunkZ);
349  if ((Chunk == nullptr) || !Chunk->IsValid())
350  {
351  return m_World->IsWeatherWet();
352  }
353 
354  return Chunk->IsWeatherWetAt(Position);
355 }
356 
357 
358 
359 
360 
361 bool cChunkMap::IsChunkValid(int a_ChunkX, int a_ChunkZ) const
362 {
363  cCSLock Lock(m_CSChunks);
364  const auto Chunk = FindChunk(a_ChunkX, a_ChunkZ);
365  return (Chunk != nullptr) && Chunk->IsValid();
366 }
367 
368 
369 
370 
371 
372 bool cChunkMap::HasChunkAnyClients(int a_ChunkX, int a_ChunkZ) const
373 {
374  cCSLock Lock(m_CSChunks);
375  const auto Chunk = FindChunk(a_ChunkX, a_ChunkZ);
376  return (Chunk != nullptr) && Chunk->HasAnyClients();
377 }
378 
379 
380 
381 
382 
383 int cChunkMap::GetHeight(int a_BlockX, int a_BlockZ)
384 {
385  for (;;)
386  {
387  cCSLock Lock(m_CSChunks);
388  int ChunkX, ChunkZ, BlockY = 0;
389  cChunkDef::AbsoluteToRelative(a_BlockX, BlockY, a_BlockZ, ChunkX, ChunkZ);
390  auto & Chunk = GetChunk(ChunkX, ChunkZ);
391  if (Chunk.IsValid())
392  {
393  return Chunk.GetHeight(a_BlockX, a_BlockZ);
394  }
395 
396  // The chunk is not valid, wait for it to become valid:
397  cCSUnlock Unlock(Lock);
399  } // while (true)
400 }
401 
402 
403 
404 
405 
406 bool cChunkMap::TryGetHeight(int a_BlockX, int a_BlockZ, int & a_Height)
407 {
408  // Returns false if chunk not loaded / generated
409  cCSLock Lock(m_CSChunks);
410  int ChunkX, ChunkZ, BlockY = 0;
411  cChunkDef::AbsoluteToRelative(a_BlockX, BlockY, a_BlockZ, ChunkX, ChunkZ);
412  const auto Chunk = FindChunk(ChunkX, ChunkZ);
413  if ((Chunk == nullptr) || !Chunk->IsValid())
414  {
415  return false;
416  }
417  a_Height = Chunk->GetHeight(a_BlockX, a_BlockZ);
418  return true;
419 }
420 
421 
422 
423 
424 
425 void cChunkMap::FastSetBlock(Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
426 {
427  auto chunkPos = cChunkDef::BlockToChunk(a_BlockPos);
428  auto relPos = cChunkDef::AbsoluteToRelative(a_BlockPos, chunkPos);
429 
430  cCSLock Lock(m_CSChunks);
431  const auto Chunk = FindChunk(chunkPos.m_ChunkX, chunkPos.m_ChunkZ);
432  if ((Chunk != nullptr) && Chunk->IsValid())
433  {
434  Chunk->FastSetBlock(relPos, a_BlockType, a_BlockMeta);
435  }
436 }
437 
438 
439 
440 
441 
443 {
444  cCSLock Lock(m_CSChunks);
445 
446  auto BoundingBox = a_Entity.GetBoundingBox();
447  BoundingBox.Expand(1, 0.5, 1);
448 
449  ForEachEntityInBox(BoundingBox, [&a_Entity](cEntity & Entity)
450  {
451  // Only pickups and projectiles can be picked up:
452  if (Entity.IsPickup())
453  {
454  /*
455  LOG("Pickup %d being collected by player \"%s\", distance %f",
456  (*itr)->GetUniqueID(), a_Player->GetName().c_str(), SqrDist
457  );
458  */
459  static_cast<cPickup &>(Entity).CollectedBy(a_Entity);
460  }
461  else if (Entity.IsProjectile() && a_Entity.IsPlayer())
462  {
463  static_cast<cProjectileEntity &>(Entity).CollectedBy(static_cast<cPlayer&>(a_Entity));
464  }
465 
466  // The entities will MarkDirty when they Destroy themselves
467  return false;
468  });
469 }
470 
471 
472 
473 
474 
476 {
477  auto chunkPos = cChunkDef::BlockToChunk(a_BlockPos);
478  auto relPos = cChunkDef::AbsoluteToRelative(a_BlockPos, chunkPos);
479 
480  // Query the chunk, if loaded:
481  cCSLock Lock(m_CSChunks);
482  const auto Chunk = FindChunk(chunkPos.m_ChunkX, chunkPos.m_ChunkZ);
483  if ((Chunk != nullptr) && Chunk->IsValid())
484  {
485  return Chunk->GetBlock(relPos);
486  }
487  return 0;
488 }
489 
490 
491 
492 
493 
495 {
496  auto chunkPos = cChunkDef::BlockToChunk(a_BlockPos);
497  auto relPos = cChunkDef::AbsoluteToRelative(a_BlockPos, chunkPos);
498 
499  // Query the chunk, if loaded:
500  cCSLock Lock(m_CSChunks);
501  const auto Chunk = FindChunk(chunkPos.m_ChunkX, chunkPos.m_ChunkZ);
502  if ((Chunk != nullptr) && Chunk->IsValid())
503  {
504  return Chunk->GetMeta(relPos);
505  }
506  return 0;
507 }
508 
509 
510 
511 
512 
514 {
515  auto chunkPos = cChunkDef::BlockToChunk(a_BlockPos);
516  auto relPos = cChunkDef::AbsoluteToRelative(a_BlockPos, chunkPos);
517 
518  // Query the chunk, if loaded:
519  cCSLock Lock(m_CSChunks);
520  const auto Chunk = FindChunk(chunkPos.m_ChunkX, chunkPos.m_ChunkZ);
521  if ((Chunk != nullptr) && Chunk->IsValid())
522  {
523  return Chunk->GetSkyLight(relPos);
524  }
525  return 0;
526 }
527 
528 
529 
530 
531 
533 {
534  auto chunkPos = cChunkDef::BlockToChunk(a_BlockPos);
535  auto relPos = cChunkDef::AbsoluteToRelative(a_BlockPos, chunkPos);
536 
537  // Query the chunk, if loaded:
538  cCSLock Lock(m_CSChunks);
539  const auto Chunk = FindChunk(chunkPos.m_ChunkX, chunkPos.m_ChunkZ);
540  if ((Chunk != nullptr) && Chunk->IsValid())
541  {
542  return Chunk->GetBlockLight(relPos);
543  }
544  return 0;
545 }
546 
547 
548 
549 
550 
551 void cChunkMap::SetBlockMeta(Vector3i a_BlockPos, NIBBLETYPE a_BlockMeta)
552 {
553  auto chunkPos = cChunkDef::BlockToChunk(a_BlockPos);
554  auto relPos = cChunkDef::AbsoluteToRelative(a_BlockPos, chunkPos);
555 
556  // Query the chunk, if loaded:
557  cCSLock Lock(m_CSChunks);
558  const auto Chunk = FindChunk(chunkPos.m_ChunkX, chunkPos.m_ChunkZ);
559  if ((Chunk != nullptr) && Chunk->IsValid())
560  {
561  Chunk->SetMeta(relPos, a_BlockMeta);
562  }
563 }
564 
565 
566 
567 
568 
569 void cChunkMap::SetBlock(Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
570 {
571  auto chunkPos = cChunkDef::BlockToChunk(a_BlockPos);
572  auto relPos = cChunkDef::AbsoluteToRelative(a_BlockPos, chunkPos);
573 
574  cCSLock Lock(m_CSChunks);
575  const auto Chunk = FindChunk(chunkPos.m_ChunkX, chunkPos.m_ChunkZ);
576  if ((Chunk != nullptr) && Chunk->IsValid())
577  {
578  Chunk->SetBlock(relPos, a_BlockType, a_BlockMeta);
579  }
580 }
581 
582 
583 
584 
585 
586 bool cChunkMap::GetBlockTypeMeta(Vector3i a_BlockPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) const
587 {
588  auto chunkCoord = cChunkDef::BlockToChunk(a_BlockPos);
589  auto relPos = cChunkDef::AbsoluteToRelative(a_BlockPos, chunkCoord);
590 
591  cCSLock Lock(m_CSChunks);
592  const auto Chunk = FindChunk(chunkCoord.m_ChunkX, chunkCoord.m_ChunkZ);
593  if ((Chunk != nullptr) && Chunk->IsValid())
594  {
595  Chunk->GetBlockTypeMeta(relPos, a_BlockType, a_BlockMeta);
596  return true;
597  }
598  return false;
599 }
600 
601 
602 
603 
604 
605 bool cChunkMap::GetBlockInfo(Vector3i a_BlockPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_Meta, NIBBLETYPE & a_SkyLight, NIBBLETYPE & a_BlockLight) const
606 {
607  auto chunkPos = cChunkDef::BlockToChunk(a_BlockPos);
608  auto relPos = cChunkDef::AbsoluteToRelative(a_BlockPos, chunkPos);
609 
610  // Query the chunk, if loaded:
611  cCSLock Lock(m_CSChunks);
612  const auto Chunk = FindChunk(chunkPos.m_ChunkX, chunkPos.m_ChunkZ);
613  if ((Chunk != nullptr) && Chunk->IsValid())
614  {
615  Chunk->GetBlockInfo(relPos, a_BlockType, a_Meta, a_SkyLight, a_BlockLight);
616  return true;
617  }
618  return false;
619 }
620 
621 
622 
623 
624 
626 {
627  cCSLock Lock(m_CSChunks);
628  for (sSetBlockVector::const_iterator itr = a_Blocks.begin(); itr != a_Blocks.end(); ++itr)
629  {
630  const auto Chunk = FindChunk(itr->m_ChunkX, itr->m_ChunkZ);
631  if ((Chunk == nullptr) || !Chunk->IsValid())
632  {
633  continue;
634  }
635  Vector3i relPos(itr->m_RelX, itr->m_RelY, itr->m_RelZ);
636  switch (Chunk->GetBlock(relPos))
637  {
639  {
640  Chunk->SetBlock(relPos, itr->m_BlockType, itr->m_BlockMeta);
641  break;
642  }
643  case E_BLOCK_LEAVES:
644  case E_BLOCK_NEW_LEAVES:
645  {
646  if ((itr->m_BlockType == E_BLOCK_LOG) || (itr->m_BlockType == E_BLOCK_NEW_LOG))
647  {
648  Chunk->SetBlock(relPos, itr->m_BlockType, itr->m_BlockMeta);
649  }
650  break;
651  }
652  }
653  } // for itr - a_Blocks[]
654 }
655 
656 
657 
658 
659 
660 EMCSBiome cChunkMap::GetBiomeAt(int a_BlockX, int a_BlockZ) const
661 {
662  int ChunkX, ChunkZ, X = a_BlockX, Y = 0, Z = a_BlockZ;
663  cChunkDef::AbsoluteToRelative(X, Y, Z, ChunkX, ChunkZ);
664 
665  cCSLock Lock(m_CSChunks);
666  const auto Chunk = FindChunk(ChunkX, ChunkZ);
667  if ((Chunk != nullptr) && Chunk->IsValid())
668  {
669  return Chunk->GetBiomeAt(X, Z);
670  }
672 }
673 
674 
675 
676 
677 
678 bool cChunkMap::SetBiomeAt(int a_BlockX, int a_BlockZ, EMCSBiome a_Biome)
679 {
680  int ChunkX, ChunkZ, X = a_BlockX, Y = 0, Z = a_BlockZ;
681  cChunkDef::AbsoluteToRelative(X, Y, Z, ChunkX, ChunkZ);
682 
683  cCSLock Lock(m_CSChunks);
684  const auto Chunk = FindChunk(ChunkX, ChunkZ);
685  if ((Chunk != nullptr) && Chunk->IsValid())
686  {
687  Chunk->SetBiomeAt(X, Z, a_Biome);
688  return true;
689  }
690  return false;
691 }
692 
693 
694 
695 
696 
697 bool cChunkMap::SetAreaBiome(int a_MinX, int a_MaxX, int a_MinZ, int a_MaxZ, EMCSBiome a_Biome)
698 {
699  // Translate coords to relative:
700  int Y = 0;
701  int MinChunkX, MinChunkZ, MinX = a_MinX, MinZ = a_MinZ;
702  int MaxChunkX, MaxChunkZ, MaxX = a_MaxX, MaxZ = a_MaxZ;
703  cChunkDef::AbsoluteToRelative(MinX, Y, MinZ, MinChunkX, MinChunkZ);
704  cChunkDef::AbsoluteToRelative(MaxX, Y, MaxZ, MaxChunkX, MaxChunkZ);
705 
706  // Go through all chunks, set:
707  bool res = true;
708  cCSLock Lock(m_CSChunks);
709  for (int x = MinChunkX; x <= MaxChunkX; x++)
710  {
711  int MinRelX = (x == MinChunkX) ? MinX : 0;
712  int MaxRelX = (x == MaxChunkX) ? MaxX : cChunkDef::Width - 1;
713  for (int z = MinChunkZ; z <= MaxChunkZ; z++)
714  {
715  int MinRelZ = (z == MinChunkZ) ? MinZ : 0;
716  int MaxRelZ = (z == MaxChunkZ) ? MaxZ : cChunkDef::Width - 1;
717  const auto Chunk = FindChunk(x, z);
718  if ((Chunk != nullptr) && Chunk->IsValid())
719  {
720  Chunk->SetAreaBiome(MinRelX, MaxRelX, MinRelZ, MaxRelZ, a_Biome);
721  }
722  else
723  {
724  res = false;
725  }
726  } // for z
727  } // for x
728  return res;
729 }
730 
731 
732 
733 
734 
735 bool cChunkMap::GetBlocks(sSetBlockVector & a_Blocks, bool a_ContinueOnFailure)
736 {
737  bool res = true;
738  cCSLock Lock(m_CSChunks);
739  for (sSetBlockVector::iterator itr = a_Blocks.begin(); itr != a_Blocks.end(); ++itr)
740  {
741  const auto Chunk = FindChunk(itr->m_ChunkX, itr->m_ChunkZ);
742  if ((Chunk == nullptr) || !Chunk->IsValid())
743  {
744  if (!a_ContinueOnFailure)
745  {
746  return false;
747  }
748  res = false;
749  continue;
750  }
751  if (!cChunkDef::IsValidHeight(itr->GetRelativePos()))
752  {
753  continue;
754  }
755  itr->m_BlockType = Chunk->GetBlock(itr->m_RelX, itr->m_RelY, itr->m_RelZ);
756  itr->m_BlockMeta = Chunk->GetMeta(itr->m_RelX, itr->m_RelY, itr->m_RelZ);
757  }
758  return res;
759 }
760 
761 
762 
763 
764 
766 {
767  auto chunkCoords = cChunkDef::BlockToChunk(a_BlockPos);
768  auto relPos = cChunkDef::AbsoluteToRelative(a_BlockPos, chunkCoords);
769 
770  {
771  cCSLock Lock(m_CSChunks);
772  const auto Chunk = FindChunk(chunkCoords.m_ChunkX, chunkCoords.m_ChunkZ);
773  if ((Chunk == nullptr) || !Chunk->IsValid())
774  {
775  return false;
776  }
777 
778  Chunk->SetBlock(relPos, E_BLOCK_AIR, 0);
779  }
780  return true;
781 }
782 
783 
784 
785 
786 
787 cItems cChunkMap::PickupsFromBlock(Vector3i a_BlockPos, const cEntity * a_Digger, const cItem * a_Tool)
788 {
789  auto chunkCoords = cChunkDef::BlockToChunk(a_BlockPos);
790  auto relPos = cChunkDef::AbsoluteToRelative(a_BlockPos, chunkCoords);
791 
792  cCSLock Lock(m_CSChunks);
793  const auto Chunk = FindChunk(chunkCoords.m_ChunkX, chunkCoords.m_ChunkZ);
794  if ((Chunk == nullptr) || !Chunk->IsValid())
795  {
796  return {};
797  }
798  return Chunk->PickupsFromBlock(relPos, a_Digger, a_Tool);
799 }
800 
801 
802 
803 
804 
805 void cChunkMap::SendBlockTo(int a_X, int a_Y, int a_Z, const cPlayer & a_Player)
806 {
807  int ChunkX, ChunkZ;
808  cChunkDef::AbsoluteToRelative(a_X, a_Y, a_Z, ChunkX, ChunkZ);
809 
810  cCSLock Lock(m_CSChunks);
811  const auto Chunk = FindChunk(ChunkX, ChunkZ);
812  if ((Chunk != nullptr) && (Chunk->IsValid()))
813  {
814  Chunk->SendBlockTo(a_X, a_Y, a_Z, a_Player.GetClientHandle());
815  }
816 }
817 
818 
819 
820 
821 
822 void cChunkMap::CompareChunkClients(int a_ChunkX1, int a_ChunkZ1, int a_ChunkX2, int a_ChunkZ2, cClientDiffCallback & a_Callback)
823 {
824  cCSLock Lock(m_CSChunks);
825  const auto Chunk1 = FindChunk(a_ChunkX1, a_ChunkZ1);
826  if (Chunk1 == nullptr)
827  {
828  return;
829  }
830  const auto Chunk2 = FindChunk(a_ChunkX2, a_ChunkZ2);
831  if (Chunk2 == nullptr)
832  {
833  return;
834  }
835 
836  CompareChunkClients(Chunk1, Chunk2, a_Callback);
837 }
838 
839 
840 
841 
842 
843 void cChunkMap::CompareChunkClients(cChunk * a_Chunk1, cChunk * a_Chunk2, cClientDiffCallback & a_Callback)
844 {
845  const auto & Clients1 = a_Chunk1->GetAllClients();
846  const auto & Clients2 = a_Chunk2->GetAllClients();
847 
848  // Find "removed" clients:
849  for (auto * Client : Clients1)
850  {
851  bool Found = (std::find(Clients2.begin(), Clients2.end(), Client) != Clients2.end());
852  if (!Found)
853  {
854  a_Callback.Removed(Client);
855  }
856  } // for Client - Clients1[]
857 
858  // Find "added" clients:
859  for (auto * Client : Clients2)
860  {
861  bool Found = (std::find(Clients1.begin(), Clients1.end(), Client) != Clients1.end());
862  if (!Found)
863  {
864  a_Callback.Added(Client);
865  }
866  } // for Client - Clients2[]
867 }
868 
869 
870 
871 
872 
873 bool cChunkMap::AddChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client)
874 {
875  cCSLock Lock(m_CSChunks);
876  return GetChunk(a_ChunkX, a_ChunkZ).AddClient(a_Client);
877 }
878 
879 
880 
881 
882 
883 void cChunkMap::RemoveChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client)
884 {
885  cCSLock Lock(m_CSChunks);
886  const auto Chunk = FindChunk(a_ChunkX, a_ChunkZ);
887  ASSERT(Chunk != nullptr);
888  Chunk->RemoveClient(a_Client);
889 }
890 
891 
892 
893 
894 
896 {
897  cCSLock Lock(m_CSChunks);
898  for (auto & Chunk : m_Chunks)
899  {
900  Chunk.second.RemoveClient(a_Client);
901  }
902 }
903 
904 
905 
906 
907 
909 {
910  cCSLock Lock(m_CSChunks);
911  if (FindChunk(a_Entity->GetChunkX(), a_Entity->GetChunkZ()) == nullptr)
912  {
913  LOGWARNING("%s: Entity at %p (%s, ID %d) spawning in a non-existent chunk.",
914  __FUNCTION__, static_cast<void *>(a_Entity.get()), a_Entity->GetClass(), a_Entity->GetUniqueID()
915  );
916  }
917 
918  const auto EntityPtr = a_Entity.get();
919  ASSERT(EntityPtr->GetWorld() == m_World);
920 
921  auto & Chunk = ConstructChunk(a_Entity->GetChunkX(), a_Entity->GetChunkZ());
922  Chunk.AddEntity(std::move(a_Entity));
923 
924  EntityPtr->OnAddToWorld(*m_World);
925  ASSERT(!EntityPtr->IsTicking());
926  EntityPtr->SetIsTicking(true);
927 
929 }
930 
931 
932 
933 
934 
935 void cChunkMap::AddPlayer(std::unique_ptr<cPlayer> a_Player)
936 {
937  cCSLock Lock(m_CSChunks);
938  auto & Chunk = ConstructChunk(a_Player->GetChunkX(), a_Player->GetChunkZ()); // Always construct the chunk for players
939  ASSERT(!Chunk.HasEntity(a_Player->GetUniqueID()));
940  Chunk.AddEntity(std::move(a_Player));
941 }
942 
943 
944 
945 
946 
947 bool cChunkMap::HasEntity(UInt32 a_UniqueID) const
948 {
949  cCSLock Lock(m_CSChunks);
950  for (const auto & Chunk : m_Chunks)
951  {
952  if (Chunk.second.IsValid() && Chunk.second.HasEntity(a_UniqueID))
953  {
954  return true;
955  }
956  }
957  return false;
958 }
959 
960 
961 
962 
963 
965 {
966  cCSLock Lock(m_CSChunks);
967  const auto Chunk = a_Entity.GetParentChunk();
968 
969  if (Chunk == nullptr)
970  {
971  return nullptr;
972  }
973 
974  // Remove the entity no matter whether the chunk itself is valid or not (#1190)
975  return Chunk->RemoveEntity(a_Entity);
976 }
977 
978 
979 
980 
981 
983 {
984  cCSLock Lock(m_CSChunks);
985  for (const auto & Chunk : m_Chunks)
986  {
987  if (Chunk.second.IsValid() && !Chunk.second.ForEachEntity(a_Callback))
988  {
989  return false;
990  }
991  }
992  return true;
993 }
994 
995 
996 
997 
998 
999 bool cChunkMap::ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback a_Callback)
1000 {
1001  cCSLock Lock(m_CSChunks);
1002  const auto Chunk = FindChunk(a_ChunkX, a_ChunkZ);
1003  if ((Chunk == nullptr) || !Chunk->IsValid())
1004  {
1005  return false;
1006  }
1007  return Chunk->ForEachEntity(a_Callback);
1008 }
1009 
1010 
1011 
1012 
1013 
1015 {
1016  // Calculate the chunk range for the box:
1017  int MinChunkX = FloorC(a_Box.GetMinX() / cChunkDef::Width);
1018  int MinChunkZ = FloorC(a_Box.GetMinZ() / cChunkDef::Width);
1019  int MaxChunkX = FloorC((a_Box.GetMaxX() + cChunkDef::Width) / cChunkDef::Width);
1020  int MaxChunkZ = FloorC((a_Box.GetMaxZ() + cChunkDef::Width) / cChunkDef::Width);
1021 
1022  // Iterate over each chunk in the range:
1023  cCSLock Lock(m_CSChunks);
1024  for (int z = MinChunkZ; z <= MaxChunkZ; z++)
1025  {
1026  for (int x = MinChunkX; x <= MaxChunkX; x++)
1027  {
1028  const auto Chunk = FindChunk(x, z);
1029  if ((Chunk == nullptr) || !Chunk->IsValid())
1030  {
1031  continue;
1032  }
1033  if (!Chunk->ForEachEntityInBox(a_Box, a_Callback))
1034  {
1035  return false;
1036  }
1037  } // for x
1038  } // for z
1039  return true;
1040 }
1041 
1042 
1043 
1044 
1045 
1046 bool cChunkMap::DoWithEntityByID(UInt32 a_UniqueID, cEntityCallback a_Callback) const
1047 {
1048  cCSLock Lock(m_CSChunks);
1049  bool res = false;
1050  for (const auto & Chunk : m_Chunks)
1051  {
1052  if (Chunk.second.IsValid() && Chunk.second.DoWithEntityByID(a_UniqueID, a_Callback, res))
1053  {
1054  return res;
1055  }
1056  }
1057  return false;
1058 }
1059 
1060 
1061 
1062 
1063 
1064 bool cChunkMap::ForEachBlockEntityInChunk(int a_ChunkX, int a_ChunkZ, cBlockEntityCallback a_Callback)
1065 {
1066  cCSLock Lock(m_CSChunks);
1067  const auto Chunk = FindChunk(a_ChunkX, a_ChunkZ);
1068  if ((Chunk == nullptr) || !Chunk->IsValid())
1069  {
1070  return false;
1071  }
1072  return Chunk->ForEachBlockEntity(a_Callback);
1073 }
1074 
1075 
1076 
1077 
1078 
1080 {
1081  const auto ChunkPosition = cChunkDef::BlockToChunk(a_Position);
1082  const auto Relative = cChunkDef::AbsoluteToRelative(a_Position, ChunkPosition);
1083  cCSLock Lock(m_CSChunks);
1084  const auto Chunk = FindChunk(ChunkPosition.m_ChunkX, ChunkPosition.m_ChunkZ);
1085  if ((Chunk == nullptr) || !Chunk->IsValid())
1086  {
1087  return false;
1088  }
1089  return Chunk->DoWithBlockEntityAt(Relative, a_Callback);
1090 }
1091 
1092 
1093 
1094 
1095 
1096 void cChunkMap::PrepareChunk(int a_ChunkX, int a_ChunkZ, std::unique_ptr<cChunkCoordCallback> a_Callback)
1097 {
1098  cCSLock Lock(m_CSChunks);
1099  const auto Chunk = FindChunk(a_ChunkX, a_ChunkZ);
1100 
1101  // If the chunk is not prepared, queue it in the lighting thread, that will do all the needed processing:
1102  if ((Chunk == nullptr) || !Chunk->IsValid() || !Chunk->IsLightValid())
1103  {
1104  m_World->GetLightingThread().QueueChunk(a_ChunkX, a_ChunkZ, std::move(a_Callback));
1105  return;
1106  }
1107 
1108  // The chunk is present and lit, just call the callback, report as success:
1109  if (a_Callback != nullptr)
1110  {
1111  a_Callback->Call({a_ChunkX, a_ChunkZ}, true);
1112  }
1113 }
1114 
1115 
1116 
1117 
1118 
1119 void cChunkMap::GenerateChunk(int a_ChunkX, int a_ChunkZ)
1120 {
1121  cCSLock Lock(m_CSChunks);
1122  GetChunk(a_ChunkX, a_ChunkZ); // Touches the chunk, loading or generating it
1123 }
1124 
1125 
1126 
1127 
1128 
1129 void cChunkMap::ChunkLoadFailed(int a_ChunkX, int a_ChunkZ)
1130 {
1131  cCSLock Lock(m_CSChunks);
1132  const auto Chunk = FindChunk(a_ChunkX, a_ChunkZ);
1133  ASSERT(Chunk != nullptr); // Chunk cannot have unloaded since it is marked as queued
1134  Chunk->MarkLoadFailed();
1135 }
1136 
1137 
1138 
1139 
1140 
1141 void cChunkMap::MarkChunkRegenerating(int a_ChunkX, int a_ChunkZ)
1142 {
1143  cCSLock Lock(m_CSChunks);
1144  ConstructChunk(a_ChunkX, a_ChunkZ).MarkRegenerating();
1145 }
1146 
1147 
1148 
1149 
1150 
1151 bool cChunkMap::IsChunkLighted(int a_ChunkX, int a_ChunkZ)
1152 {
1153  cCSLock Lock(m_CSChunks);
1154  const auto Chunk = FindChunk(a_ChunkX, a_ChunkZ);
1155  if (Chunk == nullptr)
1156  {
1157  // Not present
1158  return false;
1159  }
1160  return Chunk->IsLightValid();
1161 }
1162 
1163 
1164 
1165 
1166 
1167 bool cChunkMap::ForEachChunkInRect(int a_MinChunkX, int a_MaxChunkX, int a_MinChunkZ, int a_MaxChunkZ, cChunkDataCallback & a_Callback)
1168 {
1169  bool Result = true;
1170  cCSLock Lock(m_CSChunks);
1171  for (int z = a_MinChunkZ; z <= a_MaxChunkZ; z++)
1172  {
1173  for (int x = a_MinChunkX; x <= a_MaxChunkX; x++)
1174  {
1175  const auto Chunk = FindChunk(x, z);
1176  if ((Chunk == nullptr) || !Chunk->IsValid())
1177  {
1178  // Not present / not valid
1179  Result = false;
1180  continue;
1181  }
1182  if (!a_Callback.Coords(x, z))
1183  {
1184  continue;
1185  }
1186  Chunk->GetAllData(a_Callback);
1187  }
1188  }
1189  return Result;
1190 }
1191 
1192 
1193 
1194 
1195 
1196 bool cChunkMap::ForEachLoadedChunk(cFunctionRef<bool(int, int)> a_Callback) const
1197 {
1198  cCSLock Lock(m_CSChunks);
1199  for (const auto & Chunk : m_Chunks)
1200  {
1201  if (Chunk.second.IsValid())
1202  {
1203  if (a_Callback(Chunk.first.m_ChunkX, Chunk.first.m_ChunkZ))
1204  {
1205  return false;
1206  }
1207  }
1208  }
1209  return true;
1210 }
1211 
1212 
1213 
1214 
1215 
1216 bool cChunkMap::WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlockY, int a_MinBlockZ, int a_DataTypes)
1217 {
1218  // Convert block coords to chunks coords:
1219  int MinChunkX, MaxChunkX;
1220  int MinChunkZ, MaxChunkZ;
1221  int MinBlockX = a_MinBlockX;
1222  int MinBlockY = a_MinBlockY;
1223  int MinBlockZ = a_MinBlockZ;
1224  int MaxBlockX = a_MinBlockX + a_Area.GetSizeX();
1225  int MaxBlockY = a_MinBlockY + a_Area.GetSizeY();
1226  int MaxBlockZ = a_MinBlockZ + a_Area.GetSizeZ();
1227  cChunkDef::AbsoluteToRelative(MinBlockX, MinBlockY, MinBlockZ, MinChunkX, MinChunkZ);
1228  cChunkDef::AbsoluteToRelative(MaxBlockX, MaxBlockY, MaxBlockZ, MaxChunkX, MaxChunkZ);
1229 
1230  // Iterate over chunks, write data into each:
1231  bool Result = true;
1232  cCSLock Lock(m_CSChunks);
1233  for (int z = MinChunkZ; z <= MaxChunkZ; z++)
1234  {
1235  for (int x = MinChunkX; x <= MaxChunkX; x++)
1236  {
1237  const auto Chunk = FindChunk(x, z);
1238  if ((Chunk == nullptr) || !Chunk->IsValid())
1239  {
1240  // Not present / not valid
1241  Result = false;
1242  continue;
1243  }
1244  Chunk->WriteBlockArea(a_Area, a_MinBlockX, a_MinBlockY, a_MinBlockZ, a_DataTypes);
1245  } // for x
1246  } // for z
1247  return Result;
1248 }
1249 
1250 
1251 
1252 
1253 
1254 void cChunkMap::GetChunkStats(int & a_NumChunksValid, int & a_NumChunksDirty) const
1255 {
1256  a_NumChunksValid = 0;
1257  a_NumChunksDirty = 0;
1258  cCSLock Lock(m_CSChunks);
1259  for (const auto & Chunk : m_Chunks)
1260  {
1261  a_NumChunksValid++;
1262  if (Chunk.second.IsDirty())
1263  {
1264  a_NumChunksDirty++;
1265  }
1266  }
1267 }
1268 
1269 
1270 
1271 
1272 
1273 int cChunkMap::GrowPlantAt(Vector3i a_BlockPos, int a_NumStages)
1274 {
1275  auto chunkPos = cChunkDef::BlockToChunk(a_BlockPos);
1276  auto relPos = cChunkDef::AbsoluteToRelative(a_BlockPos, chunkPos);
1277  cCSLock lock(m_CSChunks);
1278  const auto Chunk = FindChunk(chunkPos.m_ChunkX, chunkPos.m_ChunkZ);
1279  if ((Chunk == nullptr) || !Chunk->IsValid())
1280  {
1281  return 0;
1282  }
1283  return Chunk->GrowPlantAt(relPos, a_NumStages);
1284 }
1285 
1286 
1287 
1288 
1289 
1291 {
1292  auto ChunkPos = cChunkDef::BlockToChunk(a_BlockPos);
1293  auto RelPos = cChunkDef::AbsoluteToRelative(a_BlockPos, ChunkPos);
1294 
1295  cCSLock Lock(m_CSChunks);
1296  const auto Chunk = FindChunk(ChunkPos.m_ChunkX, ChunkPos.m_ChunkZ);
1297  if (Chunk != nullptr)
1298  {
1299  Chunk->SetNextBlockToTick(RelPos);
1300  }
1301 }
1302 
1303 
1304 
1305 
1306 
1308 {
1309  cCSLock Lock(m_CSChunks);
1310  for (auto & Chunk : m_Chunks)
1311  {
1312  // We do count every Mobs in the world. But we are assuming that every chunk not loaded by any client
1313  // doesn't affect us. Normally they should not have mobs because every "too far" mobs despawn
1314  // If they have (f.i. when player disconnect) we assume we don't have to make them live or despawn
1315  if (Chunk.second.IsValid() && Chunk.second.HasAnyClients())
1316  {
1317  Chunk.second.CollectMobCensus(a_ToFill);
1318  }
1319  }
1320 }
1321 
1322 
1323 
1324 
1325 
1326 void cChunkMap::SpawnMobs(cMobSpawner & a_MobSpawner)
1327 {
1328  cCSLock Lock(m_CSChunks);
1329  for (auto & Chunk : m_Chunks)
1330  {
1331  // We only spawn close to players
1332  if (Chunk.second.IsValid() && Chunk.second.HasAnyClients())
1333  {
1334  Chunk.second.SpawnMobs(a_MobSpawner);
1335  }
1336  }
1337 }
1338 
1339 
1340 
1341 
1342 
1343 void cChunkMap::Tick(std::chrono::milliseconds a_Dt)
1344 {
1345  cCSLock Lock(m_CSChunks);
1346 
1347  // Do the magic of updating the world:
1348  for (auto & Chunk : m_Chunks)
1349  {
1350  if (Chunk.second.ShouldBeTicked())
1351  {
1352  Chunk.second.Tick(a_Dt);
1353  }
1354  }
1355 
1356  // Finally, only after all chunks are ticked, tell the client about all aggregated changes:
1357  for (auto & Chunk : m_Chunks)
1358  {
1359  Chunk.second.BroadcastPendingChanges();
1360  }
1361 }
1362 
1363 
1364 
1365 
1366 
1367 void cChunkMap::TickBlock(const Vector3i a_BlockPos)
1368 {
1369  auto ChunkPos = cChunkDef::BlockToChunk(a_BlockPos);
1370  auto RelPos = cChunkDef::AbsoluteToRelative(a_BlockPos, ChunkPos);
1371  cCSLock Lock(m_CSChunks);
1372  const auto Chunk = FindChunk(ChunkPos.m_ChunkX, ChunkPos.m_ChunkZ);
1373  if ((Chunk == nullptr) || !Chunk->IsValid())
1374  {
1375  return;
1376  }
1377  Chunk->TickBlock(RelPos);
1378 }
1379 
1380 
1381 
1382 
1383 
1385 {
1386  cCSLock Lock(m_CSChunks);
1387  for (auto itr = m_Chunks.begin(); itr != m_Chunks.end();)
1388  {
1389  if (
1390  itr->second.CanUnload() && // Can unload
1391  !cPluginManager::Get()->CallHookChunkUnloading(*GetWorld(), itr->first.m_ChunkX, itr->first.m_ChunkZ) // Plugins agree
1392  )
1393  {
1394  // First notify plugins:
1395  cPluginManager::Get()->CallHookChunkUnloaded(*m_World, itr->first.m_ChunkX, itr->first.m_ChunkZ);
1396 
1397  // Notify entities within the chunk, while everything's still valid:
1398  itr->second.OnUnload();
1399 
1400  // Kill the chunk:
1401  itr = m_Chunks.erase(itr);
1402  }
1403  else
1404  {
1405  ++itr;
1406  }
1407  }
1408 }
1409 
1410 
1411 
1412 
1413 
1415 {
1416  cCSLock Lock(m_CSChunks);
1417  for (const auto & Chunk : m_Chunks)
1418  {
1419  if (Chunk.second.IsValid() && Chunk.second.IsDirty())
1420  {
1421  GetWorld()->GetStorage().QueueSaveChunk(Chunk.first.m_ChunkX, Chunk.first.m_ChunkZ);
1422  }
1423  }
1424 }
1425 
1426 
1427 
1428 
1429 
1430 size_t cChunkMap::GetNumChunks(void) const
1431 {
1432  cCSLock Lock(m_CSChunks);
1433  return m_Chunks.size();
1434 }
1435 
1436 
1437 
1438 
1439 
1441 {
1442  cCSLock Lock(m_CSChunks);
1443  size_t res = 0;
1444  for (const auto & Chunk : m_Chunks)
1445  {
1446  if (Chunk.second.IsValid() && Chunk.second.CanUnloadAfterSaving())
1447  {
1448  res += 1;
1449  }
1450  }
1451  return res;
1452 }
1453 
1454 
1455 
1456 
1457 
1459 {
1460  m_evtChunkValid.Set();
1461 }
1462 
1463 
1464 
1465 
1466 
1467 void cChunkMap::SetChunkAlwaysTicked(int a_ChunkX, int a_ChunkZ, bool a_AlwaysTicked)
1468 {
1469  cCSLock Lock(m_CSChunks);
1470  GetChunk(a_ChunkX, a_ChunkZ).SetAlwaysTicked(a_AlwaysTicked);
1471 }
1472 
1473 
1474 
1475 
1476 
1477 void cChunkMap::TrackInDeadlockDetect(cDeadlockDetect & a_DeadlockDetect, const AString & a_WorldName)
1478 {
1479  a_DeadlockDetect.TrackCriticalSection(m_CSChunks, fmt::format(FMT_STRING("World {} chunkmap"), a_WorldName));
1480 }
1481 
1482 
1483 
1484 
1485 
1487 {
1488  a_DeadlockDetect.UntrackCriticalSection(m_CSChunks);
1489 }
1490 
1491 
1492 
1493 
1494 
1496 {
1497  cCSLock Lock(m_CSChunks);
1498 
1499  // Add it to the list:
1500  ASSERT(std::find(m_ChunkStays.begin(), m_ChunkStays.end(), &a_ChunkStay) == m_ChunkStays.end()); // Has not yet been added
1501  m_ChunkStays.push_back(&a_ChunkStay);
1502 
1503  // Schedule all chunks to be loaded / generated, and mark each as locked:
1504  const cChunkCoordsVector & WantedChunks = a_ChunkStay.GetChunks();
1505  for (cChunkCoordsVector::const_iterator itr = WantedChunks.begin(); itr != WantedChunks.end(); ++itr)
1506  {
1507  auto & Chunk = GetChunk(itr->m_ChunkX, itr->m_ChunkZ);
1508  Chunk.Stay(true);
1509  if (Chunk.IsValid())
1510  {
1511  if (a_ChunkStay.ChunkAvailable(itr->m_ChunkX, itr->m_ChunkZ))
1512  {
1513  // The chunkstay wants to be deactivated, disable it and bail out:
1514  a_ChunkStay.Disable();
1515  return;
1516  }
1517  }
1518  } // for itr - WantedChunks[]
1519 }
1520 
1521 
1522 
1523 
1524 
1527 {
1528  cCSLock Lock(m_CSChunks);
1529 
1530  // Remove from the list of active chunkstays:
1531  bool HasFound = false;
1532  for (cChunkStays::iterator itr = m_ChunkStays.begin(), end = m_ChunkStays.end(); itr != end; ++itr)
1533  {
1534  if (*itr == &a_ChunkStay)
1535  {
1536  m_ChunkStays.erase(itr);
1537  HasFound = true;
1538  break;
1539  }
1540  } // for itr - m_ChunkStays[]
1541 
1542  if (!HasFound)
1543  {
1544  ASSERT(!"Removing a cChunkStay that hasn't been added!");
1545  return;
1546  }
1547 
1548  // Unmark all contained chunks:
1549  const cChunkCoordsVector & Chunks = a_ChunkStay.GetChunks();
1550  for (cChunkCoordsVector::const_iterator itr = Chunks.begin(), end = Chunks.end(); itr != end; ++itr)
1551  {
1552  const auto Chunk = FindChunk(itr->m_ChunkX, itr->m_ChunkZ);
1553  ASSERT(Chunk != nullptr); // Stayed chunks cannot unload
1554  Chunk->Stay(false);
1555  } // for itr - Chunks[]
1556  a_ChunkStay.OnDisabled();
1557 }
EMCSBiome
Biome IDs The first batch corresponds to the clientside biomes, used by MineCraft.
Definition: BiomeDef.h:18
@ biInvalidBiome
Definition: BiomeDef.h:19
@ E_BLOCK_NEW_LEAVES
Definition: BlockType.h:180
@ E_BLOCK_AIR
Definition: BlockType.h:10
@ E_BLOCK_LEAVES
Definition: BlockType.h:28
@ E_BLOCK_NEW_LOG
Definition: BlockType.h:181
@ E_BLOCK_LOG
Definition: BlockType.h:27
std::vector< sSetBlock > sSetBlockVector
Definition: ChunkDef.h:441
unsigned char NIBBLETYPE
The datatype used by nibbledata (meta, light, skylight)
Definition: ChunkDef.h:44
std::unique_ptr< cEntity > OwnedEntity
Definition: ChunkDef.h:32
std::vector< cChunkCoords > cChunkCoordsVector
Definition: ChunkDef.h:444
unsigned char BLOCKTYPE
The datatype used by blockdata.
Definition: ChunkDef.h:41
#define CASE_TREE_OVERWRITTEN_BLOCKS
Definition: Trees.h:38
unsigned int UInt32
Definition: Globals.h:157
#define ASSERT(x)
Definition: Globals.h:276
std::enable_if< std::is_arithmetic< T >::value, C >::type FloorC(T a_Value)
Floors a value, then casts it to C (an int by default).
Definition: Globals.h:347
void LOGWARNING(std::string_view a_Format, const Args &... args)
Definition: LoggerSimple.h:67
std::string AString
Definition: StringUtils.h:11
bool CallHookSpawnedEntity(cWorld &a_World, cEntity &a_Entity)
bool CallHookChunkAvailable(cWorld &a_World, int a_ChunkX, int a_ChunkZ)
static cPluginManager * Get(void)
Returns the instance of the Plugin Manager (there is only ever one)
bool CallHookChunkUnloaded(cWorld &a_World, int a_ChunkX, int a_ChunkZ)
bool CallHookChunkUnloading(cWorld &a_World, int a_ChunkX, int a_ChunkZ)
int GetSizeY(void) const
Definition: BlockArea.h:348
int GetSizeZ(void) const
Definition: BlockArea.h:349
int GetSizeX(void) const
Definition: BlockArea.h:347
Represents two sets of coords, minimum and maximum for each direction.
Definition: BoundingBox.h:24
double GetMinZ(void) const
Definition: BoundingBox.h:94
double GetMaxX(void) const
Definition: BoundingBox.h:96
double GetMinX(void) const
Definition: BoundingBox.h:92
void Expand(double a_ExpandX, double a_ExpandY, double a_ExpandZ)
Expands the bounding box by the specified amount in each direction (so the box becomes larger by 2 * ...
Definition: BoundingBox.cpp:90
double GetMaxZ(void) const
Definition: BoundingBox.h:98
Definition: Chunk.h:36
void MarkRegenerating(void)
Marks all clients attached to this chunk as wanting this chunk.
Definition: Chunk.cpp:176
bool AddClient(cClientHandle *a_Client)
Adds a client to the chunk; returns true if added, false if already there.
Definition: Chunk.cpp:1520
@ cpQueued
The chunk is not present, but is queued for loading / generation.
Definition: Chunk.h:43
const auto & GetAllClients(void) const
Definition: Chunk.h:443
OwnedEntity RemoveEntity(cEntity &a_Entity)
Releases ownership of the given entity if it was found in this chunk.
Definition: Chunk.cpp:1602
void SetAlwaysTicked(bool a_AlwaysTicked)
Increments (a_AlwaysTicked == true) or decrements (false) the m_AlwaysTicked counter.
Definition: Chunk.cpp:1456
Wraps the chunk coords into a single structure.
Definition: ChunkDef.h:57
int m_ChunkZ
Definition: ChunkDef.h:60
int m_ChunkX
Definition: ChunkDef.h:59
static bool IsValidHeight(Vector3i a_BlockPosition)
Validates a height-coordinate.
Definition: ChunkDef.h:185
static void BlockToChunk(int a_X, int a_Z, int &a_ChunkX, int &a_ChunkZ)
Converts absolute block coords to chunk coords:
Definition: ChunkDef.h:210
static void AbsoluteToRelative(int &a_X, int &a_Y, int &a_Z, int &a_ChunkX, int &a_ChunkZ)
Converts absolute block coords into relative (chunk + block) coords:
Definition: ChunkDef.h:147
static const int Width
Definition: ChunkDef.h:124
NIBBLETYPE BlockNibbles[NumBlocks/2]
The type used for block data in nibble format, AXIS_ORDER ordering.
Definition: ChunkDef.h:143
Interface class used for comparing clients of two chunks.
Definition: ChunkDef.h:370
virtual void Removed(cClientHandle *a_Client)=0
Called for clients that are in Chunk1 and not in Chunk2,.
virtual void Added(cClientHandle *a_Client)=0
Called for clients that are in Chunk2 and not in Chunk1.
bool SetBiomeAt(int a_BlockX, int a_BlockZ, EMCSBiome a_Biome)
Sets the biome at the specified coords.
Definition: ChunkMap.cpp:678
bool ForEachLoadedChunk(cFunctionRef< bool(int, int)> a_Callback) const
Calls the callback for each loaded chunk.
Definition: ChunkMap.cpp:1196
BLOCKTYPE GetBlock(Vector3i a_BlockPos) const
Definition: ChunkMap.cpp:475
bool GetBlockTypeMeta(Vector3i a_BlockPos, BLOCKTYPE &a_BlockType, NIBBLETYPE &a_BlockMeta) const
Definition: ChunkMap.cpp:586
void UntrackInDeadlockDetect(cDeadlockDetect &a_DeadlockDetect)
Removes this chunkmap's CS from the DeadlockDetect's tracked CSs.
Definition: ChunkMap.cpp:1486
cChunk & GetChunk(int a_ChunkX, int a_ChunkZ)
Constructs a chunk and queues it for loading / generating if not valid, returning it.
Definition: ChunkMap.cpp:52
void PrepareChunk(int a_ChunkX, int a_ChunkZ, std::unique_ptr< cChunkCoordCallback > a_CallAfter={})
Queues the chunk for preparing - making sure that it's generated and lit.
Definition: ChunkMap.cpp:1096
void SpawnMobs(cMobSpawner &a_MobSpawner)
Try to Spawn Monsters inside all Chunks.
Definition: ChunkMap.cpp:1326
bool SetAreaBiome(int a_MinX, int a_MaxX, int a_MinZ, int a_MaxZ, EMCSBiome a_Biome)
Sets the biome at the area.
Definition: ChunkMap.cpp:697
void ChunkValidated(void)
Definition: ChunkMap.cpp:1458
void SetChunkAlwaysTicked(int a_ChunkX, int a_ChunkZ, bool a_AlwaysTicked)
Increments (a_AlwaysTicked == true) or decrements (false) the m_AlwaysTicked counter for the specifie...
Definition: ChunkMap.cpp:1467
void SendBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cClientHandle &a_Client)
Sends the block entity, if it is at the coords specified, to a_Client.
Definition: ChunkMap.cpp:93
bool DoWithChunk(int a_ChunkX, int a_ChunkZ, cChunkCallback a_Callback)
Calls the callback for the chunk specified, with ChunkMapCS locked; returns false if the chunk doesn'...
Definition: ChunkMap.cpp:128
NIBBLETYPE GetBlockMeta(Vector3i a_BlockPos) const
Definition: ChunkMap.cpp:494
NIBBLETYPE GetBlockSkyLight(Vector3i a_BlockPos) const
Definition: ChunkMap.cpp:513
void MarkChunkSaving(int a_ChunkX, int a_ChunkZ)
Definition: ChunkMap.cpp:185
void MarkChunkRegenerating(int a_ChunkX, int a_ChunkZ)
Marks the chunk as being regenerated - all its clients want that chunk again (used by cWorld::Regener...
Definition: ChunkMap.cpp:1141
cItems PickupsFromBlock(Vector3i a_BlockPos, const cEntity *a_Digger, const cItem *a_Tool)
Returns all the pickups that would result if the a_Digger dug up the block at a_BlockPos using a_Tool...
Definition: ChunkMap.cpp:787
void SaveAllChunks(void) const
Definition: ChunkMap.cpp:1414
bool IsChunkValid(int a_ChunkX, int a_ChunkZ) const
Definition: ChunkMap.cpp:361
bool IsChunkLighted(int a_ChunkX, int a_ChunkZ)
Definition: ChunkMap.cpp:1151
std::map< cChunkCoords, cChunk > m_Chunks
A map of chunk coordinates to chunks.
Definition: ChunkMap.h:301
void SetChunkData(SetChunkData &&a_SetChunkData)
Sets the chunk data as either loaded from the storage or generated.
Definition: ChunkMap.cpp:215
void RemoveClientFromChunks(cClientHandle *a_Client)
Removes the client from all chunks it is present in.
Definition: ChunkMap.cpp:895
void ChunkLoadFailed(int a_ChunkX, int a_ChunkZ)
Marks the chunk as failed-to-load.
Definition: ChunkMap.cpp:1129
NIBBLETYPE GetBlockBlockLight(Vector3i a_BlockPos) const
Definition: ChunkMap.cpp:532
void GenerateChunk(int a_ChunkX, int a_ChunkZ)
Queues the chunk for generating.
Definition: ChunkMap.cpp:1119
void GetChunkStats(int &a_NumChunksValid, int &a_NumChunksDirty) const
Returns the number of valid chunks and the number of dirty chunks.
Definition: ChunkMap.cpp:1254
void RemoveChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle *a_Client)
Removes the client from the chunk.
Definition: ChunkMap.cpp:883
void AddChunkStay(cChunkStay &a_ChunkStay)
Adds a new cChunkStay descendant to the internal list of ChunkStays; loads its chunks.
Definition: ChunkMap.cpp:1495
void AddEntity(OwnedEntity a_Entity)
Adds the entity to its appropriate chunk, takes ownership of the entity pointer.
Definition: ChunkMap.cpp:908
void SetNextBlockToTick(const Vector3i a_BlockPos)
Causes the specified block to be ticked on the next Tick() call.
Definition: ChunkMap.cpp:1290
void MarkChunkDirty(int a_ChunkX, int a_ChunkZ)
Definition: ChunkMap.cpp:170
bool GetBlockInfo(Vector3i, BLOCKTYPE &a_BlockType, NIBBLETYPE &a_Meta, NIBBLETYPE &a_SkyLight, NIBBLETYPE &a_BlockLight) const
Definition: ChunkMap.cpp:605
cChunk * FindChunk(int a_ChunkX, int a_ChunkZ)
Locates a chunk ptr in the chunkmap; doesn't create it when not found; assumes m_CSChunks is locked.
Definition: ChunkMap.cpp:69
cEvent m_evtChunkValid
Definition: ChunkMap.h:303
bool UseBlockEntity(cPlayer *a_Player, int a_X, int a_Y, int a_Z)
a_Player rclked block entity at the coords specified, handle it returns true if the use was successfu...
Definition: ChunkMap.cpp:110
void SetBlockMeta(Vector3i a_BlockPos, NIBBLETYPE a_BlockMeta)
Sets the meta for the specified block, while keeping the blocktype.
Definition: ChunkMap.cpp:551
void TickBlock(const Vector3i a_BlockPos)
Ticks a single block.
Definition: ChunkMap.cpp:1367
void ReplaceTreeBlocks(const sSetBlockVector &a_Blocks)
Special function used for growing trees, replaces only blocks that tree may overwrite.
Definition: ChunkMap.cpp:625
bool WriteBlockArea(cBlockArea &a_Area, int a_MinBlockX, int a_MinBlockY, int a_MinBlockZ, int a_DataTypes)
Writes the block area into the specified coords.
Definition: ChunkMap.cpp:1216
void FastSetBlock(Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
Sets the block at the specified coords to the specified value.
Definition: ChunkMap.cpp:425
cWorld * GetWorld(void) const
Definition: ChunkMap.h:262
bool ForEachEntity(cEntityCallback a_Callback) const
Calls the callback for each entity in the entire world; returns true if all entities processed,...
Definition: ChunkMap.cpp:982
bool ForEachEntityInBox(const cBoundingBox &a_Box, cEntityCallback a_Callback)
Calls the callback for each entity that has a nonempty intersection with the specified boundingbox.
Definition: ChunkMap.cpp:1014
bool DoWithBlockEntityAt(Vector3i a_Position, cBlockEntityCallback a_Callback)
Calls the callback for the block entity at the specified coords.
Definition: ChunkMap.cpp:1079
void DelChunkStay(cChunkStay &a_ChunkStay)
Removes the specified cChunkStay descendant from the internal list of ChunkStays.
Definition: ChunkMap.cpp:1526
OwnedEntity RemoveEntity(cEntity &a_Entity)
Removes the entity from its appropriate chunk Returns an owning reference to the found entity.
Definition: ChunkMap.cpp:964
void TrackInDeadlockDetect(cDeadlockDetect &a_DeadlockDetect, const AString &a_WorldName)
Adds this chunkmap's CS to the DeadlockDetect's tracked CSs.
Definition: ChunkMap.cpp:1477
void CollectPickupsByEntity(cEntity &a_Entity)
Makes the specified entity collect all the pickups around them.
Definition: ChunkMap.cpp:442
bool IsWeatherSunnyAt(int a_BlockX, int a_BlockZ) const
Definition: ChunkMap.cpp:304
void MarkChunkSaved(int a_ChunkX, int a_ChunkZ)
Definition: ChunkMap.cpp:200
void WakeUpSimulators(Vector3i a_Block)
Wakes up simulators for the specified block.
Definition: ChunkMap.cpp:153
bool GetBlocks(sSetBlockVector &a_Blocks, bool a_ContinueOnFailure)
Retrieves block types and metas of the specified blocks.
Definition: ChunkMap.cpp:735
bool IsChunkQueued(int a_ChunkX, int a_ChunkZ) const
Returns true iff the chunk is in the loader / generator queue.
Definition: ChunkMap.cpp:293
bool ForEachBlockEntityInChunk(int a_ChunkX, int a_ChunkZ, cBlockEntityCallback a_Callback)
Calls the callback for each block entity in the specified chunk.
Definition: ChunkMap.cpp:1064
bool HasEntity(UInt32 a_EntityID) const
Returns true if the entity with specified ID is present in the chunks.
Definition: ChunkMap.cpp:947
bool DigBlock(Vector3i a_BlockPos)
Removes the block at the specified coords and wakes up simulators.
Definition: ChunkMap.cpp:765
std::list< cChunkStay * > cChunkStays
Definition: ChunkMap.h:295
bool TryGetHeight(int a_BlockX, int a_BlockZ, int &a_Height)
Definition: ChunkMap.cpp:406
bool AddChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle *a_Client)
Adds client to a chunk, if not already present; returns true if added, false if present.
Definition: ChunkMap.cpp:873
cWorld * m_World
Definition: ChunkMap.h:305
void Tick(std::chrono::milliseconds a_Dt)
Definition: ChunkMap.cpp:1343
cChunkStays m_ChunkStays
The cChunkStay descendants that are currently enabled in this chunkmap.
Definition: ChunkMap.h:308
bool ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback a_Callback)
Calls the callback for each entity in the specified chunk; returns true if all entities processed,...
Definition: ChunkMap.cpp:999
EMCSBiome GetBiomeAt(int a_BlockX, int a_BlockZ) const
Returns the biome at the specified coords.
Definition: ChunkMap.cpp:660
void SetBlock(Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
Definition: ChunkMap.cpp:569
void UnloadUnusedChunks(void)
Definition: ChunkMap.cpp:1384
int GrowPlantAt(Vector3i a_BlockPos, int a_NumStages=1)
Grows the plant at the specified position by at most a_NumStages.
Definition: ChunkMap.cpp:1273
int GetHeight(int a_BlockX, int a_BlockZ)
Definition: ChunkMap.cpp:383
bool DoWithChunkAt(Vector3i a_BlockPos, cChunkCallback a_Callback)
Calls the callback for the chunk at the block position specified, with ChunkMapCS locked; returns fal...
Definition: ChunkMap.cpp:143
void CollectMobCensus(cMobCensus &a_ToFill)
Make a Mob census, of all mobs, their family, their chunk and their distance to closest player.
Definition: ChunkMap.cpp:1307
cCriticalSection m_CSChunks
Definition: ChunkMap.h:297
size_t GetNumChunks(void) const
Definition: ChunkMap.cpp:1430
bool ForEachChunkInRect(int a_MinChunkX, int a_MaxChunkX, int a_MinChunkZ, int a_MaxChunkZ, cChunkDataCallback &a_Callback)
Calls the callback for each chunk in the coords specified (all cords are inclusive).
Definition: ChunkMap.cpp:1167
size_t GetNumUnusedDirtyChunks(void) const
Returns the number of unused dirty chunks.
Definition: ChunkMap.cpp:1440
void SendBlockTo(int a_BlockX, int a_BlockY, int a_BlockZ, const cPlayer &a_Player)
Sends the block at the specified coords to the specified player.
Definition: ChunkMap.cpp:805
bool IsWeatherWetAt(int a_BlockX, int a_BlockZ) const
Definition: ChunkMap.cpp:323
cChunk & ConstructChunk(int a_ChunkX, int a_ChunkZ)
Returns or creates and returns a chunk pointer corresponding to the given chunk coordinates.
Definition: ChunkMap.cpp:39
bool DoWithEntityByID(UInt32 a_EntityID, cEntityCallback a_Callback) const
Calls the callback if the entity with the specified ID is found, with the entity object as the callba...
Definition: ChunkMap.cpp:1046
bool HasChunkAnyClients(int a_ChunkX, int a_ChunkZ) const
Definition: ChunkMap.cpp:372
void ChunkLighted(int a_ChunkX, int a_ChunkZ, const cChunkDef::BlockNibbles &a_BlockLight, const cChunkDef::BlockNibbles &a_SkyLight)
Definition: ChunkMap.cpp:251
bool GetChunkData(cChunkCoords a_Coords, cChunkDataCallback &a_Callback) const
Calls the callback with the chunk's data, if available (with ChunkCS locked).
Definition: ChunkMap.cpp:271
void CompareChunkClients(int a_ChunkX1, int a_ChunkZ1, int a_ChunkX2, int a_ChunkZ2, cClientDiffCallback &a_Callback)
Compares clients of two chunks, calls the callback accordingly.
Definition: ChunkMap.cpp:822
void AddPlayer(std::unique_ptr< cPlayer > a_Player)
Adds the player to its appropriate chunk, takes ownership of the player pointer.
Definition: ChunkMap.cpp:935
cChunkMap(cWorld *a_World)
Definition: ChunkMap.cpp:30
Makes chunks stay loaded until this object is cleared or destroyed Works by setting internal flags in...
Definition: ChunkStay.h:36
virtual void Disable(void)
Disables the ChunkStay, the chunks are released and the ChunkStay object can be edited with Add() and...
Definition: ChunkStay.cpp:93
bool ChunkAvailable(int a_ChunkX, int a_ChunkZ)
Called by cChunkMap when a chunk is available, checks m_NumLoaded and triggers the appropriate callba...
Definition: ChunkStay.cpp:106
virtual void OnDisabled(void)=0
Called by the ChunkMap when the ChunkStay is disabled.
const cChunkCoordsVector & GetChunks(void) const
Returns all the chunks that should be kept.
Definition: ChunkStay.h:63
void UntrackCriticalSection(cCriticalSection &a_CS)
Removes the CS from the tracking.
void TrackCriticalSection(cCriticalSection &a_CS, const AString &a_Name)
Adds the critical section for tracking.
Definition: Entity.h:76
bool IsProjectile(void) const
Definition: Entity.h:168
bool IsPlayer(void) const
Definition: Entity.h:160
cBoundingBox GetBoundingBox() const
Definition: Entity.h:211
bool IsPickup(void) const
Definition: Entity.h:161
cChunk * GetParentChunk()
Returns the chunk responsible for ticking this entity.
Definition: Entity.h:541
Definition: Player.h:29
cClientHandle * GetClientHandle(void) const
Definition: Player.h:276
Definition: Item.h:37
This class bridges a vector of cItem for safe access via Lua.
Definition: Item.h:215
void QueueChunk(int a_ChunkX, int a_ChunkZ, std::unique_ptr< cChunkCoordCallback > a_CallbackAfter)
Queues the entire chunk for lighting.
This class is used to collect information, for each Mob, what is the distance of the closest player i...
Definition: MobCensus.h:26
This class is used to determine which monster can be spawned in which place it is essentially static ...
Definition: MobSpawner.h:16
bool IsLockedByCurrentThread(void)
Returns true if the CS is currently locked by the thread calling this function.
RAII for cCriticalSection - locks the CS on creation, unlocks on destruction.
Temporary RAII unlock for a cCSLock.
void Wait(void)
Waits until the event has been set.
Definition: Event.cpp:23
void Set(void)
Sets the event - releases one thread that has been waiting in Wait().
Definition: Event.cpp:52
Contains the data for a loaded / generated chunk, ready to be set into a cWorld.
Definition: SetChunkData.h:12
void WakeUp(cChunk &a_Chunk, Vector3i a_Position)
Definition: World.h:53
bool IsWeatherSunny(void) const
Returns true if the current weather is sunny.
Definition: World.h:811
cLightingThread & GetLightingThread(void)
Definition: World.h:771
cWorldStorage & GetStorage(void)
Definition: World.h:851
bool IsWeatherWet(void) const
Returns true if the world currently has any precipitation - rain, storm or snow.
Definition: World.h:835
cSimulatorManager * GetSimulatorManager(void)
Definition: World.h:597
void QueueLoadChunk(int a_ChunkX, int a_ChunkZ)
Queues a chunk to be loaded, asynchronously.
void QueueSaveChunk(int a_ChunkX, int a_ChunkZ)
Queues a chunk to be saved, asynchronously.