Implement loading non-bundled mods
This commit is contained in:
parent
7b417f8b63
commit
04688ac719
6 changed files with 124 additions and 48 deletions
|
@ -22,27 +22,25 @@ function dmf_mod_object:init()
|
|||
dofile("scripts/mods/dmf/modules/core/misc")
|
||||
dofile("scripts/mods/dmf/modules/core/persistent_tables")
|
||||
dofile("scripts/mods/dmf/modules/core/io")
|
||||
dofile("scripts/mods/dmf/modules/debug/dev_console")
|
||||
dofile("scripts/mods/dmf/modules/debug/table_dump")
|
||||
dofile("scripts/mods/dmf/modules/core/hooks")
|
||||
dofile("scripts/mods/dmf/modules/core/require")
|
||||
dofile("scripts/mods/dmf/modules/core/toggling")
|
||||
dofile("scripts/mods/dmf/modules/core/keybindings")
|
||||
dofile("scripts/mods/dmf/modules/core/chat")
|
||||
dofile("scripts/mods/dmf/modules/core/localization")
|
||||
dofile("scripts/mods/dmf/modules/core/options")
|
||||
dofile("scripts/mods/dmf/modules/core/network")
|
||||
dofile("scripts/mods/dmf/modules/core/commands")
|
||||
dofile("scripts/mods/dmf/modules/gui/custom_textures")
|
||||
dofile("scripts/mods/dmf/modules/gui/custom_views")
|
||||
dofile("scripts/mods/dmf/modules/ui/chat/chat_actions")
|
||||
dofile("scripts/mods/dmf/modules/ui/options/mod_options")
|
||||
dofile("scripts/mods/dmf/modules/dmf_options")
|
||||
dofile("scripts/mods/dmf/modules/core/mutators/mutators_manager")
|
||||
|
||||
dmf = get_mod("DMF")
|
||||
|
||||
dmf:dofile("scripts/mods/dmf/modules/debug/dev_console")
|
||||
dmf:dofile("scripts/mods/dmf/modules/debug/table_dump")
|
||||
dmf:dofile("scripts/mods/dmf/modules/core/hooks")
|
||||
dmf:dofile("scripts/mods/dmf/modules/core/require")
|
||||
dmf:dofile("scripts/mods/dmf/modules/core/toggling")
|
||||
dmf:dofile("scripts/mods/dmf/modules/core/keybindings")
|
||||
dmf:dofile("scripts/mods/dmf/modules/core/chat")
|
||||
dmf:dofile("scripts/mods/dmf/modules/core/localization")
|
||||
dmf:dofile("scripts/mods/dmf/modules/core/options")
|
||||
dmf:dofile("scripts/mods/dmf/modules/core/network")
|
||||
dmf:dofile("scripts/mods/dmf/modules/core/commands")
|
||||
dmf:dofile("scripts/mods/dmf/modules/gui/custom_textures")
|
||||
dmf:dofile("scripts/mods/dmf/modules/gui/custom_views")
|
||||
dmf:dofile("scripts/mods/dmf/modules/ui/chat/chat_actions")
|
||||
dmf:dofile("scripts/mods/dmf/modules/ui/options/mod_options")
|
||||
dmf:dofile("scripts/mods/dmf/modules/dmf_options")
|
||||
dmf:dofile("scripts/mods/dmf/modules/core/mutators/mutators_manager")
|
||||
|
||||
dmf.delayed_chat_messages_hook()
|
||||
end
|
||||
|
||||
|
|
|
@ -95,7 +95,7 @@ local function handle_io(mod, local_path, file_name, file_extension, args, safe_
|
|||
|
||||
-- If this is a safe call, wrap it in a pcall
|
||||
if safe_call then
|
||||
status, result = pcall(function ()
|
||||
status, result = pcall(function()
|
||||
return read_or_execute(file_path, args, return_type)
|
||||
end)
|
||||
|
||||
|
@ -114,15 +114,50 @@ local function handle_io(mod, local_path, file_name, file_extension, args, safe_
|
|||
|
||||
-- If the initial open failed, report failure
|
||||
else
|
||||
mod:error("Error opening '" .. file_path .. "': " .. tostring(err_io))
|
||||
mod:error("Error during I/O: %s\n%s", tostring(err_io), Script.callstack())
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- #####################################################################################################################
|
||||
-- ##### DMFMod ########################################################################################################
|
||||
-- #####################################################################################################################
|
||||
|
||||
-- Use the io library to execute the given file with a pcall, without return
|
||||
function DMFMod:io_exec(local_path, file_name, file_extension, args)
|
||||
return handle_io(self, local_path, file_name, file_extension, args, true, "exec_boolean")
|
||||
end
|
||||
|
||||
-- Use the io library to execute the given file without a pcall, without return
|
||||
function DMFMod:io_exec_unsafe(local_path, file_name, file_extension, args)
|
||||
return handle_io(self, local_path, file_name, file_extension, args, false, "exec_boolean")
|
||||
end
|
||||
|
||||
-- Use the io library to execute the given file with a pcall and return the result
|
||||
function DMFMod:io_exec_with_return(local_path, file_name, file_extension, args)
|
||||
return handle_io(self, local_path, file_name, file_extension, args, true, "exec_result")
|
||||
end
|
||||
|
||||
-- Use the io library to execute the given file without a pcall and return the result
|
||||
function DMFMod:io_exec_unsafe_with_return(local_path, file_name, file_extension, args)
|
||||
return handle_io(self, local_path, file_name, file_extension, args, false, "exec_result")
|
||||
end
|
||||
|
||||
-- Use the io library to execute the given file with a pcall and return the result,
|
||||
-- but treat the first parameter as the entire path to the file, and assume .lua.
|
||||
-- IO version of the dofile method with a pcall.
|
||||
function DMFMod:io_dofile(file_path)
|
||||
return handle_io(self, file_path, nil, nil, nil, true, "exec_result")
|
||||
end
|
||||
|
||||
-- Use the io library to execute the given file without a pcall and return the result,
|
||||
-- but treat the first parameter as the entire path to the file, and assume .lua.
|
||||
-- IO version of the dofile method.
|
||||
function DMFMod:io_dofile_unsafe(file_path)
|
||||
return handle_io(self, file_path, nil, nil, nil, false, "exec_result")
|
||||
end
|
||||
|
||||
-- Use the io library to return the contents of the given file
|
||||
function DMFMod:io_read_content(file_path, file_extension)
|
||||
return handle_io(self, file_path, nil, file_extension, nil, true, "data")
|
||||
|
|
|
@ -35,24 +35,63 @@ end
|
|||
-- ##### DMFMod ########################################################################################################
|
||||
-- #####################################################################################################################
|
||||
|
||||
-- Add a file path to be loaded through io instead of require()
|
||||
--- Loads the given file with the same semantics as Lua's `require`.
|
||||
---
|
||||
--- This provides a unified API for both bundled and non-bundled mods.
|
||||
---
|
||||
--- @param path string The file to load
|
||||
function DMFMod:require(path)
|
||||
local is_bundled = self:get_internal_data("is_bundled")
|
||||
|
||||
if is_bundled then
|
||||
return require(path)
|
||||
else
|
||||
local loaded = self:io_dofile_unsafe(path)
|
||||
if loaded then
|
||||
package.loaded[path] = loaded
|
||||
end
|
||||
return loaded
|
||||
end
|
||||
end
|
||||
|
||||
--- Loads the given file with the same semantics as Lua's `dofile`.
|
||||
---
|
||||
--- This provides a unified API for both bundled and non-bundled mods.
|
||||
---
|
||||
--- @param path string The file to load
|
||||
function DMFMod:dofile(path)
|
||||
local is_bundled = self:get_internal_data("is_bundled")
|
||||
|
||||
if is_bundled then
|
||||
return dofile(path)
|
||||
else
|
||||
return dmf.io_dofile_unsafe(self, path)
|
||||
end
|
||||
end
|
||||
|
||||
-- Add a file path to be loaded through `io` instead of `require`.
|
||||
--
|
||||
-- Certain game systems will be given a path value and then call `require`
|
||||
-- internally, where a mod cannot easily hook and replace the call.
|
||||
--
|
||||
-- This function allows non-bundled mods to inject a file such that these systems
|
||||
-- can `require` them without additional hooks.
|
||||
--
|
||||
-- Bundled mods already have all their files available through regular `require`.
|
||||
function DMFMod:add_require_path(path)
|
||||
add_io_require_path(path)
|
||||
end
|
||||
|
||||
|
||||
-- Remove a file path that was previously loaded through io instead of require()
|
||||
function DMFMod:remove_require_path(path)
|
||||
remove_io_require_path(path)
|
||||
end
|
||||
|
||||
|
||||
-- Get all instances of a file created through require()
|
||||
function DMFMod:get_require_store(path)
|
||||
return get_require_store(path)
|
||||
end
|
||||
|
||||
|
||||
-- Get a file through the original, unhooked require() function
|
||||
function DMFMod:original_require(path, ...)
|
||||
return original_require(path, ...)
|
||||
|
@ -63,7 +102,7 @@ end
|
|||
-- #####################################################################################################################
|
||||
|
||||
-- Handles the swap to io for registered files and the application of file hooks
|
||||
dmf:hook(_G, "require", function (func, path, ...)
|
||||
dmf:hook(_G, "require", function(func, path, ...)
|
||||
if _io_requires[path] then
|
||||
return dmf:dofile(path)
|
||||
else
|
||||
|
|
|
@ -8,21 +8,22 @@ local print = __print
|
|||
-- #####################################################################################################################
|
||||
|
||||
local function pack_pcall(status, ...)
|
||||
return status, {n = select('#', ...), ...}
|
||||
return status, { n = select('#', ...), ... }
|
||||
end
|
||||
|
||||
|
||||
local function print_error_callstack(error_message)
|
||||
if type(error_message) == "table" and error_message.error then
|
||||
print(string.format(
|
||||
"<<Script Error>>%s<</Script Error>>\n<<Lua Stack>>%s<</Lua Stack>>\n<<Lua Locals>>%s<</Lua Locals>>\n<<Lua Self>>%s<</Lua Self>>",
|
||||
error_message.error, error_message.traceback, error_message.locals, error_message.self
|
||||
))
|
||||
local function print_error_callstack(err)
|
||||
if type(err) == "table" and err.error then
|
||||
Log.error(
|
||||
"DMF",
|
||||
"%s\n<<Lua Stack>>%s<</Lua Stack>>\n<<Lua Locals>>%s<</Lua Locals>>\n<<Lua Self>>%s<</Lua Self>>",
|
||||
err.error, err.traceback, err.locals, err.self
|
||||
)
|
||||
else
|
||||
print("Error: " .. tostring(error_message) .. "\n" .. Script.callstack())
|
||||
Log.error("DMF", "Error: %s\n%s", tostring(err), Script.callstack())
|
||||
end
|
||||
|
||||
return error_message
|
||||
return err
|
||||
end
|
||||
|
||||
|
||||
|
@ -45,12 +46,6 @@ function DMFMod:pcall(...)
|
|||
return dmf.safe_call(self, "(pcall)", ...)
|
||||
end
|
||||
|
||||
|
||||
function DMFMod:dofile(file_path)
|
||||
local _, return_values = pack_pcall(dmf.safe_call_dofile(self, "(dofile)", file_path))
|
||||
return unpack(return_values, 1, return_values.n)
|
||||
end
|
||||
|
||||
-- #####################################################################################################################
|
||||
-- ##### DMF internal functions and variables ##########################################################################
|
||||
-- #####################################################################################################################
|
||||
|
@ -65,7 +60,6 @@ function dmf.safe_call(mod, error_prefix_data, func, ...)
|
|||
return success, unpack(return_values, 1, return_values.n)
|
||||
end
|
||||
|
||||
|
||||
-- Safe Call [No return values]
|
||||
function dmf.safe_call_nr(mod, error_prefix_data, func, ...)
|
||||
local success, error_message = xpcall(func, print_error_callstack, ...)
|
||||
|
@ -75,7 +69,6 @@ function dmf.safe_call_nr(mod, error_prefix_data, func, ...)
|
|||
return success
|
||||
end
|
||||
|
||||
|
||||
-- Safe Call [No return values and error callstack]
|
||||
function dmf.safe_call_nrc(mod, error_prefix_data, func, ...)
|
||||
local success, error_message = pcall(func, ...)
|
||||
|
@ -85,7 +78,6 @@ function dmf.safe_call_nrc(mod, error_prefix_data, func, ...)
|
|||
return success
|
||||
end
|
||||
|
||||
|
||||
-- Safe Call [dofile]
|
||||
function dmf.safe_call_dofile(mod, error_prefix_data, file_path)
|
||||
if type(file_path) ~= "string" then
|
||||
|
@ -95,6 +87,14 @@ function dmf.safe_call_dofile(mod, error_prefix_data, file_path)
|
|||
return dmf.safe_call(mod, error_prefix_data, dofile, file_path)
|
||||
end
|
||||
|
||||
-- Safe Call [io_dofile]
|
||||
function dmf.safe_call_io_dofile(mod, error_prefix_data, file_path)
|
||||
if type(file_path) ~= "string" then
|
||||
show_error(mod, error_prefix_data, "file path should be a string.")
|
||||
return false
|
||||
end
|
||||
return dmf.safe_call(mod, error_prefix_data, mod.io_dofile_unsafe, mod, file_path)
|
||||
end
|
||||
|
||||
-- Format error message and throw error.
|
||||
function dmf.throw_error(error_message, ...)
|
||||
|
|
|
@ -24,7 +24,7 @@ function DMFMod:init(mod_name)
|
|||
|
||||
self._data = setmetatable({}, {
|
||||
__index = {},
|
||||
__newindex = function(t_, k)
|
||||
__newindex = function(_, k)
|
||||
self:warning("Attempt to change internal mod data value (\"%s\"). Changing internal mod data is forbidden.", k)
|
||||
end
|
||||
})
|
||||
|
@ -37,7 +37,8 @@ function DMFMod:init(mod_name)
|
|||
local vanilla_mod_data = Managers.mod:mod_data(mod_name)
|
||||
set_internal_data(self, "workshop_id", vanilla_mod_data.id)
|
||||
set_internal_data(self, "workshop_name", vanilla_mod_data.name)
|
||||
set_internal_data(self, "mod_handle", vanilla_mod_data.handle)
|
||||
set_internal_data(self, "mod_handle", vanilla_mod_data.handle)
|
||||
set_internal_data(self, "is_bundled", vanilla_mod_data.bundled or false)
|
||||
|
||||
print(string.format("Init DMF mod '%s' [workshop_name: '%s', workshop_id: %s]", mod_name, vanilla_mod_data.name,
|
||||
vanilla_mod_data.id))
|
||||
|
|
|
@ -50,7 +50,11 @@ local function resolve_resource(mod, error_prefix_data, resource, resource_value
|
|||
local type_value = type(resource_value)
|
||||
|
||||
if type_value == "string" then
|
||||
return dmf.safe_call_dofile(mod, error_prefix_data, resource_value)
|
||||
if mod:get_internal_data("is_bundled") then
|
||||
return dmf.safe_call_dofile(mod, error_prefix_data, resource_value)
|
||||
else
|
||||
return dmf.safe_call_io_dofile(mod, error_prefix_data, resource_value)
|
||||
end
|
||||
elseif type_value == "function" then
|
||||
return dmf.safe_call(mod, error_prefix_data, resource_value, mod)
|
||||
elseif type_value == "table" then
|
||||
|
@ -131,7 +135,6 @@ function new_mod(mod_name, mod_resources)
|
|||
return mod
|
||||
end
|
||||
|
||||
|
||||
function get_mod(mod_name)
|
||||
return _mods[mod_name]
|
||||
end
|
||||
|
|
Loading…
Add table
Reference in a new issue