Reworked mods initialization process.
Reworked 'new_mod' functionality. Reworked pcalls (added error callstack). Got rid of 'mod:initialize', 'mod:initialize_data', 'mod:localization'.
This commit is contained in:
parent
c2dabc69ac
commit
1fbe207930
4 changed files with 202 additions and 82 deletions
|
@ -21,10 +21,6 @@ local function safe_format(mod, str, ...)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function pack_pcall(status, ...)
|
|
||||||
|
|
||||||
return status, {...}
|
|
||||||
end
|
|
||||||
|
|
||||||
local function send_to_chat(message)
|
local function send_to_chat(message)
|
||||||
|
|
||||||
|
@ -96,33 +92,6 @@ function VMFMod:debug(message, ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function VMFMod:pcall(...)
|
|
||||||
local status, values = pack_pcall(pcall(...))
|
|
||||||
|
|
||||||
if not status then
|
|
||||||
self:error("(pcall): %s", tostring(values[1]))
|
|
||||||
end
|
|
||||||
|
|
||||||
return status, unpack(values)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
function VMFMod:dofile(script_path)
|
|
||||||
|
|
||||||
local success, values = pack_pcall(pcall(dofile, script_path))
|
|
||||||
|
|
||||||
if not success then
|
|
||||||
|
|
||||||
if values[1].error then
|
|
||||||
self:error("(dofile): %s", values[1].error)
|
|
||||||
print("\nTRACEBACK:\n\n" .. values[1].traceback .. "\nLOCALS:\n\n" .. values[1].locals)
|
|
||||||
else
|
|
||||||
self:error("(dofile): %s", tostring(values[1]))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return unpack(values)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- ####################################################################################################################
|
-- ####################################################################################################################
|
||||||
-- ##### VMF internal functions and variables #########################################################################
|
-- ##### VMF internal functions and variables #########################################################################
|
||||||
|
|
|
@ -34,28 +34,6 @@ end
|
||||||
-- ##### VMFMod #######################################################################################################
|
-- ##### VMFMod #######################################################################################################
|
||||||
-- ####################################################################################################################
|
-- ####################################################################################################################
|
||||||
|
|
||||||
VMFMod.localization = function (self, path)
|
|
||||||
|
|
||||||
local success, value = pcall(dofile, path)
|
|
||||||
|
|
||||||
if not success then
|
|
||||||
self:error("(localization): %s", value.error)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if type(value) ~= "table" then
|
|
||||||
self:error("(localization): localization file should return table")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if _LOCALIZATION_DATABASE[self:get_name()] then
|
|
||||||
self:warning("(localization): overwritting already loaded localization file")
|
|
||||||
end
|
|
||||||
|
|
||||||
_LOCALIZATION_DATABASE[self:get_name()] = value
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
VMFMod.localize = function (self, text_id, ...)
|
VMFMod.localize = function (self, text_id, ...)
|
||||||
|
|
||||||
local mod_localization_table = _LOCALIZATION_DATABASE[self:get_name()]
|
local mod_localization_table = _LOCALIZATION_DATABASE[self:get_name()]
|
||||||
|
@ -89,8 +67,27 @@ VMFMod.localize = function (self, text_id, ...)
|
||||||
return "<" .. tostring(text_id) .. ">"
|
return "<" .. tostring(text_id) .. ">"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- ####################################################################################################################
|
||||||
|
-- ##### VMF internal functions and variables #########################################################################
|
||||||
|
-- ####################################################################################################################
|
||||||
|
|
||||||
|
vmf.load_mod_localization = function (mod, localization_table)
|
||||||
|
|
||||||
|
if type(localization_table) ~= "table" then
|
||||||
|
mod:error("(localization): localization file should return table")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if _LOCALIZATION_DATABASE[mod:get_name()] then
|
||||||
|
mod:warning("(localization): overwritting already loaded localization file")
|
||||||
|
end
|
||||||
|
|
||||||
|
_LOCALIZATION_DATABASE[mod:get_name()] = localization_table
|
||||||
|
end
|
||||||
|
|
||||||
-- ####################################################################################################################
|
-- ####################################################################################################################
|
||||||
-- ##### Script #######################################################################################################
|
-- ##### Script #######################################################################################################
|
||||||
-- ####################################################################################################################
|
-- ####################################################################################################################
|
||||||
|
|
||||||
vmf:localization("localization/vmf")
|
local localization_table = vmf:dofile("localization/vmf")
|
||||||
|
vmf.load_mod_localization(vmf, localization_table)
|
|
@ -4,29 +4,118 @@ local _MODS = {}
|
||||||
local _MODS_UNLOADING_ORDER = {}
|
local _MODS_UNLOADING_ORDER = {}
|
||||||
|
|
||||||
-- ####################################################################################################################
|
-- ####################################################################################################################
|
||||||
-- ##### Public functions #############################################################################################
|
-- ##### Local functions ##############################################################################################
|
||||||
-- ####################################################################################################################
|
-- ####################################################################################################################
|
||||||
|
|
||||||
function new_mod(mod_name)
|
-- WORKING WITH XPCALL
|
||||||
|
|
||||||
if type(mod_name) ~= "string" then
|
local function pack_pcall(status, ...)
|
||||||
vmf:error("(new_mod): the mod name should be the string, not '%s'", type(mod_name)) -- @EARLY_CALL:
|
return status, {n = select('#', ...), ...}
|
||||||
return nil
|
end
|
||||||
|
|
||||||
|
local function print_error_callstack(error_message)
|
||||||
|
|
||||||
|
if type(error_message) == "table" and error_message.error then
|
||||||
|
error_message = error_message.error
|
||||||
end
|
end
|
||||||
|
|
||||||
|
print("Error: " .. tostring(error_message) .. "\n" .. Script.callstack())
|
||||||
|
return error_message
|
||||||
|
end
|
||||||
|
|
||||||
|
-- CREATING MOD
|
||||||
|
|
||||||
|
local function create_mod(mod_name)
|
||||||
|
|
||||||
if _MODS[mod_name] then
|
if _MODS[mod_name] then
|
||||||
vmf:error("(new_mod): you can't use name \"%s\" for your mod, because the mod with the same name already exists", mod_name) -- @EARLY_CALL:
|
vmf:error("(new_mod): you can't use name \"%s\" for your mod, because " ..
|
||||||
return nil
|
"the mod with the same name already exists.", mod_name)
|
||||||
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
table.insert(_MODS_UNLOADING_ORDER, 1, mod_name)
|
table.insert(_MODS_UNLOADING_ORDER, 1, mod_name)
|
||||||
|
|
||||||
local mod = VMFMod:new(mod_name)
|
local mod = VMFMod:new()
|
||||||
_MODS[mod_name] = mod
|
_MODS[mod_name] = mod
|
||||||
|
|
||||||
|
mod._data = {}
|
||||||
|
mod._data.name = mod_name
|
||||||
|
mod._data.readable_name = mod_name
|
||||||
|
mod._data.is_enabled = true
|
||||||
|
mod._data.is_togglable = false
|
||||||
|
mod._data.is_mutator = false
|
||||||
|
|
||||||
return mod
|
return mod
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- ####################################################################################################################
|
||||||
|
-- ##### Public functions #############################################################################################
|
||||||
|
-- ####################################################################################################################
|
||||||
|
|
||||||
|
function new_mod(mod_name, mod_resources)
|
||||||
|
|
||||||
|
-- Checking for correct arguments
|
||||||
|
if type(mod_name) ~= "string" then
|
||||||
|
vmf:error("(new_mod): the mod name should be the string, not '%s'.", type(mod_name))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if type(mod_resources) ~= "table" then
|
||||||
|
--vmf:error("(new_mod): 'mod_resources' argument should have the 'table' type, not '%s'", type(mod_resources))
|
||||||
|
--return
|
||||||
|
vmf:error("ERROR: '%s' can't be loaded. Wait until its author updates their mod to the newest VMF structure.",
|
||||||
|
mod_name)
|
||||||
|
return {
|
||||||
|
localization = function() end,
|
||||||
|
initialize = function() end
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
if not mod_resources.mod_script then
|
||||||
|
vmf:error("(new_mod): 'mod_resources' table should have 'mod_script' field.", type(mod_name))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Creating a mod object
|
||||||
|
local mod = create_mod(mod_name)
|
||||||
|
if not mod then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Load localization data file
|
||||||
|
if mod_resources.mod_localization then
|
||||||
|
local success, localization_table = vmf.xpcall_dofile(mod, "(new_mod)('mod_localization' initialization)",
|
||||||
|
mod_resources.mod_localization)
|
||||||
|
if success then
|
||||||
|
vmf.load_mod_localization(mod, localization_table)
|
||||||
|
else
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Load mod data file
|
||||||
|
if mod_resources.mod_data then
|
||||||
|
local success, mod_data_table = vmf.xpcall_dofile(mod, "(new_mod)('mod_data' initialization)",
|
||||||
|
mod_resources.mod_data)
|
||||||
|
if success then
|
||||||
|
vmf.initialize_mod_data(mod, mod_data_table)
|
||||||
|
else
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Load mod
|
||||||
|
if not vmf.xpcall_dofile(mod, "(new_mod)('mod_script' initialization)", mod_resources.mod_script) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Initialize mod state
|
||||||
|
if mod:is_togglable() then
|
||||||
|
vmf.initialize_mod_state(mod)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
function get_mod(mod_name)
|
function get_mod(mod_name)
|
||||||
return _MODS[mod_name]
|
return _MODS[mod_name]
|
||||||
end
|
end
|
||||||
|
@ -37,55 +126,120 @@ end
|
||||||
|
|
||||||
VMFMod = class(VMFMod)
|
VMFMod = class(VMFMod)
|
||||||
|
|
||||||
VMFMod.init = function (self, mod_name)
|
|
||||||
self._data = {}
|
|
||||||
-- @TODO: forbid changing _data table
|
|
||||||
self._data.name = mod_name
|
|
||||||
self._data.readable_name = mod_name
|
|
||||||
self._data.is_enabled = true
|
|
||||||
self._data.is_togglable = false
|
|
||||||
self._data.is_mutator = false
|
|
||||||
end
|
|
||||||
|
|
||||||
-- DATA
|
-- DATA
|
||||||
|
|
||||||
VMFMod.get_name = function (self)
|
function VMFMod:get_name()
|
||||||
return self._data.name
|
return self._data.name
|
||||||
end
|
end
|
||||||
|
|
||||||
VMFMod.get_readable_name = function (self)
|
function VMFMod:get_readable_name()
|
||||||
return self._data.readable_name
|
return self._data.readable_name
|
||||||
end
|
end
|
||||||
|
|
||||||
VMFMod.get_description = function (self)
|
function VMFMod:get_description()
|
||||||
return self._data.description
|
return self._data.description
|
||||||
end
|
end
|
||||||
|
|
||||||
VMFMod.is_enabled = function (self)
|
function VMFMod:is_enabled()
|
||||||
return self._data.is_enabled
|
return self._data.is_enabled
|
||||||
end
|
end
|
||||||
|
|
||||||
VMFMod.is_togglable = function (self)
|
function VMFMod:is_togglable()
|
||||||
return self._data.is_togglable
|
return self._data.is_togglable
|
||||||
end
|
end
|
||||||
|
|
||||||
VMFMod.is_mutator = function (self)
|
function VMFMod:is_mutator()
|
||||||
return self._data.is_mutator
|
return self._data.is_mutator
|
||||||
end
|
end
|
||||||
|
|
||||||
VMFMod.get_config = function (self)
|
function VMFMod:get_config()
|
||||||
return self._data.config
|
return self._data.config
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- CORE FUNCTIONS
|
||||||
|
|
||||||
|
function VMFMod:pcall(...)
|
||||||
|
return vmf.xpcall(self, "(pcall)", ...)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function VMFMod:dofile(file_path)
|
||||||
|
local _, return_values = pack_pcall(vmf.xpcall_dofile(self, "(dofile)", file_path))
|
||||||
|
return unpack(return_values, 1, return_values.n)
|
||||||
|
end
|
||||||
|
|
||||||
-- ####################################################################################################################
|
-- ####################################################################################################################
|
||||||
-- ##### VMF Initialization ###########################################################################################
|
-- ##### VMF Initialization ###########################################################################################
|
||||||
-- ####################################################################################################################
|
-- ####################################################################################################################
|
||||||
|
|
||||||
vmf = new_mod("VMF")
|
vmf = create_mod("VMF")
|
||||||
|
|
||||||
-- ####################################################################################################################
|
-- ####################################################################################################################
|
||||||
-- ##### VMF internal functions and variables #########################################################################
|
-- ##### VMF internal functions and variables #########################################################################
|
||||||
-- ####################################################################################################################
|
-- ####################################################################################################################
|
||||||
|
|
||||||
|
-- XPCALL
|
||||||
|
|
||||||
|
function vmf.xpcall(mod, error_prefix, func, ...)
|
||||||
|
|
||||||
|
local success, return_values = pack_pcall(xpcall(func, print_error_callstack, ...))
|
||||||
|
|
||||||
|
if not success then
|
||||||
|
mod:error("%s: %s", error_prefix, return_values[1])
|
||||||
|
return success
|
||||||
|
end
|
||||||
|
|
||||||
|
return success, unpack(return_values, 1, return_values.n)
|
||||||
|
end
|
||||||
|
|
||||||
|
function vmf.xpcall_no_return_values(mod, error_prefix, func, ...)
|
||||||
|
|
||||||
|
local success, error_message = xpcall(func, print_error_callstack, ...)
|
||||||
|
|
||||||
|
if not success then
|
||||||
|
mod:error("%s: %s", error_prefix, error_message)
|
||||||
|
end
|
||||||
|
|
||||||
|
return success
|
||||||
|
end
|
||||||
|
|
||||||
|
function vmf.xpcall_dofile(mod, error_prefix, file_path)
|
||||||
|
|
||||||
|
if type(file_path) ~= "string" then
|
||||||
|
mod:error("%s: file path should be a string.", error_prefix)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
return vmf.xpcall(mod, error_prefix, dofile, file_path)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- MOD DATA INITIALIZATION
|
||||||
|
|
||||||
|
function vmf.initialize_mod_data(mod, mod_data)
|
||||||
|
|
||||||
|
if type(mod_data) ~= "table" then
|
||||||
|
mod:error("(new_mod)(mod_data initialization): mod_data file should return a 'table' value.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if mod_data.name then
|
||||||
|
mod._data.readable_name = mod_data.name
|
||||||
|
end
|
||||||
|
mod._data.description = mod_data.description
|
||||||
|
mod._data.is_togglable = mod_data.is_togglable or mod_data.is_mutator
|
||||||
|
mod._data.is_mutator = mod_data.is_mutator
|
||||||
|
|
||||||
|
if mod_data.is_mutator then
|
||||||
|
vmf.register_mod_as_mutator(mod, mod_data.mutator_settings)
|
||||||
|
end
|
||||||
|
|
||||||
|
if mod_data.options_widgets or (mod_data.is_togglable and not mod_data.is_mutator) then
|
||||||
|
vmf.create_options(mod, mod_data.options_widgets)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- VARIABLES
|
||||||
|
|
||||||
vmf.mods = _MODS
|
vmf.mods = _MODS
|
||||||
vmf.mods_unloading_order = _MODS_UNLOADING_ORDER
|
vmf.mods_unloading_order = _MODS_UNLOADING_ORDER
|
|
@ -270,7 +270,7 @@ end
|
||||||
-- ##### Script #######################################################################################################
|
-- ##### Script #######################################################################################################
|
||||||
-- ####################################################################################################################
|
-- ####################################################################################################################
|
||||||
|
|
||||||
vmf:initialize_data(vmf_mod_data)
|
vmf.initialize_mod_data(vmf, vmf_mod_data)
|
||||||
|
|
||||||
-- first VMF initialization
|
-- first VMF initialization
|
||||||
-- it will be run only 1 time, when the player launch the game with VMF for the first time
|
-- it will be run only 1 time, when the player launch the game with VMF for the first time
|
||||||
|
|
Loading…
Add table
Reference in a new issue