mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-18 03:01:29 +00:00
[Quest API] Add tracebacks to Lua error messages (#4079)
This adds an error msg handler for lua calls to add a stack trace to
error messages. Lua 5.1 does not have luaL_traceback like luajit and lua
5.2+ so debug.traceback() is used directly as the msg handler.
The traceback will add more detail to errors than just logging package
and event names. Exceptions in C++ binds and luabind errors will now
show script context instead of just the error message.
e.g., for a luabind overload error:
No matching overload found, candidates:
void signal(int,int,int)
void signal(int,int)
stack traceback:
[C]: in function 'signal'
quests/arena/player.lua:10: in function 'somefn'
quests/arena/player.lua:27: in function <quests/arena/player.lua:17>
This commit is contained in:
parent
447fc026a8
commit
86f39743fc
@ -190,6 +190,14 @@ std::map<std::string, std::list<lua_registered_event>> lua_encounter_events_regi
|
|||||||
std::map<std::string, bool> lua_encounters_loaded;
|
std::map<std::string, bool> lua_encounters_loaded;
|
||||||
std::map<std::string, Encounter *> lua_encounters;
|
std::map<std::string, Encounter *> lua_encounters;
|
||||||
|
|
||||||
|
// use debug.traceback() for errors (luaL_traceback is only in luajit and lua 5.2+)
|
||||||
|
static void PushErrorHandler(lua_State* L)
|
||||||
|
{
|
||||||
|
lua_getglobal(L, "debug");
|
||||||
|
lua_getfield(L, -1, "traceback");
|
||||||
|
lua_remove(L, -2);
|
||||||
|
}
|
||||||
|
|
||||||
LuaParser::LuaParser() {
|
LuaParser::LuaParser() {
|
||||||
for (int i = 0; i < _LargestEventID; ++i) {
|
for (int i = 0; i < _LargestEventID; ++i) {
|
||||||
NPCArgumentDispatch[i] = handle_npc_null;
|
NPCArgumentDispatch[i] = handle_npc_null;
|
||||||
@ -416,13 +424,14 @@ int LuaParser::_EventNPC(std::string package_name, QuestEventID evt, NPC* npc, M
|
|||||||
int start = lua_gettop(L);
|
int start = lua_gettop(L);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
int npop = 1;
|
int npop = 2;
|
||||||
|
PushErrorHandler(L);
|
||||||
if(l_func != nullptr) {
|
if(l_func != nullptr) {
|
||||||
l_func->push(L);
|
l_func->push(L);
|
||||||
} else {
|
} else {
|
||||||
lua_getfield(L, LUA_REGISTRYINDEX, package_name.c_str());
|
lua_getfield(L, LUA_REGISTRYINDEX, package_name.c_str());
|
||||||
lua_getfield(L, -1, sub_name);
|
lua_getfield(L, -1, sub_name);
|
||||||
npop = 2;
|
npop = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
lua_createtable(L, 0, 0);
|
lua_createtable(L, 0, 0);
|
||||||
@ -437,7 +446,7 @@ int LuaParser::_EventNPC(std::string package_name, QuestEventID evt, NPC* npc, M
|
|||||||
Client *c = (init && init->IsClient()) ? init->CastToClient() : nullptr;
|
Client *c = (init && init->IsClient()) ? init->CastToClient() : nullptr;
|
||||||
|
|
||||||
quest_manager.StartQuest(npc, c);
|
quest_manager.StartQuest(npc, c);
|
||||||
if(lua_pcall(L, 1, 1, 0)) {
|
if(lua_pcall(L, 1, 1, start + 1)) {
|
||||||
std::string error = lua_tostring(L, -1);
|
std::string error = lua_tostring(L, -1);
|
||||||
AddError(error);
|
AddError(error);
|
||||||
quest_manager.EndQuest();
|
quest_manager.EndQuest();
|
||||||
@ -509,13 +518,14 @@ int LuaParser::_EventPlayer(std::string package_name, QuestEventID evt, Client *
|
|||||||
int start = lua_gettop(L);
|
int start = lua_gettop(L);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
int npop = 1;
|
int npop = 2;
|
||||||
|
PushErrorHandler(L);
|
||||||
if(l_func != nullptr) {
|
if(l_func != nullptr) {
|
||||||
l_func->push(L);
|
l_func->push(L);
|
||||||
} else {
|
} else {
|
||||||
lua_getfield(L, LUA_REGISTRYINDEX, package_name.c_str());
|
lua_getfield(L, LUA_REGISTRYINDEX, package_name.c_str());
|
||||||
lua_getfield(L, -1, sub_name);
|
lua_getfield(L, -1, sub_name);
|
||||||
npop = 2;
|
npop = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
lua_createtable(L, 0, 0);
|
lua_createtable(L, 0, 0);
|
||||||
@ -529,7 +539,7 @@ int LuaParser::_EventPlayer(std::string package_name, QuestEventID evt, Client *
|
|||||||
arg_function(this, L, client, data, extra_data, extra_pointers);
|
arg_function(this, L, client, data, extra_data, extra_pointers);
|
||||||
|
|
||||||
quest_manager.StartQuest(client, client);
|
quest_manager.StartQuest(client, client);
|
||||||
if(lua_pcall(L, 1, 1, 0)) {
|
if(lua_pcall(L, 1, 1, start + 1)) {
|
||||||
std::string error = lua_tostring(L, -1);
|
std::string error = lua_tostring(L, -1);
|
||||||
AddError(error);
|
AddError(error);
|
||||||
quest_manager.EndQuest();
|
quest_manager.EndQuest();
|
||||||
@ -586,13 +596,14 @@ int LuaParser::_EventItem(std::string package_name, QuestEventID evt, Client *cl
|
|||||||
int start = lua_gettop(L);
|
int start = lua_gettop(L);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
int npop = 1;
|
int npop = 2;
|
||||||
|
PushErrorHandler(L);
|
||||||
if(l_func != nullptr) {
|
if(l_func != nullptr) {
|
||||||
l_func->push(L);
|
l_func->push(L);
|
||||||
} else {
|
} else {
|
||||||
lua_getfield(L, LUA_REGISTRYINDEX, package_name.c_str());
|
lua_getfield(L, LUA_REGISTRYINDEX, package_name.c_str());
|
||||||
lua_getfield(L, -1, sub_name);
|
lua_getfield(L, -1, sub_name);
|
||||||
npop = 2;
|
npop = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
lua_createtable(L, 0, 0);
|
lua_createtable(L, 0, 0);
|
||||||
@ -612,7 +623,7 @@ int LuaParser::_EventItem(std::string package_name, QuestEventID evt, Client *cl
|
|||||||
arg_function(this, L, client, item, mob, data, extra_data, extra_pointers);
|
arg_function(this, L, client, item, mob, data, extra_data, extra_pointers);
|
||||||
|
|
||||||
quest_manager.StartQuest(client, client, item);
|
quest_manager.StartQuest(client, client, item);
|
||||||
if(lua_pcall(L, 1, 1, 0)) {
|
if(lua_pcall(L, 1, 1, start + 1)) {
|
||||||
std::string error = lua_tostring(L, -1);
|
std::string error = lua_tostring(L, -1);
|
||||||
AddError(error);
|
AddError(error);
|
||||||
quest_manager.EndQuest();
|
quest_manager.EndQuest();
|
||||||
@ -666,13 +677,14 @@ int LuaParser::_EventSpell(std::string package_name, QuestEventID evt, Mob* mob,
|
|||||||
int start = lua_gettop(L);
|
int start = lua_gettop(L);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
int npop = 1;
|
int npop = 2;
|
||||||
|
PushErrorHandler(L);
|
||||||
if(l_func != nullptr) {
|
if(l_func != nullptr) {
|
||||||
l_func->push(L);
|
l_func->push(L);
|
||||||
} else {
|
} else {
|
||||||
lua_getfield(L, LUA_REGISTRYINDEX, package_name.c_str());
|
lua_getfield(L, LUA_REGISTRYINDEX, package_name.c_str());
|
||||||
lua_getfield(L, -1, sub_name);
|
lua_getfield(L, -1, sub_name);
|
||||||
npop = 2;
|
npop = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
lua_createtable(L, 0, 0);
|
lua_createtable(L, 0, 0);
|
||||||
@ -693,7 +705,7 @@ int LuaParser::_EventSpell(std::string package_name, QuestEventID evt, Mob* mob,
|
|||||||
arg_function(this, L, mob, client, spell_id, data, extra_data, extra_pointers);
|
arg_function(this, L, mob, client, spell_id, data, extra_data, extra_pointers);
|
||||||
|
|
||||||
quest_manager.StartQuest(mob, client, nullptr, const_cast<SPDat_Spell_Struct*>(&spells[spell_id]));
|
quest_manager.StartQuest(mob, client, nullptr, const_cast<SPDat_Spell_Struct*>(&spells[spell_id]));
|
||||||
if(lua_pcall(L, 1, 1, 0)) {
|
if(lua_pcall(L, 1, 1, start + 1)) {
|
||||||
std::string error = lua_tostring(L, -1);
|
std::string error = lua_tostring(L, -1);
|
||||||
AddError(error);
|
AddError(error);
|
||||||
quest_manager.EndQuest();
|
quest_manager.EndQuest();
|
||||||
@ -745,6 +757,7 @@ int LuaParser::_EventEncounter(std::string package_name, QuestEventID evt, std::
|
|||||||
int start = lua_gettop(L);
|
int start = lua_gettop(L);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
PushErrorHandler(L);
|
||||||
lua_getfield(L, LUA_REGISTRYINDEX, package_name.c_str());
|
lua_getfield(L, LUA_REGISTRYINDEX, package_name.c_str());
|
||||||
lua_getfield(L, -1, sub_name);
|
lua_getfield(L, -1, sub_name);
|
||||||
|
|
||||||
@ -758,22 +771,22 @@ int LuaParser::_EventEncounter(std::string package_name, QuestEventID evt, std::
|
|||||||
arg_function(this, L, enc, data, extra_data, extra_pointers);
|
arg_function(this, L, enc, data, extra_data, extra_pointers);
|
||||||
|
|
||||||
quest_manager.StartQuest(enc, nullptr, nullptr, nullptr, encounter_name);
|
quest_manager.StartQuest(enc, nullptr, nullptr, nullptr, encounter_name);
|
||||||
if(lua_pcall(L, 1, 1, 0)) {
|
if(lua_pcall(L, 1, 1, start + 1)) {
|
||||||
std::string error = lua_tostring(L, -1);
|
std::string error = lua_tostring(L, -1);
|
||||||
AddError(error);
|
AddError(error);
|
||||||
quest_manager.EndQuest();
|
quest_manager.EndQuest();
|
||||||
lua_pop(L, 2);
|
lua_pop(L, 3);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
quest_manager.EndQuest();
|
quest_manager.EndQuest();
|
||||||
|
|
||||||
if(lua_isnumber(L, -1)) {
|
if(lua_isnumber(L, -1)) {
|
||||||
int ret = static_cast<int>(lua_tointeger(L, -1));
|
int ret = static_cast<int>(lua_tointeger(L, -1));
|
||||||
lua_pop(L, 2);
|
lua_pop(L, 3);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
lua_pop(L, 2);
|
lua_pop(L, 3);
|
||||||
} catch(std::exception &ex) {
|
} catch(std::exception &ex) {
|
||||||
AddError(fmt::format("Lua Exception | [{}] for Encounter [{}]: {}", sub_name, encounter_name, ex.what()));
|
AddError(fmt::format("Lua Exception | [{}] for Encounter [{}]: {}", sub_name, encounter_name, ex.what()));
|
||||||
|
|
||||||
@ -1124,10 +1137,11 @@ void LuaParser::LoadScript(std::string filename, std::string package_name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto top = lua_gettop(L);
|
auto top = lua_gettop(L);
|
||||||
|
PushErrorHandler(L);
|
||||||
if(luaL_loadfile(L, filename.c_str())) {
|
if(luaL_loadfile(L, filename.c_str())) {
|
||||||
std::string error = lua_tostring(L, -1);
|
std::string error = lua_tostring(L, -1);
|
||||||
AddError(error);
|
AddError(error);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 2);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1147,10 +1161,10 @@ void LuaParser::LoadScript(std::string filename, std::string package_name) {
|
|||||||
|
|
||||||
lua_setfenv(L, -2); //set the env to the table we made
|
lua_setfenv(L, -2); //set the env to the table we made
|
||||||
|
|
||||||
if(lua_pcall(L, 0, 0, 0)) {
|
if(lua_pcall(L, 0, 0, top + 1)) {
|
||||||
std::string error = lua_tostring(L, -1);
|
std::string error = lua_tostring(L, -1);
|
||||||
AddError(error);
|
AddError(error);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 2);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
loaded_[package_name] = true;
|
loaded_[package_name] = true;
|
||||||
@ -1599,13 +1613,14 @@ int LuaParser::_EventBot(
|
|||||||
int start = lua_gettop(L);
|
int start = lua_gettop(L);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
int npop = 1;
|
int npop = 2;
|
||||||
|
PushErrorHandler(L);
|
||||||
if(l_func != nullptr) {
|
if(l_func != nullptr) {
|
||||||
l_func->push(L);
|
l_func->push(L);
|
||||||
} else {
|
} else {
|
||||||
lua_getfield(L, LUA_REGISTRYINDEX, package_name.c_str());
|
lua_getfield(L, LUA_REGISTRYINDEX, package_name.c_str());
|
||||||
lua_getfield(L, -1, sub_name);
|
lua_getfield(L, -1, sub_name);
|
||||||
npop = 2;
|
npop = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
lua_createtable(L, 0, 0);
|
lua_createtable(L, 0, 0);
|
||||||
@ -1620,7 +1635,7 @@ int LuaParser::_EventBot(
|
|||||||
auto* c = (init && init->IsClient()) ? init->CastToClient() : nullptr;
|
auto* c = (init && init->IsClient()) ? init->CastToClient() : nullptr;
|
||||||
|
|
||||||
quest_manager.StartQuest(bot, c);
|
quest_manager.StartQuest(bot, c);
|
||||||
if(lua_pcall(L, 1, 1, 0)) {
|
if(lua_pcall(L, 1, 1, start + 1)) {
|
||||||
std::string error = lua_tostring(L, -1);
|
std::string error = lua_tostring(L, -1);
|
||||||
AddError(error);
|
AddError(error);
|
||||||
quest_manager.EndQuest();
|
quest_manager.EndQuest();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user