Server: announce MIN/MAX protocol version supported to serverlist. Client: check serverlist

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
This commit is contained in:
est31 2015-02-17 01:37:14 +01:00 committed by Loic Blot
parent 8941ea0cc9
commit 5a0ed780f5
8 changed files with 129 additions and 12 deletions

@ -564,7 +564,7 @@ if INIT == "mainmenu" then
return nil return nil
end end
function fgettext(text, ...) function fgettext_ne(text, ...)
text = core.gettext(text) text = core.gettext(text)
local arg = {n=select('#', ...), ...} local arg = {n=select('#', ...), ...}
if arg.n >= 1 then if arg.n >= 1 then
@ -586,7 +586,11 @@ if INIT == "mainmenu" then
end end
text = result text = result
end end
return core.formspec_escape(text) return text
end
function fgettext(text, ...)
return core.formspec_escape(fgettext_ne(text, ...))
end end
end end

@ -16,9 +16,15 @@
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. --51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
-- Global menu data -- Global menu data
--------------------------------------------------------------------------------- --------------------------------------------------------------------------------
menudata = {} 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 -- Menu helper functions
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
@ -42,6 +48,25 @@ function image_column(tooltip, flagname)
"1=" .. core.formspec_escape(defaulttexturedir .. "server_flags_" .. flagname .. ".png") "1=" .. core.formspec_escape(defaulttexturedir .. "server_flags_" .. flagname .. ".png")
end 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) function render_favorite(spec,render_details)
local text = "" local text = ""
@ -68,6 +93,7 @@ function render_favorite(spec,render_details)
end end
local details = "" 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 if spec.clients ~= nil and spec.clients_max ~= nil then
local clients_color = '' local clients_color = ''
@ -87,11 +113,17 @@ function render_favorite(spec,render_details)
clients_color = '#ffba97' -- 90-100%: orange clients_color = '#ffba97' -- 90-100%: orange
end end
if grey_out then
clients_color = '#aaaaaa'
end
details = details .. details = details ..
clients_color .. ',' .. clients_color .. ',' ..
render_client_count(spec.clients) .. ',' .. render_client_count(spec.clients) .. ',' ..
'/,' .. '/,' ..
render_client_count(spec.clients_max) .. ',' render_client_count(spec.clients_max) .. ','
elseif grey_out then
details = details .. '#aaaaaa,?,/,?,'
else else
details = details .. ',?,/,?,' details = details .. ',?,/,?,'
end end
@ -114,7 +146,7 @@ function render_favorite(spec,render_details)
details = details .. "0," details = details .. "0,"
end end
return details .. text return details .. (grey_out and '#aaaaaa,' or ',') .. text
end end
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
@ -195,7 +227,7 @@ function asyncOnlineFavourites()
nil, nil,
function(result) function(result)
if core.setting_getbool("public_serverlist") then if core.setting_getbool("public_serverlist") then
menudata.favorites = result menudata.favorites = order_favorite_list(result)
core.event_handler("Refresh") core.event_handler("Refresh")
end end
end end
@ -225,3 +257,21 @@ function text2textlist(xpos,ypos,width,height,tl_name,textlen,text,transparency)
return retval return retval
end 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

