Core/Pools: Refactor PoolGroup::SpawnObject
* Prevent double spawn with pools with maxlimit 1 in certain situations * Prevent infinite recursive call with specific case of nested pools (cherry picked from commit 3e6bbb827de4013578af65a343af7aa979a186b5)
This commit is contained in:
@@ -289,66 +289,69 @@ void PoolGroup<Pool>::RemoveOneRelation(uint32 child_pool_id)
|
||||
template <class T>
|
||||
void PoolGroup<T>::SpawnObject(SpawnedPoolData& spawns, uint32 limit, uint64 triggerFrom)
|
||||
{
|
||||
int count = limit - spawns.GetSpawnedObjects(poolId);
|
||||
|
||||
// If triggered from some object respawn this object is still marked as spawned
|
||||
// and also counted into m_SpawnedPoolAmount so we need increase count to be
|
||||
// spawned by 1
|
||||
// First clear the object that triggered the respawn, if any.
|
||||
// DespawnObject is responsible for decrementing the active object counter.
|
||||
if (triggerFrom)
|
||||
++count;
|
||||
DespawnObject(spawns, triggerFrom);
|
||||
|
||||
if (count > 0)
|
||||
int32 count = limit - spawns.GetSpawnedObjects(poolId);
|
||||
if (count <= 0)
|
||||
return;
|
||||
|
||||
PoolObjectList candidates;
|
||||
candidates.reserve(EqualChanced.size() + ExplicitlyChanced.size());
|
||||
|
||||
// Add all not already active candidates.
|
||||
for (PoolObject& obj : EqualChanced)
|
||||
if (!spawns.IsSpawnedObject<T>(obj.guid))
|
||||
candidates.push_back(obj);
|
||||
|
||||
for (PoolObject& obj : ExplicitlyChanced)
|
||||
if (!spawns.IsSpawnedObject<T>(obj.guid))
|
||||
candidates.push_back(obj);
|
||||
|
||||
if (candidates.empty())
|
||||
return;
|
||||
|
||||
PoolObjectList rolledObjects;
|
||||
rolledObjects.reserve(count);
|
||||
|
||||
// Attempt to select one object based on explicit chance.
|
||||
if (!ExplicitlyChanced.empty())
|
||||
{
|
||||
PoolObjectList rolledObjects;
|
||||
rolledObjects.reserve(count);
|
||||
|
||||
// roll objects to be spawned
|
||||
if (!ExplicitlyChanced.empty())
|
||||
float roll = rand_chance();
|
||||
for (PoolObject& candidate : candidates)
|
||||
{
|
||||
float roll = rand_chance();
|
||||
|
||||
for (PoolObject& obj : ExplicitlyChanced)
|
||||
if (candidate.chance > 0)
|
||||
{
|
||||
roll -= obj.chance;
|
||||
// Triggering object is marked as spawned at this time and can be also rolled (respawn case)
|
||||
// so this need explicit check for this case
|
||||
if (roll < 0 && (obj.guid == triggerFrom || !spawns.IsSpawnedObject<T>(obj.guid)))
|
||||
roll -= candidate.chance;
|
||||
if (roll < 0)
|
||||
{
|
||||
rolledObjects.push_back(obj);
|
||||
break;
|
||||
rolledObjects.push_back(candidate);
|
||||
std::swap(candidate, candidates.back());
|
||||
candidates.pop_back();
|
||||
break; // We only roll for one chanced object.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!EqualChanced.empty() && rolledObjects.empty())
|
||||
{
|
||||
std::copy_if(EqualChanced.begin(), EqualChanced.end(), std::back_inserter(rolledObjects), [triggerFrom, &spawns](PoolObject const& object)
|
||||
{
|
||||
return object.guid == triggerFrom || !spawns.IsSpawnedObject<T>(object.guid);
|
||||
});
|
||||
|
||||
Trinity::Containers::RandomResize(rolledObjects, count);
|
||||
}
|
||||
|
||||
// try to spawn rolled objects
|
||||
for (PoolObject& obj : rolledObjects)
|
||||
{
|
||||
if (obj.guid == triggerFrom)
|
||||
{
|
||||
ReSpawn1Object(spawns, &obj);
|
||||
triggerFrom = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
spawns.AddSpawn<T>(obj.guid, poolId);
|
||||
Spawn1Object(spawns, &obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// One spawn one despawn no count increase
|
||||
if (triggerFrom)
|
||||
DespawnObject(spawns, triggerFrom);
|
||||
// Fill the remaining slots with random selections from the rest of the candidates.
|
||||
uint32 remainingCount = count - rolledObjects.size();
|
||||
if (remainingCount > 0 && !candidates.empty())
|
||||
{
|
||||
if (candidates.size() > remainingCount)
|
||||
Trinity::Containers::RandomResize(candidates, remainingCount);
|
||||
|
||||
rolledObjects.insert(rolledObjects.end(), candidates.begin(), candidates.end());
|
||||
}
|
||||
|
||||
// Spawn all the objects we've selected.
|
||||
for (PoolObject& objToSpawn : rolledObjects)
|
||||
{
|
||||
spawns.AddSpawn<T>(objToSpawn.guid, poolId);
|
||||
Spawn1Object(spawns, &objToSpawn);
|
||||
}
|
||||
}
|
||||
|
||||
// Method that is actualy doing the spawn job on 1 creature
|
||||
|
||||
Reference in New Issue
Block a user