From 3b849fcbc05daf1841d919cae511f560c612b01f Mon Sep 17 00:00:00 2001 From: Das Keifer <43280661+DasKeifer@users.noreply.github.com> Date: Mon, 2 Feb 2026 22:20:38 -0500 Subject: [PATCH 1/2] Adding more details to hooks and events to match modLoader changes --- scripts/hooks.lua | 7 +++++-- scripts/internal.lua | 31 +++++++++++++++++++++---------- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/scripts/hooks.lua b/scripts/hooks.lua index 185ad4b..04a75cf 100644 --- a/scripts/hooks.lua +++ b/scripts/hooks.lua @@ -66,12 +66,15 @@ function hooks:addTo(modApiExt) local eventId = "on"..Name local addHook = "add"..Name.."Hook" - events[eventId] = Event() + events[eventId] = Event({ eventName = eventId }) modApiExt[hookId] = {} modApiExt[addHook] = function(self, fn) assert(type(fn) == "function") - table.insert(self[hookId], fn) + table.insert(self[hookId], { + fn = fn, + creator = debug.traceback("", 3) + }) end -- functions to fire the hooks are built in internal.lua diff --git a/scripts/internal.lua b/scripts/internal.lua index bb8aa9f..07924da 100644 --- a/scripts/internal.lua +++ b/scripts/internal.lua @@ -1,5 +1,16 @@ local internal = {} +function internal.handleFailure(errorOrResult, creator, caller) + errorOrResult = errorOrResult or "" + local message = Event.buildErrorMessage("An event callback failed: ", errorOrResult, + nil, creator, caller) + if Event.isStackOverflowError(errorOrResult) then + error(message) + else + LOG(message) + end +end + --[[ Creates a broadcast function for the specified hooks field, allowing to trigger the hook callbacks on all registered modApiExt objects. @@ -10,14 +21,15 @@ local internal = {} --]] function internal:buildBroadcastFunc(hooksField, argsFunc) local errfunc = function(e) - return string.format( - "A '%s' callback has failed:\n%s", - hooksField, e - ) + -- Capture and return the stack trace of the xpcall + -- 2 makes it start a frame higher so it doesn't include + -- this error handling fn + return debug.traceback(tostring(e), 2) end return function(...) local args = {...} + local caller = debug.traceback("") if #args == 0 then -- We didn't receive arguments directly. Fall back to @@ -28,19 +40,18 @@ function internal:buildBroadcastFunc(hooksField, argsFunc) for i, extObj in ipairs(modApiExt_internal.extObjects) do if extObj[hooksField] then - for j, hook in ipairs(extObj[hooksField]) do + for j, hookTbl in ipairs(extObj[hooksField]) do -- invoke the hook in a xpcall, since errors in SkillEffect -- scripts fail silently, making debugging a nightmare. - local ok, err = xpcall( + local ok, errorOrResult = xpcall( args - and function() hook(unpack(args)) end - or function() hook() end, + and function() hookTbl.fn(unpack(args)) end + or function() hookTbl.fn() end, errfunc ) if not ok then - local owner = extObj.owner and extObj.owner.id or "" - LOG("In mod id '" .. owner .. "', ", err) + internal.handleFailure(errorOrResult, hookTbl.creator, caller) end end end From 497767acc5bb2d8ca1123e5e9f8c50742b78a280 Mon Sep 17 00:00:00 2001 From: Das Keifer <43280661+DasKeifer@users.noreply.github.com> Date: Sat, 14 Feb 2026 17:55:45 -0500 Subject: [PATCH 2/2] Fixing backwards compatibility of hooks --- scripts/internal.lua | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/scripts/internal.lua b/scripts/internal.lua index 07924da..0b75d18 100644 --- a/scripts/internal.lua +++ b/scripts/internal.lua @@ -1,7 +1,15 @@ local internal = {} -function internal.handleFailure(errorOrResult, creator, caller) +function internal.handleFailure(errorOrResult, owner, creator, caller) errorOrResult = errorOrResult or "" + if creator then + if owner then + -- creator will already have a newline + creator = "In mod id '"..owner.."'"..creator + end + else + creator = "In mod id '"..(owner and owner or "").."'" + end local message = Event.buildErrorMessage("An event callback failed: ", errorOrResult, nil, creator, caller) if Event.isStackOverflowError(errorOrResult) then @@ -41,17 +49,22 @@ function internal:buildBroadcastFunc(hooksField, argsFunc) for i, extObj in ipairs(modApiExt_internal.extObjects) do if extObj[hooksField] then for j, hookTbl in ipairs(extObj[hooksField]) do + local hook = hookTbl + if type(hookTbl) == "table" then + hook = hookTbl.fn + end -- invoke the hook in a xpcall, since errors in SkillEffect -- scripts fail silently, making debugging a nightmare. local ok, errorOrResult = xpcall( args - and function() hookTbl.fn(unpack(args)) end - or function() hookTbl.fn() end, + and function() hook(unpack(args)) end + or function() hook() end, errfunc ) if not ok then - internal.handleFailure(errorOrResult, hookTbl.creator, caller) + local owner = extObj.owner and extObj.owner.id or nil + internal.handleFailure(errorOrResult, owner, hookTbl.creator, caller) end end end