From d879a539cd19ddd1ee34afec2512fb2238de2822 Mon Sep 17 00:00:00 2001 From: Novatux Date: Sat, 23 Nov 2013 15:35:49 +0100 Subject: [PATCH] Add minetest.swap_node --- games/minimal/mods/default/init.lua | 15 +++++---------- src/client.cpp | 12 +++++++++--- src/client.h | 2 +- src/clientserver.h | 8 +++++++- src/environment.cpp | 5 +++++ src/environment.h | 1 + src/map.cpp | 14 ++++++++------ src/map.h | 9 +++++++-- src/script/lua_api/l_env.cpp | 17 +++++++++++++++++ src/script/lua_api/l_env.h | 4 ++++ src/server.cpp | 21 ++++++++++++++++----- src/server.h | 3 ++- 12 files changed, 82 insertions(+), 29 deletions(-) diff --git a/games/minimal/mods/default/init.lua b/games/minimal/mods/default/init.lua index 8cef3fcc0..038bf9abc 100644 --- a/games/minimal/mods/default/init.lua +++ b/games/minimal/mods/default/init.lua @@ -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 diff --git a/src/client.cpp b/src/client.cpp index 5e8f20620..a9a1f6dd9 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -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) {} diff --git a/src/client.h b/src/client.h index 9f5eb833b..eb0f225a2 100644 --- a/src/client.h +++ b/src/client.h @@ -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); diff --git a/src/clientserver.h b/src/clientserver.h index 67a4846a6..90f6f9a88 100644 --- a/src/clientserver.h +++ b/src/clientserver.h @@ -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 diff --git a/src/environment.cpp b/src/environment.cpp index f019591df..e4567a78e 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -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 ServerEnvironment::getObjectsInsideRadius(v3f pos, float radius) { std::set objects; diff --git a/src/environment.h b/src/environment.h index 86654937d..9f9a0a23c 100644 --- a/src/environment.h +++ b/src/environment.h @@ -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 getObjectsInsideRadius(v3f pos, float radius); diff --git a/src/map.cpp b/src/map.cpp index 0f9c82c3c..c85876a75 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -931,7 +931,8 @@ void Map::updateLighting(std::map & a_blocks, /* */ void Map::addNodeAndUpdate(v3s16 p, MapNode n, - std::map &modified_blocks) + std::map &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 modified_blocks; - addNodeAndUpdate(p, n, modified_blocks); + addNodeAndUpdate(p, n, modified_blocks, remove_metadata); // Copy modified_blocks to event for(std::map::iterator diff --git a/src/map.h b/src/map.h index 8e55af437..8abea896e 100644 --- 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 &modified_blocks); + std::map &modified_blocks, + bool remove_metadata = true); void removeNodeAndUpdate(v3s16 p, std::map &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); /* diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp index 76e8c6907..a33882bdf 100644 --- a/src/script/lua_api/l_env.cpp +++ b/src/script/lua_api/l_env.cpp @@ -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); diff --git a/src/script/lua_api/l_env.h b/src/script/lua_api/l_env.h index 814d12165..126349c6e 100644 --- a/src/script/lua_api/l_env.h +++ b/src/script/lua_api/l_env.h @@ -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} diff --git a/src/server.cpp b/src/server.cpp index c29ec3d83..f0de54f66 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1582,16 +1582,16 @@ void Server::AsyncRunStep() // for them. std::list far_players; - if(event->type == MEET_ADDNODE) + if(event->type == MEET_ADDNODE || event->type == MEET_SWAPNODE) { //infostream<<"Server: MEET_ADDNODE"<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 *far_players, float far_d_nodes) + std::list *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 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); diff --git a/src/server.h b/src/server.h index b52ae02dc..87a603533 100644 --- a/src/server.h +++ b/src/server.h @@ -556,7 +556,8 @@ private: void sendRemoveNode(v3s16 p, u16 ignore_id=0, std::list *far_players=NULL, float far_d_nodes=100); void sendAddNode(v3s16 p, MapNode n, u16 ignore_id=0, - std::list *far_players=NULL, float far_d_nodes=100); + std::list *far_players=NULL, float far_d_nodes=100, + bool remove_metadata=true); void setBlockNotSent(v3s16 p); // Environment and Connection must be locked when called