Updated hotpatch

This commit is contained in:
Daniel Vestøl committed 2019-03-13 20:13:03 +01:00
1 parent a3e33f6164
commit a2be560b8b
6 files changed
+244 -206

No files matched your search

+1 -1
View File
@@ -98,7 +98,7 @@ files['testfolder.test'] = [===[
]===]
files['test'] = [===[
require 'testfolder.test'
require 'testfolder.test'
]===]
hotpatch_tools.static_mod('require-test', '1.0.0', [===[
+5 -5
View File
@@ -61,11 +61,11 @@ sub_commands = {
if (not param) or (param == '') then
caller.print('Usage: /hotpatch [command] [parameters]')
caller.print('Available commands:')
for k, v in pairs(sub_commands) do caller.print(k) end
for k, _ in pairs(sub_commands) do caller.print(k) end
caller.print('Use /hotpatch help [command] for help on a particular command')
else
local text = help_commands[param]
if text then
if text then
caller.print(text)
end
end
@@ -82,7 +82,7 @@ sub_commands = {
caller.print(table.concat{'[', k, '] ', v.name, ' ', v.version, ' ', (v.loaded and 'loaded') or 'not loaded', ' ', (v.running and 'running') or 'not running'})
end
else
end
end,
}
@@ -113,7 +113,7 @@ local admin_commands = {
_ENV.commands.add_command('hotpatch', 'Commands for hotpatch. Run /hotpatch help for details.', function(e)
local caller = (e.player_index and game.players[e.player_index]) or console
if (not e.parameter) or (e.parameter == '') then
if (not e.parameter) or (e.parameter == '') then
sub_commands['help'](e.player_index)
return
end
@@ -130,6 +130,6 @@ _ENV.commands.add_command('hotpatch', 'Commands for hotpatch. Run /hotpatch help
end
end)
]===])
--]===])
return true
+68 -66
View File
@@ -55,26 +55,26 @@ script.on_event(defines.events.on_player_joined_game, function(e)
local top = mod_gui.get_button_flow(player)
local left = mod_gui.get_frame_flow(player)
local center = player.gui.center
local button = top['hotpatch-button']
if button then
button.destroy()
end
local menu = left['hotpatch-menu']
if menu then
if menu then
menu.destroy()
end
local IDE = center['hotpatch-IDE']
if IDE then
if IDE then
IDE.destroy()
end
local main = center['hotpatch-main']
if main then
if main then
main.destroy()
end
button = top.add{type = 'sprite-button', name = 'hotpatch-button', sprite='utility/heat_exchange_indication', tooltip = 'Hotpatch', style = mod_gui.button_style}
end)
@@ -89,26 +89,26 @@ on_gui_click_handlers = {
local top = mod_gui.get_button_flow(player)
local left = mod_gui.get_frame_flow(player)
local center = player.gui.center
local menu = left['hotpatch-menu']
if not menu then
menu = left.add{type = 'frame', name = 'hotpatch-menu', direction = 'vertical'}
menu.add{type = 'button', name = 'hotpatch-menu.IDE', caption = 'Mod IDE', tooltip = 'Open debugging GUI'}
menu.add{type = 'button', name = 'hotpatch-menu.console', caption = 'Mod Console', tooltip = 'Open debugging console'}
menu.style.visible = true
menu.visible = true
return
end
menu.style.visible = not menu.style.visible
menu.visible = not menu.visible
end,
['hotpatch-menu'] = function(e)
local player = game.players[e.player_index]
local top = mod_gui.get_button_flow(player)
local left = mod_gui.get_frame_flow(player)
local center = player.gui.center
local menu = left['hotpatch-menu']
menu.style.visible = not menu.style.visible
menu.visible = not menu.visible
on_gui_click_handlers[e.element.name](e)
end,
['hotpatch-menu.IDE'] = function(e)
@@ -116,7 +116,7 @@ on_gui_click_handlers = {
local top = mod_gui.get_button_flow(player)
local left = mod_gui.get_frame_flow(player)
local center = player.gui.center
local IDE = center['hotpatch-IDE']
if not IDE then
IDE = center.add{type = 'frame', name = 'hotpatch-IDE', direction = 'vertical', caption = 'Hotpatch IDE', style = mod_gui.frame_style}
@@ -132,22 +132,22 @@ on_gui_click_handlers = {
local code = IDE_table.add{type = 'text-box', name = 'hotpatch-IDE-code'}
code.word_wrap = true
files.style.width = 400
files.style.cell_spacing = 0
files.style.cell_padding = 0
files.style.top_padding = 0
files.style.bottom_padding = 0
code.style.width = 600
code.style.height = 600
IDE.style.visible = false
IDE.visible = false
end
local IDE_dropdown = IDE['hotpatch-IDE-top']['hotpatch-IDE-mod-selector']
IDE_dropdown.clear_items()
for k, v in ipairs(installed_mods) do
for _, v in ipairs(installed_mods) do
IDE_dropdown.add_item(v.name)
end
IDE.style.visible = not IDE.style.visible
if IDE.style.visible then
IDE.visible = not IDE.visible
if IDE.visible then
player.opened = IDE
else
player.opened = nil
@@ -158,15 +158,15 @@ on_gui_click_handlers = {
local top = mod_gui.get_button_flow(player)
local left = mod_gui.get_frame_flow(player)
local center = player.gui.center
local console = center['hotpatch-console']
if not console then
console = center.add{type = 'frame', name = 'hotpatch-console', direction = 'vertical', caption = 'Hotpatch Console'}
local top_flow = console.add{type = 'flow', name = 'hotpatch-console-top', direction = 'horizontal'}
local hotpatch_console = center['hotpatch-console']
if not hotpatch_console then
hotpatch_console = center.add{type = 'frame', name = 'hotpatch-console', direction = 'vertical', caption = 'Hotpatch Console'}
local top_flow = hotpatch_console.add{type = 'flow', name = 'hotpatch-console-top', direction = 'horizontal'}
top_flow.add{type = 'label', name = 'hotpatch-console-mod-label', caption = 'Mod: '}
local console_dropdown = top_flow.add{type = 'drop-down', name = 'hotpatch-console-mod-selector'}
top_flow.add{type = 'label', name = 'hotpatch-console-mod-version', caption = 'Version: No mod selected'}
local bottom_flow = console.add{type = 'flow', name = 'hotpatch-console-bottom', direction = 'vertical'}
local bottom_flow = hotpatch_console.add{type = 'flow', name = 'hotpatch-console-bottom', direction = 'vertical'}
local output = bottom_flow.add{type = 'text-box', name = 'hotpatch-console-output'}
local bottom_input_flow = bottom_flow.add{type = 'flow', name = 'hotpatch-console-bottom-input', direction = 'horizontal'}
local input = bottom_input_flow.add{type = 'textfield', name = 'hotpatch-console-input'}
@@ -174,53 +174,54 @@ on_gui_click_handlers = {
output.style.width = 800
output.style.height = 600
input.style.width = 600
hotpatch_console.visible = false
end
local console_dropdown = console['hotpatch-console-top']['hotpatch-console-mod-selector']
local console_dropdown = hotpatch_console['hotpatch-console-top']['hotpatch-console-mod-selector']
console_dropdown.clear_items()
for k, v in ipairs(loaded_mods) do
for _, v in ipairs(loaded_mods) do
console_dropdown.add_item(v.name)
end
console.style.visible = not console.style.visible
if console.style.visible then
player.opened = console
hotpatch_console.visible = not hotpatch_console.visible
if hotpatch_console.visible then
player.opened = hotpatch_console
else
player.opened = nil
end
end,
['hotpatch-console-run'] = function(e)
local player = game.players[e.player_index]
local top = mod_gui.get_button_flow(player)
local left = mod_gui.get_frame_flow(player)
local center = player.gui.center
local console = center['hotpatch-console']
local output = console['hotpatch-console-bottom']['hotpatch-console-output']
local input = console['hotpatch-console-bottom']['hotpatch-console-bottom-input']['hotpatch-console-input']
local console_dropdown = console['hotpatch-console-top']['hotpatch-console-mod-selector']
local hotpatch_console = center['hotpatch-console']
local output = hotpatch_console['hotpatch-console-bottom']['hotpatch-console-output']
local input = hotpatch_console['hotpatch-console-bottom']['hotpatch-console-bottom-input']['hotpatch-console-input']
local console_dropdown = hotpatch_console['hotpatch-console-top']['hotpatch-console-mod-selector']
if not player.admin then
output.text = table.concat{output.text, '\n', 'Only admins!'}
return
end
if not (console_dropdown.selected_index > 0) then
output.text = table.concat{output.text, '\n', 'Select a mod!'}
return
end
local mod_name = console_dropdown.items[console_dropdown.selected_index]
local loaded_index = find_loaded_mod(mod_name)
local env = loaded_mods[loaded_index].env
local old_print = env.print
local old_log = env.log
env.print = function(...)
--local count = select('#', ...)
local t = table.pack(...)
@@ -230,21 +231,22 @@ on_gui_click_handlers = {
local text = table.concat(t, '\t')
output.text = table.concat{output.text, '\n', text}
end
env.log = function(text)
output.text = table.concat{output.text, '\n', text}
end
local success
local code, err = load(input.text, input.text, 't', env)
if code then
local success, err = pcall(code)
if code then
success, err = pcall(code)
if not success then
output.text = table.concat{output.text, '\n', err}
end
else
output.text = table.concat{output.text, '\n', err}
end
env.print = old_print
env.log = old_log
end,
@@ -253,10 +255,10 @@ on_gui_click_handlers = {
local top = mod_gui.get_button_flow(player)
local left = mod_gui.get_frame_flow(player)
local center = player.gui.center
local element = e.element
local previous
for k, v in pairs(center['hotpatch-IDE']['hotpatch-IDE-table']['hotpatch-IDE-files']['hotpatch-IDE-files-table'].children) do
for _, v in pairs(center['hotpatch-IDE']['hotpatch-IDE-table']['hotpatch-IDE-files']['hotpatch-IDE-files-table'].children) do
if table.compare(v.style.font_color or {}, {r=1.0, g=1.0, b=0.0, a=1.0}) then
previous = v
break
@@ -297,7 +299,7 @@ on_gui_selection_state_changed_handlers = {
local top = mod_gui.get_button_flow(player)
local left = mod_gui.get_frame_flow(player)
local center = player.gui.center
local element = e.element
local name = element.items[element.selected_index]
if name then
@@ -306,8 +308,8 @@ on_gui_selection_state_changed_handlers = {
local mod = loaded_mods[index]
local version_label = center['hotpatch-console']['hotpatch-console-top']['hotpatch-console-mod-version']
version_label.caption = 'Version: ' .. mod.version
local console = center['hotpatch-console']
local output = console['hotpatch-console-bottom']['hotpatch-console-output']
local hotpatch_console = center['hotpatch-console']
local output = hotpatch_console['hotpatch-console-bottom']['hotpatch-console-output']
output.text = ''
end
end
@@ -317,9 +319,9 @@ on_gui_selection_state_changed_handlers = {
local top = mod_gui.get_button_flow(player)
local left = mod_gui.get_frame_flow(player)
local center = player.gui.center
local element = e.element
local name = element.items[element.selected_index]
if name then
local index = find_installed_mod(name)
@@ -332,7 +334,7 @@ on_gui_selection_state_changed_handlers = {
local file = list.add{type = 'label', style = 'hoverable_bold_label', caption = 'control', name = 'hotpatch-IDE-file.control'}
file.style.bottom_padding = 0
file.style.top_padding = 0
for k, v in pairs(mod.files) do
for k, _ in pairs(mod.files) do
file = list.add{type = 'label', style = 'hoverable_bold_label', caption = k, name = 'hotpatch-IDE-file.' .. k}
file.style.bottom_padding = 0
file.style.top_padding = 0
@@ -356,20 +358,20 @@ script.on_event(defines.events.on_gui_closed, function(e)
if e.gui_type == defines.gui_type.custom then
if element and element.valid then
if element.name == 'hotpatch-IDE' then
if element.style.visible then
if element.visible then
player.play_sound{path = "utility/gui_click"}
end
element.style.visible = false
element.visible = false
elseif element.name == 'hotpatch-console' then
if element.style.visible then
if element.visible then
player.play_sound{path = "utility/gui_click"}
end
element.style.visible = false
element.visible = false
end
end
end
end)
]===])
--]===])
return true
+114 -111
View File
@@ -67,7 +67,7 @@ local mod_obj_template = {
}
-- this is for the core factorio libraries; hotpatch MUST load these now, as they cannot be dynamically loaded due to factorio limitation
local loaded_libraries = {}
local loaded_libraries = {}
-- mod installation/uninstallation support functions
-- These take a mod NAME as a first argument
@@ -101,6 +101,8 @@ local mod_on_configuration_changed
local on_event
local on_nth_tick
local register_all_events
-- core handlers
local on_init -- installs static mods, loads, runs, and calls mod_on_init
local on_load -- loads, runs, and calls mod_on_load
@@ -222,12 +224,12 @@ local function build_locale(ini)
local t = {}
local section = ''
local temp
-- line must end with a linefeed - single line file with no LF will fail
if not ini:match('[\r\n]+$') then
ini = ini .. '\n'
end
-- for each non-empty line do
local key, value
for l in ini:gmatch('[\r\n]*(.-)[\r\n]+') do
@@ -261,7 +263,7 @@ local function static_translate(t, recursive)
-- only translate tables that have a string as the first item
local k = t[1]
if type(k) ~= 'string' then return t end
-- make a copy, don't destroy the original table, after we copy we can translate in place
if not recursive then
t = table.deepcopy(t)
@@ -285,12 +287,12 @@ local function static_translate(t, recursive)
-- substitution of parameters: use literal value of parameter n
-- __n__
local result = (pattern:gsub('__(%d+)__', function(s) return tostring(t[tonumber(s)+1]) end))
-- re-substitution engine: match value of parameter n to provide additional translation; use for pluralization
-- __n:(pattern-1)=substitution-1;(pattern-2)=substitution-2;...(pattern-i)=substitution-i;__
for n, p in result:gmatch('__(%d+)(:.-;)__') do
for x, y in p:gmatch('%((.-)%)=(.-[^%%]);') do
if t[tonumber(n)+1]:match(x) then
if t[tonumber(n)+1]:match(x) then
result = result:gsub(table.concat{'__', n, escape(p), '__'}, unescape(y))
break
end
@@ -324,7 +326,7 @@ local hidden_log = hidden(static_translate)
-- logs localized data
local function debug_log(message, mod_name, stack_level)
if debug_level > -1 then
if debug_level > -1 then
if not stack_level then stack_level = 2 end
local di = debug.getinfo(stack_level)
local line = di.currentline
@@ -363,7 +365,7 @@ debug_log({'hotpatch-info.logging-enabled'})
-- track _ENV accesses
setmetatable(_ENV, {
__index = function(t, k)
__index = function(_, k)
debug_log({'hotpatch-trace.nil-var-access', k}, nil, 3)
return nil
end,
@@ -428,14 +430,14 @@ uninstall_mod = function(mod_name)
return
end
local loaded_index = find_loaded_mod(mod_name)
if loaded_index then
unload_mod(loaded_index)
end
debug_log({'hotpatch-info.uninstalling', mod_name})
table.remove(global.mods, index)
end
@@ -446,7 +448,7 @@ install_mod_file = function(mod_name, mod_file, mod_file_code)
return
end
local mod = global.mods[index]
debug_log({'hotpatch-info.installing-file', mod_file}, mod_name)
mod_file = mod_file:gsub('/', '.')
@@ -474,7 +476,7 @@ install_mod = function(mod_name, mod_version, mod_code, mod_files)
end
debug_log({'hotpatch-warning.contains-comments-console'}, mod_name)
end
mod_code = mod_code:gsub('\t', ' ')
mod.name = mod_name
@@ -482,7 +484,7 @@ install_mod = function(mod_name, mod_version, mod_code, mod_files)
mod.code = mod_code
mod.version = mod_version
mod.global = mod.global or {}
if mod_files then
for k,v in pairs(mod_files) do
install_mod_file(mod_name, k, v)
@@ -500,7 +502,7 @@ load_mod = function(installed_index)
--TODO notify that mod was already loaded
unload_mod(loaded_index)
end
local mod_obj = {
name = mod_name, -- name of the current mod
version = mod.version,
@@ -515,7 +517,7 @@ load_mod = function(installed_index)
on_nth_tick = {}, -- list of on_nth_tick handlers registered
loaded_files = {}, -- list of files loaded by require() that were installed into the virtual file system
}
debug_log({'hotpatch-info.script-shim'}, mod_name)
--mods private script table/shim
local mod_script = {}
@@ -540,7 +542,7 @@ load_mod = function(installed_index)
mod_script.on_nth_tick = function(tick, f)
if tick then
if type(tick) == 'table' then
for k, v in pairs(tick) do
for _, v in pairs(tick) do
mod_script.on_nth_tick(v, f)
end
return
@@ -550,12 +552,12 @@ load_mod = function(installed_index)
mod_obj.on_nth_tick = {}
end
end
else
else
mod_script.on_event = function(event, f)
if event == defines.events.on_tick then
mod_obj.on_tick = f
if mod_obj.running then
register_on_tick(mod_name, event)
register_on_tick(mod_name)
end
else
mod_obj.on_event[event] = f
@@ -567,7 +569,7 @@ load_mod = function(installed_index)
mod_script.on_nth_tick = function(tick, f)
if tick then
if type(tick) == 'table' then
for k, v in pairs(tick) do
for _, v in pairs(tick) do
mod_script.on_nth_tick(v, f)
end
return
@@ -577,11 +579,11 @@ load_mod = function(installed_index)
register_nth_tick(mod_name, tick)
end
else
local on_nth_tick = mod_obj.on_nth_tick
local mod_on_nth_tick = mod_obj.on_nth_tick
mod_obj.on_nth_tick = {}
if mod_obj.running then
for k, v in pairs(on_nth_tick) do
register_nth_tick(mod_name, tick)
for _, v in pairs(mod_on_nth_tick) do
register_nth_tick(mod_name, v)
end
end
end
@@ -603,7 +605,7 @@ load_mod = function(installed_index)
mod_script.mod_name = function()
return script.mod_name()
end
debug_log({'hotpatch-info.setting-env'}, mod_name)
-- mods private env
local env = mod_obj.env
@@ -620,20 +622,20 @@ load_mod = function(installed_index)
loaded[k] = v
end
loaded._G = env
-- so many ways to escape sandboxes...
for k,v in pairs(_ENV.package) do
pack[k] = v
end
pack.loaded = loaded
env.package = pack
loaded.package = pack
env.script = mod_script
env.global = mod.global
env._G = env
env['remote'] = {
add_interface = function(name, functions)
if remote.interfaces[name] then
@@ -649,7 +651,7 @@ load_mod = function(installed_index)
return remote.call(...)
end,
interfaces = setmetatable({}, {
__index = function(t, k) return remote.interfaces[k] end,
__index = function(_, k) return remote.interfaces[k] end,
__pairs = function(t) local function iter(t, k) local v; k, v = next(remote.interfaces, k); if v then return k, t[k] end; end; return iter, t, nil end
})
}
@@ -665,16 +667,16 @@ load_mod = function(installed_index)
return commands.remove_command(name)
end,
commands = setmetatable({}, {
__index = function(t, k) return commands.commands[k] end,
__index = function(_, k) return commands.commands[k] end,
__pairs = function(t) local function iter(t, k) local v; k, v = next(commands.commands, k); if v then return k, t[k] end; end; return iter, t, nil end
}),
game_commands = setmetatable({}, {
__index = function(t, k) return commands.game_commands[k] end,
__index = function(_, k) return commands.game_commands[k] end,
__pairs = function(t) local function iter(t, k) local v; k, v = next(commands.game_commands, k); if v then return k, t[k] end; end; return iter, t, nil end
})
}
env.require = function(path)
-- I blame Nexela for this
path = path:gsub('/', '.')
@@ -709,7 +711,7 @@ load_mod = function(installed_index)
error(err)
end
end
local file = global.mods[installed_index].files[alt_path]
file = global.mods[installed_index].files[alt_path]
if file then
debug_log({'hotpatch-trace.load-require', alt_path}, mod_name)
local code, err = load(file, '[' .. mod_name .. '] ' .. alt_path .. '.lua', 'bt', env)
@@ -723,31 +725,31 @@ load_mod = function(installed_index)
error(err)
end
end
debug_log({'hotpatch-trace.load-core-lib', path}, mod_name)
env.package._current_path_in_package = oldbase
local lib = package.loaded[path]
if not lib then
debug_log(path .. ' not found', nil, 3)
if not lib then
debug_log({'hotpatch-error.path-not-found', path}, mod_name, 3)
error(path .. ' not found')
end
return lib
end
end
env['load'] = function(l, s, m, e)
return load(l, s, m, e or env)
end
env['loadstring'] = env['load']
env['game'] = setmetatable({}, {
__index = function(t, k) return game[k] end,
__index = function(_, k) return game[k] end,
__pairs = function(t) local function iter(t, k) local v; k, v = next(game, k); if v then return k, t[k] end; end; return iter, t, nil end
})
local mt = {}
mt.__index = function(t, k)
mt.__index = function(_, k)
debug_log({'hotpatch-trace.nil-var-access', k}, nil, 3)
return nil
end
@@ -761,7 +763,7 @@ load_mod = function(installed_index)
--load/run code
debug_log({'hotpatch-info.loading'}, mod_name)
local mod_code, message = load(mod.code, '[' .. mod_name .. '] control.lua', 'bt', env)
if not mod_code then
debug_log({'hotpatch-error.compilation-failed'}, mod_name)
@@ -815,12 +817,12 @@ reset_mod = function(loaded_index)
end
reset_mod_events = function(loaded_index)
local loaded_index = find_loaded_mod(mod_name)
if not loaded_index then
debug_log({'hotpatch-warning.reset-events-not-running'}, mod_name)
else
local loaded_mod = loaded_mods[loaded_index]
--local loaded_index = find_loaded_mod(mod_name)
local loaded_mod = loaded_mods[loaded_index]
if not loaded_mod then
--debug_log({'hotpatch-warning.reset-events-not-running'}, mod_name)
else
loaded_mod.on_event = {}
loaded_mod.on_nth_tick = {}
loaded_mod.on_init = nil
@@ -841,7 +843,7 @@ run_mod = function(loaded_index)
--mod.env.global = {}
end
debug_log({'hotpatch-info.running'}, mod_name)
local success, result = xpcall(mod.code, debug.traceback)
if not success then
debug_log({'hotpatch-error.execution-failed'}, mod_name)
@@ -850,22 +852,22 @@ run_mod = function(loaded_index)
if game and game.player then
game.player.print(result)
end
return false
end
if strict_mode then
--if mod.env.global ~= {} then
--TODO: error, mod touched global inappropriately during load
--end
--mod.env.global = old_global
end
-- if a mod is being loaded that already has global data, it must be restored after
-- running control.lua, discarding any changes made
if not table.compare(old_global, {}) then
for k,v in pairs(mod.env.global) do
for k,_ in pairs(mod.env.global) do
mod.env.global[k] = nil
end
for k,v in pairs(old_global) do
@@ -874,16 +876,16 @@ run_mod = function(loaded_index)
--mod.env.global = old_global
end
old_global = nil
mod.running = true
debug_log({'hotpatch-info.complete', {'hotpatch-info.running'}}, mod_name)
--load complete, start notifying on event subscriptions
if not compat_mode then
mod.env.script.on_event = function(event, f)
if event == defines.events.on_tick then
mod.on_tick = f
register_on_tick(mod_name, event)
register_on_tick(mod_name)
else
mod.on_event[event] = f
register_event(mod_name, event)
@@ -892,18 +894,18 @@ run_mod = function(loaded_index)
mod.env.script.on_nth_tick = function(tick, f)
if tick then
if type(tick) == 'table' then
for k, v in pairs(tick) do
mod_script.on_nth_tick(v, f)
for _, v in pairs(tick) do
mod.env.script.on_nth_tick(v, f)
end
return
end
mod.on_nth_tick[tick] = f
register_nth_tick(mod_name, tick)
else
local on_nth_tick = mod.on_nth_tick
local mod_on_nth_tick = mod.on_nth_tick
mod.on_nth_tick = {}
for k, v in pairs(on_nth_tick) do
register_nth_tick(mod_name, tick)
for _, v in pairs(mod_on_nth_tick) do
register_nth_tick(mod_name, v)
end
end
end
@@ -923,7 +925,7 @@ on_event = function(event)
for i = 1, #loaded_mods do
mod = loaded_mods[i]
f = mod.on_event[event.name]
if f then
if f then
debug_log({'hotpatch-trace.event-running', event_name}, mod.name)
f(event)
end
@@ -939,7 +941,7 @@ if debug_log_on_tick then
for i = 1, #loaded_mods do
mod = loaded_mods[i]
f = mod.on_nth_tick[event.nth_tick]
if f then
if f then
debug_log({'hotpatch-trace.nth-tick-event-running', tick}, mod.name)
f(event)
end
@@ -953,7 +955,7 @@ else
for i = 1, #loaded_mods do
mod = loaded_mods[i]
f = mod.on_nth_tick[event.nth_tick]
if f then
if f then
debug_log({'hotpatch-trace.nth-tick-event-running', tick}, mod.name)
f(event)
end
@@ -961,7 +963,7 @@ else
end
end
local register_all_events = function()
register_all_events = function()
--unregister all events
script.on_event(defines.events, nil)
script.on_nth_tick(nil, nil)
@@ -980,12 +982,12 @@ register_mod_events = function(loaded_index)
debug_log({'hotpatch-trace.on-tick-event-registered'}, mod_name)
script.on_event(defines.events.on_tick, on_tick)
end
for k,v in pairs(mod.on_event) do
for k,_ in pairs(mod.on_event) do
local event_name = (event_names[k] or k)
debug_log({'hotpatch-trace.on-event-registered', event_name}, mod_name)
script.on_event(k, on_event)
end
for k,v in pairs(mod.on_nth_tick) do
for k,_ in pairs(mod.on_nth_tick) do
debug_log({'hotpatch-trace.on-nth-tick-event-registered', k}, mod_name)
script.on_nth_tick(k, on_nth_tick)
end
@@ -993,14 +995,14 @@ end
mod_on_init = function(loaded_index)
local mod = loaded_mods[loaded_index]
if mod then
debug_log({'hotpatch-trace.mod-on-init'}, mod.name)
if mod.on_init then
if mod.on_init then
local success, result = xpcall(mod.on_init, debug.traceback)
if not success then
debug_log('on_init failed for ' .. mod.name)
debug_log(result)
debug_log({'hotpatch-error.on-init-failed'}, mod_name)
debug_log(result, mod_name)
return false
end
end
@@ -1012,15 +1014,15 @@ end
mod_on_load = function(loaded_index)
local mod = loaded_mods[loaded_index]
if mod then
debug_log({'hotpatch-trace.mod-on-load'}, mod.name)
if mod.on_load then
if mod.on_load then
--local old_global = table.deepcopy(mod.env.global)
local success, result = xpcall(mod.on_load, debug.traceback)
if not success then
debug_log('on_load failed for ' .. mod.name)
debug_log(result)
debug_log({'hotpatch-error.on-load-failed'}, mod_name)
debug_log(result, mod_name)
return false
end
end
@@ -1032,14 +1034,14 @@ end
mod_on_configuration_changed = function(loaded_index, config)
local mod = loaded_mods[loaded_index]
if mod then
debug_log({'hotpatch-trace.mod-on-configuration-changed'}, mod.name)
if mod.on_configuration_changed then
if mod.on_configuration_changed then
local success, result = xpcall(mod.on_configuration_changed, debug.traceback, config)
if not success then
debug_log('on_configuration_changed failed for ' .. mod.name)
debug_log(result)
debug_log({'hotpatch-error.on-configuration-changed-failed'}, mod_name)
debug_log(result, mod_name)
return false
end
end
@@ -1057,9 +1059,9 @@ register_on_tick = function(mod_name)
for i = 1, #loaded_mods do
mod = loaded_mods[i]
local f = mod.on_tick
if f then
found_event = true
break
if f then
found_event = true
break
end
end
debug_log({'hotpatch-trace.on-tick-event-registered'}, mod_name)
@@ -1077,9 +1079,9 @@ register_nth_tick = function(mod_name, nth_tick)
for i = 1, #loaded_mods do
mod = loaded_mods[i]
local f = mod.on_nth_tick[nth_tick]
if f then
found_event = true
break
if f then
found_event = true
break
end
end
debug_log({'hotpatch-trace.on-nth-tick-event-registered', nth_tick}, mod_name)
@@ -1125,7 +1127,7 @@ on_init = function()
debug_log({'hotpatch-info.on-init'})
--juuuuust in case
global.mods = global.mods or {}
debug_log({'hotpatch-info.installing-included-mods'})
local mod
for i = 1, #static_mods do
@@ -1136,7 +1138,7 @@ on_init = function()
for i = 1, #global.mods do
load_mod(i)
end
for i = 1, #loaded_mods do
run_mod(i)
mod_on_init(i)
@@ -1152,10 +1154,10 @@ on_load = function()
hidden_log = hidden()
debug_log({'hotpatch-info.on-load'})
debug_log({'hotpatch-info.loading-installed-mods'})
if global.globals then
error('Upgrading from Hotpatch 1.0.X to 1.1.0 is not currently supported!')
-- untested migration: use a tick to do the migration
script.on_event(defines.events.on_tick, function(e)
global.mods = {}
@@ -1173,19 +1175,19 @@ on_load = function()
global.mod_code = nil
global.mod_files = nil
global.globals = nil
on_load() -- jump back into loading
on_tick(e) -- need to test if factorio auto calls this or not after assigning the handler
script.on_event(defines.events.on_tick, on_tick) -- restore old on_tick handler
end)
return
end
-- load installed mods
for i = 1, #global.mods do
load_mod(i)
end
-- run mods which loaded successfully
local failed_mods = {}
for i = 1, #loaded_mods do
@@ -1197,12 +1199,12 @@ on_load = function()
table.insert(failed_mods, i)
end
end
-- unload mods which failed to run
for i = 1, #failed_mods do
unload_mod(failed_mods[i])
end
debug_log({'hotpatch-info.complete', {'hotpatch-info.loading-installed-mods'}})
debug_log({'hotpatch-info.complete', {'hotpatch-info.on-load'}})
end
@@ -1211,11 +1213,11 @@ on_configuration_changed = function(config)
debug_log({'hotpatch-info.on-configuration-changed'})
local failed_mods = {}
for i = 1, #loaded_mods do
if not mod_on_configuration_changed(i) then
if not mod_on_configuration_changed(i, config) then
table.insert(failed_mods, i)
end
end
for i = 1, #failed_mods do
unload_mod(failed_mods[i])
end
@@ -1230,7 +1232,7 @@ if debug_log_on_tick then
for i = 1, #loaded_mods do
mod = loaded_mods[i]
f = mod.on_tick
if f then
if f then
debug_log({'hotpatch-trace.event-running', 'on_tick'}, mod.name)
f(e)
end
@@ -1243,7 +1245,7 @@ else
for i = 1, #loaded_mods do
mod = loaded_mods[i]
f = mod.on_tick
if f then
if f then
f(e)
end
end
@@ -1285,31 +1287,31 @@ local mod_tools_internal = setmetatable({
mod_on_init = mod_on_init,
mod_on_load = mod_on_load,
mod_on_configuration_changed = mod_on_configuration_changed,
static_mods = static_mods,
console = console,
debug_log = debug_log,
loaded_mods = loaded_mods,
loaded_libraries = loaded_libraries,
installed_mods = setmetatable({}, {
__index = function(t, k)
__index = function(_, k)
return global.mods[k]
end,
__newindex = function(t, k, v)
__newindex = function(_, __, ___)
-- do nothing
end,
__len = function(t)
__len = function(_)
return #global.mods
end,
__pairs = function(t) local function iter(t, k) local v; v = global.mods[k+1]; if v then return k+1, v end; end; return iter, t, 0 end,
__ipairs = function(t) local function iter(t, k) local v; v = global.mods[k+1]; if v then return k+1, v end; end; return iter, t, 0 end,
__pairs = function(t) local function iter(_, k) local v; v = global.mods[k+1]; if v then return k+1, v end; end; return iter, t, 0 end,
__ipairs = function(t) local function iter(_, k) local v; v = global.mods[k+1]; if v then return k+1, v end; end; return iter, t, 0 end,
__metatable = false,
})
},{
__index = function(t, k)
__index = function(_, k)
debug_log({'hotpatch-error.invalid-API-access', k}, nil, 3)
end,
__newindex = function(t, k, v)
__newindex = function(_, __, ___)
-- do nothing
end,
-- Don't let mods muck around
@@ -1321,11 +1323,12 @@ local mod_tools = setmetatable({
-- most code should use static_mod
static_mod = static_mod, -- (name, version, code, files)
set_debug_level = function(level)
debug_level = tonumber(_ENV.debug_settings.level) or debug_levels[_ENV.debug_settings.level]
--debug_level = tonumber(_ENV.debug_settings.level) or debug_levels[_ENV.debug_settings.level]
debug_level = tonumber(level) or debug_levels[level]
end,
},{
__index = mod_tools_internal,
__newindex = function(t, k, v)
__newindex = function(_, __, ___)
-- do nothing, read-only table
end,
-- Don't let mods muck around
@@ -65,7 +65,7 @@ remote_interface['install'] = function(mod_name, mod_version, mod_code, mod_file
local caller = game.player or console
if caller.admin then
if mod_files then
for k,v in pairs(mod_files) do
for k,_ in pairs(mod_files) do
if k == 'control' then
caller.print('ERROR: control.lua loaded twice for mod ' .. mod_name)
return
@@ -77,14 +77,14 @@ remote_interface['install'] = function(mod_name, mod_version, mod_code, mod_file
if installed_index then
local old_version = installed_mods[installed_index].version
if old_version then
debug_log('WARNING: mod already exists: ' .. mod_name .. ' ' .. old_version)
debug_log('WARNING: reinstalling mod in-place: ' .. mod_name .. ' ' .. mod_version)
debug_log({'hotpatch-warning.already-exists', mod_name, old_version})
debug_log({'hotpatch-warning.reinstalling', mod_name, old_version})
end
if loaded_index then
unload_mod(loaded_index)
end
end
install_mod(mod_name, mod_version, mod_code, mod_files)
if not only_install then
installed_index = find_installed_mod(mod_name)
@@ -131,6 +131,8 @@ remote_interface['run'] = function(mod_name)
if caller.admin then
local installed_index = find_installed_mod(mod_name)
local loaded_index = find_loaded_mod(mod_name)
local mod
local version
if installed_index and not loaded_index then
if not load_mod(installed_index) then
caller.print('compilation failed for mod ' .. mod_name)
@@ -139,13 +141,13 @@ remote_interface['run'] = function(mod_name)
loaded_index = find_loaded_mod(mod_name)
else
if loaded_index then
local mod = loaded_mods[loaded_index]
local version = mod.version
debug_log('WARNING: mod already loaded: ' .. mod_name .. ' ' .. version)
debug_log('WARNING: reinitializing: ' .. mod_name .. ' ' .. version)
mod = loaded_mods[loaded_index]
version = mod.version
debug_log({'hotpatch-warning.already-loaded', mod_name, version})
debug_log({'hotpatch-warning.reinitializing', mod_name, version})
end
end
if loaded_index then
if not run_mod(loaded_index) then
caller.print('execution failed for mod ' .. mod_name)
@@ -164,7 +166,7 @@ remote_interface['run'] = function(mod_name)
unload_mod(loaded_index)
return
end
end
end
else
caller.print('You must be an admin to run this command.')
end
@@ -178,7 +180,7 @@ remote_interface['update'] = function(mod_name, mod_version, mod_code, mod_files
local caller = game.player or console
if caller.admin then
if mod_files then
for k,v in pairs(mod_files) do
for k,_ in pairs(mod_files) do
if k == 'control' then
caller.print('ERROR: control.lua loaded twice for mod ' .. mod_name)
return
@@ -186,6 +188,9 @@ remote_interface['update'] = function(mod_name, mod_version, mod_code, mod_files
end
end
local installed_index = find_installed_mod(mod_name)
if installed_index then
;
end
local loaded_index = find_loaded_mod(mod_name)
local old_version
if loaded_index then
@@ -245,16 +250,40 @@ remote_interface['install_mod_file'] = function(mod_name, mod_file, mod_file_cod
end
end
remote_interface['exec'] = function(mod_name, exec_code)
local caller = game.player or console
if caller.admin then
local loaded_index = find_loaded_mod(mod_name)
local env = loaded_mods[loaded_index].env
local success
local code, err = load(exec_code, exec_code, 't', env)
if code then
success, err = pcall(code)
if not success then
debug_log(err)
end
else
debug_log(err)
end
else
caller.print('You must be an admin to run this command.')
end
end
--TODO: most of this function
remote_interface['clean'] = function(mod_name)
-- Removes ALL mod data and reinitializes
-- doesn't remove things a mod may add like surfaces, etc
local caller = game.player or console
if caller.admin then
mod_reset(mod_name)
run_mod(mod_name)
mod_on_init(mod_name)
mod_on_configuration_changed(mod_name, {mod_changes = {mod_name={new_version=mod_version}}})
--mod_reset(mod_name)
--run_mod(mod_name)
--mod_on_init(mod_name)
local loaded_index = find_loaded_mod(mod_name)
local mod = loaded_mods[loaded_index]
local version = mod.version
mod_on_configuration_changed(loaded_index, {mod_changes = {mod_name={new_version=version}}})
else
caller.print('You must be an admin to run this command.')
end
@@ -274,13 +303,13 @@ remote.add_interface('hotpatch', remote_interface)
debug_log({'hotpatch-info.complete', {'hotpatch-info.remote-installing'}})
]===])
--]===])
--[[
remote.call('hotpatch, 'install', 'test', '1.0.0', [===[
script.on_event(defines.events.on_player_changed_position, function(e)
game.print('changed position')
remote.call('hotpatch, 'install', 'test', '1.0.0', [===[
script.on_event(defines.events.on_player_changed_position, function(e)
game.print('changed position')
end
]===]
@@ -65,13 +65,17 @@ contains-comments-console=comments from console will comment out the entire code
reset-events-not-running=tried to reset events for mod that isn't running!
remote-interface-exists=remote interface __1__ already exists, removing...
command-exists=command __1__ already exists, removing...
already-loaded=mod already loaded
reinitializing=reinitializing...
already-exists=mod already exists
reinstalling=reinstalling mod in-place
already-exists=mod already exists: __1__ __2__
reinstalling=reinstalling mod in-place: __1__ __2__
already-loaded=mod already loaded: __1__ __2__
reinitializing=reinitializing: __1__ __2__
[hotpatch-error]
invalid-API-access=Invalid API access: __1__
not-installed=mod not installed, cannot install file for mod that does not exist
compilation-failed=compilation failed for mod
execution-failed=execution failed for mod
path-not-found=path '__1__' not found
on-init-failed=on_init failed
on-load-failed=on_load failed
on-configuration-changed-failed=on_configuration_changed failed