Improvements for delayed hooks
This commit is contained in:
parent
178aa48f80
commit
6b7c4d7fc2
2 changed files with 51 additions and 29 deletions
|
@ -80,7 +80,6 @@ end
|
||||||
|
|
||||||
function dmf_mod_object:on_unload()
|
function dmf_mod_object:on_unload()
|
||||||
print("DMF:ON_UNLOAD()")
|
print("DMF:ON_UNLOAD()")
|
||||||
dmf.report_delayed_hooks()
|
|
||||||
dmf.save_chat_history()
|
dmf.save_chat_history()
|
||||||
dmf.save_unsaved_settings_to_file()
|
dmf.save_unsaved_settings_to_file()
|
||||||
dmf.destroy_command_gui()
|
dmf.destroy_command_gui()
|
||||||
|
@ -102,7 +101,7 @@ function dmf_mod_object:on_game_state_changed(status, state)
|
||||||
print("DMF:ON_GAME_STATE_CHANGED(), status: " .. tostring(status) .. ", state: " .. tostring(state))
|
print("DMF:ON_GAME_STATE_CHANGED(), status: " .. tostring(status) .. ", state: " .. tostring(state))
|
||||||
dmf.mods_game_state_changed_event(status, state)
|
dmf.mods_game_state_changed_event(status, state)
|
||||||
dmf.save_unsaved_settings_to_file()
|
dmf.save_unsaved_settings_to_file()
|
||||||
dmf.apply_delayed_hooks(status, state)
|
dmf.apply_delayed_hooks()
|
||||||
dmf.destroy_command_gui()
|
dmf.destroy_command_gui()
|
||||||
|
|
||||||
if status == "enter" and state == "StateIngame" then
|
if status == "enter" and state == "StateIngame" then
|
||||||
|
|
|
@ -17,8 +17,7 @@ local HOOK_TYPE_SAFE = 2
|
||||||
local HOOK_TYPE_ORIGIN = 3
|
local HOOK_TYPE_ORIGIN = 3
|
||||||
|
|
||||||
-- dont need to attach this to registry.
|
-- dont need to attach this to registry.
|
||||||
local _delayed = {}
|
local _delayed_hooks = {}
|
||||||
local _delayed_obj_names = {}
|
|
||||||
local _delaying_enabled = true
|
local _delaying_enabled = true
|
||||||
|
|
||||||
-- This metatable will automatically create a table entry if one doesnt exist.
|
-- This metatable will automatically create a table entry if one doesnt exist.
|
||||||
|
@ -239,7 +238,29 @@ local function create_hook(mod, orig, obj, method, handler, func_name, hook_type
|
||||||
mod:warning("(%s): Attempting to rehook active hook [%s].", func_name, method)
|
mod:warning("(%s): Attempting to rehook active hook [%s].", func_name, method)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Applies delayed hooks set for the given object name.
|
||||||
|
local function apply_delayed_hooks_by_obj_name(obj_name)
|
||||||
|
if _delayed_hooks[obj_name] and #_delayed_hooks[obj_name] > 0 then
|
||||||
|
|
||||||
|
-- Check for the object before attempting hooks
|
||||||
|
local obj, success = get_object_reference(obj_name) --luacheck: ignore
|
||||||
|
if obj and success then
|
||||||
|
dmf:info("Attempting to hook %s delayed hooks for object %s", #_delayed_hooks[obj_name], obj_name)
|
||||||
|
|
||||||
|
-- Go through the table in reverse so we don't get any issues removing entries inside the loop
|
||||||
|
for i = #_delayed_hooks[obj_name], 1, -1 do
|
||||||
|
_delayed_hooks[obj_name][i]()
|
||||||
|
table.remove(_delayed_hooks[obj_name], i)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Remove the table if empty
|
||||||
|
if #_delayed_hooks[obj_name] == 0 then
|
||||||
|
_delayed_hooks[obj_name] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- ####################################################################################################################
|
-- ####################################################################################################################
|
||||||
|
@ -283,10 +304,12 @@ local function generic_hook(mod, obj, method, handler, func_name)
|
||||||
if _delaying_enabled and type(obj) == "string" then
|
if _delaying_enabled and type(obj) == "string" then
|
||||||
-- Call this func at a later time, using upvalues.
|
-- Call this func at a later time, using upvalues.
|
||||||
mod:info("(%s): [%s.%s] needs to be delayed.", func_name, obj, method)
|
mod:info("(%s): [%s.%s] needs to be delayed.", func_name, obj, method)
|
||||||
table.insert(_delayed, function()
|
|
||||||
|
-- Sort hooks by obj string
|
||||||
|
_delayed_hooks[obj] = _delayed_hooks[obj] or {}
|
||||||
|
_delayed_hooks[obj][#_delayed_hooks[obj] + 1] = function()
|
||||||
generic_hook(mod, obj, method, handler, func_name)
|
generic_hook(mod, obj, method, handler, func_name)
|
||||||
end)
|
end
|
||||||
_delayed_obj_names[obj] = true
|
|
||||||
return
|
return
|
||||||
else
|
else
|
||||||
mod:error("(%s): trying to hook object that doesn't exist: %s", func_name, obj)
|
mod:error("(%s): trying to hook object that doesn't exist: %s", func_name, obj)
|
||||||
|
@ -338,10 +361,12 @@ local function generic_hook_toggle(mod, obj, method, enabled_state)
|
||||||
if _delaying_enabled and type(obj) == "string" then
|
if _delaying_enabled and type(obj) == "string" then
|
||||||
-- Call this func at a later time, using upvalues.
|
-- Call this func at a later time, using upvalues.
|
||||||
mod:info("(%s): [%s.%s] needs to be delayed.", func_name, obj, method)
|
mod:info("(%s): [%s.%s] needs to be delayed.", func_name, obj, method)
|
||||||
table.insert(_delayed, function()
|
|
||||||
|
-- Sort hooks by obj string
|
||||||
|
_delayed_hooks[obj] = _delayed_hooks[obj] or {}
|
||||||
|
_delayed_hooks[obj][#_delayed_hooks[obj] + 1] = function()
|
||||||
generic_hook_toggle(mod, obj, method, enabled_state)
|
generic_hook_toggle(mod, obj, method, enabled_state)
|
||||||
end)
|
end
|
||||||
_delayed_obj_names[obj] = true
|
|
||||||
return
|
return
|
||||||
else
|
else
|
||||||
mod:error("(%s): trying to toggle hook on object that doesn't exist: %s", func_name, obj)
|
mod:error("(%s): trying to toggle hook on object that doesn't exist: %s", func_name, obj)
|
||||||
|
@ -466,24 +491,22 @@ dmf.hooks_unload = function()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
dmf.apply_delayed_hooks = function(status, state)
|
-- Apply all previously-delayed hooks
|
||||||
if #_delayed > 0 then
|
dmf.apply_delayed_hooks = function()
|
||||||
dmf:info("Attempt to hook %s delayed hooks", #_delayed)
|
local num_delayed = 0
|
||||||
-- Go through the table in reverse so we don't get any issues removing entries inside the loop
|
|
||||||
for i = #_delayed, 1, -1 do
|
for obj_name, hooks in pairs(_delayed_hooks) do
|
||||||
_delayed[i]()
|
num_delayed = num_delayed + #hooks
|
||||||
table.remove(_delayed, i)
|
apply_delayed_hooks_by_obj_name(obj_name)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if num_delayed > 0 then
|
||||||
|
dmf:info("Attempted to hook " .. tostring(num_delayed) .. " delayed function" ..
|
||||||
|
(num_delayed == 1 and "" or "s"))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
dmf.report_delayed_hooks = function()
|
-- Apply all associated file hooks to the given file
|
||||||
if #_delayed > 0 then
|
|
||||||
dmf:info(tostring(#_delayed) .. " hooked function" ..
|
|
||||||
(#_delayed == 1 and " does" or "s do") .. " not exist.")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
dmf.apply_hooks_to_file = function(require_store, filepath, store_index)
|
dmf.apply_hooks_to_file = function(require_store, filepath, store_index)
|
||||||
if _file_hooks_by_file[filepath] and require_store and require_store[store_index] then
|
if _file_hooks_by_file[filepath] and require_store and require_store[store_index] then
|
||||||
for mod_name, hook_create_func in pairs(_file_hooks_by_file[filepath]) do
|
for mod_name, hook_create_func in pairs(_file_hooks_by_file[filepath]) do
|
||||||
|
@ -501,14 +524,14 @@ end
|
||||||
-- If class() is called on an object we've delayed for, re-run delayed hooks
|
-- If class() is called on an object we've delayed for, re-run delayed hooks
|
||||||
dmf:hook(_G, "class", function(func, class_name, ...)
|
dmf:hook(_G, "class", function(func, class_name, ...)
|
||||||
local class_object = func(class_name, ...)
|
local class_object = func(class_name, ...)
|
||||||
if _delayed_obj_names[class_name] then
|
if _delayed_hooks[class_name] then
|
||||||
dmf:info("%s is now available for previously-delayed hooks.", class_name)
|
dmf:info("%s is now available for previously-delayed hooks.", class_name)
|
||||||
|
|
||||||
-- Methods aren't defined yet, so we need to wait for the instance creation to apply delayed hooks
|
-- Methods aren't defined yet, so we need to wait for the instance creation to apply delayed hooks
|
||||||
dmf:hook_safe(class_object, "new", function ()
|
dmf:hook(class_object, "new", function (class_func, ...)
|
||||||
dmf.apply_delayed_hooks()
|
apply_delayed_hooks_by_obj_name(class_name)
|
||||||
_delayed_obj_names[class_name] = nil
|
|
||||||
dmf:hook_disable(class_object, "new")
|
dmf:hook_disable(class_object, "new")
|
||||||
|
return class_func(...)
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
return class_object
|
return class_object
|
||||||
|
|
Loading…
Add table
Reference in a new issue