mirror of
https://github.com/Refactorio/RedMew.git
synced 2025-02-09 13:37:05 +02:00
Merge pull request #919 from grilledham/debugger/gui_data
Debugger/gui data
This commit is contained in:
commit
4ec2d46f62
@ -142,10 +142,12 @@ end
|
||||
if _DEBUG then
|
||||
require 'features.scenario_data_manipulation'
|
||||
end
|
||||
-- Needs to be at bottom so tokens are registered last.
|
||||
|
||||
if _DUMP_ENV then
|
||||
require 'utils.dump_env'
|
||||
end
|
||||
|
||||
-- Needs to be at bottom so tokens are registered last.
|
||||
if _DEBUG then
|
||||
require 'features.gui.debug.command'
|
||||
end
|
||||
|
@ -1,6 +1,12 @@
|
||||
local DebugView = require 'features.gui.debug.main_view'
|
||||
local Model = require 'features.gui.debug.model'
|
||||
local Command = require 'utils.command'
|
||||
|
||||
local loadstring = loadstring
|
||||
local pcall = pcall
|
||||
local dump = Model.dump
|
||||
local log = log
|
||||
|
||||
Command.add(
|
||||
'debug',
|
||||
{
|
||||
@ -11,3 +17,124 @@ Command.add(
|
||||
DebugView.open_dubug(player)
|
||||
end
|
||||
)
|
||||
|
||||
Command.add(
|
||||
'dump',
|
||||
{
|
||||
arguments = {'str'},
|
||||
capture_excess_arguments = true,
|
||||
allowed_by_server = true,
|
||||
debug_only = true,
|
||||
description = 'dumps value to player.print'
|
||||
},
|
||||
function(args, player)
|
||||
local p
|
||||
if player then
|
||||
p = player.print
|
||||
else
|
||||
p = print
|
||||
end
|
||||
|
||||
local func, err = loadstring('return ' .. args.str)
|
||||
|
||||
if not func then
|
||||
p(err)
|
||||
return
|
||||
end
|
||||
|
||||
local suc, value = pcall(func)
|
||||
|
||||
if not suc then
|
||||
if value then
|
||||
local i = value:find('\n')
|
||||
if i then
|
||||
p(value:sub(1, i))
|
||||
return
|
||||
end
|
||||
|
||||
i = value:find('%s')
|
||||
if i then
|
||||
p(value:sub(i + 1))
|
||||
end
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
p(dump(value))
|
||||
end
|
||||
)
|
||||
|
||||
Command.add(
|
||||
'dump-log',
|
||||
{
|
||||
arguments = {'str'},
|
||||
capture_excess_arguments = true,
|
||||
allowed_by_server = true,
|
||||
debug_only = true,
|
||||
description = 'dumps value to log'
|
||||
},
|
||||
function(args, player)
|
||||
local p
|
||||
if player then
|
||||
p = player.print
|
||||
else
|
||||
p = print
|
||||
end
|
||||
|
||||
local func, err = loadstring('return ' .. args.str)
|
||||
|
||||
if not func then
|
||||
p(err)
|
||||
return
|
||||
end
|
||||
|
||||
local suc, value = pcall(func)
|
||||
|
||||
if not suc then
|
||||
p(value)
|
||||
return
|
||||
end
|
||||
|
||||
log(dump(value))
|
||||
end
|
||||
)
|
||||
|
||||
Command.add(
|
||||
'dump-file',
|
||||
{
|
||||
arguments = {'str'},
|
||||
capture_excess_arguments = true,
|
||||
allowed_by_server = true,
|
||||
debug_only = true,
|
||||
description = 'dumps value to dump.lua'
|
||||
},
|
||||
function(args, player)
|
||||
local p
|
||||
local player_index
|
||||
if player then
|
||||
p = player.print
|
||||
player_index = player.index
|
||||
else
|
||||
p = print
|
||||
player_index = 0
|
||||
end
|
||||
|
||||
local func, err = loadstring('return ' .. args.str)
|
||||
|
||||
if not func then
|
||||
p(err)
|
||||
return
|
||||
end
|
||||
|
||||
local suc, value = pcall(func)
|
||||
|
||||
if not suc then
|
||||
p(value)
|
||||
return
|
||||
end
|
||||
|
||||
value = dump(value)
|
||||
game.write_file('dump.lua', value, false, player_index)
|
||||
end
|
||||
)
|
||||
|
283
features/gui/debug/gui_data_view.lua
Normal file
283
features/gui/debug/gui_data_view.lua
Normal file
@ -0,0 +1,283 @@
|
||||
local Gui = require 'utils.gui'
|
||||
local Color = require 'resources.color_presets'
|
||||
local Model = require 'features.gui.debug.model'
|
||||
|
||||
local dump = Model.dump
|
||||
local dump_text = Model.dump_text
|
||||
local concat = table.concat
|
||||
|
||||
local Public = {}
|
||||
|
||||
local player_header_name = Gui.uid_name()
|
||||
local element_header_name = Gui.uid_name()
|
||||
local player_panel_name = Gui.uid_name()
|
||||
local element_panel_name = Gui.uid_name()
|
||||
local input_text_box_name = Gui.uid_name()
|
||||
local refresh_name = Gui.uid_name()
|
||||
local data_panel_name = Gui.uid_name()
|
||||
|
||||
Public.name = 'Gui Data'
|
||||
|
||||
local function draw_player_headers(player_panel, selected_index)
|
||||
local selected_header = nil
|
||||
|
||||
for player_index, values in pairs(Gui.data()) do
|
||||
local player = game.get_player(player_index)
|
||||
local player_name
|
||||
if not player then
|
||||
player_name = 'invalid player'
|
||||
else
|
||||
player_name = player.name
|
||||
end
|
||||
|
||||
local header =
|
||||
player_panel.add({type = 'flow'}).add {
|
||||
type = 'label',
|
||||
name = player_header_name,
|
||||
caption = concat({player_index, ' - ', player_name})
|
||||
}
|
||||
Gui.set_data(header, {values = values, player_index = player_index})
|
||||
|
||||
if player_index == selected_index then
|
||||
selected_header = header
|
||||
end
|
||||
end
|
||||
|
||||
return selected_header
|
||||
end
|
||||
|
||||
function Public.show(container)
|
||||
local main_flow = container.add {type = 'flow', direction = 'horizontal'}
|
||||
|
||||
local player_panel = main_flow.add {type = 'scroll-pane', name = player_panel_name}
|
||||
local player_panel_style = player_panel.style
|
||||
player_panel_style.width = 200
|
||||
|
||||
draw_player_headers(player_panel)
|
||||
|
||||
local right_flow = main_flow.add {type = 'flow', direction = 'vertical'}
|
||||
|
||||
local element_panel = right_flow.add {type = 'scroll-pane', name = element_panel_name}
|
||||
local element_panel_style = element_panel.style
|
||||
element_panel_style.horizontally_stretchable = true
|
||||
element_panel_style.height = 200
|
||||
|
||||
local right_middle_flow = right_flow.add {type = 'flow', direction = 'horizontal'}
|
||||
|
||||
local input_text_box = right_middle_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_middle_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 data_panel = right_flow.add {type = 'text-box', name = data_panel_name}
|
||||
data_panel.read_only = true
|
||||
data_panel.selectable = true
|
||||
|
||||
local data_panel_style = data_panel.style
|
||||
data_panel_style.vertically_stretchable = true
|
||||
data_panel_style.horizontally_stretchable = true
|
||||
data_panel_style.maximal_width = 1000
|
||||
data_panel_style.maximal_height = 1000
|
||||
|
||||
local data = {
|
||||
player_panel = player_panel,
|
||||
element_panel = element_panel,
|
||||
input_text_box = input_text_box,
|
||||
data_panel = data_panel,
|
||||
selected_player_header = nil,
|
||||
selected_element_header = nil,
|
||||
selected_player_index = nil,
|
||||
selected_element_index = nil
|
||||
}
|
||||
|
||||
Gui.set_data(player_panel, data)
|
||||
Gui.set_data(element_panel, data)
|
||||
Gui.set_data(input_text_box, data)
|
||||
Gui.set_data(refresh_button, data)
|
||||
end
|
||||
|
||||
local function draw_element_headers(element_panel, values, selected_index)
|
||||
local selected_header = nil
|
||||
local element_map = Gui.element_map()
|
||||
local name_map = Gui.names
|
||||
|
||||
for ei, stored_data in pairs(values) do
|
||||
local ele = element_map[ei]
|
||||
local ele_name = ''
|
||||
if ele and ele.valid then
|
||||
ele_name = ele.name
|
||||
end
|
||||
|
||||
local gui_name = name_map[ele_name]
|
||||
if gui_name then
|
||||
ele_name = gui_name
|
||||
end
|
||||
|
||||
local middle_header =
|
||||
element_panel.add({type = 'flow'}).add {
|
||||
type = 'label',
|
||||
name = element_header_name,
|
||||
caption = concat({ei, ' - ', ele_name})
|
||||
}
|
||||
|
||||
Gui.set_data(middle_header, {stored_data = stored_data, element_index = ei})
|
||||
|
||||
if ei == selected_index then
|
||||
selected_header = middle_header
|
||||
end
|
||||
end
|
||||
|
||||
return selected_header
|
||||
end
|
||||
|
||||
Gui.on_click(
|
||||
player_header_name,
|
||||
function(event)
|
||||
local element = event.element
|
||||
local header_data = Gui.get_data(element)
|
||||
local values = header_data.values
|
||||
local player_index = header_data.player_index
|
||||
|
||||
local player_panel = element.parent.parent
|
||||
local data = Gui.get_data(player_panel)
|
||||
local element_panel = data.element_panel
|
||||
local selected_player_header = data.selected_player_header
|
||||
local input_text_box = data.input_text_box
|
||||
|
||||
if selected_player_header then
|
||||
selected_player_header.style.font_color = Color.white
|
||||
end
|
||||
|
||||
element.style.font_color = Color.orange
|
||||
data.selected_player_header = element
|
||||
data.selected_player_index = player_index
|
||||
data.selected_element_index = nil
|
||||
|
||||
input_text_box.text = ''
|
||||
|
||||
if not values then
|
||||
return
|
||||
end
|
||||
|
||||
local copy = {}
|
||||
for k, v in pairs(values) do
|
||||
copy[k] = v
|
||||
end
|
||||
|
||||
draw_element_headers(element_panel, copy)
|
||||
end
|
||||
)
|
||||
|
||||
Gui.on_click(
|
||||
element_header_name,
|
||||
function(event)
|
||||
local element = event.element
|
||||
local header_data = Gui.get_data(element)
|
||||
local stored_data = header_data.stored_data
|
||||
local element_index = header_data.element_index
|
||||
|
||||
local player_panel = element.parent.parent
|
||||
local data = Gui.get_data(player_panel)
|
||||
local data_panel = data.data_panel
|
||||
local selected_element_header = data.selected_element_header
|
||||
local input_text_box = data.input_text_box
|
||||
|
||||
if selected_element_header then
|
||||
selected_element_header.style.font_color = Color.white
|
||||
end
|
||||
|
||||
element.style.font_color = Color.orange
|
||||
data.selected_element_header = element
|
||||
data.selected_element_index = element_index
|
||||
|
||||
local selected_player_index = data.selected_player_index
|
||||
|
||||
if selected_player_index then
|
||||
input_text_box.text =
|
||||
concat {'global.tokens[', Gui.token, '].data[', selected_player_index, '][', element_index, ']'}
|
||||
else
|
||||
input_text_box.text = 'missing player'
|
||||
end
|
||||
|
||||
local content = dump(stored_data) or 'nil'
|
||||
data_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.data_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
|
||||
local player_panel = data.player_panel
|
||||
local element_panel = data.element_panel
|
||||
local selected_player_index = data.selected_player_index
|
||||
local selected_element_index = data.selected_element_index
|
||||
|
||||
Gui.clear(player_panel)
|
||||
local selected_player_header = draw_player_headers(player_panel, selected_player_index)
|
||||
data.selected_player_header = selected_player_header
|
||||
if selected_player_header then
|
||||
selected_player_header.style.font_color = Color.orange
|
||||
end
|
||||
|
||||
Gui.clear(element_panel)
|
||||
if selected_player_header then
|
||||
local player_header_data = Gui.get_data(selected_player_header)
|
||||
local values = player_header_data.values
|
||||
|
||||
local copy = {}
|
||||
for k, v in pairs(values) do
|
||||
copy[k] = v
|
||||
end
|
||||
|
||||
local selected_element_header = draw_element_headers(element_panel, copy, selected_element_index)
|
||||
data.selected_element_header = selected_element_header
|
||||
if selected_element_header then
|
||||
selected_element_header.style.font_color = Color.orange
|
||||
update_dump(input_text_box, data, event.player)
|
||||
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
data.input_text_box.text = ''
|
||||
data.data_panel.text = ''
|
||||
end
|
||||
)
|
||||
|
||||
return Public
|
@ -8,6 +8,7 @@ local pages = {
|
||||
require 'features.gui.debug.global_view',
|
||||
require 'features.gui.debug.package_view',
|
||||
require 'features.gui.debug._g_view',
|
||||
require 'features.gui.debug.gui_data_view',
|
||||
require 'features.gui.debug.event_view'
|
||||
}
|
||||
|
||||
@ -30,7 +31,7 @@ function Public.open_dubug(player)
|
||||
return
|
||||
end
|
||||
|
||||
frame = center.add {type = 'frame', name = main_frame_name, caption = 'Debuggertron 3001', direction = 'vertical'}
|
||||
frame = center.add {type = 'frame', name = main_frame_name, caption = 'Debuggertron 3002', direction = 'vertical'}
|
||||
local frame_style = frame.style
|
||||
frame_style.height = 600
|
||||
frame_style.width = 900
|
||||
|
@ -87,6 +87,7 @@ function Public.dump(data)
|
||||
return inspect(data, inspect_options)
|
||||
end
|
||||
local dump = Public.dump
|
||||
_G.dump = dump
|
||||
|
||||
function Public.dump_ignore_builder(ignore)
|
||||
local function process(item)
|
||||
|
@ -14,6 +14,8 @@ function Global.register(tbl, callback)
|
||||
callback(Token.get_global(token))
|
||||
end
|
||||
)
|
||||
|
||||
return token
|
||||
end
|
||||
|
||||
function Global.register_init(tbl, init_handler, callback)
|
||||
@ -34,6 +36,8 @@ function Global.register_init(tbl, init_handler, callback)
|
||||
callback(Token.get_global(token))
|
||||
end
|
||||
)
|
||||
|
||||
return token
|
||||
end
|
||||
|
||||
if _DEBUG then
|
||||
@ -53,6 +57,8 @@ if _DEBUG then
|
||||
callback(Token.get_global(token))
|
||||
end
|
||||
)
|
||||
|
||||
return token
|
||||
end
|
||||
|
||||
function Global.register_init(tbl, init_handler, callback)
|
||||
@ -73,6 +79,8 @@ if _DEBUG then
|
||||
callback(Token.get_global(token))
|
||||
end
|
||||
)
|
||||
|
||||
return token
|
||||
end
|
||||
end
|
||||
|
||||
|
101
utils/gui.lua
101
utils/gui.lua
@ -2,14 +2,20 @@ local Token = require 'utils.token'
|
||||
local Event = require 'utils.event'
|
||||
local Global = require 'utils.global'
|
||||
|
||||
local tostring = tostring
|
||||
local next = next
|
||||
|
||||
local Gui = {}
|
||||
|
||||
local data = {}
|
||||
local element_map = {}
|
||||
|
||||
Global.register(
|
||||
data,
|
||||
Gui.token =
|
||||
Global.register(
|
||||
{data = data, element_map = element_map},
|
||||
function(tbl)
|
||||
data = tbl
|
||||
data = tbl.data
|
||||
element_map = tbl.element_map
|
||||
end
|
||||
)
|
||||
|
||||
@ -23,17 +29,46 @@ end
|
||||
|
||||
-- Associates data with the LuaGuiElement. If data is nil then removes the data
|
||||
function Gui.set_data(element, value)
|
||||
data[element.player_index * 0x100000000 + element.index] = value
|
||||
local player_index = element.player_index
|
||||
local values = data[player_index]
|
||||
|
||||
if value == nil then
|
||||
if not values then
|
||||
return
|
||||
end
|
||||
|
||||
values[element.index] = nil
|
||||
|
||||
if next(values) == nil then
|
||||
data[player_index] = nil
|
||||
end
|
||||
else
|
||||
if not values then
|
||||
values = {}
|
||||
data[player_index] = values
|
||||
end
|
||||
|
||||
values[element.index] = value
|
||||
end
|
||||
end
|
||||
local set_data = Gui.set_data
|
||||
|
||||
-- Gets the Associated data with this LuaGuiElement if any.
|
||||
function Gui.get_data(element)
|
||||
return data[element.player_index * 0x100000000 + element.index]
|
||||
local player_index = element.player_index
|
||||
|
||||
local values = data[player_index]
|
||||
if not values then
|
||||
return nil
|
||||
end
|
||||
|
||||
return values[element.index]
|
||||
end
|
||||
|
||||
local remove_data_recursively
|
||||
-- Removes data associated with LuaGuiElement and its children recursively.
|
||||
function Gui.remove_data_recursively(element)
|
||||
Gui.set_data(element, nil)
|
||||
set_data(element, nil)
|
||||
|
||||
local children = element.children
|
||||
|
||||
@ -41,13 +76,15 @@ function Gui.remove_data_recursively(element)
|
||||
return
|
||||
end
|
||||
|
||||
for _, child in ipairs(children) do
|
||||
for _, child in next, children do
|
||||
if child.valid then
|
||||
Gui.remove_data_recursively(child)
|
||||
remove_data_recursively(child)
|
||||
end
|
||||
end
|
||||
end
|
||||
remove_data_recursively = Gui.remove_data_recursively
|
||||
|
||||
local remove_children_data
|
||||
function Gui.remove_children_data(element)
|
||||
local children = element.children
|
||||
|
||||
@ -55,21 +92,22 @@ function Gui.remove_children_data(element)
|
||||
return
|
||||
end
|
||||
|
||||
for _, child in ipairs(children) do
|
||||
for _, child in next, children do
|
||||
if child.valid then
|
||||
Gui.set_data(child, nil)
|
||||
Gui.remove_children_data(child)
|
||||
set_data(child, nil)
|
||||
remove_children_data(child)
|
||||
end
|
||||
end
|
||||
end
|
||||
remove_children_data = Gui.remove_children_data
|
||||
|
||||
function Gui.destroy(element)
|
||||
Gui.remove_data_recursively(element)
|
||||
remove_data_recursively(element)
|
||||
element.destroy()
|
||||
end
|
||||
|
||||
function Gui.clear(element)
|
||||
Gui.remove_children_data(element)
|
||||
remove_children_data(element)
|
||||
element.clear()
|
||||
end
|
||||
|
||||
@ -274,6 +312,43 @@ if _DEBUG then
|
||||
|
||||
return token
|
||||
end
|
||||
|
||||
function Gui.set_data(element, value)
|
||||
local player_index = element.player_index
|
||||
local values = data[player_index]
|
||||
|
||||
if value == nil then
|
||||
if not values then
|
||||
return
|
||||
end
|
||||
|
||||
local index = element.index
|
||||
values[index] = nil
|
||||
element_map[index] = nil
|
||||
|
||||
if next(values) == nil then
|
||||
data[player_index] = nil
|
||||
end
|
||||
else
|
||||
if not values then
|
||||
values = {}
|
||||
data[player_index] = values
|
||||
end
|
||||
|
||||
local index = element.index
|
||||
values[index] = value
|
||||
element_map[index] = element
|
||||
end
|
||||
end
|
||||
set_data = Gui.set_data
|
||||
|
||||
function Gui.data()
|
||||
return data
|
||||
end
|
||||
|
||||
function Gui.element_map()
|
||||
return element_map
|
||||
end
|
||||
end
|
||||
|
||||
return Gui
|
||||
|
Loading…
x
Reference in New Issue
Block a user