diff options
Diffstat (limited to 'src')
51 files changed, 604 insertions, 1438 deletions
diff --git a/src/ByteBuffer.cpp b/src/ByteBuffer.cpp index 012105ca1..080176dcd 100644 --- a/src/ByteBuffer.cpp +++ b/src/ByteBuffer.cpp @@ -111,26 +111,36 @@ public: #ifdef _DEBUG -/// Simple RAII class that uses one internal unsigned long for checking if two threads are using an object simultanously -class cSingleThreadAccessChecker -{ -public: - cSingleThreadAccessChecker(unsigned long * a_ThreadID) : - m_ThreadID(a_ThreadID) + /** Simple RAII class that is used for checking that no two threads are using an object simultanously. + It requires the monitored object to provide the storage for a thread ID. + It uses that storage to check if the thread ID of consecutive calls is the same all the time. */ + class cSingleThreadAccessChecker { - ASSERT((*a_ThreadID == 0) || (*a_ThreadID == cIsThread::GetCurrentID())); - } - - ~cSingleThreadAccessChecker() - { - *m_ThreadID = 0; - } - -protected: - unsigned long * m_ThreadID; -} ; + public: + cSingleThreadAccessChecker(std::thread::id * a_ThreadID) : + m_ThreadID(a_ThreadID) + { + ASSERT( + (*a_ThreadID == std::this_thread::get_id()) || // Either the object is used by current thread... + (*a_ThreadID == std::thread::id()) // ... or by no thread at all + ); + + // Mark as being used by this thread: + *m_ThreadID = std::this_thread::get_id(); + } + + ~cSingleThreadAccessChecker() + { + // Mark as not being used by any thread: + *m_ThreadID = std::thread::id(); + } + + protected: + /** Points to the storage used for ID of the thread using the object. */ + std::thread::id * m_ThreadID; + }; -#define CHECK_THREAD cSingleThreadAccessChecker Checker(const_cast<unsigned long *>(&m_ThreadID)) + #define CHECK_THREAD cSingleThreadAccessChecker Checker(&m_ThreadID); #else #define CHECK_THREAD @@ -146,9 +156,6 @@ protected: cByteBuffer::cByteBuffer(size_t a_BufferSize) : m_Buffer(new char[a_BufferSize + 1]), m_BufferSize(a_BufferSize + 1), - #ifdef _DEBUG - m_ThreadID(0), - #endif // _DEBUG m_DataStart(0), m_WritePos(0), m_ReadPos(0) @@ -174,7 +181,7 @@ cByteBuffer::~cByteBuffer() bool cByteBuffer::Write(const void * a_Bytes, size_t a_Count) { - CHECK_THREAD; + CHECK_THREAD CheckValid(); // Store the current free space for a check after writing: @@ -221,7 +228,7 @@ bool cByteBuffer::Write(const void * a_Bytes, size_t a_Count) size_t cByteBuffer::GetFreeSpace(void) const { - CHECK_THREAD; + CHECK_THREAD CheckValid(); if (m_WritePos >= m_DataStart) { @@ -243,7 +250,7 @@ size_t cByteBuffer::GetFreeSpace(void) const /// Returns the number of bytes that are currently in the ringbuffer. Note GetReadableBytes() size_t cByteBuffer::GetUsedSpace(void) const { - CHECK_THREAD; + CHECK_THREAD CheckValid(); ASSERT(m_BufferSize >= GetFreeSpace()); ASSERT((m_BufferSize - GetFreeSpace()) >= 1); @@ -257,7 +264,7 @@ size_t cByteBuffer::GetUsedSpace(void) const /// Returns the number of bytes that are currently available for reading (may be less than UsedSpace due to some data having been read already) size_t cByteBuffer::GetReadableSpace(void) const { - CHECK_THREAD; + CHECK_THREAD CheckValid(); if (m_ReadPos > m_WritePos) { @@ -276,7 +283,7 @@ size_t cByteBuffer::GetReadableSpace(void) const bool cByteBuffer::CanReadBytes(size_t a_Count) const { - CHECK_THREAD; + CHECK_THREAD CheckValid(); return (a_Count <= GetReadableSpace()); } @@ -287,7 +294,7 @@ bool cByteBuffer::CanReadBytes(size_t a_Count) const bool cByteBuffer::CanWriteBytes(size_t a_Count) const { - CHECK_THREAD; + CHECK_THREAD CheckValid(); return (a_Count <= GetFreeSpace()); } @@ -298,7 +305,7 @@ bool cByteBuffer::CanWriteBytes(size_t a_Count) const bool cByteBuffer::ReadChar(char & a_Value) { - CHECK_THREAD; + CHECK_THREAD CheckValid(); NEEDBYTES(1); ReadBuf(&a_Value, 1); @@ -311,7 +318,7 @@ bool cByteBuffer::ReadChar(char & a_Value) bool cByteBuffer::ReadByte(unsigned char & a_Value) { - CHECK_THREAD; + CHECK_THREAD CheckValid(); NEEDBYTES(1); ReadBuf(&a_Value, 1); @@ -324,7 +331,7 @@ bool cByteBuffer::ReadByte(unsigned char & a_Value) bool cByteBuffer::ReadBEShort(short & a_Value) { - CHECK_THREAD; + CHECK_THREAD CheckValid(); NEEDBYTES(2); ReadBuf(&a_Value, 2); @@ -338,7 +345,7 @@ bool cByteBuffer::ReadBEShort(short & a_Value) bool cByteBuffer::ReadBEInt(int & a_Value) { - CHECK_THREAD; + CHECK_THREAD CheckValid(); NEEDBYTES(4); ReadBuf(&a_Value, 4); @@ -352,7 +359,7 @@ bool cByteBuffer::ReadBEInt(int & a_Value) bool cByteBuffer::ReadBEInt64(Int64 & a_Value) { - CHECK_THREAD; + CHECK_THREAD CheckValid(); NEEDBYTES(8); ReadBuf(&a_Value, 8); @@ -366,7 +373,7 @@ bool cByteBuffer::ReadBEInt64(Int64 & a_Value) bool cByteBuffer::ReadBEFloat(float & a_Value) { - CHECK_THREAD; + CHECK_THREAD CheckValid(); NEEDBYTES(4); ReadBuf(&a_Value, 4); @@ -380,7 +387,7 @@ bool cByteBuffer::ReadBEFloat(float & a_Value) bool cByteBuffer::ReadBEDouble(double & a_Value) { - CHECK_THREAD; + CHECK_THREAD CheckValid(); NEEDBYTES(8); ReadBuf(&a_Value, 8); @@ -394,7 +401,7 @@ bool cByteBuffer::ReadBEDouble(double & a_Value) bool cByteBuffer::ReadBool(bool & a_Value) { - CHECK_THREAD; + CHECK_THREAD CheckValid(); NEEDBYTES(1); char Value = 0; @@ -409,7 +416,7 @@ bool cByteBuffer::ReadBool(bool & a_Value) bool cByteBuffer::ReadBEUTF16String16(AString & a_Value) { - CHECK_THREAD; + CHECK_THREAD CheckValid(); short Length; if (!ReadBEShort(Length)) @@ -430,7 +437,7 @@ bool cByteBuffer::ReadBEUTF16String16(AString & a_Value) bool cByteBuffer::ReadVarInt(UInt32 & a_Value) { - CHECK_THREAD; + CHECK_THREAD CheckValid(); UInt32 Value = 0; int Shift = 0; @@ -452,7 +459,7 @@ bool cByteBuffer::ReadVarInt(UInt32 & a_Value) bool cByteBuffer::ReadVarUTF8String(AString & a_Value) { - CHECK_THREAD; + CHECK_THREAD CheckValid(); UInt32 Size = 0; if (!ReadVarInt(Size)) @@ -472,7 +479,7 @@ bool cByteBuffer::ReadVarUTF8String(AString & a_Value) bool cByteBuffer::ReadLEInt(int & a_Value) { - CHECK_THREAD; + CHECK_THREAD CheckValid(); NEEDBYTES(4); ReadBuf(&a_Value, 4); @@ -491,6 +498,7 @@ bool cByteBuffer::ReadLEInt(int & a_Value) bool cByteBuffer::ReadPosition(int & a_BlockX, int & a_BlockY, int & a_BlockZ) { + CHECK_THREAD Int64 Value; if (!ReadBEInt64(Value)) { @@ -515,7 +523,7 @@ bool cByteBuffer::ReadPosition(int & a_BlockX, int & a_BlockY, int & a_BlockZ) bool cByteBuffer::WriteChar(char a_Value) { - CHECK_THREAD; + CHECK_THREAD CheckValid(); PUTBYTES(1); return WriteBuf(&a_Value, 1); @@ -527,7 +535,7 @@ bool cByteBuffer::WriteChar(char a_Value) bool cByteBuffer::WriteByte(unsigned char a_Value) { - CHECK_THREAD; + CHECK_THREAD CheckValid(); PUTBYTES(1); return WriteBuf(&a_Value, 1); @@ -539,7 +547,7 @@ bool cByteBuffer::WriteByte(unsigned char a_Value) bool cByteBuffer::WriteBEShort(short a_Value) { - CHECK_THREAD; + CHECK_THREAD CheckValid(); PUTBYTES(2); u_short Converted = htons((u_short)a_Value); @@ -552,7 +560,7 @@ bool cByteBuffer::WriteBEShort(short a_Value) bool cByteBuffer::WriteBEUShort(unsigned short a_Value) { - CHECK_THREAD; + CHECK_THREAD CheckValid(); PUTBYTES(2); u_short Converted = htons((u_short)a_Value); @@ -565,7 +573,7 @@ bool cByteBuffer::WriteBEUShort(unsigned short a_Value) bool cByteBuffer::WriteBEInt(int a_Value) { - CHECK_THREAD; + CHECK_THREAD CheckValid(); PUTBYTES(4); UInt32 Converted = HostToNetwork4(&a_Value); @@ -578,7 +586,7 @@ bool cByteBuffer::WriteBEInt(int a_Value) bool cByteBuffer::WriteBEInt64(Int64 a_Value) { - CHECK_THREAD; + CHECK_THREAD CheckValid(); PUTBYTES(8); UInt64 Converted = HostToNetwork8(&a_Value); @@ -591,7 +599,7 @@ bool cByteBuffer::WriteBEInt64(Int64 a_Value) bool cByteBuffer::WriteBEFloat(float a_Value) { - CHECK_THREAD; + CHECK_THREAD CheckValid(); PUTBYTES(4); UInt32 Converted = HostToNetwork4(&a_Value); @@ -604,7 +612,7 @@ bool cByteBuffer::WriteBEFloat(float a_Value) bool cByteBuffer::WriteBEDouble(double a_Value) { - CHECK_THREAD; + CHECK_THREAD CheckValid(); PUTBYTES(8); UInt64 Converted = HostToNetwork8(&a_Value); @@ -618,7 +626,7 @@ bool cByteBuffer::WriteBEDouble(double a_Value) bool cByteBuffer::WriteBool(bool a_Value) { - CHECK_THREAD; + CHECK_THREAD CheckValid(); return WriteChar(a_Value ? 1 : 0); } @@ -629,7 +637,7 @@ bool cByteBuffer::WriteBool(bool a_Value) bool cByteBuffer::WriteVarInt(UInt32 a_Value) { - CHECK_THREAD; + CHECK_THREAD CheckValid(); // A 32-bit integer can be encoded by at most 5 bytes: @@ -650,7 +658,7 @@ bool cByteBuffer::WriteVarInt(UInt32 a_Value) bool cByteBuffer::WriteVarUTF8String(const AString & a_Value) { - CHECK_THREAD; + CHECK_THREAD CheckValid(); PUTBYTES(a_Value.size() + 1); // This is a lower-bound on the bytes that will be actually written. Fail early. bool res = WriteVarInt((UInt32)(a_Value.size())); @@ -667,7 +675,7 @@ bool cByteBuffer::WriteVarUTF8String(const AString & a_Value) bool cByteBuffer::WriteLEInt(int a_Value) { - CHECK_THREAD; + CHECK_THREAD CheckValid(); #ifdef IS_LITTLE_ENDIAN return WriteBuf((const char *)&a_Value, 4); @@ -683,6 +691,7 @@ bool cByteBuffer::WriteLEInt(int a_Value) bool cByteBuffer::WritePosition(int a_BlockX, int a_BlockY, int a_BlockZ) { + CHECK_THREAD return WriteBEInt64(((Int64)a_BlockX & 0x3FFFFFF) << 38 | ((Int64)a_BlockY & 0xFFF) << 26 | ((Int64)a_BlockZ & 0x3FFFFFF)); } @@ -692,7 +701,7 @@ bool cByteBuffer::WritePosition(int a_BlockX, int a_BlockY, int a_BlockZ) bool cByteBuffer::ReadBuf(void * a_Buffer, size_t a_Count) { - CHECK_THREAD; + CHECK_THREAD CheckValid(); NEEDBYTES(a_Count); char * Dst = (char *)a_Buffer; // So that we can do byte math @@ -725,7 +734,7 @@ bool cByteBuffer::ReadBuf(void * a_Buffer, size_t a_Count) bool cByteBuffer::WriteBuf(const void * a_Buffer, size_t a_Count) { - CHECK_THREAD; + CHECK_THREAD CheckValid(); PUTBYTES(a_Count); char * Src = (char *)a_Buffer; // So that we can do byte math @@ -755,7 +764,7 @@ bool cByteBuffer::WriteBuf(const void * a_Buffer, size_t a_Count) bool cByteBuffer::ReadString(AString & a_String, size_t a_Count) { - CHECK_THREAD; + CHECK_THREAD CheckValid(); NEEDBYTES(a_Count); a_String.clear(); @@ -790,7 +799,7 @@ bool cByteBuffer::ReadString(AString & a_String, size_t a_Count) bool cByteBuffer::ReadUTF16String(AString & a_String, size_t a_NumChars) { // Reads 2 * a_NumChars bytes and interprets it as a UTF16 string, converting it into UTF8 string a_String - CHECK_THREAD; + CHECK_THREAD CheckValid(); AString RawData; if (!ReadString(RawData, a_NumChars * 2)) @@ -807,7 +816,7 @@ bool cByteBuffer::ReadUTF16String(AString & a_String, size_t a_NumChars) bool cByteBuffer::SkipRead(size_t a_Count) { - CHECK_THREAD; + CHECK_THREAD CheckValid(); if (!CanReadBytes(a_Count)) { @@ -823,7 +832,7 @@ bool cByteBuffer::SkipRead(size_t a_Count) void cByteBuffer::ReadAll(AString & a_Data) { - CHECK_THREAD; + CHECK_THREAD CheckValid(); ReadString(a_Data, GetReadableSpace()); } @@ -834,6 +843,7 @@ void cByteBuffer::ReadAll(AString & a_Data) bool cByteBuffer::ReadToByteBuffer(cByteBuffer & a_Dst, size_t a_NumBytes) { + CHECK_THREAD if (!a_Dst.CanWriteBytes(a_NumBytes) || !CanReadBytes(a_NumBytes)) { // There's not enough source bytes or space in the dest BB @@ -858,7 +868,7 @@ bool cByteBuffer::ReadToByteBuffer(cByteBuffer & a_Dst, size_t a_NumBytes) void cByteBuffer::CommitRead(void) { - CHECK_THREAD; + CHECK_THREAD CheckValid(); m_DataStart = m_ReadPos; } @@ -869,7 +879,7 @@ void cByteBuffer::CommitRead(void) void cByteBuffer::ResetRead(void) { - CHECK_THREAD; + CHECK_THREAD CheckValid(); m_ReadPos = m_DataStart; } @@ -882,7 +892,7 @@ void cByteBuffer::ReadAgain(AString & a_Out) { // Return the data between m_DataStart and m_ReadPos (the data that has been read but not committed) // Used by ProtoProxy to repeat communication twice, once for parsing and the other time for the remote party - CHECK_THREAD; + CHECK_THREAD CheckValid(); size_t DataStart = m_DataStart; if (m_ReadPos < m_DataStart) @@ -902,7 +912,7 @@ void cByteBuffer::ReadAgain(AString & a_Out) void cByteBuffer::AdvanceReadPos(size_t a_Count) { - CHECK_THREAD; + CHECK_THREAD CheckValid(); m_ReadPos += a_Count; if (m_ReadPos >= m_BufferSize) diff --git a/src/ByteBuffer.h b/src/ByteBuffer.h index 70de419f0..2a316fa32 100644 --- a/src/ByteBuffer.h +++ b/src/ByteBuffer.h @@ -130,13 +130,15 @@ protected: char * m_Buffer; size_t m_BufferSize; // Total size of the ringbuffer - #ifdef _DEBUG - volatile unsigned long m_ThreadID; // Thread that is currently accessing the object, checked via cSingleThreadAccessChecker - #endif // _DEBUG - size_t m_DataStart; // Where the data starts in the ringbuffer size_t m_WritePos; // Where the data ends in the ringbuffer size_t m_ReadPos; // Where the next read will start in the ringbuffer + + #ifdef _DEBUG + /** The ID of the thread currently accessing the object. + Used for checking that only one thread accesses the object at a time, via cSingleThreadAccessChecker. */ + mutable std::thread::id m_ThreadID; + #endif /** Advances the m_ReadPos by a_Count bytes */ void AdvanceReadPos(size_t a_Count); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d6218ff42..997326cc7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -113,7 +113,6 @@ SET (HDRS Map.h MapManager.h Matrix4.h - MersenneTwister.h MobCensus.h MobFamilyCollecter.h MobProximityCounter.h diff --git a/src/CheckBasicStyle.lua b/src/CheckBasicStyle.lua index 7914aedfd..0c7b05d6d 100644 --- a/src/CheckBasicStyle.lua +++ b/src/CheckBasicStyle.lua @@ -135,11 +135,11 @@ local g_ViolationPatterns = -- Space after keywords: {"[^_]if%(", "Needs a space after \"if\""}, - {"for%(", "Needs a space after \"for\""}, - {"while%(", "Needs a space after \"while\""}, - {"switch%(", "Needs a space after \"switch\""}, - {"catch%(", "Needs a space after \"catch\""}, - {"template<", "Needs a space after \"template\""}, + {"%sfor%(", "Needs a space after \"for\""}, + {"%swhile%(", "Needs a space after \"while\""}, + {"%sswitch%(", "Needs a space after \"switch\""}, + {"%scatch%(", "Needs a space after \"catch\""}, + {"%stemplate<", "Needs a space after \"template\""}, -- No space after keyword's parenthesis: {"[^%a#]if %( ", "Remove the space after \"(\""}, diff --git a/src/Chunk.cpp b/src/Chunk.cpp index d271b4cb4..017ceda26 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -28,7 +28,6 @@ #include "Item.h" #include "Noise/Noise.h" #include "Root.h" -#include "MersenneTwister.h" #include "Entities/Player.h" #include "BlockArea.h" #include "Bindings/PluginManager.h" diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 366f20170..cc83bcab3 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -16,7 +16,6 @@ #include "Mobs/Monster.h" #include "ChatColor.h" #include "OSSupport/Socket.h" -#include "OSSupport/Timer.h" #include "Items/ItemHandler.h" #include "Blocks/BlockHandler.h" #include "Blocks/BlockSlab.h" @@ -25,8 +24,6 @@ #include "Root.h" #include "Protocol/Authenticator.h" -#include "MersenneTwister.h" - #include "Protocol/ProtocolRecognizer.h" #include "CompositeChat.h" #include "Items/ItemSword.h" @@ -41,18 +38,13 @@ /** Maximum number of block change interactions a player can perform per tick - exceeding this causes a kick */ #define MAX_BLOCK_CHANGE_INTERACTIONS 20 +/** The interval for sending pings to clients. +Vanilla sends one ping every 1 second. */ +static const std::chrono::milliseconds PING_TIME_MS = std::chrono::milliseconds(1000); -#define RECI_RAND_MAX (1.f/RAND_MAX) -inline int fRadRand(MTRand & r1, int a_BlockCoord) -{ - return a_BlockCoord * 32 + (int)(16 * ((float)r1.rand() * RECI_RAND_MAX) * 16 - 8); -} - - - int cClientHandle::s_ClientCount = 0; @@ -76,8 +68,6 @@ cClientHandle::cClientHandle(const cSocket * a_Socket, int a_ViewDistance) : m_TimeSinceLastPacket(0), m_Ping(1000), m_PingID(1), - m_PingStartTime(0), - m_LastPingTime(1000), m_BlockDigAnimStage(-1), m_BlockDigAnimSpeed(0), m_BlockDigAnimX(0), @@ -101,9 +91,7 @@ cClientHandle::cClientHandle(const cSocket * a_Socket, int a_ViewDistance) : s_ClientCount++; // Not protected by CS because clients are always constructed from the same thread m_UniqueID = s_ClientCount; - - cTimer t1; - m_LastPingTime = t1.GetNowTime(); + m_PingStartTime = std::chrono::steady_clock::now(); LOGD("New ClientHandle created at %p", this); } @@ -401,8 +389,7 @@ void cClientHandle::Authenticate(const AString & a_Name, const AString & a_UUID, // Delay the first ping until the client "settles down" // This should fix #889, "BadCast exception, cannot convert bit to fm" error in client - cTimer t1; - m_LastPingTime = t1.GetNowTime() + 3000; // Send the first KeepAlive packet in 3 seconds + m_PingStartTime = std::chrono::steady_clock::now() + std::chrono::seconds(3); // Send the first KeepAlive packet in 3 seconds cRoot::Get()->GetPluginManager()->CallHookPlayerSpawned(*m_Player); } @@ -1783,9 +1770,45 @@ void cClientHandle::HandleKeepAlive(int a_KeepAliveID) { if (a_KeepAliveID == m_PingID) { - cTimer t1; - m_Ping = (short)((t1.GetNowTime() - m_PingStartTime) / 2); + m_Ping = std::chrono::steady_clock::now() - m_PingStartTime; + } +} + + + + + +bool cClientHandle::CheckMultiLogin(const AString & a_Username) +{ + // If the multilogin is allowed, skip this check entirely: + if ((cRoot::Get()->GetServer()->DoesAllowMultiLogin())) + { + return true; + } + + // Check if the player is waiting to be transferred to the World. + if (cRoot::Get()->GetServer()->IsPlayerInQueue(a_Username)) + { + Kick("A player of the username is already logged in"); + return false; + } + + class cCallback : + public cPlayerListCallback + { + virtual bool Item(cPlayer * a_Player) override + { + return true; + } + } Callback; + + // Check if the player is in any World. + if (cRoot::Get()->DoWithPlayer(a_Username, Callback)) + { + Kick("A player of the username is already logged in"); + return false; } + return true; } @@ -1802,7 +1825,8 @@ bool cClientHandle::HandleHandshake(const AString & a_Username) return false; } } - return true; + + return CheckMultiLogin(a_Username); } @@ -2009,13 +2033,11 @@ void cClientHandle::Tick(float a_Dt) // Send a ping packet: if (m_State == csPlaying) { - cTimer t1; - if ((m_LastPingTime + cClientHandle::PING_TIME_MS <= t1.GetNowTime())) + if ((m_PingStartTime + PING_TIME_MS <= std::chrono::steady_clock::now())) { m_PingID++; - m_PingStartTime = t1.GetNowTime(); + m_PingStartTime = std::chrono::steady_clock::now(); m_Protocol->SendKeepAlive(m_PingID); - m_LastPingTime = m_PingStartTime; } } diff --git a/src/ClientHandle.h b/src/ClientHandle.h index f195b6be7..0e588d839 100644 --- a/src/ClientHandle.h +++ b/src/ClientHandle.h @@ -215,7 +215,7 @@ public: const AString & GetUsername(void) const; void SetUsername( const AString & a_Username); - inline short GetPing(void) const { return m_Ping; } + inline short GetPing(void) const { return static_cast<short>(std::chrono::duration_cast<std::chrono::milliseconds>(m_Ping).count()); } /** Sets the maximal view distance. */ void SetViewDistance(int a_ViewDistance); @@ -280,6 +280,10 @@ public: void HandleEntityLeaveBed (int a_EntityID); void HandleEntitySprinting (int a_EntityID, bool a_IsSprinting); + /** Kicks the current player if the same username is already logged in. + Returns false if a player has been kicked, true otherwise. */ + bool CheckMultiLogin(const AString & a_Username); + /** Called when the protocol handshake has been received (for protocol versions that support it; otherwise the first instant when a username is received). Returns true if the player is to be let in, false if they were disconnected @@ -378,12 +382,15 @@ private: /** Seconds since the last packet data was received (updated in Tick(), reset in DataReceived()) */ float m_TimeSinceLastPacket; - short m_Ping; - int m_PingID; - long long m_PingStartTime; - long long m_LastPingTime; - static const unsigned short PING_TIME_MS = 1000; // Vanilla sends 1 per 20 ticks (1 second or every 1000 ms) - + /** Duration of the last completed client ping. */ + std::chrono::steady_clock::duration m_Ping; + + /** ID of the last ping request sent to the client. */ + int m_PingID; + + /** Time of the last ping request sent to the client. */ + std::chrono::steady_clock::time_point m_PingStartTime; + // Values required for block dig animation int m_BlockDigAnimStage; // Current stage of the animation; -1 if not digging int m_BlockDigAnimSpeed; // Current speed of the animation (units ???) diff --git a/src/DeadlockDetect.cpp b/src/DeadlockDetect.cpp index 7f703416c..3bb897221 100644 --- a/src/DeadlockDetect.cpp +++ b/src/DeadlockDetect.cpp @@ -13,7 +13,7 @@ -/// Number of milliseconds per cycle +/** Number of milliseconds per cycle */ const int CYCLE_MILLISECONDS = 100; @@ -87,7 +87,7 @@ void cDeadlockDetect::Execute(void) } Checker(this); cRoot::Get()->ForEachWorld(Checker); - cSleep::MilliSleep(CYCLE_MILLISECONDS); + std::this_thread::sleep_for(std::chrono::milliseconds(CYCLE_MILLISECONDS)); } // while (should run) } @@ -119,7 +119,7 @@ void cDeadlockDetect::CheckWorldAge(const AString & a_WorldName, Int64 a_Age) if (WorldAge.m_Age == a_Age) { WorldAge.m_NumCyclesSame += 1; - if (WorldAge.m_NumCyclesSame > (1000 * m_IntervalSec) / CYCLE_MILLISECONDS) + if (WorldAge.m_NumCyclesSame > (m_IntervalSec * 1000) / CYCLE_MILLISECONDS) { DeadlockDetected(); } diff --git a/src/DeadlockDetect.h b/src/DeadlockDetect.h index 6aa98acbb..57027e923 100644 --- a/src/DeadlockDetect.h +++ b/src/DeadlockDetect.h @@ -28,7 +28,7 @@ class cDeadlockDetect : public: cDeadlockDetect(void); - /// Starts the detection. Hides cIsThread's Start, because we need some initialization + /** Starts the detection. Hides cIsThread's Start, because we need some initialization */ bool Start(int a_IntervalSec); protected: diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index bafd06277..8d2eb1e5f 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -11,7 +11,6 @@ #include "../BlockEntities/BlockEntity.h" #include "../BlockEntities/EnderChestEntity.h" #include "../Root.h" -#include "../OSSupport/Timer.h" #include "../Chunk.h" #include "../Items/ItemHandler.h" #include "../Vector3.h" @@ -27,7 +26,7 @@ #define PLAYER_INVENTORY_SAVE_INTERVAL 6000 // 1000 = once per second -#define PLAYER_LIST_TIME_MS 1000 +#define PLAYER_LIST_TIME_MS std::chrono::milliseconds(1000) @@ -91,9 +90,7 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName) : SetMaxHealth(MAX_HEALTH); m_Health = MAX_HEALTH; - cTimer t1; - m_LastPlayerListTime = t1.GetNowTime(); - + m_LastPlayerListTime = std::chrono::steady_clock::now(); m_PlayerName = a_PlayerName; cWorld * World = nullptr; @@ -268,11 +265,10 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk) m_Inventory.UpdateItems(); // Send Player List (Once per m_LastPlayerListTime/1000 ms) - cTimer t1; - if (m_LastPlayerListTime + PLAYER_LIST_TIME_MS <= t1.GetNowTime()) + if (m_LastPlayerListTime + PLAYER_LIST_TIME_MS <= std::chrono::steady_clock::now()) { m_World->BroadcastPlayerListUpdatePing(*this); - m_LastPlayerListTime = t1.GetNowTime(); + m_LastPlayerListTime = std::chrono::steady_clock::now(); } if (IsFlying()) @@ -363,7 +359,7 @@ float cPlayer::GetXpPercentage() bool cPlayer::SetCurrentExperience(short int a_CurrentXp) { - if (!(a_CurrentXp >= 0) || (a_CurrentXp > (SHRT_MAX - m_LifetimeTotalXp))) + if (!(a_CurrentXp >= 0) || (a_CurrentXp > (std::numeric_limits<short>().max() - m_LifetimeTotalXp))) { LOGWARNING("Tried to update experiece with an invalid Xp value: %d", a_CurrentXp); return false; // oops, they gave us a dodgey number @@ -383,18 +379,17 @@ bool cPlayer::SetCurrentExperience(short int a_CurrentXp) short cPlayer::DeltaExperience(short a_Xp_delta) { - if (a_Xp_delta > (SHRT_MAX - m_CurrentXp)) + if (a_Xp_delta > (std::numeric_limits<short>().max() - m_CurrentXp)) { // Value was bad, abort and report - LOGWARNING("Attempt was made to increment Xp by %d, which overflowed the short datatype. Ignoring.", - a_Xp_delta); + LOGWARNING("Attempt was made to increment Xp by %d, which overflowed the short datatype. Ignoring.", a_Xp_delta); return -1; // Should we instead just return the current Xp? } m_CurrentXp += a_Xp_delta; // Make sure they didn't subtract too much - m_CurrentXp = std::max<short int>(m_CurrentXp, 0); + m_CurrentXp = std::max<short>(m_CurrentXp, 0); // Update total for score calculation if (a_Xp_delta > 0) @@ -402,8 +397,7 @@ short cPlayer::DeltaExperience(short a_Xp_delta) m_LifetimeTotalXp += a_Xp_delta; } - LOGD("Player \"%s\" gained/lost %d experience, total is now: %d", - GetName().c_str(), a_Xp_delta, m_CurrentXp); + LOGD("Player \"%s\" gained/lost %d experience, total is now: %d", GetName().c_str(), a_Xp_delta, m_CurrentXp); // Set experience to be updated m_bDirtyExperience = true; diff --git a/src/Entities/Player.h b/src/Entities/Player.h index 4bb51b556..c643aaa8e 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -516,7 +516,7 @@ protected: /** The item being dragged by the cursor while in a UI window */ cItem m_DraggingItem; - long long m_LastPlayerListTime; + std::chrono::steady_clock::time_point m_LastPlayerListTime; cClientHandle * m_ClientHandle; diff --git a/src/FastRandom.cpp b/src/FastRandom.cpp index 42bf5f3f9..515dc25ea 100644 --- a/src/FastRandom.cpp +++ b/src/FastRandom.cpp @@ -4,13 +4,15 @@ // Implements the cFastRandom class representing a fast random number generator #include "Globals.h" -#include <time.h> #include "FastRandom.h" +//////////////////////////////////////////////////////////////////////////////// +// cFastRandom: + #if 0 && defined(_DEBUG) // Self-test // Both ints and floats are quick-tested to see if the random is calculated correctly, checking the range in ASSERTs, @@ -83,16 +85,8 @@ public: - -int cFastRandom::m_SeedCounter = 0; - - - - - cFastRandom::cFastRandom(void) : - m_Seed(m_SeedCounter++), - m_Counter(0) + m_LinearRand(static_cast<unsigned>(std::chrono::system_clock::now().time_since_epoch().count())) { } @@ -102,82 +96,96 @@ cFastRandom::cFastRandom(void) : int cFastRandom::NextInt(int a_Range) { - ASSERT(a_Range <= 1000000); // The random is not sufficiently linearly distributed with bigger ranges - ASSERT(a_Range > 0); - - // Make the m_Counter operations as minimal as possible, to emulate atomicity - int Counter = m_Counter++; - - // Use a_Range, m_Counter and m_Seed as inputs to the pseudorandom function: - int n = a_Range + Counter * 57 + m_Seed * 57 * 57; - n = (n << 13) ^ n; - n = ((n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff); - return ((n / 11) % a_Range); + std::uniform_int_distribution<> distribution(0, a_Range - 1); + return distribution(m_LinearRand); } + int cFastRandom::NextInt(int a_Range, int a_Salt) { - ASSERT(a_Range <= 1000000); // The random is not sufficiently linearly distributed with bigger ranges - ASSERT(a_Range > 0); - - // Make the m_Counter operations as minimal as possible, to emulate atomicity - int Counter = m_Counter++; - - // Use a_Range, a_Salt, m_Counter and m_Seed as inputs to the pseudorandom function: - int n = a_Range + Counter * 57 + m_Seed * 57 * 57 + a_Salt * 57 * 57 * 57; - n = (n << 13) ^ n; - n = ((n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff); - return ((n / 11) % a_Range); + m_LinearRand.seed(a_Salt); + std::uniform_int_distribution<> distribution(0, a_Range - 1); + return distribution(m_LinearRand); } + float cFastRandom::NextFloat(float a_Range) { - // Make the m_Counter operations as minimal as possible, to emulate atomicity - int Counter = m_Counter++; - - // Use a_Range, a_Salt, m_Counter and m_Seed as inputs to the pseudorandom function: - int n = (int)a_Range + Counter * 57 + m_Seed * 57 * 57; - n = (n << 13) ^ n; - n = ((n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff); - - // Convert the integer into float with the specified range: - return (((float)n / (float)0x7fffffff) * a_Range); + std::uniform_real_distribution<float> distribution(0, a_Range); + return distribution(m_LinearRand); } + float cFastRandom::NextFloat(float a_Range, int a_Salt) { - // Make the m_Counter operations as minimal as possible, to emulate atomicity - int Counter = m_Counter++; - - // Use a_Range, a_Salt, m_Counter and m_Seed as inputs to the pseudorandom function: - int n = (int)a_Range + Counter * 57 + m_Seed * 57 * 57 + a_Salt * 57 * 57 * 57; - n = (n << 13) ^ n; - n = ((n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff); - - // Convert the integer into float with the specified range: - return (((float)n / (float)0x7fffffff) * a_Range); + m_LinearRand.seed(a_Salt); + std::uniform_real_distribution<float> distribution(0, a_Range); + return distribution(m_LinearRand); } + int cFastRandom::GenerateRandomInteger(int a_Begin, int a_End) { - cFastRandom Random; - return Random.NextInt(a_End - a_Begin + 1) + a_Begin; + std::uniform_int_distribution<> distribution(a_Begin, a_End); + return distribution(m_LinearRand); +} + + + + + +//////////////////////////////////////////////////////////////////////////////// +// MTRand: + +MTRand::MTRand() : + m_MersenneRand(static_cast<unsigned>(std::chrono::system_clock::now().time_since_epoch().count())) +{ +} + + + + + +int MTRand::randInt(int a_Range) +{ + std::uniform_int_distribution<> distribution(0, a_Range); + return distribution(m_MersenneRand); +} + + + + + +int MTRand::randInt() +{ + std::uniform_int_distribution<> distribution(0, std::numeric_limits<int>::max()); + return distribution(m_MersenneRand); +} + + + + + +double MTRand::rand(double a_Range) +{ + std::uniform_real_distribution<> distribution(0, a_Range); + return distribution(m_MersenneRand); } diff --git a/src/FastRandom.h b/src/FastRandom.h index cebebad96..64a087c97 100644 --- a/src/FastRandom.h +++ b/src/FastRandom.h @@ -22,6 +22,7 @@ salts, the values they get will be different. #pragma once +#include <random> @@ -30,18 +31,19 @@ salts, the values they get will be different. class cFastRandom { public: + cFastRandom(void); - /// Returns a random int in the range [0 .. a_Range - 1]; a_Range must be less than 1M + /** Returns a random int in the range [0 .. a_Range - 1]; a_Range must be less than 1M */ int NextInt(int a_Range); - /// Returns a random int in the range [0 .. a_Range - 1]; a_Range must be less than 1M; a_Salt is additional source of randomness + /** Returns a random int in the range [0 .. a_Range - 1]; a_Range must be less than 1M; a_Salt is additional source of randomness */ int NextInt(int a_Range, int a_Salt); - /// Returns a random float in the range [0 .. a_Range]; a_Range must be less than 1M + /** Returns a random float in the range [0 .. a_Range]; a_Range must be less than 1M */ float NextFloat(float a_Range); - /// Returns a random float in the range [0 .. a_Range]; a_Range must be less than 1M; a_Salt is additional source of randomness + /** Returns a random float in the range [0 .. a_Range]; a_Range must be less than 1M; a_Salt is additional source of randomness */ float NextFloat(float a_Range, int a_Salt); /** Returns a random float between 0 and 1. */ @@ -49,14 +51,35 @@ public: /** Returns a random int in the range [a_Begin .. a_End] */ int GenerateRandomInteger(int a_Begin, int a_End); - -protected: - int m_Seed; - int m_Counter; - - /// Counter that is used to initialize the seed, incremented for each object created - static int m_SeedCounter; -} ; + +private: + + std::minstd_rand m_LinearRand; +}; + + + + + +class MTRand +{ +public: + + MTRand(void); + + /** Returns a random integer in the range [0 .. a_Range]. */ + int randInt(int a_Range); + + /** Returns a random integer in the range [0 .. MAX_INT]. */ + int randInt(void); + + /** Returns a random floating point number in the range [0 .. a_Range]. */ + double rand(double a_Range); + +private: + + std::mt19937 m_MersenneRand; +}; diff --git a/src/Generating/ChunkGenerator.cpp b/src/Generating/ChunkGenerator.cpp index 3ee02c767..d2e7b47b4 100644 --- a/src/Generating/ChunkGenerator.cpp +++ b/src/Generating/ChunkGenerator.cpp @@ -6,7 +6,7 @@ #include "ChunkDesc.h" #include "ComposableGenerator.h" #include "Noise3DGenerator.h" -#include "../MersenneTwister.h" +#include "FastRandom.h" diff --git a/src/Generating/DungeonRoomsFinisher.cpp b/src/Generating/DungeonRoomsFinisher.cpp index 092e232ab..c4bf8839e 100644 --- a/src/Generating/DungeonRoomsFinisher.cpp +++ b/src/Generating/DungeonRoomsFinisher.cpp @@ -131,8 +131,8 @@ protected: { int BlockX = a_ChunkDesc.GetChunkX() * cChunkDef::Width; int BlockZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width; - int RelStartX = Clamp(a_StartX - BlockX, 0, cChunkDef::Width - 1); - int RelStartZ = Clamp(a_StartZ - BlockZ, 0, cChunkDef::Width - 1); + int RelStartX = Clamp(a_StartX - BlockX, 0, cChunkDef::Width); + int RelStartZ = Clamp(a_StartZ - BlockZ, 0, cChunkDef::Width); int RelEndX = Clamp(a_EndX - BlockX, 0, cChunkDef::Width); int RelEndZ = Clamp(a_EndZ - BlockZ, 0, cChunkDef::Width); for (int y = a_StartY; y < a_EndY; y++) diff --git a/src/Generating/FinishGen.cpp b/src/Generating/FinishGen.cpp index e6732dbd5..e10cb00f8 100644 --- a/src/Generating/FinishGen.cpp +++ b/src/Generating/FinishGen.cpp @@ -1014,7 +1014,7 @@ void cFinishGenPassiveMobs::GenFinish(cChunkDesc & a_ChunkDesc) eMonsterType RandomMob = GetRandomMob(a_ChunkDesc); if (RandomMob == mtInvalidType) { - LOGWARNING("Attempted to spawn invalid mob type."); + // No mobs here. Don't send an error, because if the biome was a desert it would return mtInvalidType as well. return; } diff --git a/src/Generating/Noise3DGenerator.cpp b/src/Generating/Noise3DGenerator.cpp index 57e23809e..b43a1a6de 100644 --- a/src/Generating/Noise3DGenerator.cpp +++ b/src/Generating/Noise3DGenerator.cpp @@ -6,7 +6,6 @@ #include "Globals.h" #include "Noise3DGenerator.h" #include "../OSSupport/File.h" -#include "../OSSupport/Timer.h" #include "../IniFile.h" #include "../LinearInterpolation.h" #include "../LinearUpscale.h" @@ -739,7 +738,7 @@ void cBiomalNoise3DComposable::GetBiomeParams(EMCSBiome a_Biome, NOISE_DATATYPE case biFlowerForest: a_HeightAmp = 0.1f; a_MidPoint = 64; break; case biForest: a_HeightAmp = 0.1f; a_MidPoint = 64; break; case biForestHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break; - case biFrozenRiver: a_HeightAmp = 0.4f; a_MidPoint = 57; break; + case biFrozenRiver: a_HeightAmp = 0.4f; a_MidPoint = 54; break; case biFrozenOcean: a_HeightAmp = 0.12f; a_MidPoint = 45; break; case biIceMountains: a_HeightAmp = 0.075f; a_MidPoint = 68; break; case biIcePlains: a_HeightAmp = 0.3f; a_MidPoint = 62; break; @@ -764,7 +763,7 @@ void cBiomalNoise3DComposable::GetBiomeParams(EMCSBiome a_Biome, NOISE_DATATYPE case biNether: a_HeightAmp = 0.01f; a_MidPoint = 64; break; case biOcean: a_HeightAmp = 0.12f; a_MidPoint = 45; break; case biPlains: a_HeightAmp = 0.3f; a_MidPoint = 62; break; - case biRiver: a_HeightAmp = 0.4f; a_MidPoint = 57; break; + case biRiver: a_HeightAmp = 0.4f; a_MidPoint = 54; break; case biRoofedForest: a_HeightAmp = 0.1f; a_MidPoint = 64; break; case biRoofedForestM: a_HeightAmp = 0.1f; a_MidPoint = 64; break; case biSavanna: a_HeightAmp = 0.3f; a_MidPoint = 62; break; diff --git a/src/Globals.h b/src/Globals.h index d75ae0093..61f500db9 100644 --- a/src/Globals.h +++ b/src/Globals.h @@ -184,9 +184,9 @@ template class SizeChecker<UInt16, 2>; // OS-dependent stuff: #ifdef _WIN32 - #define WIN32_LEAN_AND_MEAN - #define _WIN32_WINNT 0x501 // We want to target WinXP and higher + #define WIN32_LEAN_AND_MEAN + #define _WIN32_WINNT _WIN32_WINNT_WS03 // We want to target Windows XP with Service Pack 2 & Windows Server 2003 with Service Pack 1 and higher #include <Windows.h> #include <winsock2.h> @@ -241,6 +241,7 @@ template class SizeChecker<UInt16, 2>; // STL stuff: +#include <chrono> #include <vector> #include <list> #include <deque> @@ -251,17 +252,17 @@ template class SizeChecker<UInt16, 2>; #include <set> #include <queue> #include <limits> +#include <chrono> + #ifndef TEST_GLOBALS // Common headers (part 1, without macros): #include "StringUtils.h" - #include "OSSupport/Sleep.h" #include "OSSupport/CriticalSection.h" #include "OSSupport/Semaphore.h" #include "OSSupport/Event.h" - #include "OSSupport/Thread.h" #include "OSSupport/File.h" #include "Logger.h" #include "OSSupport/StackTrace.h" diff --git a/src/HTTPServer/HTTPFormParser.h b/src/HTTPServer/HTTPFormParser.h index edc6d2471..d9d29d9bc 100644 --- a/src/HTTPServer/HTTPFormParser.h +++ b/src/HTTPServer/HTTPFormParser.h @@ -82,7 +82,7 @@ protected: bool m_IsValid; /// The parser for the multipart data, if used - std::auto_ptr<cMultipartParser> m_MultipartParser; + std::unique_ptr<cMultipartParser> m_MultipartParser; /// Name of the currently parsed part in multipart data AString m_CurrentPartName; diff --git a/src/Logger.cpp b/src/Logger.cpp index cb528e8ab..292622a46 100644 --- a/src/Logger.cpp +++ b/src/Logger.cpp @@ -45,12 +45,12 @@ void cLogger::LogSimple(AString a_Message, eLogLevel a_LogLevel) AString Line; #ifdef _DEBUG - Printf(Line, "[%04lx|%02d:%02d:%02d] %s\n", cIsThread::GetCurrentID(), timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, a_Message.c_str()); + Printf(Line, "[%04llx|%02d:%02d:%02d] %s\n", static_cast<UInt64>(std::hash<std::thread::id>()(std::this_thread::get_id())), timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, a_Message.c_str()); #else Printf(Line, "[%02d:%02d:%02d] %s\n", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, a_Message.c_str()); #endif - + cCSLock Lock(m_CriticalSection); for (size_t i = 0; i < m_LogListeners.size(); i++) { diff --git a/src/MersenneTwister.h b/src/MersenneTwister.h deleted file mode 100644 index e83a470e2..000000000 --- a/src/MersenneTwister.h +++ /dev/null @@ -1,456 +0,0 @@ -// MersenneTwister.h -// Mersenne Twister random number generator -- a C++ class MTRand -// Based on code by Makoto Matsumoto, Takuji Nishimura, and Shawn Cokus -// Richard J. Wagner v1.1 28 September 2009 wagnerr@umich.edu - -// The Mersenne Twister is an algorithm for generating random numbers. It -// was designed with consideration of the flaws in various other generators. -// The period, 2^19937-1, and the order of equidistribution, 623 dimensions, -// are far greater. The generator is also fast; it avoids multiplication and -// division, and it benefits from caches and pipelines. For more information -// see the inventors' web page at -// http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html - -// Reference -// M. Matsumoto and T. Nishimura, "Mersenne Twister: A 623-Dimensionally -// Equidistributed Uniform Pseudo-Random Number Generator", ACM Transactions on -// Modeling and Computer Simulation, Vol. 8, No. 1, January 1998, pp 3-30. - -// Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, -// Copyright (C) 2000 - 2009, Richard J. Wagner -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// 3. The names of its contributors may not be used to endorse or promote -// products derived from this software without specific prior written -// permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. - -#ifndef MERSENNETWISTER_H -#define MERSENNETWISTER_H - -// Not thread safe (unless auto-initialization is avoided and each thread has -// its own MTRand object) - -#include <iostream> -#include <climits> -#include <cstdio> -#include <ctime> -#include <cmath> - -class MTRand { -// Data -public: - typedef UInt32 uint32; // unsigned integer type, at least 32 bits - - enum { N = 624 }; // length of state vector - enum { SAVE = N + 1 }; // length of array for save() - -protected: - enum { M = 397 }; // period parameter - - uint32 state[N]; // internal state - uint32 *pNext; // next value to get from state - uint32 left; // number of values left before reload needed - -// Methods -public: - MTRand( const uint32 oneSeed ); // initialize with a simple uint32 - MTRand( uint32 *const bigSeed, uint32 const seedLength = N ); // or array - MTRand(); // auto-initialize with /dev/urandom or time() and clock() - MTRand( const MTRand& o ); // copy - - // Do NOT use for CRYPTOGRAPHY without securely hashing several returned - // values together, otherwise the generator state can be learned after - // reading 624 consecutive values. - - // Access to 32-bit random numbers - uint32 randInt(); // integer in [0,2^32-1] - uint32 randInt( const uint32 n ); // integer in [0,n] for n < 2^32 - double rand(); // real number in [0,1] - double rand( const double n ); // real number in [0,n] - double randExc(); // real number in [0,1) - double randExc( const double n ); // real number in [0,n) - double randDblExc(); // real number in (0,1) - double randDblExc( const double n ); // real number in (0,n) - double operator()(); // same as rand() - - // Access to 53-bit random numbers (capacity of IEEE double precision) - double rand53(); // real number in [0,1) - - // Access to nonuniform random number distributions - double randNorm( const double mean = 0.0, const double stddev = 1.0 ); - - // Re-seeding functions with same behavior as initializers - void seed( const uint32 oneSeed ); - void seed( uint32 *const bigSeed, const uint32 seedLength = N ); - void seed(); - - // Saving and loading generator state - void save( uint32* saveArray ) const; // to array of size SAVE - void load( uint32 *const loadArray ); // from such array - friend std::ostream& operator<<( std::ostream& os, const MTRand& mtrand ); - friend std::istream& operator>>( std::istream& is, MTRand& mtrand ); - MTRand& operator=( const MTRand& o ); - -protected: - void initialize( const uint32 oneSeed ); - void reload(); - uint32 hiBit( const uint32 u ) const { return u & 0x80000000UL; } - uint32 loBit( const uint32 u ) const { return u & 0x00000001UL; } - uint32 loBits( const uint32 u ) const { return u & 0x7fffffffUL; } - uint32 mixBits( const uint32 u, const uint32 v ) const - { return hiBit(u) | loBits(v); } - uint32 magic( const uint32 u ) const - { return loBit(u) ? 0x9908b0dfUL : 0x0UL; } - uint32 twist( const uint32 m, const uint32 s0, const uint32 s1 ) const - { return m ^ (mixBits(s0,s1)>>1) ^ magic(s1); } - static uint32 hash( time_t t, clock_t c ); -}; - -// Functions are defined in order of usage to assist inlining - -inline MTRand::uint32 MTRand::hash( time_t t, clock_t c ) -{ - // Get a uint32 from t and c - // Better than uint32(x) in case x is floating point in [0,1] - // Based on code by Lawrence Kirby (fred@genesis.demon.co.uk) - - static uint32 differ = 0; // guarantee time-based seeds will change - - uint32 h1 = 0; - unsigned char *p = (unsigned char *) &t; - for( size_t i = 0; i < sizeof(t); ++i ) - { - h1 *= UCHAR_MAX + 2U; - h1 += p[i]; - } - uint32 h2 = 0; - p = (unsigned char *) &c; - for( size_t j = 0; j < sizeof(c); ++j ) - { - h2 *= UCHAR_MAX + 2U; - h2 += p[j]; - } - return ( h1 + differ++ ) ^ h2; -} - -inline void MTRand::initialize( const uint32 seed ) -{ - // Initialize generator state with seed - // See Knuth TAOCP Vol 2, 3rd Ed, p.106 for multiplier. - // In previous versions, most significant bits (MSBs) of the seed affect - // only MSBs of the state array. Modified 9 Jan 2002 by Makoto Matsumoto. - uint32 *s = state; - uint32 *r = state; - uint32 i = 1; - *s++ = seed & 0xffffffffUL; - for( ; i < N; ++i ) - { - *s++ = ( 1812433253UL * ( *r ^ (*r >> 30) ) + i ) & 0xffffffffUL; - r++; - } -} - -inline void MTRand::reload() -{ - // Generate N new values in state - // Made clearer and faster by Matthew Bellew (matthew.bellew@home.com) - static const int MmN = int(M) - int(N); // in case enums are unsigned - uint32 *p = state; - int i; - for( i = N - M; i--; ++p ) - *p = twist( p[M], p[0], p[1] ); - for( i = M; --i; ++p ) - *p = twist( p[MmN], p[0], p[1] ); - *p = twist( p[MmN], p[0], state[0] ); - - left = N, pNext = state; -} - -inline void MTRand::seed( const uint32 oneSeed ) -{ - // Seed the generator with a simple uint32 - initialize(oneSeed); - reload(); -} - -inline void MTRand::seed( uint32 *const bigSeed, const uint32 seedLength ) -{ - // Seed the generator with an array of uint32's - // There are 2^19937-1 possible initial states. This function allows - // all of those to be accessed by providing at least 19937 bits (with a - // default seed length of N = 624 uint32's). Any bits above the lower 32 - // in each element are discarded. - // Just call seed() if you want to get array from /dev/urandom - initialize(19650218UL); - uint32 i = 1; - uint32 j = 0; - uint32 k = ( static_cast<uint32>(N) > seedLength ? static_cast<uint32>(N) : seedLength ); - for( ; k; --k ) - { - state[i] = - state[i] ^ ( (state[i-1] ^ (state[i-1] >> 30)) * 1664525UL ); - state[i] += ( bigSeed[j] & 0xffffffffUL ) + j; - state[i] &= 0xffffffffUL; - ++i; ++j; - if( i >= N ) { state[0] = state[N-1]; i = 1; } - if( j >= seedLength ) j = 0; - } - for( k = N - 1; k; --k ) - { - state[i] = - state[i] ^ ( (state[i-1] ^ (state[i-1] >> 30)) * 1566083941UL ); - state[i] -= i; - state[i] &= 0xffffffffUL; - ++i; - if( i >= N ) { state[0] = state[N-1]; i = 1; } - } - state[0] = 0x80000000UL; // MSB is 1, assuring non-zero initial array - reload(); -} - -inline void MTRand::seed() -{ - // Seed the generator with an array from /dev/urandom if available - // Otherwise use a hash of time() and clock() values - - // First try getting an array from /dev/urandom - - /* // Commented out by FakeTruth because doing this 200 times a tick is SUUUUPEERRR SLOW!!~~!\D5Ne - FILE* urandom = fopen( "/dev/urandom", "rb" ); - if( urandom ) - { - uint32 bigSeed[N]; - register uint32 *s = bigSeed; - register int i = N; - register bool success = true; - while( success && i-- ) - success = fread( s++, sizeof(uint32), 1, urandom ); - fclose(urandom); - if( success ) { seed( bigSeed, N ); return; } - } - */ - - // Was not successful, so use time() and clock() instead - seed( hash( time(NULL), clock() ) ); -} - -inline MTRand::MTRand( const uint32 oneSeed ) - { seed(oneSeed); } - -inline MTRand::MTRand( uint32 *const bigSeed, const uint32 seedLength ) - { seed(bigSeed,seedLength); } - -inline MTRand::MTRand() - { seed(); } - -inline MTRand::MTRand( const MTRand& o ) -{ - const uint32 *t = o.state; - uint32 *s = state; - int i = N; - for( ; i--; *s++ = *t++ ) {} - left = o.left; - pNext = &state[N-left]; -} - -inline MTRand::uint32 MTRand::randInt() -{ - // Pull a 32-bit integer from the generator state - // Every other access function simply transforms the numbers extracted here - - if( left == 0 ) reload(); - --left; - - uint32 s1; - s1 = *pNext++; - s1 ^= (s1 >> 11); - s1 ^= (s1 << 7) & 0x9d2c5680UL; - s1 ^= (s1 << 15) & 0xefc60000UL; - return ( s1 ^ (s1 >> 18) ); -} - -inline MTRand::uint32 MTRand::randInt( const uint32 n ) -{ - // Find which bits are used in n - // Optimized by Magnus Jonsson (magnus@smartelectronix.com) - uint32 used = n; - used |= used >> 1; - used |= used >> 2; - used |= used >> 4; - used |= used >> 8; - used |= used >> 16; - - // Draw numbers until one is found in [0,n] - uint32 i; - do - i = randInt() & used; // toss unused bits to shorten search - while( i > n ); - return i; -} - -inline double MTRand::rand() - { return double(randInt()) * (1.0/4294967295.0); } - -inline double MTRand::rand( const double n ) - { return rand() * n; } - -inline double MTRand::randExc() - { return double(randInt()) * (1.0/4294967296.0); } - -inline double MTRand::randExc( const double n ) - { return randExc() * n; } - -inline double MTRand::randDblExc() - { return ( double(randInt()) + 0.5 ) * (1.0/4294967296.0); } - -inline double MTRand::randDblExc( const double n ) - { return randDblExc() * n; } - -inline double MTRand::rand53() -{ - uint32 a = randInt() >> 5, b = randInt() >> 6; - return ( a * 67108864.0 + b ) * (1.0/9007199254740992.0); // by Isaku Wada -} - -inline double MTRand::randNorm( const double mean, const double stddev ) -{ - // Return a real number from a normal (Gaussian) distribution with given - // mean and standard deviation by polar form of Box-Muller transformation - double x, y, r; - do - { - x = 2.0 * rand() - 1.0; - y = 2.0 * rand() - 1.0; - r = x * x + y * y; - } - while ( r >= 1.0 || r == 0.0 ); - double s = sqrt( -2.0 * log(r) / r ); - return mean + x * s * stddev; -} - -inline double MTRand::operator()() -{ - return rand(); -} - -inline void MTRand::save( uint32* saveArray ) const -{ - const uint32 *s = state; - uint32 *sa = saveArray; - int i = N; - for( ; i--; *sa++ = *s++ ) {} - *sa = left; -} - -inline void MTRand::load( uint32 *const loadArray ) -{ - uint32 *s = state; - uint32 *la = loadArray; - int i = N; - for( ; i--; *s++ = *la++ ) {} - left = *la; - pNext = &state[N-left]; -} - -inline std::ostream& operator<<( std::ostream& os, const MTRand& mtrand ) -{ - const MTRand::uint32 *s = mtrand.state; - int i = mtrand.N; - for( ; i--; os << *s++ << "\t" ) {} - return os << mtrand.left; -} - -inline std::istream& operator>>( std::istream& is, MTRand& mtrand ) -{ - MTRand::uint32 *s = mtrand.state; - int i = mtrand.N; - for( ; i--; is >> *s++ ) {} - is >> mtrand.left; - mtrand.pNext = &mtrand.state[mtrand.N-mtrand.left]; - return is; -} - -inline MTRand& MTRand::operator=( const MTRand& o ) -{ - if( this == &o ) return (*this); - const uint32 *t = o.state; - uint32 *s = state; - int i = N; - for( ; i--; *s++ = *t++ ) {} - left = o.left; - pNext = &state[N-left]; - return (*this); -} - -#endif // MERSENNETWISTER_H - -// Change log: -// -// v0.1 - First release on 15 May 2000 -// - Based on code by Makoto Matsumoto, Takuji Nishimura, and Shawn Cokus -// - Translated from C to C++ -// - Made completely ANSI compliant -// - Designed convenient interface for initialization, seeding, and -// obtaining numbers in default or user-defined ranges -// - Added automatic seeding from /dev/urandom or time() and clock() -// - Provided functions for saving and loading generator state -// -// v0.2 - Fixed bug which reloaded generator one step too late -// -// v0.3 - Switched to clearer, faster reload() code from Matthew Bellew -// -// v0.4 - Removed trailing newline in saved generator format to be consistent -// with output format of built-in types -// -// v0.5 - Improved portability by replacing static const int's with enum's and -// clarifying return values in seed(); suggested by Eric Heimburg -// - Removed MAXINT constant; use 0xffffffffUL instead -// -// v0.6 - Eliminated seed overflow when uint32 is larger than 32 bits -// - Changed integer [0,n] generator to give better uniformity -// -// v0.7 - Fixed operator precedence ambiguity in reload() -// - Added access for real numbers in (0,1) and (0,n) -// -// v0.8 - Included time.h header to properly support time_t and clock_t -// -// v1.0 - Revised seeding to match 26 Jan 2002 update of Nishimura and Matsumoto -// - Allowed for seeding with arrays of any length -// - Added access for real numbers in [0,1) with 53-bit resolution -// - Added access for real numbers from normal (Gaussian) distributions -// - Increased overall speed by optimizing twist() -// - Doubled speed of integer [0,n] generation -// - Fixed out-of-range number generation on 64-bit machines -// - Improved portability by substituting literal constants for long enum's -// - Changed license from GNU LGPL to BSD -// -// v1.1 - Corrected parameter label in randNorm from "variance" to "stddev" -// - Changed randNorm algorithm from basic to polar form for efficiency -// - Updated includes from deprecated <xxxx.h> to standard <cxxxx> forms -// - Cleaned declarations and definitions to please Intel compiler -// - Revised twist() operator to work on ones'-complement machines -// - Fixed reload() function to work when N and M are unsigned -// - Added copy constructor and copy operator from Salvador Espana diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index c8b2ed774..7b8f763af 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -9,7 +9,6 @@ #include "../Entities/Player.h" #include "../Entities/ExpOrb.h" #include "../MonsterConfig.h" -#include "../MersenneTwister.h" #include "../Chunk.h" #include "../FastRandom.h" diff --git a/src/Mobs/Witch.cpp b/src/Mobs/Witch.cpp index 747a11f97..a3cadbaa0 100644 --- a/src/Mobs/Witch.cpp +++ b/src/Mobs/Witch.cpp @@ -2,6 +2,7 @@ #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "Witch.h" +#include "FastRandom.h" diff --git a/src/Mobs/Witch.h b/src/Mobs/Witch.h index 03691fef1..8230e1f98 100644 --- a/src/Mobs/Witch.h +++ b/src/Mobs/Witch.h @@ -2,7 +2,6 @@ #pragma once #include "AggressiveMonster.h" -#include "../MersenneTwister.h" diff --git a/src/OSSupport/CMakeLists.txt b/src/OSSupport/CMakeLists.txt index 592525941..e943ceb18 100644 --- a/src/OSSupport/CMakeLists.txt +++ b/src/OSSupport/CMakeLists.txt @@ -13,12 +13,9 @@ SET (SRCS IsThread.cpp ListenThread.cpp Semaphore.cpp - Sleep.cpp Socket.cpp SocketThreads.cpp StackTrace.cpp - Thread.cpp - Timer.cpp ) SET (HDRS @@ -31,12 +28,9 @@ SET (HDRS ListenThread.h Queue.h Semaphore.h - Sleep.h Socket.h SocketThreads.h StackTrace.h - Thread.h - Timer.h ) if(NOT MSVC) diff --git a/src/OSSupport/CriticalSection.cpp b/src/OSSupport/CriticalSection.cpp index 5dfc8b5f9..13a3e4d9f 100644 --- a/src/OSSupport/CriticalSection.cpp +++ b/src/OSSupport/CriticalSection.cpp @@ -1,6 +1,5 @@ #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules -#include "IsThread.h" @@ -9,41 +8,12 @@ //////////////////////////////////////////////////////////////////////////////// // cCriticalSection: +#ifdef _DEBUG cCriticalSection::cCriticalSection() { - #ifdef _WIN32 - InitializeCriticalSection(&m_CriticalSection); - #else - pthread_mutexattr_init(&m_Attributes); - pthread_mutexattr_settype(&m_Attributes, PTHREAD_MUTEX_RECURSIVE); - - if (pthread_mutex_init(&m_CriticalSection, &m_Attributes) != 0) - { - LOGERROR("Could not initialize Critical Section!"); - } - #endif - - #ifdef _DEBUG - m_IsLocked = 0; - #endif // _DEBUG -} - - - - - -cCriticalSection::~cCriticalSection() -{ - #ifdef _WIN32 - DeleteCriticalSection(&m_CriticalSection); - #else - if (pthread_mutex_destroy(&m_CriticalSection) != 0) - { - LOGWARNING("Could not destroy Critical Section!"); - } - pthread_mutexattr_destroy(&m_Attributes); - #endif + m_IsLocked = 0; } +#endif // _DEBUG @@ -51,15 +21,11 @@ cCriticalSection::~cCriticalSection() void cCriticalSection::Lock() { - #ifdef _WIN32 - EnterCriticalSection(&m_CriticalSection); - #else - pthread_mutex_lock(&m_CriticalSection); - #endif + m_Mutex.lock(); #ifdef _DEBUG m_IsLocked += 1; - m_OwningThreadID = cIsThread::GetCurrentID(); + m_OwningThreadID = std::this_thread::get_id(); #endif // _DEBUG } @@ -74,11 +40,7 @@ void cCriticalSection::Unlock() m_IsLocked -= 1; #endif // _DEBUG - #ifdef _WIN32 - LeaveCriticalSection(&m_CriticalSection); - #else - pthread_mutex_unlock(&m_CriticalSection); - #endif + m_Mutex.unlock(); } @@ -97,7 +59,7 @@ bool cCriticalSection::IsLocked(void) bool cCriticalSection::IsLockedByCurrentThread(void) { - return ((m_IsLocked > 0) && (m_OwningThreadID == cIsThread::GetCurrentID())); + return ((m_IsLocked > 0) && (m_OwningThreadID == std::this_thread::get_id())); } #endif // _DEBUG diff --git a/src/OSSupport/CriticalSection.h b/src/OSSupport/CriticalSection.h index c3c6e57f0..17fcdfc12 100644 --- a/src/OSSupport/CriticalSection.h +++ b/src/OSSupport/CriticalSection.h @@ -1,5 +1,7 @@ #pragma once +#include <mutex> +#include <thread> @@ -8,8 +10,6 @@ class cCriticalSection { public: - cCriticalSection(void); - ~cCriticalSection(); void Lock(void); void Unlock(void); @@ -17,6 +17,7 @@ public: // IsLocked/IsLockedByCurrentThread are only used in ASSERT statements, but because of the changes with ASSERT they must always be defined // The fake versions (in Release) will not effect the program in any way #ifdef _DEBUG + cCriticalSection(void); bool IsLocked(void); bool IsLockedByCurrentThread(void); #else @@ -27,15 +28,10 @@ public: private: #ifdef _DEBUG int m_IsLocked; // Number of times this CS is locked - unsigned long m_OwningThreadID; + std::thread::id m_OwningThreadID; #endif // _DEBUG - #ifdef _WIN32 - CRITICAL_SECTION m_CriticalSection; - #else // _WIN32 - pthread_mutex_t m_CriticalSection; - pthread_mutexattr_t m_Attributes; - #endif // else _WIN32 + std::recursive_mutex m_Mutex; } ALIGN_8; diff --git a/src/OSSupport/Event.cpp b/src/OSSupport/Event.cpp index 87bc110ce..d6ba937f9 100644 --- a/src/OSSupport/Event.cpp +++ b/src/OSSupport/Event.cpp @@ -12,137 +12,59 @@ -cEvent::cEvent(void) +cEvent::cEvent(void) : + m_ShouldWait(true) { -#ifdef _WIN32 - m_Event = CreateEvent(nullptr, FALSE, FALSE, nullptr); - if (m_Event == nullptr) - { - LOGERROR("cEvent: cannot create event, GLE = %u. Aborting server.", (unsigned)GetLastError()); - abort(); - } -#else // *nix - m_bIsNamed = false; - m_Event = new sem_t; - if (sem_init(m_Event, 0, 0)) - { - // This path is used by MacOS, because it doesn't support unnamed semaphores. - delete m_Event; - m_bIsNamed = true; - - AString EventName; - Printf(EventName, "cEvent%p", this); - m_Event = sem_open(EventName.c_str(), O_CREAT, 777, 0); - if (m_Event == SEM_FAILED) - { - AString error = GetOSErrorString(errno); - LOGERROR("cEvent: Cannot create event, err = %s. Aborting server.", error.c_str()); - abort(); - } - // Unlink the semaphore immediately - it will continue to function but will not pollute the namespace - // We don't store the name, so can't call this in the destructor - if (sem_unlink(EventName.c_str()) != 0) - { - AString error = GetOSErrorString(errno); - LOGWARN("ERROR: Could not unlink cEvent. (%s)", error.c_str()); - } - } -#endif // *nix } -cEvent::~cEvent() +void cEvent::Wait(void) { -#ifdef _WIN32 - CloseHandle(m_Event); -#else - if (m_bIsNamed) - { - if (sem_close(m_Event) != 0) - { - AString error = GetOSErrorString(errno); - LOGERROR("ERROR: Could not close cEvent. (%s)", error.c_str()); - } - } - else + std::unique_lock<std::mutex> Lock(m_Mutex); + while (m_ShouldWait) { - sem_destroy(m_Event); - delete m_Event; - m_Event = nullptr; + m_CondVar.wait(Lock); } -#endif + m_ShouldWait = true; } -void cEvent::Wait(void) +bool cEvent::Wait(unsigned a_TimeoutMSec) { - #ifdef _WIN32 - DWORD res = WaitForSingleObject(m_Event, INFINITE); - if (res != WAIT_OBJECT_0) - { - LOGWARN("cEvent: waiting for the event failed: %u, GLE = %u. Continuing, but server may be unstable.", (unsigned)res, (unsigned)GetLastError()); - } - #else - int res = sem_wait(m_Event); - if (res != 0) - { - AString error = GetOSErrorString(errno); - LOGWARN("cEvent: waiting for the event failed: %i, err = %s. Continuing, but server may be unstable.", res, error.c_str()); - } - #endif -} - - - - - -bool cEvent::Wait(int a_TimeoutMSec) -{ - #ifdef _WIN32 - DWORD res = WaitForSingleObject(m_Event, (DWORD)a_TimeoutMSec); - switch (res) + auto dst = std::chrono::system_clock::now() + std::chrono::milliseconds(a_TimeoutMSec); + std::unique_lock<std::mutex> Lock(m_Mutex); // We assume that this lock is acquired without much delay - we are the only user of the mutex + while (m_ShouldWait && (std::chrono::system_clock::now() <= dst)) + { + switch (m_CondVar.wait_until(Lock, dst)) { - case WAIT_OBJECT_0: return true; // Regular event signalled - case WAIT_TIMEOUT: return false; // Regular event timeout - default: + case std::cv_status::no_timeout: { - LOGWARN("cEvent: waiting for the event failed: %u, GLE = %u. Continuing, but server may be unstable.", (unsigned)res, (unsigned)GetLastError()); - return false; + // The wait was successful, check for spurious wakeup: + if (!m_ShouldWait) + { + m_ShouldWait = true; + return true; + } + // This was a spurious wakeup, wait again: + continue; } - } - #else - // Get the current time: - timespec timeout; - if (clock_gettime(CLOCK_REALTIME, &timeout) == -1) - { - LOGWARN("cEvent: Getting current time failed: %i, err = %s. Continuing, but the server may be unstable.", errno, GetOSErrorString(errno).c_str()); - return false; - } - - // Add the specified timeout: - timeout.tv_sec += a_TimeoutMSec / 1000; - timeout.tv_nsec += (a_TimeoutMSec % 1000) * 1000000; // 1 msec = 1000000 usec - - // Wait with timeout: - int res = sem_timedwait(m_Event, &timeout); - switch (res) - { - case 0: return true; // Regular event signalled - case ETIMEDOUT: return false; // Regular even timeout - default: + + case std::cv_status::timeout: { - AString error = GetOSErrorString(errno); - LOGWARN("cEvent: waiting for the event failed: %i, err = %s. Continuing, but server may be unstable.", res, error.c_str()); + // The wait timed out, return failure: return false; } - } - #endif + } // switch (wait_until()) + } // while (m_ShouldWait && not timeout) + + // The wait timed out in the while() condition: + return false; } @@ -151,19 +73,11 @@ bool cEvent::Wait(int a_TimeoutMSec) void cEvent::Set(void) { - #ifdef _WIN32 - if (!SetEvent(m_Event)) - { - LOGWARN("cEvent: Could not set cEvent: GLE = %u", (unsigned)GetLastError()); - } - #else - int res = sem_post(m_Event); - if (res != 0) - { - AString error = GetOSErrorString(errno); - LOGWARN("cEvent: Could not set cEvent: %i, err = %s", res, error.c_str()); - } - #endif + { + std::unique_lock<std::mutex> Lock(m_Mutex); + m_ShouldWait = false; + } + m_CondVar.notify_one(); } diff --git a/src/OSSupport/Event.h b/src/OSSupport/Event.h index e2fa65a05..572388a3f 100644 --- a/src/OSSupport/Event.h +++ b/src/OSSupport/Event.h @@ -1,16 +1,17 @@ // Event.h -// Interfaces to the cEvent object representing an OS-specific synchronization primitive that can be waited-for -// Implemented as an Event on Win and as a 1-semaphore on *nix +// Interfaces to the cEvent object representing a synchronization primitive that can be waited-for +// Implemented using C++11 condition variable and mutex #pragma once -#ifndef CEVENT_H_INCLUDED -#define CEVENT_H_INCLUDED + +#include <mutex> +#include <condition_variable> @@ -20,31 +21,31 @@ class cEvent { public: cEvent(void); - ~cEvent(); + /** Waits until the event has been set. + If the event has been set before it has been waited for, Wait() returns immediately. */ void Wait(void); + + /** Sets the event - releases one thread that has been waiting in Wait(). + If there was no thread waiting, the next call to Wait() will not block. */ void Set (void); /** Waits for the event until either it is signalled, or the (relative) timeout is passed. Returns true if the event was signalled, false if the timeout was hit or there was an error. */ - bool Wait(int a_TimeoutMSec); + bool Wait(unsigned a_TimeoutMSec); private: - #ifdef _WIN32 - HANDLE m_Event; - #else - sem_t * m_Event; - bool m_bIsNamed; - #endif -} ; - - - + /** Used for checking for spurious wakeups. */ + bool m_ShouldWait; + /** Mutex protecting m_ShouldWait from multithreaded access. */ + std::mutex m_Mutex; + /** The condition variable used as the Event. */ + std::condition_variable m_CondVar; +} ; -#endif // CEVENT_H_INCLUDED diff --git a/src/OSSupport/IsThread.cpp b/src/OSSupport/IsThread.cpp index 1a436623a..94bed1f56 100644 --- a/src/OSSupport/IsThread.cpp +++ b/src/OSSupport/IsThread.cpp @@ -5,49 +5,40 @@ // This class will eventually suupersede the old cThread class #include "Globals.h" - #include "IsThread.h" -// When in MSVC, the debugger provides "thread naming" by catching special exceptions. Interface here: #if defined(_MSC_VER) && defined(_DEBUG) -// -// Usage: SetThreadName (-1, "MainThread"); -// - -// Code adapted from MSDN: http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx - -const DWORD MS_VC_EXCEPTION = 0x406D1388; - -#pragma pack(push, 8) -typedef struct tagTHREADNAME_INFO -{ - DWORD dwType; // Must be 0x1000. - LPCSTR szName; // Pointer to name (in user addr space). - DWORD dwThreadID; // Thread ID (-1 = caller thread). - DWORD dwFlags; // Reserved for future use, must be zero. -} THREADNAME_INFO; -#pragma pack(pop) - -static void SetThreadName(DWORD dwThreadID, const char * threadName) -{ - THREADNAME_INFO info; - info.dwType = 0x1000; - info.szName = threadName; - info.dwThreadID = dwThreadID; - info.dwFlags = 0; + // Code adapted from MSDN: http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx - __try - { - RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR *)&info); - } - __except (EXCEPTION_EXECUTE_HANDLER) + const DWORD MS_VC_EXCEPTION = 0x406D1388; + #pragma pack(push, 8) + struct THREADNAME_INFO + { + DWORD dwType; // Must be 0x1000. + LPCSTR szName; // Pointer to name (in user addr space). + DWORD dwThreadID; // Thread ID (-1 = caller thread). + DWORD dwFlags; // Reserved for future use, must be zero. + }; + #pragma pack(pop) + + /** Sets the name of a thread with the specified ID + (When in MSVC, the debugger provides "thread naming" by catching special exceptions) + */ + static void SetThreadName(std::thread * a_Thread, const char * a_ThreadName) { + THREADNAME_INFO info { 0x1000, a_ThreadName, GetThreadId(a_Thread->native_handle()), 0 }; + __try + { + RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR *)&info); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + } } -} #endif // _MSC_VER && _DEBUG @@ -57,13 +48,9 @@ static void SetThreadName(DWORD dwThreadID, const char * threadName) //////////////////////////////////////////////////////////////////////////////// // cIsThread: -cIsThread::cIsThread(const AString & iThreadName) : +cIsThread::cIsThread(const AString & a_ThreadName) : m_ShouldTerminate(false), - m_ThreadName(iThreadName), - #ifdef _WIN32 - m_ThreadID(0), - #endif - m_Handle(NULL_HANDLE) + m_ThreadName(a_ThreadName) { } @@ -83,35 +70,24 @@ cIsThread::~cIsThread() bool cIsThread::Start(void) { - ASSERT(m_Handle == NULL_HANDLE); // Has already started one thread? - #ifdef _WIN32 - // Create the thread suspended, so that the mHandle variable is valid in the thread procedure - m_ThreadID = 0; - m_Handle = CreateThread(NULL, 0, thrExecute, this, CREATE_SUSPENDED, &m_ThreadID); - if (m_Handle == NULL) - { - LOGERROR("ERROR: Could not create thread \"%s\", GLE = %u!", m_ThreadName.c_str(), (unsigned)GetLastError()); - return false; - } - ResumeThread(m_Handle); - - #if defined(_DEBUG) && defined(_MSC_VER) - // Thread naming is available only in MSVC - if (!m_ThreadName.empty()) - { - SetThreadName(m_ThreadID, m_ThreadName.c_str()); - } - #endif // _DEBUG and _MSC_VER - - #else // _WIN32 - if (pthread_create(&m_Handle, NULL, thrExecute, this)) + try + { + m_Thread = std::thread(&cIsThread::Execute, this); + + #if defined (_MSC_VER) && defined(_DEBUG) + if (!m_ThreadName.empty()) { - LOGERROR("ERROR: Could not create thread \"%s\", !", m_ThreadName.c_str()); - return false; + SetThreadName(&m_Thread, m_ThreadName.c_str()); } - #endif // else _WIN32 + #endif - return true; + return true; + } + catch (std::system_error & a_Exception) + { + LOGERROR("cIsThread::Start error %i: could not construct thread %s; %s", a_Exception.code().value(), m_ThreadName.c_str(), a_Exception.code().message().c_str()); + return false; + } } @@ -120,10 +96,12 @@ bool cIsThread::Start(void) void cIsThread::Stop(void) { - if (m_Handle == NULL_HANDLE) + if (!m_Thread.joinable()) { + // The thread hasn't been started or has already been joined return; } + m_ShouldTerminate = true; Wait(); } @@ -134,59 +112,23 @@ void cIsThread::Stop(void) bool cIsThread::Wait(void) { - if (m_Handle == NULL_HANDLE) + LOGD("Waiting for thread %s to finish", m_ThreadName.c_str()); + if (m_Thread.joinable()) { - return true; + try + { + m_Thread.join(); + return true; + } + catch (std::system_error & a_Exception) + { + LOGERROR("cIsThread::Wait error %i: could not join thread %s; %s", a_Exception.code().value(), m_ThreadName.c_str(), a_Exception.code().message().c_str()); + return false; + } } - - #ifdef LOGD // ProtoProxy doesn't have LOGD - LOGD("Waiting for thread %s to finish", m_ThreadName.c_str()); - #endif // LOGD - - #ifdef _WIN32 - int res = WaitForSingleObject(m_Handle, INFINITE); - m_Handle = NULL; - - #ifdef LOGD // ProtoProxy doesn't have LOGD - LOGD("Thread %s finished", m_ThreadName.c_str()); - #endif // LOGD - - return (res == WAIT_OBJECT_0); - #else // _WIN32 - int res = pthread_join(m_Handle, NULL); - m_Handle = NULL_HANDLE; - - #ifdef LOGD // ProtoProxy doesn't have LOGD - LOGD("Thread %s finished", m_ThreadName.c_str()); - #endif // LOGD - - return (res == 0); - #endif // else _WIN32 -} - - - - -unsigned long cIsThread::GetCurrentID(void) -{ - #ifdef _WIN32 - return (unsigned long) GetCurrentThreadId(); - #else - return (unsigned long) pthread_self(); - #endif -} - - - - -bool cIsThread::IsCurrentThread(void) const -{ - #ifdef _WIN32 - return (GetCurrentThreadId() == m_ThreadID); - #else - return (m_Handle == pthread_self()); - #endif + LOGD("Thread %s finished", m_ThreadName.c_str()); + return true; } diff --git a/src/OSSupport/IsThread.h b/src/OSSupport/IsThread.h index 5c8d28d2d..131c6950e 100644 --- a/src/OSSupport/IsThread.h +++ b/src/OSSupport/IsThread.h @@ -16,8 +16,7 @@ In the descending class' constructor call the Start() method to start the thread #pragma once -#ifndef CISTHREAD_H_INCLUDED -#define CISTHREAD_H_INCLUDED +#include <thread> @@ -33,7 +32,7 @@ protected: volatile bool m_ShouldTerminate; public: - cIsThread(const AString & iThreadName); + cIsThread(const AString & a_ThreadName); virtual ~cIsThread(); /// Starts the thread; returns without waiting for the actual start @@ -45,56 +44,14 @@ public: /// Waits for the thread to finish. Doesn't signalize the ShouldTerminate flag bool Wait(void); - /// Returns the OS-dependent thread ID for the caller's thread - static unsigned long GetCurrentID(void); - /** Returns true if the thread calling this function is the thread contained within this object. */ - bool IsCurrentThread(void) const; + bool IsCurrentThread(void) const { return std::this_thread::get_id() == m_Thread.get_id(); } protected: AString m_ThreadName; - - // Value used for "no handle": - #ifdef _WIN32 - #define NULL_HANDLE NULL - #else - #define NULL_HANDLE 0 - #endif - - #ifdef _WIN32 - - DWORD m_ThreadID; - HANDLE m_Handle; - - static DWORD __stdcall thrExecute(LPVOID a_Param) - { - // Create a window so that the thread can be identified by 3rd party tools: - HWND IdentificationWnd = CreateWindowA("STATIC", ((cIsThread *)a_Param)->m_ThreadName.c_str(), 0, 0, 0, 0, WS_OVERLAPPED, NULL, NULL, NULL, NULL); - - // Run the thread: - ((cIsThread *)a_Param)->Execute(); - - // Destroy the identification window: - DestroyWindow(IdentificationWnd); - - return 0; - } - - #else // _WIN32 - - pthread_t m_Handle; - - static void * thrExecute(void * a_Param) - { - (static_cast<cIsThread *>(a_Param))->Execute(); - return NULL; - } - - #endif // else _WIN32 + std::thread m_Thread; } ; - -#endif // CISTHREAD_H_INCLUDED diff --git a/src/OSSupport/Sleep.cpp b/src/OSSupport/Sleep.cpp deleted file mode 100644 index 297d668d7..000000000 --- a/src/OSSupport/Sleep.cpp +++ /dev/null @@ -1,19 +0,0 @@ - -#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules - -#ifndef _WIN32 - #include <unistd.h> -#endif - - - - - -void cSleep::MilliSleep( unsigned int a_MilliSeconds) -{ -#ifdef _WIN32 - Sleep(a_MilliSeconds); // Don't tick too much -#else - usleep(a_MilliSeconds*1000); -#endif -} diff --git a/src/OSSupport/Sleep.h b/src/OSSupport/Sleep.h deleted file mode 100644 index 57d29682c..000000000 --- a/src/OSSupport/Sleep.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -class cSleep -{ -public: - static void MilliSleep( unsigned int a_MilliSeconds); -}; diff --git a/src/OSSupport/SocketThreads.cpp b/src/OSSupport/SocketThreads.cpp index 7a3ef4274..153d6ed1d 100644 --- a/src/OSSupport/SocketThreads.cpp +++ b/src/OSSupport/SocketThreads.cpp @@ -86,7 +86,8 @@ void cSocketThreads::RemoveClient(const cCallback * a_Client) } } // for itr - m_Threads[] - ASSERT(!"Removing an unknown client"); + // This client wasn't found. + // It's not an error, because it may have been removed by a different thread in the meantime. } @@ -491,10 +492,17 @@ void cSocketThreads::cSocketThread::ReadFromSockets(fd_set * a_Read) { case sSlot::ssNormal: { - // Notify the callback that the remote has closed the socket; keep the slot - m_Slots[i].m_Client->SocketClosed(); + // Close the socket on our side: m_Slots[i].m_State = sSlot::ssRemoteClosed; m_Slots[i].m_Socket.CloseSocket(); + + // Notify the callback that the remote has closed the socket, *after* removing the socket: + cCallback * client = m_Slots[i].m_Client; + m_Slots[i] = m_Slots[--m_NumSlots]; + if (client != nullptr) + { + client->SocketClosed(); + } break; } case sSlot::ssWritingRestOut: diff --git a/src/OSSupport/Thread.cpp b/src/OSSupport/Thread.cpp deleted file mode 100644 index 6188d5088..000000000 --- a/src/OSSupport/Thread.cpp +++ /dev/null @@ -1,146 +0,0 @@ - -#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules - - - - - -// When in MSVC, the debugger provides "thread naming" by catching special exceptions. Interface here: -#ifdef _MSC_VER -// -// Usage: SetThreadName (-1, "MainThread"); -// - -// Code adapted from MSDN: http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx - -const DWORD MS_VC_EXCEPTION = 0x406D1388; - -#pragma pack(push, 8) -typedef struct tagTHREADNAME_INFO -{ - DWORD dwType; // Must be 0x1000. - LPCSTR szName; // Pointer to name (in user addr space). - DWORD dwThreadID; // Thread ID (-1 = caller thread). - DWORD dwFlags; // Reserved for future use, must be zero. -} THREADNAME_INFO; -#pragma pack(pop) - -static void SetThreadName(DWORD dwThreadID, const char * threadName) -{ - THREADNAME_INFO info; - info.dwType = 0x1000; - info.szName = threadName; - info.dwThreadID = dwThreadID; - info.dwFlags = 0; - - __try - { - RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR *)&info); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - } -} -#endif // _MSC_VER - - - - - -cThread::cThread( ThreadFunc a_ThreadFunction, void* a_Param, const char* a_ThreadName /* = 0 */) - : m_ThreadFunction( a_ThreadFunction) - , m_Param( a_Param) - , m_Event( new cEvent()) - , m_StopEvent( 0) -{ - if (a_ThreadName) - { - m_ThreadName.assign(a_ThreadName); - } -} - - - - - -cThread::~cThread() -{ - delete m_Event; - m_Event = NULL; - - if (m_StopEvent) - { - m_StopEvent->Wait(); - delete m_StopEvent; - m_StopEvent = NULL; - } -} - - - - - -void cThread::Start( bool a_bWaitOnDelete /* = true */) -{ - if (a_bWaitOnDelete) - { - m_StopEvent = new cEvent(); - } - -#ifndef _WIN32 - pthread_t SndThread; - if (pthread_create( &SndThread, NULL, MyThread, this)) - { - LOGERROR("ERROR: Could not create thread!"); - } -#else - DWORD ThreadID = 0; - HANDLE hThread = CreateThread(NULL // security - , 0 // stack size - , (LPTHREAD_START_ROUTINE) MyThread // function name - , this // parameters - , 0 // flags - , &ThreadID); // thread id - CloseHandle( hThread); - - #ifdef _MSC_VER - if (!m_ThreadName.empty()) - { - SetThreadName(ThreadID, m_ThreadName.c_str()); - } - #endif // _MSC_VER -#endif - - // Wait until thread has actually been created - m_Event->Wait(); -} - - - - - -#ifdef _WIN32 -unsigned long cThread::MyThread(void* a_Param) -#else -void *cThread::MyThread( void *a_Param) -#endif -{ - cThread* self = (cThread*)a_Param; - cEvent* StopEvent = self->m_StopEvent; - - ThreadFunc* ThreadFunction = self->m_ThreadFunction; - void* ThreadParam = self->m_Param; - - // Set event to let other thread know this thread has been created and it's safe to delete the cThread object - self->m_Event->Set(); - - ThreadFunction( ThreadParam); - - // If the thread was marked as wait-on-delete, signal the event being waited on: - if (StopEvent != nullptr) - { - StopEvent->Set(); - } - - return 0; -} diff --git a/src/OSSupport/Thread.h b/src/OSSupport/Thread.h deleted file mode 100644 index 7ee352c82..000000000 --- a/src/OSSupport/Thread.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -class cThread -{ -public: - typedef void (ThreadFunc)(void*); - cThread( ThreadFunc a_ThreadFunction, void* a_Param, const char* a_ThreadName = 0); - ~cThread(); - - void Start( bool a_bWaitOnDelete = true); - void WaitForThread(); -private: - ThreadFunc* m_ThreadFunction; - -#ifdef _WIN32 - static unsigned long MyThread(void* a_Param); -#else - static void *MyThread( void *lpParam); -#endif - - void* m_Param; - cEvent* m_Event; - cEvent* m_StopEvent; - - AString m_ThreadName; -}; diff --git a/src/OSSupport/Timer.cpp b/src/OSSupport/Timer.cpp deleted file mode 100644 index fd838dd0d..000000000 --- a/src/OSSupport/Timer.cpp +++ /dev/null @@ -1,37 +0,0 @@ - -#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules - -#include "Timer.h" - - - - - - -cTimer::cTimer(void) -{ - #ifdef _WIN32 - QueryPerformanceFrequency(&m_TicksPerSecond); - #endif -} - - - - - -long long cTimer::GetNowTime(void) -{ - #ifdef _WIN32 - LARGE_INTEGER now; - QueryPerformanceCounter(&now); - return ((now.QuadPart * 1000) / m_TicksPerSecond.QuadPart); - #else - struct timeval now; - gettimeofday(&now, NULL); - return (long long)now.tv_sec * 1000 + (long long)now.tv_usec / 1000; - #endif -} - - - - diff --git a/src/OSSupport/Timer.h b/src/OSSupport/Timer.h deleted file mode 100644 index a059daa41..000000000 --- a/src/OSSupport/Timer.h +++ /dev/null @@ -1,32 +0,0 @@ - -// Timer.h - -// Declares the cTimer class representing an OS-independent of retrieving current time with msec accuracy - - - - - -#pragma once - - - - - -class cTimer -{ -public: - cTimer(void); - - // Returns the current time expressed in milliseconds - long long GetNowTime(void); -private: - - #ifdef _WIN32 - LARGE_INTEGER m_TicksPerSecond; - #endif -} ; - - - - diff --git a/src/ProbabDistrib.cpp b/src/ProbabDistrib.cpp index 7a5869dcc..c34c75982 100644 --- a/src/ProbabDistrib.cpp +++ b/src/ProbabDistrib.cpp @@ -5,7 +5,7 @@ #include "Globals.h" #include "ProbabDistrib.h" -#include "MersenneTwister.h" +#include "FastRandom.h" diff --git a/src/Protocol/MojangAPI.cpp b/src/Protocol/MojangAPI.cpp index 67f513e44..570754204 100644 --- a/src/Protocol/MojangAPI.cpp +++ b/src/Protocol/MojangAPI.cpp @@ -161,26 +161,38 @@ class cMojangAPI::cUpdateThread : { typedef cIsThread super; public: - cUpdateThread() : - super("cMojangAPI::cUpdateThread") + cUpdateThread(cMojangAPI & a_MojangAPI) : + super("cMojangAPI::cUpdateThread"), + m_MojangAPI(a_MojangAPI) { } ~cUpdateThread() { + // Notify the thread that it should stop: + m_ShouldTerminate = true; m_evtNotify.Set(); + + // Wait for the thread to actually finish work: Stop(); } protected: + + /** The cMojangAPI instance to update. */ + cMojangAPI & m_MojangAPI; + + /** The event used for notifying that the thread should terminate, as well as timing. */ cEvent m_evtNotify; + + // cIsThread override: virtual void Execute(void) override { do { - cRoot::Get()->GetMojangAPI().Update(); - } while (!m_evtNotify.Wait(60 * 60 * 1000)); // Repeat every 60 minutes + m_MojangAPI.Update(); + } while (!m_ShouldTerminate && !m_evtNotify.Wait(60 * 60 * 1000)); // Repeat every 60 minutes until termination request } } ; @@ -197,7 +209,7 @@ cMojangAPI::cMojangAPI(void) : m_UUIDToProfileServer(DEFAULT_UUID_TO_PROFILE_SERVER), m_UUIDToProfileAddress(DEFAULT_UUID_TO_PROFILE_ADDRESS), m_RankMgr(nullptr), - m_UpdateThread(new cUpdateThread()) + m_UpdateThread(new cUpdateThread(*this)) { } diff --git a/src/Root.cpp b/src/Root.cpp index e309bb174..29daaedcc 100644 --- a/src/Root.cpp +++ b/src/Root.cpp @@ -16,7 +16,6 @@ #include "Protocol/ProtocolRecognizer.h" // for protocol version constants #include "CommandOutput.h" #include "DeadlockDetect.h" -#include "OSSupport/Timer.h" #include "LoggerListeners.h" #include "BuildInfo.h" #include "IniFile.h" @@ -42,7 +41,6 @@ cRoot* cRoot::s_Root = nullptr; cRoot::cRoot(void) : m_pDefaultWorld(nullptr), - m_InputThread(nullptr), m_Server(nullptr), m_MonsterConfig(nullptr), m_CraftingRecipes(nullptr), @@ -68,26 +66,24 @@ cRoot::~cRoot() -void cRoot::InputThread(void * a_Params) +void cRoot::InputThread(cRoot & a_Params) { - cRoot & self = *(cRoot*)a_Params; - cLogCommandOutputCallback Output; - while (!self.m_bStop && !self.m_bRestart && !m_TerminateEventRaised && std::cin.good()) + while (!a_Params.m_bStop && !a_Params.m_bRestart && !m_TerminateEventRaised && std::cin.good()) { AString Command; std::getline(std::cin, Command); if (!Command.empty()) { - self.ExecuteConsoleCommand(TrimString(Command), Output); + a_Params.ExecuteConsoleCommand(TrimString(Command), Output); } } if (m_TerminateEventRaised || !std::cin.good()) { // We have come here because the std::cin has received an EOF / a terminate signal has been sent, and the server is still running; stop the server: - self.m_bStop = true; + a_Params.m_bStop = true; } } @@ -120,9 +116,7 @@ void cRoot::Start(void) m_bStop = false; while (!m_bStop) { - cTimer Time; - long long mseconds = Time.GetNowTime(); - + auto BeginTime = std::chrono::steady_clock::now(); m_bRestart = false; LoadGlobalSettings(); @@ -191,21 +185,25 @@ void cRoot::Start(void) #if !defined(ANDROID_NDK) LOGD("Starting InputThread..."); - m_InputThread = new cThread( InputThread, this, "cRoot::InputThread"); - m_InputThread->Start( false); // We should NOT wait? Otherwise we can't stop the server from other threads than the input thread + try + { + m_InputThread = std::thread(InputThread, std::ref(*this)); + m_InputThread.detach(); + } + catch (std::system_error & a_Exception) + { + LOGERROR("cRoot::Start (std::thread) error %i: could not construct input thread; %s", a_Exception.code().value(), a_Exception.what()); + } #endif - long long finishmseconds = Time.GetNowTime(); - finishmseconds -= mseconds; - - LOG("Startup complete, took %lld ms!", finishmseconds); + LOG("Startup complete, took %ld ms!", std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - BeginTime).count()); #ifdef _WIN32 EnableMenuItem(hmenu, SC_CLOSE, MF_ENABLED); // Re-enable close button #endif while (!m_bStop && !m_bRestart && !m_TerminateEventRaised) // These are modified by external threads { - cSleep::MilliSleep(1000); + std::this_thread::sleep_for(std::chrono::seconds(1)); } if (m_TerminateEventRaised) @@ -213,10 +211,6 @@ void cRoot::Start(void) m_bStop = true; } - #if !defined(ANDROID_NDK) - delete m_InputThread; m_InputThread = nullptr; - #endif - // Stop the server: m_WebAdmin->Stop(); LOG("Shutting down server..."); @@ -649,6 +643,22 @@ bool cRoot::DoWithPlayerByUUID(const AString & a_PlayerUUID, cPlayerListCallback +bool cRoot::DoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback) +{ + for (auto World : m_WorldsByName) + { + if (World.second->DoWithPlayer(a_PlayerName, a_Callback)) + { + return true; + } + } + return false; +} + + + + + AString cRoot::GetProtocolVersionTextFromInt(int a_ProtocolVersion) { return cProtocolRecognizer::GetVersionTextFromInt(a_ProtocolVersion); diff --git a/src/Root.h b/src/Root.h index 29753a47d..2c512a5df 100644 --- a/src/Root.h +++ b/src/Root.h @@ -6,6 +6,7 @@ #include "HTTPServer/HTTPServer.h" #include "Defines.h" #include "RankManager.h" +#include <thread> @@ -128,7 +129,10 @@ public: /** Finds the player over his uuid and calls the callback */ bool DoWithPlayerByUUID(const AString & a_PlayerUUID, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS << - + + /** Finds the player using it's complete username and calls the callback */ + bool DoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback); + // tolua_begin /// Sends a chat message to all connected clients (in all worlds) @@ -177,7 +181,7 @@ private: cCriticalSection m_CSPendingCommands; cCommandQueue m_PendingCommands; - cThread * m_InputThread; + std::thread m_InputThread; cServer * m_Server; cMonsterConfig * m_MonsterConfig; @@ -212,10 +216,10 @@ private: /// Does the actual work of executing a command void DoExecuteConsoleCommand(const AString & a_Cmd); - - static void InputThread(void* a_Params); static cRoot* s_Root; + + static void InputThread(cRoot & a_Params); }; // tolua_export diff --git a/src/Server.cpp b/src/Server.cpp index bbb5ecff3..3eaf6e096 100644 --- a/src/Server.cpp +++ b/src/Server.cpp @@ -4,7 +4,6 @@ #include "Server.h" #include "ClientHandle.h" -#include "OSSupport/Timer.h" #include "Mobs/Monster.h" #include "OSSupport/Socket.h" #include "Root.h" @@ -20,8 +19,6 @@ #include "Protocol/ProtocolRecognizer.h" #include "CommandOutput.h" -#include "MersenneTwister.h" - #include "IniFile.h" #include "Vector3.h" @@ -75,22 +72,20 @@ cServer::cTickThread::cTickThread(cServer & a_Server) : void cServer::cTickThread::Execute(void) { - cTimer Timer; - - long long msPerTick = 50; - long long LastTime = Timer.GetNowTime(); + auto LastTime = std::chrono::steady_clock::now(); + static const auto msPerTick = std::chrono::milliseconds(50); while (!m_ShouldTerminate) { - long long NowTime = Timer.GetNowTime(); - float DeltaTime = (float)(NowTime-LastTime); - m_ShouldTerminate = !m_Server.Tick(DeltaTime); - long long TickTime = Timer.GetNowTime() - NowTime; + auto NowTime = std::chrono::steady_clock::now(); + auto msec = std::chrono::duration_cast<std::chrono::milliseconds>(NowTime - LastTime).count(); + m_ShouldTerminate = !m_Server.Tick(static_cast<float>(msec)); + auto TickTime = std::chrono::steady_clock::now() - NowTime; if (TickTime < msPerTick) { // Stretch tick time until it's at least msPerTick - cSleep::MilliSleep((unsigned int)(msPerTick - TickTime)); + std::this_thread::sleep_for(msPerTick - TickTime); } LastTime = NowTime; @@ -201,6 +196,7 @@ bool cServer::InitServer(cIniFile & a_SettingsIni, bool a_ShouldAuth) m_Description = a_SettingsIni.GetValueSet("Server", "Description", "MCServer - in C++!"); m_MaxPlayers = a_SettingsIni.GetValueSetI("Server", "MaxPlayers", 100); m_bIsHardcore = a_SettingsIni.GetValueSetB("Server", "HardcoreEnabled", false); + m_bAllowMultiLogin = a_SettingsIni.GetValueSetB("Server", "AllowMultiLogin", false); m_PlayerCount = 0; m_PlayerCountDiff = 0; @@ -303,6 +299,23 @@ int cServer::GetNumPlayers(void) const +bool cServer::IsPlayerInQueue(AString a_Username) +{ + cCSLock Lock(m_CSClients); + for (auto client : m_Clients) + { + if ((client->GetUsername()).compare(a_Username) == 0) + { + return true; + } + } + return false; +} + + + + + void cServer::PrepareKeys(void) { LOGD("Generating protocol encryption keypair..."); diff --git a/src/Server.h b/src/Server.h index 022794bbc..39a5a1a71 100644 --- a/src/Server.h +++ b/src/Server.h @@ -67,6 +67,14 @@ public: // tolua_export int GetNumPlayers(void) const; void SetMaxPlayers(int a_MaxPlayers) { m_MaxPlayers = a_MaxPlayers; } + /** Check if the player is queued to be transferred to a World. + Returns true is Player is found in queue. */ + bool IsPlayerInQueue(AString a_Username); + + /** Can login more than once with same username. + Returns false if it is not allowed, true otherwise. */ + bool DoesAllowMultiLogin(void) { return m_bAllowMultiLogin; } + // Hardcore mode or not: bool IsHardcore(void) const { return m_bIsHardcore; } @@ -216,6 +224,9 @@ private: int m_MaxPlayers; bool m_bIsHardcore; + /** True - allow same username to login more than once False - only once */ + bool m_bAllowMultiLogin; + cTickThread m_TickThread; cEvent m_RestartEvent; diff --git a/src/UI/SlotArea.cpp b/src/UI/SlotArea.cpp index ff934c049..e784569d9 100644 --- a/src/UI/SlotArea.cpp +++ b/src/UI/SlotArea.cpp @@ -2322,7 +2322,7 @@ cItem * cSlotAreaTemporary::GetPlayerSlots(cPlayer & a_Player) { return nullptr; } - return &(itr->second[0]); + return itr->second.data(); } diff --git a/src/World.cpp b/src/World.cpp index 4a741d37b..db19649f3 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) { @@ -178,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; } } @@ -239,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; @@ -354,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(); } @@ -747,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, Animals"); + 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: @@ -759,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", "SoulsandRims, WormNestCaves, BottomLava, LavaSprings, NetherClumpFoliage, NetherForts, PreSimulator"); + a_IniFile.GetValueSet("Generator", "Finishers", "SoulsandRims, WormNestCaves, BottomLava, LavaSprings, NetherClumpFoliage, NetherOreNests, NetherForts, PreSimulator"); a_IniFile.GetValueSet("Generator", "BottomLavaHeight", "30"); break; } @@ -3130,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); } @@ -3668,3 +3669,4 @@ void cWorld::cChunkGeneratorCallbacks::CallHookChunkGenerated (cChunkDesc & a_Ch + diff --git a/src/World.h b/src/World.h index 31bc9dad6..2f51d60a1 100644 --- a/src/World.h +++ b/src/World.h @@ -10,7 +10,6 @@ #define MAX_PLAYERS 65535 #include "Simulator/SimulatorManager.h" -#include "MersenneTwister.h" #include "ChunkMap.h" #include "WorldStorage/WorldStorage.h" #include "Generating/ChunkGenerator.h" @@ -26,6 +25,7 @@ #include "MapManager.h" #include "Blocks/WorldInterface.h" #include "Blocks/BroadcastInterface.h" +#include "FastRandom.h" #include "ClientHandle.h" @@ -808,7 +808,7 @@ public: This function allows nesting and task-concurrency (multiple separate tasks can request ticking and as long as at least one requests is active the chunk will be ticked). */ void SetChunkAlwaysTicked(int a_ChunkX, int a_ChunkZ, bool a_AlwaysTicked = true); // tolua_export - + private: friend class cRoot; diff --git a/src/WorldStorage/FireworksSerializer.cpp b/src/WorldStorage/FireworksSerializer.cpp index ecb600483..91a5b8b63 100644 --- a/src/WorldStorage/FireworksSerializer.cpp +++ b/src/WorldStorage/FireworksSerializer.cpp @@ -22,11 +22,11 @@ void cFireworkItem::WriteToNBTCompound(const cFireworkItem & a_FireworkItem, cFa a_Writer.AddByte("Type", a_FireworkItem.m_Type); if (!a_FireworkItem.m_Colours.empty()) { - a_Writer.AddIntArray("Colors", &(a_FireworkItem.m_Colours[0]), a_FireworkItem.m_Colours.size()); + a_Writer.AddIntArray("Colors", a_FireworkItem.m_Colours.data(), a_FireworkItem.m_Colours.size()); } if (!a_FireworkItem.m_FadeColours.empty()) { - a_Writer.AddIntArray("FadeColors", &(a_FireworkItem.m_FadeColours[0]), a_FireworkItem.m_FadeColours.size()); + a_Writer.AddIntArray("FadeColors", a_FireworkItem.m_FadeColours.data(), a_FireworkItem.m_FadeColours.size()); } a_Writer.EndCompound(); a_Writer.EndList(); @@ -41,11 +41,11 @@ void cFireworkItem::WriteToNBTCompound(const cFireworkItem & a_FireworkItem, cFa a_Writer.AddByte("Type", a_FireworkItem.m_Type); if (!a_FireworkItem.m_Colours.empty()) { - a_Writer.AddIntArray("Colors", &(a_FireworkItem.m_Colours[0]), a_FireworkItem.m_Colours.size()); + a_Writer.AddIntArray("Colors", a_FireworkItem.m_Colours.data(), a_FireworkItem.m_Colours.size()); } if (!a_FireworkItem.m_FadeColours.empty()) { - a_Writer.AddIntArray("FadeColors", &(a_FireworkItem.m_FadeColours[0]), a_FireworkItem.m_FadeColours.size()); + a_Writer.AddIntArray("FadeColors", a_FireworkItem.m_FadeColours.data(), a_FireworkItem.m_FadeColours.size()); } a_Writer.EndCompound(); break; diff --git a/src/WorldStorage/MapSerializer.cpp b/src/WorldStorage/MapSerializer.cpp index 4a913c81a..f2d35b318 100644 --- a/src/WorldStorage/MapSerializer.cpp +++ b/src/WorldStorage/MapSerializer.cpp @@ -112,7 +112,7 @@ void cMapSerializer::SaveMapToNBT(cFastNBTWriter & a_Writer) a_Writer.AddInt("zCenter", m_Map->GetCenterZ()); const cMap::cColorList & Data = m_Map->GetData(); - a_Writer.AddByteArray("colors", (char *) &Data[0], Data.size()); + a_Writer.AddByteArray("colors", (char *)Data.data(), Data.size()); a_Writer.EndCompound(); } @@ -190,7 +190,7 @@ bool cMapSerializer::LoadMapFromNBT(const cParsedNBT & a_NBT) CurrLine = a_NBT.FindChildByName(Data, "colors"); if ((CurrLine >= 0) && (a_NBT.GetType(CurrLine) == TAG_ByteArray)) { - memcpy(&m_Map->m_Data[0], a_NBT.GetData(CurrLine), NumPixels); + memcpy(m_Map->m_Data.data(), a_NBT.GetData(CurrLine), NumPixels); } return true; diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp index a44adea1e..ad875b4cb 100755 --- a/src/WorldStorage/WSSAnvil.cpp +++ b/src/WorldStorage/WSSAnvil.cpp @@ -631,7 +631,7 @@ void cWSSAnvil::LoadBlockEntitiesFromNBT(cBlockEntityList & a_BlockEntities, con // Load the proper BlockEntity type based on the block type: BLOCKTYPE BlockType = cChunkDef::GetBlock(a_BlockTypes, RelX, RelY, RelZ); NIBBLETYPE BlockMeta = cChunkDef::GetNibble(a_BlockMetas, RelX, RelY, RelZ); - std::auto_ptr<cBlockEntity> be(LoadBlockEntityFromNBT(a_NBT, Child, x, y, z, BlockType, BlockMeta)); + std::unique_ptr<cBlockEntity> be(LoadBlockEntityFromNBT(a_NBT, Child, x, y, z, BlockType, BlockMeta)); if (be.get() == nullptr) { continue; @@ -858,7 +858,7 @@ cBlockEntity * cWSSAnvil::LoadBeaconFromNBT(const cParsedNBT & a_NBT, int a_TagI return nullptr; } - std::auto_ptr<cBeaconEntity> Beacon(new cBeaconEntity(a_BlockX, a_BlockY, a_BlockZ, m_World)); + std::unique_ptr<cBeaconEntity> Beacon(new cBeaconEntity(a_BlockX, a_BlockY, a_BlockZ, m_World)); int CurrentLine = a_NBT.FindChildByName(a_TagIdx, "Levels"); if (CurrentLine >= 0) @@ -908,7 +908,7 @@ cBlockEntity * cWSSAnvil::LoadChestFromNBT(const cParsedNBT & a_NBT, int a_TagId { return nullptr; // Make it an empty chest - the chunk loader will provide an empty cChestEntity for this } - std::auto_ptr<cChestEntity> Chest(new cChestEntity(a_BlockX, a_BlockY, a_BlockZ, m_World, a_ChestBlockType)); + std::unique_ptr<cChestEntity> Chest(new cChestEntity(a_BlockX, a_BlockY, a_BlockZ, m_World, a_ChestBlockType)); LoadItemGridFromNBT(Chest->GetContents(), a_NBT, Items); return Chest.release(); } @@ -925,7 +925,7 @@ cBlockEntity * cWSSAnvil::LoadCommandBlockFromNBT(const cParsedNBT & a_NBT, int return nullptr; } - std::auto_ptr<cCommandBlockEntity> CmdBlock(new cCommandBlockEntity(a_BlockX, a_BlockY, a_BlockZ, m_World)); + std::unique_ptr<cCommandBlockEntity> CmdBlock(new cCommandBlockEntity(a_BlockX, a_BlockY, a_BlockZ, m_World)); int currentLine = a_NBT.FindChildByName(a_TagIdx, "Command"); if (currentLine >= 0) @@ -967,7 +967,7 @@ cBlockEntity * cWSSAnvil::LoadDispenserFromNBT(const cParsedNBT & a_NBT, int a_T { return nullptr; // Make it an empty dispenser - the chunk loader will provide an empty cDispenserEntity for this } - std::auto_ptr<cDispenserEntity> Dispenser(new cDispenserEntity(a_BlockX, a_BlockY, a_BlockZ, m_World)); + std::unique_ptr<cDispenserEntity> Dispenser(new cDispenserEntity(a_BlockX, a_BlockY, a_BlockZ, m_World)); LoadItemGridFromNBT(Dispenser->GetContents(), a_NBT, Items); return Dispenser.release(); } @@ -989,7 +989,7 @@ cBlockEntity * cWSSAnvil::LoadDropperFromNBT(const cParsedNBT & a_NBT, int a_Tag { return nullptr; // Make it an empty dropper - the chunk loader will provide an empty cDropperEntity for this } - std::auto_ptr<cDropperEntity> Dropper(new cDropperEntity(a_BlockX, a_BlockY, a_BlockZ, m_World)); + std::unique_ptr<cDropperEntity> Dropper(new cDropperEntity(a_BlockX, a_BlockY, a_BlockZ, m_World)); LoadItemGridFromNBT(Dropper->GetContents(), a_NBT, Items); return Dropper.release(); } @@ -1006,7 +1006,7 @@ cBlockEntity * cWSSAnvil::LoadFlowerPotFromNBT(const cParsedNBT & a_NBT, int a_T return nullptr; } - std::auto_ptr<cFlowerPotEntity> FlowerPot(new cFlowerPotEntity(a_BlockX, a_BlockY, a_BlockZ, m_World)); + std::unique_ptr<cFlowerPotEntity> FlowerPot(new cFlowerPotEntity(a_BlockX, a_BlockY, a_BlockZ, m_World)); short ItemType = 0, ItemData = 0; int currentLine = a_NBT.FindChildByName(a_TagIdx, "Item"); @@ -1043,7 +1043,7 @@ cBlockEntity * cWSSAnvil::LoadFurnaceFromNBT(const cParsedNBT & a_NBT, int a_Tag return nullptr; // Make it an empty furnace - the chunk loader will provide an empty cFurnaceEntity for this } - std::auto_ptr<cFurnaceEntity> Furnace(new cFurnaceEntity(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, m_World)); + std::unique_ptr<cFurnaceEntity> Furnace(new cFurnaceEntity(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, m_World)); // Load slots: for (int Child = a_NBT.GetFirstChild(Items); Child != -1; Child = a_NBT.GetNextSibling(Child)) @@ -1148,7 +1148,7 @@ cBlockEntity * cWSSAnvil::LoadHopperFromNBT(const cParsedNBT & a_NBT, int a_TagI { return nullptr; // Make it an empty hopper - the chunk loader will provide an empty cHopperEntity for this } - std::auto_ptr<cHopperEntity> Hopper(new cHopperEntity(a_BlockX, a_BlockY, a_BlockZ, m_World)); + std::unique_ptr<cHopperEntity> Hopper(new cHopperEntity(a_BlockX, a_BlockY, a_BlockZ, m_World)); LoadItemGridFromNBT(Hopper->GetContents(), a_NBT, Items); return Hopper.release(); } @@ -1165,7 +1165,7 @@ cBlockEntity * cWSSAnvil::LoadJukeboxFromNBT(const cParsedNBT & a_NBT, int a_Tag return nullptr; } - std::auto_ptr<cJukeboxEntity> Jukebox(new cJukeboxEntity(a_BlockX, a_BlockY, a_BlockZ, m_World)); + std::unique_ptr<cJukeboxEntity> Jukebox(new cJukeboxEntity(a_BlockX, a_BlockY, a_BlockZ, m_World)); int Record = a_NBT.FindChildByName(a_TagIdx, "Record"); if (Record >= 0) { @@ -1186,7 +1186,7 @@ cBlockEntity * cWSSAnvil::LoadMobHeadFromNBT(const cParsedNBT & a_NBT, int a_Tag return nullptr; } - std::auto_ptr<cMobHeadEntity> MobHead(new cMobHeadEntity(a_BlockX, a_BlockY, a_BlockZ, m_World)); + std::unique_ptr<cMobHeadEntity> MobHead(new cMobHeadEntity(a_BlockX, a_BlockY, a_BlockZ, m_World)); int currentLine = a_NBT.FindChildByName(a_TagIdx, "SkullType"); if (currentLine >= 0) @@ -1221,7 +1221,7 @@ cBlockEntity * cWSSAnvil::LoadNoteBlockFromNBT(const cParsedNBT & a_NBT, int a_T return nullptr; } - std::auto_ptr<cNoteEntity> NoteBlock(new cNoteEntity(a_BlockX, a_BlockY, a_BlockZ, m_World)); + std::unique_ptr<cNoteEntity> NoteBlock(new cNoteEntity(a_BlockX, a_BlockY, a_BlockZ, m_World)); int note = a_NBT.FindChildByName(a_TagIdx, "note"); if (note >= 0) { @@ -1242,7 +1242,7 @@ cBlockEntity * cWSSAnvil::LoadSignFromNBT(const cParsedNBT & a_NBT, int a_TagIdx return nullptr; } - std::auto_ptr<cSignEntity> Sign(new cSignEntity(a_BlockType, a_BlockX, a_BlockY, a_BlockZ, m_World)); + std::unique_ptr<cSignEntity> Sign(new cSignEntity(a_BlockType, a_BlockX, a_BlockY, a_BlockZ, m_World)); int currentLine = a_NBT.FindChildByName(a_TagIdx, "Text1"); if (currentLine >= 0) @@ -1495,7 +1495,7 @@ void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a void cWSSAnvil::LoadBoatFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cBoat> Boat(new cBoat(0, 0, 0)); + std::unique_ptr<cBoat> Boat(new cBoat(0, 0, 0)); if (!LoadEntityBaseFromNBT(*Boat.get(), a_NBT, a_TagIdx)) { return; @@ -1509,7 +1509,7 @@ void cWSSAnvil::LoadBoatFromNBT(cEntityList & a_Entities, const cParsedNBT & a_N void cWSSAnvil::LoadEnderCrystalFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cEnderCrystal> EnderCrystal(new cEnderCrystal(0, 0, 0)); + std::unique_ptr<cEnderCrystal> EnderCrystal(new cEnderCrystal(0, 0, 0)); if (!LoadEntityBaseFromNBT(*EnderCrystal.get(), a_NBT, a_TagIdx)) { return; @@ -1534,7 +1534,7 @@ void cWSSAnvil::LoadFallingBlockFromNBT(cEntityList & a_Entities, const cParsedN int Type = a_NBT.GetInt(TypeIdx); NIBBLETYPE Meta = (NIBBLETYPE)a_NBT.GetByte(MetaIdx); - std::auto_ptr<cFallingBlock> FallingBlock(new cFallingBlock(Vector3i(0, 0, 0), Type, Meta)); + std::unique_ptr<cFallingBlock> FallingBlock(new cFallingBlock(Vector3i(0, 0, 0), Type, Meta)); if (!LoadEntityBaseFromNBT(*FallingBlock.get(), a_NBT, a_TagIdx)) { return; @@ -1548,7 +1548,7 @@ void cWSSAnvil::LoadFallingBlockFromNBT(cEntityList & a_Entities, const cParsedN void cWSSAnvil::LoadMinecartRFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cRideableMinecart> Minecart(new cRideableMinecart(0, 0, 0, cItem(), 1)); // TODO: Load the block and the height + std::unique_ptr<cRideableMinecart> Minecart(new cRideableMinecart(0, 0, 0, cItem(), 1)); // TODO: Load the block and the height if (!LoadEntityBaseFromNBT(*Minecart.get(), a_NBT, a_TagIdx)) { return; @@ -1567,7 +1567,7 @@ void cWSSAnvil::LoadMinecartCFromNBT(cEntityList & a_Entities, const cParsedNBT { return; // Make it an empty chest - the chunk loader will provide an empty cChestEntity for this } - std::auto_ptr<cMinecartWithChest> Minecart(new cMinecartWithChest(0, 0, 0)); + std::unique_ptr<cMinecartWithChest> Minecart(new cMinecartWithChest(0, 0, 0)); if (!LoadEntityBaseFromNBT(*Minecart.get(), a_NBT, a_TagIdx)) { return; @@ -1594,7 +1594,7 @@ void cWSSAnvil::LoadMinecartCFromNBT(cEntityList & a_Entities, const cParsedNBT void cWSSAnvil::LoadMinecartFFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cMinecartWithFurnace> Minecart(new cMinecartWithFurnace(0, 0, 0)); + std::unique_ptr<cMinecartWithFurnace> Minecart(new cMinecartWithFurnace(0, 0, 0)); if (!LoadEntityBaseFromNBT(*Minecart.get(), a_NBT, a_TagIdx)) { return; @@ -1611,7 +1611,7 @@ void cWSSAnvil::LoadMinecartFFromNBT(cEntityList & a_Entities, const cParsedNBT void cWSSAnvil::LoadMinecartTFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cMinecartWithTNT> Minecart(new cMinecartWithTNT(0, 0, 0)); + std::unique_ptr<cMinecartWithTNT> Minecart(new cMinecartWithTNT(0, 0, 0)); if (!LoadEntityBaseFromNBT(*Minecart.get(), a_NBT, a_TagIdx)) { return; @@ -1628,7 +1628,7 @@ void cWSSAnvil::LoadMinecartTFromNBT(cEntityList & a_Entities, const cParsedNBT void cWSSAnvil::LoadMinecartHFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cMinecartWithHopper> Minecart(new cMinecartWithHopper(0, 0, 0)); + std::unique_ptr<cMinecartWithHopper> Minecart(new cMinecartWithHopper(0, 0, 0)); if (!LoadEntityBaseFromNBT(*Minecart.get(), a_NBT, a_TagIdx)) { return; @@ -1657,7 +1657,7 @@ void cWSSAnvil::LoadPickupFromNBT(cEntityList & a_Entities, const cParsedNBT & a return; } - std::auto_ptr<cPickup> Pickup(new cPickup(0, 0, 0, Item, false)); // Pickup delay doesn't matter, just say false + std::unique_ptr<cPickup> Pickup(new cPickup(0, 0, 0, Item, false)); // Pickup delay doesn't matter, just say false if (!LoadEntityBaseFromNBT(*Pickup.get(), a_NBT, a_TagIdx)) { return; @@ -1679,7 +1679,7 @@ void cWSSAnvil::LoadPickupFromNBT(cEntityList & a_Entities, const cParsedNBT & a void cWSSAnvil::LoadTNTFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cTNTEntity> TNT(new cTNTEntity(0.0, 0.0, 0.0, 0)); + std::unique_ptr<cTNTEntity> TNT(new cTNTEntity(0.0, 0.0, 0.0, 0)); if (!LoadEntityBaseFromNBT(*TNT.get(), a_NBT, a_TagIdx)) { return; @@ -1701,7 +1701,7 @@ void cWSSAnvil::LoadTNTFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NB void cWSSAnvil::LoadExpOrbFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cExpOrb> ExpOrb(new cExpOrb(0.0, 0.0, 0.0, 0)); + std::unique_ptr<cExpOrb> ExpOrb(new cExpOrb(0.0, 0.0, 0.0, 0)); if (!LoadEntityBaseFromNBT(*ExpOrb.get(), a_NBT, a_TagIdx)) { return; @@ -1800,7 +1800,7 @@ void cWSSAnvil::LoadItemFrameFromNBT(cEntityList & a_Entities, const cParsedNBT return; } - std::auto_ptr<cItemFrame> ItemFrame(new cItemFrame(BLOCK_FACE_NONE, 0.0, 0.0, 0.0)); + std::unique_ptr<cItemFrame> ItemFrame(new cItemFrame(BLOCK_FACE_NONE, 0.0, 0.0, 0.0)); if (!LoadEntityBaseFromNBT(*ItemFrame.get(), a_NBT, a_TagIdx)) { return; @@ -1825,7 +1825,7 @@ void cWSSAnvil::LoadItemFrameFromNBT(cEntityList & a_Entities, const cParsedNBT void cWSSAnvil::LoadArrowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cArrowEntity> Arrow(new cArrowEntity(nullptr, 0, 0, 0, Vector3d(0, 0, 0))); + std::unique_ptr<cArrowEntity> Arrow(new cArrowEntity(nullptr, 0, 0, 0, Vector3d(0, 0, 0))); if (!LoadProjectileBaseFromNBT(*Arrow.get(), a_NBT, a_TagIdx)) { return; @@ -1895,7 +1895,7 @@ void cWSSAnvil::LoadArrowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_ void cWSSAnvil::LoadSplashPotionFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cSplashPotionEntity> SplashPotion(new cSplashPotionEntity(nullptr, 0, 0, 0, Vector3d(0, 0, 0), cItem())); + std::unique_ptr<cSplashPotionEntity> SplashPotion(new cSplashPotionEntity(nullptr, 0, 0, 0, Vector3d(0, 0, 0), cItem())); if (!LoadProjectileBaseFromNBT(*SplashPotion.get(), a_NBT, a_TagIdx)) { return; @@ -1919,7 +1919,7 @@ void cWSSAnvil::LoadSplashPotionFromNBT(cEntityList & a_Entities, const cParsedN void cWSSAnvil::LoadSnowballFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cThrownSnowballEntity> Snowball(new cThrownSnowballEntity(nullptr, 0, 0, 0, Vector3d(0, 0, 0))); + std::unique_ptr<cThrownSnowballEntity> Snowball(new cThrownSnowballEntity(nullptr, 0, 0, 0, Vector3d(0, 0, 0))); if (!LoadProjectileBaseFromNBT(*Snowball.get(), a_NBT, a_TagIdx)) { return; @@ -1935,7 +1935,7 @@ void cWSSAnvil::LoadSnowballFromNBT(cEntityList & a_Entities, const cParsedNBT & void cWSSAnvil::LoadEggFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cThrownEggEntity> Egg(new cThrownEggEntity(nullptr, 0, 0, 0, Vector3d(0, 0, 0))); + std::unique_ptr<cThrownEggEntity> Egg(new cThrownEggEntity(nullptr, 0, 0, 0, Vector3d(0, 0, 0))); if (!LoadProjectileBaseFromNBT(*Egg.get(), a_NBT, a_TagIdx)) { return; @@ -1951,7 +1951,7 @@ void cWSSAnvil::LoadEggFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NB void cWSSAnvil::LoadFireballFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cGhastFireballEntity> Fireball(new cGhastFireballEntity(nullptr, 0, 0, 0, Vector3d(0, 0, 0))); + std::unique_ptr<cGhastFireballEntity> Fireball(new cGhastFireballEntity(nullptr, 0, 0, 0, Vector3d(0, 0, 0))); if (!LoadProjectileBaseFromNBT(*Fireball.get(), a_NBT, a_TagIdx)) { return; @@ -1967,7 +1967,7 @@ void cWSSAnvil::LoadFireballFromNBT(cEntityList & a_Entities, const cParsedNBT & void cWSSAnvil::LoadFireChargeFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cFireChargeEntity> FireCharge(new cFireChargeEntity(nullptr, 0, 0, 0, Vector3d(0, 0, 0))); + std::unique_ptr<cFireChargeEntity> FireCharge(new cFireChargeEntity(nullptr, 0, 0, 0, Vector3d(0, 0, 0))); if (!LoadProjectileBaseFromNBT(*FireCharge.get(), a_NBT, a_TagIdx)) { return; @@ -1983,7 +1983,7 @@ void cWSSAnvil::LoadFireChargeFromNBT(cEntityList & a_Entities, const cParsedNBT void cWSSAnvil::LoadThrownEnderpearlFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cThrownEnderPearlEntity> Enderpearl(new cThrownEnderPearlEntity(nullptr, 0, 0, 0, Vector3d(0, 0, 0))); + std::unique_ptr<cThrownEnderPearlEntity> Enderpearl(new cThrownEnderPearlEntity(nullptr, 0, 0, 0, Vector3d(0, 0, 0))); if (!LoadProjectileBaseFromNBT(*Enderpearl.get(), a_NBT, a_TagIdx)) { return; @@ -1999,7 +1999,7 @@ void cWSSAnvil::LoadThrownEnderpearlFromNBT(cEntityList & a_Entities, const cPar void cWSSAnvil::LoadBatFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cBat> Monster(new cBat()); + std::unique_ptr<cBat> Monster(new cBat()); if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) { return; @@ -2019,7 +2019,7 @@ void cWSSAnvil::LoadBatFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NB void cWSSAnvil::LoadBlazeFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cBlaze> Monster(new cBlaze()); + std::unique_ptr<cBlaze> Monster(new cBlaze()); if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) { return; @@ -2039,7 +2039,7 @@ void cWSSAnvil::LoadBlazeFromNBT(cEntityList & a_Entities, const cParsedNBT & a_ void cWSSAnvil::LoadCaveSpiderFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cCaveSpider> Monster(new cCaveSpider()); + std::unique_ptr<cCaveSpider> Monster(new cCaveSpider()); if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) { return; @@ -2059,7 +2059,7 @@ void cWSSAnvil::LoadCaveSpiderFromNBT(cEntityList & a_Entities, const cParsedNBT void cWSSAnvil::LoadChickenFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cChicken> Monster(new cChicken()); + std::unique_ptr<cChicken> Monster(new cChicken()); if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) { return; @@ -2079,7 +2079,7 @@ void cWSSAnvil::LoadChickenFromNBT(cEntityList & a_Entities, const cParsedNBT & void cWSSAnvil::LoadCowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cCow> Monster(new cCow()); + std::unique_ptr<cCow> Monster(new cCow()); if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) { return; @@ -2099,7 +2099,7 @@ void cWSSAnvil::LoadCowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NB void cWSSAnvil::LoadCreeperFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cCreeper> Monster(new cCreeper()); + std::unique_ptr<cCreeper> Monster(new cCreeper()); if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) { return; @@ -2119,7 +2119,7 @@ void cWSSAnvil::LoadCreeperFromNBT(cEntityList & a_Entities, const cParsedNBT & void cWSSAnvil::LoadEnderDragonFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cEnderDragon> Monster(new cEnderDragon()); + std::unique_ptr<cEnderDragon> Monster(new cEnderDragon()); if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) { return; @@ -2139,7 +2139,7 @@ void cWSSAnvil::LoadEnderDragonFromNBT(cEntityList & a_Entities, const cParsedNB void cWSSAnvil::LoadEndermanFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cEnderman> Monster(new cEnderman()); + std::unique_ptr<cEnderman> Monster(new cEnderman()); if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) { return; @@ -2159,7 +2159,7 @@ void cWSSAnvil::LoadEndermanFromNBT(cEntityList & a_Entities, const cParsedNBT & void cWSSAnvil::LoadGhastFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cGhast> Monster(new cGhast()); + std::unique_ptr<cGhast> Monster(new cGhast()); if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) { return; @@ -2179,7 +2179,7 @@ void cWSSAnvil::LoadGhastFromNBT(cEntityList & a_Entities, const cParsedNBT & a_ void cWSSAnvil::LoadGiantFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cGiant> Monster(new cGiant()); + std::unique_ptr<cGiant> Monster(new cGiant()); if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) { return; @@ -2211,7 +2211,7 @@ void cWSSAnvil::LoadHorseFromNBT(cEntityList & a_Entities, const cParsedNBT & a_ int Color = a_NBT.GetInt(ColorIdx); int Style = a_NBT.GetInt(StyleIdx); - std::auto_ptr<cHorse> Monster(new cHorse(Type, Color, Style, 1)); + std::unique_ptr<cHorse> Monster(new cHorse(Type, Color, Style, 1)); if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) { @@ -2232,7 +2232,7 @@ void cWSSAnvil::LoadHorseFromNBT(cEntityList & a_Entities, const cParsedNBT & a_ void cWSSAnvil::LoadIronGolemFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cIronGolem> Monster(new cIronGolem()); + std::unique_ptr<cIronGolem> Monster(new cIronGolem()); if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) { return; @@ -2261,7 +2261,7 @@ void cWSSAnvil::LoadMagmaCubeFromNBT(cEntityList & a_Entities, const cParsedNBT int Size = a_NBT.GetInt(SizeIdx); - std::auto_ptr<cMagmaCube> Monster(new cMagmaCube(Size)); + std::unique_ptr<cMagmaCube> Monster(new cMagmaCube(Size)); if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) { return; @@ -2281,7 +2281,7 @@ void cWSSAnvil::LoadMagmaCubeFromNBT(cEntityList & a_Entities, const cParsedNBT void cWSSAnvil::LoadMooshroomFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cMooshroom> Monster(new cMooshroom()); + std::unique_ptr<cMooshroom> Monster(new cMooshroom()); if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) { return; @@ -2301,7 +2301,7 @@ void cWSSAnvil::LoadMooshroomFromNBT(cEntityList & a_Entities, const cParsedNBT void cWSSAnvil::LoadOcelotFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cOcelot> Monster(new cOcelot()); + std::unique_ptr<cOcelot> Monster(new cOcelot()); if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) { return; @@ -2321,7 +2321,7 @@ void cWSSAnvil::LoadOcelotFromNBT(cEntityList & a_Entities, const cParsedNBT & a void cWSSAnvil::LoadPigFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cPig> Monster(new cPig()); + std::unique_ptr<cPig> Monster(new cPig()); if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) { return; @@ -2348,7 +2348,7 @@ void cWSSAnvil::LoadSheepFromNBT(cEntityList & a_Entities, const cParsedNBT & a_ Color = (int)a_NBT.GetByte(ColorIdx); } - std::auto_ptr<cSheep> Monster(new cSheep(Color)); + std::unique_ptr<cSheep> Monster(new cSheep(Color)); if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) { return; @@ -2374,7 +2374,7 @@ void cWSSAnvil::LoadSheepFromNBT(cEntityList & a_Entities, const cParsedNBT & a_ void cWSSAnvil::LoadSilverfishFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cSilverfish> Monster(new cSilverfish()); + std::unique_ptr<cSilverfish> Monster(new cSilverfish()); if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) { return; @@ -2402,7 +2402,7 @@ void cWSSAnvil::LoadSkeletonFromNBT(cEntityList & a_Entities, const cParsedNBT & bool Type = ((a_NBT.GetByte(TypeIdx) == 1) ? true : false); - std::auto_ptr<cSkeleton> Monster(new cSkeleton(Type)); + std::unique_ptr<cSkeleton> Monster(new cSkeleton(Type)); if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) { return; @@ -2431,7 +2431,7 @@ void cWSSAnvil::LoadSlimeFromNBT(cEntityList & a_Entities, const cParsedNBT & a_ int Size = a_NBT.GetInt(SizeIdx); - std::auto_ptr<cSlime> Monster(new cSlime(Size)); + std::unique_ptr<cSlime> Monster(new cSlime(Size)); if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) { return; @@ -2451,7 +2451,7 @@ void cWSSAnvil::LoadSlimeFromNBT(cEntityList & a_Entities, const cParsedNBT & a_ void cWSSAnvil::LoadSnowGolemFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cSnowGolem> Monster(new cSnowGolem()); + std::unique_ptr<cSnowGolem> Monster(new cSnowGolem()); if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) { return; @@ -2471,7 +2471,7 @@ void cWSSAnvil::LoadSnowGolemFromNBT(cEntityList & a_Entities, const cParsedNBT void cWSSAnvil::LoadSpiderFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cSpider> Monster(new cSpider()); + std::unique_ptr<cSpider> Monster(new cSpider()); if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) { return; @@ -2491,7 +2491,7 @@ void cWSSAnvil::LoadSpiderFromNBT(cEntityList & a_Entities, const cParsedNBT & a void cWSSAnvil::LoadSquidFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cSquid> Monster(new cSquid()); + std::unique_ptr<cSquid> Monster(new cSquid()); if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) { return; @@ -2519,7 +2519,7 @@ void cWSSAnvil::LoadVillagerFromNBT(cEntityList & a_Entities, const cParsedNBT & int Type = a_NBT.GetInt(TypeIdx); - std::auto_ptr<cVillager> Monster(new cVillager(cVillager::eVillagerType(Type))); + std::unique_ptr<cVillager> Monster(new cVillager(cVillager::eVillagerType(Type))); if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) { return; @@ -2539,7 +2539,7 @@ void cWSSAnvil::LoadVillagerFromNBT(cEntityList & a_Entities, const cParsedNBT & void cWSSAnvil::LoadWitchFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cWitch> Monster(new cWitch()); + std::unique_ptr<cWitch> Monster(new cWitch()); if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) { return; @@ -2559,7 +2559,7 @@ void cWSSAnvil::LoadWitchFromNBT(cEntityList & a_Entities, const cParsedNBT & a_ void cWSSAnvil::LoadWitherFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cWither> Monster(new cWither()); + std::unique_ptr<cWither> Monster(new cWither()); if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) { return; @@ -2585,7 +2585,7 @@ void cWSSAnvil::LoadWitherFromNBT(cEntityList & a_Entities, const cParsedNBT & a void cWSSAnvil::LoadWolfFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cWolf> Monster(new cWolf()); + std::unique_ptr<cWolf> Monster(new cWolf()); if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) { return; @@ -2646,7 +2646,7 @@ void cWSSAnvil::LoadZombieFromNBT(cEntityList & a_Entities, const cParsedNBT & a bool IsVillagerZombie = ((a_NBT.GetByte(IsVillagerIdx) == 1) ? true : false); - std::auto_ptr<cZombie> Monster(new cZombie(IsVillagerZombie)); + std::unique_ptr<cZombie> Monster(new cZombie(IsVillagerZombie)); if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) { return; @@ -2666,7 +2666,7 @@ void cWSSAnvil::LoadZombieFromNBT(cEntityList & a_Entities, const cParsedNBT & a void cWSSAnvil::LoadPigZombieFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cZombiePigman> Monster(new cZombiePigman()); + std::unique_ptr<cZombiePigman> Monster(new cZombiePigman()); if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) { return; diff --git a/src/main.cpp b/src/main.cpp index fe4b360a5..d4adc1ed9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -163,9 +163,9 @@ BOOL CtrlHandler(DWORD fdwCtrlType) cRoot::m_TerminateEventRaised = true; LOGD("Terminate event raised from the Windows CtrlHandler"); - if (fdwCtrlType == CTRL_CLOSE_EVENT) // Console window closed via 'x' button, Windows will try to close immediately, therefore... + while (!g_ServerTerminated) { - while (!g_ServerTerminated) { cSleep::MilliSleep(100); } // Delay as much as possible to try to get the server to shut down cleanly + std::this_thread::sleep_for(std::chrono::milliseconds(50)); // Delay as much as possible to try to get the server to shut down cleanly } return TRUE; |