Server: announce MIN/MAX protocol version supported to serverlist. Client: check...
authorest31 <MTest31@outlook.com>
Tue, 17 Feb 2015 00:37:14 +0000 (01:37 +0100)
committerLoic Blot <loic.blot@unix-experience.fr>
Wed, 18 Feb 2015 15:17:03 +0000 (16:17 +0100)
Client now informs about incompatible servers from the list, this permits to prevent the protocol movements.
Server announces its supported protocol versions to master server

builtin/common/misc_helpers.lua
builtin/mainmenu/common.lua
builtin/mainmenu/tab_multiplayer.lua
builtin/mainmenu/tab_simple_main.lua
doc/menu_lua_api.txt
src/script/lua_api/l_mainmenu.cpp
src/script/lua_api/l_mainmenu.h
src/serverlist.cpp

index d9ebc39c3dbc5e618c3a6b0dcf13c5746397130f..39fca7d1e919a1593a9326411cfcdfd0979e749d 100644 (file)
@@ -564,7 +564,7 @@ if INIT == "mainmenu" then
                return nil
        end
 
-       function fgettext(text, ...)
+       function fgettext_ne(text, ...)
                text = core.gettext(text)
                local arg = {n=select('#', ...), ...}
                if arg.n >= 1 then
@@ -586,7 +586,11 @@ if INIT == "mainmenu" then
                        end
                        text = result
                end
-               return core.formspec_escape(text)
+               return text
+       end
+
+       function fgettext(text, ...)
+               return core.formspec_escape(fgettext_ne(text, ...))
        end
 end
 
index 549c0967b207b5650942c38f62d5d7f542d426e4..f32d77f2a4a03c11c85782517e8b19c2eb3f5b46 100644 (file)
 --51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 --------------------------------------------------------------------------------
 -- Global menu data
----------------------------------------------------------------------------------
+--------------------------------------------------------------------------------
 menudata = {}
 
+--------------------------------------------------------------------------------
+-- Local cached values
+--------------------------------------------------------------------------------
+local min_supp_proto = core.get_min_supp_proto()
+local max_supp_proto = core.get_max_supp_proto()
+
 --------------------------------------------------------------------------------
 -- Menu helper functions
 --------------------------------------------------------------------------------
@@ -42,6 +48,25 @@ function image_column(tooltip, flagname)
                "1=" .. core.formspec_escape(defaulttexturedir .. "server_flags_" .. flagname .. ".png")
 end
 
+--------------------------------------------------------------------------------
+function order_favorite_list(list)
+       local res = {}
+       --orders the favorite list after support
+       for i=1,#list,1 do
+               local fav = list[i]
+               if is_server_protocol_compat(fav.proto_min, fav.proto_max) then
+                       table.insert(res, fav)
+               end
+       end
+       for i=1,#list,1 do
+               local fav = list[i]
+               if not is_server_protocol_compat(fav.proto_min, fav.proto_max) then
+                       table.insert(res, fav)
+               end
+       end
+       return res
+end
+
 --------------------------------------------------------------------------------
 function render_favorite(spec,render_details)
        local text = ""
@@ -68,6 +93,7 @@ function render_favorite(spec,render_details)
        end
 
        local details = ""
+       local grey_out = not is_server_protocol_compat(spec.proto_max, spec.proto_min)
 
        if spec.clients ~= nil and spec.clients_max ~= nil then
                local clients_color = ''
@@ -87,11 +113,17 @@ function render_favorite(spec,render_details)
                        clients_color = '#ffba97' -- 90-100%: orange
                end
 
+               if grey_out then
+                       clients_color = '#aaaaaa'
+               end
+
                details = details ..
                                clients_color .. ',' ..
                                render_client_count(spec.clients) .. ',' ..
                                '/,' ..
                                render_client_count(spec.clients_max) .. ','
+       elseif grey_out then
+               details = details .. '#aaaaaa,?,/,?,'
        else
                details = details .. ',?,/,?,'
        end
