aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/lua_api.txt3
-rw-r--r--src/client.cpp14
-rw-r--r--src/client.h6
-rw-r--r--src/clientserver.h10
-rw-r--r--src/game.cpp48
-rw-r--r--src/scriptapi.cpp16
-rw-r--r--src/server.cpp32
-rw-r--r--src/server.h2
8 files changed, 129 insertions, 2 deletions
diff --git a/doc/lua_api.txt b/doc/lua_api.txt
index 117d4b24e..ebad1dad2 100644
--- a/doc/lua_api.txt
+++ b/doc/lua_api.txt
@@ -888,6 +888,9 @@ minetest.get_inventory(location) -> InvRef
minetest.create_detached_inventory(name, callbacks) -> InvRef
^ callbacks: See "Detached inventory callbacks"
^ Creates a detached inventory. If it already exists, it is cleared.
+minetest.show_formspec(playername, formspec)
+^ playername: name of player to show formspec
+^ formspec: formspec to display
Item handling:
minetest.inventorycube(img1, img2, img3)
diff --git a/src/client.cpp b/src/client.cpp
index cb7afe29f..216d86cd4 100644
--- a/src/client.cpp
+++ b/src/client.cpp
@@ -1900,6 +1900,20 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
}
inv->deSerialize(is);
}
+ else if(command == TOCLIENT_SHOW_FORMSPEC)
+ {
+ std::string datastring((char*)&data[2], datasize-2);
+ std::istringstream is(datastring, std::ios_base::binary);
+
+ std::string formspec = deSerializeLongString(is);
+
+ ClientEvent event;
+ event.type = CE_SHOW_FORMSPEC;
+ // pointer is required as event is a struct only!
+ // adding a std:string to a struct isn't possible
+ event.show_formspec.formspec = new std::string(formspec);
+ m_client_event_queue.push_back(event);
+ }
else
{
infostream<<"Client: Ignoring unknown command "
diff --git a/src/client.h b/src/client.h
index 155b4386b..e46da6b0e 100644
--- a/src/client.h
+++ b/src/client.h
@@ -154,7 +154,8 @@ enum ClientEventType
CE_PLAYER_DAMAGE,
CE_PLAYER_FORCE_MOVE,
CE_DEATHSCREEN,
- CE_TEXTURES_UPDATED
+ CE_TEXTURES_UPDATED,
+ CE_SHOW_FORMSPEC
};
struct ClientEvent
@@ -177,6 +178,9 @@ struct ClientEvent
f32 camera_point_target_z;
} deathscreen;
struct{
+ std::string* formspec;
+ } show_formspec;
+ struct{
} textures_updated;
};
};
diff --git a/src/clientserver.h b/src/clientserver.h
index db551a90c..bb7e1181e 100644
--- a/src/clientserver.h
+++ b/src/clientserver.h
@@ -77,9 +77,11 @@ SharedBuffer<u8> makePacket_TOCLIENT_TIME_OF_DAY(u16 time, float time_speed);
GENERIC_CMD_SET_ATTACHMENT
PROTOCOL_VERSION 15:
Serialization format changes
+ PROTOCOL_VERSION 16:
+ TOCLIENT_SHOW_FORMSPEC
*/
-#define LATEST_PROTOCOL_VERSION 15
+#define LATEST_PROTOCOL_VERSION 16
// Server's supported network protocol range
#define SERVER_PROTOCOL_VERSION_MIN 13
@@ -354,6 +356,12 @@ enum ToClientCommand
u8[len] name
[2] serialized inventory
*/
+ TOCLIENT_SHOW_FORMSPEC = 0x44,
+ /*
+ [0] u16 command
+ u16 len
+ u8[len] formspec
+ */
};
enum ToServerCommand
diff --git a/src/game.cpp b/src/game.cpp
index 541127f5d..15bf3f09f 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -192,6 +192,32 @@ public:
Client *m_client;
};
+class FormspecFormSource: public IFormSource
+{
+public:
+ FormspecFormSource(std::string formspec,FormspecFormSource** game_formspec)
+ {
+ m_formspec = formspec;
+ m_game_formspec = game_formspec;
+ }
+
+ ~FormspecFormSource()
+ {
+ *m_game_formspec = 0;
+ }
+
+ void setForm(std::string formspec) {
+ m_formspec = formspec;
+ }
+
+ std::string getForm()
+ {
+ return m_formspec;
+ }
+
+ std::string m_formspec;
+ FormspecFormSource** m_game_formspec;
+};
/*
Hotbar draw routine
*/
@@ -901,6 +927,7 @@ void the_game(
bool simple_singleplayer_mode
)
{
+ FormspecFormSource* current_formspec = 0;
video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager();
@@ -2067,6 +2094,27 @@ void the_game(
player->setPosition(player->getPosition() + v3f(0,-BS,0));
camera.update(player, busytime, screensize);*/
}
+ else if (event.type == CE_SHOW_FORMSPEC)
+ {
+ if (current_formspec == 0)
+ {
+ /* Create menu */
+ current_formspec = new FormspecFormSource(*(event.show_formspec.formspec),&current_formspec);
+
+ GUIFormSpecMenu *menu =
+ new GUIFormSpecMenu(device, guiroot, -1,
+ &g_menumgr,
+ &client, gamedef);
+ menu->setFormSource(current_formspec);
+ menu->drop();
+ }
+ else
+ {
+ /* update menu */
+ current_formspec->setForm(*(event.show_formspec.formspec));
+ }
+ delete(event.show_formspec.formspec);
+ }
else if(event.type == CE_TEXTURES_UPDATED)
{
update_wielded_item_trigger = true;
diff --git a/src/scriptapi.cpp b/src/scriptapi.cpp
index d086b7e51..83987fc9b 100644
--- a/src/scriptapi.cpp
+++ b/src/scriptapi.cpp
@@ -4899,6 +4899,21 @@ static int l_create_detached_inventory_raw(lua_State *L)
return 1;
}
+// create_detached_formspec_raw(name)
+static int l_show_formspec(lua_State *L)
+{
+ const char *playername = luaL_checkstring(L, 1);
+ const char *formspec = luaL_checkstring(L, 2);
+
+ if(get_server(L)->showFormspec(playername,formspec))
+ {
+ lua_pushboolean(L, true);
+ }else{
+ lua_pushboolean(L, false);
+ }
+ return 1;
+}
+
// get_dig_params(groups, tool_capabilities[, time_from_last_punch])
static int l_get_dig_params(lua_State *L)
{
@@ -5228,6 +5243,7 @@ static const struct luaL_Reg minetest_f [] = {
{"unban_player_or_ip", l_unban_player_of_ip},
{"get_inventory", l_get_inventory},
{"create_detached_inventory_raw", l_create_detached_inventory_raw},
+ {"show_formspec", l_show_formspec},
{"get_dig_params", l_get_dig_params},
{"get_hit_params", l_get_hit_params},
{"get_current_modname", l_get_current_modname},
diff --git a/src/server.cpp b/src/server.cpp
index 39407f961..f4b5ee872 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -3638,6 +3638,24 @@ void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
// Send as reliable
m_con.Send(peer_id, 0, data, true);
}
+void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec)
+{
+ DSTACK(__FUNCTION_NAME);
+
+ std::ostringstream os(std::ios_base::binary);
+ u8 buf[12];
+
+ // Write command
+ writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
+ os.write((char*)buf, 2);
+ os<<serializeLongString(formspec);
+
+ // Make data buffer
+ std::string s = os.str();
+ SharedBuffer<u8> data((u8*)s.c_str(), s.size());
+ // Send as reliable
+ m_con.Send(peer_id, 0, data, true);
+}
void Server::BroadcastChatMessage(const std::wstring &message)
{
@@ -4578,6 +4596,20 @@ void Server::notifyPlayer(const char *name, const std::wstring msg)
SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
}
+bool Server::showFormspec(const char *playername, const std::string &formspec)
+{
+ Player *player = m_env->getPlayer(playername);
+
+ if(!player)
+ {
+ infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
+ return false;
+ }
+
+ SendShowFormspecMessage(player->peer_id,formspec);
+ return true;
+}
+
void Server::notifyPlayers(const std::wstring msg)
{
BroadcastChatMessage(msg);
diff --git a/src/server.h b/src/server.h
index ce826ae52..19c29cbd7 100644
--- a/src/server.h
+++ b/src/server.h
@@ -583,6 +583,7 @@ public:
m_async_fatal_error.set(error);
}
+ bool showFormspec(const char *name, const std::string &formspec);
private:
// con::PeerHandler implementation.
@@ -620,6 +621,7 @@ private:
void SendMovePlayer(u16 peer_id);
void SendPlayerPrivileges(u16 peer_id);
void SendPlayerInventoryFormspec(u16 peer_id);
+ void SendShowFormspecMessage(u16 peer_id, const std::string formspec);
/*
Send a node removal/addition event to all clients except ignore_id.
Additionally, if far_players!=NULL, players further away than