summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--source/Bindings.cpp6
-rw-r--r--source/Bindings.h2
-rw-r--r--source/ClientHandle.cpp38
-rw-r--r--source/ClientHandle.h4
-rw-r--r--source/Player.cpp15
-rw-r--r--source/Server.cpp45
-rw-r--r--source/Server.h14
7 files changed, 108 insertions, 16 deletions
diff --git a/source/Bindings.cpp b/source/Bindings.cpp
index 8feb070e1..a0ad85156 100644
--- a/source/Bindings.cpp
+++ b/source/Bindings.cpp
@@ -1,6 +1,6 @@
/*
** 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
@@ -11295,14 +11295,14 @@ static int tolua_AllToLua_cServer_GetNumPlayers00(lua_State* tolua_S)
#ifndef TOLUA_RELEASE
tolua_Error tolua_err;
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)
)
goto tolua_lerror;
else
#endif
{
- const cServer* self = (const cServer*) tolua_tousertype(tolua_S,1,0);
+ cServer* self = (cServer*) tolua_tousertype(tolua_S,1,0);
#ifndef TOLUA_RELEASE
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetNumPlayers'", NULL);
#endif
diff --git a/source/Bindings.h b/source/Bindings.h
index a8d39e32f..0211e0eeb 100644
--- a/source/Bindings.h
+++ b/source/Bindings.h
@@ -1,6 +1,6 @@
/*
** 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 */
diff --git a/source/ClientHandle.cpp b/source/ClientHandle.cpp
index fe78ef2b6..32bfb00f5 100644
--- a/source/ClientHandle.cpp
+++ b/source/ClientHandle.cpp
@@ -275,7 +275,7 @@ void cClientHandle::Authenticate(void)
void cClientHandle::StreamChunks(void)
{
- if ((m_State < csAuthenticating) || (m_State >= csDestroying))
+ if ((m_State < csAuthenticated) || (m_State >= csDestroying))
{
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)
{
ASSERT(m_Player != NULL);
diff --git a/source/ClientHandle.h b/source/ClientHandle.h
index 1f40cc8d2..4dcb188b3 100644
--- a/source/ClientHandle.h
+++ b/source/ClientHandle.h
@@ -32,6 +32,7 @@ class cRedstone;
class cWindow;
class cFallingBlock;
class cItemHandler;
+class cWorld;
@@ -194,6 +195,9 @@ public:
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:
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 )
diff --git a/source/Player.cpp b/source/Player.cpp
index 365a0396f..34980d2f6 100644
--- a/source/Player.cpp
+++ b/source/Player.cpp
@@ -100,6 +100,8 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName)
m_LastJumpHeight = (float)(GetPosY());
m_LastGroundHeight = (float)(GetPosY());
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_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
SetWorld(World);
World->AddEntity(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;
}
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);
diff --git a/source/Server.h b/source/Server.h
index 6f8576ece..87e472465 100644
--- a/source/Server.h
+++ b/source/Server.h
@@ -43,7 +43,7 @@ public: // tolua_export
// Player counts:
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; }
// tolua_end
@@ -78,6 +78,12 @@ public: // tolua_export
/// Don't tick a_Client anymore, it will be ticked from its cPlayer instead
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::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_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;
int m_ClientViewDistance; // The default view distance for clients; settable in Settings.ini
@@ -150,7 +161,6 @@ private:
AString m_Description;
int m_MaxPlayers;
- int m_NumPlayers;
cTickThread m_TickThread;
cEvent m_RestartEvent;