From ebf7ea50193afe5a3d0968b87b4743eb1ee84025 Mon Sep 17 00:00:00 2001 From: sapier Date: Wed, 25 Jun 2014 19:04:47 +0200 Subject: [PATCH] Add formspec api versioning --- src/clientserver.h | 4 ++ src/game.cpp | 5 +- src/guiFormSpecMenu.cpp | 131 +++++++++++++++++++++++++++++++--------- src/guiFormSpecMenu.h | 5 +- src/server.cpp | 5 +- src/util/string.h | 14 +++++ 6 files changed, 130 insertions(+), 34 deletions(-) diff --git a/src/clientserver.h b/src/clientserver.h index a995d8b99..f12384b18 100644 --- a/src/clientserver.h +++ b/src/clientserver.h @@ -19,6 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #ifndef CLIENTSERVER_HEADER #define CLIENTSERVER_HEADER +#include "util/string.h" /* changes by PROTOCOL_VERSION: @@ -122,6 +123,9 @@ with this program; if not, write to the Free Software Foundation, Inc., #define PASSWORD_SIZE 28 // Maximum password length. Allows for // base64-encoded SHA-1 (27+\0). +#define FORMSPEC_API_VERSION 1 +#define FORMSPEC_VERSION_STRING "formspec_version[" TOSTRING(FORMSPEC_API_VERSION) "]" + #define TEXTURENAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.-" enum ToClientCommand diff --git a/src/game.cpp b/src/game.cpp index 3acc93828..e74e4697b 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -948,6 +948,7 @@ static void show_chat_menu(GUIFormSpecMenu** cur_formspec, Client* client, std::string text) { std::string formspec = + FORMSPEC_VERSION_STRING "size[11,5.5,true]" "field[3,2.35;6,0.5;f_text;;" + text + "]" "button_exit[4,3;3,0.5;btn_send;" + wide_to_narrow(wstrgettext("Proceed")) + "]" @@ -967,7 +968,7 @@ static void show_deathscreen(GUIFormSpecMenu** cur_formspec, IWritableTextureSource* tsrc, IrrlichtDevice * device, Client* client) { std::string formspec = - std::string("") + + std::string(FORMSPEC_VERSION_STRING) + "size[11,5.5,true]" "bgcolor[#320000b4;true]" "label[4.85,1.35;You died.]" @@ -1005,7 +1006,7 @@ static void show_pause_menu(GUIFormSpecMenu** cur_formspec, float ypos = singleplayermode ? 1.0 : 0.5; std::ostringstream os; - os << "size[11,5.5,true]" + os << FORMSPEC_VERSION_STRING << "size[11,5.5,true]" << "button_exit[4," << (ypos++) << ";3,0.5;btn_continue;" << wide_to_narrow(wstrgettext("Continue")) << "]"; diff --git a/src/guiFormSpecMenu.cpp b/src/guiFormSpecMenu.cpp index 2f4c2f5f3..fd12c4d4d 100644 --- a/src/guiFormSpecMenu.cpp +++ b/src/guiFormSpecMenu.cpp @@ -86,7 +86,8 @@ GUIFormSpecMenu::GUIFormSpecMenu(irr::IrrlichtDevice* dev, m_form_src(fsrc), m_text_dst(tdst), m_ext_ptr(ext_ptr), - m_font(dev->getGUIEnvironment()->getSkin()->getFont()) + m_font(dev->getGUIEnvironment()->getSkin()->getFont()), + m_formspec_version(0) { current_keys_pending.key_down = false; current_keys_pending.key_up = false; @@ -265,7 +266,9 @@ void GUIFormSpecMenu::parseSize(parserData* data,std::string element) { std::vector parts = split(element,','); - if ((parts.size() == 2) || parts.size() == 3) { + if (((parts.size() == 2) || parts.size() == 3) || + ((parts.size() > 3) && (m_formspec_version > FORMSPEC_API_VERSION))) + { v2f invsize; if (parts[1].find(';') != std::string::npos) @@ -359,7 +362,9 @@ void GUIFormSpecMenu::parseList(parserData* data,std::string element) std::vector parts = split(element,';'); - if ((parts.size() == 4) || (parts.size() == 5)) { + if (((parts.size() == 4) || (parts.size() == 5)) || + ((parts.size() > 5) && (m_formspec_version > FORMSPEC_API_VERSION))) + { std::string location = parts[0]; std::string listname = parts[1]; std::vector v_pos = split(parts[2],','); @@ -407,7 +412,9 @@ void GUIFormSpecMenu::parseCheckbox(parserData* data,std::string element) { std::vector parts = split(element,';'); - if ((parts.size() >= 3) || (parts.size() <= 4)) { + if (((parts.size() >= 3) || (parts.size() <= 4)) || + ((parts.size() > 4) && (m_formspec_version > FORMSPEC_API_VERSION))) + { std::vector v_pos = split(parts[0],','); std::string name = parts[1]; std::string label = parts[2]; @@ -460,7 +467,9 @@ void GUIFormSpecMenu::parseImage(parserData* data,std::string element) { std::vector parts = split(element,';'); - if (parts.size() == 3) { + if ((parts.size() == 3) || + ((parts.size() > 3) && (m_formspec_version > FORMSPEC_API_VERSION))) + { std::vector v_pos = split(parts[0],','); std::vector v_geom = split(parts[1],','); std::string name = unescape_string(parts[2]); @@ -504,7 +513,9 @@ void GUIFormSpecMenu::parseItemImage(parserData* data,std::string element) { std::vector parts = split(element,';'); - if (parts.size() == 3) { + if ((parts.size() == 3) || + ((parts.size() > 3) && (m_formspec_version > FORMSPEC_API_VERSION))) + { std::vector v_pos = split(parts[0],','); std::vector v_geom = split(parts[1],','); std::string name = parts[2]; @@ -533,7 +544,9 @@ void GUIFormSpecMenu::parseButton(parserData* data,std::string element, { std::vector parts = split(element,';'); - if (parts.size() == 4) { + if ((parts.size() == 4) || + ((parts.size() > 4) && (m_formspec_version > FORMSPEC_API_VERSION))) + { std::vector v_pos = split(parts[0],','); std::vector v_geom = split(parts[1],','); std::string name = parts[2]; @@ -587,7 +600,9 @@ void GUIFormSpecMenu::parseBackground(parserData* data,std::string element) { std::vector parts = split(element,';'); - if ((parts.size() == 3) || (parts.size() == 4)) { + if (((parts.size() == 3) || (parts.size() == 4)) || + ((parts.size() > 4) && (m_formspec_version > FORMSPEC_API_VERSION))) + { std::vector v_pos = split(parts[0],','); std::vector v_geom = split(parts[1],','); std::string name = unescape_string(parts[2]); @@ -655,7 +670,9 @@ void GUIFormSpecMenu::parseTable(parserData* data,std::string element) { std::vector parts = split(element,';'); - if ((parts.size() == 4) || (parts.size() == 5)) { + if (((parts.size() == 4) || (parts.size() == 5)) || + ((parts.size() > 5) && (m_formspec_version > FORMSPEC_API_VERSION))) + { std::vector v_pos = split(parts[0],','); std::vector v_geom = split(parts[1],','); std::string name = parts[2]; @@ -724,7 +741,9 @@ void GUIFormSpecMenu::parseTextList(parserData* data,std::string element) { std::vector parts = split(element,';'); - if ((parts.size() == 4) || (parts.size() == 5) || (parts.size() == 6)) { + if (((parts.size() == 4) || (parts.size() == 5) || (parts.size() == 6)) || + ((parts.size() > 6) && (m_formspec_version > FORMSPEC_API_VERSION))) + { std::vector v_pos = split(parts[0],','); std::vector v_geom = split(parts[1],','); std::string name = parts[2]; @@ -797,7 +816,9 @@ void GUIFormSpecMenu::parseDropDown(parserData* data,std::string element) { std::vector parts = split(element,';'); - if (parts.size() == 5) { + if ((parts.size() == 5) || + ((parts.size() > 5) && (m_formspec_version > FORMSPEC_API_VERSION))) + { std::vector v_pos = split(parts[0],','); std::string name = parts[2]; std::vector items = split(parts[3],','); @@ -852,7 +873,9 @@ void GUIFormSpecMenu::parsePwdField(parserData* data,std::string element) { std::vector parts = split(element,';'); - if (parts.size() == 4) { + if ((parts.size() == 4) || + ((parts.size() > 4) && (m_formspec_version > FORMSPEC_API_VERSION))) + { std::vector v_pos = split(parts[0],','); std::vector v_geom = split(parts[1],','); std::string name = parts[2]; @@ -1103,7 +1126,9 @@ void GUIFormSpecMenu::parseField(parserData* data,std::string element, return; } - if (parts.size() == 5) { + if ((parts.size() == 5) || + ((parts.size() > 5) && (m_formspec_version > FORMSPEC_API_VERSION))) + { parseTextArea(data,parts,type); return; } @@ -1114,7 +1139,9 @@ void GUIFormSpecMenu::parseLabel(parserData* data,std::string element) { std::vector parts = split(element,';'); - if (parts.size() == 2) { + if ((parts.size() == 2) || + ((parts.size() > 2) && (m_formspec_version > FORMSPEC_API_VERSION))) + { std::vector v_pos = split(parts[0],','); std::string text = parts[1]; @@ -1153,7 +1180,9 @@ void GUIFormSpecMenu::parseVertLabel(parserData* data,std::string element) { std::vector parts = split(element,';'); - if (parts.size() == 2) { + if ((parts.size() == 2) || + ((parts.size() > 2) && (m_formspec_version > FORMSPEC_API_VERSION))) + { std::vector v_pos = split(parts[0],','); std::wstring text = narrow_to_wide(unescape_string(parts[1])); @@ -1201,7 +1230,9 @@ void GUIFormSpecMenu::parseImageButton(parserData* data,std::string element, { std::vector parts = split(element,';'); - if (((parts.size() >= 5) && (parts.size() <= 8)) && (parts.size() != 6)) { + if ((((parts.size() >= 5) && (parts.size() <= 8)) && (parts.size() != 6)) || + ((parts.size() > 8) && (m_formspec_version > FORMSPEC_API_VERSION))) + { std::vector v_pos = split(parts[0],','); std::vector v_geom = split(parts[1],','); std::string image_name = parts[2]; @@ -1286,7 +1317,9 @@ void GUIFormSpecMenu::parseTabHeader(parserData* data,std::string element) { std::vector parts = split(element,';'); - if ((parts.size() == 4) || (parts.size() == 6)) { + if (((parts.size() == 4) || (parts.size() == 6)) || + ((parts.size() > 6) && (m_formspec_version > FORMSPEC_API_VERSION))) + { std::vector v_pos = split(parts[0],','); std::string name = parts[1]; std::vector buttons = split(parts[2],','); @@ -1363,7 +1396,9 @@ void GUIFormSpecMenu::parseItemImageButton(parserData* data,std::string element) std::vector parts = split(element,';'); - if (parts.size() == 5) { + if ((parts.size() == 5) || + ((parts.size() > 5) && (m_formspec_version > FORMSPEC_API_VERSION))) + { std::vector v_pos = split(parts[0],','); std::vector v_geom = split(parts[1],','); std::string item_name = parts[2]; @@ -1426,7 +1461,9 @@ void GUIFormSpecMenu::parseBox(parserData* data,std::string element) { std::vector parts = split(element,';'); - if (parts.size() == 3) { + if ((parts.size() == 3) || + ((parts.size() > 3) && (m_formspec_version > FORMSPEC_API_VERSION))) + { std::vector v_pos = split(parts[0],','); std::vector v_geom = split(parts[1],','); @@ -1460,7 +1497,9 @@ void GUIFormSpecMenu::parseBackgroundColor(parserData* data,std::string element) { std::vector parts = split(element,';'); - if ((parts.size() == 1) || (parts.size() == 2)) { + if (((parts.size() == 1) || (parts.size() == 2)) || + ((parts.size() > 2) && (m_formspec_version > FORMSPEC_API_VERSION))) + { parseColor(parts[0],m_bgcolor,false); if (parts.size() == 2) { @@ -1476,7 +1515,9 @@ void GUIFormSpecMenu::parseListColors(parserData* data,std::string element) { std::vector parts = split(element,';'); - if ((parts.size() == 2) || (parts.size() == 3) || (parts.size() == 5)) { + if (((parts.size() == 2) || (parts.size() == 3) || (parts.size() == 5)) || + ((parts.size() > 5) && (m_formspec_version > FORMSPEC_API_VERSION))) + { parseColor(parts[0], m_slotbg_n, false); parseColor(parts[1], m_slotbg_h, false); @@ -1503,12 +1544,12 @@ void GUIFormSpecMenu::parseTooltip(parserData* data, std::string element) std::vector parts = split(element,';'); if (parts.size() == 2) { std::string name = parts[0]; - m_tooltips[narrow_to_wide(name.c_str())] = TooltipSpec (parts[1], m_default_tooltip_bgcolor, m_default_tooltip_color); + m_tooltips[narrow_to_wide(name.c_str())] = TooltipSpec (parts[1], m_default_tooltip_bgcolor, m_default_tooltip_color); return; } else if (parts.size() == 4) { std::string name = parts[0]; video::SColor tmp_color1, tmp_color2; - if ( parseColor(parts[2], tmp_color1, false) && parseColor(parts[3], tmp_color2, false) ) { + if ( parseColor(parts[2], tmp_color1, false) && parseColor(parts[3], tmp_color2, false) ) { m_tooltips[narrow_to_wide(name.c_str())] = TooltipSpec (parts[1], tmp_color1, tmp_color2); return; } @@ -1516,7 +1557,31 @@ void GUIFormSpecMenu::parseTooltip(parserData* data, std::string element) errorstream<< "Invalid tooltip element(" << parts.size() << "): '" << element << "'" << std::endl; } -void GUIFormSpecMenu::parseElement(parserData* data,std::string element) +bool GUIFormSpecMenu::parseVersionDirect(std::string data) +{ + //some prechecks + if (data == "") + return false; + + std::vector parts = split(data,'['); + + if (parts.size() < 2) { + return false; + } + + if (parts[0] != "formspec_version") { + return false; + } + + if (is_number(parts[1])) { + m_formspec_version = mystoi(parts[1]); + return true; + } + + return false; +} + +void GUIFormSpecMenu::parseElement(parserData* data, std::string element) { //some prechecks if (element == "") @@ -1763,10 +1828,18 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize) m_tooltip_element->grab(); } - std::vector elements = split(m_formspec_string,']'); - for (unsigned int i=0; i< elements.size(); i++) { - parseElement(&mydata,elements[i]); + unsigned int i = 0; + + /* try to read version from first element only */ + if (elements.size() >= 1) { + if ( parseVersionDirect(elements[0]) ) { + i++; + } + } + + for (; i< elements.size(); i++) { + parseElement(&mydata, elements[i]); } // If there's fields, add a Proceed button @@ -2167,12 +2240,12 @@ void GUIFormSpecMenu::drawMenu() m_tooltip_element->setVisible(true); this->bringToFront(m_tooltip_element); break; - } + } } } } - skip_tooltip: + skip_tooltip: /* Draw dragged item stack */ diff --git a/src/guiFormSpecMenu.h b/src/guiFormSpecMenu.h index 3368bb82d..5d74978a9 100644 --- a/src/guiFormSpecMenu.h +++ b/src/guiFormSpecMenu.h @@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "inventorymanager.h" #include "modalMenu.h" #include "guiTable.h" +#include "clientserver.h" class IGameDef; class InventoryManager; @@ -339,6 +340,7 @@ private: TextDest *m_text_dst; GUIFormSpecMenu **m_ext_ptr; gui::IGUIFont *m_font; + unsigned int m_formspec_version; typedef struct { v2s32 size; @@ -390,6 +392,7 @@ private: void parseBackgroundColor(parserData* data,std::string element); void parseListColors(parserData* data,std::string element); void parseTooltip(parserData* data,std::string element); + bool parseVersionDirect(std::string data); /** * check if event is part of a double click @@ -420,7 +423,7 @@ public: {} void setForm(std::string formspec) { - m_formspec = formspec; + m_formspec = FORMSPEC_VERSION_STRING + formspec; } std::string getForm() diff --git a/src/server.cpp b/src/server.cpp index 58ecb23b4..122ea993d 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -3132,10 +3132,11 @@ void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec, std::ostringstream os(std::ios_base::binary); u8 buf[12]; + // Write command writeU16(buf, TOCLIENT_SHOW_FORMSPEC); os.write((char*)buf, 2); - os<inventory_formspec); + os<inventory_formspec); // Make data buffer std::string s = os.str(); diff --git a/src/util/string.h b/src/util/string.h index bed66417e..4aeea17db 100644 --- a/src/util/string.h +++ b/src/util/string.h @@ -27,6 +27,9 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include +#define STRINGIFY(x) #x +#define TOSTRING(x) STRINGIFY(x) + struct FlagDesc { const char *name; u32 flag; @@ -316,6 +319,17 @@ inline std::string unescape_string(std::string &s) return res; } +inline bool is_number(const std::string& tocheck) +{ + std::string::const_iterator iter = tocheck.begin(); + + while (iter != tocheck.end() && std::isdigit(*iter)) { + ++iter; + } + + return ((!tocheck.empty()) && (iter == tocheck.end())); +} + std::string translatePassword(std::string playername, std::wstring password); std::string urlencode(std::string str); std::string urldecode(std::string str);