1
0

Fix spells to properly cleanup in function SpellProcess::CheckRemoveTargetFromSpell -- RemoveEffectsFromLuaSpell was not properly cleaning up special effects like sneak/snare/root/so on lingered on to cause a crash with dead spells with /reload spells or other activity

This commit is contained in:
Emagi 2025-02-04 18:45:48 -05:00
parent 8dff68f6ab
commit 5d191927cf
3 changed files with 51 additions and 32 deletions

View File

@ -1954,10 +1954,10 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie
else {
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Reloading Spells & NPC Spell Lists (Note: Must Reload Spawns/Repop to reset npc spells)...");
world.SetReloadingSubsystem("Spells");
zone_list.DeleteSpellProcess();
if (lua_interface)
lua_interface->DestroySpells();
zone_list.DeleteSpellProcess();
master_spell_list.Reload();
zone_list.LoadSpellProcess();
world.RemoveReloadingSubSystem("Spells");

View File

@ -150,6 +150,22 @@ void LuaInterface::DestroySpells() {
for(inner_itr = spell_script_itr->second.begin(); inner_itr != spell_script_itr->second.end(); inner_itr++) {
LuaSpell* cur_spell = inner_itr->second;
MSpellDelete.lock();
ZoneServer* zone = nullptr;
if(cur_spell && cur_spell->zone) {
zone = cur_spell->zone;
cur_spell->MSpellTargets.readlock(__FUNCTION__, __LINE__);
for (int8 i = 0; i < cur_spell->targets.size(); i++) {
Spawn* target = cur_spell->zone->GetSpawnByID(cur_spell->targets.at(i));
if (!target || !target->IsEntity())
continue;
cur_spell->zone->RemoveTargetFromSpell(cur_spell, target);
}
cur_spell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
zone->GetSpellProcess()->CheckRemoveTargetFromSpell(cur_spell, false, true);
}
SetLuaUserDataStale(cur_spell);
RemoveCurrentSpell(inner_itr->first, inner_itr->second, false, true, false);
lua_close(inner_itr->first);
safe_delete(cur_spell);

View File

@ -62,6 +62,9 @@ void SpellProcess::RemoveCaster(Spawn* caster, bool lock_spell_process){
void SpellProcess::RemoveAllSpells(bool reload_spells){
ClearSpellScriptTimerList();
if(reload_spells) {
active_spells.clear();
}
MutexList<LuaSpell*>::iterator active_spells_itr = active_spells.begin();
while(active_spells_itr.Next()){
DeleteCasterSpell(active_spells_itr->value, "", true, 0, !reload_spells);
@ -69,11 +72,13 @@ void SpellProcess::RemoveAllSpells(bool reload_spells){
MSpellProcess.lock();
active_spells_itr = active_spells.begin();
while(active_spells_itr.Next()){
active_spells.Remove(active_spells_itr->value);
if(!reload_spells) {
active_spells_itr = active_spells.begin();
while(active_spells_itr.Next()){
active_spells.Remove(active_spells_itr->value);
}
active_spells.clear();
}
active_spells.clear();
InterruptStruct* interrupt = 0;
MutexList<InterruptStruct*>::iterator interrupt_list_itr = interrupt_list.begin();
@ -2820,6 +2825,7 @@ void SpellProcess::CheckRemoveTargetFromSpell(LuaSpell* spell, bool allow_delete
MRemoveTargetList.writelock(__FUNCTION__, __LINE__);
if (remove_target_list.size() > 0){
vector<Spawn*> spawnsToRemove;
map<LuaSpell*, vector<int32>*>::iterator remove_itr;
vector<int32>::iterator remove_target_itr;
vector<int32>::iterator target_itr;
@ -2828,6 +2834,7 @@ void SpellProcess::CheckRemoveTargetFromSpell(LuaSpell* spell, bool allow_delete
Spawn* remove_spawn = 0;
bool should_delete = false;
bool dropped_lock = false;
bool targets_empty = false;
for (remove_itr = remove_target_list.begin(); remove_itr != remove_target_list.end(); remove_itr++){
if (remove_itr->first == spell){
targets = &spell->targets;
@ -2835,10 +2842,7 @@ void SpellProcess::CheckRemoveTargetFromSpell(LuaSpell* spell, bool allow_delete
if (remove_targets && targets){
spell->MSpellTargets.writelock(__FUNCTION__, __LINE__);
for (remove_target_itr = remove_targets->begin(); remove_target_itr != remove_targets->end(); remove_target_itr++){
if(!spell->caster || !spell->caster->GetZone())
continue;
remove_spawn = spell->caster->GetZone()->GetSpawnByID((*remove_target_itr));
remove_spawn = spell->zone->GetSpawnByID((*remove_target_itr));
if (remove_spawn) {
bool found_target = false;
if(remove_spawn->IsPlayer())
@ -2856,32 +2860,18 @@ void SpellProcess::CheckRemoveTargetFromSpell(LuaSpell* spell, bool allow_delete
((Entity*)remove_spawn)->RemoveMaintainedSpell(spell);
LogWrite(SPELL__DEBUG, 0, "Spell", "%s CheckRemoveTargetFromSpell %s (%u).", spell->spell->GetName(), remove_spawn->GetName(), remove_spawn->GetID());
targets->erase(target_itr);
if (remove_spawn->IsEntity())
((Entity*)remove_spawn)->RemoveEffectsFromLuaSpell(spell);
if(remove_spawn && std::find(spawnsToRemove.begin(), spawnsToRemove.end(), remove_spawn) == spawnsToRemove.end())
spawnsToRemove.push_back(remove_spawn);
break;
}
}
if (targets->size() == 0 && spell->char_id_targets.size() == 0 && allow_delete) {
spell->MSpellTargets.releasewritelock(__FUNCTION__, __LINE__);
if(!dropped_lock) {
MRemoveTargetList.releasewritelock(__FUNCTION__, __LINE__);
}
if(found_target)
lua_interface->RemoveSpell(spell, true, false, !remove_spawn->Alive() ? "target_dead" : "target_removed", false, false, remove_spawn);
targets_empty = (targets->size() == 0 && spell->char_id_targets.size() == 0);
if (targets_empty && allow_delete) {
should_delete = true;
dropped_lock = true;
break;
}
else {
spell->MSpellTargets.releasewritelock(__FUNCTION__, __LINE__);
if(!dropped_lock) {
MRemoveTargetList.releasewritelock(__FUNCTION__, __LINE__);
}
// call remove function "on death"
if(found_target)
lua_interface->RemoveSpell(spell, true, false, !remove_spawn->Alive() ? "target_dead" : "target_removed", false, true, remove_spawn);
spell->MSpellTargets.writelock(__FUNCTION__, __LINE__);
dropped_lock = true;
else if(remove_spawn && std::find(spawnsToRemove.begin(), spawnsToRemove.end(), remove_spawn) == spawnsToRemove.end()) {
spawnsToRemove.push_back(remove_spawn);
}
}
}
@ -2891,10 +2881,23 @@ void SpellProcess::CheckRemoveTargetFromSpell(LuaSpell* spell, bool allow_delete
}
}
if(dropped_lock) {
MRemoveTargetList.writelock(__FUNCTION__, __LINE__);
MRemoveTargetList.releasewritelock(__FUNCTION__, __LINE__);
for(int s=0;s<spawnsToRemove.size();s++) {
Spawn* target = spawnsToRemove.at(s);
if(target) {
bool not_last_itr = (s != spawnsToRemove.size() - 1);
if(target->IsEntity())
((Entity*)target)->RemoveEffectsFromLuaSpell(spell);
if(targets_empty && allow_delete) {
lua_interface->RemoveSpell(spell, true, false, !target->Alive() ? "target_dead" : "target_removed", false, not_last_itr, target);
}
else
lua_interface->RemoveSpell(spell, true, false, !target->Alive() ? "target_dead" : "target_removed", false, true, target);
}
}
MRemoveTargetList.writelock(__FUNCTION__, __LINE__);
remove_target_list.erase(spell);
if (remove_targets)
remove_targets->clear();