ZoneServer::KillSpawnByDistance deadlock fixed by calling outside of grid mutex lock. Killing spawn resulted in dropping loot chest, then Entity::DropChest calls SetLocation which calls AddSpawnToGrid causing deadlock.

This commit is contained in:
Emagi 2025-08-26 09:00:59 -04:00
parent 1bc87d6617
commit 3045b15f88
2 changed files with 43 additions and 27 deletions

View File

@ -4653,35 +4653,14 @@ void ZoneServer::KillSpawnByDistance(Spawn* spawn, float max_distance, bool incl
if(!spawn)
return;
auto loc = glm::vec3(spawn->GetX(), spawn->GetZ(), spawn->GetY());
std::vector<int32> grids_by_radius;
if(spawn->GetMap()) {
grids_by_radius = GetGridsByLocation(spawn, loc, max_distance);
}
else {
grids_by_radius.push_back(spawn->GetLocation());
}
Spawn* test_spawn = 0;
MGridMaps.lock_shared();
std::vector<int32>::iterator grid_radius_itr;
for(grid_radius_itr = grids_by_radius.begin(); grid_radius_itr != grids_by_radius.end(); grid_radius_itr++) {
std::map<int32, GridMap*>::iterator grids = grid_maps.find((*grid_radius_itr));
if(grids != grid_maps.end()) {
grids->second->MSpawns.lock_shared();
typedef map <int32, Spawn*> SpawnMapType;
for( SpawnMapType::iterator it = grids->second->spawns.begin(); it != grids->second->spawns.end(); ++it ) {
test_spawn = it->second;
if(test_spawn && test_spawn->Alive() && test_spawn->GetID() > 0 && test_spawn->GetID() != spawn->GetID() && test_spawn->IsEntity() &&
(!test_spawn->IsPlayer() || include_players)){
if(test_spawn->GetDistance(spawn) < max_distance)
std::vector<std::pair<int32, float>> spawns = GetSpawnsByDistance(spawn, max_distance, include_players);
for (const auto& pair : spawns) {
int32 target_id = pair.first;
Spawn* test_spawn = GetSpawnByID(target_id);
if(test_spawn)
KillSpawn(false, test_spawn, spawn, send_packet);
}
}
grids->second->MSpawns.unlock_shared();
}
}
MGridMaps.unlock_shared();
}
void ZoneServer::SpawnSetByDistance(Spawn* spawn, float max_distance, string field, string value){
@ -7824,6 +7803,42 @@ std::vector<std::pair<int32, float>> ZoneServer::GetAttackableSpawnsByDistance(S
return spawns_by_distance;
}
std::vector<std::pair<int32, float>> ZoneServer::GetSpawnsByDistance(Spawn* spawn, float max_distance, bool include_players) {
std::vector<std::pair<int32, float>> spawns_by_distance;
auto loc = glm::vec3(spawn->GetX(), spawn->GetZ(), spawn->GetY());
std::vector<int32> grids_by_radius;
if(spawn->GetMap()) {
grids_by_radius = GetGridsByLocation(spawn, loc, max_distance);
}
else {
grids_by_radius.push_back(spawn->GetLocation());
}
float tmp_dist = 0.0f;
MGridMaps.lock_shared();
std::vector<int32>::iterator grid_radius_itr;
for(grid_radius_itr = grids_by_radius.begin(); grid_radius_itr != grids_by_radius.end(); grid_radius_itr++) {
std::map<int32, GridMap*>::iterator grids = grid_maps.find((*grid_radius_itr));
if(grids != grid_maps.end()) {
grids->second->MSpawns.lock_shared();
typedef map <int32, Spawn*> SpawnMapType;
for( SpawnMapType::iterator it = grids->second->spawns.begin(); it != grids->second->spawns.end(); ++it ) {
Spawn* test_spawn = it->second;
if(test_spawn && test_spawn->Alive() && test_spawn->GetID() > 0 && test_spawn->GetID() != spawn->GetID() && test_spawn->IsEntity() &&
(!test_spawn->IsPlayer() || include_players)){
if(test_spawn->GetDistance(spawn) < max_distance)
spawns_by_distance.push_back({test_spawn->GetID(), tmp_dist});
}
}
grids->second->MSpawns.unlock_shared();
}
}
MGridMaps.unlock_shared();
std::sort(spawns_by_distance.begin(), spawns_by_distance.end(), compareByValue);
return spawns_by_distance;
}
void ZoneServer::ResurrectSpawn(Spawn* spawn, Client* client) {
if(!client || !spawn)
return;

View File

@ -448,6 +448,7 @@ public:
std::vector<int32> GetGridsByLocation(Spawn* originator, glm::vec3 loc, float distance);
/// <summary>Gets spawns for a true AoE spell</summary>
std::vector<std::pair<int32, float>> GetAttackableSpawnsByDistance(Spawn* spawn, float distance);
std::vector<std::pair<int32, float>> GetSpawnsByDistance(Spawn* spawn, float max_distance, bool include_players);
// Comparator function to sort by the value (second element of the pair)
static bool compareByValue(const std::pair<int32, float>& a, const std::pair<int32, float>& b) {