Migrate all commands to new lib
This commit is contained in:
181
exp_scenario/module/commands/search.lua
Normal file
181
exp_scenario/module/commands/search.lua
Normal file
@@ -0,0 +1,181 @@
|
||||
--[[-- Commands - Inventory Search
|
||||
Adds commands that will search all players inventories for an item
|
||||
]]
|
||||
|
||||
local ExpUtil = require("modules/exp_util")
|
||||
|
||||
local Commands = require("modules/exp_commands")
|
||||
local format_player_name = Commands.format_player_name_locale
|
||||
|
||||
local format_number = require("util").format_number
|
||||
|
||||
--- A player who is of a lower role than the executing player
|
||||
--- @type Commands.InputParser
|
||||
local function parse_item(input, player)
|
||||
-- First Case - internal name is given
|
||||
-- Second Case - rich text is given
|
||||
local item_name = input:lower():gsub(" ", "-")
|
||||
local item = prototypes.item[item_name] or prototypes.item[input:match("%[item=([0-9a-z-]+)%]")]
|
||||
if item then
|
||||
return Commands.status.success(item)
|
||||
end
|
||||
|
||||
-- No item found, we do not attempt to search all prototypes as this will be expensive
|
||||
return Commands.status.invalid_input{ "exp-commands_search.invalid-item", item_name }
|
||||
end
|
||||
|
||||
--- @class SearchResult: { player: LuaPlayer, count: number, online_time: number }
|
||||
|
||||
--- Search all players for this item
|
||||
--- @param players LuaPlayer[] Players to search
|
||||
--- @param item LuaItemPrototype Item to find
|
||||
--- @return SearchResult[]
|
||||
local function search_players(players, item)
|
||||
local found = {} --- @type SearchResult[]
|
||||
local head = 1
|
||||
|
||||
-- Check the item count of all players
|
||||
for _, player in pairs(players) do
|
||||
local item_count = player.get_item_count(item.name)
|
||||
if item_count > 0 then
|
||||
-- Add the player to the array as they have the item
|
||||
found[head] = { player = player, count = item_count, online_time = player.online_time }
|
||||
head = head + 1
|
||||
end
|
||||
end
|
||||
|
||||
return found
|
||||
end
|
||||
|
||||
--- @alias SortFunction fun(result: SearchResult): number
|
||||
|
||||
--- Custom sort function which only retains 5 greatest values
|
||||
--- @param results SearchResult[] Players to sort
|
||||
--- @param func SortFunction Function to calculate value, higher better
|
||||
--- @return SearchResult[] # Top 5 results
|
||||
local function sort_results(results, func)
|
||||
local sorted = {}
|
||||
local values = {}
|
||||
local threshold = 0
|
||||
|
||||
-- Loop over all provided players
|
||||
for index, result in ipairs(results) do
|
||||
local value = func(result)
|
||||
-- Check if the item will make the top 5 elements
|
||||
if index <= 5 or value > threshold then
|
||||
local inserted = false
|
||||
values[result] = value
|
||||
|
||||
-- Find where in the top 5 to insert the element
|
||||
for next_index, next_result in ipairs(sorted) do
|
||||
if value > values[next_result] then
|
||||
table.insert(sorted, next_index, result)
|
||||
inserted = true
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
-- Update the threshold, clean up the tables, and insert if needed
|
||||
if sorted[6] then
|
||||
threshold = values[sorted[5]]
|
||||
values[sorted[6]] = nil
|
||||
sorted[6] = nil
|
||||
elseif not inserted then
|
||||
-- index <= 5 so insert at the end
|
||||
sorted[#sorted + 1] = result
|
||||
threshold = value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return sorted
|
||||
end
|
||||
|
||||
local display_players_time_format = ExpUtil.format_time_factory_locale{ format = "short", hours = true, minutes = true }
|
||||
|
||||
--- Display to the player the top players which were found
|
||||
--- @param results SearchResult[]
|
||||
--- @param item LuaItemPrototype
|
||||
--- @return LocalisedString
|
||||
local function format_response(results, item)
|
||||
if #results == 0 then
|
||||
return { "exp-commands_search.no-results", item.name }
|
||||
end
|
||||
|
||||
local response = { "", { "exp-commands_search.title", item.name } } --- @type LocalisedString
|
||||
for index, data in ipairs(results) do
|
||||
response[index + 2] = {
|
||||
"exp-commands_search.result",
|
||||
index,
|
||||
format_player_name(data.player),
|
||||
format_number(data.count, false),
|
||||
display_players_time_format(data.online_time),
|
||||
}
|
||||
end
|
||||
|
||||
return response
|
||||
end
|
||||
|
||||
--- Return the the amount of an item a player has divided by their playtime
|
||||
local function combined_sort(data)
|
||||
return data.count / data.online_time
|
||||
end
|
||||
|
||||
--- Get a list of players sorted by quantity held and play time
|
||||
Commands.new("search", { "exp-commands_search.description-search" })
|
||||
:argument("item", { "exp-commands_search.arg-item" }, parse_item)
|
||||
:enable_auto_concatenation()
|
||||
:add_aliases{ "s" }
|
||||
:register(function(player, item)
|
||||
--- @cast item LuaItemPrototype
|
||||
local results = search_players(game.players, item)
|
||||
local sorted = sort_results(results, combined_sort)
|
||||
return Commands.status.success(format_response(sorted, item))
|
||||
end)
|
||||
|
||||
--- Get a list of online players sorted by quantity held and play time
|
||||
Commands.new("search-online", { "exp-commands_search.description-online" })
|
||||
:argument("item", { "exp-commands_search.arg-item" }, parse_item)
|
||||
:enable_auto_concatenation()
|
||||
:add_aliases{ "so" }
|
||||
:register(function(player, item)
|
||||
--- @cast item LuaItemPrototype
|
||||
local results = search_players(game.connected_players, item)
|
||||
local sorted = sort_results(results, combined_sort)
|
||||
return Commands.status.success(format_response(sorted, item))
|
||||
end)
|
||||
|
||||
--- Return the amount of an item a player has
|
||||
--- @type SortFunction
|
||||
local function sort_by_count(data)
|
||||
return data.count
|
||||
end
|
||||
|
||||
--- Get a list of players sorted by the quantity of an item in their inventory
|
||||
Commands.new("search-amount", { "exp-commands_search.description-amount" })
|
||||
:argument("item", { "exp-commands_search.arg-item" }, parse_item)
|
||||
:enable_auto_concatenation()
|
||||
:add_aliases{ "sa" } -- cant use /sc
|
||||
:register(function(player, item)
|
||||
--- @cast item LuaItemPrototype
|
||||
local results = search_players(game.players, item)
|
||||
local sorted = sort_results(results, sort_by_count)
|
||||
return Commands.status.success(format_response(sorted, item))
|
||||
end)
|
||||
|
||||
--- Return the index of the player, higher means they joined more recently
|
||||
local function sort_by_recent(data)
|
||||
return data.player.index
|
||||
end
|
||||
|
||||
--- Get a list of players who have the given item, sorted by how recently they joined
|
||||
Commands.new("search-recent", { "exp-commands_search.description-recent" })
|
||||
:argument("item", { "exp-commands_search.arg-item" }, parse_item)
|
||||
:enable_auto_concatenation()
|
||||
:add_aliases{ "sr" } -- cant use /sc
|
||||
:register(function(player, item)
|
||||
--- @cast item LuaItemPrototype
|
||||
local results = search_players(game.players, item)
|
||||
local sorted = sort_results(results, sort_by_recent)
|
||||
return Commands.status.success(format_response(sorted, item))
|
||||
end)
|
||||
Reference in New Issue
Block a user