diff options
author | Tiger Wang <ziwei.tiger@outlook.com> | 2017-08-18 12:17:56 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-08-18 12:17:56 +0200 |
commit | 72d7027861a3b7e7e8bb5fdcbbc5a1a778fa7f82 (patch) | |
tree | c1c1a040332d4ba1f784be25c67c9800e85015eb | |
parent | Sitting cats block enderchests from opening (#3906) (diff) | |
parent | Changed entity ownership model to use smart pointers (diff) | |
download | cuberite-72d7027861a3b7e7e8bb5fdcbbc5a1a778fa7f82.tar cuberite-72d7027861a3b7e7e8bb5fdcbbc5a1a778fa7f82.tar.gz cuberite-72d7027861a3b7e7e8bb5fdcbbc5a1a778fa7f82.tar.bz2 cuberite-72d7027861a3b7e7e8bb5fdcbbc5a1a778fa7f82.tar.lz cuberite-72d7027861a3b7e7e8bb5fdcbbc5a1a778fa7f82.tar.xz cuberite-72d7027861a3b7e7e8bb5fdcbbc5a1a778fa7f82.tar.zst cuberite-72d7027861a3b7e7e8bb5fdcbbc5a1a778fa7f82.zip |
Diffstat (limited to '')
39 files changed, 480 insertions, 421 deletions
diff --git a/src/BlockEntities/MobSpawnerEntity.cpp b/src/BlockEntities/MobSpawnerEntity.cpp index 9cc6f20c6..5246ae6ca 100644 --- a/src/BlockEntities/MobSpawnerEntity.cpp +++ b/src/BlockEntities/MobSpawnerEntity.cpp @@ -178,7 +178,7 @@ void cMobSpawnerEntity::SpawnEntity(void) double PosX = Chunk->GetPosX() * cChunkDef::Width + RelX; double PosZ = Chunk->GetPosZ() * cChunkDef::Width + RelZ; - cMonster * Monster = cMonster::NewMonsterFromType(m_MobType); + auto Monster = cMonster::NewMonsterFromType(m_MobType); if (Monster == nullptr) { continue; @@ -186,7 +186,7 @@ void cMobSpawnerEntity::SpawnEntity(void) Monster->SetPosition(PosX, RelY, PosZ); Monster->SetYaw(Random.RandReal(360.0f)); - if (Chunk->GetWorld()->SpawnMobFinalize(Monster) != cEntity::INVALID_ID) + if (Chunk->GetWorld()->SpawnMobFinalize(std::move(Monster)) != cEntity::INVALID_ID) { EntitiesSpawned = true; Chunk->BroadcastSoundParticleEffect( diff --git a/src/Chunk.cpp b/src/Chunk.cpp index 646aea985..f2b936a3f 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -136,13 +136,12 @@ cChunk::~cChunk() // Remove and destroy all entities that are not players: cEntityList Entities; std::swap(Entities, m_Entities); // Need another list because cEntity destructors check if they've been removed from chunk - for (auto Entity : Entities) + for (auto & Entity : Entities) { if (!Entity->IsPlayer()) { // Scheduling a normal destruction is neither possible (Since this chunk will be gone till the schedule occurs) nor necessary. Entity->DestroyNoScheduling(false); // No point in broadcasting in an unloading chunk. Chunks unload when no one is nearby. - delete Entity; } } @@ -300,9 +299,9 @@ void cChunk::GetAllData(cChunkDataCallback & a_Callback) a_Callback.ChunkData(m_ChunkData); - for (auto Entity : m_Entities) + for (const auto & Entity : m_Entities) { - a_Callback.Entity(Entity); + a_Callback.Entity(Entity.get()); } for (auto & KeyPair : m_BlockEntities) @@ -534,7 +533,7 @@ void cChunk::CollectMobCensus(cMobCensus & toFill) } Vector3d currentPosition; - for (auto entity : m_Entities) + for (auto & entity : m_Entities) { // LOGD("Counting entity #%i (%s)", (*itr)->GetUniqueID(), (*itr)->GetClass()); if (entity->IsMob()) @@ -637,7 +636,7 @@ void cChunk::SpawnMobs(cMobSpawner & a_MobSpawner) continue; } - cEntity * newMob = a_MobSpawner.TryToSpawnHere(this, TryX, TryY, TryZ, Biome, MaxNbOfSuccess); + auto newMob = a_MobSpawner.TryToSpawnHere(this, TryX, TryY, TryZ, Biome, MaxNbOfSuccess); if (newMob == nullptr) { continue; @@ -661,7 +660,7 @@ void cChunk::Tick(std::chrono::milliseconds a_Dt) // If we are not valid, tick players and bailout if (!IsValid()) { - for (auto Entity : m_Entities) + for (const auto & Entity : m_Entities) { if (Entity->IsPlayer()) { @@ -686,7 +685,7 @@ void cChunk::Tick(std::chrono::milliseconds a_Dt) m_IsDirty = KeyPair.second->Tick(a_Dt, *this) | m_IsDirty; } - for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end();) + for (auto itr = m_Entities.begin(); itr != m_Entities.end();) { // Do not tick mobs that are detached from the world. They're either scheduled for teleportation or for removal. if (!(*itr)->IsTicking()) @@ -711,20 +710,22 @@ void cChunk::Tick(std::chrono::milliseconds a_Dt) continue; } - if ((((*itr)->GetChunkX() != m_PosX) || - ((*itr)->GetChunkZ() != m_PosZ)) + if ( + ((*itr)->GetChunkX() != m_PosX) || + ((*itr)->GetChunkZ() != m_PosZ) ) { - // This block is very similar to RemoveEntity, except it uses an iterator to avoid scanning the whole m_Entities - // The entity moved out of the chunk, move it to the neighbor - - (*itr)->SetParentChunk(nullptr); - MoveEntityToNewChunk(*itr); // Mark as dirty if it was a server-generated entity: if (!(*itr)->IsPlayer()) { MarkDirty(); } + + // This block is very similar to RemoveEntity, except it uses an iterator to avoid scanning the whole m_Entities + // The entity moved out of the chunk, move it to the neighbor + (*itr)->SetParentChunk(nullptr); + MoveEntityToNewChunk(std::move(*itr)); + itr = m_Entities.erase(itr); } else @@ -753,7 +754,7 @@ void cChunk::TickBlock(int a_RelX, int a_RelY, int a_RelZ) -void cChunk::MoveEntityToNewChunk(cEntity * a_Entity) +void cChunk::MoveEntityToNewChunk(OwnedEntity a_Entity) { cChunk * Neighbor = GetNeighborChunk(a_Entity->GetChunkX() * cChunkDef::Width, a_Entity->GetChunkZ() * cChunkDef::Width); if (Neighbor == nullptr) @@ -767,28 +768,29 @@ void cChunk::MoveEntityToNewChunk(cEntity * a_Entity) } ASSERT(Neighbor != this); // Moving into the same chunk? wtf? - Neighbor->AddEntity(a_Entity); + auto & Entity = *a_Entity; + Neighbor->AddEntity(std::move(a_Entity)); class cMover : public cClientDiffCallback { virtual void Removed(cClientHandle * a_Client) override { - a_Client->SendDestroyEntity(*m_Entity); + a_Client->SendDestroyEntity(m_Entity); } virtual void Added(cClientHandle * a_Client) override { - m_Entity->SpawnOn(*a_Client); + m_Entity.SpawnOn(*a_Client); } - cEntity * m_Entity; + cEntity & m_Entity; public: - cMover(cEntity * a_CallbackEntity) : + cMover(cEntity & a_CallbackEntity) : m_Entity(a_CallbackEntity) {} - } Mover(a_Entity); + } Mover(Entity); m_ChunkMap->CompareChunkClients(this, Neighbor, Mover); } @@ -1869,15 +1871,15 @@ void cChunk::CollectPickupsByPlayer(cPlayer & a_Player) double PosY = a_Player.GetPosY(); double PosZ = a_Player.GetPosZ(); - for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr) + for (auto & Entity : m_Entities) { - if ((!(*itr)->IsPickup()) && (!(*itr)->IsProjectile())) + if ((!Entity->IsPickup()) && (!Entity->IsProjectile())) { continue; // Only pickups and projectiles can be picked up } - float DiffX = static_cast<float>((*itr)->GetPosX() - PosX); - float DiffY = static_cast<float>((*itr)->GetPosY() - PosY); - float DiffZ = static_cast<float>((*itr)->GetPosZ() - PosZ); + float DiffX = static_cast<float>(Entity->GetPosX() - PosX); + float DiffY = static_cast<float>(Entity->GetPosY() - PosY); + float DiffZ = static_cast<float>(Entity->GetPosZ() - PosZ); float SqrDist = DiffX * DiffX + DiffY * DiffY + DiffZ * DiffZ; if (SqrDist < 1.5f * 1.5f) // 1.5 block { @@ -1887,13 +1889,13 @@ void cChunk::CollectPickupsByPlayer(cPlayer & a_Player) ); */ MarkDirty(); - if ((*itr)->IsPickup()) + if (Entity->IsPickup()) { - (reinterpret_cast<cPickup *>(*itr))->CollectedBy(a_Player); + reinterpret_cast<cPickup *>(Entity.get())->CollectedBy(a_Player); } else { - (reinterpret_cast<cProjectileEntity *>(*itr))->CollectedBy(a_Player); + reinterpret_cast<cProjectileEntity *>(Entity.get())->CollectedBy(a_Player); } } else if (SqrDist < 5 * 5) @@ -1989,7 +1991,7 @@ void cChunk::RemoveClient(cClientHandle * a_Client) if (!a_Client->IsDestroyed()) { - for (auto Entity : m_Entities) + for (auto & Entity : m_Entities) { /* // DEBUG: @@ -2027,34 +2029,59 @@ bool cChunk::HasAnyClients(void) const -void cChunk::AddEntity(cEntity * a_Entity) +void cChunk::AddEntity(OwnedEntity a_Entity) { if (!a_Entity->IsPlayer()) { MarkDirty(); } + auto EntityPtr = a_Entity.get(); + ASSERT(std::find(m_Entities.begin(), m_Entities.end(), a_Entity) == m_Entities.end()); // Not there already + m_Entities.emplace_back(std::move(a_Entity)); - m_Entities.push_back(a_Entity); - ASSERT(a_Entity->GetParentChunk() == nullptr); - a_Entity->SetParentChunk(this); + ASSERT(EntityPtr->GetParentChunk() == nullptr); + EntityPtr->SetParentChunk(this); } -void cChunk::RemoveEntity(cEntity * a_Entity) +OwnedEntity cChunk::RemoveEntity(cEntity & a_Entity) { - ASSERT(a_Entity->GetParentChunk() == this); - a_Entity->SetParentChunk(nullptr); - m_Entities.remove(a_Entity); + ASSERT(a_Entity.GetParentChunk() == this); + ASSERT(!a_Entity.IsTicking()); + a_Entity.SetParentChunk(nullptr); + // Mark as dirty if it was a server-generated entity: - if (!a_Entity->IsPlayer()) + if (!a_Entity.IsPlayer()) { MarkDirty(); } + + OwnedEntity Removed; + m_Entities.erase( + std::remove_if( + m_Entities.begin(), + m_Entities.end(), + [&a_Entity, &Removed](decltype(m_Entities)::value_type & a_Value) + { + if (a_Value.get() == &a_Entity) + { + ASSERT(!Removed); + Removed = std::move(a_Value); + return true; + } + + return false; + } + ), + m_Entities.end() + ); + + return Removed; } @@ -2063,13 +2090,13 @@ void cChunk::RemoveEntity(cEntity * a_Entity) bool cChunk::HasEntity(UInt32 a_EntityID) { - for (cEntityList::const_iterator itr = m_Entities.begin(), end = m_Entities.end(); itr != end; ++itr) + for (const auto & Entity : m_Entities) { - if ((*itr)->GetUniqueID() == a_EntityID) + if (Entity->GetUniqueID() == a_EntityID) { return true; } - } // for itr - m_Entities[] + } return false; } @@ -2080,14 +2107,14 @@ bool cChunk::HasEntity(UInt32 a_EntityID) bool cChunk::ForEachEntity(cEntityCallback & a_Callback) { // The entity list is locked by the parent chunkmap's CS - for (cEntityList::iterator itr = m_Entities.begin(), itr2 = itr; itr != m_Entities.end(); itr = itr2) + for (auto itr = m_Entities.begin(), itr2 = itr; itr != m_Entities.end(); itr = itr2) { ++itr2; if (!(*itr)->IsTicking()) { continue; } - if (a_Callback.Item(*itr)) + if (a_Callback.Item(itr->get())) { return false; } @@ -2102,7 +2129,7 @@ bool cChunk::ForEachEntity(cEntityCallback & a_Callback) bool cChunk::ForEachEntityInBox(const cBoundingBox & a_Box, cEntityCallback & a_Callback) { // The entity list is locked by the parent chunkmap's CS - for (cEntityList::iterator itr = m_Entities.begin(), itr2 = itr; itr != m_Entities.end(); itr = itr2) + for (auto itr = m_Entities.begin(), itr2 = itr; itr != m_Entities.end(); itr = itr2) { ++itr2; if (!(*itr)->IsTicking()) @@ -2115,7 +2142,7 @@ bool cChunk::ForEachEntityInBox(const cBoundingBox & a_Box, cEntityCallback & a_ // The entity is not in the specified box continue; } - if (a_Callback.Item(*itr)) + if (a_Callback.Item(itr->get())) { return false; } @@ -2139,11 +2166,11 @@ bool cChunk::DoWithEntityByID(UInt32 a_EntityID, cEntityCallback & a_Callback, b bool cChunk::DoWithEntityByID(UInt32 a_EntityID, cLambdaEntityCallback a_Callback, bool & a_CallbackResult) { // The entity list is locked by the parent chunkmap's CS - for (cEntityList::iterator itr = m_Entities.begin(), end = m_Entities.end(); itr != end; ++itr) + for (const auto & Entity : m_Entities) { - if (((*itr)->GetUniqueID() == a_EntityID) && ((*itr)->IsTicking())) + if ((Entity->GetUniqueID() == a_EntityID) && (Entity->IsTicking())) { - a_CallbackResult = a_Callback(*itr); + a_CallbackResult = a_Callback(Entity.get()); return true; } } // for itr - m_Entitites[] diff --git a/src/Chunk.h b/src/Chunk.h index 87f2cd568..7e399052d 100644 --- a/src/Chunk.h +++ b/src/Chunk.h @@ -61,6 +61,7 @@ class cChunk : public cChunkDef // The inheritance is "misused" here only to inherit the functions and constants defined in cChunkDef { public: + /** Represents the presence state of the chunk */ enum ePresence { @@ -75,7 +76,7 @@ public: cChunk * a_NeighborXM, cChunk * a_NeighborXP, cChunk * a_NeighborZM, cChunk * a_NeighborZP, // Neighbor chunks cAllocationPool<cChunkData::sChunkSection> & a_Pool ); - cChunk(cChunk & other); + cChunk(cChunk & other) = delete; ~cChunk(); /** Returns true iff the chunk block data is valid (loaded / generated) */ @@ -248,8 +249,12 @@ public: /** Returns true if theres any client in the chunk; false otherwise */ bool HasAnyClients(void) const; - void AddEntity(cEntity * a_Entity); - void RemoveEntity(cEntity * a_Entity); + void AddEntity(OwnedEntity a_Entity); + + /** Releases ownership of the given entity if it was found in this chunk. + Returns an owning reference to the found entity. */ + OwnedEntity RemoveEntity(cEntity & a_Entity); + bool HasEntity(UInt32 a_EntityID); /** Calls the callback for each entity; returns true if all entities processed, false if the callback aborted by returning true */ @@ -525,7 +530,7 @@ private: // A critical section is not needed, because all chunk access is protected by its parent ChunkMap's csLayers std::vector<cClientHandle *> m_LoadedByClient; - cEntityList m_Entities; + std::vector<OwnedEntity> m_Entities; cBlockEntities m_BlockEntities; /** Number of times the chunk has been requested to stay (by various cChunkStay objects); if zero, the chunk can be unloaded */ @@ -602,7 +607,7 @@ private: bool GrowMelonPumpkin(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType); /** Called by Tick() when an entity moves out of this chunk into a neighbor; moves the entity and sends spawn / despawn packet to clients */ - void MoveEntityToNewChunk(cEntity * a_Entity); + void MoveEntityToNewChunk(OwnedEntity a_Entity); }; typedef cChunk * cChunkPtr; diff --git a/src/ChunkDef.h b/src/ChunkDef.h index 0e9dbf6b7..f4a0867b5 100644 --- a/src/ChunkDef.h +++ b/src/ChunkDef.h @@ -29,7 +29,8 @@ class cClientHandle; class cBlockEntity; class cChunkCoords; -typedef std::list<cEntity *> cEntityList; +typedef std::unique_ptr<cEntity> OwnedEntity; +typedef std::vector<OwnedEntity> cEntityList; typedef std::map<int, cBlockEntity *> cBlockEntities; diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp index 1e5bb6f93..fcd990ad6 100644 --- a/src/ChunkMap.cpp +++ b/src/ChunkMap.cpp @@ -1495,38 +1495,38 @@ void cChunkMap::RemoveClientFromChunks(cClientHandle * a_Client) -void cChunkMap::AddEntity(cEntity * a_Entity) +void cChunkMap::AddEntity(OwnedEntity a_Entity) { cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunk(a_Entity->GetChunkX(), a_Entity->GetChunkZ()); if (Chunk == nullptr) // This will assert inside GetChunk in Debug builds { LOGWARNING("Entity at %p (%s, ID %d) spawning in a non-existent chunk, the entity is lost.", - static_cast<void *>(a_Entity), a_Entity->GetClass(), a_Entity->GetUniqueID() + static_cast<void *>(a_Entity.get()), a_Entity->GetClass(), a_Entity->GetUniqueID() ); return; } - Chunk->AddEntity(a_Entity); + Chunk->AddEntity(std::move(a_Entity)); } -void cChunkMap::AddEntityIfNotPresent(cEntity * a_Entity) +void cChunkMap::AddEntityIfNotPresent(OwnedEntity a_Entity) { cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunk(a_Entity->GetChunkX(), a_Entity->GetChunkZ()); if (Chunk == nullptr) // This will assert inside GetChunk in Debug builds { LOGWARNING("Entity at %p (%s, ID %d) spawning in a non-existent chunk, the entity is lost.", - static_cast<void *>(a_Entity), a_Entity->GetClass(), a_Entity->GetUniqueID() + static_cast<void *>(a_Entity.get()), a_Entity->GetClass(), a_Entity->GetUniqueID() ); return; } if (!Chunk->HasEntity(a_Entity->GetUniqueID())) { - Chunk->AddEntity(a_Entity); + Chunk->AddEntity(std::move(a_Entity)); } } @@ -1551,17 +1551,18 @@ bool cChunkMap::HasEntity(UInt32 a_UniqueID) -void cChunkMap::RemoveEntity(cEntity * a_Entity) +OwnedEntity cChunkMap::RemoveEntity(cEntity & a_Entity) { cCSLock Lock(m_CSChunks); - cChunkPtr Chunk = a_Entity->GetParentChunk(); + cChunkPtr Chunk = a_Entity.GetParentChunk(); - // Even if a chunk is not valid, it may still contain entities such as players; make sure to remove them (#1190) if (Chunk == nullptr) { - return; + return nullptr; } - Chunk->RemoveEntity(a_Entity); + + // Remove the entity no matter whether the chunk itself is valid or not (#1190) + return Chunk->RemoveEntity(a_Entity); } diff --git a/src/ChunkMap.h b/src/ChunkMap.h index 87174e624..e902be60c 100644 --- a/src/ChunkMap.h +++ b/src/ChunkMap.h @@ -214,17 +214,18 @@ public: void RemoveClientFromChunks(cClientHandle * a_Client); /** Adds the entity to its appropriate chunk, takes ownership of the entity pointer */ - void AddEntity(cEntity * a_Entity); + void AddEntity(OwnedEntity a_Entity); /** Adds the entity to its appropriate chunk, if the entity is not already added. Takes ownership of the entity pointer */ - void AddEntityIfNotPresent(cEntity * a_Entity); + void AddEntityIfNotPresent(OwnedEntity a_Entity); /** Returns true if the entity with specified ID is present in the chunks */ bool HasEntity(UInt32 a_EntityID); - /** Removes the entity from its appropriate chunk */ - void RemoveEntity(cEntity * a_Entity); + /** Removes the entity from its appropriate chunk + Returns an owning reference to the found entity. */ + OwnedEntity RemoveEntity(cEntity & a_Entity); /** Calls the callback for each entity in the entire world; returns true if all entities processed, false if the callback aborted by returning true */ bool ForEachEntity(cEntityCallback & a_Callback); // Lua-accessible diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index b015b745f..9366facf3 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -133,7 +133,7 @@ cClientHandle::~cClientHandle() } m_Player->DestroyNoScheduling(true); } - delete m_Player; + m_PlayerPtr.reset(); m_Player = nullptr; } @@ -157,8 +157,12 @@ void cClientHandle::Destroy(void) cCSLock Lock(m_CSOutgoingData); m_Link.reset(); } + + // Temporary (#3115-will-fix): variable to keep track of whether the client authenticated and had the opportunity to have ownership transferred to the world + bool WasAddedToWorld = false; { cCSLock Lock(m_CSState); + WasAddedToWorld = (m_State >= csAuthenticated); if (m_State >= csDestroying) { // Already called @@ -186,7 +190,23 @@ void cClientHandle::Destroy(void) { player->StopEveryoneFromTargetingMe(); player->SetIsTicking(false); - world->RemovePlayer(player, true); + + if (WasAddedToWorld) + { + // If ownership was transferred, our own smart pointer should be unset + ASSERT(!m_PlayerPtr); + + m_PlayerPtr = world->RemovePlayer(*player, true); + + // And RemovePlayer should have returned a valid smart pointer + ASSERT(m_PlayerPtr); + } + else + { + // If ownership was not transferred, our own smart pointer should be valid and RemovePlayer's should not + ASSERT(m_PlayerPtr); + ASSERT(!world->IsPlayerReferencedInWorldOrChunk(*player)); + } } player->RemoveClientHandle(); } @@ -359,7 +379,8 @@ void cClientHandle::Authenticate(const AString & a_Name, const AString & a_UUID, m_Protocol->SendLoginSuccess(); // Spawn player (only serversided, so data is loaded) - m_Player = new cPlayer(m_Self, GetUsername()); + m_PlayerPtr = cpp14::make_unique<cPlayer>(m_Self, GetUsername()); + m_Player = m_PlayerPtr.get(); /* LOGD("Created a new cPlayer object at %p for client %s @ %s (%p)", static_cast<void *>(m_Player), @@ -2203,7 +2224,7 @@ void cClientHandle::ServerTick(float a_Dt) // Add the player to the world (start ticking from there): m_State = csDownloadingWorld; - m_Player->Initialize(*(m_Player->GetWorld())); + m_Player->Initialize(std::move(m_PlayerPtr), *(m_Player->GetWorld())); return; } } // lock(m_CSState) diff --git a/src/ClientHandle.h b/src/ClientHandle.h index b298751fe..9e1d1a9b5 100644 --- a/src/ClientHandle.h +++ b/src/ClientHandle.h @@ -416,6 +416,9 @@ private: cPlayer * m_Player; + // Temporary (#3115-will-fix): maintain temporary ownership of created cPlayer objects while they are in limbo + std::unique_ptr<cPlayer> m_PlayerPtr; + /** This is an optimization which saves you an iteration of m_SentChunks if you just want to know whether or not the player is standing at a sent chunk. If this is equal to the coordinates of the chunk the player is currrently standing at, then this must be a sent chunk diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 245ae84bf..a38a6552d 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -135,9 +135,9 @@ const char * cEntity::GetParentClass(void) const -bool cEntity::Initialize(cWorld & a_World) +bool cEntity::Initialize(OwnedEntity a_Self, cWorld & a_EntityWorld) { - if (cPluginManager::Get()->CallHookSpawningEntity(a_World, *this)) + if (cPluginManager::Get()->CallHookSpawningEntity(a_EntityWorld, *this)) { return false; } @@ -151,13 +151,13 @@ bool cEntity::Initialize(cWorld & a_World) ASSERT(m_World == nullptr); ASSERT(GetParentChunk() == nullptr); - a_World.AddEntity(this); + a_EntityWorld.AddEntity(std::move(a_Self)); ASSERT(m_World != nullptr); - cPluginManager::Get()->CallHookSpawnedEntity(a_World, *this); + cPluginManager::Get()->CallHookSpawnedEntity(a_EntityWorld, *this); // Spawn the entity on the clients: - a_World.BroadcastSpawnEntity(*this); + a_EntityWorld.BroadcastSpawnEntity(*this); return true; } @@ -230,8 +230,10 @@ void cEntity::Destroy(bool a_ShouldBroadcast) this->GetUniqueID(), this->GetClass(), ParentChunk->GetPosX(), ParentChunk->GetPosZ() ); - ParentChunk->RemoveEntity(this); - delete this; + + // Make sure that RemoveEntity returned a valid smart pointer + // Also, not storing the returned pointer means automatic destruction + VERIFY(ParentChunk->RemoveEntity(*this)); }); Destroyed(); } @@ -1581,8 +1583,7 @@ bool cEntity::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn, Vector3d a_OldWorld.GetName().c_str(), a_World->GetName().c_str(), ParentChunk->GetPosX(), ParentChunk->GetPosZ() ); - ParentChunk->RemoveEntity(this); - a_World->AddEntity(this); + a_World->AddEntity(ParentChunk->RemoveEntity(*this)); cRoot::Get()->GetPluginManager()->CallHookEntityChangedWorld(*this, a_OldWorld); }); return true; diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h index 8991b9fad..8f433b816 100644 --- a/src/Entities/Entity.h +++ b/src/Entities/Entity.h @@ -157,7 +157,7 @@ public: /** Spawns the entity in the world; returns true if spawned, false if not (plugin disallowed). Adds the entity to the world. */ - virtual bool Initialize(cWorld & a_World); + virtual bool Initialize(OwnedEntity a_Self, cWorld & a_EntityWorld); // tolua_begin @@ -670,8 +670,6 @@ private: int m_InvulnerableTicks; } ; // tolua_export -typedef std::list<cEntity *> cEntityList; - diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 3e6d912dd..a1b518cbc 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -149,12 +149,12 @@ cPlayer::cPlayer(cClientHandlePtr a_Client, const AString & a_PlayerName) : -bool cPlayer::Initialize(cWorld & a_World) +bool cPlayer::Initialize(OwnedEntity a_Self, cWorld & a_World) { UNUSED(a_World); ASSERT(GetWorld() != nullptr); ASSERT(GetParentChunk() == nullptr); - GetWorld()->AddPlayer(this); + GetWorld()->AddPlayer(std::unique_ptr<cPlayer>(static_cast<cPlayer *>(a_Self.release()))); cPluginManager::Get()->CallHookSpawnedEntity(*GetWorld(), *this); @@ -2009,7 +2009,9 @@ bool cPlayer::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn, Vector3d GetWorld()->BroadcastDestroyEntity(*this); // Remove player from world - GetWorld()->RemovePlayer(this, false); + // Make sure that RemovePlayer didn't return a valid smart pointer, due to the second parameter being false + // We remain valid and not destructed after this call + VERIFY(!GetWorld()->RemovePlayer(*this, false)); // Set position to the new position SetPosition(a_NewPosition); @@ -2051,8 +2053,10 @@ bool cPlayer::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn, Vector3d a_OldWorld.GetName().c_str(), a_World->GetName().c_str(), ParentChunk->GetPosX(), ParentChunk->GetPosZ() ); - ParentChunk->RemoveEntity(this); - a_World->AddPlayer(this, &a_OldWorld); // New world will take over and announce client at its next tick + + // New world will take over and announce client at its next tick + auto PlayerPtr = static_cast<cPlayer *>(ParentChunk->RemoveEntity(*this).release()); + a_World->AddPlayer(std::unique_ptr<cPlayer>(PlayerPtr), &a_OldWorld); }); return true; diff --git a/src/Entities/Player.h b/src/Entities/Player.h index c00dbc7f1..8c21c25d6 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -41,7 +41,7 @@ public: cPlayer(cClientHandlePtr a_Client, const AString & a_PlayerName); - virtual bool Initialize(cWorld & a_World) override; + virtual bool Initialize(OwnedEntity a_Self, cWorld & a_World) override; virtual ~cPlayer() override; diff --git a/src/Entities/ProjectileEntity.cpp b/src/Entities/ProjectileEntity.cpp index 64522acef..d1e101964 100644 --- a/src/Entities/ProjectileEntity.cpp +++ b/src/Entities/ProjectileEntity.cpp @@ -260,7 +260,7 @@ cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Ve -cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem * a_Item, const Vector3d * a_Speed) +std::unique_ptr<cProjectileEntity> cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem * a_Item, const Vector3d * a_Speed) { Vector3d Speed; if (a_Speed != nullptr) @@ -270,15 +270,15 @@ cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator, switch (a_Kind) { - case pkArrow: return new cArrowEntity (a_Creator, a_X, a_Y, a_Z, Speed); - case pkEgg: return new cThrownEggEntity (a_Creator, a_X, a_Y, a_Z, Speed); - case pkEnderPearl: return new cThrownEnderPearlEntity(a_Creator, a_X, a_Y, a_Z, Speed); - case pkSnowball: return new cThrownSnowballEntity (a_Creator, a_X, a_Y, a_Z, Speed); - case pkGhastFireball: return new cGhastFireballEntity (a_Creator, a_X, a_Y, a_Z, Speed); - case pkFireCharge: return new cFireChargeEntity (a_Creator, a_X, a_Y, a_Z, Speed); - case pkExpBottle: return new cExpBottleEntity (a_Creator, a_X, a_Y, a_Z, Speed); - case pkSplashPotion: return new cSplashPotionEntity (a_Creator, a_X, a_Y, a_Z, Speed, *a_Item); - case pkWitherSkull: return new cWitherSkullEntity (a_Creator, a_X, a_Y, a_Z, Speed); + case pkArrow: return cpp14::make_unique<cArrowEntity> (a_Creator, a_X, a_Y, a_Z, Speed); + case pkEgg: return cpp14::make_unique<cThrownEggEntity> (a_Creator, a_X, a_Y, a_Z, Speed); + case pkEnderPearl: return cpp14::make_unique<cThrownEnderPearlEntity>(a_Creator, a_X, a_Y, a_Z, Speed); + case pkSnowball: return cpp14::make_unique<cThrownSnowballEntity> (a_Creator, a_X, a_Y, a_Z, Speed); + case pkGhastFireball: return cpp14::make_unique<cGhastFireballEntity> (a_Creator, a_X, a_Y, a_Z, Speed); + case pkFireCharge: return cpp14::make_unique<cFireChargeEntity> (a_Creator, a_X, a_Y, a_Z, Speed); + case pkExpBottle: return cpp14::make_unique<cExpBottleEntity> (a_Creator, a_X, a_Y, a_Z, Speed); + case pkSplashPotion: return cpp14::make_unique<cSplashPotionEntity> (a_Creator, a_X, a_Y, a_Z, Speed, *a_Item); + case pkWitherSkull: return cpp14::make_unique<cWitherSkullEntity> (a_Creator, a_X, a_Y, a_Z, Speed); case pkFirework: { ASSERT(a_Item != nullptr); @@ -287,7 +287,7 @@ cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator, return nullptr; } - return new cFireworkEntity(a_Creator, a_X, a_Y, a_Z, *a_Item); + return cpp14::make_unique<cFireworkEntity>(a_Creator, a_X, a_Y, a_Z, *a_Item); } case pkFishingFloat: break; } diff --git a/src/Entities/ProjectileEntity.h b/src/Entities/ProjectileEntity.h index b354c7cfc..da8c650f5 100644 --- a/src/Entities/ProjectileEntity.h +++ b/src/Entities/ProjectileEntity.h @@ -46,7 +46,7 @@ public: cProjectileEntity(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, double a_Width, double a_Height); cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Vector3d & a_Pos, const Vector3d & a_Speed, double a_Width, double a_Height); - static cProjectileEntity * Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem * a_Item, const Vector3d * a_Speed = nullptr); + static std::unique_ptr<cProjectileEntity> Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem * a_Item, const Vector3d * a_Speed = nullptr); /** Called by the physics blocktracer when the entity hits a solid block, the hit position and the face hit (BLOCK_FACE_) is given */ virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace); diff --git a/src/Generating/ChunkDesc.cpp b/src/Generating/ChunkDesc.cpp index 22a0113e5..451451fd3 100644 --- a/src/Generating/ChunkDesc.cpp +++ b/src/Generating/ChunkDesc.cpp @@ -7,6 +7,7 @@ #include "ChunkDesc.h" #include "../Noise/Noise.h" #include "../BlockEntities/BlockEntity.h" +#include "../Entities/Entity.h" diff --git a/src/Generating/ChunkDesc.h b/src/Generating/ChunkDesc.h index 4c97430a2..709fccb70 100644 --- a/src/Generating/ChunkDesc.h +++ b/src/Generating/ChunkDesc.h @@ -231,7 +231,7 @@ private: cChunkDef::BiomeMap m_BiomeMap; cBlockArea m_BlockArea; cChunkDef::HeightMap m_HeightMap; - cEntityList m_Entities; // Individual entities are NOT owned by this object! + cEntityList m_Entities; cBlockEntities m_BlockEntities; // Individual block entities are NOT owned by this object! bool m_bUseDefaultBiomes; diff --git a/src/Generating/FinishGen.cpp b/src/Generating/FinishGen.cpp index d1201797c..fe5ce82be 100644 --- a/src/Generating/FinishGen.cpp +++ b/src/Generating/FinishGen.cpp @@ -1489,11 +1489,11 @@ bool cFinishGenPassiveMobs::TrySpawnAnimals(cChunkDesc & a_ChunkDesc, int a_RelX double AnimalY = a_RelY; double AnimalZ = static_cast<double>(a_ChunkDesc.GetChunkZ() * cChunkDef::Width + a_RelZ + 0.5); - cMonster * NewMob = cMonster::NewMonsterFromType(AnimalToSpawn); + auto NewMob = cMonster::NewMonsterFromType(AnimalToSpawn); NewMob->SetHealth(NewMob->GetMaxHealth()); NewMob->SetPosition(AnimalX, AnimalY, AnimalZ); - a_ChunkDesc.GetEntities().push_back(NewMob); LOGD("Spawning %s #%i at {%.02f, %.02f, %.02f}", NewMob->GetClass(), NewMob->GetUniqueID(), AnimalX, AnimalY, AnimalZ); + a_ChunkDesc.GetEntities().emplace_back(std::move(NewMob)); return true; } diff --git a/src/Items/ItemBoat.h b/src/Items/ItemBoat.h index bdfed8944..f39a35a88 100644 --- a/src/Items/ItemBoat.h +++ b/src/Items/ItemBoat.h @@ -95,11 +95,8 @@ public: } // Spawn block at water level - cBoat * Boat = new cBoat(x + 0.5, y + 0.5, z + 0.5, cBoat::ItemToMaterial(a_Player->GetEquippedItem())); - if (!Boat->Initialize(*a_World)) + if (a_World->SpawnBoat(x + 0.5, y + 0.5, z + 0.5, cBoat::ItemToMaterial(a_Player->GetEquippedItem())) == cEntity::INVALID_ID) { - delete Boat; - Boat = nullptr; return false; } diff --git a/src/Items/ItemBow.h b/src/Items/ItemBow.h index a2f646efc..7cbd1dc70 100644 --- a/src/Items/ItemBow.h +++ b/src/Items/ItemBow.h @@ -69,17 +69,12 @@ public: } // Create the arrow entity: - cArrowEntity * Arrow = new cArrowEntity(*a_Player, Force * 2); - if (Arrow == nullptr) + auto Arrow = cpp14::make_unique<cArrowEntity>(*a_Player, Force * 2); + auto ArrowPtr = Arrow.get(); + if (!ArrowPtr->Initialize(std::move(Arrow), *a_Player->GetWorld())) { return; } - if (!Arrow->Initialize(*a_Player->GetWorld())) - { - delete Arrow; - Arrow = nullptr; - return; - } a_Player->GetWorld()->BroadcastSoundEffect( "entity.arrow.shoot", a_Player->GetPosX(), diff --git a/src/Items/ItemFishingRod.h b/src/Items/ItemFishingRod.h index a32368304..012f13a6c 100644 --- a/src/Items/ItemFishingRod.h +++ b/src/Items/ItemFishingRod.h @@ -251,14 +251,13 @@ public: } else { - cFloater * Floater = new cFloater(a_Player->GetPosX(), a_Player->GetStance(), a_Player->GetPosZ(), a_Player->GetLookVector() * 15, a_Player->GetUniqueID(), (Random.RandInt(100, 900) - static_cast<int>(a_Player->GetEquippedItem().m_Enchantments.GetLevel(cEnchantments::enchLure) * 100))); - if (!Floater->Initialize(*a_World)) + auto Floater = cpp14::make_unique<cFloater>(a_Player->GetPosX(), a_Player->GetStance(), a_Player->GetPosZ(), a_Player->GetLookVector() * 15, a_Player->GetUniqueID(), (Random.RandInt(100, 900) - static_cast<int>(a_Player->GetEquippedItem().m_Enchantments.GetLevel(cEnchantments::enchLure) * 100))); + auto FloaterPtr = Floater.get(); + if (!FloaterPtr->Initialize(std::move(Floater), *a_World)) { - delete Floater; - Floater = nullptr; return false; } - a_Player->SetIsFishing(true, Floater->GetUniqueID()); + a_Player->SetIsFishing(true, FloaterPtr->GetUniqueID()); } return true; } diff --git a/src/Items/ItemItemFrame.h b/src/Items/ItemItemFrame.h index 77a5bf47c..dd3e1f5a8 100644 --- a/src/Items/ItemItemFrame.h +++ b/src/Items/ItemItemFrame.h @@ -38,11 +38,10 @@ public: if (Block == E_BLOCK_AIR) { - cItemFrame * ItemFrame = new cItemFrame(a_BlockFace, a_BlockX, a_BlockY, a_BlockZ); - if (!ItemFrame->Initialize(*a_World)) + auto ItemFrame = cpp14::make_unique<cItemFrame>(a_BlockFace, a_BlockX, a_BlockY, a_BlockZ); + auto ItemFramePtr = ItemFrame.get(); + if (!ItemFramePtr->Initialize(std::move(ItemFrame), *a_World)) { - delete ItemFrame; - ItemFrame = nullptr; return false; } diff --git a/src/Items/ItemMinecart.h b/src/Items/ItemMinecart.h index 623342d41..05f375f06 100644 --- a/src/Items/ItemMinecart.h +++ b/src/Items/ItemMinecart.h @@ -59,24 +59,9 @@ public: double x = static_cast<double>(a_BlockX) + 0.5; double y = static_cast<double>(a_BlockY) + 0.5; double z = static_cast<double>(a_BlockZ) + 0.5; - cMinecart * Minecart = nullptr; - switch (m_ItemType) - { - case E_ITEM_MINECART: Minecart = new cRideableMinecart (x, y, z, cItem(), 1); break; - case E_ITEM_CHEST_MINECART: Minecart = new cMinecartWithChest (x, y, z); break; - case E_ITEM_FURNACE_MINECART: Minecart = new cMinecartWithFurnace (x, y, z); break; - case E_ITEM_MINECART_WITH_TNT: Minecart = new cMinecartWithTNT (x, y, z); break; - case E_ITEM_MINECART_WITH_HOPPER: Minecart = new cMinecartWithHopper (x, y, z); break; - default: - { - ASSERT(!"Unhandled minecart item"); - return false; - } - } // switch (m_ItemType) - if (!Minecart->Initialize(*a_World)) + + if (a_World->SpawnMinecart(x, y, z, m_ItemType) == cEntity::INVALID_ID) { - delete Minecart; - Minecart = nullptr; return false; } diff --git a/src/Items/ItemPainting.h b/src/Items/ItemPainting.h index 3432583ca..8e5a1b5d2 100644 --- a/src/Items/ItemPainting.h +++ b/src/Items/ItemPainting.h @@ -70,11 +70,10 @@ public: { "BurningSkull" } }; - cPainting * Painting = new cPainting(gPaintingTitlesList[a_World->GetTickRandomNumber(ARRAYCOUNT(gPaintingTitlesList) - 1)].Title, a_BlockFace, a_BlockX, a_BlockY, a_BlockZ); - if (!Painting->Initialize(*a_World)) + auto Painting = cpp14::make_unique<cPainting>(gPaintingTitlesList[a_World->GetTickRandomNumber(ARRAYCOUNT(gPaintingTitlesList) - 1)].Title, a_BlockFace, a_BlockX, a_BlockY, a_BlockZ); + auto PaintingPtr = Painting.get(); + if (!PaintingPtr->Initialize(std::move(Painting), *a_World)) { - delete Painting; - Painting = nullptr; return false; } diff --git a/src/MobSpawner.cpp b/src/MobSpawner.cpp index e3f5298e4..1e0db5175 100644 --- a/src/MobSpawner.cpp +++ b/src/MobSpawner.cpp @@ -342,13 +342,12 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R cMonster * cMobSpawner::TryToSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, EMCSBiome a_Biome, int & a_MaxPackSize) { - cMonster * toReturn = nullptr; if (m_NewPack) { m_MobType = ChooseMobType(a_Biome); if (m_MobType == mtInvalidType) { - return toReturn; + return nullptr; } if (m_MobType == mtWolf) { @@ -366,14 +365,16 @@ cMonster * cMobSpawner::TryToSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, if ((m_AllowedTypes.find(m_MobType) != m_AllowedTypes.end()) && CanSpawnHere(a_Chunk, a_RelX, a_RelY, a_RelZ, m_MobType, a_Biome)) { - cMonster * newMob = cMonster::NewMonsterFromType(m_MobType); + auto newMob = cMonster::NewMonsterFromType(m_MobType); + auto NewMobPtr = newMob.get(); if (newMob) { - m_Spawned.insert(newMob); + m_Spawned.insert(std::move(newMob)); } - toReturn = newMob; + return NewMobPtr; } - return toReturn; + + return nullptr; } diff --git a/src/MobSpawner.h b/src/MobSpawner.h index 4d38d9657..14c721ae3 100644 --- a/src/MobSpawner.h +++ b/src/MobSpawner.h @@ -37,7 +37,7 @@ public : // return true if there is at least one allowed type bool CanSpawnAnything(void); - typedef const std::set<cMonster *> tSpawnedContainer; + typedef const std::set<std::unique_ptr<cMonster>> tSpawnedContainer; tSpawnedContainer & getSpawned(void); /** Returns true if specified type of mob can spawn on specified block */ @@ -55,7 +55,7 @@ protected : std::set<eMonsterType> m_AllowedTypes; bool m_NewPack; eMonsterType m_MobType; - std::set<cMonster *> m_Spawned; + std::set<std::unique_ptr<cMonster>> m_Spawned; } ; diff --git a/src/Mobs/Blaze.cpp b/src/Mobs/Blaze.cpp index 8cdac12d1..a48bfa886 100644 --- a/src/Mobs/Blaze.cpp +++ b/src/Mobs/Blaze.cpp @@ -39,19 +39,17 @@ bool cBlaze::Attack(std::chrono::milliseconds a_Dt) // Setting this higher gives us more wiggle room for attackrate Vector3d Speed = GetLookVector() * 20; Speed.y = Speed.y + 1; - cFireChargeEntity * FireCharge = new cFireChargeEntity(this, GetPosX(), GetPosY() + 1, GetPosZ(), Speed); - if (FireCharge == nullptr) - { - return false; - } - if (!FireCharge->Initialize(*m_World)) + + auto FireCharge = cpp14::make_unique<cFireChargeEntity>(this, GetPosX(), GetPosY() + 1, GetPosZ(), Speed); + auto FireChargePtr = FireCharge.get(); + if (!FireChargePtr->Initialize(std::move(FireCharge), *m_World)) { - delete FireCharge; - FireCharge = nullptr; return false; } + ResetAttackCooldown(); // ToDo: Shoot 3 fireballs instead of 1. + return true; } return false; diff --git a/src/Mobs/Ghast.cpp b/src/Mobs/Ghast.cpp index 6f5a93d93..2488e63b1 100644 --- a/src/Mobs/Ghast.cpp +++ b/src/Mobs/Ghast.cpp @@ -39,17 +39,14 @@ bool cGhast::Attack(std::chrono::milliseconds a_Dt) // Setting this higher gives us more wiggle room for attackrate Vector3d Speed = GetLookVector() * 20; Speed.y = Speed.y + 1; - cGhastFireballEntity * GhastBall = new cGhastFireballEntity(this, GetPosX(), GetPosY() + 1, GetPosZ(), Speed); - if (GhastBall == nullptr) - { - return false; - } - if (!GhastBall->Initialize(*m_World)) + + auto GhastBall = cpp14::make_unique<cGhastFireballEntity>(this, GetPosX(), GetPosY() + 1, GetPosZ(), Speed); + auto GhastBallPtr = GhastBall.get(); + if (!GhastBallPtr->Initialize(std::move(GhastBall), *m_World)) { - delete GhastBall; - GhastBall = nullptr; return false; } + ResetAttackCooldown(); return true; } diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index ecda6e724..6dc03c7e3 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -996,7 +996,7 @@ void cMonster::UnsafeUnsetTarget() -cPawn * cMonster::GetTarget () +cPawn * cMonster::GetTarget() { return m_Target; } @@ -1005,29 +1005,25 @@ cPawn * cMonster::GetTarget () -cMonster * cMonster::NewMonsterFromType(eMonsterType a_MobType) +std::unique_ptr<cMonster> cMonster::NewMonsterFromType(eMonsterType a_MobType) { auto & Random = GetRandomProvider(); - cMonster * toReturn = nullptr; // Create the mob entity switch (a_MobType) { case mtMagmaCube: { - toReturn = new cMagmaCube(1 << Random.RandInt(2)); // Size 1, 2 or 4 - break; + return cpp14::make_unique<cMagmaCube>(1 << Random.RandInt(2)); // Size 1, 2 or 4 } case mtSlime: { - toReturn = new cSlime(1 << Random.RandInt(2)); // Size 1, 2 or 4 - break; + return cpp14::make_unique<cSlime>(1 << Random.RandInt(2)); // Size 1, 2 or 4 } case mtSkeleton: { // TODO: Actual detection of spawning in Nether - toReturn = new cSkeleton(false); - break; + return cpp14::make_unique<cSkeleton>(false); } case mtVillager: { @@ -1038,8 +1034,7 @@ cMonster * cMonster::NewMonsterFromType(eMonsterType a_MobType) VillagerType = 0; } - toReturn = new cVillager(static_cast<cVillager::eVillagerType>(VillagerType)); - break; + return cpp14::make_unique<cVillager>(static_cast<cVillager::eVillagerType>(VillagerType)); } case mtHorse: { @@ -1055,42 +1050,41 @@ cMonster * cMonster::NewMonsterFromType(eMonsterType a_MobType) HorseType = 0; } - toReturn = new cHorse(HorseType, HorseColor, HorseStyle, HorseTameTimes); - break; + return cpp14::make_unique<cHorse>(HorseType, HorseColor, HorseStyle, HorseTameTimes); } - case mtBat: toReturn = new cBat(); break; - case mtBlaze: toReturn = new cBlaze(); break; - case mtCaveSpider: toReturn = new cCaveSpider(); break; - case mtChicken: toReturn = new cChicken(); break; - case mtCow: toReturn = new cCow(); break; - case mtCreeper: toReturn = new cCreeper(); break; - case mtEnderDragon: toReturn = new cEnderDragon(); break; - case mtEnderman: toReturn = new cEnderman(); break; - case mtGhast: toReturn = new cGhast(); break; - case mtGiant: toReturn = new cGiant(); break; - case mtGuardian: toReturn = new cGuardian(); break; - case mtIronGolem: toReturn = new cIronGolem(); break; - case mtMooshroom: toReturn = new cMooshroom(); break; - case mtOcelot: toReturn = new cOcelot(); break; - case mtPig: toReturn = new cPig(); break; - case mtRabbit: toReturn = new cRabbit(); break; - case mtSheep: toReturn = new cSheep(); break; - case mtSilverfish: toReturn = new cSilverfish(); break; - case mtSnowGolem: toReturn = new cSnowGolem(); break; - case mtSpider: toReturn = new cSpider(); break; - case mtSquid: toReturn = new cSquid(); break; - case mtWitch: toReturn = new cWitch(); break; - case mtWither: toReturn = new cWither(); break; - case mtWolf: toReturn = new cWolf(); break; - case mtZombie: toReturn = new cZombie(false); break; // TODO: Infected zombie parameter - case mtZombiePigman: toReturn = new cZombiePigman(); break; + case mtBat: return cpp14::make_unique<cBat>(); + case mtBlaze: return cpp14::make_unique<cBlaze>(); + case mtCaveSpider: return cpp14::make_unique<cCaveSpider>(); + case mtChicken: return cpp14::make_unique<cChicken>(); + case mtCow: return cpp14::make_unique<cCow>(); + case mtCreeper: return cpp14::make_unique < cCreeper>(); + case mtEnderDragon: return cpp14::make_unique<cEnderDragon>(); + case mtEnderman: return cpp14::make_unique<cEnderman>(); + case mtGhast: return cpp14::make_unique<cGhast>(); + case mtGiant: return cpp14::make_unique<cGiant>(); + case mtGuardian: return cpp14::make_unique<cGuardian>(); + case mtIronGolem: return cpp14::make_unique<cIronGolem>(); + case mtMooshroom: return cpp14::make_unique<cMooshroom>(); + case mtOcelot: return cpp14::make_unique<cOcelot>(); + case mtPig: return cpp14::make_unique<cPig>(); + case mtRabbit: return cpp14::make_unique<cRabbit>(); + case mtSheep: return cpp14::make_unique<cSheep>(); + case mtSilverfish: return cpp14::make_unique<cSilverfish>(); + case mtSnowGolem: return cpp14::make_unique<cSnowGolem>(); + case mtSpider: return cpp14::make_unique<cSpider>(); + case mtSquid: return cpp14::make_unique<cSquid>(); + case mtWitch: return cpp14::make_unique<cWitch>(); + case mtWither: return cpp14::make_unique<cWither>(); + case mtWolf: return cpp14::make_unique<cWolf>(); + case mtZombie: return cpp14::make_unique<cZombie>(false); // TODO: Infected zombie parameter + case mtZombiePigman: return cpp14::make_unique<cZombiePigman>(); default: { ASSERT(!"Unhandled mob type whilst trying to spawn mob!"); + return nullptr; } } - return toReturn; } diff --git a/src/Mobs/Monster.h b/src/Mobs/Monster.h index d1630e4ff..268db6168 100644 --- a/src/Mobs/Monster.h +++ b/src/Mobs/Monster.h @@ -168,13 +168,13 @@ public: void UnsafeUnsetTarget(); /** Returns the current target. */ - cPawn * GetTarget (); + cPawn * GetTarget(); /** Creates a new object of the specified mob. a_MobType is the type of the mob to be created Asserts and returns null if mob type is not specified */ - static cMonster * NewMonsterFromType(eMonsterType a_MobType); + static std::unique_ptr<cMonster> NewMonsterFromType(eMonsterType a_MobType); /** Returns if this mob last target was a player to avoid destruction on player quit */ bool WasLastTargetAPlayer() const { return m_WasLastTargetAPlayer; } @@ -203,7 +203,11 @@ protected: bool ReachedFinalDestination(void) { return ((m_FinalDestination - GetPosition()).SqrLength() < WAYPOINT_RADIUS * WAYPOINT_RADIUS); } /** Returns whether or not the target is close enough for attack. */ - bool TargetIsInRange(void) { ASSERT(m_Target != nullptr); return ((m_Target->GetPosition() - GetPosition()).SqrLength() < (m_AttackRange * m_AttackRange)); } + bool TargetIsInRange(void) + { + ASSERT(GetTarget() != nullptr); + return ((GetTarget()->GetPosition() - GetPosition()).SqrLength() < (m_AttackRange * m_AttackRange)); + } /** Returns whether the monster needs to jump to reach a given height. */ inline bool DoesPosYRequireJump(double a_PosY) @@ -272,7 +276,9 @@ protected: void AddRandomWeaponDropItem(cItems & a_Drops, unsigned int a_LootingLevel); private: - /** A pointer to the entity this mobile is aiming to reach */ + /** A pointer to the entity this mobile is aiming to reach. + The validity of this pointer SHALL be guaranteed by the pointee; + it MUST be reset when the pointee changes worlds or is destroyed. */ cPawn * m_Target; } ; // tolua_export diff --git a/src/Mobs/Skeleton.cpp b/src/Mobs/Skeleton.cpp index 0d6d5e428..e48991a06 100644 --- a/src/Mobs/Skeleton.cpp +++ b/src/Mobs/Skeleton.cpp @@ -57,19 +57,15 @@ bool cSkeleton::Attack(std::chrono::milliseconds a_Dt) Vector3d Inaccuracy = Vector3d(Random.RandReal<double>(-0.25, 0.25), Random.RandReal<double>(-0.25, 0.25), Random.RandReal<double>(-0.25, 0.25)); Vector3d Speed = (GetTarget()->GetPosition() + Inaccuracy - GetPosition()) * 5; Speed.y += Random.RandInt(-1, 1); - cArrowEntity * Arrow = new cArrowEntity(this, GetPosX(), GetPosY() + 1, GetPosZ(), Speed); - if (Arrow == nullptr) - { - return false; - } - if (!Arrow->Initialize(*m_World)) + + auto Arrow = cpp14::make_unique<cArrowEntity>(this, GetPosX(), GetPosY() + 1, GetPosZ(), Speed); + auto ArrowPtr = Arrow.get(); + if (!ArrowPtr->Initialize(std::move(Arrow), *m_World)) { - delete Arrow; - Arrow = nullptr; return false; } - ResetAttackCooldown(); + ResetAttackCooldown(); return true; } return false; diff --git a/src/Mobs/Slime.cpp b/src/Mobs/Slime.cpp index 3f832ae87..291a3a57f 100644 --- a/src/Mobs/Slime.cpp +++ b/src/Mobs/Slime.cpp @@ -78,10 +78,10 @@ void cSlime::KilledBy(TakeDamageInfo & a_TDI) double AddX = (i % 2 - 0.5) * m_Size / 4.0; double AddZ = (i / 2 - 0.5) * m_Size / 4.0; - cSlime * NewSlime = new cSlime(m_Size / 2); + auto NewSlime = cpp14::make_unique<cSlime>(m_Size / 2); NewSlime->SetPosition(GetPosX() + AddX, GetPosY() + 0.5, GetPosZ() + AddZ); NewSlime->SetYaw(Random.RandReal(360.0f)); - m_World->SpawnMobFinalize(NewSlime); + m_World->SpawnMobFinalize(std::move(NewSlime)); } } super::KilledBy(a_TDI); diff --git a/src/Mobs/Wither.cpp b/src/Mobs/Wither.cpp index fad51c05f..dd85d7d2b 100644 --- a/src/Mobs/Wither.cpp +++ b/src/Mobs/Wither.cpp @@ -15,6 +15,7 @@ cWither::cWither(void) : m_WitherInvulnerableTicks(220) { SetMaxHealth(300); + SetHealth(GetMaxHealth() / 3); } @@ -30,18 +31,6 @@ bool cWither::IsArmored(void) const -bool cWither::Initialize(cWorld & a_World) -{ - // Set health before BroadcastSpawnEntity() - SetHealth(GetMaxHealth() / 3); - - return super::Initialize(a_World); -} - - - - - bool cWither::DoTakeDamage(TakeDamageInfo & a_TDI) { if (a_TDI.DamageType == dtDrowning) diff --git a/src/Mobs/Wither.h b/src/Mobs/Wither.h index b430588c9..5f6ec607c 100644 --- a/src/Mobs/Wither.h +++ b/src/Mobs/Wither.h @@ -25,7 +25,6 @@ public: bool IsArmored(void) const; // cEntity overrides - virtual bool Initialize(cWorld & a_World) override; virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override; virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override; virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override; diff --git a/src/SetChunkData.cpp b/src/SetChunkData.cpp index cb530b3b6..c218c361c 100644 --- a/src/SetChunkData.cpp +++ b/src/SetChunkData.cpp @@ -6,6 +6,7 @@ #include "Globals.h" #include "SetChunkData.h" #include "BlockEntities/BlockEntity.h" +#include "Entities/Entity.h" diff --git a/src/SetChunkData.h b/src/SetChunkData.h index b0c59e40b..c608a8f61 100644 --- a/src/SetChunkData.h +++ b/src/SetChunkData.h @@ -115,11 +115,3 @@ protected: bool m_AreBiomesValid; bool m_ShouldMarkDirty; }; - -typedef std::unique_ptr<cSetChunkData> cSetChunkDataPtr; -typedef std::vector<cSetChunkDataPtr> cSetChunkDataPtrs; - - - - - diff --git a/src/Simulator/SandSimulator.cpp b/src/Simulator/SandSimulator.cpp index c26452d98..01e699b49 100644 --- a/src/Simulator/SandSimulator.cpp +++ b/src/Simulator/SandSimulator.cpp @@ -60,11 +60,11 @@ void cSandSimulator::SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, Pos.x, Pos.y, Pos.z, ItemTypeToString(BlockType).c_str(), ItemTypeToString(BlockBelow).c_str() ); */ - cFallingBlock * FallingBlock = new cFallingBlock(Pos, BlockType, a_Chunk->GetMeta(itr->x, itr->y, itr->z)); - if (!FallingBlock->Initialize(m_World)) + + auto FallingBlock = cpp14::make_unique<cFallingBlock>(Pos, BlockType, a_Chunk->GetMeta(itr->x, itr->y, itr->z)); + auto FallingBlockPtr = FallingBlock.get(); + if (!FallingBlockPtr->Initialize(std::move(FallingBlock), m_World)) { - delete FallingBlock; - FallingBlock = nullptr; continue; } a_Chunk->SetBlock(itr->x, itr->y, itr->z, E_BLOCK_AIR, 0); diff --git a/src/World.cpp b/src/World.cpp index 6f9c44c13..738761aa6 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -999,9 +999,10 @@ void cWorld::Tick(std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_La for (auto & Entity : m_EntitiesToAdd) { Entity->SetWorld(this); - m_ChunkMap->AddEntity(Entity); - ASSERT(!Entity->IsTicking()); - Entity->SetIsTicking(true); + auto EntityPtr = Entity.get(); + m_ChunkMap->AddEntity(std::move(Entity)); + ASSERT(!EntityPtr->IsTicking()); + EntityPtr->SetIsTicking(true); } m_EntitiesToAdd.clear(); } @@ -1114,7 +1115,7 @@ void cWorld::TickMobs(std::chrono::milliseconds a_Dt) // do the spawn for (cMobSpawner::tSpawnedContainer::const_iterator itr2 = Spawner.getSpawned().begin(); itr2 != Spawner.getSpawned().end(); ++itr2) { - SpawnMobFinalize(*itr2); + SpawnMobFinalize(std::move(const_cast<std::unique_ptr<cMonster> &>(*itr2))); } } } // for i - AllFamilies[] @@ -1560,7 +1561,7 @@ bool cWorld::DoWithChunk(int a_ChunkX, int a_ChunkZ, cChunkCallback & a_Callback -bool cWorld::DoWithChunk(int a_ChunkX, int a_ChunkZ, std::function<bool(cChunk &)> a_Callback) +bool cWorld::DoWithChunk(int a_ChunkX, int a_ChunkZ, std::function<bool(cChunk &)> a_Callback) { struct cCallBackWrapper : cChunkCallback { @@ -2186,15 +2187,12 @@ void cWorld::SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double float SpeedY = static_cast<float>(a_FlyAwaySpeed * Random.RandInt(50)); float SpeedZ = static_cast<float>(a_FlyAwaySpeed * Random.RandInt(-5, 5)); - cPickup * Pickup = new cPickup( + auto Pickup = cpp14::make_unique<cPickup>( a_BlockX, a_BlockY, a_BlockZ, *itr, IsPlayerCreated, SpeedX, SpeedY, SpeedZ ); - if (!Pickup->Initialize(*this)) - { - delete Pickup; - Pickup = nullptr; - } + auto PickupPtr = Pickup.get(); + PickupPtr->Initialize(std::move(Pickup), *this); } } @@ -2211,15 +2209,12 @@ void cWorld::SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double continue; } - cPickup * Pickup = new cPickup( + auto Pickup = cpp14::make_unique<cPickup>( a_BlockX, a_BlockY, a_BlockZ, *itr, IsPlayerCreated, static_cast<float>(a_SpeedX), static_cast<float>(a_SpeedY), static_cast<float>(a_SpeedZ) ); - if (!Pickup->Initialize(*this)) - { - delete Pickup; - Pickup = nullptr; - } + auto PickupPtr = Pickup.get(); + PickupPtr->Initialize(std::move(Pickup), *this); } } @@ -2229,14 +2224,13 @@ void cWorld::SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double UInt32 cWorld::SpawnItemPickup(double a_PosX, double a_PosY, double a_PosZ, const cItem & a_Item, float a_SpeedX, float a_SpeedY, float a_SpeedZ, int a_LifetimeTicks, bool a_CanCombine) { - cPickup * Pickup = new cPickup(a_PosX, a_PosY, a_PosZ, a_Item, false, a_SpeedX, a_SpeedY, a_SpeedZ, a_LifetimeTicks, a_CanCombine); - if (!Pickup->Initialize(*this)) + auto Pickup = cpp14::make_unique<cPickup>(a_PosX, a_PosY, a_PosZ, a_Item, false, a_SpeedX, a_SpeedY, a_SpeedZ, a_LifetimeTicks, a_CanCombine); + auto PickupPtr = Pickup.get(); + if (!PickupPtr->Initialize(std::move(Pickup), *this)) { - delete Pickup; - Pickup = nullptr; return cEntity::INVALID_ID; } - return Pickup->GetUniqueID(); + return PickupPtr->GetUniqueID(); } @@ -2245,14 +2239,14 @@ UInt32 cWorld::SpawnItemPickup(double a_PosX, double a_PosY, double a_PosZ, cons UInt32 cWorld::SpawnFallingBlock(int a_X, int a_Y, int a_Z, BLOCKTYPE BlockType, NIBBLETYPE BlockMeta) { - cFallingBlock * FallingBlock = new cFallingBlock(Vector3i(a_X, a_Y, a_Z), BlockType, BlockMeta); - if (!FallingBlock->Initialize(*this)) + auto FallingBlock = cpp14::make_unique<cFallingBlock>(Vector3i(a_X, a_Y, a_Z), BlockType, BlockMeta); + auto FallingBlockPtr = FallingBlock.get(); + auto ID = FallingBlock->GetUniqueID(); + if (!FallingBlockPtr->Initialize(std::move(FallingBlock), *this)) { - delete FallingBlock; - FallingBlock = nullptr; return cEntity::INVALID_ID; } - return FallingBlock->GetUniqueID(); + return ID; } @@ -2267,14 +2261,13 @@ UInt32 cWorld::SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Rewa return cEntity::INVALID_ID; } - cExpOrb * ExpOrb = new cExpOrb(a_X, a_Y, a_Z, a_Reward); - if (!ExpOrb->Initialize(*this)) + auto ExpOrb = cpp14::make_unique<cExpOrb>(a_X, a_Y, a_Z, a_Reward); + auto ExpOrbPtr = ExpOrb.get(); + if (!ExpOrbPtr->Initialize(std::move(ExpOrb), *this)) { - delete ExpOrb; - ExpOrb = nullptr; return cEntity::INVALID_ID; } - return ExpOrb->GetUniqueID(); + return ExpOrbPtr->GetUniqueID(); } @@ -2283,26 +2276,26 @@ UInt32 cWorld::SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Rewa UInt32 cWorld::SpawnMinecart(double a_X, double a_Y, double a_Z, int a_MinecartType, const cItem & a_Content, int a_BlockHeight) { - cMinecart * Minecart; + std::unique_ptr<cMinecart> Minecart; switch (a_MinecartType) { - case E_ITEM_MINECART: Minecart = new cRideableMinecart (a_X, a_Y, a_Z, a_Content, a_BlockHeight); break; - case E_ITEM_CHEST_MINECART: Minecart = new cMinecartWithChest (a_X, a_Y, a_Z); break; - case E_ITEM_FURNACE_MINECART: Minecart = new cMinecartWithFurnace (a_X, a_Y, a_Z); break; - case E_ITEM_MINECART_WITH_TNT: Minecart = new cMinecartWithTNT (a_X, a_Y, a_Z); break; - case E_ITEM_MINECART_WITH_HOPPER: Minecart = new cMinecartWithHopper (a_X, a_Y, a_Z); break; + case E_ITEM_MINECART: Minecart = cpp14::make_unique<cRideableMinecart>(a_X, a_Y, a_Z, a_Content, a_BlockHeight); break; + case E_ITEM_CHEST_MINECART: Minecart = cpp14::make_unique<cMinecartWithChest>(a_X, a_Y, a_Z); break; + case E_ITEM_FURNACE_MINECART: Minecart = cpp14::make_unique<cMinecartWithFurnace>(a_X, a_Y, a_Z); break; + case E_ITEM_MINECART_WITH_TNT: Minecart = cpp14::make_unique<cMinecartWithTNT>(a_X, a_Y, a_Z); break; + case E_ITEM_MINECART_WITH_HOPPER: Minecart = cpp14::make_unique<cMinecartWithHopper>(a_X, a_Y, a_Z); break; default: { return cEntity::INVALID_ID; } } // switch (a_MinecartType) - if (!Minecart->Initialize(*this)) + + auto MinecartPtr = Minecart.get(); + if (!MinecartPtr->Initialize(std::move(Minecart), *this)) { - delete Minecart; - Minecart = nullptr; return cEntity::INVALID_ID; } - return Minecart->GetUniqueID(); + return MinecartPtr->GetUniqueID(); } @@ -2311,18 +2304,13 @@ UInt32 cWorld::SpawnMinecart(double a_X, double a_Y, double a_Z, int a_MinecartT UInt32 cWorld::SpawnBoat(double a_X, double a_Y, double a_Z, cBoat::eMaterial a_Material) { - cBoat * Boat = new cBoat(a_X, a_Y, a_Z, a_Material); - if (Boat == nullptr) - { - return cEntity::INVALID_ID; - } - if (!Boat->Initialize(*this)) + auto Boat = cpp14::make_unique<cBoat>(a_X, a_Y, a_Z, a_Material); + auto BoatPtr = Boat.get(); + if (!BoatPtr->Initialize(std::move(Boat), *this)) { - delete Boat; - Boat = nullptr; return cEntity::INVALID_ID; } - return Boat->GetUniqueID(); + return BoatPtr->GetUniqueID(); } @@ -2330,20 +2318,20 @@ UInt32 cWorld::SpawnBoat(double a_X, double a_Y, double a_Z, cBoat::eMaterial a_ UInt32 cWorld::SpawnPrimedTNT(double a_X, double a_Y, double a_Z, int a_FuseTicks, double a_InitialVelocityCoeff) { - cTNTEntity * TNT = new cTNTEntity(a_X, a_Y, a_Z, a_FuseTicks); - if (!TNT->Initialize(*this)) + auto TNT = cpp14::make_unique<cTNTEntity>(a_X, a_Y, a_Z, a_FuseTicks); + auto TNTPtr = TNT.get(); + if (!TNTPtr->Initialize(std::move(TNT), *this)) { - delete TNT; - TNT = nullptr; return cEntity::INVALID_ID; } + auto & Random = GetRandomProvider(); - TNT->SetSpeed( + TNTPtr->SetSpeed( a_InitialVelocityCoeff * Random.RandInt(-1, 1), a_InitialVelocityCoeff * 2, a_InitialVelocityCoeff * Random.RandInt(-1, 1) ); - return TNT->GetUniqueID(); + return TNTPtr->GetUniqueID(); } @@ -2912,7 +2900,7 @@ void cWorld::QueueSetChunkData(cSetChunkDataPtr a_SetChunkData) // Store a copy of the data in the queue: // TODO: If the queue is too large, wait for it to get processed. Not likely, though. cCSLock Lock(m_CSSetChunkDataQueue); - m_SetChunkDataQueue.push_back(std::move(a_SetChunkData)); + m_SetChunkDataQueue.emplace_back(std::move(a_SetChunkData)); } @@ -2927,15 +2915,10 @@ void cWorld::SetChunkData(cSetChunkData & a_SetChunkData) m_ChunkMap->SetChunkData(a_SetChunkData); // Initialize the entities (outside the m_ChunkMap's CS, to fix FS #347): - cEntityList Entities; - std::swap(a_SetChunkData.GetEntities(), Entities); - for (cEntityList::iterator itr = Entities.begin(), end = Entities.end(); itr != end; ++itr) + for (auto & Entity : a_SetChunkData.GetEntities()) { - if (!(*itr)->Initialize(*this)) - { - delete *itr; - *itr = nullptr; - } + auto EntityPtr = Entity.get(); + EntityPtr->Initialize(std::move(Entity), *this); } // If a client is requesting this chunk, send it to them: @@ -3056,39 +3039,41 @@ void cWorld::CollectPickupsByPlayer(cPlayer & a_Player) -void cWorld::AddPlayer(cPlayer * a_Player, cWorld * a_OldWorld) +void cWorld::AddPlayer(std::unique_ptr<cPlayer> a_Player, cWorld * a_OldWorld) { cCSLock Lock(m_CSPlayersToAdd); - m_PlayersToAdd.emplace_back(a_Player, a_OldWorld); + m_PlayersToAdd.emplace_back(std::move(a_Player), a_OldWorld); } -void cWorld::RemovePlayer(cPlayer * a_Player, bool a_RemoveFromChunk) +std::unique_ptr<cPlayer> cWorld::RemovePlayer(cPlayer & a_Player, bool a_RemoveFromChunk) { + std::unique_ptr<cPlayer> PlayerPtr; + if (a_RemoveFromChunk) { // 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 - m_ChunkMap->RemoveEntity(a_Player); + PlayerPtr = std::unique_ptr<cPlayer>(static_cast<cPlayer *>(m_ChunkMap->RemoveEntity(a_Player).release())); } { cCSLock Lock(m_CSPlayersToAdd); - m_PlayersToAdd.remove_if([&](const std::pair< cPlayer *, cWorld * > & value) -> bool + m_PlayersToAdd.remove_if([&](const decltype(m_PlayersToAdd)::value_type & value) -> bool { - return (value.first == a_Player); + return (value.first.get() == &a_Player); }); } { cCSLock Lock(m_CSPlayers); - LOGD("Removing player %s from world \"%s\"", a_Player->GetName().c_str(), m_WorldName.c_str()); - m_Players.remove(a_Player); + LOGD("Removing player %s from world \"%s\"", a_Player.GetName().c_str(), m_WorldName.c_str()); + m_Players.remove(&a_Player); } // Remove the player's client from the list of clients to be ticked: - cClientHandle * Client = a_Player->GetClientHandle(); + cClientHandle * Client = a_Player.GetClientHandle(); if (Client != nullptr) { Client->RemoveFromWorld(); @@ -3096,7 +3081,61 @@ void cWorld::RemovePlayer(cPlayer * a_Player, bool a_RemoveFromChunk) cCSLock Lock(m_CSClients); m_ClientsToRemove.push_back(Client); } + + return PlayerPtr; +} + + + + + +#ifdef _DEBUG +bool cWorld::IsPlayerReferencedInWorldOrChunk(cPlayer & a_Player) +{ + if (m_ChunkMap->RemoveEntity(a_Player) != nullptr) + { + return true; + } + + { + cCSLock Lock(m_CSPlayersToAdd); + if (std::find_if( + m_PlayersToAdd.begin(), m_PlayersToAdd.end(), + [&a_Player](const cAwaitingPlayerList::value_type & Item) { return Item.first.get() == &a_Player; }) != m_PlayersToAdd.end() + ) + { + return true; + } + } + + { + cCSLock Lock(m_CSPlayers); + if (std::find(m_Players.begin(), m_Players.end(), &a_Player) != m_Players.end()) + { + return true; + } + } + + { + cCSLock Lock(m_CSEntitiesToAdd); + if (std::find(m_ClientsToAdd.begin(), m_ClientsToAdd.end(), a_Player.GetClientHandlePtr()) != m_ClientsToAdd.end()) + { + return true; + } + } + + { + cCSLock Lock(m_CSClients); + if (std::find(m_Clients.begin(), m_Clients.end(), a_Player.GetClientHandlePtr()) != m_Clients.end()) + { + return true; + } + } + + // Assume OK if in ClientsToRemove or PlayersToRemove + return false; } +#endif @@ -3313,11 +3352,11 @@ bool cWorld::DoWithEntityByID(UInt32 a_UniqueID, cLambdaEntityCallback a_Callbac // First check the entities-to-add: { cCSLock Lock(m_CSEntitiesToAdd); - for (auto & ent: m_EntitiesToAdd) + for (const auto & ent: m_EntitiesToAdd) { if (ent->GetUniqueID() == a_UniqueID) { - a_Callback(ent); + a_Callback(ent.get()); return true; } } // for ent - m_EntitiesToAdd[] @@ -3610,11 +3649,11 @@ void cWorld::ScheduleTask(int a_DelayTicks, std::function<void (cWorld &)> a_Tas -void cWorld::AddEntity(cEntity * a_Entity) +void cWorld::AddEntity(OwnedEntity a_Entity) { a_Entity->SetWorld(this); cCSLock Lock(m_CSEntitiesToAdd); - m_EntitiesToAdd.push_back(a_Entity); + m_EntitiesToAdd.emplace_back(std::move(a_Entity)); } @@ -3749,9 +3788,7 @@ bool cWorld::IsBlockDirectlyWatered(int a_BlockX, int a_BlockY, int a_BlockZ) UInt32 cWorld::SpawnMob(double a_PosX, double a_PosY, double a_PosZ, eMonsterType a_MonsterType, bool a_Baby) { - cMonster * Monster = nullptr; - - Monster = cMonster::NewMonsterFromType(a_MonsterType); + auto Monster = cMonster::NewMonsterFromType(a_MonsterType); if (Monster == nullptr) { return cEntity::INVALID_ID; @@ -3763,13 +3800,13 @@ UInt32 cWorld::SpawnMob(double a_PosX, double a_PosY, double a_PosZ, eMonsterTyp Monster->SetAge(-1); } - return SpawnMobFinalize(Monster); + return SpawnMobFinalize(std::move(Monster)); } -UInt32 cWorld::SpawnMobFinalize(cMonster * a_Monster) +UInt32 cWorld::SpawnMobFinalize(std::unique_ptr<cMonster> a_Monster) { ASSERT(a_Monster != nullptr); @@ -3779,22 +3816,20 @@ UInt32 cWorld::SpawnMobFinalize(cMonster * a_Monster) // A plugin doesn't agree with the spawn. bail out. if (cPluginManager::Get()->CallHookSpawningMonster(*this, *a_Monster)) { - delete a_Monster; - a_Monster = nullptr; return cEntity::INVALID_ID; } + auto & Monster = *a_Monster; + // Initialize the monster into the current world. - if (!a_Monster->Initialize(*this)) + if (!Monster.Initialize(std::move(a_Monster), *this)) { - delete a_Monster; - a_Monster = nullptr; return cEntity::INVALID_ID; } - cPluginManager::Get()->CallHookSpawnedMonster(*this, *a_Monster); + cPluginManager::Get()->CallHookSpawnedMonster(*this, Monster); - return a_Monster->GetUniqueID(); + return Monster.GetUniqueID(); } @@ -3803,18 +3838,19 @@ UInt32 cWorld::SpawnMobFinalize(cMonster * a_Monster) UInt32 cWorld::CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const cItem * a_Item, const Vector3d * a_Speed) { - cProjectileEntity * Projectile = cProjectileEntity::Create(a_Kind, a_Creator, a_PosX, a_PosY, a_PosZ, a_Item, a_Speed); + auto Projectile = cProjectileEntity::Create(a_Kind, a_Creator, a_PosX, a_PosY, a_PosZ, a_Item, a_Speed); if (Projectile == nullptr) { return cEntity::INVALID_ID; } - if (!Projectile->Initialize(*this)) + + auto ProjectilePtr = Projectile.get(); + if (!ProjectilePtr->Initialize(std::move(Projectile), *this)) { - delete Projectile; - Projectile = nullptr; return cEntity::INVALID_ID; } - return Projectile->GetUniqueID(); + + return ProjectilePtr->GetUniqueID(); } @@ -4010,29 +4046,35 @@ void cWorld::AddQueuedPlayers(void) std::swap(PlayersToAdd, m_PlayersToAdd); } + // Temporary (#3115-will-fix): store pointers to player objects after ownership transferral + std::vector<std::pair<cPlayer *, cWorld *>> AddedPlayerPtrs; + AddedPlayerPtrs.reserve(PlayersToAdd.size()); + // Add all the players in the grabbed list: { cCSLock Lock(m_CSPlayers); 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? + ASSERT(std::find(m_Players.begin(), m_Players.end(), Player.get()) == 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()); - m_Players.push_back(Player); + m_Players.push_back(Player.get()); Player->SetWorld(this); // Add to chunkmap, if not already there (Spawn vs MoveToWorld): - m_ChunkMap->AddEntityIfNotPresent(Player); - ASSERT(!Player->IsTicking()); - Player->SetIsTicking(true); + auto PlayerPtr = Player.get(); + m_ChunkMap->AddEntityIfNotPresent(std::move(Player)); + ASSERT(!PlayerPtr->IsTicking()); + PlayerPtr->SetIsTicking(true); + AddedPlayerPtrs.emplace_back(PlayerPtr, AwaitingPlayer.second); } // for itr - PlayersToAdd[] } // Lock(m_CSPlayers) // Add all the players' clienthandles: { cCSLock Lock(m_CSClients); - for (auto & AwaitingPlayer : PlayersToAdd) + for (auto & AwaitingPlayer : AddedPlayerPtrs) { auto & Player = AwaitingPlayer.first; cClientHandlePtr Client = Player->GetClientHandlePtr(); @@ -4044,7 +4086,7 @@ void cWorld::AddQueuedPlayers(void) } // Lock(m_CSClients) // Stream chunks to all eligible clients: - for (auto & AwaitingPlayer : PlayersToAdd) + for (auto & AwaitingPlayer : AddedPlayerPtrs) { auto & Player = AwaitingPlayer.first; cClientHandle * Client = Player->GetClientHandle(); @@ -4057,7 +4099,7 @@ void cWorld::AddQueuedPlayers(void) } // for itr - PlayersToAdd[] // Call EntityChangedWorld callback on all eligible clients - for (auto & AwaitingPlayer : PlayersToAdd) + for (auto & AwaitingPlayer : AddedPlayerPtrs) { if (AwaitingPlayer.second != nullptr) { @@ -4087,14 +4129,14 @@ void cWorld::cChunkGeneratorCallbacks::OnChunkGenerated(cChunkDesc & a_ChunkDesc cChunkDef::BlockNibbles BlockMetas; a_ChunkDesc.CompressBlockMetas(BlockMetas); - cSetChunkDataPtr SetChunkData(new cSetChunkData( + auto SetChunkData = cpp14::make_unique<cSetChunkData>( a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ(), a_ChunkDesc.GetBlockTypes(), BlockMetas, nullptr, nullptr, // We don't have lighting, chunk will be lighted when needed &a_ChunkDesc.GetHeightMap(), &a_ChunkDesc.GetBiomeMap(), std::move(a_ChunkDesc.GetEntities()), std::move(a_ChunkDesc.GetBlockEntities()), true - )); + ); SetChunkData->RemoveInvalidBlockEntities(); m_World->QueueSetChunkData(std::move(SetChunkData)); } diff --git a/src/World.h b/src/World.h index 064dad0d2..8ff64046d 100644 --- a/src/World.h +++ b/src/World.h @@ -52,7 +52,7 @@ class cBroadcaster; class cDeadlockDetect; typedef std::list< cPlayer * > cPlayerList; -typedef std::list< std::pair< cPlayer *, cWorld * > > cAwaitingPlayerList; +typedef std::list< std::pair< std::unique_ptr<cPlayer>, cWorld * > > cAwaitingPlayerList; typedef std::unique_ptr<cSetChunkData> cSetChunkDataPtr; typedef std::vector<cSetChunkDataPtr> cSetChunkDataPtrs; @@ -258,13 +258,18 @@ public: 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. 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); + void AddPlayer(std::unique_ptr<cPlayer> a_Player, cWorld * a_OldWorld = nullptr); /** Removes the player from the world. Removes the player from the addition queue, too, if appropriate. If the player has a ClientHandle, the ClientHandle is removed from all chunks in the world and will not be ticked by this world anymore. - @param a_RemoveFromChunk determines if the entity should be removed from its chunk as well. Should be false when ticking from cChunk. */ - void RemovePlayer(cPlayer * a_Player, bool a_RemoveFromChunk); + @param a_RemoveFromChunk determines if the entity should be removed from its chunk as well. Should be false when ticking from cChunk. + @return An owning reference to the given player. */ + std::unique_ptr<cPlayer> RemovePlayer(cPlayer & a_Player, bool a_RemoveFromChunk); + +#ifdef _DEBUG + bool IsPlayerReferencedInWorldOrChunk(cPlayer & a_Player); +#endif /** Calls the callback for each player in the list; returns true if all players processed, false if the callback aborted by returning true */ virtual bool ForEachPlayer(cPlayerListCallback & a_Callback) override; // >> EXPORTED IN MANUALBINDINGS << @@ -287,7 +292,7 @@ public: /** Adds the entity into its appropriate chunk; takes ownership of the entity ptr. The entity is added lazily - this function only puts it in a queue that is then processed by the Tick thread. */ - void AddEntity(cEntity * a_Entity); + void AddEntity(OwnedEntity a_Entity); /** Returns true if an entity with the specified UniqueID exists in the world. Note: Only loaded chunks are considered. */ @@ -801,7 +806,9 @@ public: /** Spawns a mob of the specified type. Returns the mob's UniqueID if recognized and spawned, cEntity::INVALID_ID otherwise */ virtual UInt32 SpawnMob(double a_PosX, double a_PosY, double a_PosZ, eMonsterType a_MonsterType, bool a_Baby = false) override; // tolua_export - UInt32 SpawnMobFinalize(cMonster * a_Monster); + /** Wraps cEntity::Initialize, doing Monster-specific things before spawning the monster. + Takes ownership of the given Monster reference. */ + UInt32 SpawnMobFinalize(std::unique_ptr<cMonster> a_Monster); /** Creates a projectile of the specified type. Returns the projectile's UniqueID if successful, cEntity::INVALID_ID otherwise Item parameter is currently used for Fireworks to correctly set entity metadata based on item metadata. */ diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp index 16688b712..14d5738c2 100755 --- a/src/WorldStorage/WSSAnvil.cpp +++ b/src/WorldStorage/WSSAnvil.cpp @@ -458,7 +458,7 @@ bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT } // for y //*/ - cSetChunkDataPtr SetChunkData(new cSetChunkData( + auto SetChunkData = cpp14::make_unique<cSetChunkData>( a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, BlockTypes, MetaData, IsLightValid ? BlockLight : nullptr, @@ -466,7 +466,7 @@ bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT nullptr, Biomes, std::move(Entities), std::move(BlockEntities), false - )); + ); m_World->QueueSetChunkData(std::move(SetChunkData)); return true; } @@ -1655,7 +1655,7 @@ void cWSSAnvil::LoadBoatFromNBT(cEntityList & a_Entities, const cParsedNBT & a_N { Boat->SetMaterial(cBoat::StringToMaterial(a_NBT.GetString(TypeIdx))); } - a_Entities.push_back(Boat.release()); + a_Entities.emplace_back(std::move(Boat)); } @@ -1669,7 +1669,7 @@ void cWSSAnvil::LoadEnderCrystalFromNBT(cEntityList & a_Entities, const cParsedN { return; } - a_Entities.push_back(EnderCrystal.release()); + a_Entities.emplace_back(std::move(EnderCrystal)); } @@ -1694,7 +1694,7 @@ void cWSSAnvil::LoadFallingBlockFromNBT(cEntityList & a_Entities, const cParsedN { return; } - a_Entities.push_back(FallingBlock.release()); + a_Entities.emplace_back(std::move(FallingBlock)); } @@ -1708,7 +1708,7 @@ void cWSSAnvil::LoadMinecartRFromNBT(cEntityList & a_Entities, const cParsedNBT { return; } - a_Entities.push_back(Minecart.release()); + a_Entities.emplace_back(std::move(Minecart)); } @@ -1740,7 +1740,7 @@ void cWSSAnvil::LoadMinecartCFromNBT(cEntityList & a_Entities, const cParsedNBT Minecart->SetSlot(a_NBT.GetByte(Slot), Item); } } // for itr - ItemDefs[] - a_Entities.push_back(Minecart.release()); + a_Entities.emplace_back(std::move(Minecart)); } @@ -1757,7 +1757,7 @@ void cWSSAnvil::LoadMinecartFFromNBT(cEntityList & a_Entities, const cParsedNBT // TODO: Load the Push and Fuel tags - a_Entities.push_back(Minecart.release()); + a_Entities.emplace_back(std::move(Minecart)); } @@ -1774,7 +1774,7 @@ void cWSSAnvil::LoadMinecartTFromNBT(cEntityList & a_Entities, const cParsedNBT // TODO: Everything to do with TNT carts - a_Entities.push_back(Minecart.release()); + a_Entities.emplace_back(std::move(Minecart)); } @@ -1791,7 +1791,7 @@ void cWSSAnvil::LoadMinecartHFromNBT(cEntityList & a_Entities, const cParsedNBT // TODO: Everything to do with hopper carts - a_Entities.push_back(Minecart.release()); + a_Entities.emplace_back(std::move(Minecart)); } @@ -1825,7 +1825,7 @@ void cWSSAnvil::LoadPickupFromNBT(cEntityList & a_Entities, const cParsedNBT & a Pickup->SetAge(a_NBT.GetShort(Age)); } - a_Entities.push_back(Pickup.release()); + a_Entities.emplace_back(std::move(Pickup)); } @@ -1847,7 +1847,7 @@ void cWSSAnvil::LoadTNTFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NB TNT->SetFuseTicks(static_cast<int>(a_NBT.GetByte(FuseTicks))); } - a_Entities.push_back(TNT.release()); + a_Entities.emplace_back(std::move(TNT)); } @@ -1876,7 +1876,7 @@ void cWSSAnvil::LoadExpOrbFromNBT(cEntityList & a_Entities, const cParsedNBT & a ExpOrb->SetReward(a_NBT.GetShort(Reward)); } - a_Entities.push_back(ExpOrb.release()); + a_Entities.emplace_back(std::move(ExpOrb)); } @@ -1941,7 +1941,7 @@ void cWSSAnvil::LoadItemFrameFromNBT(cEntityList & a_Entities, const cParsedNBT ItemFrame->SetItemRotation(static_cast<Byte>(a_NBT.GetByte(Rotation))); } - a_Entities.push_back(ItemFrame.release()); + a_Entities.emplace_back(std::move(ItemFrame)); } @@ -1964,7 +1964,7 @@ void cWSSAnvil::LoadPaintingFromNBT(cEntityList & a_Entities, const cParsedNBT & } LoadHangingFromNBT(*Painting.get(), a_NBT, a_TagIdx); - a_Entities.push_back(Painting.release()); + a_Entities.emplace_back(std::move(Painting)); } @@ -2035,7 +2035,7 @@ void cWSSAnvil::LoadArrowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_ } // Store the new arrow in the entities list: - a_Entities.push_back(Arrow.release()); + a_Entities.emplace_back(std::move(Arrow)); } @@ -2058,7 +2058,7 @@ void cWSSAnvil::LoadSplashPotionFromNBT(cEntityList & a_Entities, const cParsedN SplashPotion->SetPotionColor(a_NBT.FindChildByName(a_TagIdx, "PotionName")); // Store the new splash potion in the entities list: - a_Entities.push_back(SplashPotion.release()); + a_Entities.emplace_back(std::move(SplashPotion)); } @@ -2074,7 +2074,7 @@ void cWSSAnvil::LoadSnowballFromNBT(cEntityList & a_Entities, const cParsedNBT & } // Store the new snowball in the entities list: - a_Entities.push_back(Snowball.release()); + a_Entities.emplace_back(std::move(Snowball)); } @@ -2090,7 +2090,7 @@ void cWSSAnvil::LoadEggFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NB } // Store the new egg in the entities list: - a_Entities.push_back(Egg.release()); + a_Entities.emplace_back(std::move(Egg)); } @@ -2106,7 +2106,7 @@ void cWSSAnvil::LoadFireballFromNBT(cEntityList & a_Entities, const cParsedNBT & } // Store the new fireball in the entities list: - a_Entities.push_back(Fireball.release()); + a_Entities.emplace_back(std::move(Fireball)); } @@ -2122,7 +2122,7 @@ void cWSSAnvil::LoadFireChargeFromNBT(cEntityList & a_Entities, const cParsedNBT } // Store the new FireCharge in the entities list: - a_Entities.push_back(FireCharge.release()); + a_Entities.emplace_back(std::move(FireCharge)); } @@ -2138,7 +2138,7 @@ void cWSSAnvil::LoadThrownEnderpearlFromNBT(cEntityList & a_Entities, const cPar } // Store the new enderpearl in the entities list: - a_Entities.push_back(Enderpearl.release()); + a_Entities.emplace_back(std::move(Enderpearl)); } @@ -2158,7 +2158,7 @@ void cWSSAnvil::LoadBatFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NB return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2178,7 +2178,7 @@ void cWSSAnvil::LoadBlazeFromNBT(cEntityList & a_Entities, const cParsedNBT & a_ return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2198,7 +2198,7 @@ void cWSSAnvil::LoadCaveSpiderFromNBT(cEntityList & a_Entities, const cParsedNBT return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2218,7 +2218,7 @@ void cWSSAnvil::LoadChickenFromNBT(cEntityList & a_Entities, const cParsedNBT & return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2238,7 +2238,7 @@ void cWSSAnvil::LoadCowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NB return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2258,7 +2258,7 @@ void cWSSAnvil::LoadCreeperFromNBT(cEntityList & a_Entities, const cParsedNBT & return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2278,7 +2278,7 @@ void cWSSAnvil::LoadEnderDragonFromNBT(cEntityList & a_Entities, const cParsedNB return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2298,7 +2298,7 @@ void cWSSAnvil::LoadEndermanFromNBT(cEntityList & a_Entities, const cParsedNBT & return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2318,7 +2318,7 @@ void cWSSAnvil::LoadGhastFromNBT(cEntityList & a_Entities, const cParsedNBT & a_ return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2338,7 +2338,7 @@ void cWSSAnvil::LoadGiantFromNBT(cEntityList & a_Entities, const cParsedNBT & a_ return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2358,7 +2358,7 @@ void cWSSAnvil::LoadGuardianFromNBT(cEntityList & a_Entities, const cParsedNBT & return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2404,7 +2404,7 @@ void cWSSAnvil::LoadHorseFromNBT(cEntityList & a_Entities, const cParsedNBT & a_ Monster->SetAge(Age); } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2424,7 +2424,7 @@ void cWSSAnvil::LoadIronGolemFromNBT(cEntityList & a_Entities, const cParsedNBT return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2453,7 +2453,7 @@ void cWSSAnvil::LoadMagmaCubeFromNBT(cEntityList & a_Entities, const cParsedNBT return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2473,7 +2473,7 @@ void cWSSAnvil::LoadMooshroomFromNBT(cEntityList & a_Entities, const cParsedNBT return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2527,7 +2527,7 @@ void cWSSAnvil::LoadOcelotFromNBT(cEntityList & a_Entities, const cParsedNBT & a Monster->SetAge(Age); } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2560,7 +2560,7 @@ void cWSSAnvil::LoadPigFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NB Monster->SetAge(Age); } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2604,7 +2604,7 @@ void cWSSAnvil::LoadRabbitFromNBT(cEntityList & a_Entities, const cParsedNBT & a Monster->SetAge(Age); } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2650,7 +2650,7 @@ void cWSSAnvil::LoadSheepFromNBT(cEntityList & a_Entities, const cParsedNBT & a_ Monster->SetAge(Age); } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2670,7 +2670,7 @@ void cWSSAnvil::LoadSilverfishFromNBT(cEntityList & a_Entities, const cParsedNBT return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2698,7 +2698,7 @@ void cWSSAnvil::LoadSkeletonFromNBT(cEntityList & a_Entities, const cParsedNBT & return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2727,7 +2727,7 @@ void cWSSAnvil::LoadSlimeFromNBT(cEntityList & a_Entities, const cParsedNBT & a_ return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2747,7 +2747,7 @@ void cWSSAnvil::LoadSnowGolemFromNBT(cEntityList & a_Entities, const cParsedNBT return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2767,7 +2767,7 @@ void cWSSAnvil::LoadSpiderFromNBT(cEntityList & a_Entities, const cParsedNBT & a return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2787,7 +2787,7 @@ void cWSSAnvil::LoadSquidFromNBT(cEntityList & a_Entities, const cParsedNBT & a_ return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2829,7 +2829,7 @@ void cWSSAnvil::LoadVillagerFromNBT(cEntityList & a_Entities, const cParsedNBT & } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2849,7 +2849,7 @@ void cWSSAnvil::LoadWitchFromNBT(cEntityList & a_Entities, const cParsedNBT & a_ return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2875,7 +2875,7 @@ void cWSSAnvil::LoadWitherFromNBT(cEntityList & a_Entities, const cParsedNBT & a Monster->SetWitherInvulnerableTicks(static_cast<unsigned int>(a_NBT.GetInt(CurrLine))); } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2951,7 +2951,7 @@ void cWSSAnvil::LoadWolfFromNBT(cEntityList & a_Entities, const cParsedNBT & a_N Monster->SetAge(Age); } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2992,7 +2992,7 @@ void cWSSAnvil::LoadZombieFromNBT(cEntityList & a_Entities, const cParsedNBT & a Monster->SetAge(Age); } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -3025,7 +3025,7 @@ void cWSSAnvil::LoadPigZombieFromNBT(cEntityList & a_Entities, const cParsedNBT Monster->SetAge(Age); } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } |