Resolve Deadlock in MSpawnList against CombatProcess, barebones of disarm trap
Resolved deadlock in CombatProcess (dead_spawns). Fixes #31. Added base for issue #24
This commit is contained in:
parent
1149dc7f2a
commit
bd2658946f
12 changed files with 207 additions and 89 deletions
|
@ -1075,7 +1075,7 @@ void Entity::KillSpawn(Spawn* dead, int8 damage_type, int16 kill_blow_type) {
|
|||
// Kill movement for the dead npc so the corpse doesn't move
|
||||
dead->CalculateRunningLocation(true);
|
||||
|
||||
GetZone()->KillSpawn(dead, this, true, damage_type, kill_blow_type);
|
||||
GetZone()->KillSpawn(true, dead, this, true, damage_type, kill_blow_type);
|
||||
}
|
||||
|
||||
void Entity::ProcessCombat() {
|
||||
|
|
|
@ -1758,7 +1758,7 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie
|
|||
if(dead && dead->IsPlayer() == false){
|
||||
dead->SetHP(0);
|
||||
if(sep && sep->arg[0] && sep->IsNumber(0) && atoi(sep->arg[0]) == 1)
|
||||
client->GetCurrentZone()->RemoveSpawn(dead, true);
|
||||
client->GetCurrentZone()->RemoveSpawn(false, dead, true);
|
||||
else
|
||||
client->GetPlayer()->KillSpawn(dead);
|
||||
}else{
|
||||
|
@ -3327,7 +3327,7 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie
|
|||
delete_spawn = true;
|
||||
}
|
||||
if(delete_spawn)
|
||||
client->GetCurrentZone()->RemoveSpawn(spawn, true, false);
|
||||
client->GetCurrentZone()->RemoveSpawn(false, spawn, true, false);
|
||||
else
|
||||
spawn->SetSpawnLocationID(0);
|
||||
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Successfully removed spawn from zone");
|
||||
|
|
|
@ -48,6 +48,7 @@ Entity::Entity(){
|
|||
memset(&ranged_combat_data, 0, sizeof(CombatData));
|
||||
memset(&info_struct, 0, sizeof(InfoStruct));
|
||||
loot_coins = 0;
|
||||
trap_triggered = false;
|
||||
memset(&features, 0, sizeof(CharFeatures));
|
||||
memset(&equipment, 0, sizeof(EQ2_Equipment));
|
||||
pet = 0;
|
||||
|
@ -1196,7 +1197,7 @@ void Entity::DismissPet(NPC* pet, bool from_death) {
|
|||
|
||||
// remove the spawn from the world
|
||||
if (!from_death && pet->GetPetType() != PET_TYPE_CHARMED)
|
||||
GetZone()->RemoveSpawn(pet);
|
||||
GetZone()->RemoveSpawn(false, pet);
|
||||
}
|
||||
|
||||
float Entity::CalculateBonusMod() {
|
||||
|
|
|
@ -502,6 +502,12 @@ public:
|
|||
void AddLootCoins(int32 coins){
|
||||
loot_coins += coins;
|
||||
}
|
||||
bool HasTrapTriggered() {
|
||||
return trap_triggered;
|
||||
}
|
||||
void SetTrapTriggered(bool triggered) {
|
||||
trap_triggered = triggered;
|
||||
}
|
||||
void AddLootItem(int32 id, int16 charges = 1){
|
||||
Item* master_item = master_item_list.GetItem(id);
|
||||
if(master_item){
|
||||
|
@ -817,6 +823,7 @@ private:
|
|||
float max_speed;
|
||||
vector<Item*> loot_items;
|
||||
int32 loot_coins;
|
||||
bool trap_triggered;
|
||||
int8 deity;
|
||||
sint16 regen_hp_rate;
|
||||
sint16 regen_power_rate;
|
||||
|
|
|
@ -184,7 +184,7 @@ int EQ2Emu_lua_KillSpawn(lua_State* state) {
|
|||
Spawn* killer = lua_interface->GetSpawn(state, 2);
|
||||
bool send_packet = (lua_interface->GetInt8Value(state, 3) == 1);
|
||||
if(dead && dead->Alive() && dead->GetZone())
|
||||
dead->GetZone()->KillSpawn(dead, killer, send_packet);
|
||||
dead->GetZone()->KillSpawn(true, dead, killer, send_packet);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -3351,7 +3351,7 @@ int EQ2Emu_lua_Harvest(lua_State* state){
|
|||
|
||||
((GroundSpawn*)node)->ProcessHarvest(client);
|
||||
if(((GroundSpawn*)node)->GetNumberHarvests() == 0)
|
||||
player->GetZone()->RemoveSpawn(node, true);
|
||||
player->GetZone()->RemoveSpawn(false, node, true);
|
||||
}
|
||||
}
|
||||
else if(player && player->IsPlayer()){
|
||||
|
|
|
@ -481,3 +481,33 @@ void PlayerSkillList::RemoveSkillBonus(int32 spell_id) {
|
|||
safe_delete(sb);
|
||||
}
|
||||
}
|
||||
|
||||
int Skill::CheckDisarmSkill(int16 targetLevel, int8 chest_difficulty)
|
||||
{
|
||||
if (chest_difficulty < 2) // no triggers on this chest type
|
||||
return 1;
|
||||
|
||||
int chest_diff_result = targetLevel * chest_difficulty;
|
||||
float base_difficulty = 15.0f;
|
||||
float fail_threshold = 10.0f;
|
||||
|
||||
|
||||
float chance = ((100.0f - base_difficulty) * ((float)current_val / (float)chest_diff_result));
|
||||
|
||||
if (chance > (100.0f - base_difficulty))
|
||||
{
|
||||
chance = 100.0f - base_difficulty;
|
||||
}
|
||||
|
||||
float d100 = (float)MakeRandomFloat(0, 100);
|
||||
|
||||
if (d100 <= chance)
|
||||
return 1;
|
||||
else
|
||||
{
|
||||
if (d100 > (chance + fail_threshold))
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -72,6 +72,8 @@ public:
|
|||
EQ2_16BitString name;
|
||||
EQ2_16BitString description;
|
||||
bool save_needed;
|
||||
|
||||
int CheckDisarmSkill(int16 targetLevel, int8 chest_difficulty=0);
|
||||
};
|
||||
|
||||
class MasterSkillList{
|
||||
|
|
|
@ -191,7 +191,7 @@ int32 WorldDatabase::LoadCharacterSpells(int32 char_id, Player* player)
|
|||
|
||||
void WorldDatabase::SavePlayerSpells(Client* client)
|
||||
{
|
||||
if(!client)
|
||||
if(!client || client->GetCharacterID() < 1)
|
||||
return;
|
||||
|
||||
LogWrite(SPELL__DEBUG, 3, "Spells", "Saving Spell(s) for Player: '%s'", client->GetPlayer()->GetName());
|
||||
|
@ -3090,7 +3090,7 @@ bool WorldDatabase::SaveCombinedSpawnLocation(ZoneServer* zone, Spawn* in_spawn,
|
|||
}
|
||||
for(itr=spawns->begin();itr!=spawns->end();itr++){
|
||||
spawn = *itr;
|
||||
zone->RemoveSpawn(spawn);
|
||||
zone->RemoveSpawn(false, spawn);
|
||||
}
|
||||
safe_delete(spawns);
|
||||
}
|
||||
|
|
|
@ -586,7 +586,7 @@ void Client::HandlePlayerRevive(int32 point_id)
|
|||
safe_delete(packet);
|
||||
}
|
||||
|
||||
GetCurrentZone()->RemoveSpawn(player, false);
|
||||
GetCurrentZone()->RemoveSpawn(false, player, false);
|
||||
|
||||
m_resurrect.writelock(__FUNCTION__, __LINE__);
|
||||
if(current_rez.active)
|
||||
|
@ -1299,7 +1299,7 @@ bool Client::HandlePacket(EQApplicationPacket *app) {
|
|||
GetPlayer()->SetCharSheetChanged(true);
|
||||
GetCurrentZone()->SendDamagePacket(0, GetPlayer(), DAMAGE_PACKET_TYPE_SIMPLE_DAMAGE, GetPlayer()->GetInvulnerable() ? DAMAGE_PACKET_RESULT_INVULNERABLE : DAMAGE_PACKET_RESULT_SUCCESSFUL, DAMAGE_PACKET_DAMAGE_TYPE_FALLING, damage, 0);
|
||||
if(GetPlayer()->GetHP() == 0) {
|
||||
GetCurrentZone()->KillSpawn(GetPlayer(), 0);
|
||||
GetCurrentZone()->KillSpawn(false, GetPlayer(), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2724,7 +2724,7 @@ void ClientList::Remove(Client* client, bool remove_data) {
|
|||
void Client::SetCurrentZone(int32 id){
|
||||
if(current_zone){
|
||||
//current_zone->GetCombat()->RemoveHate(player);
|
||||
current_zone->RemoveSpawn(player, false);
|
||||
current_zone->RemoveSpawn(false, player, false);
|
||||
}
|
||||
SetCurrentZone(zone_list.Get(id));
|
||||
|
||||
|
@ -2733,7 +2733,7 @@ void Client::SetCurrentZone(int32 id){
|
|||
void Client::SetCurrentZoneByInstanceID(int32 id,int32 zoneid){
|
||||
if(current_zone){
|
||||
//current_zone->GetCombat()->RemoveHate(player);
|
||||
current_zone->RemoveSpawn(player, false);
|
||||
current_zone->RemoveSpawn(false, player, false);
|
||||
}
|
||||
SetCurrentZone(zone_list.GetByInstanceID(id,zoneid));
|
||||
|
||||
|
@ -3181,7 +3181,7 @@ void Client::Zone(ZoneServer* new_zone, bool set_coords){
|
|||
|
||||
|
||||
LogWrite(CCLIENT__DEBUG, 0, "Client", "%s: Removing player from current zone...", __FUNCTION__);
|
||||
GetCurrentZone()->RemoveSpawn(player, false);
|
||||
GetCurrentZone()->RemoveSpawn(false, player, false);
|
||||
|
||||
LogWrite(CCLIENT__DEBUG, 0, "Client", "%s: Setting zone to '%s'...", __FUNCTION__, new_zone->GetZoneName());
|
||||
SetCurrentZone(new_zone);
|
||||
|
@ -3952,7 +3952,7 @@ void Client::Loot(int32 total_coins, vector<Item*>* items, Entity* entity){
|
|||
memcpy(data, &packet_size, sizeof(int32));
|
||||
packet_size += sizeof(int32);
|
||||
EQ2Packet* outapp = new EQ2Packet(OP_ClientCmdMsg, data, packet_size);
|
||||
//DumpPacket(outapp);
|
||||
//DumpPacket(outapp);
|
||||
QueuePacket(outapp);
|
||||
safe_delete_array(data);
|
||||
safe_delete(packet);
|
||||
|
@ -3967,36 +3967,87 @@ void Client::Loot(Entity* entity){
|
|||
Loot(total_coins, entity->GetLootItems(), entity);
|
||||
entity->UnlockLoot();
|
||||
|
||||
int32 state = 0;
|
||||
// Check for the chest and set the action state
|
||||
/*4034 = small chest | 5864 = treasure chest | 5865 = ornate treasure chest | 4015 = exquisite chest*/
|
||||
if (entity->GetModelType() == 4034) {
|
||||
// small chest, open with copper coins
|
||||
state = 11899;
|
||||
}
|
||||
else if (entity->GetModelType() == 5864) {
|
||||
// treasure chest, open with silver coins
|
||||
state = 11901;
|
||||
}
|
||||
else if (entity->GetModelType() == 5865) {
|
||||
// ornate chest, open with gold coins
|
||||
state = 11900;
|
||||
}
|
||||
else if (entity->GetModelType() == 4015) {
|
||||
// exquisite chest, open with gold coins and jewels as well as a glow effect
|
||||
state = 11898;
|
||||
}
|
||||
|
||||
// We set the visual state with out updating so those not in range will see it opened when it is finally sent to them,
|
||||
// for those in range the SendStateCommand will cause it to animate open.
|
||||
entity->SetVisualState(state, false);
|
||||
GetCurrentZone()->SendStateCommand(entity, state);
|
||||
OpenChest(entity);
|
||||
}
|
||||
else
|
||||
SimpleMessage(CHANNEL_COLOR_YELLOW, "You are not allowed to loot at this time.");
|
||||
|
||||
}
|
||||
|
||||
void Client::OpenChest(Entity* entity)
|
||||
{
|
||||
if (!entity)
|
||||
return;
|
||||
|
||||
int8 chest_difficulty = 0;
|
||||
int32 state = 0;
|
||||
// Check for the chest and set the action state
|
||||
/*4034 = small chest | 5864 = treasure chest | 5865 = ornate treasure chest | 4015 = exquisite chest*/
|
||||
if (entity->GetModelType() == 4034) {
|
||||
// small chest, open with copper coins
|
||||
// does not include traps, however can be disarmed
|
||||
chest_difficulty = 1;
|
||||
state = 11899;
|
||||
}
|
||||
else if (entity->GetModelType() == 5864) {
|
||||
// treasure chest, open with silver coins
|
||||
chest_difficulty = 2;
|
||||
state = 11901;
|
||||
}
|
||||
else if (entity->GetModelType() == 5865) {
|
||||
// ornate chest, open with gold coins
|
||||
chest_difficulty = 3;
|
||||
state = 11900;
|
||||
}
|
||||
else if (entity->GetModelType() == 4015) {
|
||||
// exquisite chest, open with gold coins and jewels as well as a glow effect
|
||||
chest_difficulty = 5;
|
||||
state = 11898;
|
||||
}
|
||||
boolean firstChestOpen = false;
|
||||
|
||||
if (chest_difficulty > 0 && !entity->HasTrapTriggered())
|
||||
{
|
||||
Skill* disarmSkill = GetPlayer()->GetSkillByName("Disarm Trap", false);
|
||||
firstChestOpen = true;
|
||||
entity->SetTrapTriggered(true);
|
||||
if (disarmSkill)
|
||||
{
|
||||
if (disarmSkill->CheckDisarmSkill(entity->GetLevel(), chest_difficulty) < 1)
|
||||
{
|
||||
//Spell* spell = master_spell_list.GetSpell(spellid, tier);
|
||||
|
||||
//GetPlayer()->GetZone()->GetSpellProcess()->CastInstant(spell, (Entity*)GetPlayer(), (Entity*)GetPlayer());
|
||||
|
||||
SimpleMessage(CHANNEL_COLOR_YELLOW, "You failed to disarm the chest.");
|
||||
}
|
||||
else
|
||||
{
|
||||
SimpleMessage(CHANNEL_COLOR_YELLOW, "You have disarmed the chest.");
|
||||
GetPlayer()->GetSkillByName("Disarm Trap", true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SimpleMessage(CHANNEL_COLOR_YELLOW, "You triggered the chest.");
|
||||
}
|
||||
}
|
||||
else if(!entity->HasTrapTriggered())
|
||||
{
|
||||
firstChestOpen = true;
|
||||
entity->SetTrapTriggered(true);
|
||||
}
|
||||
|
||||
// We set the visual state with out updating so those not in range will see it opened when it is finally sent to them,
|
||||
// for those in range the SendStateCommand will cause it to animate open.
|
||||
|
||||
// TODO: when player enters radius that does not have visual state, update visual state
|
||||
if (firstChestOpen)
|
||||
entity->SetVisualState(state, false);
|
||||
|
||||
GetCurrentZone()->SendStateCommand(entity, state);
|
||||
}
|
||||
|
||||
Spawn* Client::GetBanker(){
|
||||
return banker;
|
||||
}
|
||||
|
@ -5006,7 +5057,7 @@ void Client::SaveCombineSpawns(const char* name){
|
|||
SimpleMessage(CHANNEL_COLOR_YELLOW, "Error: You only have a single Spawn in the group!");
|
||||
else if(database.SaveCombinedSpawnLocation(GetCurrentZone(), combine_spawn, name)){
|
||||
Message(CHANNEL_COLOR_YELLOW, "Successfully combined %u spawns into spawn location: %u", count, combine_spawn->GetSpawnLocationID());
|
||||
GetCurrentZone()->RemoveSpawn(combine_spawn);
|
||||
GetCurrentZone()->RemoveSpawn(false, combine_spawn);
|
||||
}
|
||||
else
|
||||
SimpleMessage(CHANNEL_COLOR_YELLOW, "Error saving spawn group, check console for details.");
|
||||
|
|
|
@ -244,6 +244,7 @@ public:
|
|||
void SendPendingLoot(int32 total_coins, Entity* entity);
|
||||
void Loot(int32 total_coins, vector<Item*>* items, Entity* entity);
|
||||
void Loot(Entity* entity);
|
||||
void OpenChest(Entity* entity);
|
||||
void CheckPlayerQuestsKillUpdate(Spawn* spawn);
|
||||
void CheckPlayerQuestsChatUpdate(Spawn* spawn);
|
||||
void CheckPlayerQuestsItemUpdate(Item* item);
|
||||
|
|
|
@ -1202,9 +1202,9 @@ void ZoneServer::DelayedSpawnRemoval(bool force_delete_all) {
|
|||
}
|
||||
|
||||
if (spawn->IsPlayer())
|
||||
RemoveSpawn(spawn, false);
|
||||
RemoveSpawn(false, spawn, false);
|
||||
else
|
||||
RemoveSpawn(spawn);
|
||||
RemoveSpawn(false, spawn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1614,7 +1614,7 @@ void ZoneServer::CheckDeadSpawnRemoval() {
|
|||
if (!spawn->IsPlayer())
|
||||
{
|
||||
dead_spawns.erase(spawn->GetID());
|
||||
RemoveSpawn(spawn, true, true, false);
|
||||
RemoveSpawn(true, spawn, true, true, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1831,7 +1831,7 @@ void ZoneServer::ProcessDrowning(){
|
|||
vector<Client*>::iterator itr;
|
||||
for(itr = dead_list.begin(); itr != dead_list.end(); itr++){
|
||||
RemoveDrowningVictim((*itr)->GetPlayer());
|
||||
KillSpawn((*itr)->GetPlayer(), 0);
|
||||
KillSpawn(false, (*itr)->GetPlayer(), 0);
|
||||
(*itr)->SimpleMessage(CHANNEL_COLOR_WHITE, "You are sleeping with the fishes! Glug, glug...");
|
||||
}
|
||||
}
|
||||
|
@ -2863,7 +2863,7 @@ void ZoneServer::RemoveClient(Client* client)
|
|||
client->GetPlayer()->DismissPet((NPC*)client->GetPlayer()->GetDeityPet());
|
||||
client->GetPlayer()->DismissPet((NPC*)client->GetPlayer()->GetCosmeticPet());
|
||||
|
||||
RemoveSpawn(client->GetPlayer(), false);
|
||||
RemoveSpawn(false, client->GetPlayer(), false);
|
||||
connected_clients.Remove(client, true, DisconnectClientTimer);
|
||||
//}
|
||||
}
|
||||
|
@ -3644,7 +3644,7 @@ void ZoneServer::KillSpawnByDistance(Spawn* spawn, float max_distance, bool incl
|
|||
test_spawn = itr->second;
|
||||
if(test_spawn && test_spawn->IsEntity() && test_spawn != spawn && (!test_spawn->IsPlayer() || include_players)){
|
||||
if(test_spawn->GetDistance(spawn) < max_distance)
|
||||
KillSpawn(test_spawn, spawn, send_packet);
|
||||
KillSpawn(true, test_spawn, spawn, send_packet);
|
||||
}
|
||||
}
|
||||
MSpawnList.releasereadlock(__FUNCTION__, __LINE__);
|
||||
|
@ -3681,7 +3681,7 @@ void ZoneServer::RemoveFromRangeMap(Client* client){
|
|||
}
|
||||
*/
|
||||
|
||||
void ZoneServer::RemoveSpawn(Spawn* spawn, bool delete_spawn, bool respawn, bool lock)
|
||||
void ZoneServer::RemoveSpawn(bool spawnListLocked, Spawn* spawn, bool delete_spawn, bool respawn, bool lock)
|
||||
{
|
||||
LogWrite(ZONE__DEBUG, 3, "Zone", "Processing RemoveSpawn function...");
|
||||
|
||||
|
@ -3690,18 +3690,74 @@ void ZoneServer::RemoveSpawn(Spawn* spawn, bool delete_spawn, bool respawn, bool
|
|||
}
|
||||
|
||||
RemoveSpawnSupportFunctions(spawn);
|
||||
RemoveDeadEnemyList(spawn);
|
||||
if (reloading)
|
||||
RemoveDeadEnemyList(spawn);
|
||||
|
||||
LogWrite(ZONE__DEBUG, 7, "Zone", "Lock DeadSpawns...");
|
||||
|
||||
if (lock)
|
||||
MDeadSpawns.writelock(__FUNCTION__, __LINE__);
|
||||
|
||||
LogWrite(ZONE__DEBUG, 7, "Zone", "Erase DeadSpawns...");
|
||||
if (dead_spawns.count(spawn->GetID()) > 0)
|
||||
dead_spawns.erase(spawn->GetID());
|
||||
if (lock)
|
||||
MDeadSpawns.releasewritelock(__FUNCTION__, __LINE__);;
|
||||
MDeadSpawns.releasewritelock(__FUNCTION__, __LINE__);
|
||||
|
||||
LogWrite(ZONE__DEBUG, 7, "Zone", "End DeadSpawns...");
|
||||
|
||||
|
||||
LogWrite(ZONE__DEBUG, 7, "Zone", "SpawnExpireTimers...");
|
||||
if (spawn_expire_timers.count(spawn->GetID()) > 0)
|
||||
spawn_expire_timers.erase(spawn->GetID());
|
||||
LogWrite(ZONE__DEBUG, 7, "Zone", "SpawnExpireTimers Done...");
|
||||
|
||||
RemoveDelayedSpawnRemove(spawn);
|
||||
LogWrite(ZONE__DEBUG, 7, "Zone", "RemoveDelayedSpawnRemove Done...");
|
||||
|
||||
// Clear the pointer in the spawn list, spawn thread will remove the key
|
||||
if (!spawnListLocked)
|
||||
MSpawnList.writelock(__FUNCTION__, __LINE__);
|
||||
|
||||
LogWrite(ZONE__DEBUG, 7, "Zone", "RemoveSpawnList Start...");
|
||||
spawn_list[spawn->GetID()] = 0;
|
||||
|
||||
if (!spawnListLocked)
|
||||
MSpawnList.releasewritelock(__FUNCTION__, __LINE__);
|
||||
LogWrite(ZONE__DEBUG, 7, "Zone", "RemoveSpawnList Done...");
|
||||
|
||||
PacketStruct* packet = 0;
|
||||
int16 packet_version = 0;
|
||||
Client* client = 0;
|
||||
|
||||
vector<Client*>::iterator client_itr;
|
||||
|
||||
LogWrite(ZONE__DEBUG, 7, "Zone", "ClientList Start...");
|
||||
MClientList.readlock(__FUNCTION__, __LINE__);
|
||||
for (client_itr = clients.begin(); client_itr != clients.end(); client_itr++) {
|
||||
client = *client_itr;
|
||||
|
||||
if (client) {
|
||||
if (client->IsConnected() && (!packet || packet_version != client->GetVersion()))
|
||||
{
|
||||
safe_delete(packet);
|
||||
packet_version = client->GetVersion();
|
||||
packet = configReader.getStruct("WS_DestroyGhostCmd", packet_version);
|
||||
}
|
||||
|
||||
if (client->GetPlayer()->HasTarget() && client->GetPlayer()->GetTarget() == spawn)
|
||||
client->GetPlayer()->SetTarget(0);
|
||||
|
||||
SendRemoveSpawn(client, spawn, packet, delete_spawn);
|
||||
if (spawn_range_map.count(client) > 0)
|
||||
spawn_range_map.Get(client)->erase(spawn->GetID());
|
||||
}
|
||||
}
|
||||
MClientList.releasereadlock(__FUNCTION__, __LINE__);
|
||||
|
||||
LogWrite(ZONE__DEBUG, 7, "Zone", "ClientList End...");
|
||||
|
||||
safe_delete(packet);
|
||||
|
||||
if(respawn && !spawn->IsPlayer() && spawn->GetRespawnTime() > 0 && spawn->GetSpawnLocationID() > 0)
|
||||
{
|
||||
|
@ -3725,50 +3781,20 @@ void ZoneServer::RemoveSpawn(Spawn* spawn, bool delete_spawn, bool respawn, bool
|
|||
}
|
||||
}
|
||||
else
|
||||
respawn_timers.Put(spawn->GetSpawnLocationID(), Timer::GetCurrentTime2() + spawn->GetRespawnTime()*1000);
|
||||
}
|
||||
|
||||
PacketStruct* packet = 0;
|
||||
int16 packet_version = 0;
|
||||
Client* client = 0;
|
||||
|
||||
// Clear the pointer in the spawn list, spawn thread will remove the key
|
||||
MSpawnList.writelock(__FUNCTION__, __LINE__);
|
||||
spawn_list.erase(spawn->GetID());
|
||||
MSpawnList.releasewritelock(__FUNCTION__, __LINE__);
|
||||
|
||||
vector<Client*>::iterator client_itr;
|
||||
|
||||
MClientList.readlock(__FUNCTION__, __LINE__);
|
||||
for (client_itr = clients.begin(); client_itr != clients.end(); client_itr++) {
|
||||
client = *client_itr;
|
||||
|
||||
if (client) {
|
||||
if(client->IsConnected() && (!packet || packet_version != client->GetVersion()))
|
||||
{
|
||||
safe_delete(packet);
|
||||
packet_version = client->GetVersion();
|
||||
packet = configReader.getStruct("WS_DestroyGhostCmd", packet_version);
|
||||
}
|
||||
|
||||
if(client->GetPlayer()->HasTarget() && client->GetPlayer()->GetTarget() == spawn)
|
||||
client->GetPlayer()->SetTarget(0);
|
||||
|
||||
SendRemoveSpawn(client, spawn, packet, delete_spawn);
|
||||
if(spawn_range_map.count(client) > 0)
|
||||
spawn_range_map.Get(client)->erase(spawn->GetID());
|
||||
{
|
||||
int32 spawnLocationID = spawn->GetSpawnLocationID();
|
||||
int32 spawnRespawnTime = spawn->GetRespawnTime();
|
||||
safe_delete(spawn);
|
||||
respawn_timers.Put(spawnLocationID, Timer::GetCurrentTime2() + spawnRespawnTime * 1000);
|
||||
}
|
||||
}
|
||||
MClientList.releasereadlock(__FUNCTION__, __LINE__);
|
||||
|
||||
safe_delete(packet);
|
||||
|
||||
// Do we really need the mutex locks and check to dead_spawns as we remove it from dead spawns at the start of this function
|
||||
if (lock)
|
||||
if (lock && !respawn)
|
||||
MDeadSpawns.readlock(__FUNCTION__, __LINE__);
|
||||
if(delete_spawn && dead_spawns.count(spawn->GetID()) == 0)
|
||||
if(!respawn && delete_spawn && dead_spawns.count(spawn->GetID()) == 0)
|
||||
AddPendingDelete(spawn);
|
||||
if (lock)
|
||||
if (lock && !respawn)
|
||||
MDeadSpawns.releasereadlock(__FUNCTION__, __LINE__);
|
||||
|
||||
LogWrite(ZONE__DEBUG, 3, "Zone", "Done processing RemoveSpawn function...");
|
||||
|
@ -4017,7 +4043,7 @@ void ZoneServer::Despawn(Spawn* spawn, int32 timer){
|
|||
AddDeadSpawn(spawn, timer);
|
||||
}
|
||||
|
||||
void ZoneServer::KillSpawn(Spawn* dead, Spawn* killer, bool send_packet, int8 damage_type, int16 kill_blow_type)
|
||||
void ZoneServer::KillSpawn(bool spawnListLocked, Spawn* dead, Spawn* killer, bool send_packet, int8 damage_type, int16 kill_blow_type)
|
||||
{
|
||||
MDeadSpawns.readlock(__FUNCTION__, __LINE__);
|
||||
if(!dead || this->dead_spawns.count(dead->GetID()) > 0) {
|
||||
|
|
|
@ -267,7 +267,7 @@ public:
|
|||
|
||||
void AddSpawnGroupChance(int32 group_id, float percent);
|
||||
|
||||
void RemoveSpawn(Spawn* spawn, bool delete_spawn = true, bool respawn = true, bool lock = true);
|
||||
void RemoveSpawn(bool spawnListLocked, Spawn* spawn, bool delete_spawn = true, bool respawn = true, bool lock = true);
|
||||
void ProcessSpawnLocations();
|
||||
void SendQuestUpdates(Client* client, Spawn* spawn = 0);
|
||||
|
||||
|
@ -295,7 +295,7 @@ public:
|
|||
|
||||
vector<Entity*> GetPlayers();
|
||||
|
||||
void KillSpawn(Spawn* dead, Spawn* killer, bool send_packet = true, int8 damage_type = 0, int16 kill_blow_type = 0);
|
||||
void KillSpawn(bool spawnListLocked, Spawn* dead, Spawn* killer, bool send_packet = true, int8 damage_type = 0, int16 kill_blow_type = 0);
|
||||
|
||||
void SendDamagePacket(Spawn* attacker, Spawn* victim, int8 type1, int8 type2, int8 damage_type, int16 damage, const char* spell_name);
|
||||
void SendHealPacket(Spawn* caster, Spawn* target, int16 type, int32 heal_amt, const char* spell_name);
|
||||
|
|
Loading…
Reference in a new issue