Implement sign using form field protocol
authorPerttu Ahola <celeron55@gmail.com>
Fri, 1 Jun 2012 17:51:15 +0000 (20:51 +0300)
committerPerttu Ahola <celeron55@gmail.com>
Sun, 3 Jun 2012 19:31:01 +0000 (22:31 +0300)
doc/lua_api.txt
games/minimal/mods/default/init.lua
src/client.cpp
src/client.h
src/clientserver.h
src/content_nodemeta.cpp
src/game.cpp
src/scriptapi.cpp
src/scriptapi.h
src/server.cpp

index 58c260425b361f65ae91c5f16a6903397073eaa0..73d7b3641c48e8a339b738d72c2a02f6924f1a5e 100644 (file)
@@ -1036,6 +1036,10 @@ Node definition (register_node)
        on_dig = func(pos, node, digger),
     ^ default: minetest.node_dig
     ^ By default: checks privileges, wears out tool and removes node
+
+    on_receive_fields = func(pos, formname, fields, sender),
+    ^ fields = {name1 = value1, name2 = value2, ...}
+    ^ default: nil
 }
 
 Recipe: (register_craft)
index 9573db11990eaa9d4b41de37da637f809425f84a..603380d5ba552e2bd997d9a042380f008a45435c 100644 (file)
@@ -1116,7 +1116,16 @@ minetest.register_node("default:sign_wall", {
                --local n = minetest.env:get_node(pos)
                local meta = minetest.env:get_meta(pos)
                meta:set_string("formspec", "hack:sign_text_input")
-               meta:set_string("infotext", "\"${text}\"")
+               meta:set_string("infotext", "\"\"")
+       end,
+       on_receive_fields = function(pos, formname, fields, sender)
+               --print("Sign at "..minetest.pos_to_string(pos).." got "..dump(fields))
+               local meta = minetest.env:get_meta(pos)
+               fields.text = fields.text or ""
+               print((sender:get_player_name() or "").." wrote \""..fields.text..
+                               "\" to sign at "..minetest.pos_to_string(pos))
+               meta:set_string("text", fields.text)
+               meta:set_string("infotext", '"'..fields.text..'"')
        end,
 })
 
index 72667a528a4e5214afe57665e4b293c2531127ef..84cae8f97cac37be3b72b0f35bacedac636b99d7 100644 (file)
@@ -1740,33 +1740,23 @@ void Client::interact(u8 action, const PointedThing& pointed)
        Send(0, data, true);
 }
 
-void Client::sendSignNodeText(v3s16 p, std::string text)
+void Client::sendNodemetaFields(v3s16 p, const std::string &formname,
+               const std::map<std::string, std::string> &fields)
 {
-       /*
-               u16 command
-               v3s16 p
-               u16 textlen
-               textdata
-       */
        std::ostringstream os(std::ios_base::binary);
-       u8 buf[12];
-       
-       // Write command
-       writeU16(buf, TOSERVER_SIGNNODETEXT);
-       os.write((char*)buf, 2);
-       
-       // Write p
-       writeV3S16(buf, p);
-       os.write((char*)buf, 6);
 
-       u16 textlen = text.size();
-       // Write text length
-       writeS16(buf, textlen);
-       os.write((char*)buf, 2);
+       writeU16(os, TOSERVER_NODEMETA_FIELDS);
+       writeV3S16(os, p);
+       os<<serializeString(formname);
+       writeU16(os, fields.size());
+       for(std::map<std::string, std::string>::const_iterator
+                       i = fields.begin(); i != fields.end(); i++){
+               const std::string &name = i->first;
+               const std::string &value = i->second;
+               os<<serializeString(name);
+               os<<serializeLongString(value);
+       }
 
-       // Write text
-       os.write((char*)text.c_str(), textlen);
-       
        // Make data buffer
        std::string s = os.str();
        SharedBuffer<u8> data((u8*)s.c_str(), s.size());
index 72ab70abd246baed500a710c3a9bf10b0bd1c65b..0ed3eea3bc62494eb16b12d5a2791483a1902a1d 100644 (file)
@@ -210,11 +210,12 @@ public:
 
        void interact(u8 action, const PointedThing& pointed);
 
-       void sendSignNodeText(v3s16 p, std::string text);
+       void sendNodemetaFields(v3s16 p, const std::string &formname,
+                       const std::map<std::string, std::string> &fields);
        void sendInventoryAction(InventoryAction *a);
        void sendChatMessage(const std::wstring &message);
        void sendChangePassword(const std::wstring oldpassword,
-               const std::wstring newpassword);
+                       const std::wstring newpassword);
        void sendDamage(u8 damage);
        void sendRespawn();
 
index 461c13cd269e8ecf1c84d8346f30a804e2d8a187..1b5a378487997d597571d9140759eb335e75f123 100644 (file)
@@ -415,7 +415,7 @@ enum ToServerCommand
                wstring message
        */
 
-       TOSERVER_SIGNNODETEXT = 0x33,
+       TOSERVER_SIGNNODETEXT = 0x33, // obsolete
        /*
                u16 command
                v3s16 p
@@ -484,6 +484,20 @@ enum ToServerCommand
                s32[len] sound_id
        */
 
