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,36 +4653,15 @@ void ZoneServer::KillSpawnByDistance(Spawn* spawn, float max_distance, bool incl
if(!spawn) if(!spawn)
return; 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; std::vector<std::pair<int32, float>> spawns = GetSpawnsByDistance(spawn, max_distance, include_players);
MGridMaps.lock_shared(); for (const auto& pair : spawns) {
std::vector<int32>::iterator grid_radius_itr; int32 target_id = pair.first;
for(grid_radius_itr = grids_by_radius.begin(); grid_radius_itr != grids_by_radius.end(); grid_radius_itr++) { Spawn* test_spawn = GetSpawnByID(target_id);
std::map<int32, GridMap*>::iterator grids = grid_maps.find((*grid_radius_itr)); if(test_spawn)
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)
KillSpawn(false, test_spawn, spawn, send_packet); 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){ void ZoneServer::SpawnSetByDistance(Spawn* spawn, float max_distance, string field, string value){
if(!spawn) if(!spawn)
@ -7824,6 +7803,42 @@ std::vector<std::pair<int32, float>> ZoneServer::GetAttackableSpawnsByDistance(S
return spawns_by_distance; 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) { void ZoneServer::ResurrectSpawn(Spawn* spawn, Client* client) {
if(!client || !spawn) if(!client || !spawn)
return; return;

View File

@ -448,6 +448,7 @@ public:
std::vector<int32> GetGridsByLocation(Spawn* originator, glm::vec3 loc, float distance); std::vector<int32> GetGridsByLocation(Spawn* originator, glm::vec3 loc, float distance);
/// <summary>Gets spawns for a true AoE spell</summary> /// <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>> 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) // 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) { static bool compareByValue(const std::pair<int32, float>& a, const std::pair<int32, float>& b) {