From eb9d45e9065a94c93dc2f1624c22f026b9be3d5f Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sun, 11 Aug 2013 19:18:06 +0200 Subject: Moved MaxPlayers and Description from cWorld to cServer. Also started creating a new cWorld::cTickThread class, but not used yet. --- source/Server.cpp | 64 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 35 insertions(+), 29 deletions(-) (limited to 'source/Server.cpp') diff --git a/source/Server.cpp b/source/Server.cpp index b07c65f04..509c84af3 100644 --- a/source/Server.cpp +++ b/source/Server.cpp @@ -76,6 +76,38 @@ struct cServer::sServerState +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cServer: + +cServer::cServer(void) : + m_pState(new sServerState), + m_ListenThreadIPv4(*this, cSocket::IPv4, "Client"), + m_ListenThreadIPv6(*this, cSocket::IPv6, "Client"), + m_Millisecondsf(0), + m_Milliseconds(0), + m_bIsConnected(false), + m_bRestarting(false), + m_RCONServer(*this) +{ +} + + + + + +cServer::~cServer() +{ + // TODO: Shut down the server gracefully + m_pState->bStopTickThread = true; + delete m_pState->pTickThread; m_pState->pTickThread = NULL; + + delete m_pState; +} + + + + + void cServer::ClientDestroying(const cClientHandle * a_Client) { m_SocketThreads.StopReading(a_Client); @@ -123,6 +155,9 @@ void cServer::RemoveClient(const cClientHandle * a_Client) bool cServer::InitServer(cIniFile & a_SettingsIni) { + m_Description = a_SettingsIni.GetValue ("Server", "Description", "MCServer! - In C++!").c_str(); + m_MaxPlayers = a_SettingsIni.GetValueI("Server", "MaxPlayers", 100); + if (m_bIsConnected) { LOGERROR("ERROR: Trying to initialize server while server is already running!"); @@ -201,35 +236,6 @@ bool cServer::InitServer(cIniFile & a_SettingsIni) -cServer::cServer(void) - : m_pState(new sServerState) - , m_ListenThreadIPv4(*this, cSocket::IPv4, "Client") - , m_ListenThreadIPv6(*this, cSocket::IPv6, "Client") - , m_Millisecondsf(0) - , m_Milliseconds(0) - , m_bIsConnected(false) - , m_bRestarting(false) - , m_RCONServer(*this) -{ -} - - - - - -cServer::~cServer() -{ - // TODO: Shut down the server gracefully - m_pState->bStopTickThread = true; - delete m_pState->pTickThread; m_pState->pTickThread = NULL; - - delete m_pState; -} - - - - - void cServer::PrepareKeys(void) { // TODO: Save and load key for persistence across sessions -- cgit v1.2.3 From c59d80a2af12d902577ea8cb022e81dd0740247f Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sun, 11 Aug 2013 19:46:27 +0200 Subject: Removed cServer::m_pState, dissolved into direct member variables. The server tick thread is now in the cServer::cTickThread object. --- source/Server.cpp | 141 +++++++++++++++++++----------------------------------- 1 file changed, 50 insertions(+), 91 deletions(-) (limited to 'source/Server.cpp') diff --git a/source/Server.cpp b/source/Server.cpp index 509c84af3..4247a1dfe 100644 --- a/source/Server.cpp +++ b/source/Server.cpp @@ -59,18 +59,42 @@ typedef std::list< cClientHandle* > ClientList; -struct cServer::sServerState +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cServer::cTickThread: + +cServer::cTickThread::cTickThread(cServer & a_Server) : + super("ServerTickThread"), + m_Server(a_Server) +{ +} + + + + + +void cServer::cTickThread::Execute(void) { - sServerState() - : pTickThread(NULL) - , bStopTickThread(false) - {} + cTimer Timer; - cThread* pTickThread; bool bStopTickThread; + long long msPerTick = 50; // TODO - Put this in server config file + long long LastTime = Timer.GetNowTime(); + + 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; + + if (TickTime < msPerTick) + { + // Stretch tick time until it's at least msPerTick + cSleep::MilliSleep((unsigned int)(msPerTick - TickTime)); + } - cEvent RestartEvent; - std::string ServerID; -}; + LastTime = NowTime; + } +} @@ -80,28 +104,13 @@ struct cServer::sServerState // cServer: cServer::cServer(void) : - m_pState(new sServerState), m_ListenThreadIPv4(*this, cSocket::IPv4, "Client"), m_ListenThreadIPv6(*this, cSocket::IPv6, "Client"), - m_Millisecondsf(0), - m_Milliseconds(0), m_bIsConnected(false), m_bRestarting(false), - m_RCONServer(*this) -{ -} - - - - - -cServer::~cServer() + m_RCONServer(*this), + m_TickThread(*this) { - // TODO: Shut down the server gracefully - m_pState->bStopTickThread = true; - delete m_pState->pTickThread; m_pState->pTickThread = NULL; - - delete m_pState; } @@ -199,18 +208,17 @@ bool cServer::InitServer(cIniFile & a_SettingsIni) m_bIsConnected = true; - m_pState->ServerID = "-"; + m_ServerID = "-"; if (a_SettingsIni.GetValueSetB("Authentication", "Authenticate", true)) { MTRand mtrand1; - unsigned int r1 = (mtrand1.randInt()%1147483647) + 1000000000; - unsigned int r2 = (mtrand1.randInt()%1147483647) + 1000000000; + unsigned int r1 = (mtrand1.randInt() % 1147483647) + 1000000000; + unsigned int r2 = (mtrand1.randInt() % 1147483647) + 1000000000; std::ostringstream sid; sid << std::hex << r1; sid << std::hex << r2; - std::string ServerID = sid.str(); - ServerID.resize(16, '0'); - m_pState->ServerID = ServerID; + m_ServerID = sid.str(); + m_ServerID.resize(16, '0'); } m_ClientViewDistance = a_SettingsIni.GetValueSetI("Server", "DefaultViewDistance", cClientHandle::DEFAULT_VIEW_DISTANCE); @@ -309,15 +317,8 @@ void cServer::BroadcastChat(const AString & a_Message, const cClientHandle * a_E bool cServer::Tick(float a_Dt) { - m_Millisecondsf += a_Dt; - if (m_Millisecondsf > 1.f) - { - m_Milliseconds += (int)m_Millisecondsf; - m_Millisecondsf = m_Millisecondsf - (int)m_Millisecondsf; - } - - cRoot::Get()->TickWorlds(a_Dt); // TODO - Maybe give all worlds their own thread? - + cRoot::Get()->TickWorlds(a_Dt); + cClientHandleList RemoveClients; { cCSLock Lock(m_CSClients); @@ -338,8 +339,6 @@ bool cServer::Tick(float a_Dt) delete *itr; } // for itr - RemoveClients[] - cRoot::Get()->GetPluginManager()->Tick(a_Dt); - if (!m_bRestarting) { return true; @@ -347,7 +346,7 @@ bool cServer::Tick(float a_Dt) else { m_bRestarting = false; - m_pState->RestartEvent.Set(); + m_RestartEvent.Set(); return false; } } @@ -356,42 +355,8 @@ bool cServer::Tick(float a_Dt) -void ServerTickThread( void * a_Param ) -{ - LOG("ServerTickThread"); - cServer *CServerObj = (cServer*)a_Param; - - cTimer Timer; - - long long msPerTick = 50; // TODO - Put this in server config file - long long LastTime = Timer.GetNowTime(); - - bool bKeepGoing = true; - while( bKeepGoing ) - { - long long NowTime = Timer.GetNowTime(); - float DeltaTime = (float)(NowTime-LastTime); - bKeepGoing = CServerObj->Tick( DeltaTime ); - long long TickTime = Timer.GetNowTime() - NowTime; - - if( TickTime < msPerTick ) // Stretch tick time until it's at least msPerTick - { - cSleep::MilliSleep( (unsigned int)( msPerTick - TickTime ) ); - } - - LastTime = NowTime; - } - - LOG("TICK THREAD STOPPED"); -} - - - - - bool cServer::Start(void) { - m_pState->pTickThread = new cThread( ServerTickThread, this, "cServer::ServerTickThread" ); if (!m_ListenThreadIPv4.Start()) { return false; @@ -400,7 +365,10 @@ bool cServer::Start(void) { return false; } - m_pState->pTickThread->Start( true ); + if (!m_TickThread.Start()) + { + return false; + } return true; } @@ -503,13 +471,13 @@ void cServer::SendMessage(const AString & a_Message, cPlayer * a_Player /* = NUL -void cServer::Shutdown() +void cServer::Shutdown(void) { m_ListenThreadIPv4.Stop(); m_ListenThreadIPv6.Stop(); m_bRestarting = true; - m_pState->RestartEvent.Wait(); + m_RestartEvent.Wait(); cRoot::Get()->SaveAllChunks(); @@ -526,15 +494,6 @@ void cServer::Shutdown() -const AString & cServer::GetServerID(void) const -{ - return m_pState->ServerID; -} - - - - - void cServer::KickUser(int a_ClientID, const AString & a_Reason) { cCSLock Lock(m_CSClients); @@ -568,7 +527,7 @@ void cServer::AuthenticateUser(int a_ClientID) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cServer::cClientPacketThread: +// cServer::cNotifyWriteThread: cServer::cNotifyWriteThread::cNotifyWriteThread(void) : super("ClientPacketThread"), -- cgit v1.2.3 From 4c5590636cf4a311f03e735878557b1e7b3362dd Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sun, 11 Aug 2013 20:16:41 +0200 Subject: Each world now ticks in a separate thread. --- source/Server.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/Server.cpp') diff --git a/source/Server.cpp b/source/Server.cpp index 4247a1dfe..0045d4808 100644 --- a/source/Server.cpp +++ b/source/Server.cpp @@ -317,7 +317,7 @@ void cServer::BroadcastChat(const AString & a_Message, const cClientHandle * a_E bool cServer::Tick(float a_Dt) { - cRoot::Get()->TickWorlds(a_Dt); + cRoot::Get()->TickCommands(); cClientHandleList RemoveClients; { -- cgit v1.2.3 From c628ab03e9aae0b8e56f260ad02cfc7d51285a71 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Mon, 12 Aug 2013 08:35:13 +0200 Subject: Removed cServer::BroadcastChat() and cServer::SendMessage(). These two functions make it difficult to move to the new ticking system, and they aren't used anyway. If so required, they can be emulated by ForEachWorld / ForEachPlayer calls. --- source/Server.cpp | 46 ++++++++++------------------------------------ 1 file changed, 10 insertions(+), 36 deletions(-) (limited to 'source/Server.cpp') diff --git a/source/Server.cpp b/source/Server.cpp index 0045d4808..82a4cb9f5 100644 --- a/source/Server.cpp +++ b/source/Server.cpp @@ -162,6 +162,16 @@ void cServer::RemoveClient(const cClientHandle * a_Client) +void cServer::ClientMovedToWorld(const cClientHandle * a_Client) +{ + cCSLock Lock(m_CSClients); + m_Clients.remove(const_cast(a_Client)); +} + + + + + bool cServer::InitServer(cIniFile & a_SettingsIni) { m_Description = a_SettingsIni.GetValue ("Server", "Description", "MCServer! - In C++!").c_str(); @@ -298,23 +308,6 @@ void cServer::OnConnectionAccepted(cSocket & a_Socket) -void cServer::BroadcastChat(const AString & a_Message, const cClientHandle * a_Exclude) -{ - cCSLock Lock(m_CSClients); - for (ClientList::iterator itr = m_Clients.begin(); itr != m_Clients.end(); ++itr) - { - if ((*itr == a_Exclude) || !(*itr)->IsLoggedIn()) - { - continue; - } - (*itr)->SendChat(a_Message); - } -} - - - - - bool cServer::Tick(float a_Dt) { cRoot::Get()->TickCommands(); @@ -452,25 +445,6 @@ void cServer::BindBuiltInConsoleCommands(void) -void cServer::SendMessage(const AString & a_Message, cPlayer * a_Player /* = NULL */, bool a_bExclude /* = false */ ) -{ - if ((a_Player != NULL) && !a_bExclude) - { - cClientHandle * Client = a_Player->GetClientHandle(); - if (Client != NULL) - { - Client->SendChat(a_Message); - } - return; - } - - BroadcastChat(a_Message, (a_Player != NULL) ? a_Player->GetClientHandle() : NULL); -} - - - - - void cServer::Shutdown(void) { m_ListenThreadIPv4.Stop(); -- cgit v1.2.3 From 9020dc993241a4a90e8e98b3435d9b2576f313ea Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Tue, 13 Aug 2013 22:45:29 +0200 Subject: Clients are now ticked in cServer first, then in cWorld once they get assigned a world. --- source/Server.cpp | 48 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 13 deletions(-) (limited to 'source/Server.cpp') diff --git a/source/Server.cpp b/source/Server.cpp index 82a4cb9f5..31a1925a8 100644 --- a/source/Server.cpp +++ b/source/Server.cpp @@ -165,7 +165,7 @@ void cServer::RemoveClient(const cClientHandle * a_Client) void cServer::ClientMovedToWorld(const cClientHandle * a_Client) { cCSLock Lock(m_CSClients); - m_Clients.remove(const_cast(a_Client)); + m_ClientsToRemove.push_back(const_cast(a_Client)); } @@ -312,14 +312,44 @@ bool cServer::Tick(float a_Dt) { cRoot::Get()->TickCommands(); + TickClients(a_Dt); + + if (!m_bRestarting) + { + return true; + } + else + { + m_bRestarting = false; + m_RestartEvent.Set(); + return false; + } +} + + + + + +void cServer::TickClients(float a_Dt) +{ cClientHandleList RemoveClients; { cCSLock Lock(m_CSClients); + + // Remove clients that have moved to a world (the world will be ticking them from now on) + for (cClientHandleList::const_iterator itr = m_ClientsToRemove.begin(), end = m_ClientsToRemove.end(); itr != end; ++itr) + { + m_Clients.remove(*itr); + } // for itr - m_ClientsToRemove[] + m_ClientsToRemove.clear(); + + // Tick the remaining clients, take out those that have been destroyed into RemoveClients for (cClientHandleList::iterator itr = m_Clients.begin(); itr != m_Clients.end();) { if ((*itr)->IsDestroyed()) { - RemoveClients.push_back(*itr); // Remove the client later, when CS is not held, to avoid deadlock ( http://forum.mc-server.org/showthread.php?tid=374 ) + // Remove the client later, when CS is not held, to avoid deadlock ( http://forum.mc-server.org/showthread.php?tid=374 ) + RemoveClients.push_back(*itr); itr = m_Clients.erase(itr); continue; } @@ -327,21 +357,12 @@ bool cServer::Tick(float a_Dt) ++itr; } // for itr - m_Clients[] } + + // Delete the clients that have been destroyed for (cClientHandleList::iterator itr = RemoveClients.begin(); itr != RemoveClients.end(); ++itr) { delete *itr; } // for itr - RemoveClients[] - - if (!m_bRestarting) - { - return true; - } - else - { - m_bRestarting = false; - m_RestartEvent.Set(); - return false; - } } @@ -492,6 +513,7 @@ void cServer::AuthenticateUser(int a_ClientID) if ((*itr)->GetUniqueID() == a_ClientID) { (*itr)->Authenticate(); + return; } } // for itr - m_Clients[] } -- cgit v1.2.3 From 8c3837987bd5f74563790c15a1d52755383135ae Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Wed, 14 Aug 2013 10:24:34 +0200 Subject: Player counts are now properly handled. Fixes #80 --- source/Server.cpp | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) (limited to 'source/Server.cpp') diff --git a/source/Server.cpp b/source/Server.cpp index 31a1925a8..c01222e5a 100644 --- a/source/Server.cpp +++ b/source/Server.cpp @@ -172,10 +172,34 @@ void cServer::ClientMovedToWorld(const cClientHandle * a_Client) +void cServer::PlayerCreated(const cPlayer * a_Player) +{ + // To avoid deadlocks, the player count is not handled directly, but rather posted onto the tick thread + cCSLock Lock(m_CSPlayerCountDiff); + m_PlayerCountDiff += 1; +} + + + + + +void cServer::PlayerDestroyed(const cPlayer * a_Player) +{ + // To avoid deadlocks, the player count is not handled directly, but rather posted onto the tick thread + cCSLock Lock(m_CSPlayerCountDiff); + m_PlayerCountDiff -= 1; +} + + + + + bool cServer::InitServer(cIniFile & a_SettingsIni) { m_Description = a_SettingsIni.GetValue ("Server", "Description", "MCServer! - In C++!").c_str(); m_MaxPlayers = a_SettingsIni.GetValueI("Server", "MaxPlayers", 100); + m_PlayerCount = 0; + m_PlayerCountDiff = 0; if (m_bIsConnected) { @@ -254,6 +278,16 @@ bool cServer::InitServer(cIniFile & a_SettingsIni) +int cServer::GetNumPlayers(void) +{ + cCSLock Lock(m_CSPlayerCount); + return m_PlayerCount; +} + + + + + void cServer::PrepareKeys(void) { // TODO: Save and load key for persistence across sessions @@ -310,6 +344,17 @@ void cServer::OnConnectionAccepted(cSocket & a_Socket) bool cServer::Tick(float a_Dt) { + // Apply the queued playercount adjustments (postponed to avoid deadlocks) + int PlayerCountDiff = 0; + { + cCSLock Lock(m_CSPlayerCountDiff); + std::swap(PlayerCountDiff, m_PlayerCountDiff); + } + { + cCSLock Lock(m_CSPlayerCount); + m_PlayerCount += PlayerCountDiff; + } + cRoot::Get()->TickCommands(); TickClients(a_Dt); -- cgit v1.2.3 From 17b2353d71c405bc626de22e5467d13be792c317 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Wed, 14 Aug 2013 19:11:54 +0200 Subject: Server counts the players correctly. Was missing the PlayerDestroying() call, so players weren't removed from the playercount. --- source/Server.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/Server.cpp') diff --git a/source/Server.cpp b/source/Server.cpp index c01222e5a..fad562973 100644 --- a/source/Server.cpp +++ b/source/Server.cpp @@ -183,7 +183,7 @@ void cServer::PlayerCreated(const cPlayer * a_Player) -void cServer::PlayerDestroyed(const cPlayer * a_Player) +void cServer::PlayerDestroying(const cPlayer * a_Player) { // To avoid deadlocks, the player count is not handled directly, but rather posted onto the tick thread cCSLock Lock(m_CSPlayerCountDiff); -- cgit v1.2.3