@@ -114,7 +146,7 @@ function render_favorite(spec,render_details)
                details = details .. "0,"
        end
 
-       return details .. text
+       return details .. (grey_out and '#aaaaaa,' or ',') .. text
 end
 
 --------------------------------------------------------------------------------
@@ -195,7 +227,7 @@ function asyncOnlineFavourites()
                nil,
                function(result)
                        if core.setting_getbool("public_serverlist") then
-                               menudata.favorites = result
+                               menudata.favorites = order_favorite_list(result)
                                core.event_handler("Refresh")
                        end
                end
@@ -225,3 +257,21 @@ function text2textlist(xpos,ypos,width,height,tl_name,textlen,text,transparency)
 
        return retval
 end
+
+--------------------------------------------------------------------------------
+function is_server_protocol_compat(proto_min, proto_max)
+       return not ((min_supp_proto > (proto_max or 24)) or (max_supp_proto < (proto_min or 13)))
+end
+--------------------------------------------------------------------------------
+function is_server_protocol_compat_or_error(proto_min, proto_max)
+       if not is_server_protocol_compat(proto_min, proto_max) then
+               gamedata.errormessage = fgettext_ne("Protocol version mismatch, server " ..
+                       ((proto_min ~= proto_max) and "supports protocols between $1 and $2" or "enforces protocol version $1") ..
+                       ", we " ..
+                       ((min_supp_proto ~= max_supp_proto) and "support protocols between version $3 and $4." or "only support protocol version $3"),
+                       proto_min or 13, proto_max or 24, min_supp_proto, max_supp_proto)
+               return false
+       end
+
+       return true
+end
index 734cb5d3efd7cf1046b053adb68b5c130b0a564c..f9ac78f17132f5c50ea9a909e32bf044b487173d 100644 (file)
@@ -62,6 +62,7 @@ local function get_formspec(tabview, name, tabdata)
                        image_column(fgettext("Creative mode"), "creative") .. ",padding=1;" ..
                        image_column(fgettext("Damage enabled"), "damage") .. ",padding=0.25;" ..
                        image_column(fgettext("PvP enabled"), "pvp") .. ",padding=0.25;" ..
+                       "color,span=1;" ..
                        "text,padding=1]"                               -- name
        else
                retval = retval .. "tablecolumns[text]"
@@ -88,7 +89,6 @@ end
 
 --------------------------------------------------------------------------------
 local function main_button_handler(tabview, fields, name, tabdata)
-
        if fields["te_name"] ~= nil then
                gamedata.playername = fields["te_name"]
                core.setting_set("name", fields["te_name"])
@@ -98,6 +98,10 @@ local function main_button_handler(tabview, fields, name, tabdata)
                local event = core.explode_table_event(fields["favourites"])
                if event.type == "DCL" then
                        if event.row <= #menudata.favorites then
+                               if not is_server_protocol_compat_or_error(menudata.favorites[event.row].proto_min,
+                                               menudata.favorites[event.row].proto_max) then
+                                       return true
+                               end
                                gamedata.address    = menudata.favorites[event.row].address
                                gamedata.port       = menudata.favorites[event.row].port
                                gamedata.playername = fields["te_name"]
@@ -189,7 +193,7 @@ local function main_button_handler(tabview, fields, name, tabdata)
                local current_favourite = core.get_table_index("favourites")
                if current_favourite == nil then return end
                core.delete_favorite(current_favourite)
-               menudata.favorites   = core.get_favorites()
+               menudata.favorites = order_favorite_list(core.get_favorites())
                tabdata.fav_selected = nil
 
                core.setting_set("address","")
@@ -214,6 +218,11 @@ local function main_button_handler(tabview, fields, name, tabdata)
 
                        gamedata.servername        = menudata.favorites[fav_idx].name
                        gamedata.serverdescription = menudata.favorites[fav_idx].description
