summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--source/ClientHandle.cpp67
-rw-r--r--source/ClientHandle.h10
-rw-r--r--source/Player.cpp49
-rw-r--r--source/Player.h2
-rw-r--r--source/World.cpp2
5 files changed, 97 insertions, 33 deletions
diff --git a/source/ClientHandle.cpp b/source/ClientHandle.cpp
index 8e031a124..9a84d23f5 100644
--- a/source/ClientHandle.cpp
+++ b/source/ClientHandle.cpp
@@ -406,6 +406,11 @@ void cClientHandle::RemoveFromAllChunks()
cCSLock Lock(m_CSChunkLists);
m_LoadedChunks.clear();
m_ChunksToSend.clear();
+
+ // Also reset the LastStreamedChunk coords to bogus coords,
+ // so that all chunks are streamed in subsequent StreamChunks() call (FS #407)
+ m_LastStreamedChunkX = 0x7fffffff;
+ m_LastStreamedChunkZ = 0x7fffffff;
}
}
@@ -898,18 +903,11 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, c
void cClientHandle::HandleChat(const AString & a_Message)
{
- AString Message(a_Message);
- if (!cRoot::Get()->GetServer()->Command(*this, Message))
- {
- AString Msg;
- Printf(Msg, "<%s%s%s> %s",
- m_Player->GetColor().c_str(),
- m_Player->GetName().c_str(),
- cChatColor::White.c_str(),
- Message.c_str()
- );
- m_Player->GetWorld()->BroadcastChat(Msg);
- }
+ // We need to process messages in the Tick thread, to avoid deadlocks resulting from player-commands being processed
+ // in the SocketThread and waiting for acquiring the ChunkMap CS with Plugin CS locked
+
+ cCSLock Lock(m_CSMessages);
+ m_PendingMessages.push_back(a_Message);
}
@@ -1292,8 +1290,8 @@ void cClientHandle::Tick(float a_Dt)
m_ShouldCheckDownloaded = false;
}
+ // Send a ping packet:
cTimer t1;
- // Send ping packet
if (
(m_Player != NULL) && // Is logged in?
(m_LastPingTime + cClientHandle::PING_TIME_MS <= t1.GetNowTime())
@@ -1324,6 +1322,9 @@ void cClientHandle::Tick(float a_Dt)
m_CurrentExplosionTick = (m_CurrentExplosionTick + 1) % ARRAYCOUNT(m_NumExplosionsPerTick);
m_RunningSumExplosions -= m_NumExplosionsPerTick[m_CurrentExplosionTick];
m_NumExplosionsPerTick[m_CurrentExplosionTick] = 0;
+
+ // Process the queued messages:
+ ProcessPendingMessages();
}
@@ -1944,6 +1945,46 @@ void cClientHandle::AddWantedChunk(int a_ChunkX, int a_ChunkZ)
+void cClientHandle::ProcessPendingMessages(void)
+{
+ while (true)
+ {
+ AString Message;
+
+ // Extract one message from the PendingMessages buffer:
+ {
+ cCSLock Lock(m_CSMessages);
+ if (m_PendingMessages.empty())
+ {
+ // No more messages in the buffer, bail out
+ return;
+ }
+ Message = m_PendingMessages.front();
+ m_PendingMessages.pop_front();
+ } // Lock(m_CSMessages)
+
+ // If a command, perform it:
+ if (cRoot::Get()->GetServer()->Command(*this, Message))
+ {
+ continue;
+ }
+
+ // Not a command, broadcast as a simple message:
+ AString Msg;
+ Printf(Msg, "<%s%s%s> %s",
+ m_Player->GetColor().c_str(),
+ m_Player->GetName().c_str(),
+ cChatColor::White.c_str(),
+ Message.c_str()
+ );
+ m_Player->GetWorld()->BroadcastChat(Msg);
+ } // while (true)
+}
+
+
+
+
+
void cClientHandle::PacketBufferFull(void)
{
// Too much data in the incoming queue, the server is probably too busy, kick the client:
diff --git a/source/ClientHandle.h b/source/ClientHandle.h
index cd0ca1ee6..c02924ebf 100644
--- a/source/ClientHandle.h
+++ b/source/ClientHandle.h
@@ -185,6 +185,7 @@ public:
bool HandleLogin(int a_ProtocolVersion, const AString & a_Username);
void SendData(const char * a_Data, int a_Size);
+
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 )
@@ -270,6 +271,12 @@ private:
/// Running sum of m_NumExplosionsPerTick[]
int m_RunningSumExplosions;
+ /// Lock for the m_PendingMessages buffer
+ cCriticalSection m_CSMessages;
+
+ /// Buffer for received messages to be processed in the Tick thread
+ AStringList m_PendingMessages;
+
/// Returns true if the rate block interactions is within a reasonable limit (bot protection)
@@ -292,6 +299,9 @@ private:
/// Handles the block placing packet when it is a real block placement (not block-using, item-using or eating)
void HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, cItemHandler & a_ItemHandler);
+
+ /// Processes the messages in m_PendingMessages; called from the Tick thread
+ void ProcessPendingMessages(void);
// cSocketThreads::cCallback overrides:
virtual void DataReceived (const char * a_Data, int a_Size) override; // Data is received from the client
diff --git a/source/Player.cpp b/source/Player.cpp
index 84d38f13b..865ff24d6 100644
--- a/source/Player.cpp
+++ b/source/Player.cpp
@@ -117,9 +117,9 @@ cPlayer::~cPlayer(void)
-void cPlayer::Initialize( cWorld* a_World )
+void cPlayer::Initialize(cWorld * a_World)
{
- cPawn::Initialize( a_World );
+ super::Initialize(a_World);
GetWorld()->AddPlayer(this);
}
@@ -891,26 +891,37 @@ void cPlayer::TossItem(
-bool cPlayer::MoveToWorld( const char* a_WorldName )
+bool cPlayer::MoveToWorld(const char * a_WorldName)
{
- cWorld * World = cRoot::Get()->GetWorld( a_WorldName );
- if ( World )
+ cWorld * World = cRoot::Get()->GetWorld(a_WorldName);
+ if (World == NULL)
{
- /* Remove all links to the old world */
- m_World->RemovePlayer( this );
- m_ClientHandle->RemoveFromAllChunks();
- m_World->RemoveEntity(this);
-
- /* Add player to all the necessary parts of the new world */
- SetWorld( World );
- GetWorld()->AddPlayer(this);
-
- m_ClientHandle->HandleRespawn();
- m_ClientHandle->StreamChunks();
- return true;
+ LOG("%s: Couldn't find world \"%s\".", a_WorldName);
+ return false;
}
-
- return false;
+
+ eDimension OldDimension = m_World->GetDimension();
+
+ // Remove all links to the old world
+ m_World->RemovePlayer(this);
+ m_ClientHandle->RemoveFromAllChunks();
+ m_World->RemoveEntity(this);
+
+ // 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/Player.h b/source/Player.h
index f36545a4c..639b2595b 100644
--- a/source/Player.h
+++ b/source/Player.h
@@ -145,7 +145,7 @@ public:
void SetVisible( bool a_bVisible ); // tolua_export
bool IsVisible(void) const { return m_bVisible; } // tolua_export
- bool MoveToWorld(const char * a_WorldName ); // tolua_export
+ bool MoveToWorld(const char * a_WorldName); // tolua_export
bool SaveToDisk(void);
bool LoadFromDisk(void);
diff --git a/source/World.cpp b/source/World.cpp
index 4333aa7a4..ac7ba42aa 100644
--- a/source/World.cpp
+++ b/source/World.cpp
@@ -1843,6 +1843,8 @@ void cWorld::AddPlayer(cPlayer * a_Player)
m_Players.remove(a_Player); // Make sure the player is registered only once
m_Players.push_back(a_Player);
+
+ // The player has already been added to the chunkmap as the entity, do NOT add again!
}