Prevent accessing spawn list outside of read lock, removal of pending spawn removals (redundant)
This commit is contained in:
parent
9ef48d3bab
commit
b7f56e3b73
@ -294,7 +294,7 @@ void Entity::MeleeAttack(Spawn* victim, float distance, bool primary, bool multi
|
|||||||
DamageSpawn((Entity*)victim, DAMAGE_PACKET_TYPE_SIMPLE_CRIT_DMG, damage_type, min_damage, max_damage, 0);
|
DamageSpawn((Entity*)victim, DAMAGE_PACKET_TYPE_SIMPLE_CRIT_DMG, damage_type, min_damage, max_damage, 0);
|
||||||
}
|
}
|
||||||
else*/
|
else*/
|
||||||
DamageSpawn((Entity*)victim, DAMAGE_PACKET_TYPE_SIMPLE_DAMAGE, damage_type, min_damage, max_damage, 0);
|
DamageSpawn((Entity*)victim, DAMAGE_PACKET_TYPE_SIMPLE_DAMAGE, damage_type, min_damage, max_damage, 0, 0, false, false, false, false, nullptr, false, true);
|
||||||
if (!multi_attack) {
|
if (!multi_attack) {
|
||||||
CheckProcs(PROC_TYPE_OFFENSIVE, victim);
|
CheckProcs(PROC_TYPE_OFFENSIVE, victim);
|
||||||
CheckProcs(PROC_TYPE_PHYSICAL_OFFENSIVE, victim);
|
CheckProcs(PROC_TYPE_PHYSICAL_OFFENSIVE, victim);
|
||||||
@ -1057,7 +1057,7 @@ Skill* Entity::GetSkillByWeaponType(int8 type, int8 damage_type, bool update) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Entity::DamageSpawn(Entity* victim, int8 type, int8 damage_type, int32 low_damage, int32 high_damage, const char* spell_name, int8 crit_mod, bool is_tick, bool no_calcs, bool ignore_attacker, bool take_power, LuaSpell* spell, bool skip_check_wards) {
|
bool Entity::DamageSpawn(Entity* victim, int8 type, int8 damage_type, int32 low_damage, int32 high_damage, const char* spell_name, int8 crit_mod, bool is_tick, bool no_calcs, bool ignore_attacker, bool take_power, LuaSpell* spell, bool skip_check_wards, bool is_melee_spawn) {
|
||||||
if(spell) {
|
if(spell) {
|
||||||
spell->is_damage_spell = true;
|
spell->is_damage_spell = true;
|
||||||
}
|
}
|
||||||
@ -1236,7 +1236,7 @@ bool Entity::DamageSpawn(Entity* victim, int8 type, int8 damage_type, int32 low_
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (victim->GetHP() <= 0)
|
if (victim->GetHP() <= 0)
|
||||||
KillSpawn(victim, type, damage_type, blow_type);
|
KillSpawn(victim, type, damage_type, blow_type, is_melee_spawn);
|
||||||
else {
|
else {
|
||||||
victim->CheckProcs(PROC_TYPE_DEFENSIVE, this);
|
victim->CheckProcs(PROC_TYPE_DEFENSIVE, this);
|
||||||
if (spell_name)
|
if (spell_name)
|
||||||
@ -1439,7 +1439,7 @@ bool Entity::CheckInterruptSpell(Entity* attacker) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Entity::KillSpawn(Spawn* dead, int8 type, int8 damage_type, int16 kill_blow_type) {
|
void Entity::KillSpawn(Spawn* dead, int8 type, int8 damage_type, int16 kill_blow_type, bool is_melee_spawn) {
|
||||||
if(!dead)
|
if(!dead)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -1479,7 +1479,7 @@ void Entity::KillSpawn(Spawn* dead, int8 type, int8 damage_type, int16 kill_blow
|
|||||||
dead->ClearRunningLocations();
|
dead->ClearRunningLocations();
|
||||||
dead->CalculateRunningLocation(true);
|
dead->CalculateRunningLocation(true);
|
||||||
|
|
||||||
GetZone()->KillSpawn(true, dead, this, true, type, damage_type, kill_blow_type);
|
GetZone()->KillSpawn(is_melee_spawn, dead, this, true, type, damage_type, kill_blow_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Entity::HandleDeathExperienceDebt(Spawn* killer)
|
void Entity::HandleDeathExperienceDebt(Spawn* killer)
|
||||||
@ -1552,7 +1552,7 @@ void Player::ProcessCombat() {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
//If no target delete combat_target and return out
|
//If no target delete combat_target and return out
|
||||||
Spawn* Target = GetZone()->GetSpawnByID(target);
|
Spawn* Target = GetZone()->GetSpawnByID(target, true);
|
||||||
if (!Target) {
|
if (!Target) {
|
||||||
combat_target = 0;
|
combat_target = 0;
|
||||||
if (target > 0) {
|
if (target > 0) {
|
||||||
|
@ -1563,12 +1563,12 @@ public:
|
|||||||
int8 DetermineHit(Spawn* victim, int8 type, int8 damage_type, float ToHitBonus, bool is_caster_spell, LuaSpell* lua_spell = nullptr);
|
int8 DetermineHit(Spawn* victim, int8 type, int8 damage_type, float ToHitBonus, bool is_caster_spell, LuaSpell* lua_spell = nullptr);
|
||||||
float GetDamageTypeResistPercentage(int8 damage_type);
|
float GetDamageTypeResistPercentage(int8 damage_type);
|
||||||
Skill* GetSkillByWeaponType(int8 type, int8 damage_type, bool update);
|
Skill* GetSkillByWeaponType(int8 type, int8 damage_type, bool update);
|
||||||
bool DamageSpawn(Entity* victim, int8 type, int8 damage_type, int32 low_damage, int32 high_damage, const char* spell_name, int8 crit_mod = 0, bool is_tick = false, bool no_damage_calcs = false, bool ignore_attacker = false, bool take_power = false, LuaSpell* spell = 0, bool skip_check_wards = false);
|
bool DamageSpawn(Entity* victim, int8 type, int8 damage_type, int32 low_damage, int32 high_damage, const char* spell_name, int8 crit_mod = 0, bool is_tick = false, bool no_damage_calcs = false, bool ignore_attacker = false, bool take_power = false, LuaSpell* spell = 0, bool skip_check_wards = false, bool is_melee_spawn = false);
|
||||||
float CalculateMitigation(int8 type = DAMAGE_PACKET_TYPE_SIMPLE_DAMAGE, int8 damage_type = 0, int16 attacker_level = 0, bool for_pvp = false);
|
float CalculateMitigation(int8 type = DAMAGE_PACKET_TYPE_SIMPLE_DAMAGE, int8 damage_type = 0, int16 attacker_level = 0, bool for_pvp = false);
|
||||||
void AddHate(Entity* attacker, sint32 hate, bool ignore_pet_behavior = false);
|
void AddHate(Entity* attacker, sint32 hate, bool ignore_pet_behavior = false);
|
||||||
bool CheckInterruptSpell(Entity* attacker);
|
bool CheckInterruptSpell(Entity* attacker);
|
||||||
bool CheckFizzleSpell(LuaSpell* spell);
|
bool CheckFizzleSpell(LuaSpell* spell);
|
||||||
void KillSpawn(Spawn* dead, int8 type = 0, int8 damage_type = 0, int16 kill_blow_type = 0);
|
void KillSpawn(Spawn* dead, int8 type = 0, int8 damage_type = 0, int16 kill_blow_type = 0, bool is_melee_spawn = false);
|
||||||
void HandleDeathExperienceDebt(Spawn* killer);
|
void HandleDeathExperienceDebt(Spawn* killer);
|
||||||
void SetAttackDelay(bool primary = false, bool ranged = false);
|
void SetAttackDelay(bool primary = false, bool ranged = false);
|
||||||
float CalculateAttackSpeedMod();
|
float CalculateAttackSpeedMod();
|
||||||
|
@ -175,8 +175,6 @@ ZoneServer::ZoneServer(const char* name) {
|
|||||||
tradeskillMgr = nullptr;
|
tradeskillMgr = nullptr;
|
||||||
watchdogTimestamp = Timer::GetCurrentTime2();
|
watchdogTimestamp = Timer::GetCurrentTime2();
|
||||||
|
|
||||||
MPendingSpawnRemoval.SetName("ZoneServer::MPendingSpawnRemoval");
|
|
||||||
|
|
||||||
lifetime_client_count = 0;
|
lifetime_client_count = 0;
|
||||||
|
|
||||||
groupraidMinLevel = 0;
|
groupraidMinLevel = 0;
|
||||||
@ -311,6 +309,7 @@ void ZoneServer::Init()
|
|||||||
shutdownTimer.Disable();
|
shutdownTimer.Disable();
|
||||||
spawn_range.Start(rule_manager.GetGlobalRule(R_Zone, CheckAttackPlayer)->GetInt32());
|
spawn_range.Start(rule_manager.GetGlobalRule(R_Zone, CheckAttackPlayer)->GetInt32());
|
||||||
aggro_timer.Start(rule_manager.GetGlobalRule(R_Zone, CheckAttackNPC)->GetInt32());
|
aggro_timer.Start(rule_manager.GetGlobalRule(R_Zone, CheckAttackNPC)->GetInt32());
|
||||||
|
delete_timer.Start(1000);
|
||||||
/* Weather stuff */
|
/* Weather stuff */
|
||||||
InitWeather();
|
InitWeather();
|
||||||
|
|
||||||
@ -1528,21 +1527,13 @@ void ZoneServer::DeleteSpawns(bool delete_all) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
MPendingSpawnRemoval.readlock(__FUNCTION__, __LINE__);
|
|
||||||
if(!delete_all && m_pendingSpawnRemove.count(spawn->GetID())) {
|
|
||||||
to_keep.emplace_back(entry);
|
|
||||||
MPendingSpawnRemoval.releasereadlock(__FUNCTION__, __LINE__);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
MPendingSpawnRemoval.releasereadlock(__FUNCTION__, __LINE__);
|
|
||||||
|
|
||||||
lua_interface->SetLuaUserDataStale(spawn);
|
lua_interface->SetLuaUserDataStale(spawn);
|
||||||
|
|
||||||
if (spellProcess) {
|
if (spellProcess) {
|
||||||
spellProcess->RemoveCaster(spawn, true);
|
spellProcess->RemoveCaster(spawn, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(movementMgr != nullptr) {
|
if(spawn->IsEntity() && movementMgr != nullptr) {
|
||||||
movementMgr->RemoveMob((Entity*)spawn);
|
movementMgr->RemoveMob((Entity*)spawn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1890,10 +1881,7 @@ bool ZoneServer::SpawnProcess(){
|
|||||||
bool spawnRange = spawn_range.Check();
|
bool spawnRange = spawn_range.Check();
|
||||||
bool checkRemove = spawn_check_remove.Check();
|
bool checkRemove = spawn_check_remove.Check();
|
||||||
bool aggroCheck = aggro_timer.Check();
|
bool aggroCheck = aggro_timer.Check();
|
||||||
vector<int32> pending_spawn_list_remove;
|
bool deleteTimer = delete_timer.Check();
|
||||||
|
|
||||||
// Check to see if there are any spawn id's that need to be removed from the spawn list, if so remove them all
|
|
||||||
ProcessSpawnRemovals();
|
|
||||||
|
|
||||||
map<int32, Spawn*>::iterator itr;
|
map<int32, Spawn*>::iterator itr;
|
||||||
if (spawnRange || checkRemove)
|
if (spawnRange || checkRemove)
|
||||||
@ -1960,40 +1948,16 @@ bool ZoneServer::SpawnProcess(){
|
|||||||
CombatProcess(spawn);
|
CombatProcess(spawn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
// unable to get a valid spawn, lets add the id to another list to remove from the spawn list after this loop is finished
|
|
||||||
pending_spawn_list_remove.push_back(itr->first);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
MSpawnList.releasereadlock(__FUNCTION__, __LINE__);
|
MSpawnList.releasereadlock(__FUNCTION__, __LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check to see if there are any spawn id's that need to be removed from the spawn list, if so remove them all
|
|
||||||
if (pending_spawn_list_remove.size() > 0) {
|
|
||||||
MSpawnList.writelock(__FUNCTION__, __LINE__);
|
|
||||||
vector<int32>::iterator itr2;
|
|
||||||
for (itr2 = pending_spawn_list_remove.begin(); itr2 != pending_spawn_list_remove.end(); itr2++) {
|
|
||||||
spawn_list.erase(*itr2);
|
|
||||||
subspawn_list[SUBSPAWN_TYPES::COLLECTOR].erase(*itr2);
|
|
||||||
|
|
||||||
std::map<int32,int32>::iterator hsmitr = housing_spawn_map.find(*itr2);
|
|
||||||
if(hsmitr != housing_spawn_map.end()) {
|
|
||||||
subspawn_list[SUBSPAWN_TYPES::HOUSE_ITEM_SPAWN].erase(hsmitr->second);
|
|
||||||
housing_spawn_map.erase(hsmitr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pending_spawn_list_remove.clear();
|
|
||||||
MSpawnList.releasewritelock(__FUNCTION__, __LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Double Check to see if there are any spawn id's that need to be removed from the spawn list, if so remove them before we replace with pending spawns
|
|
||||||
// and also potentially further down when we delete the Spawn* in DeleteSpawns(false)
|
|
||||||
ProcessSpawnRemovals();
|
|
||||||
|
|
||||||
// Check to see if there are spawns waiting to be added to the spawn list, if so add them all
|
// Check to see if there are spawns waiting to be added to the spawn list, if so add them all
|
||||||
if (pending_spawn_list_add.size() > 0) {
|
MPendingSpawnListAdd.readlock(__FUNCTION__, __LINE__);
|
||||||
|
int32 pending_count = pending_spawn_list_add.size();
|
||||||
|
MPendingSpawnListAdd.releasereadlock(__FUNCTION__, __LINE__);
|
||||||
|
if (pending_count > 0) {
|
||||||
ProcessPendingSpawns();
|
ProcessPendingSpawns();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2011,7 +1975,7 @@ bool ZoneServer::SpawnProcess(){
|
|||||||
|
|
||||||
|
|
||||||
// Delete unused spawns, do this last
|
// Delete unused spawns, do this last
|
||||||
if(!zoneShuttingDown)
|
if(!zoneShuttingDown && deleteTimer)
|
||||||
DeleteSpawns(false);
|
DeleteSpawns(false);
|
||||||
|
|
||||||
// Nothing should come after this
|
// Nothing should come after this
|
||||||
@ -4706,7 +4670,7 @@ void ZoneServer::KillSpawnByDistance(Spawn* spawn, float max_distance, bool incl
|
|||||||
if(test_spawn && test_spawn->Alive() && test_spawn->GetID() > 0 && test_spawn->GetID() != spawn->GetID() && test_spawn->IsEntity() &&
|
if(test_spawn && test_spawn->Alive() && test_spawn->GetID() > 0 && test_spawn->GetID() != spawn->GetID() && test_spawn->IsEntity() &&
|
||||||
(!test_spawn->IsPlayer() || include_players)){
|
(!test_spawn->IsPlayer() || include_players)){
|
||||||
if(test_spawn->GetDistance(spawn) < max_distance)
|
if(test_spawn->GetDistance(spawn) < max_distance)
|
||||||
KillSpawn(true, test_spawn, spawn, send_packet);
|
KillSpawn(false, test_spawn, spawn, send_packet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
grids->second->MSpawns.unlock_shared();
|
grids->second->MSpawns.unlock_shared();
|
||||||
@ -4832,10 +4796,6 @@ void ZoneServer::RemoveSpawn(Spawn* spawn, bool delete_spawn, bool respawn, bool
|
|||||||
|
|
||||||
spawn->SetDeletedSpawn(true);
|
spawn->SetDeletedSpawn(true);
|
||||||
|
|
||||||
// we will remove the spawn ptr and entry in the spawn_list later.. it is not safe right now (lua? client process? spawn process? etc? too many factors)
|
|
||||||
if(erase_from_spawn_list)
|
|
||||||
AddPendingSpawnRemove(spawn->GetID());
|
|
||||||
|
|
||||||
if(respawn && !spawn->IsPlayer() && spawn->GetSpawnLocationID() > 0) {
|
if(respawn && !spawn->IsPlayer() && spawn->GetSpawnLocationID() > 0) {
|
||||||
LogWrite(ZONE__DEBUG, 3, "Zone", "Handle NPC Respawn for '%s'.", spawn->GetName());
|
LogWrite(ZONE__DEBUG, 3, "Zone", "Handle NPC Respawn for '%s'.", spawn->GetName());
|
||||||
AddRespawn(spawn);
|
AddRespawn(spawn);
|
||||||
@ -5131,7 +5091,7 @@ void ZoneServer::ProcessFaction(Spawn* spawn, Client* client)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ZoneServer::Despawn(Spawn* spawn, int32 timer){
|
void ZoneServer::Despawn(Spawn* spawn, int32 timer){
|
||||||
if (spawn && movementMgr != nullptr) {
|
if (spawn && spawn->IsEntity() && movementMgr != nullptr) {
|
||||||
movementMgr->RemoveMob((Entity*)spawn);
|
movementMgr->RemoveMob((Entity*)spawn);
|
||||||
}
|
}
|
||||||
if(!spawn || spawn->IsPlayer())
|
if(!spawn || spawn->IsPlayer())
|
||||||
@ -5453,7 +5413,7 @@ void ZoneServer::KillSpawn(bool spawnListLocked, Spawn* dead, Spawn* killer, boo
|
|||||||
spellProcess->RemoveSpellFromQueue((Player*)dead, true);
|
spellProcess->RemoveSpellFromQueue((Player*)dead, true);
|
||||||
|
|
||||||
if (dead->IsNPC())
|
if (dead->IsNPC())
|
||||||
((NPC*)dead)->Brain()->ClearHate(!spawnListLocked);
|
((NPC*)dead)->Brain()->ClearHate(spawnListLocked);
|
||||||
|
|
||||||
safe_delete(encounter);
|
safe_delete(encounter);
|
||||||
|
|
||||||
@ -9164,36 +9124,6 @@ Spawn* ZoneServer::GetSpawnFromUniqueItemID(int32 unique_id)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZoneServer::AddPendingSpawnRemove(int32 id)
|
|
||||||
{
|
|
||||||
MPendingSpawnRemoval.writelock(__FUNCTION__, __LINE__);
|
|
||||||
m_pendingSpawnRemove.insert(make_pair(id,true));
|
|
||||||
MPendingSpawnRemoval.releasewritelock(__FUNCTION__, __LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ZoneServer::ProcessSpawnRemovals()
|
|
||||||
{
|
|
||||||
MSpawnList.writelock(__FUNCTION__, __LINE__);
|
|
||||||
MPendingSpawnRemoval.writelock(__FUNCTION__, __LINE__);
|
|
||||||
if (m_pendingSpawnRemove.size() > 0) {
|
|
||||||
map<int32,bool>::iterator itr2;
|
|
||||||
for (itr2 = m_pendingSpawnRemove.begin(); itr2 != m_pendingSpawnRemove.end(); itr2++) {
|
|
||||||
spawn_list.erase(itr2->first);
|
|
||||||
subspawn_list[SUBSPAWN_TYPES::COLLECTOR].erase(itr2->first);
|
|
||||||
|
|
||||||
std::map<int32,int32>::iterator hsmitr = housing_spawn_map.find(itr2->first);
|
|
||||||
if(hsmitr != housing_spawn_map.end()) {
|
|
||||||
subspawn_list[SUBSPAWN_TYPES::HOUSE_ITEM_SPAWN].erase(hsmitr->second);
|
|
||||||
housing_spawn_map.erase(hsmitr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_pendingSpawnRemove.clear();
|
|
||||||
}
|
|
||||||
MPendingSpawnRemoval.releasewritelock(__FUNCTION__, __LINE__);
|
|
||||||
MSpawnList.releasewritelock(__FUNCTION__, __LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ZoneServer::AddSpawnToGroup(Spawn* spawn, int32 group_id)
|
void ZoneServer::AddSpawnToGroup(Spawn* spawn, int32 group_id)
|
||||||
{
|
{
|
||||||
if( spawn->GetSpawnGroupID() > 0 )
|
if( spawn->GetSpawnGroupID() > 0 )
|
||||||
|
@ -706,9 +706,6 @@ public:
|
|||||||
void SetWatchdogTime(int32 time) { watchdogTimestamp = time; }
|
void SetWatchdogTime(int32 time) { watchdogTimestamp = time; }
|
||||||
void CancelThreads();
|
void CancelThreads();
|
||||||
|
|
||||||
void AddPendingSpawnRemove(int32 id);
|
|
||||||
void ProcessSpawnRemovals();
|
|
||||||
|
|
||||||
bool SendRemoveSpawn(Client* client, Spawn* spawn, PacketStruct* packet = 0, bool delete_spawn = false);
|
bool SendRemoveSpawn(Client* client, Spawn* spawn, PacketStruct* packet = 0, bool delete_spawn = false);
|
||||||
|
|
||||||
void AddSpawnToGroup(Spawn* spawn, int32 group_id);
|
void AddSpawnToGroup(Spawn* spawn, int32 group_id);
|
||||||
@ -924,6 +921,7 @@ private:
|
|||||||
Timer widget_timer;
|
Timer widget_timer;
|
||||||
Timer queue_updates;
|
Timer queue_updates;
|
||||||
Timer shutdownDelayTimer;
|
Timer shutdownDelayTimer;
|
||||||
|
Timer delete_timer;
|
||||||
|
|
||||||
/* Enums */
|
/* Enums */
|
||||||
Instance_Type InstanceType;
|
Instance_Type InstanceType;
|
||||||
@ -1029,9 +1027,6 @@ private:
|
|||||||
|
|
||||||
int32 watchdogTimestamp;
|
int32 watchdogTimestamp;
|
||||||
|
|
||||||
std::map<int32, bool> m_pendingSpawnRemove;
|
|
||||||
Mutex MPendingSpawnRemoval;
|
|
||||||
|
|
||||||
std::map<int32, int32> lua_queued_state_commands;
|
std::map<int32, int32> lua_queued_state_commands;
|
||||||
std::map<int32, std::map<std::string, float>> lua_spawn_update_command;
|
std::map<int32, std::map<std::string, float>> lua_spawn_update_command;
|
||||||
std::mutex MLuaQueueStateCmd;
|
std::mutex MLuaQueueStateCmd;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user