@ -62,6 +62,7 @@ local function get_formspec(tabview, name, tabdata)
image_column(fgettext("Creative mode"), "creative") .. ",padding=1;" .. image_column(fgettext("Creative mode"), "creative") .. ",padding=1;" ..
image_column(fgettext("Damage enabled"), "damage") .. ",padding=0.25;" .. image_column(fgettext("Damage enabled"), "damage") .. ",padding=0.25;" ..
image_column(fgettext("PvP enabled"), "pvp") .. ",padding=0.25;" .. image_column(fgettext("PvP enabled"), "pvp") .. ",padding=0.25;" ..
"color,span=1;" ..
"text,padding=1]" -- name "text,padding=1]" -- name
else else
retval = retval .. "tablecolumns[text]" retval = retval .. "tablecolumns[text]"
@ -88,7 +89,6 @@ end
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
local function main_button_handler(tabview, fields, name, tabdata) local function main_button_handler(tabview, fields, name, tabdata)
if fields["te_name"] ~= nil then if fields["te_name"] ~= nil then
gamedata.playername = fields["te_name"] gamedata.playername = fields["te_name"]
core.setting_set("name", 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"]) local event = core.explode_table_event(fields["favourites"])
if event.type == "DCL" then if event.type == "DCL" then
if event.row <= #menudata.favorites 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.address = menudata.favorites[event.row].address
gamedata.port = menudata.favorites[event.row].port gamedata.port = menudata.favorites[event.row].port
gamedata.playername = fields["te_name"] 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") local current_favourite = core.get_table_index("favourites")
if current_favourite == nil then return end if current_favourite == nil then return end
core.delete_favorite(current_favourite) core.delete_favorite(current_favourite)
menudata.favorites = core.get_favorites() menudata.favorites = order_favorite_list(core.get_favorites())
tabdata.fav_selected = nil tabdata.fav_selected = nil
core.setting_set("address","") core.setting_set("address","")
@ -215,6 +219,11 @@ local function main_button_handler(tabview, fields, name, tabdata)
gamedata.servername = menudata.favorites[fav_idx].name gamedata.servername = menudata.favorites[fav_idx].name
gamedata.serverdescription = menudata.favorites[fav_idx].description 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 else
gamedata.servername = "" gamedata.servername = ""
gamedata.serverdescription = "" gamedata.serverdescription = ""

@ -45,6 +45,7 @@ local function get_formspec(tabview, name, tabdata)
image_column(fgettext("Creative mode"), "creative") .. ",padding=1;" .. image_column(fgettext("Creative mode"), "creative") .. ",padding=1;" ..
image_column(fgettext("Damage enabled"), "damage") .. ",padding=0.25;" .. image_column(fgettext("Damage enabled"), "damage") .. ",padding=0.25;" ..
image_column(fgettext("PvP enabled"), "pvp") .. ",padding=0.25;" .. image_column(fgettext("PvP enabled"), "pvp") .. ",padding=0.25;" ..
"color,span=1;" ..
"text,padding=1]" -- name "text,padding=1]" -- name
else else
retval = retval .. "tablecolumns[text]" retval = retval .. "tablecolumns[text]"
@ -87,7 +88,6 @@ local function get_formspec(tabview, name, tabdata)
end end
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
local function main_button_handler(tabview, fields, name, tabdata) local function main_button_handler(tabview, fields, name, tabdata)
if fields["btn_start_singleplayer"] then 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.servername = menudata.favorites[fav_idx].name
gamedata.serverdescription = menudata.favorites[fav_idx].description 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 else
gamedata.servername = "" gamedata.servername = ""
gamedata.serverdescription = "" gamedata.serverdescription = ""

@ -197,9 +197,11 @@ core.delete_world(index)
Helpers: Helpers:
core.gettext(string) -> string core.gettext(string) -> string
^ look up the translation of a string in the gettext message catalog ^ 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 ^ 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) core.parse_json(string[, nullvalue]) -> something (possible in async calls)
^ see core.parse_json (lua_api.txt) ^ see core.parse_json (lua_api.txt)
dump(obj, dumped={}) dump(obj, dumped={})
@ -211,6 +213,12 @@ string:trim()
core.is_yes(arg) (possible in async calls) core.is_yes(arg) (possible in async calls)
^ returns whether arg can be interpreted as yes ^ 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: Async:
core.handle_async(async_job,parameters,finished) core.handle_async(async_job,parameters,finished)
^ execute a function asynchronously ^ execute a function asynchronously

@ -472,6 +472,7 @@ int ModApiMainMenu::l_get_favorites(lua_State *L)
for (unsigned int i = 0; i < servers.size(); i++) for (unsigned int i = 0; i < servers.size(); i++)
{ {
lua_pushnumber(L,index); lua_pushnumber(L,index);
lua_newtable(L); lua_newtable(L);
@ -509,6 +510,18 @@ int ModApiMainMenu::l_get_favorites(lua_State *L)
lua_settable(L, top_lvl2); 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()) { if (servers[i]["password"].asString().size()) {
lua_pushstring(L,"password"); lua_pushstring(L,"password");
lua_pushboolean(L,servers[i]["password"].asBool()); lua_pushboolean(L,servers[i]["password"].asBool());
@ -1082,6 +1095,19 @@ int ModApiMainMenu::l_get_screen_info(lua_State *L)
return 1; 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) 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(gettext);
API_FCT(get_video_drivers); API_FCT(get_video_drivers);
API_FCT(get_screen_info); API_FCT(get_screen_info);
API_FCT(get_min_supp_proto);
API_FCT(get_max_supp_proto);
API_FCT(do_async_callback); API_FCT(do_async_callback);
} }

@ -137,6 +137,12 @@ private:
static int l_get_video_drivers(lua_State *L); 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 // async
static int l_do_async_callback(lua_State *L); static int l_do_async_callback(lua_State *L);

@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "filesys.h" #include "filesys.h"
#include "porting.h" #include "porting.h"
#include "log.h" #include "log.h"
#include "network/networkprotocol.h"
#include "json/json.h" #include "json/json.h"
#include "convert_json.h" #include "convert_json.h"
#include "httpfetch.h" #include "httpfetch.h"
@ -67,8 +68,11 @@ std::vector<ServerListSpec> getLocal()
std::vector<ServerListSpec> getOnline() std::vector<ServerListSpec> getOnline()
{ {
Json::Value root = fetchJsonValue( std::ostringstream geturl;
(g_settings->get("serverlist_url") + "/list").c_str(), NULL); 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; std::vector<ServerListSpec> server_list;
@ -205,9 +209,12 @@ void sendAnnounce(const std::string &action,
server["address"] = g_settings->get("server_address"); server["address"] = g_settings->get("server_address");
} }
if (action != "delete") { if (action != "delete") {
bool strict_checking = g_settings->getBool("strict_protocol_version_checking");
server["name"] = g_settings->get("server_name"); server["name"] = g_settings->get("server_name");
server["description"] = g_settings->get("server_description"); server["description"] = g_settings->get("server_description");
server["version"] = minetest_version_simple; 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["url"] = g_settings->get("server_url");
server["creative"] = g_settings->getBool("creative_mode"); server["creative"] = g_settings->getBool("creative_mode");
server["damage"] = g_settings->getBool("enable_damage"); server["damage"] = g_settings->getBool("enable_damage");