1
0

Player counts are now properly handled.

Fixes #80
This commit is contained in:
madmaxoft 2013-08-14 10:24:34 +02:00
parent b65a91dde3
commit 8c3837987b
7 changed files with 108 additions and 16 deletions

View File

@ -1,6 +1,6 @@
/* /*
** Lua binding: AllToLua ** Lua binding: AllToLua
** Generated automatically by tolua++-1.0.92 on 08/13/13 23:07:52. ** Generated automatically by tolua++-1.0.92 on 08/14/13 08:14:03.
*/ */
#ifndef __cplusplus #ifndef __cplusplus
@ -11295,14 +11295,14 @@ static int tolua_AllToLua_cServer_GetNumPlayers00(lua_State* tolua_S)
#ifndef TOLUA_RELEASE #ifndef TOLUA_RELEASE
tolua_Error tolua_err; tolua_Error tolua_err;
if ( if (
!tolua_isusertype(tolua_S,1,"const cServer",0,&tolua_err) || !tolua_isusertype(tolua_S,1,"cServer",0,&tolua_err) ||
!tolua_isnoobj(tolua_S,2,&tolua_err) !tolua_isnoobj(tolua_S,2,&tolua_err)
) )
goto tolua_lerror; goto tolua_lerror;
else else
#endif #endif
{ {
const cServer* self = (const cServer*) tolua_tousertype(tolua_S,1,0); cServer* self = (cServer*) tolua_tousertype(tolua_S,1,0);
#ifndef TOLUA_RELEASE #ifndef TOLUA_RELEASE
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetNumPlayers'", NULL); if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetNumPlayers'", NULL);
#endif #endif

View File

@ -1,6 +1,6 @@
/* /*
** Lua binding: AllToLua ** Lua binding: AllToLua
** Generated automatically by tolua++-1.0.92 on 08/13/13 23:07:53. ** Generated automatically by tolua++-1.0.92 on 08/14/13 08:14:04.
*/ */
/* Exported function */ /* Exported function */

View File

@ -275,7 +275,7 @@ void cClientHandle::Authenticate(void)
void cClientHandle::StreamChunks(void) void cClientHandle::StreamChunks(void)
{ {
if ((m_State < csAuthenticating) || (m_State >= csDestroying)) if ((m_State < csAuthenticated) || (m_State >= csDestroying))
{ {
return; return;
} }
@ -1314,6 +1314,42 @@ void cClientHandle::SendData(const char * a_Data, int a_Size)
void cClientHandle::MoveToWorld(cWorld & a_World, bool a_SendRespawnPacket)
{
ASSERT(m_Player != NULL);
if (a_SendRespawnPacket)
{
SendRespawn();
}
cWorld * World = m_Player->GetWorld();
// Remove all associated chunks:
cChunkCoordsList Chunks;
{
cCSLock Lock(m_CSChunkLists);
std::swap(Chunks, m_LoadedChunks);
m_ChunksToSend.clear();
}
for (cChunkCoordsList::iterator itr = Chunks.begin(), end = Chunks.end(); itr != end; ++itr)
{
World->RemoveChunkClient(itr->m_ChunkX, itr->m_ChunkZ, this);
m_Protocol->SendUnloadChunk(itr->m_ChunkX, itr->m_ChunkZ);
} // for itr - Chunks[]
// Do NOT stream new chunks, the new world runs its own tick thread and may deadlock
// Instead, the chunks will be streamed when the client is moved to the new world's Tick list,
// by setting state to csAuthenticated
m_State = csAuthenticated;
m_LastStreamedChunkX = 0x7fffffff;
m_LastStreamedChunkZ = 0x7fffffff;
}
bool cClientHandle::CheckBlockInteractionsRate(void) bool cClientHandle::CheckBlockInteractionsRate(void)
{ {
ASSERT(m_Player != NULL); ASSERT(m_Player != NULL);

View File

@ -32,6 +32,7 @@ class cRedstone;
class cWindow; class cWindow;
class cFallingBlock; class cFallingBlock;
class cItemHandler; class cItemHandler;
class cWorld;
@ -194,6 +195,9 @@ public:
void SendData(const char * a_Data, int a_Size); void SendData(const char * a_Data, int a_Size);
/// Called when the player moves into a different world; queues sreaming the new chunks
void MoveToWorld(cWorld & a_World, bool a_SendRespawnPacket);
private: private:
int m_ViewDistance; // Number of chunks the player can see in each direction; 4 is the minimum ( http://wiki.vg/Protocol_FAQ#.E2.80.A6all_connecting_clients_spasm_and_jerk_uncontrollably.21 ) int m_ViewDistance; // Number of chunks the player can see in each direction; 4 is the minimum ( http://wiki.vg/Protocol_FAQ#.E2.80.A6all_connecting_clients_spasm_and_jerk_uncontrollably.21 )

View File

@ -100,6 +100,8 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName)
m_LastJumpHeight = (float)(GetPosY()); m_LastJumpHeight = (float)(GetPosY());
m_LastGroundHeight = (float)(GetPosY()); m_LastGroundHeight = (float)(GetPosY());
m_Stance = GetPosY() + 1.62; m_Stance = GetPosY() + 1.62;
cRoot::Get()->GetServer()->PlayerCreated(this);
} }
@ -1120,20 +1122,15 @@ bool cPlayer::MoveToWorld(const char * a_WorldName)
m_ClientHandle->RemoveFromAllChunks(); m_ClientHandle->RemoveFromAllChunks();
m_World->RemoveEntity(this); m_World->RemoveEntity(this);
// If the dimension is different, we can send the respawn packet
// http://wiki.vg/Protocol#0x09 says "don't send if dimension is the same" as of 2013_07_02
m_ClientHandle->MoveToWorld(*World, (OldDimension != World->GetDimension()));
// Add player to all the necessary parts of the new world // Add player to all the necessary parts of the new world
SetWorld(World); SetWorld(World);
World->AddEntity(this); World->AddEntity(this);
World->AddPlayer(this); World->AddPlayer(this);
// If the dimension is different, we can send the respawn packet
// http://wiki.vg/Protocol#0x09 says "don't send if dimension is the same" as of 2013_07_02
if (OldDimension != World->GetDimension())
{
m_ClientHandle->SendRespawn();
}
// Stream the new chunks:
m_ClientHandle->StreamChunks();
return true; return true;
} }

View File

@ -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) bool cServer::InitServer(cIniFile & a_SettingsIni)
{ {
m_Description = a_SettingsIni.GetValue ("Server", "Description", "MCServer! - In C++!").c_str(); m_Description = a_SettingsIni.GetValue ("Server", "Description", "MCServer! - In C++!").c_str();
m_MaxPlayers = a_SettingsIni.GetValueI("Server", "MaxPlayers", 100); m_MaxPlayers = a_SettingsIni.GetValueI("Server", "MaxPlayers", 100);
m_PlayerCount = 0;
m_PlayerCountDiff = 0;
if (m_bIsConnected) 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) void cServer::PrepareKeys(void)
{ {
// TODO: Save and load key for persistence across sessions // 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) 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(); cRoot::Get()->TickCommands();
TickClients(a_Dt); TickClients(a_Dt);

View File

@ -43,7 +43,7 @@ public: // tolua_export
// Player counts: // Player counts:
int GetMaxPlayers(void) const {return m_MaxPlayers; } int GetMaxPlayers(void) const {return m_MaxPlayers; }
int GetNumPlayers(void) const { return m_NumPlayers; } int GetNumPlayers(void);
void SetMaxPlayers(int a_MaxPlayers) { m_MaxPlayers = a_MaxPlayers; } void SetMaxPlayers(int a_MaxPlayers) { m_MaxPlayers = a_MaxPlayers; }
// tolua_end // tolua_end
@ -78,6 +78,12 @@ public: // tolua_export
/// Don't tick a_Client anymore, it will be ticked from its cPlayer instead /// Don't tick a_Client anymore, it will be ticked from its cPlayer instead
void ClientMovedToWorld(const cClientHandle * a_Client); void ClientMovedToWorld(const cClientHandle * a_Client);
/// Notifies the server that a player was created; the server uses this to adjust the number of players
void PlayerCreated(const cPlayer * a_Player);
/// Notifies the server that a player was destroyed; the server uses this to adjust the number of players
void PlayerDestroyed(const cPlayer * a_Player);
CryptoPP::RSA::PrivateKey & GetPrivateKey(void) { return m_PrivateKey; } CryptoPP::RSA::PrivateKey & GetPrivateKey(void) { return m_PrivateKey; }
CryptoPP::RSA::PublicKey & GetPublicKey (void) { return m_PublicKey; } CryptoPP::RSA::PublicKey & GetPublicKey (void) { return m_PublicKey; }
@ -135,6 +141,11 @@ private:
cClientHandleList m_Clients; ///< Clients that are connected to the server and not yet assigned to a cWorld cClientHandleList m_Clients; ///< Clients that are connected to the server and not yet assigned to a cWorld
cClientHandleList m_ClientsToRemove; ///< Clients that have just been moved into a world and are to be removed from m_Clients in the next Tick() cClientHandleList m_ClientsToRemove; ///< Clients that have just been moved into a world and are to be removed from m_Clients in the next Tick()
cCriticalSection m_CSPlayerCount; ///< Locks the m_PlayerCount
int m_PlayerCount; ///< Number of players currently playing in the server
cCriticalSection m_CSPlayerCountDiff; ///< Locks the m_PlayerCountDiff
int m_PlayerCountDiff; ///< Adjustment to m_PlayerCount to be applied in the Tick thread
cSocketThreads m_SocketThreads; cSocketThreads m_SocketThreads;
int m_ClientViewDistance; // The default view distance for clients; settable in Settings.ini int m_ClientViewDistance; // The default view distance for clients; settable in Settings.ini
@ -150,7 +161,6 @@ private:
AString m_Description; AString m_Description;
int m_MaxPlayers; int m_MaxPlayers;
int m_NumPlayers;
cTickThread m_TickThread; cTickThread m_TickThread;
cEvent m_RestartEvent; cEvent m_RestartEvent;