summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpeterbell10 <peterbell10@live.co.uk>2017-09-22 17:55:42 +0200
committerMattes D <github@xoft.cz>2017-10-21 19:33:22 +0200
commit1537ebed6fa880ca8f9df92e5ac99324375b91a5 (patch)
tree0f141da47761e94a64331584b3924b9436777f51
parentFix tool builds on AppleClang (diff)
downloadcuberite-1537ebed6fa880ca8f9df92e5ac99324375b91a5.tar
cuberite-1537ebed6fa880ca8f9df92e5ac99324375b91a5.tar.gz
cuberite-1537ebed6fa880ca8f9df92e5ac99324375b91a5.tar.bz2
cuberite-1537ebed6fa880ca8f9df92e5ac99324375b91a5.tar.lz
cuberite-1537ebed6fa880ca8f9df92e5ac99324375b91a5.tar.xz
cuberite-1537ebed6fa880ca8f9df92e5ac99324375b91a5.tar.zst
cuberite-1537ebed6fa880ca8f9df92e5ac99324375b91a5.zip
-rw-r--r--src/Generating/ChunkGenerator.cpp5
-rw-r--r--src/Generating/ChunkGenerator.h6
-rw-r--r--src/Root.cpp29
-rw-r--r--src/Root.h2
-rw-r--r--src/World.cpp442
-rw-r--r--src/World.h16
6 files changed, 261 insertions, 239 deletions
diff --git a/src/Generating/ChunkGenerator.cpp b/src/Generating/ChunkGenerator.cpp
index 8c0997d6b..d66838f9e 100644
--- a/src/Generating/ChunkGenerator.cpp
+++ b/src/Generating/ChunkGenerator.cpp
@@ -47,7 +47,7 @@ cChunkGenerator::~cChunkGenerator()
-bool cChunkGenerator::Start(cPluginInterface & a_PluginInterface, cChunkSink & a_ChunkSink, cIniFile & a_IniFile)
+bool cChunkGenerator::Initialize(cPluginInterface & a_PluginInterface, cChunkSink & a_ChunkSink, cIniFile & a_IniFile)
{
m_PluginInterface = &a_PluginInterface;
m_ChunkSink = &a_ChunkSink;
@@ -86,8 +86,7 @@ bool cChunkGenerator::Start(cPluginInterface & a_PluginInterface, cChunkSink & a
}
m_Generator->Initialize(a_IniFile);
-
- return super::Start();
+ return true;
}
diff --git a/src/Generating/ChunkGenerator.h b/src/Generating/ChunkGenerator.h
index cbbe1d1c7..c4be505da 100644
--- a/src/Generating/ChunkGenerator.h
+++ b/src/Generating/ChunkGenerator.h
@@ -33,7 +33,7 @@ class cChunkDesc;
class cChunkGenerator :
- cIsThread
+ public cIsThread
{
typedef cIsThread super;
@@ -110,7 +110,9 @@ public:
cChunkGenerator (void);
virtual ~cChunkGenerator() override;
- bool Start(cPluginInterface & a_PluginInterface, cChunkSink & a_ChunkSink, cIniFile & a_IniFile);
+ /** Read settings from the ini file and initialize in preperation for being started. */
+ bool Initialize(cPluginInterface & a_PluginInterface, cChunkSink & a_ChunkSink, cIniFile & a_IniFile);
+
void Stop(void);
/** Queues the chunk for generation
diff --git a/src/Root.cpp b/src/Root.cpp
index 5c461a9ac..cdc25b2a0 100644
--- a/src/Root.cpp
+++ b/src/Root.cpp
@@ -213,7 +213,7 @@ void cRoot::Start(std::unique_ptr<cSettingsRepositoryInterface> a_OverridesRepo)
m_BrewingRecipes.reset(new cBrewingRecipes());
LOGD("Loading worlds...");
- LoadWorlds(*settingsRepo, IsNewIniFile);
+ LoadWorlds(dd, *settingsRepo, IsNewIniFile);
LOGD("Loading plugin manager...");
m_PluginManager = new cPluginManager(dd);
@@ -397,7 +397,7 @@ void cRoot::LoadGlobalSettings()
-void cRoot::LoadWorlds(cSettingsRepositoryInterface & a_Settings, bool a_IsNewIniFile)
+void cRoot::LoadWorlds(cDeadlockDetect & a_dd, cSettingsRepositoryInterface & a_Settings, bool a_IsNewIniFile)
{
if (a_IsNewIniFile)
{
@@ -407,19 +407,28 @@ void cRoot::LoadWorlds(cSettingsRepositoryInterface & a_Settings, bool a_IsNewIn
a_Settings.AddValue("WorldPaths", "world", "world");
a_Settings.AddValue("WorldPaths", "world_nether", "world_nether");
a_Settings.AddValue("WorldPaths", "world_the_end", "world_the_end");
- m_pDefaultWorld = new cWorld("world", "world");
+
+ AStringVector WorldNames{ "world", "world_nether", "world_the_end" };
+ m_pDefaultWorld = new cWorld("world", "world", a_dd, WorldNames);
m_WorldsByName["world"] = m_pDefaultWorld;
- m_WorldsByName["world_nether"] = new cWorld("world_nether", "world_nether", dimNether, "world");
- m_WorldsByName["world_the_end"] = new cWorld("world_the_end", "world_the_end", dimEnd, "world");
+ m_WorldsByName["world_nether"] = new cWorld("world_nether", "world_nether", a_dd, WorldNames, dimNether, "world");
+ m_WorldsByName["world_the_end"] = new cWorld("world_the_end", "world_the_end", a_dd, WorldNames, dimEnd, "world");
return;
}
- // First get the default world
+ // Build a list of all world names
+ auto Worlds = a_Settings.GetValues("Worlds");
+ AStringVector WorldNames(Worlds.size());
+ for (const auto & World : Worlds)
+ {
+ WorldNames.push_back(World.second);
+ }
+
+ // Get the default world
AString DefaultWorldName = a_Settings.GetValueSet("Worlds", "DefaultWorld", "world");
AString DefaultWorldPath = a_Settings.GetValueSet("WorldPaths", DefaultWorldName, DefaultWorldName);
- m_pDefaultWorld = new cWorld(DefaultWorldName.c_str(), DefaultWorldPath.c_str());
+ m_pDefaultWorld = new cWorld(DefaultWorldName.c_str(), DefaultWorldPath.c_str(), a_dd, WorldNames);
m_WorldsByName[ DefaultWorldName ] = m_pDefaultWorld;
- auto Worlds = a_Settings.GetValues("Worlds");
// Then load the other worlds
if (Worlds.size() <= 0)
@@ -516,7 +525,7 @@ void cRoot::LoadWorlds(cSettingsRepositoryInterface & a_Settings, bool a_IsNewIn
}
Dimension = dimEnd;
}
- NewWorld = new cWorld(WorldName.c_str(), WorldPath.c_str(), Dimension, LinkTo);
+ NewWorld = new cWorld(WorldName.c_str(), WorldPath.c_str(), a_dd, WorldNames, Dimension, LinkTo);
m_WorldsByName[WorldName] = NewWorld;
} // for i - Worlds
@@ -538,7 +547,7 @@ void cRoot::StartWorlds(cDeadlockDetect & a_DeadlockDetect)
{
for (WorldMap::iterator itr = m_WorldsByName.begin(); itr != m_WorldsByName.end(); ++itr)
{
- itr->second->Start(a_DeadlockDetect);
+ itr->second->Start();
itr->second->InitializeSpawn();
m_PluginManager->CallHookWorldStarted(*itr->second);
}
diff --git a/src/Root.h b/src/Root.h
index 4f191cf35..0735d9493 100644
--- a/src/Root.h
+++ b/src/Root.h
@@ -228,7 +228,7 @@ private:
void LoadGlobalSettings();
/** Loads the worlds from settings.ini, creates the worldmap */
- void LoadWorlds(cSettingsRepositoryInterface & a_Settings, bool a_IsNewIniFile);
+ void LoadWorlds(cDeadlockDetect & a_dd, cSettingsRepositoryInterface & a_Settings, bool a_IsNewIniFile);
/** Starts each world's life */
void StartWorlds(cDeadlockDetect & a_DeadlockDetect);
diff --git a/src/World.cpp b/src/World.cpp
index 48c26da5a..d86329395 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -120,7 +120,11 @@ void cWorld::cTickThread::Execute(void)
////////////////////////////////////////////////////////////////////////////////
// cWorld:
-cWorld::cWorld(const AString & a_WorldName, const AString & a_DataPath, eDimension a_Dimension, const AString & a_LinkedOverworldName) :
+cWorld::cWorld(
+ const AString & a_WorldName, const AString & a_DataPath,
+ cDeadlockDetect & a_DeadlockDetect, const AStringVector & a_WorldNames,
+ eDimension a_Dimension, const AString & a_LinkedOverworldName
+):
m_WorldName(a_WorldName),
m_DataPath(a_DataPath),
m_LinkedOverworldName(a_LinkedOverworldName),
@@ -135,7 +139,7 @@ cWorld::cWorld(const AString & a_WorldName, const AString & a_DataPath, eDimensi
m_Dimension(a_Dimension),
m_IsSpawnExplicitlySet(false),
m_SpawnX(0),
- m_SpawnY(0),
+ m_SpawnY(cChunkDef::Height),
m_SpawnZ(0),
m_BroadcastDeathMessages(true),
m_BroadcastAchievementMessages(true),
@@ -146,7 +150,7 @@ cWorld::cWorld(const AString & a_WorldName, const AString & a_DataPath, eDimensi
m_LastChunkCheck(0),
m_LastSave(0),
m_SkyDarkness(0),
- m_GameMode(gmNotSet),
+ m_GameMode(gmSurvival),
m_bEnabledPVP(false),
m_IsDeepSnowEnabled(false),
m_ShouldLavaSpawnFire(true),
@@ -201,6 +205,221 @@ cWorld::cWorld(const AString & a_WorldName, const AString & a_DataPath, eDimensi
// Load the scoreboard
cScoreboardSerializer Serializer(m_DataPath, &m_Scoreboard);
Serializer.Load();
+
+ // Track the CSs used by this world in the deadlock detector:
+ a_DeadlockDetect.TrackCriticalSection(m_CSClients, Printf("World %s clients", m_WorldName.c_str()));
+ a_DeadlockDetect.TrackCriticalSection(m_CSPlayers, Printf("World %s players", m_WorldName.c_str()));
+ a_DeadlockDetect.TrackCriticalSection(m_CSTasks, Printf("World %s tasks", m_WorldName.c_str()));
+
+ // Load world settings from the ini file
+ cIniFile IniFile;
+ if (!IniFile.ReadFile(m_IniFileName))
+ {
+ LOGWARNING("Cannot read world settings from \"%s\", defaults will be used.", m_IniFileName.c_str());
+
+ // TODO: More descriptions for each key
+ IniFile.AddHeaderComment(" This is the per-world configuration file, managing settings such as generators, simulators, and spawn points");
+ IniFile.AddKeyComment(" LinkedWorlds", "This section governs portal world linkage; leave a value blank to disabled that associated method of teleportation");
+ }
+
+ // The presence of a configuration value overrides everything
+ // 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
+ m_Dimension = StringToDimension(IniFile.GetValueSet("General", "Dimension", DimensionToString(GetDimension())));
+ int UnusedDirtyChunksCap = IniFile.GetValueSetI("General", "UnusedChunkCap", 1000);
+ if (UnusedDirtyChunksCap < 0)
+ {
+ UnusedDirtyChunksCap *= -1;
+ IniFile.SetValueI("General", "UnusedChunkCap", UnusedDirtyChunksCap);
+ }
+ m_UnusedDirtyChunksCap = static_cast<size_t>(UnusedDirtyChunksCap);
+
+ m_BroadcastDeathMessages = IniFile.GetValueSetB("Broadcasting", "BroadcastDeathMessages", true);
+ m_BroadcastAchievementMessages = IniFile.GetValueSetB("Broadcasting", "BroadcastAchievementMessages", true);
+
+ SetMaxViewDistance(IniFile.GetValueSetI("SpawnPosition", "MaxViewDistance", 12));
+
+ // Try to find the "SpawnPosition" key and coord values in the world configuration, set the flag if found
+ int KeyNum = IniFile.FindKey("SpawnPosition");
+ m_IsSpawnExplicitlySet =
+ (
+ (KeyNum >= 0) &&
+ (
+ (IniFile.FindValue(KeyNum, "X") >= 0) &&
+ (IniFile.FindValue(KeyNum, "Y") >= 0) &&
+ (IniFile.FindValue(KeyNum, "Z") >= 0)
+ )
+ );
+
+ if (m_IsSpawnExplicitlySet)
+ {
+ LOGD("Spawnpoint explicitly set!");
+ m_SpawnX = IniFile.GetValueF("SpawnPosition", "X", m_SpawnX);
+ m_SpawnY = IniFile.GetValueF("SpawnPosition", "Y", m_SpawnY);
+ m_SpawnZ = IniFile.GetValueF("SpawnPosition", "Z", m_SpawnZ);
+ }
+
+ m_StorageSchema = IniFile.GetValueSet ("Storage", "Schema", m_StorageSchema);
+ m_StorageCompressionFactor = IniFile.GetValueSetI("Storage", "CompressionFactor", m_StorageCompressionFactor);
+ m_MaxCactusHeight = IniFile.GetValueSetI("Plants", "MaxCactusHeight", 3);
+ m_MaxSugarcaneHeight = IniFile.GetValueSetI("Plants", "MaxSugarcaneHeight", 3);
+ m_IsBeetrootsBonemealable = IniFile.GetValueSetB("Plants", "IsBeetrootsBonemealable", true);
+ m_IsCactusBonemealable = IniFile.GetValueSetB("Plants", "IsCactusBonemealable", false);
+ m_IsCarrotsBonemealable = IniFile.GetValueSetB("Plants", "IsCarrotsBonemealable", true);
+ m_IsCropsBonemealable = IniFile.GetValueSetB("Plants", "IsCropsBonemealable", true);
+ m_IsGrassBonemealable = IniFile.GetValueSetB("Plants", "IsGrassBonemealable", true);
+ m_IsMelonStemBonemealable = IniFile.GetValueSetB("Plants", "IsMelonStemBonemealable", true);
+ m_IsMelonBonemealable = IniFile.GetValueSetB("Plants", "IsMelonBonemealable", false);
+ m_IsPotatoesBonemealable = IniFile.GetValueSetB("Plants", "IsPotatoesBonemealable", true);
+ m_IsPumpkinStemBonemealable = IniFile.GetValueSetB("Plants", "IsPumpkinStemBonemealable", true);
+ m_IsPumpkinBonemealable = IniFile.GetValueSetB("Plants", "IsPumpkinBonemealable", false);
+ m_IsSaplingBonemealable = IniFile.GetValueSetB("Plants", "IsSaplingBonemealable", true);
+ m_IsSugarcaneBonemealable = IniFile.GetValueSetB("Plants", "IsSugarcaneBonemealable", false);
+ m_IsBigFlowerBonemealable = IniFile.GetValueSetB("Plants", "IsBigFlowerBonemealable", true);
+ m_IsTallGrassBonemealable = IniFile.GetValueSetB("Plants", "IsTallGrassBonemealable", true);
+ m_IsDeepSnowEnabled = IniFile.GetValueSetB("Physics", "DeepSnow", true);
+ m_ShouldLavaSpawnFire = IniFile.GetValueSetB("Physics", "ShouldLavaSpawnFire", true);
+ int TNTShrapnelLevel = IniFile.GetValueSetI("Physics", "TNTShrapnelLevel", static_cast<int>(slAll));
+ m_bCommandBlocksEnabled = IniFile.GetValueSetB("Mechanics", "CommandBlocksEnabled", false);
+ m_bEnabledPVP = IniFile.GetValueSetB("Mechanics", "PVPEnabled", true);
+ m_bUseChatPrefixes = IniFile.GetValueSetB("Mechanics", "UseChatPrefixes", true);
+ m_MinNetherPortalWidth = IniFile.GetValueSetI("Mechanics", "MinNetherPortalWidth", 2);
+ m_MaxNetherPortalWidth = IniFile.GetValueSetI("Mechanics", "MaxNetherPortalWidth", 21);
+ m_MinNetherPortalHeight = IniFile.GetValueSetI("Mechanics", "MinNetherPortalHeight", 3);
+ m_MaxNetherPortalHeight = IniFile.GetValueSetI("Mechanics", "MaxNetherPortalHeight", 21);
+ m_VillagersShouldHarvestCrops = IniFile.GetValueSetB("Monsters", "VillagersShouldHarvestCrops", true);
+ m_IsDaylightCycleEnabled = IniFile.GetValueSetB("General", "IsDaylightCycleEnabled", true);
+ int GameMode = IniFile.GetValueSetI("General", "Gamemode", static_cast<int>(m_GameMode));
+ int Weather = IniFile.GetValueSetI("General", "Weather", static_cast<int>(m_Weather));
+
+ m_WorldAge = std::chrono::milliseconds(IniFile.GetValueSetI("General", "WorldAgeMS", 0LL));
+
+ // Load the weather frequency data:
+ if (m_Dimension == dimOverworld)
+ {
+ m_MaxSunnyTicks = IniFile.GetValueSetI("Weather", "MaxSunnyTicks", m_MaxSunnyTicks);
+ m_MinSunnyTicks = IniFile.GetValueSetI("Weather", "MinSunnyTicks", m_MinSunnyTicks);
+ m_MaxRainTicks = IniFile.GetValueSetI("Weather", "MaxRainTicks", m_MaxRainTicks);
+ m_MinRainTicks = IniFile.GetValueSetI("Weather", "MinRainTicks", m_MinRainTicks);
+ m_MaxThunderStormTicks = IniFile.GetValueSetI("Weather", "MaxThunderStormTicks", m_MaxThunderStormTicks);
+ m_MinThunderStormTicks = IniFile.GetValueSetI("Weather", "MinThunderStormTicks", m_MinThunderStormTicks);
+ if (m_MaxSunnyTicks < m_MinSunnyTicks)
+ {
+ std::swap(m_MaxSunnyTicks, m_MinSunnyTicks);
+ }
+ if (m_MaxRainTicks < m_MinRainTicks)
+ {
+ std::swap(m_MaxRainTicks, m_MinRainTicks);
+ }
+ if (m_MaxThunderStormTicks < m_MinThunderStormTicks)
+ {
+ std::swap(m_MaxThunderStormTicks, m_MinThunderStormTicks);
+ }
+ }
+
+ auto WorldExists = [&](const AString & a_CheckWorldName)
+ {
+ return (std::find(a_WorldNames.begin(), a_WorldNames.end(), a_CheckWorldName) != a_WorldNames.end());
+ };
+
+ if (a_Dimension == dimOverworld)
+ {
+ AString MyNetherName = GetName() + "_nether";
+ AString MyEndName = GetName() + "_the_end";
+ if (!WorldExists(MyNetherName))
+ {
+ MyNetherName.clear();
+ }
+ if (!WorldExists(MyEndName))
+ {
+ MyEndName = GetName() + "_end";
+ if (!WorldExists(MyEndName))
+ {
+ MyEndName.clear();
+ }
+ }
+
+ m_LinkedNetherWorldName = IniFile.GetValueSet("LinkedWorlds", "NetherWorldName", MyNetherName);
+ m_LinkedEndWorldName = IniFile.GetValueSet("LinkedWorlds", "EndWorldName", MyEndName);
+ }
+ else
+ {
+ m_LinkedOverworldName = IniFile.GetValueSet("LinkedWorlds", "OverworldName", GetLinkedOverworldName());
+ }
+
+ // If we are linked to one or more worlds that do not exist, unlink them
+ if (a_Dimension == dimOverworld)
+ {
+ if (!m_LinkedNetherWorldName.empty() && !WorldExists(m_LinkedNetherWorldName))
+ {
+ IniFile.SetValue("LinkedWorlds", "NetherWorldName", "");
+ LOG("%s Is linked to a nonexisting nether world called \"%s\". The server has modified \"%s/world.ini\" and removed this invalid link.",
+ GetName().c_str(), m_LinkedNetherWorldName.c_str(), GetName().c_str());
+ m_LinkedNetherWorldName.clear();
+ }
+ if (!m_LinkedEndWorldName.empty() && !WorldExists(m_LinkedEndWorldName))
+ {
+ IniFile.SetValue("LinkedWorlds", "EndWorldName", "");
+ LOG("%s Is linked to a nonexisting end world called \"%s\". The server has modified \"%s/world.ini\" and removed this invalid link.",
+ GetName().c_str(), m_LinkedEndWorldName.c_str(), GetName().c_str());
+ m_LinkedEndWorldName.clear();
+ }
+ }
+ else
+ {
+ if (!m_LinkedOverworldName.empty() && !WorldExists(m_LinkedOverworldName))
+ {
+ IniFile.SetValue("LinkedWorlds", "OverworldName", "");
+ LOG("%s Is linked to a nonexisting overworld called \"%s\". The server has modified \"%s/world.ini\" and removed this invalid link.",
+ GetName().c_str(), m_LinkedOverworldName.c_str(), GetName().c_str());
+ m_LinkedOverworldName.clear();
+ }
+ }
+
+
+
+ // Adjust the enum-backed variables into their respective bounds:
+ m_GameMode = static_cast<eGameMode> (Clamp<int>(GameMode, gmSurvival, gmSpectator));
+ m_TNTShrapnelLevel = static_cast<eShrapnelLevel>(Clamp<int>(TNTShrapnelLevel, slNone, slAll));
+ m_Weather = static_cast<eWeather> (Clamp<int>(Weather, wSunny, wStorm));
+
+ InitialiseGeneratorDefaults(IniFile);
+ InitialiseAndLoadMobSpawningValues(IniFile);
+ SetTimeOfDay(IniFile.GetValueSetI("General", "TimeInTicks", GetTimeOfDay()));
+
+ m_ChunkMap = cpp14::make_unique<cChunkMap>(this);
+ m_ChunkMap->TrackInDeadlockDetect(a_DeadlockDetect, m_WorldName);
+
+ // preallocate some memory for ticking blocks so we don't need to allocate that often
+ m_BlockTickQueue.reserve(1000);
+ m_BlockTickQueueCopy.reserve(1000);
+
+ // Simulators:
+ m_SimulatorManager = cpp14::make_unique<cSimulatorManager>(*this);
+ m_WaterSimulator = InitializeFluidSimulator(IniFile, "Water", E_BLOCK_WATER, E_BLOCK_STATIONARY_WATER);
+ m_LavaSimulator = InitializeFluidSimulator(IniFile, "Lava", E_BLOCK_LAVA, E_BLOCK_STATIONARY_LAVA);
+ m_SandSimulator = cpp14::make_unique<cSandSimulator>(*this, IniFile);
+ m_FireSimulator = cpp14::make_unique<cFireSimulator>(*this, IniFile);
+ m_RedstoneSimulator = InitializeRedstoneSimulator(IniFile);
+
+ // Water, Lava and Redstone simulators get registered in their initialize function.
+ m_SimulatorManager->RegisterSimulator(m_SandSimulator.get(), 1);
+ m_SimulatorManager->RegisterSimulator(m_FireSimulator.get(), 1);
+
+ m_Generator.Initialize(m_GeneratorCallbacks, m_GeneratorCallbacks, IniFile);
+
+ m_MapManager.LoadMapData();
+
+ // Save any changes that the defaults may have done to the ini file:
+ if (!IniFile.WriteFile(m_IniFileName))
+ {
+ LOGWARNING("Could not write world config to %s", m_IniFileName.c_str());
+ }
+
+ // Init of the spawn monster time (as they are supposed to have different spawn rate)
+ m_LastSpawnMonster.emplace(cMonster::mfHostile, cTickTimeLong(0));
+ m_LastSpawnMonster.emplace(cMonster::mfPassive, cTickTimeLong(0));
+ m_LastSpawnMonster.emplace(cMonster::mfAmbient, cTickTimeLong(0));
+ m_LastSpawnMonster.emplace(cMonster::mfWater, cTickTimeLong(0));
}
@@ -386,226 +605,13 @@ void cWorld::InitializeSpawn(void)
-void cWorld::Start(cDeadlockDetect & a_DeadlockDetect)
+void cWorld::Start()
{
- // Track the CSs used by this world in the deadlock detector:
- a_DeadlockDetect.TrackCriticalSection(m_CSClients, Printf("World %s clients", m_WorldName.c_str()));
- a_DeadlockDetect.TrackCriticalSection(m_CSPlayers, Printf("World %s players", m_WorldName.c_str()));
- a_DeadlockDetect.TrackCriticalSection(m_CSTasks, Printf("World %s tasks", m_WorldName.c_str()));
-
- m_SpawnX = 0;
- m_SpawnY = cChunkDef::Height;
- m_SpawnZ = 0;
- m_GameMode = eGameMode_Survival;
-
- cIniFile IniFile;
- if (!IniFile.ReadFile(m_IniFileName))
- {
- LOGWARNING("Cannot read world settings from \"%s\", defaults will be used.", m_IniFileName.c_str());
-
- // TODO: More descriptions for each key
- IniFile.AddHeaderComment(" This is the per-world configuration file, managing settings such as generators, simulators, and spawn points");
- IniFile.AddKeyComment(" LinkedWorlds", "This section governs portal world linkage; leave a value blank to disabled that associated method of teleportation");
- }
-
- // The presence of a configuration value overrides everything
- // 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
- m_Dimension = StringToDimension(IniFile.GetValueSet("General", "Dimension", DimensionToString(GetDimension())));
- int UnusedDirtyChunksCap = IniFile.GetValueSetI("General", "UnusedChunkCap", 1000);
- if (UnusedDirtyChunksCap < 0)
- {
- UnusedDirtyChunksCap *= -1;
- IniFile.SetValueI("General", "UnusedChunkCap", UnusedDirtyChunksCap);
- }
- m_UnusedDirtyChunksCap = static_cast<size_t>(UnusedDirtyChunksCap);
-
- m_BroadcastDeathMessages = IniFile.GetValueSetB("Broadcasting", "BroadcastDeathMessages", true);
- m_BroadcastAchievementMessages = IniFile.GetValueSetB("Broadcasting", "BroadcastAchievementMessages", true);
-
- SetMaxViewDistance(IniFile.GetValueSetI("SpawnPosition", "MaxViewDistance", 12));
-
- // Try to find the "SpawnPosition" key and coord values in the world configuration, set the flag if found
- int KeyNum = IniFile.FindKey("SpawnPosition");
- m_IsSpawnExplicitlySet =
- (
- (KeyNum >= 0) &&
- (
- (IniFile.FindValue(KeyNum, "X") >= 0) &&
- (IniFile.FindValue(KeyNum, "Y") >= 0) &&
- (IniFile.FindValue(KeyNum, "Z") >= 0)
- )
- );
-
- if (m_IsSpawnExplicitlySet)
- {
- LOGD("Spawnpoint explicitly set!");
- m_SpawnX = IniFile.GetValueF("SpawnPosition", "X", m_SpawnX);
- m_SpawnY = IniFile.GetValueF("SpawnPosition", "Y", m_SpawnY);
- m_SpawnZ = IniFile.GetValueF("SpawnPosition", "Z", m_SpawnZ);
- }
-
- m_StorageSchema = IniFile.GetValueSet ("Storage", "Schema", m_StorageSchema);
- m_StorageCompressionFactor = IniFile.GetValueSetI("Storage", "CompressionFactor", m_StorageCompressionFactor);
- m_MaxCactusHeight = IniFile.GetValueSetI("Plants", "MaxCactusHeight", 3);
- m_MaxSugarcaneHeight = IniFile.GetValueSetI("Plants", "MaxSugarcaneHeight", 3);
- m_IsBeetrootsBonemealable = IniFile.GetValueSetB("Plants", "IsBeetrootsBonemealable", true);
- m_IsCactusBonemealable = IniFile.GetValueSetB("Plants", "IsCactusBonemealable", false);
- m_IsCarrotsBonemealable = IniFile.GetValueSetB("Plants", "IsCarrotsBonemealable", true);
- m_IsCropsBonemealable = IniFile.GetValueSetB("Plants", "IsCropsBonemealable", true);
- m_IsGrassBonemealable = IniFile.GetValueSetB("Plants", "IsGrassBonemealable", true);
- m_IsMelonStemBonemealable = IniFile.GetValueSetB("Plants", "IsMelonStemBonemealable", true);
- m_IsMelonBonemealable = IniFile.GetValueSetB("Plants", "IsMelonBonemealable", false);
- m_IsPotatoesBonemealable = IniFile.GetValueSetB("Plants", "IsPotatoesBonemealable", true);
- m_IsPumpkinStemBonemealable = IniFile.GetValueSetB("Plants", "IsPumpkinStemBonemealable", true);
- m_IsPumpkinBonemealable = IniFile.GetValueSetB("Plants", "IsPumpkinBonemealable", false);
- m_IsSaplingBonemealable = IniFile.GetValueSetB("Plants", "IsSaplingBonemealable", true);
- m_IsSugarcaneBonemealable = IniFile.GetValueSetB("Plants", "IsSugarcaneBonemealable", false);
- m_IsBigFlowerBonemealable = IniFile.GetValueSetB("Plants", "IsBigFlowerBonemealable", true);
- m_IsTallGrassBonemealable = IniFile.GetValueSetB("Plants", "IsTallGrassBonemealable", true);
- m_IsDeepSnowEnabled = IniFile.GetValueSetB("Physics", "DeepSnow", true);
- m_ShouldLavaSpawnFire = IniFile.GetValueSetB("Physics", "ShouldLavaSpawnFire", true);
- int TNTShrapnelLevel = IniFile.GetValueSetI("Physics", "TNTShrapnelLevel", static_cast<int>(slAll));
- m_bCommandBlocksEnabled = IniFile.GetValueSetB("Mechanics", "CommandBlocksEnabled", false);
- m_bEnabledPVP = IniFile.GetValueSetB("Mechanics", "PVPEnabled", true);
- m_bUseChatPrefixes = IniFile.GetValueSetB("Mechanics", "UseChatPrefixes", true);
- m_MinNetherPortalWidth = IniFile.GetValueSetI("Mechanics", "MinNetherPortalWidth", 2);
- m_MaxNetherPortalWidth = IniFile.GetValueSetI("Mechanics", "MaxNetherPortalWidth", 21);
- m_MinNetherPortalHeight = IniFile.GetValueSetI("Mechanics", "MinNetherPortalHeight", 3);
- m_MaxNetherPortalHeight = IniFile.GetValueSetI("Mechanics", "MaxNetherPortalHeight", 21);
- m_VillagersShouldHarvestCrops = IniFile.GetValueSetB("Monsters", "VillagersShouldHarvestCrops", true);
- m_IsDaylightCycleEnabled = IniFile.GetValueSetB("General", "IsDaylightCycleEnabled", true);
- int GameMode = IniFile.GetValueSetI("General", "Gamemode", static_cast<int>(m_GameMode));
- int Weather = IniFile.GetValueSetI("General", "Weather", static_cast<int>(m_Weather));
-
- m_WorldAge = std::chrono::milliseconds(IniFile.GetValueSetI("General", "WorldAgeMS", 0LL));
-
- // Load the weather frequency data:
- if (m_Dimension == dimOverworld)
- {
- m_MaxSunnyTicks = IniFile.GetValueSetI("Weather", "MaxSunnyTicks", m_MaxSunnyTicks);
- m_MinSunnyTicks = IniFile.GetValueSetI("Weather", "MinSunnyTicks", m_MinSunnyTicks);
- m_MaxRainTicks = IniFile.GetValueSetI("Weather", "MaxRainTicks", m_MaxRainTicks);
- m_MinRainTicks = IniFile.GetValueSetI("Weather", "MinRainTicks", m_MinRainTicks);
- m_MaxThunderStormTicks = IniFile.GetValueSetI("Weather", "MaxThunderStormTicks", m_MaxThunderStormTicks);
- m_MinThunderStormTicks = IniFile.GetValueSetI("Weather", "MinThunderStormTicks", m_MinThunderStormTicks);
- if (m_MaxSunnyTicks < m_MinSunnyTicks)
- {
- std::swap(m_MaxSunnyTicks, m_MinSunnyTicks);
- }
- if (m_MaxRainTicks < m_MinRainTicks)
- {
- std::swap(m_MaxRainTicks, m_MinRainTicks);
- }
- if (m_MaxThunderStormTicks < m_MinThunderStormTicks)
- {
- std::swap(m_MaxThunderStormTicks, m_MinThunderStormTicks);
- }
- }
-
- if (GetDimension() == dimOverworld)
- {
- AString MyNetherName = GetName() + "_nether";
- AString MyEndName = GetName() + "_the_end";
- if (cRoot::Get()->GetWorld(MyNetherName) == nullptr)
- {
- MyNetherName = "";
- }
- if (cRoot::Get()->GetWorld(MyEndName) == nullptr)
- {
- MyEndName = GetName() + "_end";
- if (cRoot::Get()->GetWorld(MyEndName) == nullptr)
- {
- MyEndName = "";
- }
- }
-
- m_LinkedNetherWorldName = IniFile.GetValueSet("LinkedWorlds", "NetherWorldName", MyNetherName);
- m_LinkedEndWorldName = IniFile.GetValueSet("LinkedWorlds", "EndWorldName", MyEndName);
- }
- else
- {
- m_LinkedOverworldName = IniFile.GetValueSet("LinkedWorlds", "OverworldName", GetLinkedOverworldName());
- }
-
- // If we are linked to one or more worlds that do not exist, unlink them
- cRoot * Root = cRoot::Get();
- if (GetDimension() == dimOverworld)
- {
- if ((!m_LinkedNetherWorldName.empty()) && (Root->GetWorld(m_LinkedNetherWorldName) == nullptr))
- {
- IniFile.SetValue("LinkedWorlds", "NetherWorldName", "");
- LOG("%s Is linked to a nonexisting nether world called \"%s\". The server has modified \"%s/world.ini\" and removed this invalid link.",
- GetName().c_str(), m_LinkedNetherWorldName.c_str(), GetName().c_str());
- m_LinkedNetherWorldName = "";
- }
- if ((!m_LinkedEndWorldName.empty()) && (Root->GetWorld(m_LinkedEndWorldName) == nullptr))
- {
- IniFile.SetValue("LinkedWorlds", "EndWorldName", "");
- LOG("%s Is linked to a nonexisting end world called \"%s\". The server has modified \"%s/world.ini\" and removed this invalid link.",
- GetName().c_str(), m_LinkedEndWorldName.c_str(), GetName().c_str());
- m_LinkedEndWorldName = "";
- }
- }
- else
- {
- if ((!m_LinkedOverworldName.empty()) && (Root->GetWorld(m_LinkedOverworldName) == nullptr))
- {
- IniFile.SetValue("LinkedWorlds", "OverworldName", "");
- LOG("%s Is linked to a nonexisting overworld called \"%s\". The server has modified \"%s/world.ini\" and removed this invalid link.",
- GetName().c_str(), m_LinkedOverworldName.c_str(), GetName().c_str());
- m_LinkedOverworldName = "";
- }
- }
-
-
-
- // Adjust the enum-backed variables into their respective bounds:
- m_GameMode = static_cast<eGameMode> (Clamp<int>(GameMode, gmSurvival, gmSpectator));
- m_TNTShrapnelLevel = static_cast<eShrapnelLevel>(Clamp<int>(TNTShrapnelLevel, slNone, slAll));
- m_Weather = static_cast<eWeather> (Clamp<int>(Weather, wSunny, wStorm));
-
- InitialiseGeneratorDefaults(IniFile);
- InitialiseAndLoadMobSpawningValues(IniFile);
- SetTimeOfDay(IniFile.GetValueSetI("General", "TimeInTicks", GetTimeOfDay()));
-
- m_ChunkMap = cpp14::make_unique<cChunkMap>(this);
- m_ChunkMap->TrackInDeadlockDetect(a_DeadlockDetect, m_WorldName);
-
- // preallocate some memory for ticking blocks so we don't need to allocate that often
- m_BlockTickQueue.reserve(1000);
- m_BlockTickQueueCopy.reserve(1000);
-
- // Simulators:
- m_SimulatorManager = cpp14::make_unique<cSimulatorManager>(*this);
- m_WaterSimulator = InitializeFluidSimulator(IniFile, "Water", E_BLOCK_WATER, E_BLOCK_STATIONARY_WATER);
- m_LavaSimulator = InitializeFluidSimulator(IniFile, "Lava", E_BLOCK_LAVA, E_BLOCK_STATIONARY_LAVA);
- m_SandSimulator = cpp14::make_unique<cSandSimulator>(*this, IniFile);
- m_FireSimulator = cpp14::make_unique<cFireSimulator>(*this, IniFile);
- m_RedstoneSimulator = InitializeRedstoneSimulator(IniFile);
-
- // Water, Lava and Redstone simulators get registered in their initialize function.
- m_SimulatorManager->RegisterSimulator(m_SandSimulator.get(), 1);
- m_SimulatorManager->RegisterSimulator(m_FireSimulator.get(), 1);
-
m_Lighting.Start(this);
m_Storage.Start(this, m_StorageSchema, m_StorageCompressionFactor);
- m_Generator.Start(m_GeneratorCallbacks, m_GeneratorCallbacks, IniFile);
+ m_Generator.Start();
m_ChunkSender.Start();
m_TickThread.Start();
-
- // Init of the spawn monster time (as they are supposed to have different spawn rate)
- m_LastSpawnMonster.insert(std::map<cMonster::eFamily, cTickTimeLong>::value_type(cMonster::mfHostile, cTickTimeLong(0)));
- m_LastSpawnMonster.insert(std::map<cMonster::eFamily, cTickTimeLong>::value_type(cMonster::mfPassive, cTickTimeLong(0)));
- m_LastSpawnMonster.insert(std::map<cMonster::eFamily, cTickTimeLong>::value_type(cMonster::mfAmbient, cTickTimeLong(0)));
- m_LastSpawnMonster.insert(std::map<cMonster::eFamily, cTickTimeLong>::value_type(cMonster::mfWater, cTickTimeLong(0)));
-
- m_MapManager.LoadMapData();
-
- // Save any changes that the defaults may have done to the ini file:
- if (!IniFile.WriteFile(m_IniFileName))
- {
- LOGWARNING("Could not write world config to %s", m_IniFileName.c_str());
- }
}
diff --git a/src/World.h b/src/World.h
index 5f18f7a39..5b26ec197 100644
--- a/src/World.h
+++ b/src/World.h
@@ -731,9 +731,8 @@ public:
void InitializeSpawn(void);
- /** Starts threads that belong to this world.
- a_DeadlockDetect is used for tracking this world's age, detecting a possible deadlock. */
- void Start(cDeadlockDetect & a_DeadlockDetect);
+ /** Starts threads that belong to this world. */
+ void Start();
/** Stops threads that belong to this world (part of deinit).
a_DeadlockDetect is used for tracking this world's age, detecting a possible deadlock. */
@@ -1066,8 +1065,15 @@ private:
/** Queue for the chunk data to be set into m_ChunkMap by the tick thread. Protected by m_CSSetChunkDataQueue */
cSetChunkDataPtrs m_SetChunkDataQueue;
-
- cWorld(const AString & a_WorldName, const AString & a_DataPath, eDimension a_Dimension = dimOverworld, const AString & a_LinkedOverworldName = "");
+ /** Construct the world and read settings from its ini file.
+ @param a_DeadlockDetect is used for tracking this world's age, detecting a possible deadlock.
+ @param a_WorldNames is a list of all world names, used to validate linked worlds
+ */
+ cWorld(
+ const AString & a_WorldName, const AString & a_DataPath,
+ cDeadlockDetect & a_DeadlockDetect, const AStringVector & a_WorldNames,
+ eDimension a_Dimension = dimOverworld, const AString & a_LinkedOverworldName = {}
+ );
virtual ~cWorld() override;
void Tick(std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_LastTickDurationMSec);