Add minetest.swap_node
authorNovatux <nathanael.courant@laposte.net>
Sat, 23 Nov 2013 14:35:49 +0000 (15:35 +0100)
committerNovatux <nathanael.courant@laposte.net>
Sat, 30 Nov 2013 17:37:56 +0000 (18:37 +0100)
12 files changed:
games/minimal/mods/default/init.lua
src/client.cpp
src/client.h
src/clientserver.h
src/environment.cpp
src/environment.h
src/map.cpp
src/map.h
src/script/lua_api/l_env.cpp
src/script/lua_api/l_env.h
src/server.cpp
src/server.h

index 8cef3fcc0ae210ab0959cd523de135def9734133..038bf9abc51754964626864e9d045855b78bb134 100644 (file)
@@ -1318,18 +1318,13 @@ minetest.register_node("default:furnace_active", {
        end,
 })
 
-function hacky_swap_node(pos,name)
+function swap_node(pos,name)
        local node = minetest.get_node(pos)
-       local meta = minetest.get_meta(pos)
-       local meta0 = meta:to_table()
        if node.name == name then
                return
        end
        node.name = name
-       local meta0 = meta:to_table()
-       minetest.set_node(pos,node)
-       meta = minetest.get_meta(pos)
-       meta:from_table(meta0)
+       minetest.swap_node(pos, node)
 end
 
 minetest.register_abm({
@@ -1384,7 +1379,7 @@ minetest.register_abm({
                        local percent = math.floor(meta:get_float("fuel_time") /
                                        meta:get_float("fuel_totaltime") * 100)
                        meta:set_string("infotext","Furnace active: "..percent.."%")
-                       hacky_swap_node(pos,"default:furnace_active")
+                       swap_node(pos,"default:furnace_active")
                        meta:set_string("formspec",
                                "size[8,9]"..
                                "image[2,2;1,1;default_furnace_fire_bg.png^[lowpart:"..
@@ -1410,7 +1405,7 @@ minetest.register_abm({
 
                if fuel.time <= 0 then
                        meta:set_string("infotext","Furnace out of fuel")
-                       hacky_swap_node(pos,"default:furnace")
+                       swap_node(pos,"default:furnace")
                        meta:set_string("formspec", default.furnace_inactive_formspec)
                        return
                end
@@ -1418,7 +1413,7 @@ minetest.register_abm({
                if cooked.item:is_empty() then
                        if was_active then
                                meta:set_string("infotext","Furnace is empty")
-                               hacky_swap_node(pos,"default:furnace")
+                               swap_node(pos,"default:furnace")
                                meta:set_string("formspec", default.furnace_inactive_formspec)
                        end
                        return
index 5e8f20620f5b9b66000b552ff8541db0afdc3c45..a9a1f6dd90a585c9da8867075ca99935457c2934 100644 (file)
@@ -1262,7 +1262,13 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
                MapNode n;
                n.deSerialize(&data[8], ser_version);
                
-               addNode(p, n);
+               bool remove_metadata = true;
+               u32 index = 8 + MapNode::serializedLength(ser_version);
+               if ((datasize >= index+1) && data[index]){
+                       remove_metadata = false;
+               }       
+               
+               addNode(p, n, remove_metadata);
        }
        else if(command == TOCLIENT_BLOCKDATA)
        {
@@ -2514,7 +2520,7 @@ void Client::removeNode(v3s16 p)
        }
 }
 
-void Client::addNode(v3s16 p, MapNode n)
+void Client::addNode(v3s16 p, MapNode n, bool remove_metadata)
 {
        TimeTaker timer1("Client::addNode()");
 
@@ -2523,7 +2529,7 @@ void Client::addNode(v3s16 p, MapNode n)
        try
        {
                //TimeTaker timer3("Client::addNode(): addNodeAndUpdate");
-               m_env.getMap().addNodeAndUpdate(p, n, modified_blocks);
+               m_env.getMap().addNodeAndUpdate(p, n, modified_blocks, remove_metadata);
        }
        catch(InvalidPositionException &e)
        {}
index 9f5eb833bfec872432613e86287971e76f4ca7e6..eb0f225a2ef744fbfc63b99f48a0267b54676af0 100644 (file)
@@ -365,7 +365,7 @@ public:
        
        // Causes urgent mesh updates (unlike Map::add/removeNodeWithEvent)
        void removeNode(v3s16 p);
-       void addNode(v3s16 p, MapNode n);
+       void addNode(v3s16 p, MapNode n, bool remove_metadata = true);
        
        void setPlayerControl(PlayerControl &control);
 
index 67a4846a668797648c656c4cb7dcd034eaa9f5dd..90f6f9a88c00a8d766190c5be76af6da6c1e2e5d 100644 (file)
@@ -102,7 +102,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
                        added to object properties
 */
 
-#define LATEST_PROTOCOL_VERSION 21
+#define LATEST_PROTOCOL_VERSION 22
 
 // Server's supported network protocol range
 #define SERVER_PROTOCOL_VERSION_MIN 13
@@ -139,6 +139,12 @@ enum ToClientCommand
 
        TOCLIENT_BLOCKDATA = 0x20, //TODO: Multiple blocks
        TOCLIENT_ADDNODE = 0x21,
+       /*
+               u16 command
+               v3s16 position
+               serialized mapnode
+               u8 keep_metadata // Added in protocol version 22
+       */
        TOCLIENT_REMOVENODE = 0x22,
        
        TOCLIENT_PLAYERPOS = 0x23, // Obsolete
index f019591dfe21fffff90f49d9d36dd0ccd5bbe460..e4567a78e2318f8c95653bcbf15ed1af5d18e938 100644 (file)
@@ -874,6 +874,11 @@ bool ServerEnvironment::removeNode(v3s16 p)
        return true;
 }
 
+bool ServerEnvironment::swapNode(v3s16 p, const MapNode &n)
+{
+       return m_map->addNodeWithEvent(p, n, false);
+}
+
 std::set<u16> ServerEnvironment::getObjectsInsideRadius(v3f pos, float radius)
 {
        std::set<u16> objects;
index 86654937d0f18aee14402e530906d9385c032d3c..9f9a0a23ccbf1bc6e35096086985722c769c565b 100644 (file)
@@ -283,6 +283,7 @@ public:
        // Script-aware node setters
        bool setNode(v3s16 p, const MapNode &n);
        bool removeNode(v3s16 p);
+       bool swapNode(v3s16 p, const MapNode &n);
        
        // Find all active objects inside a radius around a point
        std::set<u16> getObjectsInsideRadius(v3f pos, float radius);
index 0f9c82c3cc1f00b8ff3d4b602aad91339402cd96..c85876a750ab158a1ebef921f884c2c86496dcdb 100644 (file)
@@ -931,7 +931,8 @@ void Map::updateLighting(std::map<v3s16, MapBlock*> & a_blocks,
 /*
 */
 void Map::addNodeAndUpdate(v3s16 p, MapNode n,
-               std::map<v3s16, MapBlock*> &modified_blocks)
+               std::map<v3s16, MapBlock*> &modified_blocks,
+               bool remove_metadata)
 {
        INodeDefManager *ndef = m_gamedef->ndef();
 
@@ -1018,8 +1019,9 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
        /*
                Remove node metadata
        */
-
-       removeNodeMetadata(p);
+       if (remove_metadata) {
+               removeNodeMetadata(p);
+       }
 
        /*
                Set the node on the map
@@ -1319,17 +1321,17 @@ void Map::removeNodeAndUpdate(v3s16 p,
        }
 }
 
-bool Map::addNodeWithEvent(v3s16 p, MapNode n)
+bool Map::addNodeWithEvent(v3s16 p, MapNode n, bool remove_metadata)
 {
        MapEditEvent event;
-       event.type = MEET_ADDNODE;
+       event.type = remove_metadata ? MEET_ADDNODE : MEET_SWAPNODE;
        event.p = p;
        event.n = n;
 
        bool succeeded = true;
        try{
                std::map<v3s16, MapBlock*> modified_blocks;
-               addNodeAndUpdate(p, n, modified_blocks);
+               addNodeAndUpdate(p, n, modified_blocks, remove_metadata);
 
                // Copy modified_blocks to event
                for(std::map<v3s16, MapBlock*>::iterator
index 8e55af4377ba55bcc935191b6b880a19d9095d1c..8abea896ec8c34655c2ec7c154e9792477b16c50 100644 (file)
--- a/src/map.h
+++ b/src/map.h
@@ -61,6 +61,8 @@ enum MapEditEventType{
        MEET_ADDNODE,
        // Node removed (changed to air)
        MEET_REMOVENODE,
+       // Node swapped (changed without metadata change)
+       MEET_SWAPNODE,
        // Node metadata of block changed (not knowing which node exactly)
        // p stores block coordinate
        MEET_BLOCK_NODE_METADATA_CHANGED,
@@ -99,6 +101,8 @@ struct MapEditEvent
                        return VoxelArea(p);
                case MEET_REMOVENODE:
                        return VoxelArea(p);
+               case MEET_SWAPNODE:
+                       return VoxelArea(p);
                case MEET_BLOCK_NODE_METADATA_CHANGED:
                {
                        v3s16 np1 = p*MAP_BLOCKSIZE;
@@ -236,7 +240,8 @@ public:
                These handle lighting but not faces.
        */
        void addNodeAndUpdate(v3s16 p, MapNode n,
-                       std::map<v3s16, MapBlock*> &modified_blocks);
+                       std::map<v3s16, MapBlock*> &modified_blocks,
+                       bool remove_metadata = true);
        void removeNodeAndUpdate(v3s16 p,
                        std::map<v3s16, MapBlock*> &modified_blocks);
 
@@ -245,7 +250,7 @@ public:
                These emit events.
                Return true if succeeded, false if not.
        */
-       bool addNodeWithEvent(v3s16 p, MapNode n);
+       bool addNodeWithEvent(v3s16 p, MapNode n, bool remove_metadata = true);
        bool removeNodeWithEvent(v3s16 p);
 
        /*
index 76e8c69071f0cacd22fa7bf65cd1220dca4859e5..a33882bdfba237fb35551aeee386e5edac5613c6 100644 (file)
@@ -120,6 +120,22 @@ int ModApiEnvMod::l_remove_node(lua_State *L)
        return 1;
 }
 
+// minetest.swap_node(pos, node)
+// pos = {x=num, y=num, z=num}
+int ModApiEnvMod::l_swap_node(lua_State *L)
+{
+       GET_ENV_PTR;
+
+       INodeDefManager *ndef = env->getGameDef()->ndef();
+       // parameters
+       v3s16 pos = read_v3s16(L, 1);
+       MapNode n = readnode(L, 2, ndef);
+       // Do it
+       bool succeeded = env->swapNode(pos, n);
+       lua_pushboolean(L, succeeded);
+       return 1;
+}
+
 // minetest.get_node(pos)
 // pos = {x=num, y=num, z=num}
 int ModApiEnvMod::l_get_node(lua_State *L)
@@ -798,6 +814,7 @@ void ModApiEnvMod::Initialize(lua_State *L, int top)
 {
        API_FCT(set_node);
        API_FCT(add_node);
+       API_FCT(swap_node);
        API_FCT(add_item);
        API_FCT(remove_node);
        API_FCT(get_node);
index 814d12165dc5be4de55067e21a30ccddc9ce90e9..126349c6e5016e87c16323e89b5ee1008e259e51 100644 (file)
@@ -34,6 +34,10 @@ private:
        // minetest.remove_node(pos)
        // pos = {x=num, y=num, z=num}
        static int l_remove_node(lua_State *L);
+       
+       // minetest.swap_node(pos, node)
+       // pos = {x=num, y=num, z=num}
+       static int l_swap_node(lua_State *L);
 
        // minetest.get_node(pos)
        // pos = {x=num, y=num, z=num}
index c29ec3d83583de73c670ba7bc2dae0035f0ddfcc..f0de54f665395462dfcadd68ce6343bdf47daec4 100644 (file)
@@ -1582,16 +1582,16 @@ void Server::AsyncRunStep()
                        // for them.
                        std::list<u16> far_players;
 
-                       if(event->type == MEET_ADDNODE)
+                       if(event->type == MEET_ADDNODE || event->type == MEET_SWAPNODE)
                        {
                                //infostream<<"Server: MEET_ADDNODE"<<std::endl;
                                prof.add("MEET_ADDNODE", 1);
                                if(disable_single_change_sending)
                                        sendAddNode(event->p, event->n, event->already_known_by_peer,
-                                                       &far_players, 5);
+                                                       &far_players, 5, event->type == MEET_ADDNODE);
                                else
                                        sendAddNode(event->p, event->n, event->already_known_by_peer,
-                                                       &far_players, 30);
+                                                       &far_players, 30, event->type == MEET_ADDNODE);
                        }
                        else if(event->type == MEET_REMOVENODE)
                        {
@@ -4070,7 +4070,8 @@ void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
 }
 
 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
-               std::list<u16> *far_players, float far_d_nodes)
+               std::list<u16> *far_players, float far_d_nodes,
+               bool remove_metadata)
 {
        float maxd = far_d_nodes*BS;
        v3f p_f = intToFloat(p, BS);
@@ -4106,13 +4107,23 @@ void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
                }
 
                // Create packet
-               u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
+               u32 replysize = 9 + MapNode::serializedLength(client->serialization_version);
                SharedBuffer<u8> reply(replysize);
                writeU16(&reply[0], TOCLIENT_ADDNODE);
                writeS16(&reply[2], p.X);
                writeS16(&reply[4], p.Y);
                writeS16(&reply[6], p.Z);
                n.serialize(&reply[8], client->serialization_version);
+               u32 index = 8 + MapNode::serializedLength(client->serialization_version);
+               writeU8(&reply[index], remove_metadata ? 0 : 1);
+               
+               if (!remove_metadata) {
+                       if (client->net_proto_version <= 21) {
+                               // Old clients always clear metadata; fix it
+                               // by sending the full block again.
+                               client->SetBlockNotSent(p);
+                       }
+               }
 
                // Send as reliable
                m_con.Send(client->peer_id, 0, reply, true);
index b52ae02dcf19b90ebe6a98ef54e33c314d247f9a..87a603533d08dadf22627f52a123c42dc81a62fd 100644 (file)
@@ -556,7 +556,8 @@ private:
        void sendRemoveNode(v3s16 p, u16 ignore_id=0,
                        std::list<u16> *far_players=NULL, float far_d_nodes=100);
        void sendAddNode(v3s16 p, MapNode n, u16 ignore_id=0,
-                       std::list<u16> *far_players=NULL, float far_d_nodes=100);
+                       std::list<u16> *far_players=NULL, float far_d_nodes=100,
+                       bool remove_metadata=true);
        void setBlockNotSent(v3s16 p);
 
        // Environment and Connection must be locked when called