feat(dtmm): Move class and require hooks into early loading

These need to be executed as early as possible if they're supposed to
capture all of their respective calls.
This commit is contained in:
Lucas Schwiderski 2023-03-01 00:20:45 +01:00
parent f0450285ad
commit be1cff9f3c
Signed by: lucas
GPG key ID: AA12679AAA6DF4D8

View file

@ -1,3 +1,7 @@
local _G = _G
local rawget = rawget
local rawset = rawset
local log = function(category, format, ...) local log = function(category, format, ...)
local Log = rawget(_G, "Log") local Log = rawget(_G, "Log")
if Log then if Log then
@ -7,23 +11,9 @@ local log = function(category, format, ...)
end end
end end
log("mod_main", " Initializing mods...") -- Patch `GameStateMachine.init` to add our own state for loading mods.
-- Keep a backup of certain system libraries before -- In the future, Fatshark might provide us with a dedicated way to do this.
-- Fatshark's code scrubs them. local function patch_mod_loading_state()
-- The loader can then decide to pass them on to mods, or ignore them
local libs = {
io = io,
debug = debug,
ffi = ffi,
os = os,
load = load,
loadfile = loadfile,
loadstring = loadstring,
}
require("scripts/main")
log("mod_main", "'scripts/main' loaded")
local StateBootSubStateBase = require("scripts/game_states/boot/state_boot_sub_state_base") local StateBootSubStateBase = require("scripts/game_states/boot/state_boot_sub_state_base")
-- A necessary override. -- A necessary override.
@ -75,7 +65,7 @@ StateBootLoadMods._state_update = function (self, dt)
self._mod_loader = mod_loader self._mod_loader = mod_loader
local mod_data = require("scripts/mods/mod_data") local mod_data = require("scripts/mods/mod_data")
mod_loader:init(mod_data, libs, self._parent:gui()) mod_loader:init(mod_data, self._parent:gui())
elseif state == "load_mods" and self._mod_loader:update(dt) then elseif state == "load_mods" and self._mod_loader:update(dt) then
log("StateBootLoadMods", "Mods loaded, exiting") log("StateBootLoadMods", "Mods loaded, exiting")
return true, false return true, false
@ -84,10 +74,6 @@ StateBootLoadMods._state_update = function (self, dt)
return false, false return false, false
end end
-- Patch `GameStateMachine.init` to add our own state for loading mods.
-- In the future, Fatshark might provide us with a dedicated way to do this.
local function patch_mod_loading_state()
log("mod_main", "Adding mod loading state")
local GameStateMachine = require("scripts/foundation/utilities/game_state_machine") local GameStateMachine = require("scripts/foundation/utilities/game_state_machine")
local patched = false local patched = false
@ -95,6 +81,7 @@ local function patch_mod_loading_state()
local GameStateMachine_init = GameStateMachine.init local GameStateMachine_init = GameStateMachine.init
GameStateMachine.init = function(self, parent, start_state, params, ...) GameStateMachine.init = function(self, parent, start_state, params, ...)
if not patched then if not patched then
log("mod_main", "Injecting mod loading state")
patched = true patched = true
-- Hardcoded position after `StateRequireScripts`. -- Hardcoded position after `StateRequireScripts`.
@ -112,13 +99,94 @@ local function patch_mod_loading_state()
GameStateMachine_init(self, parent, start_state, params, ...) GameStateMachine_init(self, parent, start_state, params, ...)
end end
log("mod_main", "Mod patching complete") log("mod_main", "Mod patching complete")
end end
log("mod_main", "Initializing mods...")
local require_store = {}
Mods = {
-- Keep a backup of certain system libraries before
-- Fatshark's code scrubs them.
-- The loader can then decide to pass them on to mods, or ignore them
lua = setmetatable({}, {
io = io,
debug = debug,
ffi = ffi,
os = os,
load = load,
loadfile = loadfile,
loadstring = loadstring,
}),
require_store = require_store
}
local can_insert = function(filepath, new_result)
local store = require_store[filepath]
if not store or #store then
return true
end
if store[#store] ~= new_result then
return true
end
end
local original_require = require
require = function(filepath, ...)
local result = original_require(filepath, ...)
if result and type(result) == "table" then
if can_insert(filepath, result) then
require_store[filepath] = require_store[filepath] or {}
local store = require_store[filepath]
table.insert(store, result)
if Mods.hook then
Mods.hook.enable_by_file(filepath, #store)
end
end
end
return result
end
require("scripts/boot_init")
require("scripts/foundation/utilities/class")
-- The `__index` metamethod maps a proper identifier `CLASS.MyClassName` to the
-- stringified version of the key: `"MyClassName"`.
-- This allows using LuaCheck for the stringified class names in hook parameters.
_G.CLASS = setmetatable({}, {
__index = function(_, key)
return key
end
})
local original_class = class
class = function(class_name, super_name, ...)
local result = original_class(class_name, super_name, ...)
if not rawget(_G, class_name) then
rawset(_G, class_name, result)
end
if not rawget(_G.CLASS, class_name) then
rawset(_G.CLASS, class_name, result)
end
return result
end
require("scripts/main")
log("mod_main", "'scripts/main' loaded")
-- Override `init` to run our injection
function init() function init()
patch_mod_loading_state()
-- As requested by Fatshark
local StateRequireScripts = require("scripts/game_states/boot/state_require_scripts") local StateRequireScripts = require("scripts/game_states/boot/state_require_scripts")
StateRequireScripts._get_is_modded = function() return true end StateRequireScripts._get_is_modded = function() return true end
patch_mod_loading_state()
Main:init() Main:init()
end end