1
0

Delay EntityChangedWorld players' callback until Entity fully linked to world (#3330)

Otherwise, some API calls just don't seem to happen
.gitignore tweak for test executables
This commit is contained in:
ElNounch 2016-08-22 19:43:43 +02:00 committed by Mattes D
parent 07c5f09ecf
commit e9d1a942d1
4 changed files with 32 additions and 15 deletions

1
.gitignore vendored
View File

@ -68,6 +68,7 @@ Makefile
*.a
*.d
*.so
tests/*/*-exe
BuildInfo.h
CMakeCache.txt
CMakeFiles

View File

@ -1827,8 +1827,7 @@ bool cPlayer::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn, Vector3d
ParentChunk->GetPosX(), ParentChunk->GetPosZ()
);
ParentChunk->RemoveEntity(this);
a_World->AddPlayer(this);
cRoot::Get()->GetPluginManager()->CallHookEntityChangedWorld(*this, a_OldWorld);
a_World->AddPlayer(this, &a_OldWorld); // New world will appropriate and announce client at his next tick
});
return true;
}

View File

@ -2990,10 +2990,10 @@ void cWorld::CollectPickupsByPlayer(cPlayer & a_Player)
void cWorld::AddPlayer(cPlayer * a_Player)
void cWorld::AddPlayer(cPlayer * a_Player, cWorld * a_OldWorld)
{
cCSLock Lock(m_CSPlayersToAdd);
m_PlayersToAdd.push_back(a_Player);
m_PlayersToAdd.emplace_back(a_Player, a_OldWorld);
}
@ -3010,7 +3010,10 @@ void cWorld::RemovePlayer(cPlayer * a_Player, bool a_RemoveFromChunk)
}
{
cCSLock Lock(m_CSPlayersToAdd);
m_PlayersToAdd.remove(a_Player);
m_PlayersToAdd.remove_if([&](const std::pair< cPlayer *, cWorld * > & value) -> bool
{
return (value.first == a_Player);
});
}
{
cCSLock Lock(m_CSPlayers);
@ -3895,7 +3898,7 @@ void cWorld::AddQueuedPlayers(void)
ASSERT(m_TickThread.IsCurrentThread());
// Grab the list of players to add, it has to be locked to access it:
cPlayerList PlayersToAdd;
cAwaitingPlayerList PlayersToAdd;
{
cCSLock Lock(m_CSPlayersToAdd);
std::swap(PlayersToAdd, m_PlayersToAdd);
@ -3904,8 +3907,9 @@ void cWorld::AddQueuedPlayers(void)
// Add all the players in the grabbed list:
{
cCSLock Lock(m_CSPlayers);
for (auto Player : PlayersToAdd)
for (auto & AwaitingPlayer : PlayersToAdd)
{
auto & Player = AwaitingPlayer.first;
ASSERT(std::find(m_Players.begin(), m_Players.end(), Player) == m_Players.end()); // Is it already in the list? HOW?
LOGD("Adding player %s to world \"%s\".", Player->GetName().c_str(), m_WorldName.c_str());
@ -3922,9 +3926,10 @@ void cWorld::AddQueuedPlayers(void)
// Add all the players' clienthandles:
{
cCSLock Lock(m_CSClients);
for (cPlayerList::iterator itr = PlayersToAdd.begin(), end = PlayersToAdd.end(); itr != end; ++itr)
for (auto & AwaitingPlayer : PlayersToAdd)
{
cClientHandlePtr Client = (*itr)->GetClientHandlePtr();
auto & Player = AwaitingPlayer.first;
cClientHandlePtr Client = Player->GetClientHandlePtr();
if (Client != nullptr)
{
m_Clients.push_back(Client);
@ -3933,16 +3938,26 @@ void cWorld::AddQueuedPlayers(void)
} // Lock(m_CSClients)
// Stream chunks to all eligible clients:
for (cPlayerList::iterator itr = PlayersToAdd.begin(), end = PlayersToAdd.end(); itr != end; ++itr)
for (auto & AwaitingPlayer : PlayersToAdd)
{
cClientHandle * Client = (*itr)->GetClientHandle();
auto & Player = AwaitingPlayer.first;
cClientHandle * Client = Player->GetClientHandle();
if (Client != nullptr)
{
Client->SendPlayerMoveLook();
Client->SendHealth();
Client->SendWholeInventory(*(*itr)->GetWindow());
Client->SendWholeInventory(*Player->GetWindow());
}
} // for itr - PlayersToAdd[]
// Call EntityChangedWorld callback on all eligible clients
for (auto & AwaitingPlayer : PlayersToAdd)
{
if (AwaitingPlayer.second != nullptr)
{
cRoot::Get()->GetPluginManager()->CallHookEntityChangedWorld(*(static_cast <cEntity *>(AwaitingPlayer.first)), *AwaitingPlayer.second);
}
}
}

View File

@ -61,6 +61,7 @@ class cBroadcaster;
typedef std::list< cPlayer * > cPlayerList;
typedef std::list< std::pair< cPlayer *, cWorld * > > cAwaitingPlayerList;
typedef SharedPtr<cSetChunkData> cSetChunkDataPtr; // TODO: Change to unique_ptr once we go C++11
typedef std::vector<cSetChunkDataPtr> cSetChunkDataPtrs;
@ -262,8 +263,9 @@ public:
/** Adds the player to the world.
Uses a queue to store the player object until the Tick thread processes the addition event.
Also adds the player as an entity in the chunkmap, and the player's ClientHandle, if any, for ticking. */
void AddPlayer(cPlayer * a_Player);
Also adds the player as an entity in the chunkmap, and the player's ClientHandle, if any, for ticking.
If a_OldWorld is provided, a corresponding ENTITY_CHANGED_WORLD event is triggerred after the addition. */
void AddPlayer(cPlayer * a_Player, cWorld * a_OldWorld = nullptr);
/** Removes the player from the world.
Removes the player from the addition queue, too, if appropriate.
@ -1006,7 +1008,7 @@ private:
cCriticalSection m_CSPlayersToAdd;
/** List of players that are scheduled for adding, waiting for the Tick thread to add them. */
cPlayerList m_PlayersToAdd;
cAwaitingPlayerList m_PlayersToAdd;
/** CS protecting m_SetChunkDataQueue. */
cCriticalSection m_CSSetChunkDataQueue;