summaryrefslogtreecommitdiffstats
path: root/src/World.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/World.cpp')
-rw-r--r--src/World.cpp69
1 files changed, 36 insertions, 33 deletions
diff --git a/src/World.cpp b/src/World.cpp
index 100df5742..3dc083a2e 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -11,7 +11,6 @@
#include "IniFile.h"
#include "ChunkMap.h"
#include "Generating/ChunkDesc.h"
-#include "OSSupport/Timer.h"
#include "SetChunkData.h"
// Serializers
@@ -45,7 +44,6 @@
#include "MobCensus.h"
#include "MobSpawner.h"
-#include "MersenneTwister.h"
#include "Generating/Trees.h"
#include "Bindings/PluginManager.h"
#include "Blocks/BlockHandler.h"
@@ -92,7 +90,6 @@ public:
m_PrepareDistance(a_PrepareDistance),
m_MaxIdx(a_PrepareDistance * a_PrepareDistance),
m_NumPrepared(0),
- m_LastReportTime(0),
m_LastReportChunkCount(0)
{
// Start the thread:
@@ -113,7 +110,7 @@ public:
m_MaxIdx = m_PrepareDistance * m_PrepareDistance;
int maxQueue = std::min(m_MaxIdx - 1, 100); // Number of chunks to queue at once
m_NextIdx = maxQueue;
- m_LastReportTime = m_Timer.GetNowTime();
+ m_LastReportTime = std::chrono::steady_clock::now();
for (int i = 0; i < maxQueue; i++)
{
int chunkX, chunkZ;
@@ -146,16 +143,12 @@ protected:
/** Event used to signal that the preparation is finished. */
cEvent m_EvtFinished;
- /** The timer used to report progress every second. */
- cTimer m_Timer;
-
/** The timestamp of the last progress report emitted. */
- long long m_LastReportTime;
+ std::chrono::steady_clock::time_point m_LastReportTime;
/** Number of chunks prepared when the last progress report was emitted. */
int m_LastReportChunkCount;
-
// cChunkCoordCallback override:
virtual void Call(int a_ChunkX, int a_ChunkZ)
{
@@ -164,6 +157,8 @@ protected:
if (m_NumPrepared >= m_MaxIdx)
{
m_EvtFinished.Set();
+ // Must return here, because "this" may have gotten deleted by the previous line
+ return;
}
// Queue another chunk, if appropriate:
@@ -176,15 +171,15 @@ protected:
}
// Report progress every 1 second:
- long long now = m_Timer.GetNowTime();
- if (now - m_LastReportTime > 1000)
+ auto Now = std::chrono::steady_clock::now();
+ if (Now - m_LastReportTime > std::chrono::seconds(1))
{
- float percentDone = static_cast<float>(m_NumPrepared * 100) / m_MaxIdx;
- float chunkSpeed = static_cast<float>((m_NumPrepared - m_LastReportChunkCount) * 1000) / (now - m_LastReportTime);
- LOG("Preparing spawn (%s): %.02f%% done (%d chunks out of %d; %.02f chunks / sec)",
- m_World.GetName().c_str(), percentDone, m_NumPrepared, m_MaxIdx, chunkSpeed
+ float PercentDone = static_cast<float>(m_NumPrepared * 100) / m_MaxIdx;
+ float ChunkSpeed = static_cast<float>((m_NumPrepared - m_LastReportChunkCount) * 1000) / std::chrono::duration_cast<std::chrono::milliseconds>(Now - m_LastReportTime).count();
+ LOG("Preparing spawn (%s): %.02f%% (%d/%d; %.02f chunks/s)",
+ m_World.GetName().c_str(), PercentDone, m_NumPrepared, m_MaxIdx, ChunkSpeed
);
- m_LastReportTime = now;
+ m_LastReportTime = Now;
m_LastReportChunkCount = m_NumPrepared;
}
}
@@ -237,23 +232,22 @@ cWorld::cTickThread::cTickThread(cWorld & a_World) :
void cWorld::cTickThread::Execute(void)
{
- cTimer Timer;
+ auto LastTime = std::chrono::steady_clock::now();
+ static const auto msPerTick = std::chrono::milliseconds(50);
+ auto TickTime = std::chrono::steady_clock::duration(50);
- const Int64 msPerTick = 50;
- Int64 LastTime = Timer.GetNowTime();
-
- Int64 TickDuration = 50;
while (!m_ShouldTerminate)
{
- Int64 NowTime = Timer.GetNowTime();
- float DeltaTime = (float)(NowTime - LastTime);
- m_World.Tick(DeltaTime, (int)TickDuration);
- TickDuration = Timer.GetNowTime() - NowTime;
+ auto NowTime = std::chrono::steady_clock::now();
+ auto msec = std::chrono::duration_cast<std::chrono::milliseconds>(NowTime - LastTime).count();
+ auto LastTickMsec = std::chrono::duration_cast<std::chrono::duration<int>>(TickTime).count();
+ m_World.Tick(static_cast<float>(msec), LastTickMsec);
+ TickTime = std::chrono::steady_clock::now() - NowTime;
- if (TickDuration < msPerTick)
+ if (TickTime < msPerTick)
{
// Stretch tick time until it's at least msPerTick
- cSleep::MilliSleep((unsigned int)(msPerTick - TickDuration));
+ std::this_thread::sleep_for(msPerTick - TickTime);
}
LastTime = NowTime;
@@ -352,6 +346,10 @@ cWorld::~cWorld()
Serializer.Save();
m_MapManager.SaveMapData();
+
+ // Explicitly destroy the chunkmap, so that it's guaranteed to be destroyed before the other internals
+ // This fixes crashes on stopping the server, because chunk destructor deletes entities and those access the world.
+ m_ChunkMap.reset();
}
@@ -612,7 +610,7 @@ void cWorld::Start(void)
}
// Adjust the enum-backed variables into their respective bounds:
- m_GameMode = (eGameMode) Clamp(GameMode, (int)gmSurvival, (int)gmAdventure);
+ m_GameMode = (eGameMode) Clamp(GameMode, (int)gmSurvival, (int)gmSpectator);
m_TNTShrapnelLevel = (eShrapnelLevel)Clamp(TNTShrapnelLevel, (int)slNone, (int)slAll);
m_Weather = (eWeather) Clamp(Weather, (int)wSunny, (int)wStorm);
@@ -745,7 +743,7 @@ void cWorld::InitialiseGeneratorDefaults(cIniFile & a_IniFile)
a_IniFile.GetValueSet("Generator", "BiomeGen", "Grown");
a_IniFile.GetValueSet("Generator", "ShapeGen", "BiomalNoise3D");
a_IniFile.GetValueSet("Generator", "CompositionGen", "Biomal");
- a_IniFile.GetValueSet("Generator", "Finishers", "Ravines, WormNestCaves, WaterLakes, WaterSprings, LavaLakes, LavaSprings, OreNests, Mineshafts, Trees, Villages, SprinkleFoliage, Ice, Snow, Lilypads, BottomLava, DeadBushes, PreSimulator");
+ a_IniFile.GetValueSet("Generator", "Finishers", "Ravines, WormNestCaves, WaterLakes, WaterSprings, LavaLakes, LavaSprings, OreNests, Mineshafts, Trees, Villages, SprinkleFoliage, Ice, Snow, Lilypads, BottomLava, DeadBushes, NaturalPatches, PreSimulator, Animals");
break;
}
case dimNether:
@@ -757,7 +755,7 @@ void cWorld::InitialiseGeneratorDefaults(cIniFile & a_IniFile)
a_IniFile.GetValueSet("Generator", "HeightGen", "Flat");
a_IniFile.GetValueSet("Generator", "FlatHeight", "128");
a_IniFile.GetValueSet("Generator", "CompositionGen", "Nether");
- a_IniFile.GetValueSet("Generator", "Finishers", "WormNestCaves, BottomLava, LavaSprings, NetherClumpFoliage, NetherForts, PreSimulator");
+ a_IniFile.GetValueSet("Generator", "Finishers", "SoulsandRims, WormNestCaves, BottomLava, LavaSprings, NetherClumpFoliage, NetherForts, PreSimulator");
a_IniFile.GetValueSet("Generator", "BottomLavaHeight", "30");
break;
}
@@ -1807,7 +1805,7 @@ void cWorld::SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double
a_FlyAwaySpeed /= 100; // Pre-divide, so that we don't have to divide each time inside the loop
for (cItems::const_iterator itr = a_Pickups.begin(); itr != a_Pickups.end(); ++itr)
{
- if (!IsValidItem(itr->m_ItemType) || itr->m_ItemType == E_BLOCK_AIR)
+ if (!IsValidItem(itr->m_ItemType) || (itr->m_ItemType == E_BLOCK_AIR))
{
// Don't spawn pickup if item isn't even valid; should prevent client crashing too
continue;
@@ -1833,7 +1831,7 @@ void cWorld::SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double
{
for (cItems::const_iterator itr = a_Pickups.begin(); itr != a_Pickups.end(); ++itr)
{
- if (!IsValidItem(itr->m_ItemType) || itr->m_ItemType == E_BLOCK_AIR)
+ if (!IsValidItem(itr->m_ItemType) || (itr->m_ItemType == E_BLOCK_AIR))
{
continue;
}
@@ -2678,7 +2676,7 @@ bool cWorld::ForEachPlayer(cPlayerListCallback & a_Callback)
bool cWorld::DoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback)
{
- // Calls the callback for each player in the list
+ // Calls the callback for the specified player in the list
cCSLock Lock(m_CSPlayers);
for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
{
@@ -3128,6 +3126,11 @@ bool cWorld::HasEntity(int a_UniqueID)
}
// Check if the entity is in the chunkmap:
+ if (m_ChunkMap.get() == nullptr)
+ {
+ // Chunkmap has already been destroyed, there are no entities anymore.
+ return false;
+ }
return m_ChunkMap->HasEntity(a_UniqueID);
}