From 51c5a5b1f83365b780dd208433965f036b864135 Mon Sep 17 00:00:00 2001 From: Cooldude2606 Date: Wed, 7 Apr 2021 01:01:41 +0100 Subject: [PATCH 1/2] Added search commands --- config/_file_loader.lua | 1 + config/expcore/roles.lua | 4 + locale/en/commands.cfg | 8 +- modules/commands/search.lua | 167 ++++++++++++++++++++++++++++++++++++ 4 files changed, 179 insertions(+), 1 deletion(-) create mode 100644 modules/commands/search.lua diff --git a/config/_file_loader.lua b/config/_file_loader.lua index 16a135af..caa311da 100644 --- a/config/_file_loader.lua +++ b/config/_file_loader.lua @@ -29,6 +29,7 @@ return { 'modules.commands.home', 'modules.commands.connect', 'modules.commands.last-location', + 'modules.commands.search', --- Addons 'modules.addons.chat-popups', diff --git a/config/expcore/roles.lua b/config/expcore/roles.lua index 9b826202..4125677c 100644 --- a/config/expcore/roles.lua +++ b/config/expcore/roles.lua @@ -102,6 +102,10 @@ Roles.new_role('Trainee','TrMod') 'command/unjail', 'command/kick', 'command/ban', + 'command/search', + 'command/search-amount', + 'command/search-recent', + 'command/search-online', } --- Trusted Roles diff --git a/locale/en/commands.cfg b/locale/en/commands.cfg index dea7b935..cb5ab590 100644 --- a/locale/en/commands.cfg +++ b/locale/en/commands.cfg @@ -82,4 +82,10 @@ offline=You cannot connect as the server is currently offline: __1__ none-matching=No servers were found with that name, if you used an address please append true to the end of your command. [expcom-lastlocation] -response=Last location of __1__ was [gps=__2__,__3__] \ No newline at end of file +response=Last location of __1__ was [gps=__2__,__3__] + +[expcom-inv-search] +reject-item=No item was found with internal name __1__; try using rich text selection. +results-heading=Players found with [item=__1__]: +results-item=__1__) __2__ has __3__ items. (__4__) +results-none=No players have [item=__1__] \ No newline at end of file diff --git a/modules/commands/search.lua b/modules/commands/search.lua new file mode 100644 index 00000000..52143bdd --- /dev/null +++ b/modules/commands/search.lua @@ -0,0 +1,167 @@ +--[[-- Commands Module - Inventory Search + - Adds commands that will search all players inventories for an item + @commands InventorySearch +]] + +local Commands = require 'expcore.commands' --- @dep expcore.commands +local format_number = require('util').format_number --- @dep util +local format_chat_player_name = _C.format_chat_player_name --- @dep expcore.common +local format_time = _C.format_time +require 'config.expcore.command_general_parse' + +--- Input parse for items by name +local function item_parse(input, _, reject) + if input == nil then return end + local lower_input = input:lower():gsub(' ', '-') + + -- Simple Case - internal name is given + local item = game.item_prototypes[lower_input] + if item then return item end + + -- Second Case - rich text is given + local item_name = input:match('%[item=([0-9a-z-]+)%]') + item = game.item_prototypes[item_name] + if item then return item end + + -- No item found, we do not attempt to search all prototypes as this will be expensive + return reject{'expcom-inv-search.reject-item', lower_input} +end + +--- Search all players for this item +local function search_players(players, item) + local head = 1 + local found = {} + + -- 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 + +--- Custom sort function which only retains 5 greatest values +local function sort_players(players, func) + local sorted = {} + local values = {} + local threshold = nil + + -- Loop over all provided players + for index, player in ipairs(players) do + local value = func(player) + -- Check if the item will make the top 10 elements + if value > threshold or index <= 5 then + local inserted = false + values[player] = value + -- Find where in the top 10 to insert the element + for next_index, next_player in ipairs(sorted) do + if value > values[next_player] then + table.insert(sorted, next_index, player) + inserted = true + break + end + end + -- Insert the element, this can only be called when index <= 5 + if not inserted then + sorted[#sorted+1] = player + end + -- Update the threshold + if sorted[6] then + threshold = values[sorted[5]] + values[sorted[6]] = nil + sorted[6] = nil + else + threshold = values[sorted[#sorted]] + end + end + end + + return sorted +end + +--- Display to the player the top players which were found +local function display_players(player, players, item) + player.print{'expcom-inv-search.results-heading', item.name} + for index, data in ipairs(players) do + local player_name_color = format_chat_player_name(data.player) + local amount = format_number(data.count) + local time = format_time(data.online_time) + player.print{'expcom-inv-search.results-item', index, player_name_color, amount, time} + end +end + +--- Return the amount of an item a player has +local function amount_sort(data) + return data.count +end + +--- Get a list of players sorted by the quantity of an item in their inventory +-- @command search-amount +-- @tparam LuaItemPrototype item The item to search for in players inventories +Commands.new_command('search-amount', 'Display players sorted by the quantity of an item held') +:add_alias('ia') +:add_param('item', false, item_parse) +:enable_auto_concat() +:register(function(player, item) + local players = search_players(game.players, item) + if #players == 0 then return {'expcom-inv-search.results-none', item.name} end + local top_players = sort_players(players, amount_sort) + display_players(player, top_players, item) +end) + +--- Return the index of the player, higher means they joined more recently +local function recent_sort(data) + return data.player.index +end + +--- Get a list of players who have the given item, sorted by how recently they joined +-- @command search-recent +-- @tparam LuaItemPrototype item The item to search for in players inventories +Commands.new_command('search-recent', 'Display players who hold an item sorted by join time') +:add_alias('ir') +:add_param('item', false, item_parse) +:enable_auto_concat() +:register(function(player, item) + local players = search_players(game.players, item) + if #players == 0 then return {'expcom-inv-search.results-none', item.name} end + local top_players = sort_players(players, recent_sort) + display_players(player, top_players, item) +end) + +--- Return the index of the player, higher means they joined more recently +local function combined_sort(data) + return data.count/data.online_time +end + +--- Get a list of players sorted by quantity held and play time +-- @command search +-- @tparam LuaItemPrototype item The item to search for in players inventories +Commands.new_command('search', 'Display players sorted by the quantity of an item held and playtime') +:add_alias('i') +:add_param('item', false, item_parse) +:enable_auto_concat() +:register(function(player, item) + local players = search_players(game.players, item) + if #players == 0 then return {'expcom-inv-search.results-none', item.name} end + local top_players = sort_players(players, combined_sort) + display_players(player, top_players, item) +end) + +--- Get a list of online players sorted by quantity held and play time +-- @command search-online +-- @tparam LuaItemPrototype item The item to search for in players inventories +Commands.new_command('search-online', 'Display online players sorted by the quantity of an item held and playtime') +:add_alias('io') +:add_param('item', false, item_parse) +:enable_auto_concat() +:register(function(player, item) + local players = search_players(game.connected_players, item) + if #players == 0 then return {'expcom-inv-search.results-none', item.name} end + local top_players = sort_players(players, combined_sort) + display_players(player, top_players, item) +end) \ No newline at end of file From b86efbb9435f50346e3f4ae07c12e51e17325492 Mon Sep 17 00:00:00 2001 From: Cooldude2606 Date: Wed, 7 Apr 2021 18:07:04 +0100 Subject: [PATCH 2/2] Made requested changes --- modules/commands/search.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/commands/search.lua b/modules/commands/search.lua index 52143bdd..62d1ab33 100644 --- a/modules/commands/search.lua +++ b/modules/commands/search.lua @@ -54,11 +54,11 @@ local function sort_players(players, func) -- Loop over all provided players for index, player in ipairs(players) do local value = func(player) - -- Check if the item will make the top 10 elements + -- Check if the item will make the top 5 elements if value > threshold or index <= 5 then local inserted = false values[player] = value - -- Find where in the top 10 to insert the element + -- Find where in the top 5 to insert the element for next_index, next_player in ipairs(sorted) do if value > values[next_player] then table.insert(sorted, next_index, player) @@ -133,7 +133,7 @@ Commands.new_command('search-recent', 'Display players who hold an item sorted b display_players(player, top_players, item) end) ---- Return the index of the player, higher means they joined more recently +--- 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