207 lines
7.8 KiB
Plaintext
207 lines
7.8 KiB
Plaintext
--[[
|
|
DYNAMIC ZONE
|
|
|
|
Original Author(s)
|
|
Singustromo <singustromo at disroot.org>
|
|
|
|
Edited by
|
|
|
|
License
|
|
Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)
|
|
(https://creativecommons.org/licenses/by-nc-sa/4.0)
|
|
|
|
--]]
|
|
|
|
parent = _G["dynamic_zone"]
|
|
if not (parent and parent.VERSION and parent.VERSION >= 20241224) then return end
|
|
|
|
local opt = dynamic_zone_mcm
|
|
local utils = dynamic_zone_utils
|
|
|
|
------------------------------------------
|
|
-- Global Variables & Constants --
|
|
------------------------------------------
|
|
|
|
CONST_BLOCKSTATECHANGE_NOTIFY_DELAY_MS = 100
|
|
CONST_LOGGING_PREFIX = "[DZT]" -- used for console logging
|
|
|
|
valid_logging_channels = { def = "INFO", info = "INFO", warning = "WARNING", error = "ERROR" }
|
|
registered_logging_channels = { --[[
|
|
info = instance,
|
|
warning = instance,
|
|
...
|
|
--]] }
|
|
|
|
local log_mcm
|
|
|
|
---------------------
|
|
-- Callbacks --
|
|
---------------------
|
|
|
|
function on_game_start()
|
|
RegisterScriptCallback("on_game_load", inject_debug_commands)
|
|
RegisterScriptCallback("dynzone_changed_block_state", dynzone_changed_block_state)
|
|
|
|
-- Due to this, functors called before creating those instances will log to xray console
|
|
log_mcm = log_register("info", "Debug")
|
|
create_logging_instances()
|
|
end
|
|
|
|
function inject_debug_commands()
|
|
-- no need, if not enabled. Idk if it would even break something
|
|
if not (DEV_DEBUG or DEV_DEBUG_DEV) then return end
|
|
|
|
local CMD = debug_cmd_list.command_get_list()
|
|
|
|
function CMD.dynamic_zone(_, __, x)
|
|
x:SendOutput("/ DYNAMIC ZONE " .. parent.VERSION_STRING)
|
|
parent.main_routine{ force = true }
|
|
end
|
|
|
|
function CMD.dynamic_zone_accessible(_, __, x)
|
|
x:SendOutput("- Reset all route states!")
|
|
parent.addon_safe_removal()
|
|
end
|
|
|
|
ui_debug_launcher.inject("action", { name = "[DYNZONE] Trigger",
|
|
cmd = "dynamic_zone", hide_ui = 2, key = "DIK_D" } )
|
|
ui_debug_launcher.inject("action", { name = "[DYNZONE] Clear routes",
|
|
cmd = "dynamic_zone_accessible", hide_ui = 2 } )
|
|
end
|
|
|
|
-- Just informs us about the exact block state
|
|
-- A bit hacky to prevent recursive referencing
|
|
function dynzone_changed_block_state(previous, current)
|
|
if (not opt.get("verbose")) then
|
|
UnregisterScriptCallback("dynzone_changed_block_state", dynzone_changed_block_state)
|
|
end
|
|
|
|
-- We only use it in this function, to prevent recursive referencing
|
|
local route_manager = dynamic_zone_routes
|
|
|
|
-- Done this way, so it shows the updated values changed by other functions
|
|
utils.timed_call(CONST_BLOCKSTATECHANGE_NOTIFY_DELAY_MS, function(previous, current)
|
|
local output_str = "Previously Blocked routes:"
|
|
for route_id, _ in pairs(previous) do
|
|
output_str = output_str .. "\n" .. route_manager.route_tostring(route_id, true)
|
|
end
|
|
if (size_table(previous) > 0) then
|
|
log_mcm("%s\nA total of %s routes were blocked.",
|
|
output_str, size_table(previous))
|
|
end
|
|
|
|
local output_str = "Newly Blocked routes:"
|
|
for route_id, _ in pairs(current) do
|
|
output_str = output_str .. "\n" .. route_manager.route_tostring(route_id, true)
|
|
end
|
|
if (size_table(current) > 0) then
|
|
log_mcm("%s\nA total of %s routes are freshly blocked.",
|
|
output_str, size_table(current))
|
|
end
|
|
|
|
local blocked, discovered = 0, 0
|
|
for route_id, route in route_manager.iterate_routes(true) do
|
|
blocked = (route.blocked) and (blocked +1) or blocked
|
|
discovered = (route.block_discovered) and (discovered +1) or discovered
|
|
end
|
|
log_mcm("A total of %s routes are blocked (%s discovered)", blocked, discovered)
|
|
|
|
return true
|
|
end, previous, current)
|
|
end
|
|
|
|
---------------------------
|
|
-- Debugging --
|
|
---------------------------
|
|
|
|
-- These are mainly used by this script or others where it is more suited than mcm logging
|
|
function log(message, ...)
|
|
if (not opt.get("verbose")) then return end
|
|
local args = {...}
|
|
|
|
local output = string.format("%s %s", CONST_LOGGING_PREFIX, message)
|
|
printf(output, unpack(args))
|
|
end
|
|
|
|
-- These two are more important, thus are always logged to console.
|
|
function log_warn(message, ...)
|
|
local args = {...}
|
|
local output = string.format("~%s %s", CONST_LOGGING_PREFIX, message)
|
|
printf(output, unpack(args))
|
|
end
|
|
|
|
function log_error(message, ...)
|
|
local args = {...}
|
|
local output = string.format("!%s %s", CONST_LOGGING_PREFIX, message)
|
|
printf(output, unpack(args))
|
|
end
|
|
|
|
-- REQUIRES MOD-CONFIGURATION-MENU (MCM)
|
|
-- We only create logging instances `on_game_start`, so we don't load mcm_log earlier than necessary.
|
|
function create_logging_instances()
|
|
if (_g.is_empty(registered_logging_channels)) then
|
|
return
|
|
elseif not (mcm_log and mcm_log.new) then
|
|
log_warn("MCM Logging utility not found. Falling back to console logging.")
|
|
return
|
|
end
|
|
|
|
for channelname, value in pairs(registered_logging_channels) do
|
|
if (type(value) == "userdata") then goto continue end
|
|
|
|
local logger = mcm_log and mcm_log.new and mcm_log.new(channelname)
|
|
if (not logger) then
|
|
log_warn("Unable to create a MCM logging instance! Falling back to console logging.")
|
|
callstack()
|
|
return
|
|
end
|
|
|
|
logger.continuous = true
|
|
logger.enabled = true
|
|
registered_logging_channels[channelname] = logger
|
|
|
|
:: continue ::
|
|
end
|
|
end
|
|
|
|
-- Called like this: e.g. log_info = debug.log_register("info", "Anomalies")
|
|
-- will only return function that prints to logs, when verbose setting is active
|
|
-- Will log via the MCM utility, only to console as fallback
|
|
-- Using string.format to be able to use same rules as ISO C sprintf
|
|
-- @param channelname logging level - defaults to info, if invalid
|
|
-- @param identifier optional
|
|
-- @returns pointer to logging function which uses mcm logging, when available
|
|
function log_register(channelname, identifier)
|
|
if (not channelname) then return end
|
|
|
|
identifier = identifier and string.upper(identifier)
|
|
channelname = valid_logging_channels[string.lower(channelname)]
|
|
or valid_logging_channels.def
|
|
|
|
registered_logging_channels[channelname] = true
|
|
local id_prefix = (identifier and type(identifier == "string"))
|
|
and (" - " .. identifier) or ""
|
|
|
|
return function(message, ...)
|
|
if (not opt.get("verbose")) then return end
|
|
local data = { channel = channelname, id = id_prefix }
|
|
|
|
local logger = (type(registered_logging_channels[data.channel]) ~= "boolean")
|
|
and registered_logging_channels[data.channel]
|
|
|
|
-- Fallback for e.g. before `on_game_start` or if `mcm_log` does not exist
|
|
if not (logger and logger.log) then
|
|
printf(string.format(CONST_LOGGING_PREFIX .. message, ...))
|
|
return
|
|
end
|
|
|
|
local default_prefix = logger.prefix
|
|
if (data.id and data.id ~= "") then
|
|
logger.prefix = logger.prefix .. data.id
|
|
end
|
|
|
|
logger:log(string.format(message, ...))
|
|
logger.prefix = default_prefix
|
|
end
|
|
end
|