Darktide Mod Manager #39

Merged
lucas merged 91 commits from feat/dtmm into master 2023-03-01 22:27:42 +01:00
Showing only changes of commit be1cff9f3c - Show all commits

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,28 +11,14 @@ 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 StateBootSubStateBase = require("scripts/game_states/boot/state_boot_sub_state_base")
local libs = {
io = io,
debug = debug,
ffi = ffi,
os = os,
load = load,
loadfile = loadfile,
loadstring = loadstring,
}
require("scripts/main") -- A necessary override.
log("mod_main", "'scripts/main' loaded") -- The original does not proxy `dt` to `_state_update`, but we need that.
StateBootSubStateBase.update = function (self, dt)
local StateBootSubStateBase = require("scripts/game_states/boot/state_boot_sub_state_base")
-- A necessary override.
-- The original does not proxy `dt` to `_state_update`, but we need that.
StateBootSubStateBase.update = function (self, dt)
local done, error = self:_state_update(dt) local done, error = self:_state_update(dt)
local params = self._params local params = self._params
@ -45,11 +35,11 @@ StateBootSubStateBase.update = function (self, dt)
self._parent:sub_states_done() self._parent:sub_states_done()
end end
end end
end end
local StateBootLoadMods = class("StateBootLoadMods", "StateBootSubStateBase") local StateBootLoadMods = class("StateBootLoadMods", "StateBootSubStateBase")
StateBootLoadMods.on_enter = function (self, parent, params) StateBootLoadMods.on_enter = function (self, parent, params)
log("StateBootLoadMods", "Entered") log("StateBootLoadMods", "Entered")
StateBootLoadMods.super.on_enter(self, parent, params) StateBootLoadMods.super.on_enter(self, parent, params)
@ -62,9 +52,9 @@ StateBootLoadMods.on_enter = function (self, parent, params)
["packages/mods"] = package_manager:load("packages/mods", "StateBootLoadMods", nil), ["packages/mods"] = package_manager:load("packages/mods", "StateBootLoadMods", nil),
["packages/dml"] = package_manager:load("packages/dml", "StateBootLoadMods", nil), ["packages/dml"] = package_manager:load("packages/dml", "StateBootLoadMods", nil),
} }
end end
StateBootLoadMods._state_update = function (self, dt) StateBootLoadMods._state_update = function (self, dt)
local state = self._state local state = self._state
local package_manager = self._package_manager local package_manager = self._package_manager
@ -75,19 +65,15 @@ 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
end end
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