Cuberite
A lightweight, fast and extensible game server for Minecraft
World.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 "World.h"
5 #include "BlockInfo.h"
6 #include "ClientHandle.h"
7 #include "Physics/Explodinator.h"
8 #include "Server.h"
9 #include "Root.h"
10 #include "IniFile.h"
11 #include "Generating/ChunkDesc.h"
13 #include "SetChunkData.h"
14 #include "DeadlockDetect.h"
15 #include "LineBlockTracer.h"
16 #include "UUID.h"
18 
19 // Serializers
21 
22 // Entities (except mobs):
23 #include "Entities/EnderCrystal.h"
24 #include "Entities/ExpOrb.h"
25 #include "Entities/FallingBlock.h"
26 #include "Entities/Minecart.h"
27 #include "Entities/Pickup.h"
28 #include "Entities/Player.h"
29 #include "Entities/TNTEntity.h"
30 
33 
34 // Simulators:
44 
45 // Mobs:
47 #include "MobCensus.h"
48 #include "MobSpawner.h"
49 
50 #include "Generating/Trees.h"
51 #include "Bindings/PluginManager.h"
52 #include "Blocks/BlockHandler.h"
53 
54 #ifndef _WIN32
55  #include <stdlib.h>
56 #endif
57 
58 #include "SpawnPrepare.h"
59 #include "FastRandom.h"
60 #include "OpaqueWorld.h"
61 
62 
63 
64 
65 
66 namespace World
67 {
68  // Implement conversion functions from OpaqueWorld.h
69  cBroadcastInterface * GetBroadcastInterface(cWorld * a_World) { return a_World; }
70  cForEachChunkProvider * GetFECProvider (cWorld * a_World) { return a_World; }
71  cWorldInterface * GetWorldInterface (cWorld * a_World) { return a_World; }
72 
74  {
75  return { a_World.GetChunkMap() };
76  }
77 }
78 
79 
80 
81 
82 
84 // cWorld::cLock:
85 
86 cWorld::cLock::cLock(const cWorld & a_World) :
87  Super(&(a_World.m_ChunkMap.GetCS()))
88 {
89 }
90 
91 
92 
93 
94 
96 // cWorld::cTickThread:
97 
99  Super(fmt::format(FMT_STRING("World Ticker ({})"), a_World.GetName())),
100  m_World(a_World)
101 {
102 }
103 
104 
105 
106 
107 
109 {
110  auto LastTime = std::chrono::steady_clock::now();
111  auto TickTime = std::chrono::duration_cast<std::chrono::milliseconds>(1_tick);
112 
113  while (!m_ShouldTerminate)
114  {
115  auto NowTime = std::chrono::steady_clock::now();
116  auto WaitTime = std::chrono::duration_cast<std::chrono::milliseconds>(NowTime - LastTime);
117  m_World.Tick(WaitTime, TickTime);
118  TickTime = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - NowTime);
119 
120  if (TickTime < 1_tick)
121  {
122  // Stretch tick time until it's at least 1 tick:
123  std::this_thread::sleep_for(1_tick - TickTime);
124  }
125 
126  LastTime = NowTime;
127  }
128 }
129 
130 
131 
132 
133 
135 // cWorld:
136 
138  const AString & a_WorldName, const AString & a_DataPath,
139  cDeadlockDetect & a_DeadlockDetect, const AStringVector & a_WorldNames,
140  eDimension a_Dimension, const AString & a_LinkedOverworldName
141 ):
142  m_WorldName(a_WorldName),
143  m_DataPath(a_DataPath),
144  m_LinkedOverworldName(a_LinkedOverworldName),
145  m_IniFileName(m_DataPath + "/world.ini"),
146  m_StorageSchema("Default"),
147 #ifdef __arm__
149 #else
151 #endif
152  m_IsSavingEnabled(true),
153  m_Dimension(a_Dimension),
154  m_IsSpawnExplicitlySet(false),
155  m_SpawnX(0),
156  m_SpawnY(cChunkDef::Height),
157  m_SpawnZ(0),
161  m_WorldAge(0),
162  m_WorldDate(0),
163  m_WorldTickAge(0),
164  m_LastChunkCheck(0),
165  m_LastSave(0),
166  m_SkyDarkness(0),
168  m_bEnabledPVP(false),
170  m_IsDeepSnowEnabled(false),
171  m_ShouldLavaSpawnFire(true),
174  m_SandSimulator(),
175  m_WaterSimulator(nullptr),
176  m_LavaSimulator(nullptr),
177  m_FireSimulator(),
178  m_RedstoneSimulator(nullptr),
179  m_MaxPlayers(10),
180  m_ChunkMap(this),
181  m_bAnimals(true),
183  m_WeatherInterval(24000), // Guaranteed 1 game-day of sunshine at server start :)
184  m_MaxSunnyTicks(180000), // 150 real-world minutes -+
185  m_MinSunnyTicks(12000), // 10 real-world minutes |
186  m_MaxRainTicks(24000), // 20 real-world minutes +- all values adapted from Vanilla 1.7.2
187  m_MinRainTicks(12000), // 10 real-world minutes |
188  m_MaxThunderStormTicks(15600), // 13 real-world minutes |
189  m_MinThunderStormTicks(3600), // 3 real-world minutes -+
192  /* TODO: Enable when functionality exists again
193  m_IsBeetrootsBonemealable(true),
194  m_IsCactusBonemealable(false),
195  m_IsCarrotsBonemealable(true),
196  m_IsCropsBonemealable(true),
197  m_IsGrassBonemealable(true),
198  m_IsMelonStemBonemealable(true),
199  m_IsMelonBonemealable(true),
200  m_IsPotatoesBonemealable(true),
201  m_IsPumpkinStemBonemealable(true),
202  m_IsPumpkinBonemealable(true),
203  m_IsSaplingBonemealable(true),
204  m_IsSugarcaneBonemealable(false),
205  m_IsBigFlowerBonemealable(true),
206  m_IsTallGrassBonemealable(true),
207  */
209  m_bUseChatPrefixes(false),
211  m_MaxViewDistance(12),
212  m_Scoreboard(this),
213  m_MapManager(this),
214  m_GeneratorCallbacks(*this),
215  m_ChunkSender(*this),
216  m_Lighting(*this),
217  m_TickThread(*this)
218 {
219  LOGD("cWorld::cWorld(\"%s\")", a_WorldName);
220 
222 
223  m_ChunkMap.TrackInDeadlockDetect(a_DeadlockDetect, m_WorldName);
224 
225  // Load the scoreboard
227  Serializer.Load();
228 
229  // Track the CSs used by this world in the deadlock detector:
230  a_DeadlockDetect.TrackCriticalSection(m_CSTasks, fmt::format(FMT_STRING("World {} tasks"), m_WorldName));
231 
232  // Load world settings from the ini file
233  cIniFile IniFile;
234  if (!IniFile.ReadFile(m_IniFileName))
235  {
236  LOGWARNING("Cannot read world settings from \"%s\", defaults will be used.", m_IniFileName);
237 
238  // TODO: More descriptions for each key
239  IniFile.AddHeaderComment(" This is the per-world configuration file, managing settings such as generators, simulators, and spawn points");
240  IniFile.AddKeyComment(" LinkedWorlds", "This section governs portal world linkage; leave a value blank to disabled that associated method of teleportation");
241  }
242 
243  // The presence of a configuration value overrides everything
244  // If no configuration value is found, GetDimension() is written to file and the variable is written to again to ensure that cosmic rays haven't sneakily changed its value
245  m_Dimension = StringToDimension(IniFile.GetValueSet("General", "Dimension", DimensionToString(GetDimension())));
246  int UnusedDirtyChunksCap = IniFile.GetValueSetI("General", "UnusedChunkCap", 1000);
247  if (UnusedDirtyChunksCap < 0)
248  {
249  UnusedDirtyChunksCap *= -1;
250  IniFile.SetValueI("General", "UnusedChunkCap", UnusedDirtyChunksCap);
251  }
252  m_UnusedDirtyChunksCap = static_cast<size_t>(UnusedDirtyChunksCap);
253 
254  m_BroadcastDeathMessages = IniFile.GetValueSetB("Broadcasting", "BroadcastDeathMessages", true);
255  m_BroadcastAchievementMessages = IniFile.GetValueSetB("Broadcasting", "BroadcastAchievementMessages", true);
256 
257  SetMaxViewDistance(IniFile.GetValueSetI("SpawnPosition", "MaxViewDistance", cClientHandle::DEFAULT_VIEW_DISTANCE));
258 
259  // Try to find the "SpawnPosition" key and coord values in the world configuration, set the flag if found
260  int KeyNum = IniFile.FindKey("SpawnPosition");
262  (
263  (KeyNum >= 0) &&
264  (
265  (IniFile.FindValue(KeyNum, "X") >= 0) &&
266  (IniFile.FindValue(KeyNum, "Y") >= 0) &&
267  (IniFile.FindValue(KeyNum, "Z") >= 0)
268  )
269  );
270 
272  {
273  LOGD("Spawnpoint explicitly set!");
274  m_SpawnX = IniFile.GetValueI("SpawnPosition", "X", m_SpawnX);
275  m_SpawnY = IniFile.GetValueI("SpawnPosition", "Y", m_SpawnY);
276  m_SpawnZ = IniFile.GetValueI("SpawnPosition", "Z", m_SpawnZ);
277  }
278 
279  m_StorageSchema = IniFile.GetValueSet ("Storage", "Schema", m_StorageSchema);
280  m_StorageCompressionFactor = IniFile.GetValueSetI("Storage", "CompressionFactor", m_StorageCompressionFactor);
281  m_MaxCactusHeight = IniFile.GetValueSetI("Plants", "MaxCactusHeight", 3);
282  m_MaxSugarcaneHeight = IniFile.GetValueSetI("Plants", "MaxSugarcaneHeight", 3);
283  /* TODO: Enable when functionality exists again
284  m_IsBeetrootsBonemealable = IniFile.GetValueSetB("Plants", "IsBeetrootsBonemealable", true);
285  m_IsCactusBonemealable = IniFile.GetValueSetB("Plants", "IsCactusBonemealable", false);
286  m_IsCarrotsBonemealable = IniFile.GetValueSetB("Plants", "IsCarrotsBonemealable", true);
287  m_IsCropsBonemealable = IniFile.GetValueSetB("Plants", "IsCropsBonemealable", true);
288  m_IsGrassBonemealable = IniFile.GetValueSetB("Plants", "IsGrassBonemealable", true);
289  m_IsMelonStemBonemealable = IniFile.GetValueSetB("Plants", "IsMelonStemBonemealable", true);
290  m_IsMelonBonemealable = IniFile.GetValueSetB("Plants", "IsMelonBonemealable", false);
291  m_IsPotatoesBonemealable = IniFile.GetValueSetB("Plants", "IsPotatoesBonemealable", true);
292  m_IsPumpkinStemBonemealable = IniFile.GetValueSetB("Plants", "IsPumpkinStemBonemealable", true);
293  m_IsPumpkinBonemealable = IniFile.GetValueSetB("Plants", "IsPumpkinBonemealable", false);
294  m_IsSaplingBonemealable = IniFile.GetValueSetB("Plants", "IsSaplingBonemealable", true);
295  m_IsSugarcaneBonemealable = IniFile.GetValueSetB("Plants", "IsSugarcaneBonemealable", false);
296  m_IsBigFlowerBonemealable = IniFile.GetValueSetB("Plants", "IsBigFlowerBonemealable", true);
297  m_IsTallGrassBonemealable = IniFile.GetValueSetB("Plants", "IsTallGrassBonemealable", true);
298  */
299  m_IsDeepSnowEnabled = IniFile.GetValueSetB("Physics", "DeepSnow", true);
300  m_ShouldLavaSpawnFire = IniFile.GetValueSetB("Physics", "ShouldLavaSpawnFire", true);
301  int TNTShrapnelLevel = IniFile.GetValueSetI("Physics", "TNTShrapnelLevel", static_cast<int>(slAll));
302  m_bCommandBlocksEnabled = IniFile.GetValueSetB("Mechanics", "CommandBlocksEnabled", false);
303  m_bEnabledPVP = IniFile.GetValueSetB("Mechanics", "PVPEnabled", true);
304  m_bFarmlandTramplingEnabled = IniFile.GetValueSetB("Mechanics", "FarmlandTramplingEnabled", true);
305  m_bUseChatPrefixes = IniFile.GetValueSetB("Mechanics", "UseChatPrefixes", true);
306  m_MinNetherPortalWidth = IniFile.GetValueSetI("Mechanics", "MinNetherPortalWidth", 2);
307  m_MaxNetherPortalWidth = IniFile.GetValueSetI("Mechanics", "MaxNetherPortalWidth", 21);
308  m_MinNetherPortalHeight = IniFile.GetValueSetI("Mechanics", "MinNetherPortalHeight", 3);
309  m_MaxNetherPortalHeight = IniFile.GetValueSetI("Mechanics", "MaxNetherPortalHeight", 21);
310  m_VillagersShouldHarvestCrops = IniFile.GetValueSetB("Monsters", "VillagersShouldHarvestCrops", true);
311  m_IsDaylightCycleEnabled = IniFile.GetValueSetB("General", "IsDaylightCycleEnabled", true);
312  int GameMode = IniFile.GetValueSetI("General", "Gamemode", static_cast<int>(m_GameMode));
313  int Weather = IniFile.GetValueSetI("General", "Weather", static_cast<int>(m_Weather));
314 
315  m_WorldAge = std::chrono::milliseconds(IniFile.GetValueSetI("General", "WorldAgeMS", 0LL));
316 
317  // Load the weather frequency data:
318  if (m_Dimension == dimOverworld)
319  {
320  m_MaxSunnyTicks = IniFile.GetValueSetI("Weather", "MaxSunnyTicks", m_MaxSunnyTicks);
321  m_MinSunnyTicks = IniFile.GetValueSetI("Weather", "MinSunnyTicks", m_MinSunnyTicks);
322  m_MaxRainTicks = IniFile.GetValueSetI("Weather", "MaxRainTicks", m_MaxRainTicks);
323  m_MinRainTicks = IniFile.GetValueSetI("Weather", "MinRainTicks", m_MinRainTicks);
324  m_MaxThunderStormTicks = IniFile.GetValueSetI("Weather", "MaxThunderStormTicks", m_MaxThunderStormTicks);
325  m_MinThunderStormTicks = IniFile.GetValueSetI("Weather", "MinThunderStormTicks", m_MinThunderStormTicks);
327  {
328  std::swap(m_MaxSunnyTicks, m_MinSunnyTicks);
329  }
331  {
332  std::swap(m_MaxRainTicks, m_MinRainTicks);
333  }
335  {
337  }
338  }
339 
340  auto WorldExists = [&](const AString & a_CheckWorldName)
341  {
342  return (std::find(a_WorldNames.begin(), a_WorldNames.end(), a_CheckWorldName) != a_WorldNames.end());
343  };
344 
345  if (a_Dimension == dimOverworld)
346  {
347  AString MyNetherName = GetName() + "_nether";
348  AString MyEndName = GetName() + "_the_end";
349  if (!WorldExists(MyNetherName))
350  {
351  MyNetherName.clear();
352  }
353  if (!WorldExists(MyEndName))
354  {
355  MyEndName = GetName() + "_end";
356  if (!WorldExists(MyEndName))
357  {
358  MyEndName.clear();
359  }
360  }
361 
362  m_LinkedNetherWorldName = IniFile.GetValueSet("LinkedWorlds", "NetherWorldName", MyNetherName);
363  m_LinkedEndWorldName = IniFile.GetValueSet("LinkedWorlds", "EndWorldName", MyEndName);
364  }
365  else
366  {
367  m_LinkedOverworldName = IniFile.GetValueSet("LinkedWorlds", "OverworldName", GetLinkedOverworldName());
368  }
369 
370  // If we are linked to one or more worlds that do not exist, unlink them
371  if (a_Dimension == dimOverworld)
372  {
373  if (!m_LinkedNetherWorldName.empty() && !WorldExists(m_LinkedNetherWorldName))
374  {
375  IniFile.SetValue("LinkedWorlds", "NetherWorldName", "");
376  LOG("%s Is linked to a nonexisting nether world called \"%s\". The server has modified \"%s/world.ini\" and removed this invalid link.",
377  GetName().c_str(), m_LinkedNetherWorldName.c_str(), GetName().c_str());
378  m_LinkedNetherWorldName.clear();
379  }
380  if (!m_LinkedEndWorldName.empty() && !WorldExists(m_LinkedEndWorldName))
381  {
382  IniFile.SetValue("LinkedWorlds", "EndWorldName", "");
383  LOG("%s Is linked to a nonexisting end world called \"%s\". The server has modified \"%s/world.ini\" and removed this invalid link.",
384  GetName().c_str(), m_LinkedEndWorldName.c_str(), GetName().c_str());
385  m_LinkedEndWorldName.clear();
386  }
387  }
388  else
389  {
390  if (!m_LinkedOverworldName.empty() && !WorldExists(m_LinkedOverworldName))
391  {
392  IniFile.SetValue("LinkedWorlds", "OverworldName", "");
393  LOG("%s Is linked to a nonexisting overworld called \"%s\". The server has modified \"%s/world.ini\" and removed this invalid link.",
394  GetName().c_str(), m_LinkedOverworldName.c_str(), GetName().c_str());
395  m_LinkedOverworldName.clear();
396  }
397  }
398 
399 
400 
401  // Adjust the enum-backed variables into their respective bounds:
402  m_GameMode = static_cast<eGameMode> (Clamp<int>(GameMode, gmSurvival, gmSpectator));
403  m_TNTShrapnelLevel = static_cast<eShrapnelLevel>(Clamp<int>(TNTShrapnelLevel, slNone, slAll));
404  m_Weather = static_cast<eWeather> (Clamp<int>(Weather, wSunny, wStorm));
405 
407 
409  m_WorldDate = cTickTime(IniFile.GetValueSetI("General", "TimeInTicks", GetWorldDate().count()));
410 
411  // preallocate some memory for ticking blocks so we don't need to allocate that often
412  m_BlockTickQueue.reserve(1000);
413  m_BlockTickQueueCopy.reserve(1000);
414 
415  // Simulators:
416  m_SimulatorManager = std::make_unique<cSimulatorManager>(*this);
419  m_SandSimulator = std::make_unique<cSandSimulator>(*this, IniFile);
420  m_FireSimulator = std::make_unique<cFireSimulator>(*this, IniFile);
422 
423  // Water, Lava and Redstone simulators get registered in their initialize function.
424  m_SimulatorManager->RegisterSimulator(m_SandSimulator.get(), 1);
425  m_SimulatorManager->RegisterSimulator(m_FireSimulator.get(), 1);
426 
429 
431 
432  // Save any changes that the defaults may have done to the ini file:
433  if (!IniFile.WriteFile(m_IniFileName))
434  {
435  LOGWARNING("Could not write world config to %s", m_IniFileName.c_str());
436  }
437 
438  // Init of the spawn monster time (as they are supposed to have different spawn rate)
439  m_LastSpawnMonster.emplace(cMonster::mfHostile, 0_tick);
440  m_LastSpawnMonster.emplace(cMonster::mfPassive, 0_tick);
441  m_LastSpawnMonster.emplace(cMonster::mfAmbient, 0_tick);
442  m_LastSpawnMonster.emplace(cMonster::mfWater, 0_tick);
443 }
444 
445 
446 
447 
448 
450 {
451  delete m_WaterSimulator; m_WaterSimulator = nullptr;
452  delete m_LavaSimulator; m_LavaSimulator = nullptr;
453  delete m_RedstoneSimulator; m_RedstoneSimulator = nullptr;
454 }
455 
456 
457 
458 
459 
460 void cWorld::CastThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ)
461 {
462  LOG("CastThunderbolt(int, int, int) is deprecated, use CastThunderbolt(Vector3i) instead");
463  CastThunderbolt({a_BlockX, a_BlockY, a_BlockZ});
464 }
465 
466 
467 
468 
469 
471 {
472  BroadcastThunderbolt(a_Block);
473  BroadcastSoundEffect("entity.lightning.thunder", a_Block, 50, 1);
474 }
475 
476 
477 
478 
479 
481 {
482  using namespace std::chrono_literals;
483 
484  return std::chrono::duration_cast<cTickTime>(m_WorldDate % 20min);
485 }
486 
487 
488 
489 
490 
492 {
493  return std::chrono::duration_cast<cTickTimeLong>(m_WorldAge);
494 }
495 
496 
497 
498 
499 
501 {
502  return std::chrono::duration_cast<cTickTimeLong>(m_WorldDate);
503 }
504 
505 
506 
507 
508 
510 {
511  return m_WorldTickAge;
512 }
513 
514 
515 
516 
517 
518 void cWorld::SetTimeOfDay(const cTickTime a_TimeOfDay)
519 {
520  using namespace std::chrono_literals;
521 
522  m_WorldDate = (m_WorldDate / 20min) * 20min + a_TimeOfDay;
525 }
526 
527 
528 
529 
530 
532 {
533  auto & Random = GetRandomProvider();
534  switch (a_Weather)
535  {
536  case eWeather_Sunny:
537  {
538  return Random.RandInt(m_MinSunnyTicks, m_MaxSunnyTicks);
539  }
540  case eWeather_Rain:
541  {
542  return Random.RandInt(m_MinRainTicks, m_MaxRainTicks);
543  }
545  {
546  return Random.RandInt(m_MinThunderStormTicks, m_MaxThunderStormTicks);
547  }
548  }
549  UNREACHABLE("Unsupported weather");
550 }
551 
552 
553 
554 
555 
556 void cWorld::SetWeather(eWeather a_NewWeather)
557 {
558  // Do the plugins agree? Do they want a different weather?
559  if (cRoot::Get()->GetPluginManager()->CallHookWeatherChanging(*this, a_NewWeather))
560  {
562  return;
563  }
564 
565  // Set new period for the selected weather:
567 
568  // The weather can't be found:
569  if (m_WeatherInterval < 0)
570  {
571  return;
572  }
573 
574  m_Weather = a_NewWeather;
576 
577  // Let the plugins know about the change:
579 }
580 
581 
582 
583 
584 
586 {
587  // In the next tick the weather will be changed
588  m_WeatherInterval = 0;
589 }
590 
591 
592 
593 
594 
595 bool cWorld::IsWeatherSunnyAt(int a_BlockX, int a_BlockZ) const
596 {
597  return m_ChunkMap.IsWeatherSunnyAt(a_BlockX, a_BlockZ);
598 }
599 
600 
601 
602 
603 
604 bool cWorld::IsWeatherWetAt(int a_BlockX, int a_BlockZ)
605 {
606  return m_ChunkMap.IsWeatherWetAt(a_BlockX, a_BlockZ);
607 }
608 
609 
610 
611 
612 
613 bool cWorld::IsWeatherWetAtXYZ(const Vector3i a_Position)
614 {
615  return m_ChunkMap.IsWeatherWetAt(a_Position);
616 }
617 
618 
619 
620 
621 
622 void cWorld::SetNextBlockToTick(const Vector3i a_BlockPos)
623 {
624  return m_ChunkMap.SetNextBlockToTick(a_BlockPos);
625 }
626 
627 
628 
629 
630 
631 bool cWorld::SetSpawn(int a_X, int a_Y, int a_Z)
632 {
633  cIniFile IniFile;
634 
635  IniFile.ReadFile(m_IniFileName);
636  IniFile.SetValueI("SpawnPosition", "X", a_X);
637  IniFile.SetValueI("SpawnPosition", "Y", a_Y);
638  IniFile.SetValueI("SpawnPosition", "Z", a_Z);
639  if (IniFile.WriteFile(m_IniFileName))
640  {
641  m_SpawnX = a_X;
642  m_SpawnY = a_Y;
643  m_SpawnZ = a_Z;
644  FLOGD("Spawn set at {}", Vector3i{m_SpawnX, m_SpawnY, m_SpawnZ});
645  return true;
646  }
647  else
648  {
649  LOGWARNING("Couldn't write new spawn settings to \"%s\".", m_IniFileName.c_str());
650  }
651  return false;
652 }
653 
654 
655 
656 
657 
659 {
660  // For the debugging builds, don't make the server build too much world upon start:
661  #if !defined(NDEBUG) || defined(ANDROID)
662  const int DefaultViewDist = 9;
663  #else
664  const int DefaultViewDist = 20; // Always prepare an area 20 chunks across, no matter what the actual cClientHandle::VIEWDISTANCE is
665  #endif // !NDEBUG
666 
668  {
669  // Spawn position wasn't already explicitly set, enumerate random solid-land coordinate and then write it to the world configuration:
670  GenerateRandomSpawn(DefaultViewDist);
671  }
672 
673  cIniFile IniFile;
674  IniFile.ReadFile(m_IniFileName);
675  int ViewDist = IniFile.GetValueSetI("SpawnPosition", "PregenerateDistance", DefaultViewDist);
676  IniFile.WriteFile(m_IniFileName);
677 
678  int ChunkX = 0, ChunkZ = 0;
679  cChunkDef::BlockToChunk(m_SpawnX, m_SpawnZ, ChunkX, ChunkZ);
680  cSpawnPrepare::PrepareChunks(*this, ChunkX, ChunkZ, ViewDist);
681 }
682 
683 
684 
685 
686 
688 {
689  m_Lighting.Start();
690  m_Storage.Start();
691  m_Generator.Start();
694 }
695 
696 
697 
698 
699 
700 void cWorld::GenerateRandomSpawn(int a_MaxSpawnRadius)
701 {
702  LOGD("Generating random spawnpoint...");
703 
704  // Number of checks to make sure we have a valid biome
705  // 100 checks will check across 400 chunks, we should have
706  // a valid biome by then.
707  static const int BiomeCheckCount = 100;
708 
709  // Make sure we are in a valid biome
710  Vector3i BiomeOffset = Vector3i(0, 0, 0);
711  for (int BiomeCheckIndex = 0; BiomeCheckIndex < BiomeCheckCount; ++BiomeCheckIndex)
712  {
713  EMCSBiome Biome = GetBiomeAt(BiomeOffset.x, BiomeOffset.z);
714  if ((Biome == EMCSBiome::biOcean) || (Biome == EMCSBiome::biFrozenOcean))
715  {
716  BiomeOffset += Vector3d(cChunkDef::Width * 4, 0, 0);
717  continue;
718  }
719 
720  // Found a usable biome
721  // Spawn chunks so we can find a nice spawn.
722  int ChunkX = 0, ChunkZ = 0;
723  cChunkDef::BlockToChunk(BiomeOffset.x, BiomeOffset.z, ChunkX, ChunkZ);
724  cSpawnPrepare::PrepareChunks(*this, ChunkX, ChunkZ, a_MaxSpawnRadius);
725  break;
726  }
727 
728  // Check 0, 0 first.
729  int SpawnY = 0;
730  if (CanSpawnAt(BiomeOffset.x, SpawnY, BiomeOffset.z))
731  {
732  SetSpawn(BiomeOffset.x, SpawnY, BiomeOffset.z);
733 
734  FLOGINFO("World \"{}\": Generated spawnpoint position at {}", m_WorldName, Vector3i{m_SpawnX, m_SpawnY, m_SpawnZ});
735  return;
736  }
737 
738  // A search grid (searches clockwise around the origin)
739  static const int HalfChunk = cChunkDef::Width / 2;
740  static const Vector3i ChunkOffset[] =
741  {
742  Vector3i(0, 0, HalfChunk),
743  Vector3i(HalfChunk, 0, HalfChunk),
744  Vector3i(HalfChunk, 0, 0),
745  Vector3i(HalfChunk, 0, -HalfChunk),
746  Vector3i(0, 0, -HalfChunk),
747  Vector3i(-HalfChunk, 0, -HalfChunk),
748  Vector3i(-HalfChunk, 0, 0),
749  Vector3i(-HalfChunk, 0, HalfChunk),
750  };
751 
752  static const int PerRadiSearchCount = ARRAYCOUNT(ChunkOffset);
753 
754  for (int RadiusOffset = 1; RadiusOffset < (a_MaxSpawnRadius * 2); ++RadiusOffset)
755  {
756  for (int SearchGridIndex = 0; SearchGridIndex < PerRadiSearchCount; ++SearchGridIndex)
757  {
758  const Vector3i PotentialSpawn = BiomeOffset + (ChunkOffset[SearchGridIndex] * RadiusOffset);
759 
760  if (CanSpawnAt(PotentialSpawn.x, SpawnY, PotentialSpawn.z))
761  {
762  SetSpawn(PotentialSpawn.x, SpawnY, PotentialSpawn.z);
763 
764  int ChunkX, ChunkZ;
765  cChunkDef::BlockToChunk(m_SpawnX, m_SpawnZ, ChunkX, ChunkZ);
766  cSpawnPrepare::PrepareChunks(*this, ChunkX, ChunkZ, a_MaxSpawnRadius);
767 
768  FLOGINFO("World \"{}\":Generated spawnpoint position at {}", m_WorldName, Vector3i{m_SpawnX, m_SpawnY, m_SpawnZ});
769  return;
770  }
771  }
772  }
773 
775  FLOGWARNING("World \"{}\": Did not find an acceptable spawnpoint. Generated a random spawnpoint position at {}", m_WorldName, Vector3i{m_SpawnX, m_SpawnY, m_SpawnZ});
776 }
777 
778 
779 
780 
781 
782 bool cWorld::CanSpawnAt(int a_X, int & a_Y, int a_Z)
783 {
784  // All this blocks can only be found above ground.
785  // Apart from netherrack (as the Nether is technically a massive cave)
786  static const BLOCKTYPE ValidSpawnBlocks[] =
787  {
789  E_BLOCK_SAND,
790  E_BLOCK_SNOW,
793  };
794 
795  static const int ValidSpawnBlocksCount = ARRAYCOUNT(ValidSpawnBlocks);
796 
797  // Increase this by two, because we need two more blocks for body and head
798  static const int HighestSpawnPoint = GetHeight(a_X, a_Z) + 2;
799  static const int LowestSpawnPoint = HighestSpawnPoint / 2;
800 
801  for (int PotentialY = HighestSpawnPoint; PotentialY > LowestSpawnPoint; --PotentialY)
802  {
803  BLOCKTYPE HeadBlock = GetBlock({ a_X, PotentialY, a_Z });
804 
805  // Is this block safe for spawning
806  if (HeadBlock != E_BLOCK_AIR)
807  {
808  continue;
809  }
810 
811  BLOCKTYPE BodyBlock = GetBlock({ a_X, PotentialY - 1, a_Z });
812 
813  // Is this block safe for spawning
814  if (BodyBlock != E_BLOCK_AIR)
815  {
816  continue;
817  }
818 
819  BLOCKTYPE FloorBlock = GetBlock({ a_X, PotentialY - 2, a_Z });
820 
821  // Early out - Is the floor block air
822  if (FloorBlock == E_BLOCK_AIR)
823  {
824  continue;
825  }
826 
827  // Is the floor block ok
828  bool ValidSpawnBlock = false;
829  for (int BlockIndex = 0; BlockIndex < ValidSpawnBlocksCount; ++BlockIndex)
830  {
831  ValidSpawnBlock |= (ValidSpawnBlocks[BlockIndex] == FloorBlock);
832  }
833 
834  if (!ValidSpawnBlock)
835  {
836  continue;
837  }
838 
839  if (!CheckPlayerSpawnPoint(a_X, PotentialY - 1, a_Z))
840  {
841  continue;
842  }
843 
844  a_Y = PotentialY - 1;
845  return true;
846  }
847 
848  return false;
849 }
850 
851 
852 
853 
854 
856 {
857  // Check height bounds
858  if (!cChunkDef::IsValidHeight(a_Pos))
859  {
860  return false;
861  }
862 
863  // Check that surrounding blocks are neither solid or liquid
864  constexpr std::array<Vector3i, 8> SurroundingCoords =
865  {
866  {
867  {0, 0, 1},
868  {1, 0, 1},
869  {1, 0, 0},
870  {1, 0, -1},
871  {0, 0, -1},
872  {-1, 0, -1},
873  {-1, 0, 0},
874  {-1, 0, 1},
875  }
876  };
877 
878  for (const auto & Offset : SurroundingCoords)
879  {
880  const BLOCKTYPE BlockType = GetBlock(a_Pos + Offset);
882  {
883  return true;
884  }
885  }
886 
887  return false;
888 }
889 
890 
891 
892 
893 
895 {
896  // Pick a new weather. Only reasonable transitions allowed:
897  switch (m_Weather)
898  {
899  case eWeather_Sunny:
901  {
902  return eWeather_Rain;
903  }
904  case eWeather_Rain:
905  {
906  // 1 / 8 chance of turning into a thunderstorm
908  }
909  }
910  UNREACHABLE("Unsupported weather");
911 }
912 
913 
914 
915 
916 
918 {
919  AString DefaultMonsters;
920  switch (m_Dimension)
921  {
922  case dimOverworld: DefaultMonsters = "bat, cavespider, chicken, cow, creeper, guardian, horse, mooshroom, ocelot, pig, rabbit, sheep, silverfish, skeleton, slime, spider, squid, wolf, zombie"; break; // TODO Re-add Enderman when bugs are fixed
923  case dimNether: DefaultMonsters = "blaze, ghast, magmacube, witherskeleton, zombiepigman"; break;
924  case dimEnd: DefaultMonsters = ""; break; // TODO Re-add Enderman when bugs are fixed
925  case dimNotSet: ASSERT(!"Dimension not set"); break;
926  }
927 
928  m_bAnimals = a_IniFile.GetValueSetB("Monsters", "AnimalsOn", true);
929  AString AllMonsters = a_IniFile.GetValueSet("Monsters", "Types", DefaultMonsters);
930 
931  if (!m_bAnimals)
932  {
933  return;
934  }
935 
936  AStringVector SplitList = StringSplitAndTrim(AllMonsters, ",");
937  for (AStringVector::const_iterator itr = SplitList.begin(), end = SplitList.end(); itr != end; ++itr)
938  {
940  if (ToAdd != mtInvalidType)
941  {
942  m_AllowedMobs.insert(ToAdd);
943  LOGD("Allowed mob: %s", itr->c_str());
944  }
945  else
946  {
947  LOG("World \"%s\": Unknown mob type: %s", m_WorldName.c_str(), itr->c_str());
948  }
949  }
950 }
951 
952 
953 
954 
955 
956 void cWorld::Stop(cDeadlockDetect & a_DeadlockDetect)
957 {
958  // Write settings to file; these are all plugin changeable values - keep updated!
959  cIniFile IniFile;
960  IniFile.ReadFile(m_IniFileName);
961  if (GetDimension() == dimOverworld)
962  {
963  IniFile.SetValue("LinkedWorlds", "NetherWorldName", m_LinkedNetherWorldName);
964  IniFile.SetValue("LinkedWorlds", "EndWorldName", m_LinkedEndWorldName);
965  }
966  else
967  {
968  IniFile.SetValue("LinkedWorlds", "OverworldName", m_LinkedOverworldName);
969  }
970  IniFile.SetValueI("Physics", "TNTShrapnelLevel", static_cast<int>(m_TNTShrapnelLevel));
971  IniFile.SetValueB("Mechanics", "CommandBlocksEnabled", m_bCommandBlocksEnabled);
972  IniFile.SetValueB("Mechanics", "UseChatPrefixes", m_bUseChatPrefixes);
973  IniFile.SetValueB("General", "IsDaylightCycleEnabled", m_IsDaylightCycleEnabled);
974  IniFile.SetValueI("General", "Weather", static_cast<int>(m_Weather));
975  IniFile.SetValueI("General", "TimeInTicks", GetWorldDate().count());
976  IniFile.SetValueI("General", "WorldAgeMS", static_cast<Int64>(m_WorldAge.count()));
977  IniFile.WriteFile(m_IniFileName);
978 
979  m_TickThread.Stop();
980  m_Lighting.Stop();
981  m_Generator.Stop();
983  m_Storage.Stop(); // Waits for thread to finish
984 
985  a_DeadlockDetect.UntrackCriticalSection(m_CSTasks);
986  m_ChunkMap.UntrackInDeadlockDetect(a_DeadlockDetect);
987 
988  if (IsSavingEnabled())
989  {
990  // Unload the scoreboard
992  Serializer.Save();
993 
995  }
996 }
997 
998 
999 
1000 
1001 
1002 void cWorld::Tick(std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_LastTickDurationMSec)
1003 {
1004  // Notify the plugins:
1005  cPluginManager::Get()->CallHookWorldTick(*this, a_Dt, a_LastTickDurationMSec);
1006 
1007  m_WorldAge += a_Dt;
1008  m_WorldTickAge++;
1009 
1011  {
1012  m_WorldDate += a_Dt;
1013 
1014  // Updates the sky darkness based on current time of day:
1016 
1017  // Broadcast time update every 64 ticks (3.2 seconds):
1018  if ((m_WorldTickAge % 64_tick) == 0_tick)
1019  {
1021  }
1022  }
1023 
1024  // Broadcast player list pings every 256 ticks (12.8 seconds):
1025  if ((m_WorldTickAge % 256_tick) == 0_tick)
1026  {
1028  }
1029 
1030  // Process all clients' buffered actions:
1031  for (const auto Player : m_Players)
1032  {
1033  Player->GetClientHandle()->ProcessProtocolIn();
1034  }
1035 
1036  TickClients(a_Dt);
1038  TickQueuedBlocks();
1039  m_ChunkMap.Tick(a_Dt);
1040  TickMobs(a_Dt);
1043  TickQueuedTasks();
1044  TickWeather(static_cast<float>(a_Dt.count()));
1045 
1046  GetSimulatorManager()->Simulate(static_cast<float>(a_Dt.count()));
1047 
1048  // Flush out all clients' buffered data:
1049  for (const auto Player : m_Players)
1050  {
1051  Player->GetClientHandle()->ProcessProtocolOut();
1052  }
1053 
1054  if (m_WorldAge - m_LastChunkCheck > std::chrono::seconds(10))
1055  {
1056  // Unload every 10 seconds
1058 
1059  if (m_WorldAge - m_LastSave > std::chrono::minutes(5))
1060  {
1061  // Save every 5 minutes
1062  SaveAllChunks();
1063  }
1065  {
1066  // Save if we have too many dirty unused chunks
1067  SaveAllChunks();
1068  }
1069  }
1070 }
1071 
1072 
1073 
1074 
1075 
1076 void cWorld::TickClients(const std::chrono::milliseconds a_Dt)
1077 {
1078  for (const auto Player : m_Players)
1079  {
1080  Player->GetClientHandle()->Tick(a_Dt);
1081  }
1082 }
1083 
1084 
1085 
1086 
1087 
1088 void cWorld::TickWeather(float a_Dt)
1089 {
1090  UNUSED(a_Dt);
1091  // There are no weather changes anywhere but in the Overworld:
1092  if (GetDimension() != dimOverworld)
1093  {
1094  return;
1095  }
1096 
1097  if (m_WeatherInterval > 0)
1098  {
1099  // Not yet, wait for the weather period to end
1101  }
1102  else
1103  {
1104  // Change weather:
1106  }
1107 
1109  {
1110  // 0.5% chance per tick of thunderbolt
1111  if (GetRandomProvider().RandBool(0.005))
1112  {
1113  CastThunderbolt({0, 0, 0}); // TODO: find random positions near players to cast thunderbolts.
1114  }
1115  }
1116 }
1117 
1118 
1119 
1120 
1121 
1122 void cWorld::TickMobs(std::chrono::milliseconds a_Dt)
1123 {
1124  // _X 2013_10_22: This is a quick fix for #283 - the world needs to be locked while ticking mobs
1125  cWorld::cLock Lock(*this);
1126 
1127  // before every Mob action, we have to count them depending on the distance to players, on their family ...
1128  cMobCensus MobCensus;
1129  m_ChunkMap.CollectMobCensus(MobCensus);
1130  if (m_bAnimals)
1131  {
1132  // Spawning is enabled, spawn now:
1133  static const cMonster::eFamily AllFamilies[] =
1134  {
1139  } ;
1140  for (size_t i = 0; i < ARRAYCOUNT(AllFamilies); i++)
1141  {
1142  cMonster::eFamily Family = AllFamilies[i];
1143  if (
1144  (m_LastSpawnMonster[Family] > (m_WorldTickAge - cMonster::GetSpawnDelay(Family))) || // Not reached the needed ticks before the next round
1145  MobCensus.IsCapped(Family)
1146  )
1147  {
1148  continue;
1149  }
1152  if (Spawner.CanSpawnAnything())
1153  {
1155  // do the spawn
1156  for (auto & Mob : Spawner.getSpawned())
1157  {
1158  SpawnMobFinalize(std::move(Mob));
1159  }
1160  }
1161  } // for i - AllFamilies[]
1162  } // if (Spawning enabled)
1163 
1164  ForEachEntity([=](cEntity & a_Entity)
1165  {
1166  if (!a_Entity.IsMob())
1167  {
1168  return false;
1169  }
1170  if (!a_Entity.IsTicking())
1171  {
1172  return false;
1173  }
1174 
1175  auto & Monster = static_cast<cMonster &>(a_Entity);
1176  ASSERT(Monster.GetParentChunk() != nullptr); // A ticking entity must have a valid parent chunk
1177 
1178  // Tick close mobs
1179  if (Monster.GetParentChunk()->HasAnyClients())
1180  {
1181  Monster.Tick(a_Dt, *(a_Entity.GetParentChunk()));
1182  }
1183  // Destroy far hostile mobs except if last target was a player
1184  else if ((Monster.GetMobFamily() == cMonster::eFamily::mfHostile) && !Monster.WasLastTargetAPlayer())
1185  {
1186  if (Monster.GetMobType() != eMonsterType::mtWolf)
1187  {
1188  Monster.Destroy();
1189  }
1190  else
1191  {
1192  auto & Wolf = static_cast<cWolf &>(Monster);
1193  if (!Wolf.IsAngry() && !Wolf.IsTame())
1194  {
1195  Monster.Destroy();
1196  }
1197  }
1198  }
1199  return false;
1200  }
1201  );
1202 }
1203 
1204 
1205 
1206 
1207 
1209 {
1210  decltype(m_SetChunkDataQueue) SetChunkDataQueue;
1211  {
1213  SetChunkDataQueue = std::move(m_SetChunkDataQueue);
1214  }
1215 
1216  // Set any chunk data that has been queued for setting:
1217  for (auto & Item : SetChunkDataQueue)
1218  {
1219  // A copy of the chunk coordinates since we're moving Item.
1220  const auto Chunk = Item.Chunk;
1221 
1222  // Set the data:
1223  m_ChunkMap.SetChunkData(std::move(Item));
1224 
1225  // If a client is requesting this chunk, send it to them:
1226  cChunkSender & ChunkSender = m_ChunkSender;
1227  DoWithChunk(
1228  Chunk.m_ChunkX, Chunk.m_ChunkZ,
1229  [&ChunkSender](cChunk & a_Chunk)
1230  {
1231  if (a_Chunk.HasAnyClients())
1232  {
1233  ChunkSender.QueueSendChunkTo(
1234  a_Chunk.GetPosX(),
1235  a_Chunk.GetPosZ(),
1236  cChunkSender::Priority::Medium,
1237  a_Chunk.GetAllClients()
1238  );
1239  }
1240  return true;
1241  }
1242  );
1243  } // for itr - SetChunkDataQueue[]
1244 }
1245 
1246 
1247 
1248 
1249 
1251 {
1252  decltype(m_EntitiesToAdd) EntitiesToAdd;
1253  {
1254  cCSLock Lock(m_CSEntitiesToAdd);
1255  std::swap(EntitiesToAdd, m_EntitiesToAdd);
1256  }
1257 
1258  // Ensures m_Players manipulation happens under the chunkmap lock.
1259  cLock Lock(*this);
1260 
1261  // Add entities waiting in the queue to be added:
1262  for (auto & Item: EntitiesToAdd)
1263  {
1264  const auto Entity = Item.first.get();
1265 
1266  if (Entity->IsPlayer())
1267  {
1268  const auto Player = static_cast<cPlayer *>(Entity);
1269 
1270  LOGD("Adding player %s to world \"%s\".", Player->GetName().c_str(), m_WorldName.c_str());
1271  ASSERT(std::find(m_Players.begin(), m_Players.end(), Player) == m_Players.end()); // Is it already in the list? HOW?
1272 
1273  m_Players.push_back(Player);
1274  }
1275 
1276  m_ChunkMap.AddEntity(std::move(Item.first));
1277 
1278  if (const auto OldWorld = Item.second; OldWorld != nullptr)
1279  {
1280  cRoot::Get()->GetPluginManager()->CallHookEntityChangedWorld(*Entity, *OldWorld);
1281  }
1282  }
1283 }
1284 
1285 
1286 
1287 
1288 
1290 {
1291  // Move the tasks to be executed to a seperate vector to avoid deadlocks on accessing m_Tasks
1292  decltype(m_Tasks) Tasks;
1293  {
1294  cCSLock Lock(m_CSTasks);
1295  if (m_Tasks.empty())
1296  {
1297  return;
1298  }
1299 
1300  // Partition everything to be executed by returning false to move to end of list if time reached
1301  auto MoveBeginIterator = std::partition(m_Tasks.begin(), m_Tasks.end(), [this](const decltype(m_Tasks)::value_type & a_Task)
1302  {
1303  return a_Task.first >= m_WorldAge;
1304  });
1305 
1306  // Cut all the due tasks from m_Tasks into Tasks:
1307  Tasks.insert(
1308  Tasks.end(),
1309  std::make_move_iterator(MoveBeginIterator),
1310  std::make_move_iterator(m_Tasks.end())
1311  );
1312  m_Tasks.erase(MoveBeginIterator, m_Tasks.end());
1313  }
1314 
1315  // Execute each task:
1316  for (const auto & Task : Tasks)
1317  {
1318  Task.second(*this);
1319  } // for itr - m_Tasks[]
1320 }
1321 
1322 
1323 
1324 
1325 
1327 {
1328  const auto TIME_SUNSET = 12000_tick;
1329  const auto TIME_NIGHT_START = 13187_tick;
1330  const auto TIME_NIGHT_END = 22812_tick;
1331  const auto TIME_SUNRISE = 23999_tick;
1332  const auto TIME_SPAWN_DIVISOR = 148_tick;
1333 
1334  const auto TempTime = GetTimeOfDay();
1335  if (TempTime <= TIME_SUNSET)
1336  {
1337  m_SkyDarkness = 0;
1338  }
1339  else if (TempTime <= TIME_NIGHT_START)
1340  {
1341  m_SkyDarkness = static_cast<NIBBLETYPE>((TIME_NIGHT_START - TempTime) / TIME_SPAWN_DIVISOR);
1342  }
1343  else if (TempTime <= TIME_NIGHT_END)
1344  {
1345  m_SkyDarkness = 8;
1346  }
1347  else
1348  {
1349  m_SkyDarkness = static_cast<NIBBLETYPE>((TIME_SUNRISE - TempTime) / TIME_SPAWN_DIVISOR);
1350  }
1351 }
1352 
1353 
1354 
1355 
1356 
1358 {
1359  return m_ChunkMap.WakeUpSimulators(a_Block);
1360 }
1361 
1362 
1363 
1364 
1365 
1367 {
1368  m_SimulatorManager->WakeUp(a_Area);
1369 }
1370 
1371 
1372 
1373 
1374 
1375 bool cWorld::ForEachBlockEntityInChunk(int a_ChunkX, int a_ChunkZ, cBlockEntityCallback a_Callback)
1376 {
1377  return m_ChunkMap.ForEachBlockEntityInChunk(a_ChunkX, a_ChunkZ, a_Callback);
1378 }
1379 
1380 
1381 
1382 
1383 
1384 void cWorld::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, bool a_CanCauseFire, eExplosionSource a_Source, void * a_SourceData)
1385 {
1386  cLock Lock(*this);
1387  if (!cPluginManager::Get()->CallHookExploding(*this, a_ExplosionSize, a_CanCauseFire, a_BlockX, a_BlockY, a_BlockZ, a_Source, a_SourceData) && (a_ExplosionSize > 0))
1388  {
1389  // TODO: CanCauseFire gets reset to false for some reason, (plugin has ability to change it, might be related)
1390 
1391  const cEntity * Entity;
1392  switch (a_Source)
1393  {
1401  {
1402  Entity = static_cast<const cEntity *>(a_SourceData);
1403  break;
1404  }
1405  default:
1406  {
1407  Entity = nullptr;
1408  }
1409  }
1410 
1411  Explodinator::Kaboom(*this, Vector3d(a_BlockX, a_BlockY, a_BlockZ), FloorC(a_ExplosionSize), a_CanCauseFire, Entity);
1412  cPluginManager::Get()->CallHookExploded(*this, a_ExplosionSize, a_CanCauseFire, a_BlockX, a_BlockY, a_BlockZ, a_Source, a_SourceData);
1413  }
1414 }
1415 
1416 
1417 
1418 
1419 
1421 {
1422  return m_ChunkMap.DoWithBlockEntityAt(a_Position, a_Callback);
1423 }
1424 
1425 
1426 
1427 
1428 
1429 bool cWorld::GetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4)
1430 {
1431  return DoWithBlockEntityAt({ a_BlockX, a_BlockY, a_BlockZ }, [&a_Line1, &a_Line2, &a_Line3, &a_Line4](cBlockEntity & a_BlockEntity)
1432  {
1433  if ((a_BlockEntity.GetBlockType() != E_BLOCK_WALLSIGN) && (a_BlockEntity.GetBlockType() != E_BLOCK_SIGN_POST))
1434  {
1435  return false; // Not a sign
1436  }
1437 
1438  const auto & Sign = static_cast<cSignEntity &>(a_BlockEntity);
1439  a_Line1 = Sign.GetLine(0);
1440  a_Line2 = Sign.GetLine(1);
1441  a_Line3 = Sign.GetLine(2);
1442  a_Line4 = Sign.GetLine(3);
1443  return true;
1444  });
1445 }
1446 
1447 
1448 
1449 
1450 
1451 bool cWorld::DoWithChunk(int a_ChunkX, int a_ChunkZ, cChunkCallback a_Callback)
1452 {
1453  return m_ChunkMap.DoWithChunk(a_ChunkX, a_ChunkZ, a_Callback);
1454 }
1455 
1456 
1457 
1458 
1459 
1460 bool cWorld::DoWithChunkAt(Vector3i a_BlockPos, cChunkCallback a_Callback)
1461 {
1462  return m_ChunkMap.DoWithChunkAt(a_BlockPos, a_Callback);
1463 }
1464 
1465 
1466 
1467 
1468 
1469 bool cWorld::GrowTree(const Vector3i a_BlockPos)
1470 {
1471  if (GetBlock(a_BlockPos) == E_BLOCK_SAPLING)
1472  {
1473  // There is a sapling here, grow a tree according to its type:
1474  return GrowTreeFromSapling(a_BlockPos);
1475  }
1476  else
1477  {
1478  // There is nothing here, grow a tree based on the current biome here:
1479  return GrowTreeByBiome(a_BlockPos);
1480  }
1481 }
1482 
1483 
1484 
1485 
1486 
1488 {
1489  cNoise Noise(m_Generator.GetSeed());
1490  sSetBlockVector Logs, Other;
1491  auto WorldAge = static_cast<int>(m_WorldTickAge.count() & 0xffffffff);
1492  auto SaplingMeta = GetBlockMeta(a_BlockPos);
1493  switch (SaplingMeta & 0x07)
1494  {
1495  case E_META_SAPLING_APPLE: GetAppleTreeImage (a_BlockPos, Noise, WorldAge, Logs, Other); break;
1496  case E_META_SAPLING_BIRCH: GetBirchTreeImage (a_BlockPos, Noise, WorldAge, Logs, Other); break;
1498  {
1499  bool IsLarge = GetLargeTreeAdjustment(a_BlockPos, SaplingMeta);
1500  GetConiferTreeImage(a_BlockPos, Noise, WorldAge, Logs, Other, IsLarge);
1501  break;
1502  }
1503  case E_META_SAPLING_ACACIA: GetAcaciaTreeImage (a_BlockPos, Noise, WorldAge, Logs, Other); break;
1504  case E_META_SAPLING_JUNGLE:
1505  {
1506  bool IsLarge = GetLargeTreeAdjustment(a_BlockPos, SaplingMeta);
1507  GetJungleTreeImage(a_BlockPos, Noise, WorldAge, Logs, Other, IsLarge);
1508  break;
1509  }
1511  {
1512  if (!GetLargeTreeAdjustment(a_BlockPos, SaplingMeta))
1513  {
1514  return false;
1515  }
1516 
1517  GetDarkoakTreeImage(a_BlockPos, Noise, WorldAge, Logs, Other);
1518  break;
1519  }
1520  }
1521  Other.insert(Other.begin(), Logs.begin(), Logs.end());
1522  Logs.clear();
1523  return GrowTreeImage(Other);
1524 }
1525 
1526 
1527 
1528 
1529 
1531 {
1532  bool IsLarge = true;
1533  a_Meta = a_Meta & 0x07;
1534 
1535  // Check to see if we are the northwest corner
1536  for (int x = 0; x < 2; ++x)
1537  {
1538  for (int z = 0; z < 2; ++z)
1539  {
1540  NIBBLETYPE meta;
1541  BLOCKTYPE type;
1542  GetBlockTypeMeta(a_BlockPos.addedXZ(x, z), type, meta);
1543  IsLarge = IsLarge && (type == E_BLOCK_SAPLING) && ((meta & 0x07) == a_Meta);
1544  }
1545  }
1546 
1547  if (IsLarge)
1548  {
1549  return true;
1550  }
1551 
1552  IsLarge = true;
1553  // Check to see if we are the southwest corner
1554  for (int x = 0; x < 2; ++x)
1555  {
1556  for (int z = 0; z > -2; --z)
1557  {
1558  NIBBLETYPE meta;
1559  BLOCKTYPE type;
1560  GetBlockTypeMeta(a_BlockPos.addedXZ(x, z), type, meta);
1561  IsLarge = IsLarge && (type == E_BLOCK_SAPLING) && ((meta & 0x07) == a_Meta);
1562  }
1563  }
1564 
1565  if (IsLarge)
1566  {
1567  --a_BlockPos.z;
1568  return true;
1569  }
1570 
1571  IsLarge = true;
1572  // Check to see if we are the southeast corner
1573  for (int x = 0; x > -2; --x)
1574  {
1575  for (int z = 0; z > -2; --z)
1576  {
1577  NIBBLETYPE meta;
1578  BLOCKTYPE type;
1579  GetBlockTypeMeta(a_BlockPos.addedXZ(x, z), type, meta);
1580  IsLarge = IsLarge && (type == E_BLOCK_SAPLING) && ((meta & 0x07) == a_Meta);
1581  }
1582  }
1583 
1584  if (IsLarge)
1585  {
1586  --a_BlockPos.x;
1587  --a_BlockPos.z;
1588  return true;
1589  }
1590 
1591  IsLarge = true;
1592  // Check to see if we are the northeast corner
1593  for (int x = 0; x > -2; --x)
1594  {
1595  for (int z = 0; z < 2; ++z)
1596  {
1597  NIBBLETYPE meta;
1598  BLOCKTYPE type;
1599  GetBlockTypeMeta(a_BlockPos.addedXZ(x, z), type, meta);
1600  IsLarge = IsLarge && (type == E_BLOCK_SAPLING) && ((meta & 0x07) == a_Meta);
1601  }
1602  }
1603 
1604  if (IsLarge)
1605  {
1606  --a_BlockPos.x;
1607  }
1608 
1609  return IsLarge;
1610 }
1611 
1612 
1613 
1614 
1615 
1616 bool cWorld::GrowTreeByBiome(const Vector3i a_BlockPos)
1617 {
1618  cNoise Noise(m_Generator.GetSeed());
1619  sSetBlockVector Logs, Other;
1620  auto seq = static_cast<int>(m_WorldTickAge.count() & 0xffffffff);
1621  GetTreeImageByBiome(a_BlockPos, Noise, seq, GetBiomeAt(a_BlockPos.x, a_BlockPos.z), Logs, Other);
1622  Other.insert(Other.begin(), Logs.begin(), Logs.end());
1623  Logs.clear();
1624  return GrowTreeImage(Other);
1625 }
1626 
1627 
1628 
1629 
1630 
1632 {
1633  // Check that the tree has place to grow
1634 
1635  // Make a copy of the log blocks:
1636  sSetBlockVector b2;
1637  for (sSetBlockVector::const_iterator itr = a_Blocks.begin(); itr != a_Blocks.end(); ++itr)
1638  {
1639  if (itr->m_BlockType == E_BLOCK_LOG)
1640  {
1641  b2.push_back(*itr);
1642  }
1643  } // for itr - a_Blocks[]
1644 
1645  // Query blocktypes and metas at those log blocks:
1646  if (!GetBlocks(b2, false))
1647  {
1648  return false;
1649  }
1650 
1651  // Check that at each log's coord there's an block allowed to be overwritten:
1652  for (sSetBlockVector::const_iterator itr = b2.begin(); itr != b2.end(); ++itr)
1653  {
1654  switch (itr->m_BlockType)
1655  {
1657  {
1658  break;
1659  }
1660  default:
1661  {
1662  return false;
1663  }
1664  }
1665  } // for itr - b2[]
1666 
1667  // All ok, replace blocks with the tree image:
1668  m_ChunkMap.ReplaceTreeBlocks(a_Blocks);
1669  return true;
1670 }
1671 
1672 
1673 
1674 
1675 
1676 int cWorld::GrowPlantAt(Vector3i a_BlockPos, int a_NumStages)
1677 {
1678  return m_ChunkMap.GrowPlantAt(a_BlockPos, a_NumStages);
1679 }
1680 
1681 
1682 
1683 
1684 
1686 {
1687  return (GrowPlantAt(a_BlockPos, 16) > 0);
1688 }
1689 
1690 
1691 
1692 
1693 
1694 EMCSBiome cWorld::GetBiomeAt (int a_BlockX, int a_BlockZ)
1695 {
1696  return m_ChunkMap.GetBiomeAt(a_BlockX, a_BlockZ);
1697 }
1698 
1699 
1700 
1701 
1702 
1703 bool cWorld::SetBiomeAt(int a_BlockX, int a_BlockZ, EMCSBiome a_Biome)
1704 {
1705  return m_ChunkMap.SetBiomeAt(a_BlockX, a_BlockZ, a_Biome);
1706 }
1707 
1708 
1709 
1710 
1711 
1712 bool cWorld::SetAreaBiome(int a_MinX, int a_MaxX, int a_MinZ, int a_MaxZ, EMCSBiome a_Biome)
1713 {
1714  return m_ChunkMap.SetAreaBiome(a_MinX, a_MaxX, a_MinZ, a_MaxZ, a_Biome);
1715 }
1716 
1717 
1718 
1719 
1720 
1721 bool cWorld::SetAreaBiome(const cCuboid & a_Area, EMCSBiome a_Biome)
1722 {
1723  return SetAreaBiome(
1724  std::min(a_Area.p1.x, a_Area.p2.x), std::max(a_Area.p1.x, a_Area.p2.x),
1725  std::min(a_Area.p1.z, a_Area.p2.z), std::max(a_Area.p1.z, a_Area.p2.z),
1726  a_Biome
1727  );
1728 }
1729 
1730 
1731 
1732 
1733 
1734 void cWorld::SetMaxViewDistance(int a_MaxViewDistance)
1735 {
1737 }
1738 
1739 
1740 
1741 
1742 
1743 void cWorld::SetBlock(Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
1744 {
1745  m_ChunkMap.SetBlock(a_BlockPos, a_BlockType, a_BlockMeta);
1746 }
1747 
1748 
1749 
1750 
1751 
1752 void cWorld::SetBlockMeta(Vector3i a_BlockPos, NIBBLETYPE a_MetaData)
1753 {
1754  m_ChunkMap.SetBlockMeta(a_BlockPos, a_MetaData);
1755 }
1756 
1757 
1758 
1759 
1760 
1762 {
1763  return m_ChunkMap.GetBlockSkyLight(a_BlockPos);
1764 }
1765 
1766 
1767 
1768 
1769 
1771 {
1772  return m_ChunkMap.GetBlockBlockLight(a_BlockPos);
1773 }
1774 
1775 
1776 
1777 
1778 
1779 bool cWorld::GetBlockTypeMeta(Vector3i a_BlockPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) const
1780 {
1781  return m_ChunkMap.GetBlockTypeMeta(a_BlockPos, a_BlockType, a_BlockMeta);
1782 }
1783 
1784 
1785 
1786 
1787 
1788 bool cWorld::GetBlockInfo(Vector3i a_BlockPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_Meta, NIBBLETYPE & a_SkyLight, NIBBLETYPE & a_BlockLight) const
1789 {
1790  return m_ChunkMap.GetBlockInfo(a_BlockPos, a_BlockType, a_Meta, a_SkyLight, a_BlockLight);
1791 }
1792 
1793 
1794 
1795 
1796 
1797 bool cWorld::WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlockY, int a_MinBlockZ, int a_DataTypes)
1798 {
1799  return m_ChunkMap.WriteBlockArea(a_Area, a_MinBlockX, a_MinBlockY, a_MinBlockZ, a_DataTypes);
1800 }
1801 
1802 
1803 
1804 
1805 
1806 void cWorld::SpawnItemPickups(const cItems & a_Pickups, Vector3i a_BlockPos, double a_FlyAwaySpeed, bool a_IsPlayerCreated)
1807 {
1808  auto & random = GetRandomProvider();
1809  auto microX = random.RandReal<double>(0, 1);
1810  auto microZ = random.RandReal<double>(0, 1);
1811  return SpawnItemPickups(a_Pickups, Vector3d(microX, 0, microZ) + a_BlockPos, a_FlyAwaySpeed, a_IsPlayerCreated);
1812 }
1813 
1814 
1815 
1816 
1817 
1818 void cWorld::SpawnItemPickups(const cItems & a_Pickups, Vector3d a_Pos, double a_FlyAwaySpeed, bool a_IsPlayerCreated)
1819 {
1820  auto & Random = GetRandomProvider();
1821  a_FlyAwaySpeed /= 100; // Pre-divide, so that we don't have to divide each time inside the loop
1822  for (cItems::const_iterator itr = a_Pickups.begin(); itr != a_Pickups.end(); ++itr)
1823  {
1824  if (!IsValidItem(itr->m_ItemType) || (itr->m_ItemType == E_BLOCK_AIR))
1825  {
1826  // Don't spawn pickup if item isn't even valid; should prevent client crashing too
1827  continue;
1828  }
1829 
1830  float SpeedX = static_cast<float>(a_FlyAwaySpeed * Random.RandInt(-10, 10));
1831  float SpeedY = static_cast<float>(a_FlyAwaySpeed * Random.RandInt(40, 50));
1832  float SpeedZ = static_cast<float>(a_FlyAwaySpeed * Random.RandInt(-10, 10));
1833 
1834  auto Pickup = std::make_unique<cPickup>(a_Pos, *itr, a_IsPlayerCreated, Vector3f{SpeedX, SpeedY, SpeedZ});
1835  auto PickupPtr = Pickup.get();
1836  PickupPtr->Initialize(std::move(Pickup), *this);
1837  }
1838 }
1839 
1840 
1841 
1842 
1843 
1844 void cWorld::SpawnItemPickups(const cItems & a_Pickups, Vector3d a_Pos, Vector3d a_Speed, bool a_IsPlayerCreated)
1845 {
1846  for (cItems::const_iterator itr = a_Pickups.begin(); itr != a_Pickups.end(); ++itr)
1847  {
1848  if (!IsValidItem(itr->m_ItemType) || (itr->m_ItemType == E_BLOCK_AIR))
1849  {
1850  continue;
1851  }
1852 
1853  auto pickup = std::make_unique<cPickup>(a_Pos, *itr, a_IsPlayerCreated, a_Speed);
1854  auto pickupPtr = pickup.get();
1855  pickupPtr->Initialize(std::move(pickup), *this);
1856  }
1857 }
1858 
1859 
1860 
1861 
1862 
1863 UInt32 cWorld::SpawnItemPickup(Vector3d a_Pos, const cItem & a_Item, Vector3f a_Speed, int a_LifetimeTicks, bool a_CanCombine)
1864 {
1865  auto pickup = std::make_unique<cPickup>(a_Pos, a_Item, false, a_Speed, a_LifetimeTicks, a_CanCombine);
1866  auto pickupPtr = pickup.get();
1867  if (!pickupPtr->Initialize(std::move(pickup), *this))
1868  {
1869  return cEntity::INVALID_ID;
1870  }
1871  return pickupPtr->GetUniqueID();
1872 }
1873 
1874 
1875 
1876 
1877 
1879 {
1880  auto fallingBlock = std::make_unique<cFallingBlock>(a_Pos, a_BlockType, a_BlockMeta);
1881  auto fallingBlockPtr = fallingBlock.get();
1882  auto ID = fallingBlock->GetUniqueID();
1883  if (!fallingBlockPtr->Initialize(std::move(fallingBlock), *this))
1884  {
1885  return cEntity::INVALID_ID;
1886  }
1887  return ID;
1888 }
1889 
1890 
1891 
1892 
1893 
1895 {
1896  if (a_Reward < 1)
1897  {
1898  LOGWARNING("%s: Attempting to create an experience orb with non-positive reward!", __FUNCTION__);
1899  return cEntity::INVALID_ID;
1900  }
1901 
1902  auto expOrb = std::make_unique<cExpOrb>(a_Pos, a_Reward);
1903  auto expOrbPtr = expOrb.get();
1904  if (!expOrbPtr->Initialize(std::move(expOrb), *this))
1905  {
1906  return cEntity::INVALID_ID;
1907  }
1908  return expOrbPtr->GetUniqueID();
1909 }
1910 
1911 
1912 
1913 
1914 
1915 std::vector<UInt32> cWorld::SpawnSplitExperienceOrbs(Vector3d a_Pos, int a_Reward)
1916 {
1917  std::vector<UInt32> OrbsID;
1918 
1919  if (a_Reward < 1)
1920  {
1921  LOGWARNING("%s: Attempting to create an experience orb with non-positive reward!", __FUNCTION__);
1922  return OrbsID;
1923  }
1924 
1925  std::vector<int> Rewards = cExpOrb::Split(a_Reward);
1926 
1927  // Check generate number to decide speed limit (distribute range)
1928  float SpeedLimit = static_cast<float>((Rewards.size() / 2) + 5);
1929  if (SpeedLimit > 10)
1930  {
1931  SpeedLimit = 10;
1932  }
1933 
1934  auto & Random = GetRandomProvider();
1935  for (auto Reward : Rewards)
1936  {
1937  auto ExpOrb = std::make_unique<cExpOrb>(a_Pos, Reward);
1938  auto ExpOrbPtr = ExpOrb.get();
1939  double SpeedX = Random.RandReal(-SpeedLimit, SpeedLimit);
1940  double SpeedY = Random.RandReal(0.5);
1941  double SpeedZ = Random.RandReal(-SpeedLimit, SpeedLimit);
1942  ExpOrbPtr->SetSpeed(SpeedX, SpeedY, SpeedZ);
1943 
1944  UInt32 Id = ExpOrbPtr->GetUniqueID();
1945  if (ExpOrbPtr->Initialize(std::move(ExpOrb), *this))
1946  {
1947  OrbsID.push_back(Id);
1948  }
1949  }
1950 
1951  return OrbsID;
1952 }
1953 
1954 
1955 
1956 
1957 
1958 UInt32 cWorld::SpawnMinecart(Vector3d a_Pos, int a_MinecartType, const cItem & a_Content, int a_BlockHeight)
1959 {
1960  std::unique_ptr<cMinecart> Minecart;
1961  switch (a_MinecartType)
1962  {
1963  case E_ITEM_MINECART: Minecart = std::make_unique<cRideableMinecart> (a_Pos, a_Content, a_BlockHeight); break;
1964  case E_ITEM_CHEST_MINECART: Minecart = std::make_unique<cMinecartWithChest> (a_Pos); break;
1965  case E_ITEM_FURNACE_MINECART: Minecart = std::make_unique<cMinecartWithFurnace>(a_Pos); break;
1966  case E_ITEM_MINECART_WITH_TNT: Minecart = std::make_unique<cMinecartWithTNT> (a_Pos); break;
1967  case E_ITEM_MINECART_WITH_HOPPER: Minecart = std::make_unique<cMinecartWithHopper> (a_Pos); break;
1968  default:
1969  {
1970  return cEntity::INVALID_ID;
1971  }
1972  } // switch (a_MinecartType)
1973 
1974  auto MinecartPtr = Minecart.get();
1975  if (!MinecartPtr->Initialize(std::move(Minecart), *this))
1976  {
1977  return cEntity::INVALID_ID;
1978  }
1979  return MinecartPtr->GetUniqueID();
1980 }
1981 
1982 
1983 
1984 
1985 
1987 {
1988  auto Boat = std::make_unique<cBoat>(a_Pos, a_Material);
1989  auto BoatPtr = Boat.get();
1990  if (!BoatPtr->Initialize(std::move(Boat), *this))
1991  {
1992  return cEntity::INVALID_ID;
1993  }
1994  return BoatPtr->GetUniqueID();
1995 }
1996 
1997 
1998 
1999 
2000 
2001 UInt32 cWorld::SpawnPrimedTNT(Vector3d a_Pos, int a_FuseTicks, double a_InitialVelocityCoeff, bool a_ShouldPlayFuseSound)
2002 {
2003  auto TNT = std::make_unique<cTNTEntity>(a_Pos, a_FuseTicks);
2004  auto TNTPtr = TNT.get();
2005  if (!TNTPtr->Initialize(std::move(TNT), *this))
2006  {
2007  return cEntity::INVALID_ID;
2008  }
2009 
2010  if (a_ShouldPlayFuseSound)
2011  {
2012  BroadcastSoundEffect("entity.tnt.primed", a_Pos, 1.0f, 1.0f);
2013  }
2014 
2015  auto & Random = GetRandomProvider();
2016  TNTPtr->SetSpeed(
2017  a_InitialVelocityCoeff * Random.RandReal(-0.5f, 0.5f),
2018  a_InitialVelocityCoeff * 2,
2019  a_InitialVelocityCoeff * Random.RandReal(-0.5f, 0.5f)
2020  );
2021  return TNTPtr->GetUniqueID();
2022 }
2023 
2024 
2025 
2026 
2027 
2028 UInt32 cWorld::SpawnEnderCrystal(Vector3d a_Pos, bool a_ShowBottom)
2029 {
2030  auto EnderCrystal = std::make_unique<cEnderCrystal>(a_Pos, a_ShowBottom);
2031  auto EnderCrystalPtr = EnderCrystal.get();
2032  if (!EnderCrystalPtr->Initialize(std::move(EnderCrystal), *this))
2033  {
2034  return cEntity::INVALID_ID;
2035  }
2036  return EnderCrystalPtr->GetUniqueID();
2037 }
2038 
2039 
2040 
2041 
2042 
2043 void cWorld::PlaceBlock(const Vector3i a_Position, const BLOCKTYPE a_BlockType, const NIBBLETYPE a_BlockMeta)
2044 {
2046  NIBBLETYPE BlockMeta;
2047  GetBlockTypeMeta(a_Position, BlockType, BlockMeta);
2048 
2049  SetBlock(a_Position, a_BlockType, a_BlockMeta);
2050 
2051  cChunkInterface ChunkInterface(GetChunkMap());
2052  cBlockHandler::For(BlockType).OnBroken(ChunkInterface, *this, a_Position, BlockType, BlockMeta, nullptr);
2053  cBlockHandler::For(a_BlockType).OnPlaced(ChunkInterface, *this, a_Position, a_BlockType, a_BlockMeta);
2054 }
2055 
2056 
2057 
2058 
2059 
2060 bool cWorld::GetBlocks(sSetBlockVector & a_Blocks, bool a_ContinueOnFailure)
2061 {
2062  return m_ChunkMap.GetBlocks(a_Blocks, a_ContinueOnFailure);
2063 }
2064 
2065 
2066 
2067 
2068 
2069 bool cWorld::DigBlock(Vector3i a_BlockPos, const cEntity * a_Digger)
2070 {
2072  NIBBLETYPE BlockMeta;
2073  GetBlockTypeMeta(a_BlockPos, BlockType, BlockMeta);
2074 
2075  if (!m_ChunkMap.DigBlock(a_BlockPos))
2076  {
2077  return false;
2078  }
2079 
2080  cChunkInterface ChunkInterface(GetChunkMap());
2081  cBlockHandler::For(BlockType).OnBroken(ChunkInterface, *this, a_BlockPos, BlockType, BlockMeta, a_Digger);
2082 
2083  return true;
2084 }
2085 
2086 
2087 
2088 
2089 
2090 bool cWorld::DropBlockAsPickups(Vector3i a_BlockPos, const cEntity * a_Digger, const cItem * a_Tool)
2091 {
2092  auto pickups = PickupsFromBlock(a_BlockPos, a_Digger, a_Tool);
2093  if (!DigBlock(a_BlockPos, a_Digger))
2094  {
2095  return false;
2096  }
2097  SpawnItemPickups(pickups, Vector3d(0.5, 0.5, 0.5) + a_BlockPos, 10);
2098  return true;
2099 }
2100 
2101 
2102 
2103 
2104 
2105 cItems cWorld::PickupsFromBlock(Vector3i a_BlockPos, const cEntity * a_Digger, const cItem * a_Tool)
2106 {
2107  return m_ChunkMap.PickupsFromBlock(a_BlockPos, a_Digger, a_Tool);
2108 }
2109 
2110 
2111 
2112 
2113 
2114 void cWorld::SendBlockTo(int a_X, int a_Y, int a_Z, const cPlayer & a_Player)
2115 {
2116  m_ChunkMap.SendBlockTo(a_X, a_Y, a_Z, a_Player);
2117 }
2118 
2119 
2120 
2121 
2122 
2123 int cWorld::GetHeight(int a_X, int a_Z)
2124 {
2125  return m_ChunkMap.GetHeight(a_X, a_Z);
2126 }
2127 
2128 
2129 
2130 
2131 
2132 bool cWorld::TryGetHeight(int a_BlockX, int a_BlockZ, int & a_Height)
2133 {
2134  return m_ChunkMap.TryGetHeight(a_BlockX, a_BlockZ, a_Height);
2135 }
2136 
2137 
2138 
2139 
2140 
2141 void cWorld::SendBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cClientHandle & a_Client)
2142 {
2143  m_ChunkMap.SendBlockEntity(a_BlockX, a_BlockY, a_BlockZ, a_Client);
2144 }
2145 
2146 
2147 
2148 
2149 
2150 void cWorld::MarkChunkDirty(int a_ChunkX, int a_ChunkZ)
2151 {
2152  m_ChunkMap.MarkChunkDirty(a_ChunkX, a_ChunkZ);
2153 }
2154 
2155 
2156 
2157 
2158 
2159 void cWorld::MarkChunkSaving(int a_ChunkX, int a_ChunkZ)
2160 {
2161  m_ChunkMap.MarkChunkSaving(a_ChunkX, a_ChunkZ);
2162 }
2163 
2164 
2165 
2166 
2167 
2168 void cWorld::MarkChunkSaved (int a_ChunkX, int a_ChunkZ)
2169 {
2170  m_ChunkMap.MarkChunkSaved (a_ChunkX, a_ChunkZ);
2171 }
2172 
2173 
2174 
2175 
2176 
2177 void cWorld::QueueSetChunkData(struct SetChunkData && a_SetChunkData)
2178 {
2179  // Store a copy of the data in the queue:
2180  // TODO: If the queue is too large, wait for it to get processed. Not likely, though.
2182  m_SetChunkDataQueue.emplace_back(std::move(a_SetChunkData));
2183 }
2184 
2185 
2186 
2187 
2188 
2190  int a_ChunkX, int a_ChunkZ,
2191  const cChunkDef::BlockNibbles & a_BlockLight,
2192  const cChunkDef::BlockNibbles & a_SkyLight
2193 )
2194 {
2195  m_ChunkMap.ChunkLighted(a_ChunkX, a_ChunkZ, a_BlockLight, a_SkyLight);
2196 }
2197 
2198 
2199 
2200 
2201 
2202 bool cWorld::GetChunkData(cChunkCoords a_Coords, cChunkDataCallback & a_Callback) const
2203 {
2204  return m_ChunkMap.GetChunkData(a_Coords, a_Callback);
2205 }
2206 
2207 
2208 
2209 
2210 
2211 bool cWorld::IsChunkQueued(int a_ChunkX, int a_ChunkZ) const
2212 {
2213  return m_ChunkMap.IsChunkQueued(a_ChunkX, a_ChunkZ);
2214 }
2215 
2216 
2217 
2218 
2219 
2220 bool cWorld::IsChunkValid(int a_ChunkX, int a_ChunkZ) const
2221 {
2222  return m_ChunkMap.IsChunkValid(a_ChunkX, a_ChunkZ);
2223 }
2224 
2225 
2226 
2227 
2228 
2229 bool cWorld::HasChunkAnyClients(int a_ChunkX, int a_ChunkZ) const
2230 {
2231  return m_ChunkMap.HasChunkAnyClients(a_ChunkX, a_ChunkZ);
2232 }
2233 
2234 
2235 
2236 
2237 
2239 {
2242 }
2243 
2244 
2245 
2246 
2247 
2249 {
2250  QueueTask([](cWorld & a_World) { a_World.UnloadUnusedChunks(); });
2251 }
2252 
2253 
2254 
2255 
2256 
2258 {
2260 }
2261 
2262 
2263 
2264 
2265 
2267 {
2268  // Calls the callback for each player in the list
2269  cLock Lock(*this);
2270  for (auto & Player : m_Players)
2271  {
2272  if (Player->IsTicking() && a_Callback(*Player))
2273  {
2274  return false;
2275  }
2276  } // for itr - m_Players[]
2277  return true;
2278 }
2279 
2280 
2281 
2282 
2283 
2284 bool cWorld::DoWithPlayer(const AString & a_PlayerName, cPlayerListCallback a_Callback)
2285 {
2286  // Calls the callback for the specified player in the list
2287  cLock Lock(*this);
2288  for (auto & Player : m_Players)
2289  {
2290  if (Player->IsTicking() && (NoCaseCompare(Player->GetName(), a_PlayerName) == 0))
2291  {
2292  a_Callback(*Player);
2293  return true;
2294  }
2295  } // for itr - m_Players[]
2296  return false;
2297 }
2298 
2299 
2300 
2301 
2302 
2303 bool cWorld::FindAndDoWithPlayer(const AString & a_PlayerNameHint, cPlayerListCallback a_Callback)
2304 {
2305  cPlayer * BestMatch = nullptr;
2306  size_t BestRating = 0;
2307  size_t NameLength = a_PlayerNameHint.length();
2308 
2309  cLock Lock(*this);
2310  for (const auto Player : m_Players)
2311  {
2312  if (!Player->IsTicking())
2313  {
2314  continue;
2315  }
2316  size_t Rating = RateCompareString (a_PlayerNameHint, Player->GetName());
2317  if (Rating >= BestRating)
2318  {
2319  BestMatch = Player;
2320  BestRating = Rating;
2321  }
2322  if (Rating == NameLength) // Perfect match
2323  {
2324  break;
2325  }
2326  } // for itr - m_Players[]
2327 
2328  if (BestMatch != nullptr)
2329  {
2330  return a_Callback(*BestMatch);
2331  }
2332  return false;
2333 }
2334 
2335 
2336 
2337 
2338 
2339 bool cWorld::DoWithPlayerByUUID(const cUUID & a_PlayerUUID, cPlayerListCallback a_Callback)
2340 {
2341  cLock Lock(*this);
2342  for (auto & Player : m_Players)
2343  {
2344  if (Player->IsTicking() && (Player->GetUUID() == a_PlayerUUID))
2345  {
2346  return a_Callback(*Player);
2347  }
2348  }
2349  return false;
2350 }
2351 
2352 
2353 
2354 
2355 
2356 bool cWorld::DoWithNearestPlayer(Vector3d a_Pos, double a_RangeLimit, cPlayerListCallback a_Callback, bool a_CheckLineOfSight, bool a_IgnoreSpectator)
2357 {
2358  double ClosestDistance = a_RangeLimit;
2359  cPlayer * ClosestPlayer = nullptr;
2360 
2361  cLock Lock(*this);
2362  for (const auto Player : m_Players)
2363  {
2364  if (!Player->IsTicking())
2365  {
2366  continue;
2367  }
2368 
2369  if (a_IgnoreSpectator && Player->IsGameModeSpectator())
2370  {
2371  continue;
2372  }
2373 
2374  Vector3f Pos = Player->GetPosition();
2375  double Distance = (Pos - a_Pos).Length();
2376 
2377  // If the player is too far, skip them:
2378  if (Distance > ClosestDistance)
2379  {
2380  continue;
2381  }
2382 
2383  // Check LineOfSight, if requested:
2384  if (
2385  a_CheckLineOfSight &&
2387  )
2388  {
2389  continue;
2390  }
2391 
2392  ClosestDistance = Distance;
2393  ClosestPlayer = Player;
2394  }
2395 
2396  if (ClosestPlayer)
2397  {
2398  return a_Callback(*ClosestPlayer);
2399  }
2400  else
2401  {
2402  return false;
2403  }
2404 }
2405 
2406 
2407 
2408 
2409 
2410 void cWorld::SendPlayerList(cPlayer * a_DestPlayer)
2411 {
2412  // Sends the playerlist to a_DestPlayer
2413  cLock Lock(*this);
2414  for (const auto & Player : m_Players)
2415  {
2416  if (!Player->GetClientHandle()->IsDestroyed())
2417  {
2418  a_DestPlayer->GetClientHandle()->SendPlayerListAddPlayer(*Player);
2419  }
2420  }
2421 }
2422 
2423 
2424 
2425 
2426 
2428 {
2429  return m_ChunkMap.ForEachEntity(a_Callback);
2430 }
2431 
2432 
2433 
2434 
2435 
2436 bool cWorld::ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback a_Callback)
2437 {
2438  return m_ChunkMap.ForEachEntityInChunk(a_ChunkX, a_ChunkZ, a_Callback);
2439 }
2440 
2441 
2442 
2443 
2444 
2446 {
2447  return m_ChunkMap.ForEachEntityInBox(a_Box, a_Callback);
2448 }
2449 
2450 
2451 
2452 
2453 
2455 {
2456  cLock Lock(*this);
2457  return m_Players.size();
2458 }
2459 
2460 
2461 
2462 
2463 
2465 {
2466  // First check the entities-to-add:
2467  {
2468  cCSLock Lock(m_CSEntitiesToAdd);
2469  for (const auto & Item : m_EntitiesToAdd)
2470  {
2471  if (Item.first->GetUniqueID() == a_UniqueID)
2472  {
2473  a_Callback(*Item.first);
2474  return true;
2475  }
2476  } // for ent - m_EntitiesToAdd[]
2477  }
2478 
2479  // Then check the chunkmap:
2480  return m_ChunkMap.DoWithEntityByID(a_UniqueID, a_Callback);
2481 }
2482 
2483 
2484 
2485 
2486 
2487 void cWorld::CompareChunkClients(int a_ChunkX1, int a_ChunkZ1, int a_ChunkX2, int a_ChunkZ2, cClientDiffCallback & a_Callback)
2488 {
2489  m_ChunkMap.CompareChunkClients(a_ChunkX1, a_ChunkZ1, a_ChunkX2, a_ChunkZ2, a_Callback);
2490 }
2491 
2492 
2493 
2494 
2495 
2496 bool cWorld::AddChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client)
2497 {
2498  return m_ChunkMap.AddChunkClient(a_ChunkX, a_ChunkZ, a_Client);
2499 }
2500 
2501 
2502 
2503 
2504 
2505 void cWorld::RemoveChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client)
2506 {
2507  m_ChunkMap.RemoveChunkClient(a_ChunkX, a_ChunkZ, a_Client);
2508 }
2509 
2510 
2511 
2512 
2513 
2515 {
2517 }
2518 
2519 
2520 
2521 
2522 
2523 void cWorld::SendChunkTo(int a_ChunkX, int a_ChunkZ, cChunkSender::Priority a_Priority, cClientHandle * a_Client)
2524 {
2525  m_ChunkSender.QueueSendChunkTo(a_ChunkX, a_ChunkZ, a_Priority, a_Client);
2526 }
2527 
2528 
2529 
2530 
2531 
2532 void cWorld::ForceSendChunkTo(int a_ChunkX, int a_ChunkZ, cChunkSender::Priority a_Priority, cClientHandle * a_Client)
2533 {
2534  a_Client->AddWantedChunk(a_ChunkX, a_ChunkZ);
2535  m_ChunkSender.QueueSendChunkTo(a_ChunkX, a_ChunkZ, a_Priority, a_Client);
2536 }
2537 
2538 
2539 
2540 
2541 
2542 void cWorld::PrepareChunk(int a_ChunkX, int a_ChunkZ, std::unique_ptr<cChunkCoordCallback> a_CallAfter)
2543 {
2544  m_ChunkMap.PrepareChunk(a_ChunkX, a_ChunkZ, std::move(a_CallAfter));
2545 }
2546 
2547 
2548 
2549 
2550 
2551 void cWorld::ChunkLoadFailed(int a_ChunkX, int a_ChunkZ)
2552 {
2553  m_ChunkMap.ChunkLoadFailed(a_ChunkX, a_ChunkZ);
2554 }
2555 
2556 
2557 
2558 
2559 
2560 bool cWorld::SetSignLines(Vector3i a_BlockPos, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4, cPlayer * a_Player)
2561 {
2562  // TODO: rvalue these strings
2563 
2564  AString Line1(a_Line1);
2565  AString Line2(a_Line2);
2566  AString Line3(a_Line3);
2567  AString Line4(a_Line4);
2568 
2569  if (cRoot::Get()->GetPluginManager()->CallHookUpdatingSign(*this, a_BlockPos, Line1, Line2, Line3, Line4, a_Player))
2570  {
2571  return false;
2572  }
2573 
2574  if (
2575  DoWithBlockEntityAt(a_BlockPos, [&Line1, &Line2, &Line3, &Line4](cBlockEntity & a_BlockEntity)
2576  {
2577  if ((a_BlockEntity.GetBlockType() != E_BLOCK_WALLSIGN) && (a_BlockEntity.GetBlockType() != E_BLOCK_SIGN_POST))
2578  {
2579  return false; // Not a sign
2580  }
2581 
2582  static_cast<cSignEntity &>(a_BlockEntity).SetLines(Line1, Line2, Line3, Line4);
2583  return true;
2584  })
2585  )
2586  {
2587  cRoot::Get()->GetPluginManager()->CallHookUpdatedSign(*this, a_BlockPos, Line1, Line2, Line3, Line4, a_Player);
2588  return true;
2589  }
2590 
2591  return false;
2592 }
2593 
2594 
2595 
2596 
2597 
2598 bool cWorld::SetCommandBlockCommand(int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Command)
2599 {
2600  return DoWithBlockEntityAt({ a_BlockX, a_BlockY, a_BlockZ }, [&](cBlockEntity & a_BlockEntity)
2601  {
2602  if (a_BlockEntity.GetBlockType() != E_BLOCK_COMMAND_BLOCK)
2603  {
2604  return false;
2605  }
2606 
2607  static_cast<cCommandBlockEntity &>(a_BlockEntity).SetCommand(a_Command);
2608  return true;
2609  });
2610 }
2611 
2612 
2613 
2614 
2615 
2616 bool cWorld::IsTrapdoorOpen(int a_BlockX, int a_BlockY, int a_BlockZ)
2617 {
2618  BLOCKTYPE Block;
2619  NIBBLETYPE Meta;
2620  GetBlockTypeMeta({ a_BlockX, a_BlockY, a_BlockZ }, Block, Meta);
2622  {
2623  return false;
2624  }
2625 
2626  return (Meta & 0x4) > 0;
2627 }
2628 
2629 
2630 
2631 
2632 
2633 bool cWorld::SetTrapdoorOpen(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_Open)
2634 {
2635  BLOCKTYPE Block;
2636  NIBBLETYPE Meta;
2637  GetBlockTypeMeta({ a_BlockX, a_BlockY, a_BlockZ }, Block, Meta);
2639  {
2640  return false;
2641  }
2642 
2643  bool IsOpen = (Meta & 0x4) != 0;
2644  if (a_Open != IsOpen)
2645  {
2646  SetBlockMeta({ a_BlockX, a_BlockY, a_BlockZ }, Meta ^ 0x4);
2647  BroadcastSoundParticleEffect(EffectID::SFX_RANDOM_WOODEN_TRAPDOOR_OPEN, { a_BlockX, a_BlockY, a_BlockZ }, 0);
2648  return true;
2649  }
2650  return false;
2651 }
2652 
2653 
2654 
2655 
2656 
2657 void cWorld::RegenerateChunk(int a_ChunkX, int a_ChunkZ)
2658 {
2659  m_ChunkMap.MarkChunkRegenerating(a_ChunkX, a_ChunkZ);
2660  m_Generator.QueueGenerateChunk({a_ChunkX, a_ChunkZ}, true);
2661 }
2662 
2663 
2664 
2665 
2666 
2667 void cWorld::GenerateChunk(int a_ChunkX, int a_ChunkZ)
2668 {
2669  m_ChunkMap.GenerateChunk(a_ChunkX, a_ChunkZ);
2670 }
2671 
2672 
2673 
2674 
2675 
2676 void cWorld::QueueLightChunk(int a_ChunkX, int a_ChunkZ, std::unique_ptr<cChunkCoordCallback> a_Callback)
2677 {
2678  m_Lighting.QueueChunk(a_ChunkX, a_ChunkZ, std::move(a_Callback));
2679 }
2680 
2681 
2682 
2683 
2684 
2685 bool cWorld::IsChunkLighted(int a_ChunkX, int a_ChunkZ)
2686 {
2687  return m_ChunkMap.IsChunkLighted(a_ChunkX, a_ChunkZ);
2688 }
2689 
2690 
2691 
2692 
2693 
2694 bool cWorld::ForEachChunkInRect(int a_MinChunkX, int a_MaxChunkX, int a_MinChunkZ, int a_MaxChunkZ, cChunkDataCallback & a_Callback)
2695 {
2696  return m_ChunkMap.ForEachChunkInRect(a_MinChunkX, a_MaxChunkX, a_MinChunkZ, a_MaxChunkZ, a_Callback);
2697 }
2698 
2699 
2700 
2701 
2702 
2703 bool cWorld::ForEachLoadedChunk(cFunctionRef<bool(int, int)> a_Callback)
2704 {
2705  return m_ChunkMap.ForEachLoadedChunk(a_Callback);
2706 }
2707 
2708 
2709 
2710 
2711 
2713 {
2714  if (IsSavingEnabled())
2715  {
2718  }
2719 }
2720 
2721 
2722 
2723 
2724 
2726 {
2727  QueueTask([](cWorld & a_World) { a_World.SaveAllChunks(); });
2728 }
2729 
2730 
2731 
2732 
2733 
2734 void cWorld::QueueTask(std::function<void(cWorld &)> a_Task)
2735 {
2736  cCSLock Lock(m_CSTasks);
2737  m_Tasks.emplace_back(0, std::move(a_Task));
2738 }
2739 
2740 
2741 
2742 
2743 
2744 void cWorld::ScheduleTask(const cTickTime a_DelayTicks, std::function<void (cWorld &)> a_Task)
2745 {
2746  const auto TargetTick = a_DelayTicks + m_WorldAge;
2747 
2748  // Insert the task into the list of scheduled tasks
2749  {
2750  cCSLock Lock(m_CSTasks);
2751  m_Tasks.emplace_back(TargetTick, std::move(a_Task));
2752  }
2753 }
2754 
2755 
2756 
2757 
2758 
2759 void cWorld::AddEntity(OwnedEntity a_Entity, cWorld * a_OldWorld)
2760 {
2761  cCSLock Lock(m_CSEntitiesToAdd);
2762  m_EntitiesToAdd.emplace_back(std::move(a_Entity), a_OldWorld);
2763 }
2764 
2765 
2766 
2767 
2768 
2770 {
2771  // Remove players from the player list:
2772  if (a_Entity.IsPlayer())
2773  {
2774  cLock Lock(*this);
2775  const auto Player = static_cast<cPlayer *>(&a_Entity);
2776  LOGD("Removing player %s from world \"%s\"", Player->GetName().c_str(), m_WorldName.c_str());
2777  m_Players.erase(std::remove(m_Players.begin(), m_Players.end(), Player), m_Players.end());
2778  }
2779 
2780  // Check if the entity is in the chunkmap:
2781  auto Entity = m_ChunkMap.RemoveEntity(a_Entity);
2782  if (Entity != nullptr)
2783  {
2784  Entity->OnRemoveFromWorld(*this);
2785  return Entity;
2786  }
2787 
2788  // Check if the entity is in the queue to be added to the world:
2789  cCSLock Lock(m_CSEntitiesToAdd);
2790  auto itr = std::find_if(m_EntitiesToAdd.begin(), m_EntitiesToAdd.end(),
2791  [&a_Entity](const auto & Item)
2792  {
2793  return (Item.first.get() == &a_Entity);
2794  }
2795  );
2796 
2797  if (itr != m_EntitiesToAdd.end())
2798  {
2799  Entity = std::move(itr->first);
2800  m_EntitiesToAdd.erase(itr);
2801  }
2802 
2803  return Entity;
2804 }
2805 
2806 
2807 
2808 
2809 
2810 size_t cWorld::GetNumChunks(void) const
2811 {
2812  return m_ChunkMap.GetNumChunks();
2813 }
2814 
2815 
2816 
2817 
2818 
2820 {
2822 }
2823 
2824 
2825 
2826 
2827 
2828 void cWorld::GetChunkStats(int & a_NumValid, int & a_NumDirty, int & a_NumInLightingQueue)
2829 {
2830  m_ChunkMap.GetChunkStats(a_NumValid, a_NumDirty);
2831  a_NumInLightingQueue = static_cast<int>(m_Lighting.GetQueueLength());
2832 }
2833 
2834 
2835 
2836 
2837 
2839 {
2840  if (m_BlockTickQueue.empty())
2841  {
2842  return;
2843  }
2844  m_BlockTickQueueCopy.clear();
2846 
2847  for (std::vector<BlockTickQueueItem *>::iterator itr = m_BlockTickQueueCopy.begin(); itr != m_BlockTickQueueCopy.end(); ++itr)
2848  {
2849  BlockTickQueueItem * Block = (*itr);
2850  Block->TicksToWait -= 1;
2851  if (Block->TicksToWait <= 0)
2852  {
2853  // TODO: Handle the case when the chunk is already unloaded
2854  m_ChunkMap.TickBlock({Block->X, Block->Y, Block->Z});
2855  delete Block; // We don't have to remove it from the vector, this will happen automatically on the next tick
2856  }
2857  else
2858  {
2859  m_BlockTickQueue.push_back(Block); // Keep the block in the queue
2860  }
2861  } // for itr - m_BlockTickQueueCopy[]
2862 }
2863 
2864 
2865 
2866 
2867 
2868 void cWorld::QueueBlockForTick(int a_BlockX, int a_BlockY, int a_BlockZ, int a_TicksToWait)
2869 {
2871  Block->X = a_BlockX;
2872  Block->Y = a_BlockY;
2873  Block->Z = a_BlockZ;
2874  Block->TicksToWait = a_TicksToWait;
2875 
2876  m_BlockTickQueue.push_back(Block);
2877 }
2878 
2879 
2880 
2881 
2882 
2883 bool cWorld::IsBlockDirectlyWatered(int a_BlockX, int a_BlockY, int a_BlockZ)
2884 {
2885  return (
2886  IsBlockWater(GetBlock({ a_BlockX - 1, a_BlockY, a_BlockZ })) ||
2887  IsBlockWater(GetBlock({ a_BlockX + 1, a_BlockY, a_BlockZ })) ||
2888  IsBlockWater(GetBlock({ a_BlockX, a_BlockY, a_BlockZ - 1 })) ||
2889  IsBlockWater(GetBlock({ a_BlockX, a_BlockY, a_BlockZ + 1 }))
2890  );
2891 }
2892 
2893 
2894 
2895 
2896 
2897 UInt32 cWorld::SpawnMob(double a_PosX, double a_PosY, double a_PosZ, eMonsterType a_MonsterType, bool a_Baby)
2898 {
2899  auto Monster = cMonster::NewMonsterFromType(a_MonsterType);
2900  if (Monster == nullptr)
2901  {
2902  return cEntity::INVALID_ID;
2903  }
2904  Monster->SetPosition(a_PosX, a_PosY, a_PosZ);
2905 
2906  if (a_Baby)
2907  {
2908  Monster->SetAge(-1);
2909  }
2910 
2911  return SpawnMobFinalize(std::move(Monster));
2912 }
2913 
2914 
2915 
2916 
2917 
2918 UInt32 cWorld::SpawnMobFinalize(std::unique_ptr<cMonster> a_Monster)
2919 {
2920  ASSERT(a_Monster != nullptr);
2921 
2922  // Give the mob full health.
2923  a_Monster->SetHealth(a_Monster->GetMaxHealth());
2924 
2925  // A plugin doesn't agree with the spawn. bail out.
2926  if (cPluginManager::Get()->CallHookSpawningMonster(*this, *a_Monster))
2927  {
2928  return cEntity::INVALID_ID;
2929  }
2930 
2931  auto & Monster = *a_Monster;
2932 
2933  // Initialize the monster into the current world.
2934  if (!Monster.Initialize(std::move(a_Monster), *this))
2935  {
2936  return cEntity::INVALID_ID;
2937  }
2938 
2939  cPluginManager::Get()->CallHookSpawnedMonster(*this, Monster);
2940 
2941  return Monster.GetUniqueID();
2942 }
2943 
2944 
2945 
2946 
2947 
2948 UInt32 cWorld::CreateProjectile(Vector3d a_Pos, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const cItem * a_Item, const Vector3d * a_Speed)
2949 {
2950  auto Projectile = cProjectileEntity::Create(a_Kind, a_Creator, a_Pos, a_Item, a_Speed);
2951  if (Projectile == nullptr)
2952  {
2953  return cEntity::INVALID_ID;
2954  }
2955 
2956  auto ProjectilePtr = Projectile.get();
2957  if (!ProjectilePtr->Initialize(std::move(Projectile), *this))
2958  {
2959  return cEntity::INVALID_ID;
2960  }
2961 
2962  return ProjectilePtr->GetUniqueID();
2963 }
2964 
2965 
2966 
2967 
2968 
2969 UInt32 cWorld::CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const cItem * a_Item, const Vector3d * a_Speed)
2970 {
2971  return CreateProjectile({a_PosX, a_PosY, a_PosZ}, a_Kind, a_Creator, a_Item, a_Speed);
2972 }
2973 
2974 
2975 
2976 
2977 
2979 {
2980  return GetRandomProvider().RandInt(a_Range);
2981 }
2982 
2983 
2984 
2985 
2986 
2987 void cWorld::TabCompleteUserName(const AString & a_Text, AStringVector & a_Results)
2988 {
2989  typedef std::pair<AString::size_type, AString> pair_t;
2990  size_t LastSpace = a_Text.find_last_of(" "); // Find the position of the last space
2991  AString LastWord = a_Text.substr(LastSpace + 1, a_Text.length()); // Find the last word
2992 
2993  if (LastWord.empty())
2994  {
2995  return;
2996  }
2997 
2998  std::vector<pair_t> UsernamesByWeight;
2999 
3000  cLock Lock(*this);
3001  for (const auto Player : m_Players)
3002  {
3003  AString PlayerName = Player->HasCustomName() ? Player->GetCustomName() : Player->GetName();
3004 
3005  AString::size_type Found = StrToLower(PlayerName).find(StrToLower(LastWord)); // Try to find last word in playername
3006  if (Found == AString::npos)
3007  {
3008  continue; // No match
3009  }
3010 
3011  UsernamesByWeight.push_back(std::make_pair(Found, PlayerName)); // Match! Store it with the position of the match as a weight
3012  }
3013  Lock.Unlock();
3014 
3015  std::sort(UsernamesByWeight.begin(), UsernamesByWeight.end()); // Sort lexicographically (by the first value, then second), so higher weights (usernames with match closer to start) come first (#1274)
3016 
3017  /* TODO: Uncomment once migrated to C++11
3018  std::transform(
3019  UsernamesByWeight.begin(),
3020  UsernamesByWeight.end(),
3021  std::back_inserter(a_Results),
3022  [](const pair_t & p) { return p.first; }
3023  );
3024  */
3025 
3026  a_Results.reserve(UsernamesByWeight.size());
3027  for (std::vector<pair_t>::const_iterator itr = UsernamesByWeight.begin(); itr != UsernamesByWeight.end(); ++itr)
3028  {
3029  a_Results.push_back(itr->second);
3030  }
3031 }
3032 
3033 
3034 
3035 
3036 
3037 void cWorld::SetChunkAlwaysTicked(int a_ChunkX, int a_ChunkZ, bool a_AlwaysTicked)
3038 {
3039  m_ChunkMap.SetChunkAlwaysTicked(a_ChunkX, a_ChunkZ, a_AlwaysTicked);
3040 }
3041 
3042 
3043 
3044 
3045 
3047 {
3048  AString SimulatorName = a_IniFile.GetValueSet("Physics", "RedstoneSimulator", "Incremental");
3049 
3050  if (SimulatorName.empty())
3051  {
3052  LOGWARNING("[Physics] RedstoneSimulator not present or empty in %s, using the default of \"Incremental\".", GetIniFileName().c_str());
3053  SimulatorName = "Incremental";
3054  }
3055 
3056  cRedstoneSimulator * res = nullptr;
3057 
3058  if (NoCaseCompare(SimulatorName, "Incremental") == 0)
3059  {
3060  res = new cIncrementalRedstoneSimulator(*this);
3061  }
3062  else if (NoCaseCompare(SimulatorName, "noop") == 0)
3063  {
3064  res = new cRedstoneNoopSimulator(*this);
3065  }
3066  else
3067  {
3068  LOGWARNING("[Physics] Unknown RedstoneSimulator \"%s\" in %s, using the default of \"Incremental\".", SimulatorName.c_str(), GetIniFileName().c_str());
3069  res = new cIncrementalRedstoneSimulator(*this);
3070  }
3071 
3072  m_SimulatorManager->RegisterSimulator(res, 2 /* Two game ticks is a redstone tick */);
3073 
3074  return res;
3075 }
3076 
3077 
3078 
3079 
3080 
3081 cFluidSimulator * cWorld::InitializeFluidSimulator(cIniFile & a_IniFile, const char * a_FluidName, BLOCKTYPE a_SimulateBlock, BLOCKTYPE a_StationaryBlock)
3082 {
3083  auto SimulatorNameKey = fmt::format(FMT_STRING("{}Simulator"), a_FluidName);
3084  auto SimulatorSectionName = fmt::format(FMT_STRING("{}Simulator"), a_FluidName);
3085 
3086  bool IsWater = (strcmp(a_FluidName, "Water") == 0); // Used for defaults
3087  AString DefaultSimulatorName = ((GetDimension() == dimNether) && IsWater) ? "Vaporise" : "Vanilla";
3088  AString SimulatorName = a_IniFile.GetValueSet("Physics", SimulatorNameKey, DefaultSimulatorName);
3089  if (SimulatorName.empty())
3090  {
3091  LOGWARNING("[Physics] %s not present or empty in %s, using the default of \"%s\".", SimulatorNameKey, GetIniFileName(), DefaultSimulatorName);
3092  SimulatorName = DefaultSimulatorName;
3093  }
3094  cFluidSimulator * res = nullptr;
3095  int Rate = 1;
3096  if (
3097  (NoCaseCompare(SimulatorName, "vaporize") == 0) ||
3098  (NoCaseCompare(SimulatorName, "vaporise") == 0)
3099  )
3100  {
3101  res = new cVaporizeFluidSimulator(*this, a_SimulateBlock, a_StationaryBlock);
3102  }
3103  else if (
3104  (NoCaseCompare(SimulatorName, "noop") == 0) ||
3105  (NoCaseCompare(SimulatorName, "nop") == 0) ||
3106  (NoCaseCompare(SimulatorName, "null") == 0) ||
3107  (NoCaseCompare(SimulatorName, "nil") == 0)
3108  )
3109  {
3110  res = new cNoopFluidSimulator(*this, a_SimulateBlock, a_StationaryBlock);
3111  }
3112  else
3113  {
3114  int Falloff = a_IniFile.GetValueSetI(SimulatorSectionName, "Falloff", IsWater ? 1 : 2);
3115  int TickDelay = a_IniFile.GetValueSetI(SimulatorSectionName, "TickDelay", IsWater ? 5 : 30);
3116  int NumNeighborsForSource = a_IniFile.GetValueSetI(SimulatorSectionName, "NumNeighborsForSource", IsWater ? 2 : -1);
3117 
3118  if ((Falloff > 15) || (Falloff < 0))
3119  {
3120  LOGWARNING("Falloff for %s simulator is out of range, assuming default of %d", a_FluidName, IsWater ? 1 : 2);
3121  Falloff = IsWater ? 1 : 2;
3122  }
3123 
3124  if (NoCaseCompare(SimulatorName, "floody") == 0)
3125  {
3126  res = new cFloodyFluidSimulator(*this, a_SimulateBlock, a_StationaryBlock, static_cast<NIBBLETYPE>(Falloff), TickDelay, NumNeighborsForSource);
3127  }
3128  else if (NoCaseCompare(SimulatorName, "vanilla") == 0)
3129  {
3130  res = new cVanillaFluidSimulator(*this, a_SimulateBlock, a_StationaryBlock, static_cast<NIBBLETYPE>(Falloff), TickDelay, NumNeighborsForSource);
3131  }
3132  else
3133  {
3134  // The simulator name doesn't match anything we have, issue a warning:
3135  LOGWARNING("%s [Physics]:%s specifies an unknown simulator, using the default \"Vanilla\".", GetIniFileName().c_str(), SimulatorNameKey.c_str());
3136  res = new cVanillaFluidSimulator(*this, a_SimulateBlock, a_StationaryBlock, static_cast<NIBBLETYPE>(Falloff), TickDelay, NumNeighborsForSource);
3137  }
3138  }
3139 
3140  m_SimulatorManager->RegisterSimulator(res, Rate);
3141 
3142  return res;
3143 }
3144 
3145 
3146 
3147 
3148 
3150 // cWorld::cChunkGeneratorCallbacks:
3151 
3153  m_World(&a_World)
3154 {
3155 }
3156 
3157 
3158 
3159 
3160 
3162 {
3163  cChunkDef::BlockNibbles BlockMetas;
3164  a_ChunkDesc.CompressBlockMetas(BlockMetas);
3165 
3166  struct SetChunkData Data({ a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ() });
3167  {
3168  Data.BlockData.SetAll(a_ChunkDesc.GetBlockTypes(), BlockMetas);
3169 
3170  std::copy(a_ChunkDesc.GetBiomeMap(), a_ChunkDesc.GetBiomeMap() + std::size(a_ChunkDesc.GetBiomeMap()), Data.BiomeMap);
3171  std::copy(a_ChunkDesc.GetHeightMap(), a_ChunkDesc.GetHeightMap() + std::size(a_ChunkDesc.GetHeightMap()), Data.HeightMap);
3172 
3173  Data.Entities = std::move(a_ChunkDesc.GetEntities());
3174  Data.BlockEntities = std::move(a_ChunkDesc.GetBlockEntities());
3175 
3176  Data.IsLightValid = false;
3177  }
3178 
3179  m_World->QueueSetChunkData(std::move(Data));
3180 }
3181 
3182 
3183 
3184 
3185 
3187 {
3188  return m_World->IsChunkValid(a_Coords.m_ChunkX, a_Coords.m_ChunkZ);
3189 }
3190 
3191 
3192 
3193 
3194 
3196 {
3197  return m_World->IsChunkQueued(a_Coords.m_ChunkX, a_Coords.m_ChunkZ);
3198 }
3199 
3200 
3201 
3202 
3203 
3205 {
3206  return m_World->HasChunkAnyClients(a_Coords.m_ChunkX, a_Coords.m_ChunkZ);
3207 }
3208 
3209 
3210 
3211 
3212 
3214 {
3216  *m_World, a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ(), &a_ChunkDesc
3217  );
3218 }
3219 
3220 
3221 
3222 
3223 
3225 {
3227  *m_World, a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ(), &a_ChunkDesc
3228  );
3229 }
3230 
3231 
3232 
3233 
3234 
3235 bool cWorld::IsSlimeChunk(int a_ChunkX, int a_ChunkZ) const
3236 {
3237  cNoise Noise(GetSeed());
3238  return (Noise.IntNoise2DInt(a_ChunkX, a_ChunkZ) / 8) % 10 == 0; // 10% chance
3239 }
EMCSBiome
Biome IDs The first batch corresponds to the clientside biomes, used by MineCraft.
Definition: BiomeDef.h:18
@ biOcean
Definition: BiomeDef.h:22
@ biFrozenOcean
Definition: BiomeDef.h:34
bool IsBlockWater(BLOCKTYPE a_BlockType)
Definition: BlockInfo.cpp:10
bool IsBlockLiquid(BLOCKTYPE a_BlockType)
Definition: BlockInfo.cpp:58
@ E_META_SAPLING_JUNGLE
Definition: BlockType.h:817
@ E_META_SAPLING_CONIFER
Definition: BlockType.h:815
@ E_META_SAPLING_APPLE
Definition: BlockType.h:814
@ E_META_SAPLING_DARK_OAK
Definition: BlockType.h:819
@ E_META_SAPLING_BIRCH
Definition: BlockType.h:816
@ E_META_SAPLING_ACACIA
Definition: BlockType.h:818
@ E_BLOCK_WATER
Definition: BlockType.h:18
@ E_BLOCK_TRAPDOOR
Definition: BlockType.h:111
@ E_BLOCK_STATIONARY_LAVA
Definition: BlockType.h:21
@ E_BLOCK_AIR
Definition: BlockType.h:10
@ E_BLOCK_SIGN_POST
Definition: BlockType.h:76
@ E_BLOCK_GRASS
Definition: BlockType.h:12
@ E_BLOCK_SNOW_BLOCK
Definition: BlockType.h:94
@ E_BLOCK_SNOW
Definition: BlockType.h:92
@ E_BLOCK_COMMAND_BLOCK
Definition: BlockType.h:152
@ E_BLOCK_NETHERRACK
Definition: BlockType.h:102
@ E_BLOCK_LOG
Definition: BlockType.h:27
@ E_BLOCK_SAPLING
Definition: BlockType.h:16
@ E_BLOCK_SAND
Definition: BlockType.h:22
@ E_BLOCK_IRON_TRAPDOOR
Definition: BlockType.h:186
@ E_BLOCK_STATIONARY_WATER
Definition: BlockType.h:19
@ E_BLOCK_WALLSIGN
Definition: BlockType.h:82
@ E_BLOCK_LAVA
Definition: BlockType.h:20
@ E_ITEM_CHEST_MINECART
Definition: BlockType.h:387
@ E_ITEM_MINECART_WITH_TNT
Definition: BlockType.h:453
@ E_ITEM_MINECART
Definition: BlockType.h:372
@ E_ITEM_MINECART_WITH_HOPPER
Definition: BlockType.h:454
@ E_ITEM_FURNACE_MINECART
Definition: BlockType.h:388
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
unsigned char BLOCKTYPE
The datatype used by blockdata.
Definition: ChunkDef.h:41
AString DimensionToString(eDimension a_Dimension)
Translates a dimension enum to dimension string.
Definition: Defines.cpp:236
bool IsValidItem(int a_ItemType)
Returns true if the specified item type is valid (known).
Definition: Defines.cpp:172
eDimension StringToDimension(const AString &a_DimensionString)
Translates a dimension string to dimension enum.
Definition: Defines.cpp:194
eWeather
Definition: Defines.h:160
@ eWeather_ThunderStorm
Definition: Defines.h:163
@ eWeather_Sunny
Definition: Defines.h:161
@ eWeather_Rain
Definition: Defines.h:162
@ wStorm
Definition: Defines.h:169
@ wSunny
Definition: Defines.h:166
eDimension
Dimension of a world.
Definition: Defines.h:231
@ dimEnd
Definition: Defines.h:234
@ dimNether
Definition: Defines.h:232
@ dimOverworld
Definition: Defines.h:233
@ dimNotSet
Definition: Defines.h:235
eGameMode
Definition: Defines.h:125
@ gmSurvival
Definition: Defines.h:134
@ gmSpectator
Definition: Defines.h:137
eExplosionSource
The source of an explosion.
Definition: Defines.h:309
@ esMonster
Definition: Defines.h:313
@ esWitherSkull
Definition: Defines.h:319
@ esEnderCrystal
Definition: Defines.h:311
@ esTNTMinecart
Definition: Defines.h:317
@ esPrimedTNT
Definition: Defines.h:316
@ esWitherBirth
Definition: Defines.h:318
@ esGhastFireball
Definition: Defines.h:312
eShrapnelLevel
Definition: Defines.h:328
@ slNone
Definition: Defines.h:329
@ slAll
Definition: Defines.h:331
@ SFX_RANDOM_WOODEN_TRAPDOOR_OPEN
MTRand & GetRandomProvider()
Returns the current thread's random number source.
Definition: FastRandom.cpp:12
static bool IsWater(BLOCKTYPE a_BlockType)
Definition: FinishGen.cpp:36
void GetAppleTreeImage(Vector3i a_BlockPos, cNoise &a_Noise, int a_Seq, sSetBlockVector &a_LogBlocks, sSetBlockVector &a_OtherBlocks)
Fills a_LogBlocks and a_OtherBlocks (dirt & leaves) with the blocks required to form a random apple t...
Definition: Trees.cpp:522
void GetDarkoakTreeImage(Vector3i a_BlockPos, cNoise &a_Noise, int a_Seq, sSetBlockVector &a_LogBlocks, sSetBlockVector &a_OtherBlocks)
Fills a_LogBlocks and a_OtherBlocks (dirt & leaves) with the blocks required to form a random darkoak...
Definition: Trees.cpp:769
void GetTreeImageByBiome(Vector3i a_BlockPos, cNoise &a_Noise, int a_Seq, EMCSBiome a_Biome, sSetBlockVector &a_LogBlocks, sSetBlockVector &a_OtherBlocks)
Fills a_LogBlocks and a_OtherBlocks (dirt & leaves) with the blocks required to form a tree at the sp...
Definition: Trees.cpp:310
void GetJungleTreeImage(Vector3i a_BlockPos, cNoise &a_Noise, int a_Seq, sSetBlockVector &a_LogBlocks, sSetBlockVector &a_OtherBlocks, bool a_Large)
Fills a_LogBlocks and a_OtherBlocks (dirt & leaves) with the blocks required to form a random jungle ...
Definition: Trees.cpp:1287
void GetConiferTreeImage(Vector3i a_BlockPos, cNoise &a_Noise, int a_Seq, sSetBlockVector &a_LogBlocks, sSetBlockVector &a_OtherBlocks, bool a_Large)
Fills a_LogBlocks and a_OtherBlocks (dirt & leaves) with the blocks required to form a random conifer...
Definition: Trees.cpp:878
void GetAcaciaTreeImage(Vector3i a_BlockPos, cNoise &a_Noise, int a_Seq, sSetBlockVector &a_LogBlocks, sSetBlockVector &a_OtherBlocks)
Fills a_LogBlocks and a_OtherBlocks (dirt & leaves) with the blocks required to form a random acacia ...
Definition: Trees.cpp:711
void GetBirchTreeImage(Vector3i a_BlockPos, cNoise &a_Noise, int a_Seq, sSetBlockVector &a_LogBlocks, sSetBlockVector &a_OtherBlocks)
Fills a_LogBlocks and a_OtherBlocks (dirt & leaves) with the blocks required to form a random birch t...
Definition: Trees.cpp:673
#define CASE_TREE_ALLOWED_BLOCKS
Definition: Trees.h:27
#define UNREACHABLE(x)
Definition: Globals.h:288
std::chrono::duration< signed long long int, cTickTime::period > cTickTimeLong
Definition: Globals.h:367
#define ARRAYCOUNT(X)
Evaluates to the number of elements in an array (compile-time!)
Definition: Globals.h:231
unsigned int UInt32
Definition: Globals.h:157
signed long long Int64
Definition: Globals.h:151
T Clamp(T a_Value, T a_Min, T a_Max)
Clamp X to the specified range.
Definition: Globals.h:336
std::chrono::duration< signed int, std::ratio_multiply< std::chrono::milliseconds::period, std::ratio< 50 > >> cTickTime
Definition: Globals.h:364
#define ASSERT(x)
Definition: Globals.h:276
#define UNUSED
Definition: Globals.h:72
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 FLOGINFO(std::string_view a_Format, const Args &... args)
Definition: LoggerSimple.h:35
#define FLOGD
Definition: LoggerSimple.h:91
void LOGWARNING(std::string_view a_Format, const Args &... args)
Definition: LoggerSimple.h:67
void LOG(std::string_view a_Format, const Args &... args)
Definition: LoggerSimple.h:55
#define LOGD
Definition: LoggerSimple.h:83
void FLOGWARNING(std::string_view a_Format, const Args &... args)
Definition: LoggerSimple.h:41
eMonsterType
Identifies individual monster type.
Definition: MonsterTypes.h:11
@ mtInvalidType
Definition: MonsterTypes.h:12
BlockType
Definition: BlockTypes.h:4
Item
Definition: Items.h:4
@ Minecart
AStringVector StringSplitAndTrim(const AString &str, const AString &delim)
Split the string at any of the listed delimiters and trim each value.
AString StrToLower(const AString &s)
Returns a lower-cased copy of the string.
int NoCaseCompare(const AString &s1, const AString &s2)
Case-insensitive string comparison.
size_t RateCompareString(const AString &s1, const AString &s2)
Case-insensitive string comparison that returns a rating of equal-ness between [0 - s1....
std::vector< AString > AStringVector
Definition: StringUtils.h:12
std::string AString
Definition: StringUtils.h:11
Vector3< double > Vector3d
Definition: Vector3.h:485
Vector3< int > Vector3i
Definition: Vector3.h:487
Implements custom fmtlib formatting for cChunkCoords.
Definition: ChunkDef.h:104
Utilities to allow casting a cWorld to one of its interfaces without including World....
Definition: OpaqueWorld.h:13
cWorldInterface * GetWorldInterface(cWorld *a_World)
Definition: World.cpp:71
cBroadcastInterface * GetBroadcastInterface(cWorld *a_World)
Definition: World.cpp:69
cChunkInterface GetChunkInterface(cWorld &a_World)
Definition: World.cpp:73
cForEachChunkProvider * GetFECProvider(cWorld *a_World)
Definition: World.cpp:70
void Kaboom(cWorld &a_World, const Vector3f a_Position, const int a_Power, const bool a_Fiery, const cEntity *const a_ExplodingEntity)
Creates an explosion of Power, centred at Position, with ability to set fires as provided.
unsigned char Distance(const BlockState Block)
bool CallHookChunkGenerated(cWorld &a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc *a_ChunkDesc)
bool CallHookChunkGenerating(cWorld &a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc *a_ChunkDesc)
static cPluginManager * Get(void)
Returns the instance of the Plugin Manager (there is only ever one)
bool CallHookSpawnedMonster(cWorld &a_World, cMonster &a_Monster)
bool CallHookUpdatedSign(cWorld &a_World, Vector3i a_BlockPos, const AString &a_Line1, const AString &a_Line2, const AString &a_Line3, const AString &a_Line4, cPlayer *a_Player)
bool CallHookEntityChangedWorld(cEntity &a_Entity, cWorld &a_World)
bool CallHookWeatherChanged(cWorld &a_World)
bool CallHookWorldTick(cWorld &a_World, std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_LastTickDurationMSec)
bool CallHookExploded(cWorld &a_World, double a_ExplosionSize, bool a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void *a_SourceData)
BLOCKTYPE GetBlockType() const
Definition: BlockEntity.h:97
void SetLines(const AString &a_Line1, const AString &a_Line2, const AString &a_Line3, const AString &a_Line4)
Sets all the sign's lines.
Definition: SignEntity.cpp:47
AString GetLine(size_t a_Index) const
Retrieves individual line (zero-based index)
Definition: SignEntity.cpp:74
static bool IsSolid(BLOCKTYPE Block)
Is this block solid (player cannot walk through)?
Definition: BlockInfo.cpp:892
virtual void OnPlaced(cChunkInterface &a_ChunkInterface, cWorldInterface &a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) const
Called by cWorld::SetBlock() after the block has been set.
Definition: BlockHandler.h:50
static const cBlockHandler & For(BLOCKTYPE a_BlockType)
virtual void OnBroken(cChunkInterface &a_ChunkInterface, cWorldInterface &a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta, const cEntity *a_Digger) const
Called after a block gets broken (replaced with air), by natural means.
Definition: BlockHandler.h:60
Represents two sets of coords, minimum and maximum for each direction.
Definition: BoundingBox.h:24
Definition: Chunk.h:36
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
Constants used throughout the code, useful typedefs and utility functions.
Definition: ChunkDef.h:120
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 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
bool Initialize(cPluginInterface &a_PluginInterface, cChunkSink &a_ChunkSink, cIniFile &a_IniFile)
Read settings from the ini file and initialize in preperation for being started.
void QueueGenerateChunk(cChunkCoords a_Coords, bool a_ForceRegeneration, cChunkCoordCallback *a_Callback=nullptr)
Queues the chunk for generation If a-ForceGenerate is set, the chunk is regenerated even if the data ...
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
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
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 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 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
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 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
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
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
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 DigBlock(Vector3i a_BlockPos)
Removes the block at the specified coords and wakes up simulators.
Definition: ChunkMap.cpp:765
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
void Tick(std::chrono::milliseconds a_Dt)
Definition: ChunkMap.cpp:1343
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
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
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 QueueSendChunkTo(int a_ChunkX, int a_ChunkZ, Priority a_Priority, cClientHandle *a_Client)
Queues a chunk to be sent to a specific client.
Definition: ChunkSender.cpp:92
Priority
Tag indicating urgency of chunk to be sent.
Definition: ChunkSender.h:64
void Stop(void)
Definition: ChunkSender.cpp:81
static const int MAX_VIEW_DISTANCE
Definition: ClientHandle.h:59
static const int MIN_VIEW_DISTANCE
Definition: ClientHandle.h:60
void SendPlayerListAddPlayer(const cPlayer &a_Player)
static const int DEFAULT_VIEW_DISTANCE
Definition: ClientHandle.h:57
void AddWantedChunk(int a_ChunkX, int a_ChunkZ)
Adds the chunk specified to the list of chunks wanted for sending (m_ChunksToSend)
Definition: Cuboid.h:10
Vector3i p2
Definition: Cuboid.h:13
Vector3i p1
Definition: Cuboid.h:13
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.
eMaterial
Definition: Boat.h:29
Definition: Entity.h:76
bool IsPlayer(void) const
Definition: Entity.h:160
static const UInt32 INVALID_ID
Special ID that is considered an "invalid value", signifying no entity.
Definition: Entity.h:128
bool IsTicking(void) const
Returns true if the entity is valid and ticking.
Definition: Entity.cpp:2259
bool IsMob(void) const
Definition: Entity.h:162
static std::vector< int > Split(int a_Reward)
Split reward into small values according to regular Minecraft rules.
Definition: ExpOrb.cpp:110
Definition: Player.h:29
cClientHandle * GetClientHandle(void) const
Definition: Player.h:276
eKind
The kind of the projectile.
static std::unique_ptr< cProjectileEntity > Create(eKind a_Kind, cEntity *a_Creator, Vector3d a_Pos, const cItem *a_Item, const Vector3d *a_Speed=nullptr)
Creates a new instance of the specified projectile entity.
IntType RandInt(IntType a_Min, IntType a_Max)
Return a random IntType in the range [a_Min, a_Max].
Definition: FastRandom.h:78
bool RandBool(double a_TrueProbability=0.5)
Return a random bool with the given probability of being true.
Definition: FastRandom.h:158
cEntityList & GetEntities(void)
Definition: ChunkDesc.h:240
int GetChunkX() const
Definition: ChunkDesc.h:49
cChunkDef::BlockTypes & GetBlockTypes(void)
Definition: ChunkDesc.h:235
cBlockEntities & GetBlockEntities(void)
Definition: ChunkDesc.h:241
void CompressBlockMetas(cChunkDef::BlockNibbles &a_DestMetas)
Compresses the metas from the BlockArea format (1 meta per byte) into regular format (2 metas per byt...
Definition: ChunkDesc.cpp:637
cChunkDef::HeightMap & GetHeightMap(void)
Definition: ChunkDesc.h:239
cChunkDef::BiomeMap & GetBiomeMap(void)
Definition: ChunkDesc.h:234
int GetChunkZ() const
Definition: ChunkDesc.h:50
static void InitializeGeneratorDefaults(cIniFile &a_IniFile, eDimension a_Dimension)
If there's no particular sub-generator set in the INI file, adds the default one, based on the dimens...
int FindKey(const AString &keyname) const
Returns index of specified key, or noID if not found.
Definition: IniFile.cpp:243
bool WriteFile(const AString &a_FileName) const
Writes data stored in class to the specified ini file.
Definition: IniFile.cpp:190
bool AddKeyComment(const int keyID, const AString &comment)
Add a key comment.
Definition: IniFile.cpp:739
bool ReadFile(const AString &a_FileName, bool a_AllowExampleRedirect=true)
Reads the contents of the specified ini file If the file doesn't exist and a_AllowExampleRedirect is ...
Definition: IniFile.cpp:50
bool SetValueB(const AString &a_KeyName, const AString &a_ValueName, const bool a_Value, const bool a_CreateIfNotExists=true)
Definition: IniFile.h:173
int GetValueI(const AString &keyname, const AString &valuename, const int defValue=0) const
Definition: IniFile.cpp:506
void AddHeaderComment(const AString &comment)
Adds a header comment.
Definition: IniFile.cpp:674
int GetValueSetI(const AString &keyname, const AString &valuename, const int defValue=0) override
Definition: IniFile.cpp:559
bool SetValueI(const AString &a_KeyName, const AString &a_ValueName, const int a_Value, const bool a_CreateIfNotExists=true) override
Definition: IniFile.cpp:445
bool SetValue(const int keyID, const int valueID, const AString &value)
Definition: IniFile.cpp:397
AString GetValueSet(const AString &keyname, const AString &valuename, const AString &defValue="") override
Gets the value; if not found, write the default to the repository.
Definition: IniFile.cpp:526
bool GetValueSetB(const AString &keyname, const AString &valuename, const bool defValue=false) override
Definition: IniFile.h:150
int FindValue(const int keyID, const AString &valuename) const
Returns index of specified value, in the specified key, or noID if not found.
Definition: IniFile.cpp:260
Definition: Item.h:37
This class bridges a vector of cItem for safe access via Lua.
Definition: Item.h:215
size_t GetQueueLength(void)
void QueueChunk(int a_ChunkX, int a_ChunkZ, std::unique_ptr< cChunkCoordCallback > a_CallbackAfter)
Queues the entire chunk for lighting.
static bool LineOfSightTrace(cWorld &a_World, const Vector3d &a_Start, const Vector3d &a_End, int a_Sight)
Returns true if the two positions are within line of sight (not obscured by blocks).
void LoadMapData(void)
Loads the map data from the disk.
Definition: MapManager.cpp:95
void TickMaps(void)
Ticks each registered map.
Definition: MapManager.cpp:45
void SaveMapData(void)
Saves the map data to the disk.
Definition: MapManager.cpp:129
This class is used to collect information, for each Mob, what is the distance of the closest player i...
Definition: MobCensus.h:26
bool IsCapped(cMonster::eFamily a_MobFamily)
Returns true if the family is capped (i.e.
Definition: MobCensus.cpp:20
static cTickTime GetSpawnDelay(cMonster::eFamily a_MobFamily)
Returns the spawn delay (number of game ticks between spawn attempts) for the given mob family.
Definition: Monster.cpp:1186
static std::unique_ptr< cMonster > NewMonsterFromType(eMonsterType a_MobType)
Creates a new object of the specified mob.
Definition: Monster.cpp:1252
@ mfAmbient
Definition: Monster.h:32
@ mfWater
Definition: Monster.h:33
@ mfPassive
Definition: Monster.h:31
@ mfHostile
Definition: Monster.h:30
static eMonsterType StringToMobType(const AString &a_MobTypeName)
Translates MobType string to the enum, mtInvalidType if not recognized.
Definition: Monster.cpp:1063
This class is used to determine which monster can be spawned in which place it is essentially static ...
Definition: MobSpawner.h:16
Definition: Noise.h:20
int IntNoise2DInt(int a_X, int a_Y) const
Definition: Noise.h:243
RAII for cCriticalSection - locks the CS on creation, unlocks on destruction.
void Unlock(void)
static bool CreateFolderRecursive(const AString &a_FolderPath)
Creates a new folder with the specified name, creating its parents if needed.
Definition: File.cpp:467
void Stop(void)
Signals the thread to terminate and waits until it's finished.
Definition: IsThread.cpp:48
void Start(void)
Starts the thread; returns without waiting for the actual start.
Definition: IsThread.cpp:35
static cRoot * Get()
Definition: Root.h:52
cPluginManager * GetPluginManager(void)
Definition: Root.h:111
Contains the data for a loaded / generated chunk, ready to be set into a cWorld.
Definition: SetChunkData.h:12
void Simulate(float a_Dt)
Called in each tick, a_Dt is the time passed since the last tick, in msec.
static void PrepareChunks(cWorld &a_World, int a_SpawnChunkX, int a_SpawnChunkZ, int a_PrepareDistance)
Definition: UUID.h:11
T x
Definition: Vector3.h:17
Vector3< T > addedXZ(T a_AddX, T a_AddZ) const
Returns a copy of this vector moved by the specified amount on the X and Z axes.
Definition: Vector3.h:326
T z
Definition: Vector3.h:17
Definition: World.h:53
bool TryGetHeight(int a_BlockX, int a_BlockZ, int &a_Height)
Retrieves the world height at the specified coords; returns false if chunk not loaded / generated.
Definition: World.cpp:2132
virtual bool ForEachChunkInRect(int a_MinChunkX, int a_MaxChunkX, int a_MinChunkZ, int a_MaxChunkZ, cChunkDataCallback &a_Callback) override
Calls the callback for each chunk in the coords specified (all cords are inclusive).
Definition: World.cpp:2694
cRedstoneSimulator * InitializeRedstoneSimulator(cIniFile &a_IniFile)
Creates a new redstone simulator.
Definition: World.cpp:3046
bool IsSlimeChunk(int a_ChunkX, int a_ChunkZ) const
Returns true if slimes should spawn in the chunk.
Definition: World.cpp:3235
void ScheduleTask(cTickTime a_DelayTicks, std::function< void(cWorld &)> a_Task)
Queues a lambda task onto the tick thread, with the specified delay.
Definition: World.cpp:2744
cWorldStorage m_Storage
Definition: World.h:1023
int GetSeed(void) const
Returns the seed of the world.
Definition: World.h:846
std::vector< std::pair< std::chrono::milliseconds, std::function< void(cWorld &)> > > m_Tasks
Tasks that have been queued onto the tick thread, possibly to be executed at target tick in the futur...
Definition: World.h:1096
void MarkChunkDirty(int a_ChunkX, int a_ChunkZ)
Definition: World.cpp:2150
bool DropBlockAsPickups(Vector3i a_BlockPos, const cEntity *a_Digger=nullptr, const cItem *a_Tool=nullptr)
Digs the specified block, and spawns the appropriate pickups for it.
Definition: World.cpp:2090
virtual void BroadcastThunderbolt(Vector3i a_BlockPos, const cClientHandle *a_Exclude=nullptr) override
bool m_bCommandBlocksEnabled
Whether command blocks are enabled or not.
Definition: World.h:1058
UInt32 SpawnMobFinalize(std::unique_ptr< cMonster > a_Monster)
Wraps cEntity::Initialize, doing Monster-specific things before spawning the monster.
Definition: World.cpp:2918
void ChunkLoadFailed(int a_ChunkX, int a_ChunkZ)
Marks the chunk as failed-to-load:
Definition: World.cpp:2551
void TickMobs(std::chrono::milliseconds a_Dt)
Handles the mob spawning / moving / destroying each tick.
Definition: World.cpp:1122
UInt32 SpawnItemPickup(Vector3d a_Pos, const cItem &a_Item, Vector3f a_Speed, int a_LifetimeTicks=6000, bool a_CanCombine=true)
Spawns a single pickup containing the specified item.
Definition: World.cpp:1863
cChunkSender m_ChunkSender
Definition: World.h:1088
UInt32 SpawnPrimedTNT(double a_X, double a_Y, double a_Z, int a_FuseTimeInSec=80, double a_InitialVelocityCoeff=1, bool a_ShouldPlayFuseSound=true)
Definition: World.h:519
bool IsSavingEnabled(void) const
Get whether saving chunks is enabled.
Definition: World.h:81
virtual ~cWorld() override
Definition: World.cpp:449
void RemoveClientFromChunks(cClientHandle *a_Client)
Removes the client from all chunks it is present in.
Definition: World.cpp:2514
bool CheckPlayerSpawnPoint(int a_PosX, int a_PosY, int a_PosZ)
Check if player starting point is acceptable.
Definition: World.h:1144
eShrapnelLevel m_TNTShrapnelLevel
The level of DoExplosionAt() projecting random affected blocks as FallingBlock entities See the eShra...
Definition: World.h:1066
bool DoWithPlayerByUUID(const cUUID &a_PlayerUUID, cPlayerListCallback a_Callback)
Finds the player over his uuid and calls the callback.
Definition: World.cpp:2339
void AddEntity(OwnedEntity a_Entity, cWorld *a_OldWorld=nullptr)
Adds the entity into its appropriate chunk; takes ownership of the entity ptr.
Definition: World.cpp:2759
UInt32 SpawnExperienceOrb(Vector3d a_Pos, int a_Reward)
Spawns an experience orb at the given location with the given reward.
Definition: World.cpp:1894
std::chrono::milliseconds m_WorldDate
The fully controllable age of the world.
Definition: World.h:990
int m_WeatherInterval
Definition: World.h:1033
int m_MaxSunnyTicks
Definition: World.h:1034
int m_MinRainTicks
Definition: World.h:1035
std::unique_ptr< cSandSimulator > m_SandSimulator
Definition: World.h:1014
virtual void BroadcastPlayerListUpdatePing() override
bool DoWithChunkAt(Vector3i a_BlockPos, cChunkCallback a_Callback)
Calls the callback for the chunk at the block position specified, with ChunkMapCS locked.
Definition: World.cpp:1460
size_t GetPlayerCount() const
Returns the number of players currently in this world.
Definition: World.cpp:2454
cLightingThread m_Lighting
Definition: World.h:1089
int m_SpawnY
Definition: World.h:968
virtual void BroadcastTimeUpdate(const cClientHandle *a_Exclude=nullptr) override
void QueueLightChunk(int a_ChunkX, int a_ChunkZ, std::unique_ptr< cChunkCoordCallback > a_Callback={})
Queues a chunk for lighting; a_Callback is called after the chunk is lighted.
Definition: World.cpp:2676
int m_MinThunderStormTicks
Definition: World.h:1036
virtual UInt32 SpawnMob(double a_PosX, double a_PosY, double a_PosZ, eMonsterType a_MonsterType, bool a_Baby=false) override
Spawns a mob of the specified type.
Definition: World.cpp:2897
void RegenerateChunk(int a_ChunkX, int a_ChunkZ)
Regenerate the given chunk.
Definition: World.cpp:2657
void UnloadUnusedChunks(void)
Unloads all chunks immediately.
Definition: World.cpp:2238
virtual void DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, bool a_CanCauseFire, eExplosionSource a_Source, void *a_SourceData) override
Does an explosion with the specified strength at the specified coordinates.
Definition: World.cpp:1384
std::chrono::milliseconds m_WorldAge
The age of the world.
Definition: World.h:985
std::vector< BlockTickQueueItem * > m_BlockTickQueueCopy
Definition: World.h:1011
bool GetBlockInfo(Vector3i a_BlockPos, BLOCKTYPE &a_BlockType, NIBBLETYPE &a_Meta, NIBBLETYPE &a_SkyLight, NIBBLETYPE &a_BlockLight) const
Queries the whole block specification from the world.
Definition: World.cpp:1788
void QueueSetChunkData(SetChunkData &&a_SetChunkData)
Puts the chunk data into a queue to be set into the chunkmap in the tick thread.
Definition: World.cpp:2177
cRedstoneSimulator * m_RedstoneSimulator
Definition: World.h:1018
void TabCompleteUserName(const AString &a_Text, AStringVector &a_Results)
Appends all usernames starting with a_Text (case-insensitive) into Results.
Definition: World.cpp:2987
UInt32 SpawnBoat(double a_X, double a_Y, double a_Z, cBoat::eMaterial a_Material)
Definition: World.h:480
void SetChunkAlwaysTicked(int a_ChunkX, int a_ChunkZ, bool a_AlwaysTicked=true)
Increments (a_AlwaysTicked == true) or decrements (false) the m_AlwaysTicked counter for the specifie...
Definition: World.cpp:3037
bool m_bEnabledPVP
Definition: World.h:1004
NIBBLETYPE GetBlockSkyLight(Vector3i a_BlockPos) const
Returns the sky light value at the specified block position.
Definition: World.cpp:1761
bool CanSpawnAt(int a_X, int &a_Y, int a_Z)
Can the specified coordinates be used as a spawn point? Returns true if spawn position is valid and s...
Definition: World.cpp:782
int GrowPlantAt(Vector3i a_BlockPos, int a_NumStages=1)
Grows the plant at the specified position by at most a_NumStages.
Definition: World.cpp:1676
bool GrowRipePlant(Vector3i a_BlockPos)
Grows the plant at the specified block to its ripe stage.
Definition: World.cpp:1685
int GetDefaultWeatherInterval(eWeather a_Weather) const
Returns the default weather interval for the specific weather type.
Definition: World.cpp:531
bool DoWithChunk(int a_ChunkX, int a_ChunkZ, cChunkCallback a_Callback)
Calls the callback for the chunk specified, with ChunkMapCS locked.
Definition: World.cpp:1451
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: World.cpp:2542
BLOCKTYPE GetBlock(Vector3i a_BlockPos) const
Returns the block type at the specified position.
Definition: World.h:363
bool GetLargeTreeAdjustment(Vector3i &a_BlockPos, NIBBLETYPE a_SaplingMeta)
Checks if the sapling at the specified block coord is a part of a large-tree sapling (2x2).
Definition: World.cpp:1530
bool SetAreaBiome(int a_MinX, int a_MaxX, int a_MinZ, int a_MaxZ, EMCSBiome a_Biome)
Sets the biome at the area.
Definition: World.cpp:1712
int GetTickRandomNumber(int a_Range)
Returns a random number in range [0 .
Definition: World.cpp:2978
void QueueUnloadUnusedChunks(void)
Queues a task to unload unused chunks onto the tick thread.
Definition: World.cpp:2248
int m_MaxNetherPortalHeight
Definition: World.h:975
cCriticalSection m_CSTasks
Guards the m_Tasks.
Definition: World.h:1093
virtual cTickTimeLong GetWorldAge(void) const override
Definition: World.cpp:491
bool GetChunkData(cChunkCoords a_Coords, cChunkDataCallback &a_Callback) const
Calls the callback with the chunk's data, if available (with ChunkCS locked).
Definition: World.cpp:2202
void TickQueuedChunkDataSets()
Sets the chunk data queued in the m_SetChunkDataQueue queue into their chunk.
Definition: World.cpp:1208
bool DoWithEntityByID(UInt32 a_UniqueID, cEntityCallback a_Callback)
Calls the callback if the entity with the specified ID is found, with the entity object as the callba...
Definition: World.cpp:2464
void MarkChunkSaved(int a_ChunkX, int a_ChunkZ)
Definition: World.cpp:2168
NIBBLETYPE GetBlockBlockLight(Vector3i a_BlockPos) const
Returns the block-light value at the specified block position.
Definition: World.cpp:1770
void RemoveChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle *a_Client)
Removes client from the chunk specified.
Definition: World.cpp:2505
std::vector< cPlayer * > m_Players
Definition: World.h:1021
cChunkMap m_ChunkMap
Definition: World.h:1027
UInt32 SpawnEnderCrystal(Vector3d a_Pos, bool a_ShowBottom)
Spawns a new ender crystal at the specified block coords.
Definition: World.cpp:2028
const AString & GetName(void) const
Returns the name of the world.
Definition: World.h:691
void SendBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cClientHandle &a_Client)
If there is a block entity at the specified coords, sends it to the client specified.
Definition: World.cpp:2141
bool GetBlockTypeMeta(Vector3i a_BlockPos, BLOCKTYPE &a_BlockType, NIBBLETYPE &a_BlockMeta) const
Retrieves the block type and meta at the specified coords.
Definition: World.cpp:1779
bool m_BroadcastAchievementMessages
Definition: World.h:978
bool m_bUseChatPrefixes
Whether prefixes such as [INFO] are prepended to SendMessageXXX() / BroadcastChatXXX() functions.
Definition: World.h:1061
int m_StorageCompressionFactor
Definition: World.h:958
void TickWeather(float a_Dt)
Handles the weather in each tick.
Definition: World.cpp:1088
void GetChunkStats(int &a_NumValid, int &a_NumDirty, int &a_NumInLightingQueue)
Returns the number of chunks loaded and dirty, and in the lighting queue.
Definition: World.cpp:2828
int m_MaxViewDistance
The maximum view distance that a player can have in this world.
Definition: World.h:1069
std::atomic< bool > m_IsSavingEnabled
Whether or not writing chunks to disk is currently enabled.
Definition: World.h:961
bool IsChunkValid(int a_ChunkX, int a_ChunkZ) const
Returns true iff the chunk is present and valid.
Definition: World.cpp:2220
void QueueTask(std::function< void(cWorld &)> a_Task)
Queues a task onto the tick thread.
Definition: World.cpp:2734
AString GetLinkedOverworldName(void) const
Definition: World.h:727
bool m_bAnimals
Definition: World.h:1029
NIBBLETYPE m_SkyDarkness
Definition: World.h:1001
eGameMode m_GameMode
Definition: World.h:1003
bool m_IsDaylightCycleEnabled
Definition: World.h:980
bool IsTrapdoorOpen(int a_BlockX, int a_BlockY, int a_BlockZ)
Is the trapdoor open? Returns false if there is no trapdoor at the specified coords.
Definition: World.cpp:2616
int m_MaxRainTicks
Definition: World.h:1035
bool IsWeatherSunnyAt(int a_BlockX, int a_BlockZ) const
Returns true if it is sunny at the specified location.
Definition: World.cpp:595
bool ForEachBlockEntityInChunk(int a_ChunkX, int a_ChunkZ, cBlockEntityCallback a_Callback)
Calls the callback for each block entity in the specified chunk; returns true if all block entities p...
Definition: World.cpp:1375
virtual bool ForEachEntityInBox(const cBoundingBox &a_Box, cEntityCallback a_Callback) override
Calls the callback for each entity that has a nonempty intersection with the specified boundingbox.
Definition: World.cpp:2445
void GenerateRandomSpawn(int a_MaxSpawnRadius)
Generates a random spawnpoint on solid land by walking chunks and finding their biomes.
Definition: World.cpp:700
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: World.cpp:2487
virtual void BroadcastSoundParticleEffect(const EffectID a_EffectID, Vector3i a_SrcPos, int a_Data, const cClientHandle *a_Exclude=nullptr) override
void TickClients(std::chrono::milliseconds a_Dt)
Ticks all clients that are in this world.
Definition: World.cpp:1076
int m_MinSunnyTicks
Definition: World.h:1034
virtual eDimension GetDimension(void) const override
Definition: World.h:133
void SaveAllChunks(void)
Saves all chunks immediately.
Definition: World.cpp:2712
int m_MaxSugarcaneHeight
Definition: World.h:1039
void SendPlayerList(cPlayer *a_DestPlayer)
Definition: World.cpp:2410
eWeather m_Weather
Definition: World.h:1032
void TickQueuedTasks(void)
Executes all tasks queued onto the tick thread.
Definition: World.cpp:1289
int m_SpawnX
Definition: World.h:967
std::unique_ptr< cFireSimulator > m_FireSimulator
Definition: World.h:1017
int m_SpawnZ
Definition: World.h:969
cItems PickupsFromBlock(Vector3i a_BlockPos, const cEntity *a_Digger=nullptr, const cItem *a_Tool=nullptr)
Returns all the pickups that would result if the a_Digger dug up the block at a_BlockPos using a_Tool...
Definition: World.cpp:2105
void SetNextBlockToTick(const Vector3i a_BlockPos)
Causes the specified block to be ticked on the next Tick() call.
Definition: World.cpp:622
int m_MaxNetherPortalWidth
Definition: World.h:973
void InitializeSpawn(void)
Definition: World.cpp:658
bool DigBlock(Vector3i a_BlockPos, const cEntity *a_Digger=nullptr)
Replaces the specified block with air, and calls the OnBroken block handler.
Definition: World.cpp:2069
void GenerateChunk(int a_ChunkX, int a_ChunkZ)
Generates the given chunk.
Definition: World.cpp:2667
void InitializeAndLoadMobSpawningValues(cIniFile &a_IniFile)
Sets mob spawning values if nonexistant to their dimension specific defaults.
Definition: World.cpp:917
void ForceSendChunkTo(int a_ChunkX, int a_ChunkZ, cChunkSender::Priority a_Priority, cClientHandle *a_Client)
Sends the chunk to the client specified, even if the client already has the chunk.
Definition: World.cpp:2532
bool IsBlockDirectlyWatered(int a_BlockX, int a_BlockY, int a_BlockZ)
Definition: World.cpp:2883
bool IsChunkQueued(int a_ChunkX, int a_ChunkZ) const
Returns true iff the chunk is in the loader / generator queue.
Definition: World.cpp:2211
size_t m_UnusedDirtyChunksCap
The maximum number of allowed unused dirty chunks for this world.
Definition: World.h:942
cFluidSimulator * m_LavaSimulator
Definition: World.h:1016
cChunkGeneratorThread m_Generator
The thread responsible for generating chunks.
Definition: World.h:1080
NIBBLETYPE GetBlockMeta(Vector3i a_BlockPos) const
Returns the block meta at the specified position.
Definition: World.h:370
AString m_LinkedOverworldName
The name of the overworld that portals in this world should link to.
Definition: World.h:951
bool GrowTreeFromSapling(Vector3i a_BlockPos)
Grows a tree from the sapling at the specified coords.
Definition: World.cpp:1487
bool SetSignLines(Vector3i a_BlockPos, const AString &a_Line1, const AString &a_Line2, const AString &a_Line3, const AString &a_Line4, cPlayer *a_Player=nullptr)
Sets the sign text, asking plugins for permission first.
Definition: World.cpp:2560
void CollectPickupsByEntity(cEntity &a_Entity)
Definition: World.cpp:2257
bool m_BroadcastDeathMessages
Definition: World.h:977
bool m_ShouldLavaSpawnFire
Definition: World.h:1007
std::set< eMonsterType > m_AllowedMobs
Definition: World.h:1030
void SendChunkTo(int a_ChunkX, int a_ChunkZ, cChunkSender::Priority a_Priority, cClientHandle *a_Client)
Sends the chunk to the client specified, if the client doesn't have the chunk yet.
Definition: World.cpp:2523
virtual bool WriteBlockArea(cBlockArea &a_Area, int a_MinBlockX, int a_MinBlockY, int a_MinBlockZ, int a_DataTypes) override
Writes the block area into the specified coords.
Definition: World.cpp:1797
virtual void WakeUpSimulators(Vector3i a_Block) override
Wakes up the simulators for the specified block.
Definition: World.cpp:1357
bool SetCommandBlockCommand(int a_BlockX, int a_BlockY, int a_BlockZ, const AString &a_Command)
Sets the command block command.
Definition: World.cpp:2598
bool SetTrapdoorOpen(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_Open)
Set the state of a trapdoor.
Definition: World.cpp:2633
void Start()
Starts threads that belong to this world.
Definition: World.cpp:687
void TickQueuedBlocks(void)
Processes the blocks queued for ticking with a delay (m_BlockTickQueue[])
Definition: World.cpp:2838
eDimension m_Dimension
The dimension of the world, used by the client to provide correct lighting scheme.
Definition: World.h:964
virtual void BroadcastWeather(eWeather a_Weather, const cClientHandle *a_Exclude=nullptr) override
void ChunkLighted(int a_ChunkX, int a_ChunkZ, const cChunkDef::BlockNibbles &a_BlockLight, const cChunkDef::BlockNibbles &a_SkyLight)
Definition: World.cpp:2189
bool HasChunkAnyClients(int a_ChunkX, int a_ChunkZ) const
Definition: World.cpp:2229
void ChangeWeather(void)
Forces a weather change in the next game tick.
Definition: World.cpp:585
std::unique_ptr< cSimulatorManager > m_SimulatorManager
Definition: World.h:1013
bool FindAndDoWithPlayer(const AString &a_PlayerNameHint, cPlayerListCallback a_Callback)
Finds a player from a partial or complete player name and calls the callback - case-insensitive.
Definition: World.cpp:2303
AString m_LinkedNetherWorldName
Name of the nether world - where Nether portals should teleport.
Definition: World.h:1073
bool GrowTreeImage(const sSetBlockVector &a_Blocks)
Imprints the specified blocks into the world, as long as each log block replaces only allowed blocks.
Definition: World.cpp:1631
bool ForEachEntity(cEntityCallback a_Callback)
Calls the callback for each entity in the entire world; returns true if all entities processed,...
Definition: World.cpp:2427
bool SetSpawn(int a_X, int a_Y, int a_Z)
Set default spawn at the given coordinates.
Definition: World.cpp:631
void TickQueuedEntityAdditions(void)
Adds the entities queued in the m_EntitiesToAdd queue into their chunk.
Definition: World.cpp:1250
std::map< cMonster::eFamily, cTickTimeLong > m_LastSpawnMonster
Definition: World.h:999
size_t GetNumUnusedDirtyChunks(void) const
Returns the number of unused dirty chunks.
Definition: World.cpp:2819
cTickTimeLong m_WorldTickAge
The time since this world began, in ticks.
Definition: World.h:995
AString m_WorldName
Definition: World.h:944
void MarkChunkSaving(int a_ChunkX, int a_ChunkZ)
Definition: World.cpp:2159
void PlaceBlock(const Vector3i a_Position, const BLOCKTYPE a_BlockType, const NIBBLETYPE a_BlockMeta)
Replaces the specified block with another, and calls the OnPlaced block handler.
Definition: World.cpp:2043
virtual bool IsWeatherWetAt(int a_BlockX, int a_BlockZ) override
Returns true if it is raining or storming at the specified location.
Definition: World.cpp:604
cChunkGeneratorCallbacks m_GeneratorCallbacks
The callbacks that the ChunkGenerator uses to store new chunks and interface to plugins.
Definition: World.h:1086
cCriticalSection m_CSEntitiesToAdd
Guards m_EntitiesToAdd.
Definition: World.h:1099
cMapManager m_MapManager
Definition: World.h:1083
cWorld(const AString &a_WorldName, const AString &a_DataPath, cDeadlockDetect &a_DeadlockDetect, const AStringVector &a_WorldNames, eDimension a_Dimension=dimOverworld, const AString &a_LinkedOverworldName={})
Construct the world and read settings from its ini file.
Definition: World.cpp:137
unsigned int m_MaxPlayers
Definition: World.h:1025
bool GrowTreeByBiome(Vector3i a_BlockPos)
Grows a tree at the specified coords, based on the biome in the place.
Definition: World.cpp:1616
bool GrowTree(Vector3i a_BlockPos)
Grows a tree at the specified coords.
Definition: World.cpp:1469
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
void QueueSaveAllChunks(void)
Queues a task to save all chunks onto the tick thread.
Definition: World.cpp:2725
bool m_IsDeepSnowEnabled
Definition: World.h:1006
std::vector< SetChunkData > m_SetChunkDataQueue
Queue for the chunk data to be set into m_ChunkMap by the tick thread.
Definition: World.h:1108
std::chrono::milliseconds m_LastChunkCheck
Definition: World.h:997
EMCSBiome GetBiomeAt(int a_BlockX, int a_BlockZ)
Returns the biome at the specified coords.
Definition: World.cpp:1694
AString m_StorageSchema
Name of the storage schema used to load and save chunks.
Definition: World.h:956
bool DoWithPlayer(const AString &a_PlayerName, cPlayerListCallback a_Callback)
Calls the callback for the player of the given name; returns true if the player was found and the cal...
Definition: World.cpp:2284
bool m_bFarmlandTramplingEnabled
Definition: World.h:1005
UInt32 SpawnMinecart(Vector3d a_Pos, int a_MinecartType, const cItem &a_Content=cItem(), int a_BlockHeight=1)
Spawns an minecart at the given coordinates.
Definition: World.cpp:1958
const AString & GetIniFileName(void) const
Returns the name of the world.ini file used by this world.
Definition: World.h:697
bool GetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, AString &a_Line1, AString &a_Line2, AString &a_Line3, AString &a_Line4)
Retrieves the test on the sign at the specified coords; returns false if there's no sign at those coo...
Definition: World.cpp:1429
int m_MaxThunderStormTicks
Definition: World.h:1036
virtual cTickTime GetTimeOfDay(void) const override
Definition: World.cpp:480
bool SetBiomeAt(int a_BlockX, int a_BlockZ, EMCSBiome a_Biome)
Sets the biome at the specified coords.
Definition: World.cpp:1703
AString m_IniFileName
Definition: World.h:953
virtual bool DoWithBlockEntityAt(Vector3i a_Position, cBlockEntityCallback a_Callback) override
Calls the callback for the block entity at the specified coords; returns false if there's no block en...
Definition: World.cpp:1420
virtual bool IsWeatherWetAtXYZ(Vector3i a_Position) override
Returns true if it is raining or storming at the specified location, and the rain reaches (the bottom...
Definition: World.cpp:613
std::vector< std::pair< OwnedEntity, cWorld * > > m_EntitiesToAdd
List of entities that are scheduled for adding, waiting for the Tick thread to add them.
Definition: World.h:1102
int m_MinNetherPortalWidth
Definition: World.h:972
cTickTimeLong GetWorldTickAge() const
Definition: World.cpp:509
virtual std::vector< UInt32 > SpawnSplitExperienceOrbs(Vector3d a_Pos, int a_Reward) override
Spawns experience orbs of the specified total value at the given location.
Definition: World.cpp:1915
void QueueBlockForTick(int a_BlockX, int a_BlockY, int a_BlockZ, int a_TicksToWait)
Queues the block to be ticked after the specified number of game ticks.
Definition: World.cpp:2868
cFluidSimulator * InitializeFluidSimulator(cIniFile &a_IniFile, const char *a_FluidName, BLOCKTYPE a_SimulateBlock, BLOCKTYPE a_StationaryBlock)
Creates a new fluid simulator, loads its settings from the inifile (a_FluidName section)
Definition: World.cpp:3081
AString m_DataPath
The path to the root directory for the world files.
Definition: World.h:947
std::vector< BlockTickQueueItem * > m_BlockTickQueue
Definition: World.h:1010
std::chrono::milliseconds m_LastSave
Definition: World.h:998
eWeather ChooseNewWeather(void)
Chooses a reasonable transition from the current weather to a new weather.
Definition: World.cpp:894
void CastThunderbolt(Vector3i a_Block)
Casts a thunderbolt at the specified coords.
Definition: World.cpp:470
UInt32 SpawnFallingBlock(Vector3d a_Pos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
Spawns an falling block entity at the given position.
Definition: World.cpp:1878
UInt32 CreateProjectile(Vector3d a_Pos, cProjectileEntity::eKind a_Kind, cEntity *a_Creator, const cItem *a_Item, const Vector3d *a_Speed=nullptr)
Creates a projectile of the specified type.
Definition: World.cpp:2948
cScoreboard m_Scoreboard
Definition: World.h:1082
int m_MaxCactusHeight
Definition: World.h:1038
void SetMaxViewDistance(int a_MaxViewDistance)
Definition: World.cpp:1734
size_t GetNumChunks() const
Returns the number of chunks loaded
Definition: World.cpp:2810
AString m_LinkedEndWorldName
Name of the End world - where End portals should teleport.
Definition: World.h:1077
cCriticalSection m_CSSetChunkDataQueue
CS protecting m_SetChunkDataQueue.
Definition: World.h:1105
virtual void BroadcastSoundEffect(const AString &a_SoundName, Vector3d a_Position, float a_Volume, float a_Pitch, const cClientHandle *a_Exclude=nullptr) override
virtual void SendBlockTo(int a_BlockX, int a_BlockY, int a_BlockZ, const cPlayer &a_Player)=0
Sends the block on those coords to the player.
bool GetBlocks(sSetBlockVector &a_Blocks, bool a_ContinueOnFailure)
Retrieves block types of the specified blocks.
Definition: World.cpp:2060
bool DoWithNearestPlayer(Vector3d a_Pos, double a_RangeLimit, cPlayerListCallback a_Callback, bool a_CheckLineOfSight=true, bool a_IgnoreSpectator=true)
Calls the callback for nearest player for given position, Returns false if player not found,...
Definition: World.cpp:2356
bool ForEachLoadedChunk(cFunctionRef< bool(int, int)> a_Callback)
Calls the callback for each loaded chunk.
Definition: World.cpp:2703
void WakeUpSimulatorsInArea(const cCuboid &a_Area)
Wakes up the simulators for the specified area of blocks.
Definition: World.cpp:1366
cTickTimeLong GetWorldDate() const
Definition: World.cpp:500
void SetBlockMeta(Vector3i a_BlockPos, NIBBLETYPE a_MetaData)
Sets the meta for the specified block, while keeping the blocktype.
Definition: World.cpp:1752
cChunkMap * GetChunkMap(void)
Definition: World.h:852
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: World.cpp:2436
void UpdateSkyDarkness(void)
Definition: World.cpp:1326
cSimulatorManager * GetSimulatorManager(void)
Definition: World.h:597
bool IsChunkLighted(int a_ChunkX, int a_ChunkZ)
Definition: World.cpp:2685
int m_MinNetherPortalHeight
Definition: World.h:974
OwnedEntity RemoveEntity(cEntity &a_Entity)
Removes the entity from the world.
Definition: World.cpp:2769
bool m_VillagersShouldHarvestCrops
Definition: World.h:1008
void Tick(std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_LastTickDurationMSec)
Definition: World.cpp:1002
virtual bool ForEachPlayer(cPlayerListCallback a_Callback) override
Calls the callback for each player in the list; returns true if all players processed,...
Definition: World.cpp:2266
cTickThread m_TickThread
Definition: World.h:1090
virtual void SetTimeOfDay(cTickTime a_TimeOfDay) override
Definition: World.cpp:518
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
void SetWeather(eWeather a_NewWeather)
Sets the specified weather; resets weather interval; asks and notifies plugins of the change.
Definition: World.cpp:556
virtual int GetHeight(int a_BlockX, int a_BlockZ) override
Returns the world height at the specified coords; waits for the chunk to get loaded / generated.
Definition: World.cpp:2123
void Stop(cDeadlockDetect &a_DeadlockDetect)
Stops threads that belong to this world (part of deinit).
Definition: World.cpp:956
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: World.cpp:2496
bool m_IsSpawnExplicitlySet
Definition: World.h:966
cFluidSimulator * m_WaterSimulator
Definition: World.h:1015
A simple RAII locker for the chunkmap - locks the chunkmap in its constructor, unlocks it in the dest...
Definition: World.h:60
cLock(const cWorld &a_World)
Definition: World.cpp:86
cTickThread(cWorld &a_World)
Definition: World.cpp:98
virtual void Execute(void) override
This function, overloaded by the descendants, is called in the new thread.
Definition: World.cpp:108
virtual bool IsChunkValid(cChunkCoords a_Coords) override
Called just before the chunk generation is started, to verify that it hasn't been generated in the me...
Definition: World.cpp:3186
cChunkGeneratorCallbacks(cWorld &a_World)
Definition: World.cpp:3152
virtual void CallHookChunkGenerated(cChunkDesc &a_ChunkDesc) override
Called after the chunk is generated, before it is handed to the chunk sink.
Definition: World.cpp:3224
virtual void CallHookChunkGenerating(cChunkDesc &a_ChunkDesc) override
Called when the chunk is about to be generated.
Definition: World.cpp:3213
virtual bool HasChunkAnyClients(cChunkCoords a_Coords) override
Called when the generator is overloaded to skip chunks that are no longer needed.
Definition: World.cpp:3204
virtual void OnChunkGenerated(cChunkDesc &a_ChunkDesc) override
Called after the chunk has been generated The interface may store the chunk, send it over network,...
Definition: World.cpp:3161
virtual bool IsChunkQueued(cChunkCoords a_Coords) override
Called to check whether the specified chunk is in the queued state.
Definition: World.cpp:3195
bool Load(void)
Try to load the scoreboard.
bool Save(void)
Try to save the scoreboard.
void Stop(void)
void Initialize(cWorld &a_World, const AString &a_StorageSchemaName, int a_StorageCompressionFactor)
Initializes the storage schemas, ready to be started.