Formspecs: Close on metadata removal (#8348)
authorSmallJoker <SmallJoker@users.noreply.github.com>
Mon, 10 Jun 2019 11:01:07 +0000 (13:01 +0200)
committerGitHub <noreply@github.com>
Mon, 10 Jun 2019 11:01:07 +0000 (13:01 +0200)
Formspecs will now close as soon the formspec string in the node metadata turns invalid.

src/client/game.cpp
src/client/gameui.cpp
src/client/gameui.h
src/gui/guiFormSpecMenu.h

index 8c0433283fa15b611b785f147964ba7d2797a57c..a29b357462ace5cbb6be1beea04dee581fd51994 100644 (file)
@@ -827,10 +827,6 @@ private:
 
        ChatBackend *chat_backend = nullptr;
 
-       GUIFormSpecMenu *current_formspec = nullptr;
-       //default: "". If other than "", empty show_formspec packets will only close the formspec when the formname matches
-       std::string cur_formname;
-
        EventManager *eventmgr = nullptr;
        QuicktuneShortcutter *quicktune = nullptr;
        bool registration_confirmation_shown = false;
@@ -1143,8 +1139,9 @@ void Game::shutdown()
                driver->setRenderTarget(irr::video::ERT_STEREO_BOTH_BUFFERS);
        }
 #endif
-       if (current_formspec)
-               current_formspec->quitMenu();
+       auto formspec = m_game_ui->getFormspecGUI();
+       if (formspec)
+               formspec->quitMenu();
 
        showOverlayMessage(N_("Shutting down..."), 0, 0, false);
 
@@ -1163,10 +1160,7 @@ void Game::shutdown()
                g_menumgr.deletingMenu(g_menumgr.m_stack.front());
        }
 
-       if (current_formspec) {
-               current_formspec->drop();
-               current_formspec = NULL;
-       }
+       m_game_ui->deleteFormspec();
 
        chat_backend->addMessage(L"", L"# Disconnected.");
        chat_backend->addMessage(L"", L"");
@@ -1853,8 +1847,9 @@ void Game::processUserInput(f32 dtime)
        input->step(dtime);
 
 #ifdef __ANDROID__
-       if (current_formspec != NULL)
-               current_formspec->getAndroidUIInput();
+       auto formspec = m_game_ui->getFormspecGUI();
+       if (formspec)
+               formspec->getAndroidUIInput();
        else
                handleAndroidChatInput();
 #endif
@@ -2050,10 +2045,11 @@ void Game::openInventory()
        if (!client->moddingEnabled()
                        || !client->getScript()->on_inventory_open(fs_src->m_client->getInventory(inventoryloc))) {
                TextDest *txt_dst = new TextDestPlayerInventory(client);
-               GUIFormSpecMenu::create(current_formspec, client, &input->joystick, fs_src,
+               auto *&formspec = m_game_ui->updateFormspec("");
+               GUIFormSpecMenu::create(formspec, client, &input->joystick, fs_src,
                        txt_dst, client->getFormspecPrepend());
-               cur_formname = "";
-               current_formspec->setFormSpec(fs_src->getForm(), inventoryloc);
+
+               formspec->setFormSpec(fs_src->getForm(), inventoryloc);
        }
 }
 
