mirror of
				https://github.com/luanti-org/luanti.git
				synced 2025-11-04 01:05:48 +01:00 
			
		
		
		
	Main menu server tab search improvements
This commit is contained in:
		@@ -112,6 +112,7 @@ local function get_formspec(tabview, name, tabdata)
 | 
			
		||||
	local retval =
 | 
			
		||||
		-- Search
 | 
			
		||||
		"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]" ..
 | 
			
		||||
		"container[7.25,0.25]" ..
 | 
			
		||||
		"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)
 | 
			
		||||
	menudata.search_result = nil
 | 
			
		||||
	if #serverlistmgr.servers < 2 then
 | 
			
		||||
		return
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	-- setup the keyword list
 | 
			
		||||
	local keywords = {}
 | 
			
		||||
	for word in input:gmatch("%S+") do
 | 
			
		||||
		table.insert(keywords, word:lower())
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	if #keywords == 0 then
 | 
			
		||||
	-- setup the search query
 | 
			
		||||
	local query = parse_search_input(input)
 | 
			
		||||
	if not query then
 | 
			
		||||
		return
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
@@ -292,16 +380,9 @@ local function search_server_list(input)
 | 
			
		||||
	-- Search the serverlist
 | 
			
		||||
	local search_result = {}
 | 
			
		||||
	for i, server in ipairs(serverlistmgr.servers) do
 | 
			
		||||
		local name_matches, description_matches = true, true
 | 
			
		||||
		for _, keyword in ipairs(keywords) do
 | 
			
		||||
			name_matches = name_matches and not not
 | 
			
		||||
					(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)
 | 
			
		||||
		local match = matches_query(server, query)
 | 
			
		||||
		if match then
 | 
			
		||||
			server.points = #serverlistmgr.servers - i + match
 | 
			
		||||
			table.insert(search_result, server)
 | 
			
		||||
		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
 | 
			
		||||
		tabdata.search_for = fields.te_search
 | 
			
		||||
		search_server_list(fields.te_search:lower())
 | 
			
		||||
		search_server_list(fields.te_search)
 | 
			
		||||
		if menudata.search_result then
 | 
			
		||||
			-- Note: This clears the selection if there are no results
 | 
			
		||||
			set_selected_server(menudata.search_result[1])
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user