+
+                       if not is_server_protocol_compat_or_error(menudata.favorites[fav_idx].proto_min,
+                                       menudata.favorites[fav_idx].proto_max)then
+                               return true
+                       end
                else
                        gamedata.servername        = ""
                        gamedata.serverdescription = ""
index 87bd551c05c30fa884ba841a3c690eab355a8d84..b9a6b650fa74b57d7370824c69a1ef2890505ab6 100644 (file)
@@ -45,6 +45,7 @@ local function get_formspec(tabview, name, tabdata)
                        image_column(fgettext("Creative mode"), "creative") .. ",padding=1;" ..
                        image_column(fgettext("Damage enabled"), "damage") .. ",padding=0.25;" ..
                        image_column(fgettext("PvP enabled"), "pvp") .. ",padding=0.25;" ..
+                       "color,span=1;" ..
                        "text,padding=1]"                               -- name
        else
                retval = retval .. "tablecolumns[text]"
@@ -87,7 +88,6 @@ local function get_formspec(tabview, name, tabdata)
 end
 
 --------------------------------------------------------------------------------
-
 local function main_button_handler(tabview, fields, name, tabdata)
 
        if fields["btn_start_singleplayer"] then
@@ -159,6 +159,11 @@ local function main_button_handler(tabview, fields, name, tabdata)
 
                        gamedata.servername                     = menudata.favorites[fav_idx].name
                        gamedata.serverdescription      = menudata.favorites[fav_idx].description
+
+                       if not is_server_protocol_compat_or_error(menudata.favorites[fav_idx].proto_min,
+                                       menudata.favorites[fav_idx].proto_max) then
+                               return true
+                       end
                else
                        gamedata.servername                     = ""
                        gamedata.serverdescription      = ""
index 5c0f90df65bdbbfd9c05a29f242cc71d912791f8..f76124a0d5bbf1d73f30f7b60c628e9c4064e748 100644 (file)
@@ -197,9 +197,11 @@ core.delete_world(index)
 Helpers:
 core.gettext(string) -> string
 ^ look up the translation of a string in the gettext message catalog
-fgettext(string, ...) -> string
+fgettext_ne(string, ...)
 ^ call core.gettext(string), replace "$1"..."$9" with the given
-^ extra arguments, call core.formspec_escape and return the result
+^ extra arguments and return the result
+fgettext(string, ...) -> string
+^ same as fgettext_ne(), but calls core.formspec_escape before returning result
 core.parse_json(string[, nullvalue]) -> something (possible in async calls)
 ^ see core.parse_json (lua_api.txt)
 dump(obj, dumped={})
@@ -211,6 +213,12 @@ string:trim()
 core.is_yes(arg) (possible in async calls)
 ^ returns whether arg can be interpreted as yes
 
+Version compat:
+core.get_min_supp_proto()
+^ returns the minimum supported network protocol version
+core.get_max_supp_proto()
+^ returns the maximum supported network protocol version
+
 Async:
 core.handle_async(async_job,parameters,finished)
 ^ execute a function asynchronously
index 0d8365106e123c3187c349bafe272a5d17f99191..2bed2a255f6f9383e2421035a03d334ec48afcc6 100644 (file)
@@ -472,6 +472,7 @@ int ModApiMainMenu::l_get_favorites(lua_State *L)
 
        for (unsigned int i = 0; i < servers.size(); i++)
        {
+
                lua_pushnumber(L,index);
 
                lua_newtable(L);
@@ -509,6 +510,18 @@ int ModApiMainMenu::l_get_favorites(lua_State *L)
                        lua_settable(L, top_lvl2);
                }
 