+       TOSERVER_NODEMETA_FIELDS = 0x3b,
+       /*
+               u16 command
+               v3s16 p
+               u16 len
+               u8[len] form name (reserved for future use)
+               u16 number of fields
+               for each field:
+                       u16 len
+                       u8[len] field name
+                       u32 len
+                       u8[len] field value
+       */
+
        TOSERVER_REQUEST_MEDIA = 0x40,
        /*
                u16 command
index ba4a0e5137df529cd81551590cfe08de13d88d4b..a2a341ae0701742afa5c79ac0eb6f0af3ec4d9fb 100644 (file)
@@ -57,7 +57,9 @@ static bool content_nodemeta_deserialize_legacy_body(
        else if(id == NODEMETA_SIGN) // SignNodeMetadata
        {
                meta->setString("text", deSerializeLongString(is));
-               meta->setString("infotext","\"${text}\"");
+               //meta->setString("infotext","\"${text}\"");
+               meta->setString("infotext",
+                               std::string("\"") + meta->getString("text") + "\"");
                meta->setString("formspec","field[text;;${text}]");
                return false;
        }
index 69fc601c3815dcd76d849d3c3ca0f365104929a0..815a5dd85dacb227fcfe5a6d98578243466d8960 100644 (file)
@@ -103,7 +103,9 @@ struct TextDestNodeMetadata : public TextDest
                std::string ntext = wide_to_narrow(text);
                infostream<<"Changing text of a sign node: "
                                <<ntext<<std::endl;
-               m_client->sendSignNodeText(m_p, ntext);
+               std::map<std::string, std::string> fields;
+               fields["text"] = ntext;
+               m_client->sendNodemetaFields(m_p, "", fields);
        }
 
        v3s16 m_p;
index 255d37fc2f5f1e77be7d3a91a517fe37a9bb1b7e..f9ec585826068a74b643ff29cb901a147fcd3810 100644 (file)
@@ -141,14 +141,14 @@ static Server* get_server(lua_State *L)
        return server;
 }
 
-/*static ServerEnvironment* get_env(lua_State *L)
+static ServerEnvironment* get_env(lua_State *L)
 {
        // Get environment from registry
        lua_getfield(L, LUA_REGISTRYINDEX, "minetest_env");
        ServerEnvironment *env = (ServerEnvironment*)lua_touserdata(L, -1);
        lua_pop(L, 1);
        return env;
-}*/
+}
 
 static void objectref_get(lua_State *L, u16 id)
 {
@@ -4973,6 +4973,47 @@ void scriptapi_node_on_destruct(lua_State *L, v3s16 p, MapNode node)
                script_error(L, "error: %s", lua_tostring(L, -1));
 }
 
+void scriptapi_node_on_receive_fields(lua_State *L, v3s16 p,
+               const std::string &formname,
+               const std::map<std::string, std::string> &fields,
+               ServerActiveObject *sender)
+{
+       realitycheck(L);
+       assert(lua_checkstack(L, 20));
+       StackUnroller stack_unroller(L);
+
+       INodeDefManager *ndef = get_server(L)->ndef();
+       
+       // If node doesn't exist, we don't know what callback to call
+       MapNode node = get_env(L)->getMap().getNodeNoEx(p);
+       if(node.getContent() == CONTENT_IGNORE)
+               return;
+
+       // Push callback function on stack
+       if(!get_item_callback(L, ndef->get(node).name.c_str(), "on_receive_fields"))
+               return;
+
+       // Call function
+       // param 1
+       push_v3s16(L, p);
+       // param 2
+       lua_pushstring(L, formname.c_str());
+       // param 3
+       lua_newtable(L);
+       for(std::map<std::string, std::string>::const_iterator
+                       i = fields.begin(); i != fields.end(); i++){
+               const std::string &name = i->first;
+               const std::string &value = i->second;
+               lua_pushstring(L, name.c_str());
+               lua_pushlstring(L, value.c_str(), value.size());
+               lua_settable(L, -3);
+       }
+       // param 4
+       objectref_get_or_create(L, sender);
+       if(lua_pcall(L, 4, 0, 0))
+               script_error(L, "error: %s", lua_tostring(L, -1));
+}
+
 /*
        environment
 */
index cd6a5614ceb778a37451921ca497ded26e25f094..e6c16eba665e8a13812fe30e9ee18478ff7c3fe8 100644 (file)
@@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include <string>
 #include "mapnode.h"
 #include <set>
+#include <map>
 
 class Server;
 class ServerEnvironment;
@@ -83,6 +84,10 @@ bool scriptapi_node_on_dig(lua_State *L, v3s16 p, MapNode node,
                ServerActiveObject *digger);
 void scriptapi_node_on_construct(lua_State *L, v3s16 p, MapNode node);
 void scriptapi_node_on_destruct(lua_State *L, v3s16 p, MapNode node);
+void scriptapi_node_on_receive_fields(lua_State *L, v3s16 p,
+               const std::string &formname,
+               const std::map<std::string, std::string> &fields,
+               ServerActiveObject *sender);
 
 /* luaentity */
 // Returns true if succesfully added into Lua; false otherwise.
index 0ee0ef465634aa53b23271ca6911740bf930c07c..fbeff83bfe459b368b2bd9b20258fa6f7d1df436 100644 (file)
@@ -3126,6 +3126,24 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                m_playing_sounds.erase(i++);
                }
        }
+       else if(command == TOSERVER_NODEMETA_FIELDS)
+       {
+               std::string datastring((char*)&data[2], datasize-2);
+               std::istringstream is(datastring, std::ios_base::binary);
+               
+               v3s16 p = readV3S16(is);
+               std::string formname = deSerializeString(is);
+               int num = readU16(is);
+               std::map<std::string, std::string> fields;
+               for(int k=0; k<num; k++){
+                       std::string fieldname = deSerializeString(is);
+                       std::string fieldvalue = deSerializeLongString(is);
+                       fields[fieldname] = fieldvalue;
+               }
+
+               scriptapi_node_on_receive_fields(m_lua, p, formname, fields,
+                               playersao);
+       }
        else
        {
                infostream<<"Server::ProcessData(): Ignoring "