1
0
Fork 0

Fixed player moving between worlds.

Fixes FS #407.
Also fixes a few possible deadlocks between SocketThreads and TickThread

git-svn-id: http://mc-server.googlecode.com/svn/trunk@1641 0a769ca7-a7f5-676a-18bf-c427514a06d6
This commit is contained in:
madmaxoft@gmail.com 2013-07-03 07:47:35 +00:00
parent 2f8eebaad1
commit f7b8a301f8
5 changed files with 96 additions and 32 deletions

View File

@ -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:

View File

@ -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

View File

@ -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;
}
eDimension OldDimension = m_World->GetDimension();
// Remove all links to the old world
m_World->RemovePlayer(this);
m_ClientHandle->RemoveFromAllChunks();
m_World->RemoveEntity(this);
return false;
// 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;
}

View File

@ -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);

View File

@ -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!
}