From c42c53fccf87a3819ca78de52f8f20c47c4fbb9f Mon Sep 17 00:00:00 2001 From: red-001 Date: Tue, 24 Jan 2017 16:26:15 +0000 Subject: [PATCH] [CSM] Add local formspecs. (#5094) --- builtin/client/init.lua | 10 +++++ builtin/client/preview.lua | 2 +- builtin/client/register.lua | 1 + builtin/common/misc_helpers.lua | 3 +- doc/client_lua_api.txt | 15 +++++++- src/client.h | 6 +++ src/game.cpp | 67 +++++---------------------------- src/guiFormSpecMenu.h | 4 +- src/script/cpp_api/s_client.cpp | 24 ++++++++++++ src/script/cpp_api/s_client.h | 7 +++- src/script/lua_api/l_client.cpp | 45 +++++++++++++++++++++- src/script/lua_api/l_client.h | 9 +++++ 12 files changed, 126 insertions(+), 67 deletions(-) diff --git a/builtin/client/init.lua b/builtin/client/init.lua index dd218aab6..b204ee5e6 100644 --- a/builtin/client/init.lua +++ b/builtin/client/init.lua @@ -6,8 +6,18 @@ local commonpath = scriptpath.."common"..DIR_DELIM dofile(clientpath .. "register.lua") dofile(commonpath .. "after.lua") dofile(commonpath .. "chatcommands.lua") +dofile(clientpath .. "chatcommands.lua") dofile(clientpath .. "preview.lua") core.register_on_death(function() core.display_chat_message("You died.") + local formspec = "size[11,5.5]bgcolor[#320000b4;true]" .. + "label[4.85,1.35;" .. fgettext("You died.") .. "]button_exit[4,3;3,0.5;btn_respawn;".. fgettext("Respawn") .."]" + core.show_formspec("bultin:death", formspec) +end) + +core.register_on_formspec_input(function(formname, fields) + if formname == "bultin:death" then + core.send_respawn() + end end) diff --git a/builtin/client/preview.lua b/builtin/client/preview.lua index 22e8bb97f..4c01d665f 100644 --- a/builtin/client/preview.lua +++ b/builtin/client/preview.lua @@ -32,7 +32,7 @@ end) -- This is an example function to ensure it's working properly, should be removed before merge core.register_chatcommand("dump", { - func = function(name, param) + func = function(param) return true, dump(_G) end, }) diff --git a/builtin/client/register.lua b/builtin/client/register.lua index 8b60c1222..1e6ac4342 100644 --- a/builtin/client/register.lua +++ b/builtin/client/register.lua @@ -62,5 +62,6 @@ core.registered_on_sending_chat_messages, core.register_on_sending_chat_messages core.registered_on_death, core.register_on_death = make_registration() core.registered_on_hp_modification, core.register_on_hp_modification = make_registration() core.registered_on_damage_taken, core.register_on_damage_taken = make_registration() +core.registered_on_formspec_input, core.register_on_formspec_input = make_registration() diff --git a/builtin/common/misc_helpers.lua b/builtin/common/misc_helpers.lua index c2dc7514d..70b23600a 100644 --- a/builtin/common/misc_helpers.lua +++ b/builtin/common/misc_helpers.lua @@ -606,7 +606,9 @@ if INIT == "mainmenu" then return nil end +end +if INIT == "client" or INIT == "mainmenu" then function fgettext_ne(text, ...) text = core.gettext(text) local arg = {n=select('#', ...), ...} @@ -636,4 +638,3 @@ if INIT == "mainmenu" then return core.formspec_escape(fgettext_ne(text, ...)) end end - diff --git a/doc/client_lua_api.txt b/doc/client_lua_api.txt index 8ce487bf8..3170f4c84 100644 --- a/doc/client_lua_api.txt +++ b/doc/client_lua_api.txt @@ -699,7 +699,10 @@ Call these functions only at load time! * Called when server modified player's HP * `minetest.register_on_damage_taken(func(hp))` * Called when player take damages - +* `minetest.register_on_formspec_input(func(formname, fields))` + * Called when a button is pressed in player's inventory form + * Newest functions are called first + * If function returns `true`, remaining functions are not called ### Sounds * `minetest.sound_play(spec, parameters)`: returns a handle * `spec` is a `SimpleSoundSpec` @@ -754,7 +757,15 @@ Call these functions only at load time! * Encodes a string in base64. * `minetest.decode_base64(string)`: returns string * Decodes a string encoded in base64. - +* `core.gettext(string) : returns string + * look up the translation of a string in the gettext message catalog +* `fgettext_ne(string, ...)` + * call core.gettext(string), replace "$1"..."$9" with the given + extra arguments and return the result +* `fgettext(string, ...)` : returns string + * same as fgettext_ne(), but calls core.formspec_escape before returning result +* `show_formspec(formname, formspec)` : returns true on success + * Shows a formspec to the player Class reference --------------- diff --git a/src/client.h b/src/client.h index ff8aea591..d170f9a07 100644 --- a/src/client.h +++ b/src/client.h @@ -142,6 +142,7 @@ enum ClientEventType CE_PLAYER_FORCE_MOVE, CE_DEATHSCREEN, CE_SHOW_FORMSPEC, + CE_SHOW_LOCAL_FORMSPEC, CE_SPAWN_PARTICLE, CE_ADD_PARTICLESPAWNER, CE_DELETE_PARTICLESPAWNER, @@ -570,6 +571,11 @@ public: ClientScripting *getScript() { return m_script; } + inline void pushToEventQueue(const ClientEvent &event) + { + m_client_event_queue.push(event); + } + private: // Virtual methods from con::PeerHandler diff --git a/src/game.cpp b/src/game.cpp index 2e2a8e0c1..c84e08b01 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -125,6 +125,7 @@ struct TextDestPlayerInventory : public TextDest { struct LocalFormspecHandler : public TextDest { LocalFormspecHandler(); + LocalFormspecHandler(std::string formname) : m_client(0) { @@ -178,39 +179,7 @@ struct LocalFormspecHandler : public TextDest { return; } } - - if (m_formname == "MT_DEATH_SCREEN") { - assert(m_client != 0); - - if ((fields.find("btn_respawn") != fields.end())) { - m_client->sendRespawn(); - return; - } - - if (fields.find("quit") != fields.end()) { - m_client->sendRespawn(); - return; - } - } - - // don't show error message for unhandled cursor keys - if ((fields.find("key_up") != fields.end()) || - (fields.find("key_down") != fields.end()) || - (fields.find("key_left") != fields.end()) || - (fields.find("key_right") != fields.end())) { - return; - } - - errorstream << "LocalFormspecHandler::gotText unhandled >" - << m_formname << "< event" << std::endl; - - int i = 0; - StringMap::const_iterator it; - for (it = fields.begin(); it != fields.end(); ++it) { - errorstream << "\t" << i << ": " << it->first - << "=" << it->second << std::endl; - i++; - } + m_client->getScript()->on_formspec_input(m_formname, fields); } Client *m_client; @@ -956,28 +925,6 @@ static inline void create_formspec_menu(GUIFormSpecMenu **cur_formspec, #define SIZE_TAG "size[11,5.5,true]" // Fixed size on desktop #endif -static void show_deathscreen(GUIFormSpecMenu **cur_formspec, - Client *client, - IWritableTextureSource *tsrc, IrrlichtDevice *device, - JoystickController *joystick) -{ - std::string formspec = - std::string(FORMSPEC_VERSION_STRING) + - SIZE_TAG - "bgcolor[#320000b4;true]" - "label[4.85,1.35;" + gettext("You died.") + "]" - "button_exit[4,3;3,0.5;btn_respawn;" + gettext("Respawn") + "]" - ; - - /* Create menu */ - /* Note: FormspecFormSource and LocalFormspecHandler - * are deleted by guiFormSpecMenu */ - FormspecFormSource *fs_src = new FormspecFormSource(formspec); - LocalFormspecHandler *txt_dst = new LocalFormspecHandler("MT_DEATH_SCREEN", client); - - create_formspec_menu(cur_formspec, client, device, joystick, fs_src, txt_dst); -} - /******************************************************************************/ static void show_pause_menu(GUIFormSpecMenu **cur_formspec, Client *client, @@ -3255,9 +3202,6 @@ void Game::processClientEvents(CameraOrientation *cam, float *damage_flash) cam->camera_yaw = event.player_force_move.yaw; cam->camera_pitch = event.player_force_move.pitch; } else if (event.type == CE_DEATHSCREEN) { - show_deathscreen(¤t_formspec, client, texture_src, - device, &input->joystick); - client->getScript()->on_death(); /* Handle visualization */ @@ -3283,6 +3227,13 @@ void Game::processClientEvents(CameraOrientation *cam, float *damage_flash) delete(event.show_formspec.formspec); delete(event.show_formspec.formname); + } else if (event.type == CE_SHOW_LOCAL_FORMSPEC) { + FormspecFormSource *fs_src = new FormspecFormSource(*event.show_formspec.formspec); + LocalFormspecHandler *txt_dst = new LocalFormspecHandler(*event.show_formspec.formname, client); + create_formspec_menu(¤t_formspec, client, device, &input->joystick, + fs_src, txt_dst); + delete event.show_formspec.formspec; + delete event.show_formspec.formname; } else if ((event.type == CE_SPAWN_PARTICLE) || (event.type == CE_ADD_PARTICLESPAWNER) || (event.type == CE_DELETE_PARTICLESPAWNER)) { diff --git a/src/guiFormSpecMenu.h b/src/guiFormSpecMenu.h index bbab9c164..35365a94b 100644 --- a/src/guiFormSpecMenu.h +++ b/src/guiFormSpecMenu.h @@ -548,7 +548,7 @@ private: class FormspecFormSource: public IFormSource { public: - FormspecFormSource(std::string formspec) + FormspecFormSource(const std::string &formspec) { m_formspec = formspec; } @@ -556,7 +556,7 @@ public: ~FormspecFormSource() {} - void setForm(std::string formspec) { + void setForm(const std::string &formspec) { m_formspec = FORMSPEC_VERSION_STRING + formspec; } diff --git a/src/script/cpp_api/s_client.cpp b/src/script/cpp_api/s_client.cpp index ce88d67e3..1827d483b 100644 --- a/src/script/cpp_api/s_client.cpp +++ b/src/script/cpp_api/s_client.cpp @@ -112,3 +112,27 @@ void ScriptApiClient::environment_step(float dtime) + script_get_backtrace(L)); } } + +void ScriptApiClient::on_formspec_input(const std::string &formname, + const StringMap &fields) +{ + SCRIPTAPI_PRECHECKHEADER + + // Get core.registered_on_chat_messages + lua_getglobal(L, "core"); + lua_getfield(L, -1, "registered_on_formspec_input"); + // Call callbacks + // param 1 + lua_pushstring(L, formname.c_str()); + // param 2 + lua_newtable(L); + StringMap::const_iterator it; + for (it = fields.begin(); it != fields.end(); ++it) { + const std::string &name = it->first; + const std::string &value = it->second; + lua_pushstring(L, name.c_str()); + lua_pushlstring(L, value.c_str(), value.size()); + lua_settable(L, -3); + } + runCallbacks(2, RUN_CALLBACKS_MODE_OR_SC); +} diff --git a/src/script/cpp_api/s_client.h b/src/script/cpp_api/s_client.h index 3d373f97c..42c41f8a4 100644 --- a/src/script/cpp_api/s_client.h +++ b/src/script/cpp_api/s_client.h @@ -22,6 +22,11 @@ with this program; if not, write to the Free Software Foundation, Inc., #define S_CLIENT_H_ #include "cpp_api/s_base.h" +#include "util/string.h" + +#ifdef _CRT_MSVCP_CURRENT +#include +#endif class ScriptApiClient: virtual public ScriptApiBase { @@ -36,7 +41,7 @@ public: void on_damage_taken(int32_t damage_amount); void on_hp_modification(int32_t newhp); void on_death(); - void environment_step(float dtime); + void on_formspec_input(const std::string &formname, const StringMap &fields); }; #endif diff --git a/src/script/lua_api/l_client.cpp b/src/script/lua_api/l_client.cpp index 7eb340d78..9a04bd02f 100644 --- a/src/script/lua_api/l_client.cpp +++ b/src/script/lua_api/l_client.cpp @@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "l_internal.h" #include "util/string.h" #include "cpp_api/s_base.h" +#include "gettext.h" int ModApiClient::l_get_current_modname(lua_State *L) { @@ -44,18 +45,55 @@ int ModApiClient::l_get_last_run_mod(lua_State *L) // set_last_run_mod(modname) int ModApiClient::l_set_last_run_mod(lua_State *L) { + if (!lua_isstring(L, 1)) + return 0; + const char *mod = lua_tostring(L, 1); getScriptApiBase(L)->setOriginDirect(mod); - return 0; + lua_pushboolean(L, true); + return 1; } // display_chat_message(message) int ModApiClient::l_display_chat_message(lua_State *L) { - NO_MAP_LOCK_REQUIRED; + if (!lua_isstring(L, 1)) + return 0; std::string message = luaL_checkstring(L, 1); getClient(L)->pushToChatQueue(utf8_to_wide(message)); + lua_pushboolean(L, true); + return 1; +} + +// show_formspec(formspec) +int ModApiClient::l_show_formspec(lua_State *L) +{ + if ( !lua_isstring(L, 1) || !lua_isstring(L, 2) ) + return 0; + + ClientEvent event; + event.type = CE_SHOW_LOCAL_FORMSPEC; + event.show_formspec.formname = new std::string(luaL_checkstring(L, 1)); + event.show_formspec.formspec = new std::string(luaL_checkstring(L, 2)); + getClient(L)->pushToEventQueue(event); + lua_pushboolean(L, true); + return 1; +} + +// send_respawn() +int ModApiClient::l_send_respawn(lua_State *L) +{ + getClient(L)->sendRespawn(); + return 0; +} + +// gettext(text) +int ModApiClient::l_gettext(lua_State *L) +{ + std::string text = strgettext(std::string(luaL_checkstring(L, 1))); + lua_pushstring(L, text.c_str()); + return 1; } @@ -65,4 +103,7 @@ void ModApiClient::Initialize(lua_State *L, int top) API_FCT(display_chat_message); API_FCT(set_last_run_mod); API_FCT(get_last_run_mod); + API_FCT(show_formspec); + API_FCT(send_respawn); + API_FCT(gettext); } diff --git a/src/script/lua_api/l_client.h b/src/script/lua_api/l_client.h index 150880e3c..14ef5aecc 100644 --- a/src/script/lua_api/l_client.h +++ b/src/script/lua_api/l_client.h @@ -33,6 +33,15 @@ private: // display_chat_message(message) static int l_display_chat_message(lua_State *L); + // show_formspec(name, fornspec) + static int l_show_formspec(lua_State *L); + + // send_respawn() + static int l_send_respawn(lua_State *L); + + // gettext(text) + static int l_gettext(lua_State *L); + // get_last_run_mod(n) static int l_get_last_run_mod(lua_State *L);