From 0d1c9598a0d2a4f21dc57de32efca2dc52b6b146 Mon Sep 17 00:00:00 2001
From: orwell96 <mono96.mml@gmail.com>
Date: Tue, 22 Nov 2016 17:15:22 +0100
Subject: [PATCH] Make supplying empty formspec strings close the formspec
 (#4737)

This will only happen if the formname matches or if formname is "".
---
 builtin/game/misc.lua |  4 ++++
 doc/lua_api.txt       |  7 +++++++
 src/game.cpp          | 29 +++++++++++++++++++++--------
 src/server.cpp        |  8 ++++++--
 4 files changed, 38 insertions(+), 10 deletions(-)

diff --git a/builtin/game/misc.lua b/builtin/game/misc.lua
index 1333a75ba..040016333 100644
--- a/builtin/game/misc.lua
+++ b/builtin/game/misc.lua
@@ -239,3 +239,7 @@ else
 
 end
 
+function core.close_formspec(player_name, formname)
+	return minetest.show_formspec(player_name, formname, "")
+end
+
diff --git a/doc/lua_api.txt b/doc/lua_api.txt
index 80e66020d..760a829d3 100644
--- a/doc/lua_api.txt
+++ b/doc/lua_api.txt
@@ -2316,6 +2316,13 @@ and `minetest.auth_reload` call the authetification handler.
     * `formname`: name passed to `on_player_receive_fields` callbacks.
       It should follow the `"modname:<whatever>"` naming convention
     * `formspec`: formspec to display
+* `minetest.close_formspec(playername, formname)`
+    * `playername`: name of player to close formspec
+    * `formname`: has to exactly match the one given in show_formspec, or the formspec will
+       not close.
+    * calling show_formspec(playername, formname, "") is equal to this expression
+    * to close a formspec regardless of the formname, call 
+      minetest.close_formspec(playername, ""). USE THIS ONLY WHEN ABSOLUTELY NECESSARY!
 * `minetest.formspec_escape(string)`: returns a string
     * escapes the characters "[", "]", "\", "," and ";", which can not be used in formspecs
 * `minetest.explode_table_event(string)`: returns a table
diff --git a/src/game.cpp b/src/game.cpp
index 16287fe0d..671682348 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -1205,6 +1205,7 @@ static inline void create_formspec_menu(GUIFormSpecMenu **cur_formspec,
 		(*cur_formspec)->setFormSource(fs_src);
 		(*cur_formspec)->setTextDest(txt_dest);
 	}
+	
 }
 
 #ifdef __ANDROID__
@@ -1753,6 +1754,8 @@ class Game {
 	ChatBackend *chat_backend;
 
 	GUIFormSpecMenu *current_formspec;
+	//default: "". If other than "", empty show_formspec packets will only close the formspec when the formname matches
+	std::string cur_formname;
 
 	EventManager *eventmgr;
 	QuicktuneShortcutter *quicktune;
@@ -1841,6 +1844,7 @@ Game::Game() :
 	soundmaker(NULL),
 	chat_backend(NULL),
 	current_formspec(NULL),
+	cur_formname(""),
 	eventmgr(NULL),
 	quicktune(NULL),
 	gui_chat_console(NULL),
@@ -3005,6 +3009,7 @@ void Game::openInventory()
 
 	create_formspec_menu(&current_formspec, client, gamedef, texture_src,
 			device, &input->joystick, fs_src, txt_dst, client);
+	cur_formname = "";
 
 	InventoryLocation inventoryloc;
 	inventoryloc.setCurrentPlayer();
@@ -3484,14 +3489,21 @@ void Game::processClientEvents(CameraOrientation *cam, float *damage_flash)
 			player->hurt_tilt_strength = 0;
 
 		} else if (event.type == CE_SHOW_FORMSPEC) {
-			FormspecFormSource *fs_src =
-				new FormspecFormSource(*(event.show_formspec.formspec));
-			TextDestPlayerInventory *txt_dst =
-				new TextDestPlayerInventory(client, *(event.show_formspec.formname));
-
-			create_formspec_menu(&current_formspec, client, gamedef,
-				texture_src, device, &input->joystick,
-				fs_src, txt_dst, client);
+			if (*(event.show_formspec.formspec) == "") {
+				if (current_formspec && ( *(event.show_formspec.formname) == "" || *(event.show_formspec.formname) == cur_formname) ){
+					current_formspec->quitMenu();
+				}
+			} else {
+				FormspecFormSource *fs_src =
+					new FormspecFormSource(*(event.show_formspec.formspec));
+				TextDestPlayerInventory *txt_dst =
+					new TextDestPlayerInventory(client, *(event.show_formspec.formname));
+
+				create_formspec_menu(&current_formspec, client, gamedef,
+					texture_src, device, &input->joystick,
+					fs_src, txt_dst, client);
+				cur_formname = *(event.show_formspec.formname);
+			}
 
 			delete(event.show_formspec.formspec);
 			delete(event.show_formspec.formname);
@@ -3955,6 +3967,7 @@ void Game::handlePointingAtNode(GameRunData *runData,
 
 			create_formspec_menu(&current_formspec, client, gamedef,
 				texture_src, device, &input->joystick, fs_src, txt_dst, client);
+			cur_formname = "";
 
 			current_formspec->setFormSpec(meta->getString("formspec"), inventoryloc);
 		} else {
diff --git a/src/server.cpp b/src/server.cpp
index 48331e4f8..fae375425 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -1647,8 +1647,12 @@ void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
 	DSTACK(FUNCTION_NAME);
 
 	NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
-
-	pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
+	if (formspec == "" ){
+		//the client should close the formspec
+		pkt.putLongString("");
+	} else {
+		pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
+	}
 	pkt << formname;
 
 	Send(&pkt);
-- 
GitLab