Main menu server tab search improvements

This commit is contained in:
cx384 2024-12-15 15:57:03 +01:00
parent a1b8d20f18
commit c4d624083d

@ -112,6 +112,7 @@ local function get_formspec(tabview, name, tabdata)
local retval = local retval =
-- Search -- Search
"field[0.25,0.25;7,0.75;te_search;;" .. core.formspec_escape(tabdata.search_for) .. "]" .. "field[0.25,0.25;7,0.75;te_search;;" .. core.formspec_escape(tabdata.search_for) .. "]" ..
"tooltip[te_search;" .. fgettext("Possible filters\ngame:<name>\nmod:<name>\nplayer:<name>") .. "]" ..
"field_enter_after_edit[te_search;true]" .. "field_enter_after_edit[te_search;true]" ..
"container[7.25,0.25]" .. "container[7.25,0.25]" ..
"image_button[0,0;0.75,0.75;" .. core.formspec_escape(defaulttexturedir .. "search.png") .. ";btn_mp_search;]" .. "image_button[0,0;0.75,0.75;" .. core.formspec_escape(defaulttexturedir .. "search.png") .. ";btn_mp_search;]" ..
@ -271,19 +272,106 @@ end
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
local function parse_search_input(input)
if not input:find("%S") then
return -- Return nil if nothing to search for
end
-- Search is not case sensitive
input = input:lower()
local query = {keywords = {}, mods = {}, players = {}}
-- Process quotation enclosed parts
input = input:gsub('(%S?)"([^"]*)"(%S?)', function(before, match, after)
if before == "" and after == "" then -- Also have be separated by spaces
table.insert(query.keywords, match)
return " "
end
return before..'"'..match..'"'..after
end)
-- Separate by space characters and handle special prefixes
-- (words with special prefixes need an exact match and none of them can contain spaces)
for word in input:gmatch("%S+") do
local mod = word:match("^mod:(.*)")
table.insert(query.mods, mod)
local player = word:match("^player:(.*)")
table.insert(query.players, player)
local game = word:match("^game:(.*)")
query.game = query.game or game
if not (mod or player or game) then
table.insert(query.keywords, word)
end
end
return query
end
-- Prepares the server to be used for searching
local function uncapitalize_server(server)
local function table_lower(t)
local r = {}
for i, s in ipairs(t or {}) do
r[i] = s:lower()
end
return r
end
return {
name = (server.name or ""):lower(),
description = (server.description or ""):lower(),
gameid = (server.gameid or ""):lower(),
mods = table_lower(server.mods),
clients_list = table_lower(server.clients_list),
}
end
-- Returns false if the query does not match
-- otherwise returns a number to adjust the sorting priority
local function matches_query(server, query)
-- Search is not case sensitive
server = uncapitalize_server(server)
-- Check if mods found
for _, mod in ipairs(query.mods) do
if table.indexof(server.mods, mod) < 0 then
return false
end
end
-- Check if players found
for _, player in ipairs(query.players) do
if table.indexof(server.clients_list, player) < 0 then
return false
end
end
-- Check if game matches
if query.game and query.game ~= server.gameid then
return false
end
-- Check if keyword found
local name_matches = true
local description_matches = true
for _, keyword in ipairs(query.keywords) do
name_matches = name_matches and server.name:find(keyword, 1, true)
description_matches = description_matches and server.description:find(keyword, 1, true)
end
return name_matches and 50 or description_matches and 0
end
local function search_server_list(input) local function search_server_list(input)
menudata.search_result = nil menudata.search_result = nil
if #serverlistmgr.servers < 2 then if #serverlistmgr.servers < 2 then
return return
end end
-- setup the keyword list -- setup the search query
local keywords = {} local query = parse_search_input(input)
for word in input:gmatch("%S+") do if not query then
table.insert(keywords, word:lower())
end
if #keywords == 0 then
return return
end end
@ -292,16 +380,9 @@ local function search_server_list(input)
-- Search the serverlist -- Search the serverlist
local search_result = {} local search_result = {}
for i, server in ipairs(serverlistmgr.servers) do for i, server in ipairs(serverlistmgr.servers) do
local name_matches, description_matches = true, true local match = matches_query(server, query)
for _, keyword in ipairs(keywords) do if match then
name_matches = name_matches and not not server.points = #serverlistmgr.servers - i + match
(server.name or ""):lower():find(keyword, 1, true)
description_matches = description_matches and not not
(server.description or ""):lower():find(keyword, 1, true)
end
if name_matches or description_matches then
server.points = #serverlistmgr.servers - i
+ (name_matches and 50 or 0)
table.insert(search_result, server) table.insert(search_result, server)
end end
end end
@ -395,7 +476,7 @@ local function main_button_handler(tabview, fields, name, tabdata)
if fields.btn_mp_search or fields.key_enter_field == "te_search" then if fields.btn_mp_search or fields.key_enter_field == "te_search" then
tabdata.search_for = fields.te_search tabdata.search_for = fields.te_search
search_server_list(fields.te_search:lower()) search_server_list(fields.te_search)
if menudata.search_result then if menudata.search_result then
-- Note: This clears the selection if there are no results -- Note: This clears the selection if there are no results
set_selected_server(menudata.search_result[1]) set_selected_server(menudata.search_result[1])