From da9707950e0f69d8a906572fc55f516277e057c4 Mon Sep 17 00:00:00 2001 From: sapier Date: Wed, 2 Jan 2013 19:45:04 +0000 Subject: [PATCH] Add TOCLIENT_SHOW_FORMSPEC to display formspecs at client from lua --- doc/lua_api.txt | 3 +++ src/client.cpp | 14 ++++++++++++++ src/client.h | 6 +++++- src/clientserver.h | 10 +++++++++- src/game.cpp | 48 ++++++++++++++++++++++++++++++++++++++++++++++ src/scriptapi.cpp | 16 ++++++++++++++++ src/server.cpp | 32 +++++++++++++++++++++++++++++++ src/server.h | 2 ++ 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 @@ -176,6 +177,9 @@ struct ClientEvent f32 camera_point_target_y; 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 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),¤t_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< 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:"<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