summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CONTRIBUTORS1
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/Generating/FinishGen.cpp6
-rw-r--r--src/Mobs/Creeper.cpp2
-rw-r--r--src/Mobs/Guardian.cpp3
-rw-r--r--src/Mobs/Path.cpp17
-rw-r--r--src/Mobs/Squid.cpp3
-rw-r--r--src/OSSupport/StackTrace.cpp9
-rw-r--r--src/SpawnPrepare.cpp105
-rw-r--r--src/SpawnPrepare.h47
-rw-r--r--src/StringUtils.h6
-rw-r--r--src/World.cpp138
12 files changed, 193 insertions, 146 deletions
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 4a6850a2f..3505d7155 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -12,6 +12,7 @@ jasperarmstrong
keyboard
Lapayo
Luksor
+linnemannr (Reid Linnemann)
M10360
marmot21
Masy98
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index a23e02789..5556ddc4d 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -62,6 +62,7 @@ SET (SRCS
Scoreboard.cpp
Server.cpp
SetChunkData.cpp
+ SpawnPrepare.cpp
Statistics.cpp
StringCompression.cpp
StringUtils.cpp
@@ -133,6 +134,7 @@ SET (HDRS
Server.h
SetChunkData.h
SettingsRepositoryInterface.h
+ SpawnPrepare.h
Statistics.h
StringCompression.h
StringUtils.h
diff --git a/src/Generating/FinishGen.cpp b/src/Generating/FinishGen.cpp
index 5540f80d4..656dc95db 100644
--- a/src/Generating/FinishGen.cpp
+++ b/src/Generating/FinishGen.cpp
@@ -1375,8 +1375,12 @@ eMonsterType cFinishGenPassiveMobs::GetRandomMob(cChunkDesc & a_ChunkDesc)
return mtInvalidType;
}
- size_t RandMob = static_cast<size_t>((m_Noise.IntNoise2DInt(chunkX - chunkZ + 2, chunkX + 5) / 7)) % ListOfSpawnables.size();
auto MobIter = ListOfSpawnables.begin();
+ using diff_type =
+ std::iterator_traits<decltype(MobIter)>::difference_type;
+ diff_type RandMob = static_cast<diff_type>
+ ((unsigned long)(m_Noise.IntNoise2DInt(chunkX - chunkZ + 2, chunkX + 5) / 7)
+ % ListOfSpawnables.size());
std::advance(MobIter, RandMob);
return *MobIter;
diff --git a/src/Mobs/Creeper.cpp b/src/Mobs/Creeper.cpp
index ef3245894..30bd41f13 100644
--- a/src/Mobs/Creeper.cpp
+++ b/src/Mobs/Creeper.cpp
@@ -27,7 +27,7 @@ void cCreeper::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
super::Tick(a_Dt, a_Chunk);
- if (!ReachedFinalDestination() && !m_BurnedWithFlintAndSteel)
+ if (!TargetIsInRange() && !m_BurnedWithFlintAndSteel)
{
m_ExplodingTimer = 0;
m_bIsBlowing = false;
diff --git a/src/Mobs/Guardian.cpp b/src/Mobs/Guardian.cpp
index cfe7861a6..1429e2b13 100644
--- a/src/Mobs/Guardian.cpp
+++ b/src/Mobs/Guardian.cpp
@@ -37,9 +37,10 @@ void cGuardian::GetDrops(cItems & a_Drops, cEntity * a_Killer)
void cGuardian::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
+ m_IsFollowingPath = false; // Disable Pathfinding until it's fixed. TODO
+
// We must first process current location, and only then tick, otherwise we risk processing a location in a chunk
// that is not where the entity currently resides (FS #411)
-
Vector3d Pos = GetPosition();
// TODO: Not a real behavior, but cool :D
diff --git a/src/Mobs/Path.cpp b/src/Mobs/Path.cpp
index 325e102b7..f6660907c 100644
--- a/src/Mobs/Path.cpp
+++ b/src/Mobs/Path.cpp
@@ -222,28 +222,35 @@ bool cPath::Step_Internal()
ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, 0, -1), CurrentCell, 10);
// Check diagonals on XY plane.
+ // x = -1: west, x = 1: east.
for (int x = -1; x <= 1; x += 2)
{
if (GetCell(CurrentCell->m_Location + Vector3i(x, 0, 0))->m_IsSolid) // If there's a solid our east / west.
{
- ProcessIfWalkable(CurrentCell->m_Location + Vector3i(x, 1, 0), CurrentCell, JUMP_G_COST); // Check east / west-up.
+ if (!GetCell(CurrentCell->m_Location + Vector3i(0, 1, 0))->m_IsSolid) // If there isn't a solid above.
+ {
+ ProcessIfWalkable(CurrentCell->m_Location + Vector3i(x, 1, 0), CurrentCell, JUMP_G_COST); // Check east-up / west-up.
+ }
}
else
{
- ProcessIfWalkable(CurrentCell->m_Location + Vector3i(x, -1, 0), CurrentCell, 14); // Else check east / west-down.
+ ProcessIfWalkable(CurrentCell->m_Location + Vector3i(x, -1, 0), CurrentCell, 14); // Else check east-down / west-down.
}
}
// Check diagonals on the YZ plane.
for (int z = -1; z <= 1; z += 2)
{
- if (GetCell(CurrentCell->m_Location + Vector3i(0, 0, z))->m_IsSolid) // If there's a solid our east / west.
+ if (GetCell(CurrentCell->m_Location + Vector3i(0, 0, z))->m_IsSolid) // If there's a solid our north / south.
{
- ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, 1, z), CurrentCell, JUMP_G_COST); // Check east / west-up.
+ if (!GetCell(CurrentCell->m_Location + Vector3i(0, 1, 0))->m_IsSolid) // If there isn't a solid above.
+ {
+ ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, 1, z), CurrentCell, JUMP_G_COST); // Check north-up / south-up.
+ }
}
else
{
- ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, -1, z), CurrentCell, 14); // Else check east / west-down.
+ ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, -1, z), CurrentCell, 14); // Else check north-down / south-down.
}
}
diff --git a/src/Mobs/Squid.cpp b/src/Mobs/Squid.cpp
index d148d65f3..30fbfa1ff 100644
--- a/src/Mobs/Squid.cpp
+++ b/src/Mobs/Squid.cpp
@@ -35,9 +35,10 @@ void cSquid::GetDrops(cItems & a_Drops, cEntity * a_Killer)
void cSquid::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
+ m_IsFollowingPath = false; // Disable Pathfinding until it's fixed. TODO
+
// We must first process current location, and only then tick, otherwise we risk processing a location in a chunk
// that is not where the entity currently resides (FS #411)
-
Vector3d Pos = GetPosition();
// TODO: Not a real behavior, but cool :D
diff --git a/src/OSSupport/StackTrace.cpp b/src/OSSupport/StackTrace.cpp
index 015a53ba0..1ec10f20e 100644
--- a/src/OSSupport/StackTrace.cpp
+++ b/src/OSSupport/StackTrace.cpp
@@ -12,6 +12,13 @@
#include <unistd.h>
#endif
+// FreeBSD uses size_t for the return type of backtrace()
+#if defined(__FreeBSD__) && (__FreeBSD__ >= 10)
+ #define btsize size_t
+#else
+ #define btsize int
+#endif
+
@@ -34,7 +41,7 @@ void PrintStackTrace(void)
// Use the backtrace() function to get and output the stackTrace:
// Code adapted from http://stackoverflow.com/questions/77005/how-to-generate-a-stacktrace-when-my-gcc-c-app-crashes
void * stackTrace[30];
- int numItems = backtrace(stackTrace, ARRAYCOUNT(stackTrace));
+ btsize numItems = backtrace(stackTrace, ARRAYCOUNT(stackTrace));
backtrace_symbols_fd(stackTrace, numItems, STDERR_FILENO);
#endif
}
diff --git a/src/SpawnPrepare.cpp b/src/SpawnPrepare.cpp
new file mode 100644
index 000000000..80d2c52a1
--- /dev/null
+++ b/src/SpawnPrepare.cpp
@@ -0,0 +1,105 @@
+
+#include "Globals.h"
+
+#include "SpawnPrepare.h"
+#include "World.h"
+
+
+
+
+
+
+
+cSpawnPrepare::cSpawnPrepare(cWorld & a_World, int a_SpawnChunkX, int a_SpawnChunkZ, int a_PrepareDistance, int a_FirstIdx):
+ m_World(a_World),
+ m_SpawnChunkX(a_SpawnChunkX),
+ m_SpawnChunkZ(a_SpawnChunkZ),
+ m_PrepareDistance(a_PrepareDistance),
+ m_NextIdx(a_FirstIdx),
+ m_MaxIdx(a_PrepareDistance * a_PrepareDistance),
+ m_NumPrepared(0),
+ m_LastReportTime(std::chrono::steady_clock::now()),
+ m_LastReportChunkCount(0)
+{
+}
+
+
+
+
+
+
+
+void cSpawnPrepare::PrepareChunks(cWorld & a_World, int a_SpawnChunkX, int a_SpawnChunkZ, int a_PrepareDistance)
+{
+
+ // Queue the initial chunks:
+ int MaxIdx = a_PrepareDistance * a_PrepareDistance;
+ int maxQueue = std::min(MaxIdx - 1, 100); // Number of chunks to queue at once
+ cSpawnPrepare prep(a_World, a_SpawnChunkX, a_SpawnChunkZ, a_PrepareDistance, maxQueue);
+ for (int i = 0; i < maxQueue; i++)
+ {
+ int chunkX, chunkZ;
+ prep.DecodeChunkCoords(i, chunkX, chunkZ);
+ a_World.PrepareChunk(chunkX, chunkZ, &prep);
+ } // for i
+
+ // Wait for the lighting thread to prepare everything. Event is set in the Call() callback:
+ prep.m_EvtFinished.Wait();
+}
+
+
+
+
+
+void cSpawnPrepare::DecodeChunkCoords(int a_Idx, int & a_ChunkX, int & a_ChunkZ)
+{
+ // A zigzag pattern from the top to bottom, each row alternating between forward-x and backward-x:
+ int z = a_Idx / m_PrepareDistance;
+ int x = a_Idx % m_PrepareDistance;
+ if ((z & 1) == 0)
+ {
+ // Reverse every second row:
+ x = m_PrepareDistance - 1 - x;
+ }
+ a_ChunkZ = m_SpawnChunkZ + z - m_PrepareDistance / 2;
+ a_ChunkX = m_SpawnChunkX + x - m_PrepareDistance / 2;
+}
+
+
+
+
+
+void cSpawnPrepare::Call(int a_ChunkX, int a_ChunkZ)
+{
+ // Check if this was the last chunk:
+ m_NumPrepared += 1;
+ 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:
+ if (m_NextIdx < m_MaxIdx)
+ {
+ int chunkX, chunkZ;
+ DecodeChunkCoords(m_NextIdx, chunkX, chunkZ);
+ m_World.GetLightingThread().QueueChunk(chunkX, chunkZ, this);
+ m_NextIdx += 1;
+ }
+
+ // Report progress every 1 second:
+ 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) / std::chrono::duration_cast<std::chrono::milliseconds>(Now - m_LastReportTime).count();
+ LOG("Preparing spawn (%s): %.02f%% (%d/%d; %.02f chunks / sec)",
+ m_World.GetName().c_str(), PercentDone, m_NumPrepared, m_MaxIdx, ChunkSpeed
+ );
+ m_LastReportTime = Now;
+ m_LastReportChunkCount = m_NumPrepared;
+ }
+}
+
diff --git a/src/SpawnPrepare.h b/src/SpawnPrepare.h
new file mode 100644
index 000000000..bd5c0e0c6
--- /dev/null
+++ b/src/SpawnPrepare.h
@@ -0,0 +1,47 @@
+
+#pragma once
+
+class cWorld;
+
+
+
+/** Generates and lights the spawn area of the world. Runs as a separate thread. */
+class cSpawnPrepare:
+ public cChunkCoordCallback
+{
+
+public:
+ static void PrepareChunks(cWorld & a_World, int a_SpawnChunkX, int a_SpawnChunkZ, int a_PrepareDistance);
+
+protected:
+ cWorld & m_World;
+ int m_SpawnChunkX;
+ int m_SpawnChunkZ;
+ int m_PrepareDistance;
+
+ /** The index of the next chunk to be queued in the lighting thread. */
+ int m_NextIdx;
+
+ /** The maximum index of the prepared chunks. Queueing stops when m_NextIdx reaches this number. */
+ int m_MaxIdx;
+
+ /** Total number of chunks already finished preparing. Preparation finishes when this number reaches m_MaxIdx. */
+ int m_NumPrepared;
+
+ /** Event used to signal that the preparation is finished. */
+ cEvent m_EvtFinished;
+
+ /** The timestamp of the last progress report emitted. */
+ std::chrono::steady_clock::time_point m_LastReportTime;
+
+ /** Number of chunks prepared when the last progress report was emitted. */
+ int m_LastReportChunkCount;
+
+ cSpawnPrepare(cWorld & a_World, int a_SpawnChunkX, int a_SpawnChunkZ, int a_PrepareDistance, int a_FirstIdx);
+
+ virtual void Call(int a_ChunkX, int a_ChunkZ) override;
+
+ /** Decodes the index into chunk coords. Provides the specific chunk ordering. */
+ void DecodeChunkCoords(int a_Idx, int & a_ChunkX, int & a_ChunkZ);
+};
+
diff --git a/src/StringUtils.h b/src/StringUtils.h
index 8f67d8031..62767d007 100644
--- a/src/StringUtils.h
+++ b/src/StringUtils.h
@@ -168,6 +168,12 @@ bool StringToInteger(const AString & a_str, T & a_Num)
}
else
{
+ // Unsigned result cannot be signed!
+ if (!std::numeric_limits<T>::is_signed)
+ {
+ return false;
+ }
+
for (size_t size = a_str.size(); i < size; i++)
{
if ((a_str[i] < '0') || (a_str[i] > '9'))
diff --git a/src/World.cpp b/src/World.cpp
index 27bb3bdbd..aabbd7276 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -58,6 +58,7 @@
#endif
#include "Broadcaster.h"
+#include "SpawnPrepare.h"
@@ -72,140 +73,6 @@ const int TIME_SPAWN_DIVISOR = 148;
////////////////////////////////////////////////////////////////////////////////
-// cSpawnPrepare:
-
-/** Generates and lights the spawn area of the world. Runs as a separate thread. */
-class cSpawnPrepare:
- public cIsThread,
- public cChunkCoordCallback
-{
- typedef cIsThread super;
-
-public:
- cSpawnPrepare(cWorld & a_World, int a_SpawnChunkX, int a_SpawnChunkZ, int a_PrepareDistance):
- super("SpawnPrepare"),
- m_World(a_World),
- m_SpawnChunkX(a_SpawnChunkX),
- m_SpawnChunkZ(a_SpawnChunkZ),
- m_PrepareDistance(a_PrepareDistance),
- m_MaxIdx(a_PrepareDistance * a_PrepareDistance),
- m_NumPrepared(0),
- m_LastReportChunkCount(0)
- {
- // Start the thread:
- Start();
-
- // Wait for start confirmation, so that the thread can be waited-upon after the constructor returns:
- m_EvtStarted.Wait();
- }
-
-
- // cIsThread override:
- virtual void Execute(void) override
- {
- // Confirm thread start:
- m_EvtStarted.Set();
-
- // Queue the initial chunks:
- 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 = std::chrono::steady_clock::now();
- for (int i = 0; i < maxQueue; i++)
- {
- int chunkX, chunkZ;
- DecodeChunkCoords(i, chunkX, chunkZ);
- m_World.PrepareChunk(chunkX, chunkZ, this);
- } // for i
-
- // Wait for the lighting thread to prepare everything. Event is set in the Call() callback:
- m_EvtFinished.Wait();
- }
-
-protected:
- cWorld & m_World;
- int m_SpawnChunkX;
- int m_SpawnChunkZ;
- int m_PrepareDistance;
-
- /** The index of the next chunk to be queued in the lighting thread. */
- int m_NextIdx;
-
- /** The maximum index of the prepared chunks. Queueing stops when m_NextIdx reaches this number. */
- int m_MaxIdx;
-
- /** Total number of chunks already finished preparing. Preparation finishes when this number reaches m_MaxIdx. */
- int m_NumPrepared;
-
- /** Event used to signal that the thread has started. */
- cEvent m_EvtStarted;
-
- /** Event used to signal that the preparation is finished. */
- cEvent m_EvtFinished;
-
- /** The timestamp of the last progress report emitted. */
- 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) override
- {
- // Check if this was the last chunk:
- m_NumPrepared += 1;
- 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:
- if (m_NextIdx < m_MaxIdx)
- {
- int chunkX, chunkZ;
- DecodeChunkCoords(m_NextIdx, chunkX, chunkZ);
- m_World.GetLightingThread().QueueChunk(chunkX, chunkZ, this);
- m_NextIdx += 1;
- }
-
- // Report progress every 1 second:
- 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) / std::chrono::duration_cast<std::chrono::milliseconds>(Now - m_LastReportTime).count();
- LOG("Preparing spawn (%s): %.02f%% (%d/%d; %.02f chunks / sec)",
- m_World.GetName().c_str(), PercentDone, m_NumPrepared, m_MaxIdx, ChunkSpeed
- );
- m_LastReportTime = Now;
- m_LastReportChunkCount = m_NumPrepared;
- }
- }
-
-
- /** Decodes the index into chunk coords. Provides the specific chunk ordering. */
- void DecodeChunkCoords(int a_Idx, int & a_ChunkX, int & a_ChunkZ)
- {
- // A zigzag pattern from the top to bottom, each row alternating between forward-x and backward-x:
- int z = a_Idx / m_PrepareDistance;
- int x = a_Idx % m_PrepareDistance;
- if ((z & 1) == 0)
- {
- // Reverse every second row:
- x = m_PrepareDistance - 1 - x;
- }
- a_ChunkZ = m_SpawnChunkZ + z - m_PrepareDistance / 2;
- a_ChunkX = m_SpawnChunkX + x - m_PrepareDistance / 2;
- }
-};
-
-
-
-
-
-////////////////////////////////////////////////////////////////////////////////
// cWorld::cLock:
cWorld::cLock::cLock(cWorld & a_World) :
@@ -470,8 +337,7 @@ void cWorld::InitializeSpawn(void)
int ViewDist = IniFile.GetValueSetI("SpawnPosition", "PregenerateDistance", DefaultViewDist);
IniFile.WriteFile(m_IniFileName);
- cSpawnPrepare prep(*this, ChunkX, ChunkZ, ViewDist);
- prep.Wait();
+ cSpawnPrepare::PrepareChunks(*this, ChunkX, ChunkZ, ViewDist);
#ifdef TEST_LINEBLOCKTRACER
// DEBUG: Test out the cLineBlockTracer class by tracing a few lines: