From 7d4934534e9c58a111215859ba83c32a9bc0fa8a Mon Sep 17 00:00:00 2001 From: Mat Date: Thu, 5 Mar 2020 12:52:34 +0200 Subject: Stabilise MoveToWorld (#4004) * Stabilise MoveToWorld * Fix comments and deprecate ScheduleMoveToWorld * Enhanced thread safety for m_WorldChangeInfo * Return unique_ptr from cAtomicUniquePtr::exchange * cWorld now calls entity cEntity::OnAddToWorld and cEntity::OnRemoveFromWorld. Allows broadcasting entities added to the world from the world's tick thread. This also factors out some common code from cEntity::DoMoveToWorld and cEntity::Initialize. As a consequence, cEntity::Destroy(false) (i.e. Destroying the entity without broadcasting) is impossible. This isn't used anywhere in Cuberite so it's now deprecated. * Update entity position after removing it from the world. Fixes broadcasts being sent to the wrong chunk. * Fix style * cEntity: Update LastSentPosition when sending spawn packet * Add Wno-deprecated-declarations to the lua bindings * Kill uses of ScheduleMoveToWorld --- src/World.cpp | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) (limited to 'src/World.cpp') diff --git a/src/World.cpp b/src/World.cpp index 312f5967a..a80cffbcc 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -1024,6 +1024,7 @@ void cWorld::Tick(std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_La Entity->SetWorld(this); auto EntityPtr = Entity.get(); m_ChunkMap->AddEntity(std::move(Entity)); + EntityPtr->OnAddToWorld(*this); ASSERT(!EntityPtr->IsTicking()); EntityPtr->SetIsTicking(true); } @@ -1167,14 +1168,14 @@ void cWorld::TickMobs(std::chrono::milliseconds a_Dt) { if (Monster.GetMobType() != eMonsterType::mtWolf) { - Monster.Destroy(true); + Monster.Destroy(); } else { auto & Wolf = static_cast(Monster); if (!Wolf.IsAngry() && !Wolf.IsTame()) { - Monster.Destroy(true); + Monster.Destroy(); } } } @@ -2454,23 +2455,34 @@ void cWorld::AddPlayer(std::unique_ptr a_Player, cWorld * a_OldWorld) -std::unique_ptr cWorld::RemovePlayer(cPlayer & a_Player, bool a_RemoveFromChunk) +std::unique_ptr cWorld::RemovePlayer(cPlayer & a_Player) { - std::unique_ptr PlayerPtr; + // Check the chunkmap + std::unique_ptr PlayerPtr(static_cast(m_ChunkMap->RemoveEntity(a_Player).release())); - if (a_RemoveFromChunk) + if (PlayerPtr != nullptr) { - // To prevent iterator invalidations when an entity goes through a portal and calls this function whilst being ticked by cChunk - // we should not change cChunk's entity list if asked not to - PlayerPtr = std::unique_ptr(static_cast(m_ChunkMap->RemoveEntity(a_Player).release())); + // Player found in the world, tell it it's being removed + PlayerPtr->OnRemoveFromWorld(*this); } + else // Check the awaiting players list { cCSLock Lock(m_CSPlayersToAdd); - m_PlayersToAdd.remove_if([&](const decltype(m_PlayersToAdd)::value_type & value) -> bool + auto itr = std::find_if(m_PlayersToAdd.begin(), m_PlayersToAdd.end(), + [&](const decltype(m_PlayersToAdd)::value_type & value) + { + return (value.first.get() == &a_Player); + } + ); + + if (itr != m_PlayersToAdd.end()) { - return (value.first.get() == &a_Player); - }); + PlayerPtr = std::move(itr->first); + m_PlayersToAdd.erase(itr); + } } + + // Remove from the player list { cCSLock Lock(m_CSPlayers); LOGD("Removing player %s from world \"%s\"", a_Player.GetName().c_str(), m_WorldName.c_str()); @@ -3076,6 +3088,7 @@ OwnedEntity cWorld::RemoveEntity(cEntity & a_Entity) auto Entity = m_ChunkMap->RemoveEntity(a_Entity); if (Entity != nullptr) { + Entity->OnRemoveFromWorld(*this); return Entity; } @@ -3475,6 +3488,7 @@ void cWorld::AddQueuedPlayers(void) // Add to chunkmap, if not already there (Spawn vs MoveToWorld): auto PlayerPtr = Player.get(); m_ChunkMap->AddEntityIfNotPresent(std::move(Player)); + PlayerPtr->OnAddToWorld(*this); ASSERT(!PlayerPtr->IsTicking()); PlayerPtr->SetIsTicking(true); AddedPlayerPtrs.emplace_back(PlayerPtr, AwaitingPlayer.second); -- cgit v1.2.3