Added Redmew Debugger and Debugged Checkboxs

This commit is contained in:
Cooldude2606
2019-05-10 22:47:10 +01:00
parent 5c43c5f854
commit 0559bade9c
21 changed files with 1067 additions and 72 deletions

View File

@@ -32,6 +32,8 @@ return {
'modules.addons.scorched-earth',
'modules.addons.pollution-grading',
'modules.addons.random-player-colours',
-- GUI
'modules.commands.debug',
-- Config Files
'config.command_auth_admin', -- commands tagged with admin_only are blocked for non admins
'config.command_auth_roles', -- commands must be allowed via the role config

View File

@@ -44,6 +44,7 @@ Roles.new_role('Senior Administrator','SAdmin')
:set_parent('Administrator')
:allow{
'command/interface',
'command/debug',
'command/toggle-cheat-mode'
}

View File

@@ -23,12 +23,13 @@ function Button.new_button(name)
local uid = Gui.uid_name()
local self = setmetatable({
name=uid,
clean_name=name
clean_name=name,
_draw={
name=uid,
style=mod_gui.button_style,
type='button'
}
},{__index=Button._prototype})
self._draw.name = uid
self._draw.style = mod_gui.button_style
self._draw.type = 'button'
Button.config[uid] = self
if name then

View File

@@ -30,9 +30,10 @@ end
local function get_instances(checkbox,category)
if not Checkbox.instances[checkbox.name] then return end
local instances = Checkbox.instances
local instances = Checkbox.instances[checkbox.name]
if checkbox.categorize then
instances = instances[category]
if not instances[category] then instances[category] = {} end
return instances[category]
end
return instances
end
@@ -43,9 +44,12 @@ function Checkbox.new_checkbox(name)
local self = setmetatable({
name=uid,
clean_name=name,
_draw={
name=uid,
type='checkbox',
state=false
}
},{__index=Checkbox._prototype_checkbox})
self._draw.name = uid
self._draw.type = 'checkbox'
self._post_draw = function(element)
local category = self.categorize and self.categorize(element) or nil
@@ -53,6 +57,8 @@ function Checkbox.new_checkbox(name)
if instances then
table.insert(instances,element)
end
local state = self:get_store_state(category)
if state then element.state = true end
end
Checkbox.config[uid] = self
@@ -66,7 +72,7 @@ function Checkbox.new_checkbox(name)
local element = event.element
if self.store then
if self.categorize then
Store.set_chlid(self.store,self.categorize(element),element.state)
Store.set_child(self.store,self.categorize(element),element.state)
else
Store.set(self.store,element.state)
end
@@ -87,11 +93,12 @@ function Checkbox._prototype_checkbox:add_store(categorize)
if self.store then return end
self.store = get_store_location(self)
self.categorize = categorize
Checkbox.instances[self.name]={}
Store.register(self.store,function(value,category)
local instances = get_instances(self,category)
if instances then
for k,element in pairs(instances) do
if element.valid then
if element and element.valid then
element.state = value
if self._on_state_change then
local player = Game.get_player_by_index(element.player_index)
@@ -109,7 +116,7 @@ end
function Checkbox._prototype_checkbox:get_store_state(category)
if not self.store then return end
if self.categorize then
return Store.get_chlid(self.store,category)
return Store.get_child(self.store,category)
else
return Store.get(self.store)
end
@@ -119,9 +126,9 @@ function Checkbox._prototype_checkbox:set_store_state(category,state)
if not self.store then return end
state = not not state
if self.categorize then
return Store.set_chlid(self.store,category,state)
return Store.set_child(self.store,category,state)
else
return Store.set(self.store,state)
return Store.set(self.store,category)
end
end
@@ -151,11 +158,11 @@ function Checkbox._prototype_radiobutton:add_store(categorize)
end
function Checkbox._prototype_radiobutton:get_store_value(category)
function Checkbox._prototype_radiobutton:get_store_state(category)
end
function Checkbox._prototype_radiobutton:set_store_value(category,value)
function Checkbox._prototype_radiobutton:set_store_state(category,value)
end
@@ -171,12 +178,14 @@ function Checkbox._prototype_radiobutton:on_state_change(callback)
end
function Checkbox.get_stored_value(name,category)
function Checkbox.get_stored_state(name,category)
local checkbox = get_config(name)
return checkbox:get_store_state(category)
end
function Checkbox.set_stored_value(name,category,value)
function Checkbox.set_stored_state(name,category,value)
local checkbox = get_config(name)
return checkbox:set_store_state(category,value)
end
return Checkbox

View File

@@ -1,26 +1,27 @@
local Gui = require 'utils.gui'
local Game = require 'utils.game'
Gui._prototype = {_draw={}}
Gui._prototype = {}
Gui.inputs = {}
Gui.structure = {}
Gui.outputs = {}
function Gui._extend_prototype(tbl)
for k,v in pairs(Gui._prototype) do
if not tbl[k] then tbl[k] = table.deep_copy(v) end
if not tbl[k] then tbl[k] = v end
end
return tbl
end
--- Sets the caption for the element config
function Gui._prototype:set_caption(caption)
self.caption = caption
self._draw.caption = caption
return self
end
--- Sets the tooltip for the element config
function Gui._prototype:set_tooltip(tooltip)
self.tooltip = tooltip
self._draw.tooltip = tooltip
return self
end
@@ -44,13 +45,14 @@ end
--- Draws the element using what is in the _draw table, allows use of authenticator if present
function Gui._prototype:draw_to(element)
if element.children[self.name] then return end
if element[self.name] then return end
local player = Game.get_player_by_index(element.player_index)
if self.pre_authenticator then
if not self.pre_authenticator(element.player,self.clean_name or self.name) then return end
if not self.pre_authenticator(player,self.clean_name or self.name) then return end
end
local _element = element.add(self._draw)
if self.authenticator then
_element.enabled = not not self.authenticator(element.player,self.clean_name or self.name)
_element.enabled = not not self.authenticator(player,self.clean_name or self.name)
end
if self._post_draw then self._post_draw(_element) end
return _element

View File

@@ -1,4 +1,10 @@
local Gui = require 'expcore.gui'
local format_chat_colour = ext_require('expcore.common','format_chat_colour')
local Colors = require 'resources.color_presets'
local Game = require 'utils.game'
local clean_stack_trace = ext_require('modules.commands.interface','clean_stack_trace')
local tests = {}
Gui.new_toolbar_button('click-1')
:set_authenticator(function(player,button_name)
@@ -24,4 +30,83 @@ Gui.new_toolbar_button('click-3')
end)
:on_click(function(player,element,event)
player.print('CLICK 3')
end)
Gui.new_toolbar_button('gui-test-open')
:set_caption('Open Test Gui')
:set_authenticator(function(player,button_name)
return global.show_test_gui
end)
:on_click(function(player,_element,event)
if player.gui.center.TestGui then player.gui.center.TestGui.destroy() return end
local frame = player.gui.center.add{type='frame',caption='Gui Test',name='TestGui'}
frame = frame.add{type='table',column_count=5}
for key,element in pairs(tests) do
local success,err = pcall(element.draw_to,element,frame)
if success then
player.print('Drawing: '..key..format_chat_colour(' SUCCESS',Colors.green))
else
player.print('Drawing: '..key..format_chat_colour(' FAIL',Colors.red)..' '..clean_stack_trace(err))
end
end
end)
tests['Button no display'] = Gui.new_button('test button no display')
:on_click(function(player,element,event)
player.print('Button no display')
global.test_auth_button = not global.test_auth_button
player.print('Auth Button auth state: '..tostring(global.test_auth_button))
end)
tests['Button caption'] = Gui.new_button('test button caption')
:set_caption('Button Caption')
:on_click(function(player,element,event)
player.print('Button caption')
end)
tests['Button icon'] = Gui.new_button('test Bbutton icon')
:set_sprites('utility/warning_icon','utility/warning','utility/warning_white')
:on_click(function(player,element,event)
player.print('Button icon')
end)
tests['Button auth'] = Gui.new_button('test button auth')
:set_authenticator(function(player,button_name)
return global.test_auth_button
end)
:on_click(function(player,element,event)
player.print('Button auth')
end)
tests['Checkbox local'] = Gui.new_checkbox('test checkbox local')
:set_caption('Checkbox Local')
:on_state_change(function(player,element)
player.print('Checkbox local: '..tostring(element.state))
end)
tests['Checkbox store game'] = Gui.new_checkbox('test checkbox store game')
:set_caption('Checkbox Store Game')
:add_store()
:on_state_change(function(player,element)
player.print('Checkbox store game: '..tostring(element.state))
end)
tests['Checkbox store player'] = Gui.new_checkbox('test checkbox store player')
:set_caption('Checkbox Store Player')
:add_store(function(element)
local player = Game.get_player_by_index(element.player_index)
return player.name
end)
:on_state_change(function(player,element)
player.print('Checkbox store player: '..tostring(element.state))
end)
tests['Checkbox store force'] = Gui.new_checkbox('test checkbox store force')
:set_caption('Checkbox Store Force')
:add_store(function(element)
local player = Game.get_player_by_index(element.player_index)
return player.force.name
end)
:on_state_change(function(player,element)
player.print('Checkbox store force: '..tostring(element.state))
end)

View File

@@ -1,6 +1,4 @@
-- This file is used to require all the different elements of the gui module
local opt_require = ext_require('expcore.common','opt_require')
local Gui = require('./gui/core')
local Buttons = require('./gui/buttons')
@@ -12,13 +10,8 @@ Gui.new_toolbar_button = Toolbar.new_button
Gui.add_button_to_toolbar = Toolbar.add_button
Gui.structure.toolbar = Toolbar
--[[local Checkboxs = opt_require('./gui/checkboxs')
local Checkboxs = require('./gui/checkboxs')
Gui.new_checkbox = Checkboxs.new_checkbox
Gui.new_radiobutton = Checkboxs.new_radiobutton
Gui.inputs.checkboxs = Checkboxs
local TextEntry = opt_require('./gui/text')
Gui.new_text_entry = TextEntry.new_text_entry
Gui.inputs.text_entrys = TextEntry
]]
return Gui

View File

@@ -24,4 +24,9 @@ error-log-format-promote=[ERROR] rolePromote/__1__ :: __2__
game-message-assign=__1__ has been assigned to __2__ by __3__
game-message-unassign=__1__ has been unassigned from __2__ by __3__
reject-role=Invalid Role Name.
reject-player-role=Player has a higher role.
reject-player-role=Player has a higher role.
[gui_util]
button_tooltip=Shows / hides the Toolbar Gui buttons.
[expcore-gui]

View File

@@ -76,8 +76,8 @@
end)
]]
local Global = require 'util.global'
local Event = require 'util.event'
local Global = require 'utils.global'
local Event = require 'utils.event'
local write_json = ext_require('expcore.common','write_json','table_keys')
local Store = {
@@ -169,7 +169,7 @@ end
-- @tparam value any the new value to set at the location, value may be reverted if there is a watch callback
-- @treturn boolean true if it was successful
function Store.set(location,value)
if not Store.callbacks[location] and not no_error then
if not Store.callbacks[location] then
return error('Location is not registered', 2)
end
@@ -193,7 +193,7 @@ end
function Store.get_children(location)
local store = Store.get(location)
if type(store) ~= 'table' and table ~= nil then
if type(store) ~= 'table' and store ~= nil then
return error('Location has a non table value', 2)
end
@@ -207,11 +207,11 @@ end
function Store.get_child(location,child)
local store = Store.get(location)
if type(store) ~= 'table' and table ~= nil then
if type(store) ~= 'table' and store ~= nil then
return error('Location has a non table value', 2)
end
return store[child]
return store and store[child]
end
--- Sets the value of the chlid to a location, children can be added and removed during runtime
@@ -224,7 +224,7 @@ end
function Store.set_child(location,child,value)
local store = Store.get(location)
if type(store) ~= 'table' and table ~= nil then
if type(store) ~= 'table' and store ~= nil then
return error('Location has a non table value', 2)
end
@@ -257,14 +257,18 @@ Event.add(defines.events.on_tick,function()
if not success then
table.insert(errors,store_new)
else
if store_old ~= store_new then
if type(store_old) ~= type(store_new)
or type(store_old) == 'table' and not table.compare(store_new,store_new)
or store_old ~= store_new then
Store.data[location] = store_new
Store.callbacks[location](store_new)
end
end
end
error(errors)
if #errors > 0 then
error(table.concat(errors,'; '))
end
end)
return Store

View File

@@ -1,5 +1,4 @@
time-symbol-days-short=__1__d
color-tag=[color=__1__]__2__[/color]
[expcore-commands]
unauthorized=Unauthorized, Access is denied due to invalid credentials
@@ -25,4 +24,9 @@ error-log-format-promote=[ERROR] rolePromote/__1__ :: __2__
game-message-assign=__1__ has been assigned to __2__ by __3__
game-message-unassign=__1__ has been unassigned from __2__ by __3__
reject-role=Invalid Role Name.
reject-player-role=Player has a higher role.
reject-player-role=Player has a higher role.
[gui_util]
button_tooltip=Shows / hides the Toolbar Gui buttons.
[expcore-gui]

View File

@@ -0,0 +1,7 @@
local DebugView = require 'modules.gui.debug.main_view'
local Commands = require 'expcore.commands'
Commands.new_command('debug','Opens the debug pannel for viewing tables.')
:register(function(player,raw)
DebugView.open_dubug(player)
end)

View File

@@ -96,5 +96,6 @@ add_interface_callback('tile',function(player) return player.surface.get_tile(pl
return {
add_interface_callback=add_interface_callback,
interface_env=interface_env,
interface_callbacks=interface_callbacks
interface_callbacks=interface_callbacks,
clean_stack_trace=function(str) return str:gsub('%.%.%..-/temp/currently%-playing','') end
}

View File

@@ -0,0 +1,114 @@
local Gui = require 'utils.gui'
local Model = require 'modules.gui.debug.model'
local Color = require 'resources.color_presets'
local dump = Model.dump
local Public = {}
local ignore = {
_G = true,
assert = true,
collectgarbage = true,
error = true,
getmetatable = true,
ipairs = true,
load = true,
loadstring = true,
next = true,
pairs = true,
pcall = true,
print = true,
rawequal = true,
rawlen = true,
rawget = true,
rawset = true,
select = true,
setmetatable = true,
tonumber = true,
tostring = true,
type = true,
xpcall = true,
_VERSION = true,
module = true,
require = true,
package = true,
unpack = true,
table = true,
string = true,
bit32 = true,
math = true,
debug = true,
serpent = true,
log = true,
table_size = true,
global = true,
remote = true,
commands = true,
settings = true,
rcon = true,
script = true,
util = true,
mod_gui = true,
game = true,
rendering = true
}
local header_name = Gui.uid_name()
local left_panel_name = Gui.uid_name()
local right_panel_name = Gui.uid_name()
Public.name = '_G'
function Public.show(container)
local main_flow = container.add {type = 'flow', direction = 'horizontal'}
local left_panel = main_flow.add {type = 'scroll-pane', name = left_panel_name}
local left_panel_style = left_panel.style
left_panel_style.width = 300
for key, value in pairs(_G) do
if not ignore[key] then
local header =
left_panel.add({type = 'flow'}).add {type = 'label', name = header_name, caption = tostring(key)}
Gui.set_data(header, value)
end
end
local right_panel = main_flow.add {type = 'text-box', name = right_panel_name}
right_panel.read_only = true
right_panel.selectable = true
local right_panel_style = right_panel.style
right_panel_style.vertically_stretchable = true
right_panel_style.horizontally_stretchable = true
right_panel_style.maximal_width = 1000
right_panel_style.maximal_height = 1000
Gui.set_data(left_panel, {right_panel = right_panel, selected_header = nil})
end
Gui.on_click(
header_name,
function(event)
local element = event.element
local value = Gui.get_data(element)
local left_panel = element.parent.parent
local left_panel_data = Gui.get_data(left_panel)
local right_panel = left_panel_data.right_panel
local selected_header = left_panel_data.selected_header
if selected_header then
selected_header.style.font_color = Color.white
end
element.style.font_color = Color.orange
left_panel_data.selected_header = element
local content = dump(value)
right_panel.text = content
end
)
return Public

View File

@@ -0,0 +1,117 @@
local Event = require 'utils.event'
local table = require 'utils.table'
local Gui = require 'utils.gui'
local Model = require 'modules.gui.debug.model'
local format = string.format
local insert = table.insert
local events = defines.events
-- Constants
local events_to_keep = 10
-- Local vars
local Public = {
name = 'Events'
}
local name_lookup = {}
-- GUI names
local checkbox_name = Gui.uid_name()
-- global tables
local enabled = {}
local last_events = {}
global.debug_event_view = {
enabled = enabled,
last_events = last_events
}
function Public.on_open_debug()
local tbl = global.debug_event_view
if tbl then
enabled = tbl.enabled
last_events = tbl.last_events
else
enabled = {}
last_events = {}
global.debug_event_view = {
enabled = enabled,
last_events = last_events
}
end
Public.on_open_debug = nil
end
-- Local functions
local function event_callback(event)
local id = event.name
if not enabled[id] then
return
end
local name = name_lookup[id]
if not last_events[name] then
last_events[name] = {}
end
insert(last_events[name], 1, event)
last_events[name][events_to_keep + 1] = nil
event.name = nil
local str = format('%s (id = %s): %s', name, id, Model.dump(event))
game.print(str)
log(str)
end
local function on_gui_checked_state_changed(event)
local element = event.element
local name = element.caption
local id = events[name]
local state = element.state and true or false
element.state = state
if state then
enabled[id] = true
else
enabled[id] = false
end
end
-- GUI
-- Create a table with events sorted by their names
local grid_builder = {}
for name, _ in pairs(events) do
grid_builder[#grid_builder + 1] = name
end
table.sort(grid_builder)
function Public.show(container)
local main_frame_flow = container.add({type = 'flow', direction = 'vertical'})
local scroll_pane = main_frame_flow.add({type = 'scroll-pane'})
local gui_table = scroll_pane.add({type = 'table', column_count = 3, draw_horizontal_lines = true})
for _, event_name in pairs(grid_builder) do
local index = events[event_name]
gui_table.add({type = 'flow'}).add {
name = checkbox_name,
type = 'checkbox',
state = enabled[index] or false,
caption = event_name
}
end
end
Gui.on_checked_state_changed(checkbox_name, on_gui_checked_state_changed)
-- Event registers (TODO: turn to removable hooks.. maybe)
for name, id in pairs(events) do
name_lookup[id] = name
Event.add(id, event_callback)
end
return Public

View File

@@ -0,0 +1,133 @@
local Gui = require 'utils.gui'
local Model = require 'modules.gui.debug.model'
local Color = require 'resources.color_presets'
local dump = Model.dump
local dump_text = Model.dump_text
local concat = table.concat
local Public = {}
local ignore = {tokens = true}
local header_name = Gui.uid_name()
local left_panel_name = Gui.uid_name()
local right_panel_name = Gui.uid_name()
local input_text_box_name = Gui.uid_name()
local refresh_name = Gui.uid_name()
Public.name = 'global'
function Public.show(container)
local main_flow = container.add {type = 'flow', direction = 'horizontal'}
local left_panel = main_flow.add {type = 'scroll-pane', name = left_panel_name}
local left_panel_style = left_panel.style
left_panel_style.width = 300
for key, _ in pairs(global) do
if not ignore[key] then
local header =
left_panel.add({type = 'flow'}).add {type = 'label', name = header_name, caption = tostring(key)}
Gui.set_data(header, key)
end
end
local right_flow = main_flow.add {type = 'flow', direction = 'vertical'}
local right_top_flow = right_flow.add {type = 'flow', direction = 'horizontal'}
local input_text_box = right_top_flow.add {type = 'text-box', name = input_text_box_name}
local input_text_box_style = input_text_box.style
input_text_box_style.horizontally_stretchable = true
input_text_box_style.height = 32
input_text_box_style.maximal_width = 1000
local refresh_button =
right_top_flow.add {type = 'sprite-button', name = refresh_name, sprite = 'utility/reset', tooltip = 'refresh'}
local refresh_button_style = refresh_button.style
refresh_button_style.width = 32
refresh_button_style.height = 32
local right_panel = right_flow.add {type = 'text-box', name = right_panel_name}
right_panel.read_only = true
right_panel.selectable = true
local right_panel_style = right_panel.style
right_panel_style.vertically_stretchable = true
right_panel_style.horizontally_stretchable = true
right_panel_style.maximal_width = 1000
right_panel_style.maximal_height = 1000
local data = {
right_panel = right_panel,
input_text_box = input_text_box,
selected_header = nil,
selected_token_id = nil
}
Gui.set_data(input_text_box, data)
Gui.set_data(left_panel, data)
Gui.set_data(refresh_button, data)
end
Gui.on_click(
header_name,
function(event)
local element = event.element
local key = Gui.get_data(element)
local left_panel = element.parent.parent
local data = Gui.get_data(left_panel)
local right_panel = data.right_panel
local selected_header = data.selected_header
local input_text_box = data.input_text_box
if selected_header then
selected_header.style.font_color = Color.white
end
element.style.font_color = Color.orange
data.selected_header = element
input_text_box.text = concat {"global['", key, "']"}
input_text_box.style.font_color = Color.black
local content = dump(global[key]) or 'nil'
right_panel.text = content
end
)
local function update_dump(text_input, data, player)
local suc, ouput = dump_text(text_input.text, player)
if not suc then
text_input.style.font_color = Color.red
else
text_input.style.font_color = Color.black
data.right_panel.text = ouput
end
end
Gui.on_text_changed(
input_text_box_name,
function(event)
local element = event.element
local data = Gui.get_data(element)
update_dump(element, data, event.player)
end
)
Gui.on_click(
refresh_name,
function(event)
local element = event.element
local data = Gui.get_data(element)
local input_text_box = data.input_text_box
update_dump(input_text_box, data, event.player)
end
)
return Public

View File

@@ -0,0 +1,103 @@
local Gui = require 'utils.gui'
local Color = require 'resources.color_presets'
local Public = {}
local pages = {
require 'modules.gui.debug.redmew_global_view',
require 'modules.gui.debug.global_view',
require 'modules.gui.debug.package_view',
require 'modules.gui.debug._g_view',
require 'modules.gui.debug.event_view'
}
local main_frame_name = Gui.uid_name()
local close_name = Gui.uid_name()
local tab_name = Gui.uid_name()
function Public.open_dubug(player)
for i = 1, #pages do
local page = pages[i]
local callback = page.on_open_debug
if callback then
callback()
end
end
local center = player.gui.center
local frame = center[main_frame_name]
if frame then
return
end
frame = center.add {type = 'frame', name = main_frame_name, caption = 'Debuggertron 3001', direction = 'vertical'}
local frame_style = frame.style
frame_style.height = 600
frame_style.width = 900
local tab_flow = frame.add {type = 'flow', direction = 'horizontal'}
local container = frame.add {type = 'flow'}
container.style.vertically_stretchable = true
local data = {}
for i = 1, #pages do
local page = pages[i]
local tab_button = tab_flow.add({type = 'flow'}).add {type = 'button', name = tab_name, caption = page.name}
local tab_button_style = tab_button.style
Gui.set_data(tab_button, {index = i, frame_data = data})
if i == 1 then
tab_button_style.font_color = Color.orange
data.selected_index = i
data.selected_tab_button = tab_button
data.container = container
Gui.set_data(frame, data)
page.show(container)
end
end
frame.add {type = 'button', name = close_name, caption = 'Close'}
end
Gui.on_click(
tab_name,
function(event)
local element = event.element
local data = Gui.get_data(element)
local index = data.index
local frame_data = data.frame_data
local selected_index = frame_data.selected_index
if selected_index == index then
return
end
local selected_tab_button = frame_data.selected_tab_button
selected_tab_button.style.font_color = Color.black
frame_data.selected_tab_button = element
frame_data.selected_index = index
element.style.font_color = Color.orange
local container = frame_data.container
Gui.clear(container)
pages[index].show(container)
end
)
Gui.on_click(
close_name,
function(event)
local frame = event.player.gui.center[main_frame_name]
if frame then
Gui.destroy(frame)
end
end
)
return Public

147
modules/gui/debug/model.lua Normal file
View File

@@ -0,0 +1,147 @@
local Gui = require 'utils.gui'
local table = require 'utils.table'
local gui_names = Gui.names
local type = type
local concat = table.concat
local inspect = table.inspect
local pcall = pcall
local loadstring = loadstring
local rawset = rawset
local Public = {}
local luaObject = {'{', nil, ", name = '", nil, "'}"}
local luaPlayer = {"{LuaPlayer, name = '", nil, "', index = ", nil, '}'}
local luaEntity = {"{LuaEntity, name = '", nil, "', unit_number = ", nil, '}'}
local luaGuiElement = {"{LuaGuiElement, name = '", nil, "'}"}
local function get(obj, prop)
return obj[prop]
end
local function get_name_safe(obj)
local s, r = pcall(get, obj, 'name')
if not s then
return 'nil'
else
return r or 'nil'
end
end
local function get_lua_object_type_safe(obj)
local s, r = pcall(get, obj, 'help')
if not s then
return
end
return r():match('Lua%a+')
end
local function inspect_process(item)
if type(item) ~= 'table' or type(item.__self) ~= 'userdata' then
return item
end
local suc, valid = pcall(get, item, 'valid')
if not suc then
-- no 'valid' property
return get_lua_object_type_safe(item) or '{NoHelp LuaObject}'
end
if not valid then
return '{Invalid LuaObject}'
end
local obj_type = get_lua_object_type_safe(item)
if not obj_type then
return '{NoHelp LuaObject}'
end
if obj_type == 'LuaPlayer' then
luaPlayer[2] = item.name or 'nil'
luaPlayer[4] = item.index or 'nil'
return concat(luaPlayer)
elseif obj_type == 'LuaEntity' then
luaEntity[2] = item.name or 'nil'
luaEntity[4] = item.unit_number or 'nil'
return concat(luaEntity)
elseif obj_type == 'LuaGuiElement' then
local name = item.name
luaGuiElement[2] = gui_names and gui_names[name] or name or 'nil'
return concat(luaGuiElement)
else
luaObject[2] = obj_type
luaObject[4] = get_name_safe(item)
return concat(luaObject)
end
end
local inspect_options = {process = inspect_process}
function Public.dump(data)
return inspect(data, inspect_options)
end
local dump = Public.dump
function Public.dump_ignore_builder(ignore)
local function process(item)
if ignore[item] then
return nil
end
return inspect_process(item)
end
local options = {process = process}
return function(data)
return inspect(data, options)
end
end
function Public.dump_function(func)
local res = {'upvalues:\n'}
local i = 1
while true do
local n, v = debug.getupvalue(func, i)
if n == nil then
break
elseif n ~= '_ENV' then
res[#res + 1] = n
res[#res + 1] = ' = '
res[#res + 1] = dump(v)
res[#res + 1] = '\n'
end
i = i + 1
end
return concat(res)
end
function Public.dump_text(text, player)
local func = loadstring('return ' .. text)
if not func then
return false
end
rawset(game, 'player', player)
local suc, var = pcall(func)
rawset(game, 'player', nil)
if not suc then
return false
end
return true, dump(var)
end
return Public

View File

@@ -0,0 +1,161 @@
local Gui = require 'utils.gui'
local Color = require 'resources.color_presets'
local Model = require 'modules.gui.debug.model'
local dump_function = Model.dump_function
local loaded = _G.package.loaded
local Public = {}
local ignore = {
_G = true,
package = true,
coroutine = true,
table = true,
string = true,
bit32 = true,
math = true,
debug = true,
serpent = true,
['utils.math'] = true,
util = true,
['utils.inspect'] = true,
['mod-gui'] = true
}
local file_label_name = Gui.uid_name()
local left_panel_name = Gui.uid_name()
local breadcrumbs_name = Gui.uid_name()
local top_panel_name = Gui.uid_name()
local variable_label_name = Gui.uid_name()
local text_box_name = Gui.uid_name()
Public.name = 'package'
function Public.show(container)
local main_flow = container.add {type = 'flow', direction = 'horizontal'}
local left_panel = main_flow.add {type = 'scroll-pane', name = left_panel_name}
local left_panel_style = left_panel.style
left_panel_style.width = 300
for name, file in pairs(loaded) do
if not ignore[name] then
local file_label =
left_panel.add({type = 'flow'}).add {type = 'label', name = file_label_name, caption = name}
Gui.set_data(file_label, file)
end
end
local right_flow = main_flow.add {type = 'flow', direction = 'vertical'}
local breadcrumbs = right_flow.add {type = 'label', name = breadcrumbs_name}
local top_panel = right_flow.add {type = 'scroll-pane', name = top_panel_name}
local top_panel_style = top_panel.style
top_panel_style.height = 200
top_panel_style.maximal_width = 1000
top_panel_style.horizontally_stretchable = true
local text_box = right_flow.add {type = 'text-box', name = text_box_name}
text_box.read_only = true
text_box.selectable = true
local text_box_style = text_box.style
text_box_style.vertically_stretchable = true
text_box_style.horizontally_stretchable = true
text_box_style.maximal_width = 1000
text_box_style.maximal_height = 1000
local data = {
left_panel = left_panel,
breadcrumbs = breadcrumbs,
top_panel = top_panel,
text_box = text_box,
selected_file_label = nil,
selected_variable_label = nil
}
Gui.set_data(left_panel, data)
Gui.set_data(top_panel, data)
end
Gui.on_click(
file_label_name,
function(event)
local element = event.element
local file = Gui.get_data(element)
local left_panel = element.parent.parent
local data = Gui.get_data(left_panel)
local selected_file_label = data.selected_file_label
if selected_file_label then
selected_file_label.style.font_color = Color.white
end
element.style.font_color = Color.orange
data.selected_file_label = element
local top_panel = data.top_panel
local text_box = data.text_box
Gui.clear(top_panel)
local file_type = type(file)
if file_type == 'table' then
for k, v in pairs(file) do
local label =
top_panel.add({type = 'flow'}).add {type = 'label', name = variable_label_name, caption = k}
Gui.set_data(label, v)
end
elseif file_type == 'function' then
text_box.text = dump_function(file)
else
text_box.text = tostring(file)
end
end
)
Gui.on_click(
variable_label_name,
function(event)
local element = event.element
local variable = Gui.get_data(element)
local top_panel = element.parent.parent
local data = Gui.get_data(top_panel)
local text_box = data.text_box
local variable_type = type(variable)
if variable_type == 'table' then
Gui.clear(top_panel)
for k, v in pairs(variable) do
local label =
top_panel.add({type = 'flow'}).add {type = 'label', name = variable_label_name, caption = k}
Gui.set_data(label, v)
end
return
end
local selected_label = data.selected_variable_label
if selected_label and selected_label.valid then
selected_label.style.font_color = Color.white
end
element.style.font_color = Color.orange
data.selected_variable_label = element
if variable_type == 'function' then
text_box.text = dump_function(variable)
else
text_box.text = tostring(variable)
end
end
)
return Public

View File

@@ -0,0 +1,129 @@
local Gui = require 'utils.gui'
local Global = require 'utils.global'
local Token = require 'utils.token'
local Color = require 'resources.color_presets'
local Model = require 'modules.gui.debug.model'
local dump = Model.dump
local dump_text = Model.dump_text
local concat = table.concat
local Public = {}
local header_name = Gui.uid_name()
local left_panel_name = Gui.uid_name()
local right_panel_name = Gui.uid_name()
local input_text_box_name = Gui.uid_name()
local refresh_name = Gui.uid_name()
Public.name = 'Global'
function Public.show(container)
local main_flow = container.add {type = 'flow', direction = 'horizontal'}
local left_panel = main_flow.add {type = 'scroll-pane', name = left_panel_name}
local left_panel_style = left_panel.style
left_panel_style.width = 300
for token_id, token_name in pairs(Global.names) do
local header = left_panel.add({type = 'flow'}).add {type = 'label', name = header_name, caption = token_name}
Gui.set_data(header, token_id)
end
local right_flow = main_flow.add {type = 'flow', direction = 'vertical'}
local right_top_flow = right_flow.add {type = 'flow', direction = 'horizontal'}
local input_text_box = right_top_flow.add {type = 'text-box', name = input_text_box_name}
local input_text_box_style = input_text_box.style
input_text_box_style.horizontally_stretchable = true
input_text_box_style.height = 32
input_text_box_style.maximal_width = 1000
local refresh_button =
right_top_flow.add {type = 'sprite-button', name = refresh_name, sprite = 'utility/reset', tooltip = 'refresh'}
local refresh_button_style = refresh_button.style
refresh_button_style.width = 32
refresh_button_style.height = 32
local right_panel = right_flow.add {type = 'text-box', name = right_panel_name}
right_panel.read_only = true
right_panel.selectable = true
local right_panel_style = right_panel.style
right_panel_style.vertically_stretchable = true
right_panel_style.horizontally_stretchable = true
right_panel_style.maximal_width = 1000
right_panel_style.maximal_height = 1000
local data = {
right_panel = right_panel,
input_text_box = input_text_box,
selected_header = nil
}
Gui.set_data(input_text_box, data)
Gui.set_data(left_panel, data)
Gui.set_data(refresh_button, data)
end
Gui.on_click(
header_name,
function(event)
local element = event.element
local token_id = Gui.get_data(element)
local left_panel = element.parent.parent
local data = Gui.get_data(left_panel)
local right_panel = data.right_panel
local selected_header = data.selected_header
local input_text_box = data.input_text_box
if selected_header then
selected_header.style.font_color = Color.white
end
element.style.font_color = Color.orange
data.selected_header = element
input_text_box.text = concat {'global.tokens[', token_id, ']'}
input_text_box.style.font_color = Color.black
local content = dump(Token.get_global(token_id)) or 'nil'
right_panel.text = content
end
)
local function update_dump(text_input, data, player)
local suc, ouput = dump_text(text_input.text, player)
if not suc then
text_input.style.font_color = Color.red
else
text_input.style.font_color = Color.black
data.right_panel.text = ouput
end
end
Gui.on_text_changed(
input_text_box_name,
function(event)
local element = event.element
local data = Gui.get_data(element)
update_dump(element, data, event.player)
end
)
Gui.on_click(
refresh_name,
function(event)
local element = event.element
local data = Gui.get_data(element)
local input_text_box = data.input_text_box
update_dump(input_text_box, data, event.player)
end
)
return Public

View File

@@ -3,13 +3,11 @@
-- Dependencies
local Game = require 'utils.game'
local Color = require 'resources.color_presets'
local Server = require 'features.server'
-- localized functions
local random = math.random
local sqrt = math.sqrt
local floor = math.floor
local format = string.format
local match = string.match
local insert = table.insert
local concat = table.concat
@@ -201,27 +199,6 @@ function Module.set_and_return(tbl, key, value)
return value
end
--- Takes msg and prints it to all players. Also prints to the log and discord
-- @param msg <string> The message to print
-- @param warning_prefix <string> The name of the module/warning
function Module.action_warning(warning_prefix, msg)
game.print(prefix .. msg, Color.yellow)
msg = format('%s %s', warning_prefix, msg)
log(msg)
Server.to_discord_bold(msg)
end
--- Takes msg and prints it to all players except provided player. Also prints to the log and discord
-- @param msg <string> The message to print
-- @param warning_prefix <string> The name of the module/warning
-- @param player <LuaPlayer> the player not to send the message to
function Module.silent_action_warning(warning_prefix, msg, player)
Module.print_except(prefix .. msg, player, Color.yellow)
msg = format('%s %s', warning_prefix, msg)
log(msg)
Server.to_discord_bold(msg)
end
-- add utility functions that exist in base factorio/util
require 'util'

View File

@@ -36,7 +36,7 @@ function Global.register_init(tbl, init_handler, callback)
)
end
if _DEBUG then
if _DEBUG or true then
local concat = table.concat
local names = {}