From 042131d91d0f61d1252d240aa799f3b12b509cfe Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sat, 20 Mar 2021 19:48:25 +0100 Subject: [PATCH] Mainmenu: Improve "Join Game" tab (#11078) --- LICENSE.txt | 10 +- builtin/fstk/tabview.lua | 54 +-- builtin/mainmenu/common.lua | 110 ++--- builtin/mainmenu/tab_online.lua | 452 +++++++++--------- ...flags_favorite.png => server_favorite.png} | Bin textures/base/pack/server_incompatible.png | Bin 0 -> 385 bytes textures/base/pack/server_public.png | Bin 0 -> 492 bytes 7 files changed, 307 insertions(+), 319 deletions(-) rename textures/base/pack/{server_flags_favorite.png => server_favorite.png} (100%) create mode 100644 textures/base/pack/server_incompatible.png create mode 100644 textures/base/pack/server_public.png diff --git a/LICENSE.txt b/LICENSE.txt index 9b8ee851a..2d1c0c795 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -14,6 +14,9 @@ https://www.apache.org/licenses/LICENSE-2.0.html Textures by Zughy are under CC BY-SA 4.0 https://creativecommons.org/licenses/by-sa/4.0/ +textures/base/pack/server_public.png is under CC-BY 4.0, taken from Twitter's Twemoji set +https://creativecommons.org/licenses/by/4.0/ + Authors of media files ----------------------- Everything not listed in here: @@ -39,10 +42,10 @@ erlehmann: misc/minetest.svg textures/base/pack/logo.png -JRottm +JRottm: textures/base/pack/player_marker.png -srifqi +srifqi: textures/base/pack/chat_hide_btn.png textures/base/pack/chat_show_btn.png textures/base/pack/joystick_bg.png @@ -58,6 +61,9 @@ Zughy: textures/base/pack/cdb_update.png textures/base/pack/cdb_viewonline.png +appgurueu: + textures/base/pack/server_incompatible.png + License of Minetest source code ------------------------------- diff --git a/builtin/fstk/tabview.lua b/builtin/fstk/tabview.lua index 3715e231b..424d329fb 100644 --- a/builtin/fstk/tabview.lua +++ b/builtin/fstk/tabview.lua @@ -58,26 +58,20 @@ end -------------------------------------------------------------------------------- local function get_formspec(self) - local formspec = "" - - if not self.hidden and (self.parent == nil or not self.parent.hidden) then - - if self.parent == nil then - local tsize = self.tablist[self.last_tab_index].tabsize or - {width=self.width, height=self.height} - formspec = formspec .. - string.format("size[%f,%f,%s]",tsize.width,tsize.height, - dump(self.fixed_size)) - end - formspec = formspec .. self:tab_header() - formspec = formspec .. - self.tablist[self.last_tab_index].get_formspec( - self, - self.tablist[self.last_tab_index].name, - self.tablist[self.last_tab_index].tabdata, - self.tablist[self.last_tab_index].tabsize - ) + if self.hidden or (self.parent ~= nil and self.parent.hidden) then + return "" end + local tab = self.tablist[self.last_tab_index] + + local content, prepend = tab.get_formspec(self, tab.name, tab.tabdata, tab.tabsize) + + if self.parent == nil and not prepend then + local tsize = tab.tabsize or {width=self.width, height=self.height} + prepend = string.format("size[%f,%f,%s]", tsize.width, tsize.height, + dump(self.fixed_size)) + end + + local formspec = (prepend or "") .. self:tab_header() .. content return formspec end @@ -97,14 +91,9 @@ local function handle_buttons(self,fields) return true end - if self.tablist[self.last_tab_index].button_handler ~= nil then - return - self.tablist[self.last_tab_index].button_handler( - self, - fields, - self.tablist[self.last_tab_index].name, - self.tablist[self.last_tab_index].tabdata - ) + local tab = self.tablist[self.last_tab_index] + if tab.button_handler ~= nil then + return tab.button_handler(self, fields, tab.name, tab.tabdata) end return false @@ -122,14 +111,9 @@ local function handle_events(self,event) return true end - if self.tablist[self.last_tab_index].evt_handler ~= nil then - return - self.tablist[self.last_tab_index].evt_handler( - self, - event, - self.tablist[self.last_tab_index].name, - self.tablist[self.last_tab_index].tabdata - ) + local tab = self.tablist[self.last_tab_index] + if tab.evt_handler ~= nil then + return tab.evt_handler(self, event, tab.name, tab.tabdata) end return false diff --git a/builtin/mainmenu/common.lua b/builtin/mainmenu/common.lua index cd896f9ec..6db351048 100644 --- a/builtin/mainmenu/common.lua +++ b/builtin/mainmenu/common.lua @@ -14,14 +14,11 @@ --You should have received a copy of the GNU Lesser General Public License along --with this program; if not, write to the Free Software Foundation, Inc., --51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. --------------------------------------------------------------------------------- + -- Global menu data --------------------------------------------------------------------------------- menudata = {} --------------------------------------------------------------------------------- -- Local cached values --------------------------------------------------------------------------------- local min_supp_proto, max_supp_proto function common_update_cached_supp_proto() @@ -29,14 +26,12 @@ function common_update_cached_supp_proto() max_supp_proto = core.get_max_supp_proto() end common_update_cached_supp_proto() --------------------------------------------------------------------------------- --- Menu helper functions --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- +-- Menu helper functions + local function render_client_count(n) - if n > 99 then return '99+' - elseif n >= 0 then return tostring(n) + if n > 999 then return '99+' + elseif n >= 0 then return tostring(n) else return '?' end end @@ -50,21 +45,7 @@ local function configure_selected_world_params(idx) end end --------------------------------------------------------------------------------- -function image_column(tooltip, flagname) - return "image,tooltip=" .. core.formspec_escape(tooltip) .. "," .. - "0=" .. core.formspec_escape(defaulttexturedir .. "blank.png") .. "," .. - "1=" .. core.formspec_escape(defaulttexturedir .. - (flagname and "server_flags_" .. flagname .. ".png" or "blank.png")) .. "," .. - "2=" .. core.formspec_escape(defaulttexturedir .. "server_ping_4.png") .. "," .. - "3=" .. core.formspec_escape(defaulttexturedir .. "server_ping_3.png") .. "," .. - "4=" .. core.formspec_escape(defaulttexturedir .. "server_ping_2.png") .. "," .. - "5=" .. core.formspec_escape(defaulttexturedir .. "server_ping_1.png") -end - - --------------------------------------------------------------------------------- -function render_serverlist_row(spec, is_favorite) +function render_serverlist_row(spec) local text = "" if spec.name then text = text .. core.formspec_escape(spec.name:trim()) @@ -75,31 +56,29 @@ function render_serverlist_row(spec, is_favorite) end end - local grey_out = not is_server_protocol_compat(spec.proto_min, spec.proto_max) + local grey_out = not spec.is_compatible - local details - if is_favorite then - details = "1," - else - details = "0," - end + local details = {} - if spec.ping then - local ping = spec.ping * 1000 - if ping <= 50 then - details = details .. "2," - elseif ping <= 100 then - details = details .. "3," - elseif ping <= 250 then - details = details .. "4," + if spec.lag or spec.ping then + local lag = (spec.lag or 0) * 1000 + (spec.ping or 0) * 250 + if lag <= 125 then + table.insert(details, "1") + elseif lag <= 175 then + table.insert(details, "2") + elseif lag <= 250 then + table.insert(details, "3") else - details = details .. "5," + table.insert(details, "4") end else - details = details .. "0," + table.insert(details, "0") end - if spec.clients and spec.clients_max then + table.insert(details, ",") + + local color = (grey_out and "#aaaaaa") or ((spec.is_favorite and "#ddddaa") or "#ffffff") + if spec.clients and (spec.clients_max or 0) > 0 then local clients_percent = 100 * spec.clients / spec.clients_max -- Choose a color depending on how many clients are connected @@ -110,38 +89,35 @@ function render_serverlist_row(spec, is_favorite) elseif clients_percent <= 60 then clients_color = '#a1e587' -- 0-60%: green elseif clients_percent <= 90 then clients_color = '#ffdc97' -- 60-90%: yellow elseif clients_percent == 100 then clients_color = '#dd5b5b' -- full server: red (darker) - else clients_color = '#ffba97' -- 90-100%: orange + else clients_color = '#ffba97' -- 90-100%: orange end - details = details .. clients_color .. ',' .. - render_client_count(spec.clients) .. ',/,' .. - render_client_count(spec.clients_max) .. ',' - - elseif grey_out then - details = details .. '#aaaaaa,?,/,?,' + table.insert(details, clients_color) + table.insert(details, render_client_count(spec.clients) .. " / " .. + render_client_count(spec.clients_max)) else - details = details .. ',?,/,?,' + table.insert(details, color) + table.insert(details, "?") end if spec.creative then - details = details .. "1," + table.insert(details, "1") -- creative icon else - details = details .. "0," - end - - if spec.damage then - details = details .. "1," - else - details = details .. "0," + table.insert(details, "0") end if spec.pvp then - details = details .. "1," + table.insert(details, "2") -- pvp icon + elseif spec.damage then + table.insert(details, "1") -- heart icon else - details = details .. "0," + table.insert(details, "0") end - return details .. (grey_out and '#aaaaaa,' or ',') .. text + table.insert(details, color) + table.insert(details, text) + + return table.concat(details, ",") end -------------------------------------------------------------------------------- @@ -150,14 +126,13 @@ os.tempfolder = function() return temp .. DIR_DELIM .. "MT_" .. math.random(0, 10000) end --------------------------------------------------------------------------------- os.tmpname = function() local path = os.tempfolder() io.open(path, "w"):close() return path end - -------------------------------------------------------------------------------- + function menu_render_worldlist() local retval = "" local current_worldlist = menudata.worldlist:get_list() @@ -171,7 +146,6 @@ function menu_render_worldlist() return retval end --------------------------------------------------------------------------------- function menu_handle_key_up_down(fields, textlist, settingname) local oldidx, newidx = core.get_textlist_index(textlist), 1 if fields.key_up or fields.key_down then @@ -188,7 +162,6 @@ function menu_handle_key_up_down(fields, textlist, settingname) return false end --------------------------------------------------------------------------------- function text2textlist(xpos, ypos, width, height, tl_name, textlen, text, transparency) local textlines = core.wrap_text(text, textlen, true) local retval = "textlist[" .. xpos .. "," .. ypos .. ";" .. width .. @@ -206,7 +179,6 @@ function text2textlist(xpos, ypos, width, height, tl_name, textlen, text, transp return retval end --------------------------------------------------------------------------------- function is_server_protocol_compat(server_proto_min, server_proto_max) if (not server_proto_min) or (not server_proto_max) then -- There is no info. Assume the best and act as if we would be compatible. @@ -214,7 +186,7 @@ function is_server_protocol_compat(server_proto_min, server_proto_max) end return min_supp_proto <= server_proto_max and max_supp_proto >= server_proto_min end --------------------------------------------------------------------------------- + function is_server_protocol_compat_or_error(server_proto_min, server_proto_max) if not is_server_protocol_compat(server_proto_min, server_proto_max) then local server_prot_ver_info, client_prot_ver_info @@ -242,7 +214,7 @@ function is_server_protocol_compat_or_error(server_proto_min, server_proto_max) return true end --------------------------------------------------------------------------------- + function menu_worldmt(selected, setting, value) local world = menudata.worldlist:get_list()[selected] if world then diff --git a/builtin/mainmenu/tab_online.lua b/builtin/mainmenu/tab_online.lua index e6748ed88..fb7409864 100644 --- a/builtin/mainmenu/tab_online.lua +++ b/builtin/mainmenu/tab_online.lua @@ -15,17 +15,50 @@ --with this program; if not, write to the Free Software Foundation, Inc., --51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. --------------------------------------------------------------------------------- +local function get_sorted_servers() + local servers = { + fav = {}, + public = {}, + incompatible = {} + } + + local favs = serverlistmgr.get_favorites() + local taken_favs = {} + local result = menudata.search_result or serverlistmgr.servers + for _, server in ipairs(result) do + server.is_favorite = false + for index, fav in ipairs(favs) do + if server.address == fav.address and server.port == fav.port then + taken_favs[index] = true + server.is_favorite = true + break + end + end + server.is_compatible = is_server_protocol_compat(server.proto_min, server.proto_max) + if server.is_favorite then + table.insert(servers.fav, server) + elseif server.is_compatible then + table.insert(servers.public, server) + else + table.insert(servers.incompatible, server) + end + end + + if not menudata.search_result then + for index, fav in ipairs(favs) do + if not taken_favs[index] then + table.insert(servers.fav, fav) + end + end + end + + return servers +end + local function get_formspec(tabview, name, tabdata) -- Update the cached supported proto info, -- it may have changed after a change by the settings menu. common_update_cached_supp_proto() - local selected - if menudata.search_result then - selected = menudata.search_result[tabdata.selected] - else - selected = serverlistmgr.servers[tabdata.selected] - end if not tabdata.search_for then tabdata.search_for = "" @@ -33,128 +66,221 @@ local function get_formspec(tabview, name, tabdata) local retval = -- Search - "field[0.15,0.075;5.91,1;te_search;;" .. core.formspec_escape(tabdata.search_for) .. "]" .. - "image_button[5.63,-.165;.83,.83;" .. core.formspec_escape(defaulttexturedir .. "search.png") .. ";btn_mp_search;]" .. - "image_button[6.3,-.165;.83,.83;" .. core.formspec_escape(defaulttexturedir .. "clear.png") .. ";btn_mp_clear;]" .. - "image_button[6.97,-.165;.83,.83;" .. core.formspec_escape(defaulttexturedir .. "refresh.png") - .. ";btn_mp_refresh;]" .. + "field[0.25,0.25;7,0.75;te_search;;" .. core.formspec_escape(tabdata.search_for) .. "]" .. + "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.75,0;0.75,0.75;" .. core.formspec_escape(defaulttexturedir .. "clear.png") .. ";btn_mp_clear;]" .. + "image_button[1.5,0;0.75,0.75;" .. core.formspec_escape(defaulttexturedir .. "refresh.png") .. ";btn_mp_refresh;]" .. + "tooltip[btn_mp_clear;" .. fgettext("Clear") .. "]" .. + "tooltip[btn_mp_search;" .. fgettext("Search") .. "]" .. + "tooltip[btn_mp_refresh;" .. fgettext("Refresh") .. "]" .. + "container_end[]" .. + + "container[9.75,0]" .. + "box[0,0;5.75,7;#666666]" .. -- Address / Port - "label[7.75,-0.25;" .. fgettext("Address / Port") .. "]" .. - "field[8,0.65;3.25,0.5;te_address;;" .. + "label[0.25,0.35;" .. fgettext("Address") .. "]" .. + "label[4.25,0.35;" .. fgettext("Port") .. "]" .. + "field[0.25,0.5;4,0.75;te_address;;" .. core.formspec_escape(core.settings:get("address")) .. "]" .. - "field[11.1,0.65;1.4,0.5;te_port;;" .. + "field[4.25,0.5;1.25,0.75;te_port;;" .. core.formspec_escape(core.settings:get("remote_port")) .. "]" .. -- Name / Password - "label[7.75,0.95;" .. fgettext("Name / Password") .. "]" .. - "field[8,1.85;2.9,0.5;te_name;;" .. + "label[0.25,1.55;" .. fgettext("Name") .. "]" .. + "label[3,1.55;" .. fgettext("Password") .. "]" .. + "field[0.25,1.75;2.75,0.75;te_name;;" .. core.formspec_escape(core.settings:get("name")) .. "]" .. - "pwdfield[10.73,1.85;1.77,0.5;te_pwd;]" .. + "pwdfield[3,1.75;2.5,0.75;te_pwd;]" .. -- Description Background - "box[7.73,2.25;4.25,2.6;#999999]".. + "label[0.25,2.75;" .. fgettext("Server Description") .. "]" .. + "box[0.25,3;5.25,2.75;#999999]".. -- Connect - "button[9.88,4.9;2.3,1;btn_mp_connect;" .. fgettext("Connect") .. "]" + "button[3,6;2.5,0.75;btn_mp_connect;" .. fgettext("Connect") .. "]" - if tabdata.selected and selected then + if tabdata.selected then if gamedata.fav then - retval = retval .. "button[7.73,4.9;2.3,1;btn_delete_favorite;" .. + retval = retval .. "button[0.25,6;2.5,0.75;btn_delete_favorite;" .. fgettext("Del. Favorite") .. "]" end - if selected.description then - retval = retval .. "textarea[8.1,2.3;4.23,2.9;;;" .. - core.formspec_escape((gamedata.serverdescription or ""), true) .. "]" + if gamedata.serverdescription then + retval = retval .. "textarea[0.25,3;5.25,2.75;;;" .. + core.formspec_escape(gamedata.serverdescription) .. "]" end end - --favorites + retval = retval .. "container_end[]" + + -- Table retval = retval .. "tablecolumns[" .. - image_column(fgettext("Favorite"), "favorite") .. ";" .. - image_column(fgettext("Ping")) .. ",padding=0.25;" .. - "color,span=3;" .. - "text,align=right;" .. -- clients - "text,align=center,padding=0.25;" .. -- "/" - "text,align=right,padding=0.25;" .. -- clients_max - image_column(fgettext("Creative mode"), "creative") .. ",padding=1;" .. - image_column(fgettext("Damage enabled"), "damage") .. ",padding=0.25;" .. - --~ PvP = Player versus Player - image_column(fgettext("PvP enabled"), "pvp") .. ",padding=0.25;" .. + "image,tooltip=" .. fgettext("Ping") .. "," .. + "0=" .. core.formspec_escape(defaulttexturedir .. "blank.png") .. "," .. + "1=" .. core.formspec_escape(defaulttexturedir .. "server_ping_4.png") .. "," .. + "2=" .. core.formspec_escape(defaulttexturedir .. "server_ping_3.png") .. "," .. + "3=" .. core.formspec_escape(defaulttexturedir .. "server_ping_2.png") .. "," .. + "4=" .. core.formspec_escape(defaulttexturedir .. "server_ping_1.png") .. "," .. + "5=" .. core.formspec_escape(defaulttexturedir .. "server_favorite.png") .. "," .. + "6=" .. core.formspec_escape(defaulttexturedir .. "server_public.png") .. "," .. + "7=" .. core.formspec_escape(defaulttexturedir .. "server_incompatible.png") .. ";" .. "color,span=1;" .. - "text,padding=1]" .. - "table[-0.15,0.6;7.75,5.15;favorites;" + "text,align=inline;".. + "color,span=1;" .. + "text,align=inline,width=4.25;" .. + "image,tooltip=" .. fgettext("Creative mode") .. "," .. + "0=" .. core.formspec_escape(defaulttexturedir .. "blank.png") .. "," .. + "1=" .. core.formspec_escape(defaulttexturedir .. "server_flags_creative.png") .. "," .. + "align=inline,padding=0.25,width=1.5;" .. + --~ PvP = Player versus Player + "image,tooltip=" .. fgettext("Damage / PvP") .. "," .. + "0=" .. core.formspec_escape(defaulttexturedir .. "blank.png") .. "," .. + "1=" .. core.formspec_escape(defaulttexturedir .. "server_flags_damage.png") .. "," .. + "2=" .. core.formspec_escape(defaulttexturedir .. "server_flags_pvp.png") .. "," .. + "align=inline,padding=0.25,width=1.5;" .. + "color,align=inline,span=1;" .. + "text,align=inline,padding=1]" .. + "table[0.25,1;9.25,5.75;servers;" - if menudata.search_result then - local favs = serverlistmgr.get_favorites() - for i = 1, #menudata.search_result do - local server = menudata.search_result[i] - for fav_id = 1, #favs do - if server.address == favs[fav_id].address and - server.port == favs[fav_id].port then - server.is_favorite = true - end + local servers = get_sorted_servers() + + local dividers = { + fav = "5,#ffff00," .. fgettext("Favorites") .. ",,,0,0,,", + public = "6,#4bdd42," .. fgettext("Public Servers") .. ",,,0,0,,", + incompatible = "7,"..mt_color_grey.."," .. fgettext("Incompatible Servers") .. ",,,0,0,," + } + local order = {"fav", "public", "incompatible"} + + tabdata.lookup = {} -- maps row number to server + local rows = {} + for _, section in ipairs(order) do + local section_servers = servers[section] + if next(section_servers) ~= nil then + rows[#rows + 1] = dividers[section] + for _, server in ipairs(section_servers) do + tabdata.lookup[#rows + 1] = server + rows[#rows + 1] = render_serverlist_row(server) end - - if i ~= 1 then - retval = retval .. "," - end - - retval = retval .. render_serverlist_row(server, server.is_favorite) - end - elseif #serverlistmgr.servers > 0 then - local favs = serverlistmgr.get_favorites() - if #favs > 0 then - for i = 1, #favs do - for j = 1, #serverlistmgr.servers do - if serverlistmgr.servers[j].address == favs[i].address and - serverlistmgr.servers[j].port == favs[i].port then - table.insert(serverlistmgr.servers, i, table.remove(serverlistmgr.servers, j)) - end - end - if favs[i].address ~= serverlistmgr.servers[i].address then - table.insert(serverlistmgr.servers, i, favs[i]) - end - end - end - - retval = retval .. render_serverlist_row(serverlistmgr.servers[1], (#favs > 0)) - for i = 2, #serverlistmgr.servers do - retval = retval .. "," .. render_serverlist_row(serverlistmgr.servers[i], (i <= #favs)) end end + retval = retval .. table.concat(rows, ",") + if tabdata.selected then retval = retval .. ";" .. tabdata.selected .. "]" else retval = retval .. ";0]" end - return retval + return retval, "size[15.5,7,false]real_coordinates[true]" end -------------------------------------------------------------------------------- -local function main_button_handler(tabview, fields, name, tabdata) - local serverlist = menudata.search_result or serverlistmgr.servers +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 + word = word:gsub("(%W)", "%%%1") + table.insert(keywords, word) + end + + if #keywords == 0 then + return + end + + menudata.search_result = {} + + -- Search the serverlist + local search_result = {} + for i = 1, #serverlistmgr.servers do + local server = serverlistmgr.servers[i] + local found = 0 + for k = 1, #keywords do + local keyword = keywords[k] + if server.name then + local sername = server.name:lower() + local _, count = sername:gsub(keyword, keyword) + found = found + count * 4 + end + + if server.description then + local desc = server.description:lower() + local _, count = desc:gsub(keyword, keyword) + found = found + count * 2 + end + end + if found > 0 then + local points = (#serverlistmgr.servers - i) / 5 + found + server.points = points + table.insert(search_result, server) + end + end + + if #search_result == 0 then + return + end + + table.sort(search_result, function(a, b) + return a.points > b.points + end) + menudata.search_result = search_result +end + +local function set_selected_server(tabdata, idx, server) + -- reset selection + if idx == nil or server == nil then + tabdata.selected = nil + + core.settings:set("address", "") + core.settings:set("remote_port", "30000") + return + end + + local address = server.address + local port = server.port + gamedata.serverdescription = server.description + + gamedata.fav = false + for _, fav in ipairs(serverlistmgr.get_favorites()) do + if address == fav.address and port == fav.port then + gamedata.fav = true + break + end + end + + if address and port then + core.settings:set("address", address) + core.settings:set("remote_port", port) + end + tabdata.selected = idx +end + +local function main_button_handler(tabview, fields, name, tabdata) if fields.te_name then gamedata.playername = fields.te_name core.settings:set("name", fields.te_name) end - if fields.favorites then - local event = core.explode_table_event(fields.favorites) - local fav = serverlist[event.row] + if fields.servers then + local event = core.explode_table_event(fields.servers) + local server = tabdata.lookup[event.row] - if event.type == "DCL" then - if event.row <= #serverlist then + if server then + if event.type == "DCL" then if not is_server_protocol_compat_or_error( - fav.proto_min, fav.proto_max) then + server.proto_min, server.proto_max) then return true end - gamedata.address = fav.address - gamedata.port = fav.port + gamedata.address = server.address + gamedata.port = server.port gamedata.playername = fields.te_name gamedata.selected_world = 0 @@ -162,84 +288,32 @@ local function main_button_handler(tabview, fields, name, tabdata) gamedata.password = fields.te_pwd end - gamedata.servername = fav.name - gamedata.serverdescription = fav.description + gamedata.servername = server.name + gamedata.serverdescription = server.description if gamedata.address and gamedata.port then core.settings:set("address", gamedata.address) core.settings:set("remote_port", gamedata.port) core.start() end + return true end - return true - end - - if event.type == "CHG" then - if event.row <= #serverlist then - gamedata.fav = false - local favs = serverlistmgr.get_favorites() - local address = fav.address - local port = fav.port - gamedata.serverdescription = fav.description - - for i = 1, #favs do - if fav.address == favs[i].address and - fav.port == favs[i].port then - gamedata.fav = true - end - end - - if address and port then - core.settings:set("address", address) - core.settings:set("remote_port", port) - end - tabdata.selected = event.row + if event.type == "CHG" then + set_selected_server(tabdata, event.row, server) + return true end - return true end end - if fields.key_up or fields.key_down then - local fav_idx = core.get_table_index("favorites") - local fav = serverlist[fav_idx] - - if fav_idx then - if fields.key_up and fav_idx > 1 then - fav_idx = fav_idx - 1 - elseif fields.key_down and fav_idx < #serverlistmgr.servers then - fav_idx = fav_idx + 1 - end - else - fav_idx = 1 - end - - if not serverlistmgr.servers or not fav then - tabdata.selected = 0 - return true - end - - local address = fav.address - local port = fav.port - gamedata.serverdescription = fav.description - if address and port then - core.settings:set("address", address) - core.settings:set("remote_port", port) - end - - tabdata.selected = fav_idx - return true - end - if fields.btn_delete_favorite then - local current_favorite = core.get_table_index("favorites") - if not current_favorite then return end + local idx = core.get_table_index("servers") + if not idx then return end + local server = tabdata.lookup[idx] + if not server then return end - serverlistmgr.delete_favorite(serverlistmgr.servers[current_favorite]) - serverlistmgr.sync() - tabdata.selected = nil - - core.settings:set("address", "") - core.settings:set("remote_port", "30000") + serverlistmgr.delete_favorite(server) + -- the server at [idx+1] will be at idx once list is refreshed + set_selected_server(tabdata, idx, tabdata.lookup[idx+1]) return true end @@ -250,63 +324,13 @@ local function main_button_handler(tabview, fields, name, tabdata) end if fields.btn_mp_search or fields.key_enter_field == "te_search" then - tabdata.selected = 1 - local input = fields.te_search:lower() tabdata.search_for = fields.te_search - - if #serverlistmgr.servers < 2 then - return true + search_server_list(fields.te_search:lower()) + if menudata.search_result then + -- first server in row 2 due to header + set_selected_server(tabdata, 2, menudata.search_result[1]) end - menudata.search_result = {} - - -- setup the keyword list - local keywords = {} - for word in input:gmatch("%S+") do - word = word:gsub("(%W)", "%%%1") - table.insert(keywords, word) - end - - if #keywords == 0 then - menudata.search_result = nil - return true - end - - -- Search the serverlist - local search_result = {} - for i = 1, #serverlistmgr.servers do - local server = serverlistmgr.servers[i] - local found = 0 - for k = 1, #keywords do - local keyword = keywords[k] - if server.name then - local sername = server.name:lower() - local _, count = sername:gsub(keyword, keyword) - found = found + count * 4 - end - - if server.description then - local desc = server.description:lower() - local _, count = desc:gsub(keyword, keyword) - found = found + count * 2 - end - end - if found > 0 then - local points = (#serverlistmgr.servers - i) / 5 + found - server.points = points - table.insert(search_result, server) - end - end - if #search_result > 0 then - table.sort(search_result, function(a, b) - return a.points > b.points - end) - menudata.search_result = search_result - local first_server = search_result[1] - core.settings:set("address", first_server.address) - core.settings:set("remote_port", first_server.port) - gamedata.serverdescription = first_server.description - end return true end @@ -322,20 +346,22 @@ local function main_button_handler(tabview, fields, name, tabdata) gamedata.address = fields.te_address gamedata.port = tonumber(fields.te_port) gamedata.selected_world = 0 - local fav_idx = core.get_table_index("favorites") - local fav = serverlist[fav_idx] - if fav_idx and fav_idx <= #serverlist and - fav.address == gamedata.address and - fav.port == gamedata.port then + local idx = core.get_table_index("servers") + local server = idx and tabdata.lookup[idx] - serverlistmgr.add_favorite(fav) + set_selected_server(tabdata) - gamedata.servername = fav.name - gamedata.serverdescription = fav.description + if server and server.address == gamedata.address and + server.port == gamedata.port then + + serverlistmgr.add_favorite(server) + + gamedata.servername = server.name + gamedata.serverdescription = server.description if not is_server_protocol_compat_or_error( - fav.proto_min, fav.proto_max) then + server.proto_min, server.proto_max) then return true end else @@ -354,6 +380,7 @@ local function main_button_handler(tabview, fields, name, tabdata) core.start() return true end + return false end @@ -362,7 +389,6 @@ local function on_change(type, old_tab, new_tab) serverlistmgr.sync() end --------------------------------------------------------------------------------- return { name = "online", caption = fgettext("Join Game"), diff --git a/textures/base/pack/server_flags_favorite.png b/textures/base/pack/server_favorite.png similarity index 100% rename from textures/base/pack/server_flags_favorite.png rename to textures/base/pack/server_favorite.png diff --git a/textures/base/pack/server_incompatible.png b/textures/base/pack/server_incompatible.png new file mode 100644 index 0000000000000000000000000000000000000000..9076ab58f06b5ac6b1ca8ebd44773c4140a64b0f GIT binary patch literal 385 zcmV-{0e=38P)At56opTM;395u(j|@t5+o`v;wFM1*2ztmJ}4dP)F0sF)Ck&a`5*p=IEkZwLKHDC za=O%jtuYpQ$9KPT-hKBx;6I8&xEu_o5A(J?Wwq)8fC>QE?RI#28nf4%CyLAEISgZr z(`k3z==U9Zo@BS{#)>PI8Al^Y%lfHY1aJ;?&Or zWx0Ig;gCYTE^s`mlv2Vl1bp99*6WwMw_i9x|J~Hlb}#IUEKom6E@5CNrm|Nv6|N;Ic$j&0@9sP&S+QBm-r?f2EWM fgkd&`eW<c#H5WF&~;`|^V2tXiU#NGRa%j6XzR0MXT!n)lTND#sgSe=0M6n9RkQc*B$e?fo| zyKtX^luR)ef@G>&-0du8ZpXPE(rKBn#u+Q_Sn$k(XI9*?##uTolm7by-cQOmELgDM zi4_l7i02flF=-rUA)d41fdx-2SkP!W_@kK=B@2|r>fu$HIp-V)iWVt2rR&fSkovEVk;@H3bySTP$8Q3%0DtS+HZlC2KR8#a3Qy^-|-K z1-tgVO{bg0vBp^@)t8U@^DPN(y3)E5_8`GcGAYkU<7X0^I~Lr2`1<|br?4ikxc(b~ zS6tIo#mS^RW5KQSieDU%lcMl~c+mTr2LZVkL{b#({bNI*$o-yRulF?%v?1_{qP>4~ zEU}fa`9BH&ZlWEV*sgB#_kx{QyEx^6SG(|nT|*q}bh=48ixjt{C|F~C+5@Y-_7=%G z=V-JXkk~qtN?EMV0*0qnnF53aYa0DH&I65>gX1t&ZJ4TY7OGyDdd*#=(@jERa~8Wl i#98c~#O4Rh9sCB{Tao+q-1zta0000