From 14003ee3a47bffc59feb59975dd3947ee48581d8 Mon Sep 17 00:00:00 2001 From: Emagi Date: Wed, 4 Sep 2024 06:44:04 -0400 Subject: [PATCH] LUA Spell Scripts updated to have a queue much like SpawnScripts, but extended to LuaSpell for tracking procs and lifetime of the lua state Need to avoid crashes/overrun of the lua stack. --- source/WorldServer/Combat.cpp | 34 +++- source/WorldServer/LuaFunctions.cpp | 1 - source/WorldServer/LuaInterface.cpp | 258 ++++++++++++++++----------- source/WorldServer/LuaInterface.h | 14 +- source/WorldServer/SpellProcess.cpp | 12 +- source/WorldServer/WorldDatabase.cpp | 3 +- source/WorldServer/client.cpp | 2 +- 7 files changed, 200 insertions(+), 124 deletions(-) diff --git a/source/WorldServer/Combat.cpp b/source/WorldServer/Combat.cpp index b2d3cd4..dc8210c 100644 --- a/source/WorldServer/Combat.cpp +++ b/source/WorldServer/Combat.cpp @@ -1662,7 +1662,12 @@ void Entity::AddProc(int8 type, float chance, Item* item, LuaSpell* spell, int8 proc->chance = chance; proc->item = item; proc->spell = spell; - proc->spellid = spell->spell->GetSpellID(); + if(spell) { + spell->has_proc = true; + } + if(spell && spell->spell) { + proc->spellid = spell->spell->GetSpellID(); + } proc->health_ratio = hp_ratio; proc->below_health = below_health; proc->damage_type = damage_type; @@ -1701,12 +1706,12 @@ bool Entity::CastProc(Proc* proc, int8 type, Spawn* target) { lua_State* state = 0; bool item_proc = false; int8 num_args = 3; - + Mutex* mutex = 0; if (proc->spell) { state = proc->spell->state; } else if (proc->item) { - state = lua_interface->GetItemScript(proc->item->GetItemScript()); + state = lua_interface->GetItemScript(proc->item->GetItemScript(), true, true); item_proc = true; } @@ -1714,6 +1719,13 @@ bool Entity::CastProc(Proc* proc, int8 type, Spawn* target) { LogWrite(COMBAT__ERROR, 0, "Proc", "No valid lua_State* found"); return false; } + + if(item_proc) { + mutex = lua_interface->GetItemScriptMutex(proc->item->GetItemScript()); + } + + if(mutex) + mutex->readlock(__FUNCTION__, __LINE__); if(proc->extended_version) { lua_getglobal(state, "proc_ext"); @@ -1721,7 +1733,7 @@ bool Entity::CastProc(Proc* proc, int8 type, Spawn* target) { else { lua_getglobal(state, "proc"); } - if (lua_isfunction(state, -1)) { + if (lua_isfunction(state, lua_gettop(state))) { if (item_proc) { num_args++; lua_interface->SetItemValue(state, proc->item); @@ -1730,7 +1742,10 @@ bool Entity::CastProc(Proc* proc, int8 type, Spawn* target) { lua_interface->SetSpawnValue(state, this); lua_interface->SetSpawnValue(state, target); lua_interface->SetInt32Value(state, type); - lua_interface->SetInt32Value(state, proc->damage_type); + + if(proc->extended_version) { + lua_interface->SetInt32Value(state, proc->damage_type); + } /* Add spell data from db in case of a spell proc here... @@ -1768,12 +1783,19 @@ bool Entity::CastProc(Proc* proc, int8 type, Spawn* target) { if (lua_pcall(state, num_args, 0, 0) != 0) { LogWrite(COMBAT__ERROR, 0, "Proc", "Unable to call the proc function for spell %i tier %i", proc->spell->spell->GetSpellID(), proc->spell->spell->GetSpellTier()); lua_pop(state, 1); + if(mutex) + mutex->releasereadlock(__FUNCTION__, __LINE__); + if(item_proc) + lua_interface->UseItemScript(proc->item->GetItemScript(), state, false); return false; } } lua_interface->ResetFunctionStack(state); - + if(mutex) + mutex->releasereadlock(__FUNCTION__); + if(item_proc) + lua_interface->UseItemScript(proc->item->GetItemScript(), state, false); return true; } diff --git a/source/WorldServer/LuaFunctions.cpp b/source/WorldServer/LuaFunctions.cpp index 82fe63d..559418f 100644 --- a/source/WorldServer/LuaFunctions.cpp +++ b/source/WorldServer/LuaFunctions.cpp @@ -12248,7 +12248,6 @@ int EQ2Emu_lua_GetSpell(lua_State* state) { if((lua_spell = lua_interface->GetSpell(custom_lua_script.c_str())) == nullptr) { LogWrite(LUA__WARNING, 0, "LUA", "GetSpell(%u, %u, '%s'), custom lua script not loaded, attempting to load.", spell_id, spell_tier, custom_lua_script.c_str()); - lua_interface->LoadLuaSpell(custom_lua_script); } } else diff --git a/source/WorldServer/LuaInterface.cpp b/source/WorldServer/LuaInterface.cpp index 9e52249..e61fdbf 100644 --- a/source/WorldServer/LuaInterface.cpp +++ b/source/WorldServer/LuaInterface.cpp @@ -147,11 +147,12 @@ void LuaInterface::DestroySpells() { MSpells.lock(); for(itr = spells.begin(); itr != spells.end(); itr++){ MSpellDelete.lock(); - RemoveCurrentSpell(itr->second->state, false); + RemoveCurrentSpell(itr->second->state, itr->second, false); MSpellDelete.unlock(); lua_close(itr->second->state); safe_delete(itr->second); } + spell_scripts.clear(); spells.clear(); MSpells.unlock(); } @@ -256,61 +257,6 @@ void LuaInterface::ReloadSpells() { database.LoadSpellScriptData(); } -bool LuaInterface::LoadLuaSpell(const char* name) { - LuaSpell* spell = 0; - string lua_script = string(name); - if (lua_script.find(".lua") == string::npos) - lua_script.append(".lua"); - lua_State* state = LoadLuaFile(lua_script.c_str()); - if(state){ - spell = new LuaSpell; - spell->file_name = lua_script; - spell->state = state; - spell->spell = 0; - spell->caster = 0; - spell->initial_target = 0; - spell->resisted = false; - spell->has_damaged = false; - spell->is_damage_spell = false; - spell->interrupted = false; - spell->last_spellattack_hit = false; - spell->crit = false; - spell->MSpellTargets.SetName("LuaSpell.MSpellTargets"); - spell->cancel_after_all_triggers = false; - spell->num_triggers = 0; - spell->num_calls = 0; - spell->is_recast_timer = false; - spell->had_triggers = false; - spell->had_dmg_remaining = false; - spell->slot_pos = 0; - spell->damage_remaining = 0; - spell->effect_bitmask = 0; - spell->restored = false; - spell->initial_caster_char_id = 0; - spell->initial_target_char_id = 0; - - MSpells.lock(); - if (spells.count(lua_script) > 0) { - - SetLuaUserDataStale(spells[lua_script]); - MSpellDelete.lock(); - RemoveCurrentSpell(spells[lua_script]->state, false); - MSpellDelete.unlock(); - lua_close(spells[lua_script]->state); - safe_delete(spells[lua_script]); - } - spells[lua_script] = spell; - MSpells.unlock(); - - return true; - } - return false; -} - -bool LuaInterface::LoadLuaSpell(string name) { - return LoadLuaSpell(name.c_str()); -} - bool LuaInterface::LoadItemScript(string name) { return LoadItemScript(name.c_str()); } @@ -555,6 +501,10 @@ bool LuaInterface::LoadRegionScript(string name) { return LoadRegionScript(name.c_str()); } +LuaSpell* LuaInterface::LoadSpellScript(string name) { + return LoadSpellScript(name.c_str()); +} + std::string LuaInterface::AddSpawnPointers(LuaSpell* spell, bool first_cast, bool precast, const char* function, SpellScriptTimer* timer, bool passLuaSpell, Spawn* altTarget) { std::string functionCalled = string(""); if (function) @@ -580,7 +530,7 @@ std::string LuaInterface::AddSpawnPointers(LuaSpell* spell, bool first_cast, boo LogWrite(SPELL__DEBUG, 0, "Spell", "LuaInterface::AddSpawnPointers spell %s (%u) function %s, caster %s.", spell->spell ? spell->spell->GetName() : "UnknownUnset", spell->spell ? spell->spell->GetSpellID() : 0, functionCalled.c_str(), spell->caster ? spell->caster->GetName() : "Unknown"); - if (!lua_isfunction(spell->state, -1)){ + if (!lua_isfunction(spell->state, lua_gettop(spell->state))){ lua_pop(spell->state, 1); return string(""); } @@ -647,13 +597,28 @@ LuaSpell* LuaInterface::GetCurrentSpell(lua_State* state, bool needsLock) { return spell; } -void LuaInterface::RemoveCurrentSpell(lua_State* state, bool needsLock) { +void LuaInterface::RemoveCurrentSpell(lua_State* state, LuaSpell* cur_spell, bool needsLock, bool removeCurSpell) { if(needsLock) { MSpells.lock(); MSpellDelete.lock(); } map::iterator itr = current_spells.find(state); - if(itr != current_spells.end()) + if(itr->second) { + MSpellScripts.readlock(__FUNCTION__, __LINE__); + map >::iterator spell_script_itr = spell_scripts.find(cur_spell->file_name); + if(spell_script_itr != spell_scripts.end()) { + LogWrite(SPELL__DEBUG, 9, "Spell", "LuaInterface::RemoveCurrentSpell spell %s. Queue Entries %u.", cur_spell->file_name.c_str(), spell_script_itr->second.size()); + Mutex* mutex = GetSpellScriptMutex(cur_spell->file_name.c_str()); + mutex->writelock(__FUNCTION__, __LINE__); + map::iterator spell_script_itr2 = spell_script_itr->second.find(state); + if(spell_script_itr2 != spell_script_itr->second.end()) { + spell_script_itr2->second = nullptr; + } + mutex->releasewritelock(__FUNCTION__, __LINE__); + } + MSpellScripts.releasereadlock(__FUNCTION__, __LINE__); + } + if(itr != current_spells.end() && removeCurSpell) current_spells.erase(itr); if(needsLock) { MSpellDelete.unlock(); @@ -664,10 +629,6 @@ void LuaInterface::RemoveCurrentSpell(lua_State* state, bool needsLock) { bool LuaInterface::CallSpellProcess(LuaSpell* spell, int8 num_parameters, std::string customFunction) { if(shutting_down || !spell || !spell->caster) return false; - - MSpells.lock(); - current_spells[spell->state] = spell; - MSpells.unlock(); LogWrite(SPELL__DEBUG, 0, "Spell", "LuaInterface::CallSpellProcess spell %s (%u) function %s, caster %s.", spell->spell ? spell->spell->GetName() : "UnknownUnset", spell->spell ? spell->spell->GetSpellID() : 0, customFunction.c_str(), spell->caster->GetName()); @@ -861,7 +822,7 @@ lua_State* LuaInterface::LoadLuaFile(const char* name) { void LuaInterface::RemoveSpell(LuaSpell* spell, bool call_remove_function, bool can_delete, string reason, bool removing_all_spells) { if(call_remove_function){ lua_getglobal(spell->state, "remove"); - if (!lua_isfunction(spell->state, -1)){ + if (!lua_isfunction(spell->state, lua_gettop(spell->state))){ lua_pop(spell->state, 1); } else { @@ -889,10 +850,6 @@ void LuaInterface::RemoveSpell(LuaSpell* spell, bool call_remove_function, bool reason = "dead"; lua_pushstring(spell->state, (char*)reason.c_str()); - - MSpells.lock(); - current_spells[spell->state] = spell; - MSpells.unlock(); lua_pcall(spell->state, 3, 0, 0); ResetFunctionStack(spell->state); @@ -1672,7 +1629,7 @@ void LuaInterface::DeletePendingSpells(bool all) { } SetLuaUserDataStale(spell); - RemoveCurrentSpell(spell->state, false); + RemoveCurrentSpell(spell->state, spell, false); safe_delete(spell); } } @@ -2056,47 +2013,49 @@ void LuaInterface::SetSpellValue(lua_State* state, LuaSpell* spell) { lua_pushlightuserdata(state, spell_wrapper); } -LuaSpell* LuaInterface::GetSpell(const char* name) { +LuaSpell* LuaInterface::LoadSpellScript(const char* name) { + LuaSpell* spell = nullptr; string lua_script = string(name); if (lua_script.find(".lua") == string::npos) lua_script.append(".lua"); - if(spells.count(lua_script) > 0) - { - LogWrite(LUA__DEBUG, 0, "LUA", "Found LUA Spell Script: '%s'", lua_script.c_str()); - LuaSpell* spell = spells[lua_script]; - LuaSpell* new_spell = new LuaSpell; - new_spell->state = spell->state; - new_spell->file_name = string(spell->file_name); - new_spell->timer = spell->timer; - new_spell->timer.Disable(); - new_spell->resisted = false; - new_spell->is_damage_spell = false; - new_spell->has_damaged = false; - new_spell->interrupted = false; - new_spell->crit = false; - new_spell->last_spellattack_hit = false; - new_spell->MSpellTargets.SetName("LuaSpell.MSpellTargets"); - new_spell->cancel_after_all_triggers = false; - new_spell->num_triggers = 0; - new_spell->num_calls = 0; - new_spell->is_recast_timer = false; - new_spell->had_triggers = false; - new_spell->had_dmg_remaining = false; - new_spell->slot_pos = 0; - new_spell->damage_remaining = 0; - new_spell->effect_bitmask = 0; - new_spell->caster = 0; - new_spell->initial_target = 0; - new_spell->spell = 0; - new_spell->restored = false; - new_spell->initial_caster_char_id = 0; - new_spell->initial_target_char_id = 0; - return new_spell; - } - else{ - LogWrite(LUA__ERROR, 0, "LUA", "Error LUA Spell Script: '%s'", name); - return 0; + lua_State* state = LoadLuaFile(lua_script.c_str()); + if(state) { + spell = new LuaSpell; + spell->file_name = lua_script; + spell->state = state; + spell->spell = 0; + spell->caster = 0; + spell->initial_target = 0; + spell->resisted = false; + spell->has_damaged = false; + spell->is_damage_spell = false; + spell->interrupted = false; + spell->last_spellattack_hit = false; + spell->crit = false; + spell->MSpellTargets.SetName("LuaSpell.MSpellTargets"); + spell->cancel_after_all_triggers = false; + spell->num_triggers = 0; + spell->num_calls = 0; + spell->is_recast_timer = false; + spell->had_triggers = false; + spell->had_dmg_remaining = false; + spell->slot_pos = 0; + spell->damage_remaining = 0; + spell->effect_bitmask = 0; + spell->restored = false; + spell->has_proc = false; + spell->initial_caster_char_id = 0; + spell->initial_target_char_id = 0; + + MSpells.lock(); + current_spells[spell->state] = spell; + MSpells.unlock(); + + MSpellScripts.writelock(__FUNCTION__, __LINE__); + spell_scripts[lua_script][state] = spell; + MSpellScripts.releasewritelock(__FUNCTION__, __LINE__); } + return spell; } Mutex* LuaInterface::GetItemScriptMutex(const char* name) { @@ -2143,6 +2102,17 @@ Mutex* LuaInterface::GetRegionScriptMutex(const char* name) { return mutex; } +Mutex* LuaInterface::GetSpellScriptMutex(const char* name) { + Mutex* mutex = 0; + if(spell_scripts_mutex.count(name) > 0) + mutex = spell_scripts_mutex[name]; + if(!mutex){ + mutex = new Mutex(); + spell_scripts_mutex[name] = mutex; + } + return mutex; +} + void LuaInterface::UseItemScript(const char* name, lua_State* state, bool val) { MItemScripts.writelock(__FUNCTION__, __LINE__); item_scripts[name][state] = val; @@ -2268,7 +2238,7 @@ lua_State* LuaInterface::GetZoneScript(const char* name, bool create_new, bool u } if(!ret && create_new){ if(name && LoadZoneScript(name)) - ret = GetZoneScript(name); + ret = GetZoneScript(name, create_new, use); else{ LogError("Error LUA Zone Script '%s'", name); return 0; @@ -2302,7 +2272,7 @@ lua_State* LuaInterface::GetRegionScript(const char* name, bool create_new, bool } if(!ret && create_new){ if(name && LoadRegionScript(name)) - ret = GetRegionScript(name); + ret = GetRegionScript(name, create_new, use); else{ LogError("Error LUA Zone Script '%s'", name); return 0; @@ -2311,6 +2281,78 @@ lua_State* LuaInterface::GetRegionScript(const char* name, bool create_new, bool return ret; } +LuaSpell* LuaInterface::GetSpellScript(const char* name, bool create_new, bool use) { + map >::iterator itr; + map::iterator spell_script_itr; + LuaSpell* ret = 0; + Mutex* mutex = 0; + + itr = spell_scripts.find(name); + if(itr != spell_scripts.end()) { + mutex = GetSpellScriptMutex(name); + mutex->readlock(__FUNCTION__, __LINE__); + for(spell_script_itr = itr->second.begin(); spell_script_itr != itr->second.end(); spell_script_itr++){ + if(spell_script_itr->second == nullptr){ //not in use + if (use) + { + spell_script_itr->second = CreateSpellScript(name, spell_script_itr->first); + ret = spell_script_itr->second; + break; // don't keep iterating, we already have our result + } + } + } + mutex->releasereadlock(__FUNCTION__, __LINE__); + } + if(!ret && create_new){ + if(!name || (ret = LoadSpellScript(name)) == nullptr) { + LogError("Error LUA Spell Script '%s'", name == nullptr ? "unknown" : name); + } + } + return ret; +} + +LuaSpell* LuaInterface::CreateSpellScript(const char* name, lua_State* existState) { + LuaSpell* new_spell = new LuaSpell; + new_spell->state = existState; + new_spell->file_name = string(name); + new_spell->resisted = false; + new_spell->is_damage_spell = false; + new_spell->has_damaged = false; + new_spell->interrupted = false; + new_spell->crit = false; + new_spell->last_spellattack_hit = false; + new_spell->MSpellTargets.SetName("LuaSpell.MSpellTargets"); + new_spell->cancel_after_all_triggers = false; + new_spell->num_triggers = 0; + new_spell->num_calls = 0; + new_spell->is_recast_timer = false; + new_spell->had_triggers = false; + new_spell->had_dmg_remaining = false; + new_spell->slot_pos = 0; + new_spell->damage_remaining = 0; + new_spell->effect_bitmask = 0; + new_spell->caster = 0; + new_spell->initial_target = 0; + new_spell->spell = 0; + new_spell->restored = false; + new_spell->has_proc = false; + new_spell->initial_caster_char_id = 0; + new_spell->initial_target_char_id = 0; + + MSpells.lock(); + current_spells[new_spell->state] = new_spell; + MSpells.unlock(); + + MSpellScripts.writelock(__FUNCTION__, __LINE__); + spell_scripts[std::string(name)][new_spell->state] = new_spell; + MSpellScripts.releasewritelock(__FUNCTION__, __LINE__); + return new_spell; +} + +LuaSpell* LuaInterface::GetSpell(const char* name) { + return GetSpellScript(name, true); +} + bool LuaInterface::RunItemScript(string script_name, const char* function_name, Item* item, Spawn* spawn, Spawn* target, sint64* returnValue) { if(!item) return false; diff --git a/source/WorldServer/LuaInterface.h b/source/WorldServer/LuaInterface.h index 8bd5966..1b889c7 100644 --- a/source/WorldServer/LuaInterface.h +++ b/source/WorldServer/LuaInterface.h @@ -102,6 +102,7 @@ struct LuaSpell{ Mutex MSpellTargets; int32 effect_bitmask; bool restored; // restored spell cross zone + std::atomic has_proc; }; @@ -183,8 +184,6 @@ public: LuaInterface(); ~LuaInterface(); int GetNumberOfArgs(lua_State* state); - bool LoadLuaSpell(const char* name); - bool LoadLuaSpell(string name); bool LoadItemScript(string name); bool LoadItemScript(const char* name); bool LoadSpawnScript(string name); @@ -193,6 +192,8 @@ public: bool LoadZoneScript(const char* name); bool LoadRegionScript(string name); bool LoadRegionScript(const char* name); + LuaSpell* LoadSpellScript(string name); + LuaSpell* LoadSpellScript(const char* name); void RemoveSpell(LuaSpell* spell, bool call_remove_function = true, bool can_delete = true, string reason = "", bool removing_all_spells = false); Spawn* GetSpawn(lua_State* state, int8 arg_num = 1); Item* GetItem(lua_State* state, int8 arg_num = 1); @@ -233,7 +234,7 @@ public: std::string AddSpawnPointers(LuaSpell* spell, bool first_cast, bool precast = false, const char* function = 0, SpellScriptTimer* timer = 0, bool passLuaSpell=false, Spawn* altTarget = 0); LuaSpell* GetCurrentSpell(lua_State* state, bool needsLock = true); - void RemoveCurrentSpell(lua_State* state, bool needsLock = true); + void RemoveCurrentSpell(lua_State* state, LuaSpell* cur_spell, bool needsLock = true, bool removeCurSpell = true); bool CallSpellProcess(LuaSpell* spell, int8 num_parameters, std::string functionCalled); LuaSpell* GetSpell(const char* name); void UseItemScript(const char* name, lua_State* state, bool val); @@ -244,6 +245,9 @@ public: lua_State* GetSpawnScript(const char* name, bool create_new = true, bool use = false); lua_State* GetZoneScript(const char* name, bool create_new = true, bool use = false); lua_State* GetRegionScript(const char* name, bool create_new = true, bool use = false); + LuaSpell* GetSpellScript(const char* name, bool create_new = true, bool use = true); + LuaSpell* CreateSpellScript(const char* name, lua_State* existState); + Quest* LoadQuest(int32 id, const char* name, const char* type, const char* zone, int8 level, const char* description, char* script_name); const char* GetScriptName(lua_State* state); @@ -286,6 +290,7 @@ public: Mutex* GetItemScriptMutex(const char* name); Mutex* GetZoneScriptMutex(const char* name); Mutex* GetRegionScriptMutex(const char* name); + Mutex* GetSpellScriptMutex(const char* name); Mutex* GetQuestMutex(Quest* quest); void SetLuaSystemReloading(bool val) { lua_system_reloading = val; } @@ -326,6 +331,7 @@ private: map > spawn_scripts; map > zone_scripts; map > region_scripts; + map > spell_scripts; map custom_spells; std::deque custom_free_spell_ids; @@ -340,6 +346,7 @@ private: map zone_scripts_mutex; map quests_mutex; map region_scripts_mutex; + map spell_scripts_mutex; Mutex MDebugClients; Mutex MSpells; @@ -351,6 +358,7 @@ private: Mutex MSpellDelete; Mutex MCustomSpell; Mutex MRegionScripts; + Mutex MSpellScripts; mutable std::shared_mutex MLUAUserData; }; diff --git a/source/WorldServer/SpellProcess.cpp b/source/WorldServer/SpellProcess.cpp index d7f6159..dd02a8d 100644 --- a/source/WorldServer/SpellProcess.cpp +++ b/source/WorldServer/SpellProcess.cpp @@ -217,6 +217,9 @@ void SpellProcess::Process(){ } if (cast_timer->delete_timer) { safe_delete(cast_timer->timer); + if(cast_timer->spell && !cast_timer->spell->has_proc) { + lua_interface->RemoveCurrentSpell(cast_timer->spell->state, cast_timer->spell, true, false); + } cast_timers.Remove(cast_timer, true); } } @@ -650,7 +653,7 @@ bool SpellProcess::CastInstant(Spell* spell, Entity* caster, Entity* target, boo if (!lua_spell->spell->IsCopiedSpell()) { lua_getglobal(lua_spell->state, "customspell"); - if (lua_isfunction(lua_spell->state, -1)) { + if (lua_isfunction(lua_spell->state, lua_gettop(lua_spell->state))) { lua_pop(lua_spell->state, 1); Spell* tmpSpell = lua_spell->spell; lua_spell->spell = new Spell(lua_spell->spell); @@ -1094,7 +1097,7 @@ void SpellProcess::ProcessSpell(ZoneServer* zone, Spell* spell, Entity* caster, if (!customSpell && !lua_spell->spell->IsCopiedSpell()) { lua_getglobal(lua_spell->state, "customspell"); - if (lua_isfunction(lua_spell->state, -1)) { + if (lua_isfunction(lua_spell->state, lua_gettop(lua_spell->state))) { lua_pop(lua_spell->state, 1); Spell* tmpSpell = lua_spell->spell; lua_spell->spell = new Spell(lua_spell->spell); @@ -1637,6 +1640,9 @@ void SpellProcess::ProcessSpell(ZoneServer* zone, Spell* spell, Entity* caster, DeleteSpell(lua_spell); return; } + if(!lua_spell->has_proc) { + lua_interface->RemoveCurrentSpell(lua_spell->state, lua_spell, true, false); + } } if(caster) @@ -2969,7 +2975,7 @@ void SpellProcess::DeleteSpell(LuaSpell* spell) } lua_interface->SetLuaUserDataStale(spell); - lua_interface->RemoveCurrentSpell(spell->state, true); + lua_interface->RemoveCurrentSpell(spell->state, spell, true); DeleteActiveSpell(spell); } diff --git a/source/WorldServer/WorldDatabase.cpp b/source/WorldServer/WorldDatabase.cpp index 6641cbe..98aadd1 100644 --- a/source/WorldServer/WorldDatabase.cpp +++ b/source/WorldServer/WorldDatabase.cpp @@ -4508,7 +4508,7 @@ int32 WorldDatabase::LoadSpellScriptData() { while (result && (row = mysql_fetch_row(result))) { if (row[0] && strlen(row[0]) > 0) { - if (lua_interface->LoadLuaSpell(row[0])) + if (lua_interface->GetSpell(row[0])) LogWrite(SPELL__DEBUG, 5, "Spells", "SpellScript: %s loaded.", row[0]); } } @@ -7787,7 +7787,6 @@ void WorldDatabase::LoadCharacterSpellEffects(int32 char_id, Client* client, int if((lua_spell = lua_interface->GetSpell(lua_file.c_str())) == nullptr) { LogWrite(LUA__WARNING, 0, "LUA", "WorldDatabase::LoadCharacterSpellEffects: GetSpell(%u, %u, '%s'), custom lua script not loaded, when attempting to load.", spell_id, tier, lua_file.c_str()); - lua_interface->LoadLuaSpell(lua_file); } } diff --git a/source/WorldServer/client.cpp b/source/WorldServer/client.cpp index 1910d6d..9957acf 100644 --- a/source/WorldServer/client.cpp +++ b/source/WorldServer/client.cpp @@ -11391,7 +11391,7 @@ bool Client::EntityCommandPrecheck(Spawn* spawn, const char* command) { if (state_mutex) state_mutex->writelock(__FUNCTION__, __LINE__); lua_getglobal(state, "can_use_command"); - if (lua_isfunction(state, -1)) { + if (lua_isfunction(state, lua_gettop(state))) { lua_interface->SetSpawnValue(state, spawn); lua_interface->SetSpawnValue(state, GetPlayer()); lua_interface->SetStringValue(state, command ? command : "");