Skip to content

Commit 3e6bbb8

Browse files
JildorShauren
authored andcommitted
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
1 parent 33a8d42 commit 3e6bbb8

File tree

1 file changed

+50
-47
lines changed

1 file changed

+50
-47
lines changed

src/server/game/Pools/PoolMgr.cpp

Lines changed: 50 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -255,66 +255,69 @@ void PoolGroup<Pool>::RemoveOneRelation(uint32 child_pool_id)
255255
template <class T>
256256
void PoolGroup<T>::SpawnObject(ActivePoolData& spawns, uint32 limit, uint32 triggerFrom)
257257
{
258-
int count = limit - spawns.GetActiveObjectCount(poolId);
259-
260-
// If triggered from some object respawn this object is still marked as spawned
261-
// and also counted into m_SpawnedPoolAmount so we need increase count to be
262-
// spawned by 1
258+
// First clear the object that triggered the respawn, if any.
259+
// DespawnObject is responsible for decrementing the active object counter.
263260
if (triggerFrom)
264-
++count;
261+
DespawnObject(spawns, triggerFrom);
265262

266-
if (count > 0)
267-
{
268-
PoolObjectList rolledObjects;
269-
rolledObjects.reserve(count);
263+
int32 count = limit - spawns.GetActiveObjectCount(poolId);
264+
if (count <= 0)
265+
return;
270266

271-
// roll objects to be spawned
272-
if (!ExplicitlyChanced.empty())
273-
{
274-
float roll = (float)rand_chance();
267+
PoolObjectList candidates;
268+
candidates.reserve(EqualChanced.size() + ExplicitlyChanced.size());
275269

276-
for (PoolObject& obj : ExplicitlyChanced)
277-
{
278-
roll -= obj.chance;
279-
// Triggering object is marked as spawned at this time and can be also rolled (respawn case)
280-
// so this need explicit check for this case
281-
if (roll < 0 && (obj.guid == triggerFrom || !spawns.IsActiveObject<T>(obj.guid)))
282-
{
283-
rolledObjects.push_back(obj);
284-
break;
285-
}
286-
}
287-
}
270+
// Add all not already active candidates.
271+
for (PoolObject& obj : EqualChanced)
272+
if (!spawns.IsActiveObject<T>(obj.guid))
273+
candidates.push_back(obj);
288274

289-
if (!EqualChanced.empty() && rolledObjects.empty())
290-
{
291-
std::copy_if(EqualChanced.begin(), EqualChanced.end(), std::back_inserter(rolledObjects), [triggerFrom, &spawns](PoolObject const& object)
292-
{
293-
return object.guid == triggerFrom || !spawns.IsActiveObject<T>(object.guid);
294-
});
275+
for (PoolObject& obj : ExplicitlyChanced)
276+
if (!spawns.IsActiveObject<T>(obj.guid))
277+
candidates.push_back(obj);
295278

296-
Trinity::Containers::RandomResize(rolledObjects, count);
297-
}
279+
if (candidates.empty())
280+
return;
281+
282+
PoolObjectList rolledObjects;
283+
rolledObjects.reserve(count);
298284

299-
// try to spawn rolled objects
300-
for (PoolObject& obj : rolledObjects)
285+
// Attempt to select one object based on explicit chance.
286+
if (!ExplicitlyChanced.empty())
287+
{
288+
float roll = (float)rand_chance();
289+
for (PoolObject& candidate : candidates)
301290
{
302-
if (obj.guid == triggerFrom)
291+
if (candidate.chance > 0)
303292
{
304-
ReSpawn1Object(&obj);
305-
triggerFrom = 0;
306-
}
307-
else
308-
{
309-
spawns.ActivateObject<T>(obj.guid, poolId);
310-
Spawn1Object(&obj);
293+
roll -= candidate.chance;
294+
if (roll < 0)
295+
{
296+
rolledObjects.push_back(candidate);
297+
std::swap(candidate, candidates.back());
298+
candidates.pop_back();
299+
break; // We only roll for one chanced object.
300+
}
311301
}
312302
}
313303
}
314304

315-
// One spawn one despawn no count increase
316-
if (triggerFrom)
317-
DespawnObject(spawns, triggerFrom);
305+
// Fill the remaining slots with random selections from the rest of the candidates.
306+
uint32 remainingCount = count - rolledObjects.size();
307+
if (remainingCount > 0 && !candidates.empty())
308+
{
309+
if (candidates.size() > remainingCount)
310+
Trinity::Containers::RandomResize(candidates, remainingCount);
311+
312+
rolledObjects.insert(rolledObjects.end(), candidates.begin(), candidates.end());
313+
}
314+
315+
// Spawn all the objects we've selected.
316+
for (PoolObject& objToSpawn : rolledObjects)
317+
{
318+
spawns.ActivateObject<T>(objToSpawn.guid, poolId);
319+
Spawn1Object(&objToSpawn);
320+
}
318321
}
319322

320323
// Method that is actualy doing the spawn job on 1 creature

0 commit comments

Comments
 (0)