Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

playerdata #256

Merged
merged 5 commits into from
Dec 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config/_file_loader.lua
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ return {
'modules.gui.vlayer',
'modules.gui.research',
'modules.gui.module',
'modules.gui.playerdata',
'modules.gui.surveillance',
'modules.graftorio.require', -- graftorio

Expand Down
6 changes: 4 additions & 2 deletions config/expcore/roles.lua
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,8 @@ Roles.new_role('Trainee','TrMod')
'command/bot-queue-set',
'command/game-speed',
'command/kill-biters',
'command/remove-biters'
'command/remove-biters',
'gui/playerdata'
}

--- Trusted Roles
Expand All @@ -139,7 +140,8 @@ Roles.new_role('Board Member','Board')
'command/repair',
'command/spectate',
'command/follow',
'command/personal-battery-recharge'
'command/personal-battery-recharge',
'gui/playerdata'
PHIDIAS0303 marked this conversation as resolved.
Show resolved Hide resolved
}

Roles.new_role('Senior Backer','Backer')
Expand Down
14 changes: 12 additions & 2 deletions modules/data/statistics.lua
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,16 @@ local function format_minutes(value)
})
end

--- Used to format time into a clock
local function format_clock(value)
return format_time(value*3600, {
hours=true,
minutes=true,
seconds=false,
time=true
})
end

--- Add MapsPlayed if it is enabled
if config.MapsPlayed then
Statistics:combine('MapsPlayed')
Expand All @@ -68,8 +78,8 @@ end
--- Add Playtime and AfkTime if it is enabled
if config.Playtime or config.AfkTime then
local playtime, afk_time
if config.Playtime then playtime = Statistics:combine('Playtime') playtime:set_metadata{stringify=format_minutes} end
if config.AfkTime then afk_time = Statistics:combine('AfkTime') afk_time:set_metadata{stringify=format_minutes} end
if config.Playtime then playtime = Statistics:combine('Playtime') playtime:set_metadata{stringify=format_minutes, stringify_short=format_clock} end
if config.AfkTime then afk_time = Statistics:combine('AfkTime') afk_time:set_metadata{stringify=format_minutes, stringify_short=format_clock} end
Event.on_nth_tick(3600, function()
if game.tick == 0 then return end
for _, player in pairs(game.connected_players) do
Expand Down
216 changes: 216 additions & 0 deletions modules/gui/playerdata.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
---- module pd
-- @addon pd

local Gui = require 'expcore.gui' --- @dep expcore.gui
local Roles = require 'expcore.roles' --- @dep expcore.roles
local Event = require 'utils.event' --- @dep utils.event
local PlayerData = require 'expcore.player_data' --- @dep expcore.player_data
require 'modules.data.statistics'
local format_time = _C.format_time --- @dep expcore.common
local format_number = require('util').format_number --- @dep util

local pd_container
local label_width = {
['name'] = 135,
['count'] = 105,
['total'] = 480
}

local function format_clock(value)
return format_time(value*3600, {
hours=true,
minutes=true,
seconds=false,
time=true
})
end

local function format_number_n(n)
return format_number(math.floor(n)) .. string.format('%.2f', n % 1):sub(2)
end

local playerStats = PlayerData.Statistics
local computed_stats = {
DamageDeathRatio = {
default = '0.00',
calculate = function(player_name)
return format_number_n(playerStats['DamageDealt']:get(player_name, 0) / playerStats['Deaths']:get(player_name, 1))
end
},
KillDeathRatio = {
default = '0.00',
calculate = function(player_name)
return format_number_n(playerStats['Kills']:get(player_name, 0) / playerStats['Deaths']:get(player_name, 1))
end
},
SessionTime = {
default = '00:00',
calculate = function(player_name)
return format_clock((playerStats['Playtime']:get(player_name, 0) - playerStats['AfkTime']:get(player_name, 0)) / playerStats['JoinCount']:get(player_name, 1))
end
},
BuildRatio = {
default = '0.00',
calculate = function(player_name)
return format_number_n(playerStats['MachinesBuilt']:get(player_name, 0) / playerStats['MachinesRemoved']:get(player_name, 1))
end
},
RocketPerHour = {
default = '0.00',
calculate = function(player_name)
return format_number_n(playerStats['RocketsLaunched']:get(player_name, 0) * 60 / playerStats['Playtime']:get(player_name, 1))
end
},
TreeKillPerMinute = {
default = '0.00',
calculate = function(player_name)
return format_number_n(playerStats['TreesDestroyed']:get(player_name, 0) / playerStats['Playtime']:get(player_name, 1))
end
},
NetPlayTime = {
default = '00:00',
calculate = function(player_name)
return format_clock((playerStats['Playtime']:get(player_name, 0) - playerStats['AfkTime']:get(player_name, 0)))
end
},
AFKTimeRatio = {
default = '0.00',
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
}

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)
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)
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(name, parent, player_list)
return parent.add{
name = 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)

local pd_username_update =
Gui.element{
type = 'button',
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(event_trigger, parent)
local container = Gui.container(parent, event_trigger, 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)
: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)
Loading