@@ -2581,9 +2577,10 @@ void Game::handleClientEvent_Deathscreen(ClientEvent *event, CameraOrientation *
 void Game::handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation *cam)
 {
        if (event->show_formspec.formspec->empty()) {
-               if (current_formspec && (event->show_formspec.formname->empty()
-                       || *(event->show_formspec.formname) == cur_formname)) {
-                       current_formspec->quitMenu();
+               auto formspec = m_game_ui->getFormspecGUI();
+               if (formspec && (event->show_formspec.formname->empty()
+                               || *(event->show_formspec.formname) == m_game_ui->getFormspecName())) {
+                       formspec->quitMenu();
                }
        } else {
                FormspecFormSource *fs_src =
@@ -2591,9 +2588,9 @@ void Game::handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation
                TextDestPlayerInventory *txt_dst =
                        new TextDestPlayerInventory(client, *(event->show_formspec.formname));
 
-               GUIFormSpecMenu::create(current_formspec, client, &input->joystick,
+               auto *&formspec = m_game_ui->updateFormspec(*(event->show_formspec.formname));
+               GUIFormSpecMenu::create(formspec, client, &input->joystick,
                        fs_src, txt_dst, client->getFormspecPrepend());
-               cur_formname = *(event->show_formspec.formname);
        }
 
        delete event->show_formspec.formspec;
@@ -2605,7 +2602,7 @@ void Game::handleClientEvent_ShowLocalFormSpec(ClientEvent *event, CameraOrienta
        FormspecFormSource *fs_src = new FormspecFormSource(*event->show_formspec.formspec);
        LocalFormspecHandler *txt_dst =
                new LocalFormspecHandler(*event->show_formspec.formname, client);
-       GUIFormSpecMenu::create(current_formspec, client, &input->joystick,
+       GUIFormSpecMenu::create(m_game_ui->getFormspecGUI(), client, &input->joystick,
                        fs_src, txt_dst, client->getFormspecPrepend());
 
        delete event->show_formspec.formspec;
@@ -3272,11 +3269,11 @@ void Game::handlePointingAtNode(const PointedThing &pointed,
                                &client->getEnv().getClientMap(), nodepos);
                        TextDest *txt_dst = new TextDestNodeMetadata(nodepos, client);
 
-                       GUIFormSpecMenu::create(current_formspec, client, &input->joystick, fs_src,
+                       auto *&formspec = m_game_ui->updateFormspec("");
+                       GUIFormSpecMenu::create(formspec, client, &input->joystick, fs_src,
                                txt_dst, client->getFormspecPrepend());
-                       cur_formname.clear();
 
-                       current_formspec->setFormSpec(meta->getString("formspec"), inventoryloc);
+                       formspec->setFormSpec(meta->getString("formspec"), inventoryloc);
                } else {
                        // Report right click to server
 
@@ -3844,14 +3841,28 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
           1. Delete formspec menu reference if menu was removed
           2. Else, make sure formspec menu is on top
        */
-       if (current_formspec) {
-               if (current_formspec->getReferenceCount() == 1) {
-                       current_formspec->drop();
-                       current_formspec = NULL;
-               } else if (isMenuActive()) {
-                       guiroot->bringToFront(current_formspec);
+       auto formspec = m_game_ui->getFormspecGUI();
+       do { // breakable. only runs for one iteration
+               if (!formspec)
+                       break;
+
+               if (formspec->getReferenceCount() == 1) {
+                       m_game_ui->deleteFormspec();
+                       break;
                }
-       }
+
+               auto &loc = formspec->getFormspecLocation();
+               if (loc.type == InventoryLocation::NODEMETA) {
+                       NodeMetadata *meta = client->getEnv().getClientMap().getNodeMetadata(loc.p);
+                       if (!meta || meta->getString("formspec").empty()) {
+                               formspec->quitMenu();
+                               break;
+                       }
+               }
+
+               if (isMenuActive())
+                       guiroot->bringToFront(formspec);
+       } while (false);
 
        /*
                Drawing begins
@@ -4048,7 +4059,7 @@ void Game::extendedResourceCleanup()
 
 void Game::showDeathFormspec()
 {
-       static std::string formspec =
+       static std::string formspec_str =
                std::string(FORMSPEC_VERSION_STRING) +
                SIZE_TAG
                "bgcolor[#320000b4;true]"
@@ -4059,12 +4070,13 @@ void Game::showDeathFormspec()
        /* Create menu */
        /* Note: FormspecFormSource and LocalFormspecHandler  *
         * are deleted by guiFormSpecMenu                     */
-       FormspecFormSource *fs_src = new FormspecFormSource(formspec);
+       FormspecFormSource *fs_src = new FormspecFormSource(formspec_str);
        LocalFormspecHandler *txt_dst = new LocalFormspecHandler("MT_DEATH_SCREEN", client);
 
-       GUIFormSpecMenu::create(current_formspec, client, &input->joystick, fs_src,
-               txt_dst, client->getFormspecPrepend());
-       current_formspec->setFocus("btn_respawn");
+       auto *&formspec = m_game_ui->getFormspecGUI();
+       GUIFormSpecMenu::create(formspec, client, &input->joystick,
+               fs_src, txt_dst, client->getFormspecPrepend());
+       formspec->setFocus("btn_respawn");
 }
 
 #define GET_KEY_NAME(KEY) gettext(getKeySetting(#KEY).name())
@@ -4188,10 +4200,11 @@ void Game::showPauseMenu()
        FormspecFormSource *fs_src = new FormspecFormSource(os.str());
        LocalFormspecHandler *txt_dst = new LocalFormspecHandler("MT_PAUSE_MENU");
 
-       GUIFormSpecMenu::create(current_formspec, client, &input->joystick,
+       auto *&formspec = m_game_ui->getFormspecGUI();
+       GUIFormSpecMenu::create(formspec, client, &input->joystick,
                        fs_src, txt_dst, client->getFormspecPrepend());
-       current_formspec->setFocus("btn_continue");
-       current_formspec->doPause = true;
+       formspec->setFocus("btn_continue");
+       formspec->doPause = true;
 }
 
 /****************************************************************************/
index 5533cd119706d16715b7272b3686aff39b673878..f3c3fefb6e436436426eceb2e76c9095b6085843 100644 (file)
@@ -302,3 +302,15 @@ void GameUI::toggleProfiler()
                showTranslatedStatusText("Profiler hidden");
        }
 }
+
+
+void GameUI::deleteFormspec()
+{
+       if (m_formspec)
+               m_formspec->quitMenu();
+
+       delete m_formspec;
+       m_formspec = nullptr;
+
+       m_formname.clear();
+}
index b6b54562a714ee76f7d6929576fa180a944cc1b9..8d20870d71e6214067011ac490aabcdafb264250 100644 (file)
@@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #pragma once
 
 #include <IGUIEnvironment.h>
+#include "gui/guiFormSpecMenu.h"
 #include "util/enriched_string.h"
 #include "util/pointedthing.h"
 #include "game.h"
@@ -88,6 +89,16 @@ public:
        void toggleHud();
        void toggleProfiler();
 
+       GUIFormSpecMenu *&updateFormspec(const std::string &formname)
+       {
+               m_formname = formname;
+               return m_formspec;
+       }
+
+       const std::string &getFormspecName() { return m_formname; }
+       GUIFormSpecMenu *&getFormspecGUI() { return m_formspec; }
+       void deleteFormspec();
+
 private:
        Flags m_flags;
 
@@ -107,4 +118,9 @@ private:
        gui::IGUIStaticText *m_guitext_profiler = nullptr; // Profiler text
        u8 m_profiler_current_page = 0;
        const u8 m_profiler_max_page = 3;
+
+       // Default: "". If other than "": Empty show_formspec packets will only
+       // close the formspec when the formname matches
+       std::string m_formname;
+       GUIFormSpecMenu *m_formspec = nullptr;
 };
index 33f88d8c03dad42d4b09ad7108d8620a4a4e7946..ccd9cb7533c3ce5c68db9d626ace96b67f7221a4 100644 (file)
@@ -304,6 +304,11 @@ public:
                regenerateGui(m_screensize_old);
        }
 
+       const InventoryLocation &getFormspecLocation()
+       {
+               return m_current_inventory_location;
+       }
+
        void setFormspecPrepend(const std::string &formspecPrepend)
        {
                m_formspec_prepend = formspecPrepend;