1
0
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:
grilledham 2019-05-27 13:18:12 +01:00 committed by GitHub
commit 4ec2d46f62
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 512 additions and 15 deletions

View File

@ -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

View File

@ -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
)

View 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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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