diff --git a/source/WorldServer/Combat.cpp b/source/WorldServer/Combat.cpp index ad619e6..f76b1d3 100644 --- a/source/WorldServer/Combat.cpp +++ b/source/WorldServer/Combat.cpp @@ -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); } 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) { CheckProcs(PROC_TYPE_OFFENSIVE, victim); CheckProcs(PROC_TYPE_PHYSICAL_OFFENSIVE, victim); @@ -1057,7 +1057,7 @@ Skill* Entity::GetSkillByWeaponType(int8 type, int8 damage_type, bool update) { 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) { 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) - KillSpawn(victim, type, damage_type, blow_type); + KillSpawn(victim, type, damage_type, blow_type, is_melee_spawn); else { victim->CheckProcs(PROC_TYPE_DEFENSIVE, this); if (spell_name) @@ -1439,7 +1439,7 @@ bool Entity::CheckInterruptSpell(Entity* attacker) { 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) return; @@ -1479,7 +1479,7 @@ void Entity::KillSpawn(Spawn* dead, int8 type, int8 damage_type, int16 kill_blow dead->ClearRunningLocations(); 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) @@ -1552,7 +1552,7 @@ void Player::ProcessCombat() { return; //If no target delete combat_target and return out - Spawn* Target = GetZone()->GetSpawnByID(target); + Spawn* Target = GetZone()->GetSpawnByID(target, true); if (!Target) { combat_target = 0; if (target > 0) { diff --git a/source/WorldServer/Entity.h b/source/WorldServer/Entity.h index 40348a0..ca39bf4 100644 --- a/source/WorldServer/Entity.h +++ b/source/WorldServer/Entity.h @@ -1563,12 +1563,12 @@ public: int8 DetermineHit(Spawn* victim, int8 type, int8 damage_type, float ToHitBonus, bool is_caster_spell, LuaSpell* lua_spell = nullptr); float GetDamageTypeResistPercentage(int8 damage_type); 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); void AddHate(Entity* attacker, sint32 hate, bool ignore_pet_behavior = false); bool CheckInterruptSpell(Entity* attacker); 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 SetAttackDelay(bool primary = false, bool ranged = false); float CalculateAttackSpeedMod(); diff --git a/source/WorldServer/zoneserver.cpp b/source/WorldServer/zoneserver.cpp index fe9ee83..0ccb763 100644 --- a/source/WorldServer/zoneserver.cpp +++ b/source/WorldServer/zoneserver.cpp @@ -175,8 +175,6 @@ ZoneServer::ZoneServer(const char* name) { tradeskillMgr = nullptr; watchdogTimestamp = Timer::GetCurrentTime2(); - MPendingSpawnRemoval.SetName("ZoneServer::MPendingSpawnRemoval"); - lifetime_client_count = 0; groupraidMinLevel = 0; @@ -311,6 +309,7 @@ void ZoneServer::Init() shutdownTimer.Disable(); spawn_range.Start(rule_manager.GetGlobalRule(R_Zone, CheckAttackPlayer)->GetInt32()); aggro_timer.Start(rule_manager.GetGlobalRule(R_Zone, CheckAttackNPC)->GetInt32()); + delete_timer.Start(1000); /* Weather stuff */ InitWeather(); @@ -1527,14 +1526,6 @@ void ZoneServer::DeleteSpawns(bool delete_all) { to_keep.emplace_back(entry); 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); @@ -1542,7 +1533,7 @@ void ZoneServer::DeleteSpawns(bool delete_all) { spellProcess->RemoveCaster(spawn, true); } - if(movementMgr != nullptr) { + if(spawn->IsEntity() && movementMgr != nullptr) { movementMgr->RemoveMob((Entity*)spawn); } @@ -1890,11 +1881,8 @@ bool ZoneServer::SpawnProcess(){ bool spawnRange = spawn_range.Check(); bool checkRemove = spawn_check_remove.Check(); bool aggroCheck = aggro_timer.Check(); - vector 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::iterator itr; if (spawnRange || checkRemove) { @@ -1960,40 +1948,16 @@ bool ZoneServer::SpawnProcess(){ 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__); } - // 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::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::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 - 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(); } @@ -2011,7 +1975,7 @@ bool ZoneServer::SpawnProcess(){ // Delete unused spawns, do this last - if(!zoneShuttingDown) + if(!zoneShuttingDown && deleteTimer) DeleteSpawns(false); // 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() && (!test_spawn->IsPlayer() || include_players)){ 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(); @@ -4832,10 +4796,6 @@ void ZoneServer::RemoveSpawn(Spawn* spawn, bool delete_spawn, bool respawn, bool 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) { LogWrite(ZONE__DEBUG, 3, "Zone", "Handle NPC Respawn for '%s'.", spawn->GetName()); AddRespawn(spawn); @@ -5131,7 +5091,7 @@ void ZoneServer::ProcessFaction(Spawn* spawn, Client* client) } void ZoneServer::Despawn(Spawn* spawn, int32 timer){ - if (spawn && movementMgr != nullptr) { + if (spawn && spawn->IsEntity() && movementMgr != nullptr) { movementMgr->RemoveMob((Entity*)spawn); } if(!spawn || spawn->IsPlayer()) @@ -5453,7 +5413,7 @@ void ZoneServer::KillSpawn(bool spawnListLocked, Spawn* dead, Spawn* killer, boo spellProcess->RemoveSpellFromQueue((Player*)dead, true); if (dead->IsNPC()) - ((NPC*)dead)->Brain()->ClearHate(!spawnListLocked); + ((NPC*)dead)->Brain()->ClearHate(spawnListLocked); safe_delete(encounter); @@ -9164,36 +9124,6 @@ Spawn* ZoneServer::GetSpawnFromUniqueItemID(int32 unique_id) 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::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::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) { if( spawn->GetSpawnGroupID() > 0 ) diff --git a/source/WorldServer/zoneserver.h b/source/WorldServer/zoneserver.h index bf739d7..f82fb1d 100644 --- a/source/WorldServer/zoneserver.h +++ b/source/WorldServer/zoneserver.h @@ -706,9 +706,6 @@ public: void SetWatchdogTime(int32 time) { watchdogTimestamp = time; } void CancelThreads(); - void AddPendingSpawnRemove(int32 id); - void ProcessSpawnRemovals(); - bool SendRemoveSpawn(Client* client, Spawn* spawn, PacketStruct* packet = 0, bool delete_spawn = false); void AddSpawnToGroup(Spawn* spawn, int32 group_id); @@ -924,6 +921,7 @@ private: Timer widget_timer; Timer queue_updates; Timer shutdownDelayTimer; + Timer delete_timer; /* Enums */ Instance_Type InstanceType; @@ -1029,9 +1027,6 @@ private: int32 watchdogTimestamp; - std::map m_pendingSpawnRemove; - Mutex MPendingSpawnRemoval; - std::map lua_queued_state_commands; std::map> lua_spawn_update_command; std::mutex MLuaQueueStateCmd;