---- module pd -- @gui PlayerData local ExpUtil = require("modules/exp_util") local Gui = require("modules.exp_legacy.expcore.gui") --- @dep expcore.gui local Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles local Event = require("modules/exp_legacy/utils/event") --- @dep utils.event local PlayerData = require("modules.exp_legacy.expcore.player_data") --- @dep expcore.player_data require("modules.exp_legacy.modules.data.statistics") local format_number = require("util").format_number --- @dep util local pd_container local label_width = { ["name"] = 135, ["count"] = 105, ["total"] = 480, } local short_time_format = ExpUtil.format_time_factory_locale{ format = "short", coefficient = 3600, hours = true, minutes = true } local function format_number_n(n) return format_number(math.floor(n), false) .. string.format("%.2f", n % 1):sub(2) end local PlayerStats = PlayerData.Statistics local computed_stats = { DamageDeathRatio = { default = format_number_n(0), calculate = function(player_name) return format_number_n(PlayerStats["DamageDealt"]:get(player_name, 0) / PlayerStats["Deaths"]:get(player_name, 1)) end, }, KillDeathRatio = { default = format_number_n(0), calculate = function(player_name) return format_number_n(PlayerStats["Kills"]:get(player_name, 0) / PlayerStats["Deaths"]:get(player_name, 1)) end, }, SessionTime = { default = short_time_format(0), calculate = function(player_name) return short_time_format((PlayerStats["Playtime"]:get(player_name, 0) - PlayerStats["AfkTime"]:get(player_name, 0)) / PlayerStats["JoinCount"]:get(player_name, 1)) end, }, BuildRatio = { default = format_number_n(0), calculate = function(player_name) return format_number_n(PlayerStats["MachinesBuilt"]:get(player_name, 0) / PlayerStats["MachinesRemoved"]:get(player_name, 1)) end, }, RocketPerHour = { default = format_number_n(0), calculate = function(player_name) return format_number_n(PlayerStats["RocketsLaunched"]:get(player_name, 0) * 60 / PlayerStats["Playtime"]:get(player_name, 1)) end, }, TreeKillPerMinute = { default = format_number_n(0), calculate = function(player_name) return format_number_n(PlayerStats["TreesDestroyed"]:get(player_name, 0) / PlayerStats["Playtime"]:get(player_name, 1)) end, }, NetPlayTime = { default = short_time_format(0), calculate = function(player_name) return short_time_format((PlayerStats["Playtime"]:get(player_name, 0) - PlayerStats["AfkTime"]:get(player_name, 0))) end, }, AFKTimeRatio = { default = format_number_n(0), calculate = function(player_name) return format_number_n(PlayerStats["AfkTime"]:get(player_name, 0) * 100 / PlayerStats["Playtime"]:get(player_name, 1)) end, }, } local label = Gui.element(function(_, parent, width, caption, tooltip, name) local new_label = parent.add{ type = "label", caption = caption, tooltip = tooltip, name = name, style = "heading_2_label", } new_label.style.width = width return new_label end) local pd_data_set = Gui.element(function(_, parent, name) local pd_data_set = parent.add{ type = "flow", direction = "vertical", name = name } local disp = Gui.scroll_table(pd_data_set, label_width["total"], 4, "disp") for _, stat_name in pairs(PlayerData.Statistics.metadata.display_order) do local child = PlayerData.Statistics[stat_name] local metadata = child.metadata local value = metadata.stringify_short and metadata.stringify_short(0) or metadata.stringify and metadata.stringify(0) or format_number(0, false) label(disp, label_width["name"], metadata.name or { "exp-statistics." .. stat_name }, metadata.tooltip or { "exp-statistics." .. stat_name .. "-tooltip" }) label(disp, label_width["count"], { "readme.data-format", value, metadata.unit or "" }, metadata.value_tooltip or { "exp-statistics." .. stat_name .. "-tooltip" }, stat_name) end for stat_name, data in pairs(computed_stats) do label(disp, label_width["name"], { "exp-statistics." .. stat_name }, { "exp-statistics." .. stat_name .. "-tooltip" }) label(disp, label_width["count"], { "readme.data-format", data.default, "" }, { "exp-statistics." .. stat_name .. "-tooltip" }, stat_name) end return pd_data_set end) local function pd_update(table, player_name) for _, stat_name in pairs(PlayerData.Statistics.metadata.display_order) do local child = PlayerData.Statistics[stat_name] local metadata = child.metadata local value = child:get(player_name) if metadata.stringify_short then value = metadata.stringify_short(value or 0) elseif metadata.stringify then value = metadata.stringify(value or 0) else value = format_number(value or 0, false) end table[stat_name].caption = { "readme.data-format", value, metadata.unit or "" } end for stat_name, data in pairs(computed_stats) do table[stat_name].caption = { "readme.data-format", data.calculate(player_name), "" } end end local pd_username_player = Gui.element(function(definition, parent, player_list) return parent.add{ name = definition.name, type = "drop-down", items = player_list, selected_index = #player_list > 0 and 1, } end) :style{ horizontally_stretchable = true, }:on_selection_changed(function(_, element, _) local player_name = game.connected_players[element.selected_index] local table = element.parent.parent.parent.parent["pd_st_2"].disp.table pd_update(table, player_name) end) :static_name(Gui.unique_static_name) local pd_username_update = Gui.element{ type = "button", name = Gui.unique_static_name, caption = "update", }:style{ width = 128, }:on_click(function(_, element, _) local player_index = element.parent[pd_username_player.name].selected_index if player_index > 0 then local player_name = game.connected_players[player_index] local table = element.parent.parent.parent.parent["pd_st_2"].disp.table pd_update(table, player_name) end end) local pd_username_set = Gui.element(function(_, parent, name, player_list) local pd_username_set = parent.add{ type = "flow", direction = "vertical", name = name } local disp = Gui.scroll_table(pd_username_set, label_width["total"], 2, "disp") pd_username_player(disp, player_list) pd_username_update(disp) return pd_username_set end) pd_container = Gui.element(function(definition, parent) local container = Gui.container(parent, definition.name, label_width["total"]) local player_list = {} for _, player in pairs(game.connected_players) do table.insert(player_list, player.name) end pd_username_set(container, "pd_st_1", player_list) pd_data_set(container, "pd_st_2") return container.parent end) :static_name(Gui.unique_static_name) :add_to_left_flow() Gui.left_toolbar_button("item/power-armor-mk2", "Player Data GUI", pd_container, function(player) return Roles.player_allowed(player, "gui/playerdata") end) local function gui_player_list_update() local player_list = {} for _, player in pairs(game.connected_players) do table.insert(player_list, player.name) end for _, player in pairs(game.connected_players) do local frame = Gui.get_left_element(player, pd_container) frame.container["pd_st_1"].disp.table[pd_username_player.name].items = player_list end end Event.add(defines.events.on_player_joined_game, gui_player_list_update) Event.add(defines.events.on_player_left_game, gui_player_list_update)