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({
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:"..
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
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
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)
{
}
}
-void Client::addNode(v3s16 p, MapNode n)
+void Client::addNode(v3s16 p, MapNode n, bool remove_metadata)
{
TimeTaker timer1("Client::addNode()");
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)
{}
// 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);
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
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
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;
// 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);
/*
*/
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();
/*
Remove node metadata
*/
-
- removeNodeMetadata(p);
+ if (remove_metadata) {
+ removeNodeMetadata(p);
+ }
/*
Set the node on the map
}
}
-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
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,
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;
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);
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);
/*
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)
{
API_FCT(set_node);
API_FCT(add_node);
+ API_FCT(swap_node);
API_FCT(add_item);
API_FCT(remove_node);
API_FCT(get_node);
// 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}
// 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)
{
}
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);
}
// 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);
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