Merge pull request #14 from FireSiku/new_hooks

Delay disabling delayed hooks and fix a crash
This commit is contained in:
Azumgi 2018-06-11 10:30:55 +03:00 committed by GitHub
commit 4b890a616a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 28 additions and 12 deletions

View file

@ -6,9 +6,9 @@ local vmf = get_mod("VMF")
-- hook_type is an identifier to help distinguish the different api calls. -- hook_type is an identifier to help distinguish the different api calls.
local HOOK_TYPES = { local HOOK_TYPES = {
hook = 1, hook = 1,
safe = 2, hook_safe = 2,
origin = 3, hook_origin = 3,
} }
-- Constants to ease on table lookups when not needed -- Constants to ease on table lookups when not needed
@ -204,7 +204,7 @@ local function create_hook(self, orig, obj, method, handler, func_name, hook_typ
-- Check to make sure it wasn't hooked before -- Check to make sure it wasn't hooked before
if not _registry[self][orig] then if not _registry[self][orig] then
_registry[self][orig] = { active = true } _registry[self][orig] = { active = self:is_enabled() }
local hook_registry = _registry.hooks[hook_type] local hook_registry = _registry.hooks[hook_type]
-- Add to the hook to registry. Origin hooks are unique, so we check for that too. -- Add to the hook to registry. Origin hooks are unique, so we check for that too.
@ -269,7 +269,7 @@ local function generic_hook(self, obj, method, handler, func_name)
if obj and not success then if obj and not success then
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.
vmf:info("(%s): [%s.%s] needs to be delayed.", func_name, obj, method) self:info("(%s): [%s.%s] needs to be delayed.", func_name, obj, method)
table.insert(_delayed, function() table.insert(_delayed, function()
generic_hook(self, obj, method, handler, func_name) generic_hook(self, obj, method, handler, func_name)
end) end)
@ -291,6 +291,11 @@ local function generic_hook(self, obj, method, handler, func_name)
-- obj can't be a string for these now. -- obj can't be a string for these now.
local orig = get_orig_function(self, obj, method) local orig = get_orig_function(self, obj, method)
if type(orig) ~= "function" then
self:error("(%s): trying to hook %s (a %s), not a function.", func_name, method, type(orig))
return
end
return create_hook(self, orig, obj, method, handler, func_name, hook_type) return create_hook(self, orig, obj, method, handler, func_name, hook_type)
end end
@ -313,8 +318,17 @@ local function generic_hook_toggle(self, obj, method, enabled_state)
local obj, success = get_object_reference(obj) --luacheck: ignore local obj, success = get_object_reference(obj) --luacheck: ignore
if obj and not success then if obj and not success then
self:error("(%s): object doesn't exist.", func_name) if _delaying_enabled and type(obj) == "string" then
return -- Call this func at a later time, using upvalues.
self:info("(%s): [%s.%s] needs to be delayed.", func_name, obj, method)
table.insert(_delayed, function()
generic_hook_toggle(self, obj, method, enabled_state)
end)
return
else
self:error("(%s): trying to toggle hook on object that doesn't exist: %s", func_name, obj)
return
end
end end
local orig = get_orig_function(self, obj, method) local orig = get_orig_function(self, obj, method)
@ -336,7 +350,7 @@ end
-- The handler is never given the a "func" parameter. -- The handler is never given the a "func" parameter.
-- These will always be executed the original function and the hook chain. -- These will always be executed the original function and the hook chain.
function VMFMod:hook_safe(obj, method, handler) function VMFMod:hook_safe(obj, method, handler)
return generic_hook(self, obj, method, handler, "safe") return generic_hook(self, obj, method, handler, "hook_safe")
end end
-- :hook() will allow you to hook a function, allowing your handler to replace the function in the stack, -- :hook() will allow you to hook a function, allowing your handler to replace the function in the stack,
@ -354,7 +368,7 @@ end
-- This there is a limit of a single origin hook for any given function. -- This there is a limit of a single origin hook for any given function.
-- This should only be used as a last resort due to its limitation and its potential to break the game if not careful. -- This should only be used as a last resort due to its limitation and its potential to break the game if not careful.
function VMFMod:hook_origin(obj, method, handler) function VMFMod:hook_origin(obj, method, handler)
return generic_hook(self, obj, method, handler, "origin") return generic_hook(self, obj, method, handler, "hook_origin")
end end
-- Enable/disable functions for all hook types: -- Enable/disable functions for all hook types:
@ -394,8 +408,10 @@ vmf.hooks_unload = function()
end end
end end
vmf.apply_delayed_hooks = function() vmf.apply_delayed_hooks = function(status, state)
_delaying_enabled = false if status == "enter" and state == "StateIngame" then
_delaying_enabled = false
end
if #_delayed > 0 then if #_delayed > 0 then
vmf:info("Attempt to hook %s delayed hooks", #_delayed) vmf:info("Attempt to hook %s delayed hooks", #_delayed)
-- Go through the table in reverse so we don't get any issues removing entries inside the loop -- Go through the table in reverse so we don't get any issues removing entries inside the loop

View file

@ -98,7 +98,7 @@ function vmf_mod_object:on_game_state_changed(status, state)
print("VMF:ON_GAME_STATE_CHANGED(), status: " .. tostring(status) .. ", state: " .. tostring(state)) print("VMF:ON_GAME_STATE_CHANGED(), status: " .. tostring(status) .. ", state: " .. tostring(state))
vmf.mods_game_state_changed_event(status, state) vmf.mods_game_state_changed_event(status, state)
vmf.save_unsaved_settings_to_file() vmf.save_unsaved_settings_to_file()
vmf.apply_delayed_hooks() vmf.apply_delayed_hooks(status, state)
if status == "enter" and state == "StateIngame" then if status == "enter" and state == "StateIngame" then
vmf.initialize_keybinds() vmf.initialize_keybinds()