+               if (servers[i]["proto_min"].asString().size()) {
+                       lua_pushstring(L,"proto_min");
+                       lua_pushinteger(L,servers[i]["proto_min"].asInt());
+                       lua_settable(L, top_lvl2);
+               }
+
+               if (servers[i]["proto_max"].asString().size()) {
+                       lua_pushstring(L,"proto_max");
+                       lua_pushinteger(L,servers[i]["proto_max"].asInt());
+                       lua_settable(L, top_lvl2);
+               }
+
                if (servers[i]["password"].asString().size()) {
                        lua_pushstring(L,"password");
                        lua_pushboolean(L,servers[i]["password"].asBool());
@@ -1082,6 +1095,19 @@ int ModApiMainMenu::l_get_screen_info(lua_State *L)
        return 1;
 }
 
+/******************************************************************************/
+int ModApiMainMenu::l_get_min_supp_proto(lua_State *L)
+{
+       lua_pushinteger(L, CLIENT_PROTOCOL_VERSION_MIN);
+       return 1;
+}
+
+int ModApiMainMenu::l_get_max_supp_proto(lua_State *L)
+{
+       lua_pushinteger(L, CLIENT_PROTOCOL_VERSION_MAX);
+       return 1;
+}
+
 /******************************************************************************/
 int ModApiMainMenu::l_do_async_callback(lua_State *L)
 {
@@ -1142,6 +1168,8 @@ void ModApiMainMenu::Initialize(lua_State *L, int top)
        API_FCT(gettext);
        API_FCT(get_video_drivers);
        API_FCT(get_screen_info);
+       API_FCT(get_min_supp_proto);
+       API_FCT(get_max_supp_proto);
        API_FCT(do_async_callback);
 }
 
index ff61dd97a4bf19cab00dbb9a87c5467a22a027b9..8b21a93aa08f9d2826d90c9cd15a93f9e8ea2ef7 100644 (file)
@@ -137,6 +137,12 @@ private:
 
        static int l_get_video_drivers(lua_State *L);
 
+       //version compatibility
+       static int l_get_min_supp_proto(lua_State *L);
+
+       static int l_get_max_supp_proto(lua_State *L);
+
+
        // async
        static int l_do_async_callback(lua_State *L);
 
index 472a6b85c285cbc4acb2df56f2aebf249171071b..a3353340eeb232e1eb9d8f241e9386d773f7b94b 100644 (file)
@@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "filesys.h"
 #include "porting.h"
 #include "log.h"
+#include "network/networkprotocol.h"
 #include "json/json.h"
 #include "convert_json.h"
 #include "httpfetch.h"
@@ -67,8 +68,11 @@ std::vector<ServerListSpec> getLocal()
 
 std::vector<ServerListSpec> getOnline()
 {
-       Json::Value root = fetchJsonValue(
-                       (g_settings->get("serverlist_url") + "/list").c_str(), NULL);
+       std::ostringstream geturl;
+       geturl << g_settings->get("serverlist_url") <<
+               "/list?proto_version_min=" << CLIENT_PROTOCOL_VERSION_MIN <<
+               "&proto_version_max=" << CLIENT_PROTOCOL_VERSION_MAX;
+       Json::Value root = fetchJsonValue(geturl.str(), NULL);
 
        std::vector<ServerListSpec> server_list;
 
@@ -205,9 +209,12 @@ void sendAnnounce(const std::string &action,
                server["address"] = g_settings->get("server_address");
        }
        if (action != "delete") {
+               bool strict_checking = g_settings->getBool("strict_protocol_version_checking");
                server["name"]         = g_settings->get("server_name");
                server["description"]  = g_settings->get("server_description");
                server["version"]      = minetest_version_simple;
+               server["proto_min"]    = strict_checking ? LATEST_PROTOCOL_VERSION : SERVER_PROTOCOL_VERSION_MIN;
+               server["proto_max"]    = strict_checking ? LATEST_PROTOCOL_VERSION : SERVER_PROTOCOL_VERSION_MAX;
                server["url"]          = g_settings->get("server_url");
                server["creative"]     = g_settings->getBool("creative_mode");
                server["damage"]       = g_settings->getBool("enable_damage");