Changed entity ownership model to use smart pointers
This commit is contained in:
parent
07f25253a2
commit
4ef47aed62
@ -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(
|
||||
|
129
src/Chunk.cpp
129
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)
|
||||
@ -531,7 +530,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())
|
||||
@ -634,7 +633,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;
|
||||
@ -658,7 +657,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())
|
||||
{
|
||||
@ -683,7 +682,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())
|
||||
@ -708,20 +707,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
|
||||
@ -750,7 +751,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)
|
||||
@ -764,28 +765,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);
|
||||
}
|
||||
@ -1866,15 +1868,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
|
||||
{
|
||||
@ -1884,13 +1886,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)
|
||||
@ -1986,7 +1988,7 @@ void cChunk::RemoveClient(cClientHandle * a_Client)
|
||||
|
||||
if (!a_Client->IsDestroyed())
|
||||
{
|
||||
for (auto Entity : m_Entities)
|
||||
for (auto & Entity : m_Entities)
|
||||
{
|
||||
/*
|
||||
// DEBUG:
|
||||
@ -2024,34 +2026,59 @@ bool cChunk::HasAnyClients(void) const
|
||||
|
||||
|
||||
|
||||
void cChunk::AddEntity(cEntity * a_Entity)
|
||||
void cChunk::AddEntity(OwnedEntity a_Entity)
|
||||
{
|
||||
if (!a_Entity->IsPlayer())
|
||||
{
|
||||
MarkDirty();
|
||||
}
|
||||
|
||||
ASSERT(std::find(m_Entities.begin(), m_Entities.end(), a_Entity) == m_Entities.end()); // Not there already
|
||||
auto EntityPtr = a_Entity.get();
|
||||
|
||||
m_Entities.push_back(a_Entity);
|
||||
ASSERT(a_Entity->GetParentChunk() == nullptr);
|
||||
a_Entity->SetParentChunk(this);
|
||||
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));
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@ -2060,13 +2087,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;
|
||||
}
|
||||
|
||||
@ -2077,14 +2104,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;
|
||||
}
|
||||
@ -2099,7 +2126,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())
|
||||
@ -2112,7 +2139,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;
|
||||
}
|
||||
@ -2136,11 +2163,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[]
|
||||
|
15
src/Chunk.h
15
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;
|
||||
|
@ -28,7 +28,8 @@ class cEntity;
|
||||
class cClientHandle;
|
||||
class cBlockEntity;
|
||||
|
||||
typedef std::list<cEntity *> cEntityList;
|
||||
typedef std::unique_ptr<cEntity> OwnedEntity;
|
||||
typedef std::vector<OwnedEntity> cEntityList;
|
||||
typedef std::map<int, cBlockEntity *> cBlockEntities;
|
||||
|
||||
|
||||
|
@ -1497,38 +1497,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));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1553,17 +1553,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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -207,17 +207,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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
@ -1585,8 +1587,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;
|
||||
|
@ -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;
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
||||
@ -2003,7 +2003,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);
|
||||
@ -2045,8 +2047,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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "ChunkDesc.h"
|
||||
#include "../Noise/Noise.h"
|
||||
#include "../BlockEntities/BlockEntity.h"
|
||||
#include "../Entities/Entity.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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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(),
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
||||
if (a_World->SpawnMinecart(x, y, z, m_ItemType) == cEntity::INVALID_ID)
|
||||
{
|
||||
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))
|
||||
{
|
||||
delete Minecart;
|
||||
Minecart = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -43,7 +43,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 */
|
||||
@ -61,7 +61,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;
|
||||
} ;
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
||||
auto FireCharge = cpp14::make_unique<cFireChargeEntity>(this, GetPosX(), GetPosY() + 1, GetPosZ(), Speed);
|
||||
auto FireChargePtr = FireCharge.get();
|
||||
if (!FireChargePtr->Initialize(std::move(FireCharge), *m_World))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!FireCharge->Initialize(*m_World))
|
||||
{
|
||||
delete FireCharge;
|
||||
FireCharge = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
ResetAttackCooldown();
|
||||
// ToDo: Shoot 3 fireballs instead of 1.
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -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)
|
||||
|
||||
auto GhastBall = cpp14::make_unique<cGhastFireballEntity>(this, GetPosX(), GetPosY() + 1, GetPosZ(), Speed);
|
||||
auto GhastBallPtr = GhastBall.get();
|
||||
if (!GhastBallPtr->Initialize(std::move(GhastBall), *m_World))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!GhastBall->Initialize(*m_World))
|
||||
{
|
||||
delete GhastBall;
|
||||
GhastBall = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
ResetAttackCooldown();
|
||||
return true;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
{
|
||||
delete Arrow;
|
||||
Arrow = nullptr;
|
||||
return false;
|
||||
}
|
||||
ResetAttackCooldown();
|
||||
|
||||
auto Arrow = cpp14::make_unique<cArrowEntity>(this, GetPosX(), GetPosY() + 1, GetPosZ(), Speed);
|
||||
auto ArrowPtr = Arrow.get();
|
||||
if (!ArrowPtr->Initialize(std::move(Arrow), *m_World))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ResetAttackCooldown();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "Globals.h"
|
||||
#include "SetChunkData.h"
|
||||
#include "BlockEntities/BlockEntity.h"
|
||||
#include "Entities/Entity.h"
|
||||
|
||||
|
||||
|
||||
|
@ -115,11 +115,3 @@ protected:
|
||||
bool m_AreBiomesValid;
|
||||
bool m_ShouldMarkDirty;
|
||||
};
|
||||
|
||||
typedef std::unique_ptr<cSetChunkData> cSetChunkDataPtr;
|
||||
typedef std::vector<cSetChunkDataPtr> cSetChunkDataPtrs;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
254
src/World.cpp
254
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[]
|
||||
@ -1550,7 +1551,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
|
||||
{
|
||||
@ -2176,15 +2177,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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2201,15 +2199,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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2219,14 +2214,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();
|
||||
}
|
||||
|
||||
|
||||
@ -2235,14 +2229,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;
|
||||
}
|
||||
|
||||
|
||||
@ -2257,14 +2251,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();
|
||||
}
|
||||
|
||||
|
||||
@ -2273,26 +2266,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();
|
||||
}
|
||||
|
||||
|
||||
@ -2301,18 +2294,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)
|
||||
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))
|
||||
{
|
||||
return cEntity::INVALID_ID;
|
||||
}
|
||||
if (!Boat->Initialize(*this))
|
||||
{
|
||||
delete Boat;
|
||||
Boat = nullptr;
|
||||
return cEntity::INVALID_ID;
|
||||
}
|
||||
return Boat->GetUniqueID();
|
||||
return BoatPtr->GetUniqueID();
|
||||
}
|
||||
|
||||
|
||||
@ -2320,20 +2308,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();
|
||||
}
|
||||
|
||||
|
||||
@ -2902,7 +2890,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));
|
||||
}
|
||||
|
||||
|
||||
@ -2917,15 +2905,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:
|
||||
@ -3046,39 +3029,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();
|
||||
@ -3086,12 +3071,66 @@ 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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cWorld::ForEachPlayer(cPlayerListCallback & a_Callback)
|
||||
{
|
||||
// Calls the callback for each player in the list
|
||||
@ -3303,11 +3342,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[]
|
||||
@ -3600,11 +3639,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));
|
||||
}
|
||||
|
||||
|
||||
@ -3739,9 +3778,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;
|
||||
@ -3753,13 +3790,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);
|
||||
|
||||
@ -3769,22 +3806,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();
|
||||
}
|
||||
|
||||
|
||||
@ -3793,18 +3828,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();
|
||||
}
|
||||
|
||||
|
||||
@ -4000,29 +4036,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();
|
||||
@ -4034,7 +4076,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();
|
||||
@ -4047,7 +4089,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)
|
||||
{
|
||||
@ -4077,14 +4119,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));
|
||||
}
|
||||
|
19
src/World.h
19
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. */
|
||||
@ -791,7 +796,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. */
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user