From 9af9d8f5d003d87aeea269b88463e7c20cc7bda0 Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Mon, 23 Jul 2012 20:17:44 +0300 Subject: [PATCH 01/17] Describe node definition fields better in lua_api.txt --- doc/lua_api.txt | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 2157ca8a84..d0af5b4db2 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -1280,30 +1280,29 @@ Node definition (register_node) drawtype = "normal", -- See "Node drawtypes" visual_scale = 1.0, tiles = {tile definition 1, def2, def3, def4, def5, def6}, + ^ Textures of node; +Y, -Y, +X, -X, +Z, -Z (old field name: tile_images) ^ List can be shortened to needed length - ^ Old field name: tile_images special_tiles = {tile definition 1, Tile definition 2}, + ^ Special textures of node; used rarely (old field name: special_materials) ^ List can be shortened to needed length - ^ Old field name: special_materials alpha = 255, - post_effect_color = {a=0, r=0, g=0, b=0}, - paramtype = "none", - paramtype2 = "none", - is_ground_content = false, - sunlight_propagates = false, - walkable = true, - pointable = true, - diggable = true, - climbable = false, - buildable_to = false, - drop = "", - -- alternatively drop = { max_items = ..., items = { ... } } - liquidtype = "none", - liquid_alternative_flowing = "", - liquid_alternative_source = "", - liquid_viscosity = 0, - light_source = 0, - damage_per_second = 0, + post_effect_color = {a=0, r=0, g=0, b=0}, -- If player is inside node + paramtype = "none", -- See "Nodes" + paramtype2 = "none", -- See "Nodes" + is_ground_content = false, -- Currently not used for anything + sunlight_propagates = false, -- If true, sunlight will go infinitely through this + walkable = true, -- If true, objects collide with node + pointable = true, -- If true, can be pointed at + diggable = true, -- If false, can never be dug + climbable = false, -- If true, can be climbed on (ladder) + buildable_to = false, -- If true, placed nodes can replace this node + drop = "", -- alternatively drop = { max_items = ..., items = { ... } } + liquidtype = "none", -- "none"/"source"/"flowing" + liquid_alternative_flowing = "", -- Flowing version of source liquid + liquid_alternative_source = "", -- Source version of flowing liquid + liquid_viscosity = 0, -- Higher viscosity = slower flow (max. 7) + light_source = 0, -- Amount of light emitted by node + damage_per_second = 0, -- If player is inside node, this damage is caused node_box = {type="regular"}, -- See "Node boxes" selection_box = {type="regular"}, -- See "Node boxes" legacy_facedir_simple = false, -- Support maps made in and before January 2012 From c009aa3a22b0a2d5790898ac05c92d429c82f94a Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Mon, 23 Jul 2012 20:41:40 +0300 Subject: [PATCH 02/17] Fix building on top of (pointable && buildable_to) nodes --- builtin/item.lua | 48 ++++++++++++++++++++++++++++++++++-------------- src/game.cpp | 7 +++++++ 2 files changed, 41 insertions(+), 14 deletions(-) diff --git a/builtin/item.lua b/builtin/item.lua index 5cd28303a7..08b8d1c58a 100644 --- a/builtin/item.lua +++ b/builtin/item.lua @@ -125,50 +125,70 @@ function minetest.item_place_node(itemstack, placer, pointed_thing) local item = itemstack:peek_item() local def = itemstack:get_definition() if def.type == "node" and pointed_thing.type == "node" then - local pos = pointed_thing.above - local oldnode = minetest.env:get_node(pos) - local olddef = ItemStack({name=oldnode.name}):get_definition() + local under = pointed_thing.under + local oldnode_under = minetest.env:get_node(under) + local olddef_under = ItemStack({name=oldnode_under.name}):get_definition() + olddef_under = olddef_under or minetest.nodedef_default + local above = pointed_thing.above + local oldnode_above = minetest.env:get_node(above) + local olddef_above = ItemStack({name=oldnode_above.name}):get_definition() + olddef_above = olddef_above or minetest.nodedef_default - if not olddef.buildable_to then + if not olddef_above.buildable_to and not olddef_under.buildable_to then minetest.log("info", placer:get_player_name() .. " tried to place" - .. " node in invalid position " .. minetest.pos_to_string(pos) - .. ", replacing " .. oldnode.name) + .. " node in invalid position " .. minetest.pos_to_string(above) + .. ", replacing " .. oldnode_above.name) return end + -- Place above pointed node + local place_to = {x = above.x, y = above.y, z = above.z} + + -- If node under is buildable_to, place into it instead (eg. snow) + if olddef_under.buildable_to then + minetest.log("info", "node under is buildable to") + place_to = {x = under.x, y = under.y, z = under.z} + end + minetest.log("action", placer:get_player_name() .. " places node " - .. def.name .. " at " .. minetest.pos_to_string(pos)) + .. def.name .. " at " .. minetest.pos_to_string(place_to)) local newnode = {name = def.name, param1 = 0, param2 = 0} -- Calculate direction for wall mounted stuff like torches and signs if def.paramtype2 == 'wallmounted' then - local under = pointed_thing.under - local above = pointed_thing.above - local dir = {x = under.x - above.x, y = under.y - above.y, z = under.z - above.z} + local dir = { + x = under.x - above.x, + y = under.y - above.y, + z = under.z - above.z + } newnode.param2 = minetest.dir_to_wallmounted(dir) -- Calculate the direction for furnaces and chests and stuff elseif def.paramtype2 == 'facedir' then local placer_pos = placer:getpos() if placer_pos then - local dir = {x = pos.x - placer_pos.x, y = pos.y - placer_pos.y, z = pos.z - placer_pos.z} + local dir = { + x = above.x - placer_pos.x, + y = above.y - placer_pos.y, + z = above.z - placer_pos.z + } newnode.param2 = minetest.dir_to_facedir(dir) minetest.log("action", "facedir: " .. newnode.param2) end end -- Add node and update - minetest.env:add_node(pos, newnode) + minetest.env:add_node(place_to, newnode) -- Run callback if def.after_place_node then - def.after_place_node(pos, placer) + def.after_place_node(place_to, placer) end -- Run script hook (deprecated) local _, callback for _, callback in ipairs(minetest.registered_on_placenodes) do - callback(pos, newnode, placer) + callback(place_to, newnode, placer) end itemstack:take_item() diff --git a/src/game.cpp b/src/game.cpp index 19c4707de6..7d93e3db26 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -2304,6 +2304,13 @@ void the_game( <get(n_under).buildable_to) + p = nodepos; + }catch(InvalidPositionException &e){} + // Find id of predicted node content_t id; bool found = nodedef->getId(def.node_placement_prediction, id); From e8331f0c1db5d7e0edf97d26e4b6f5a88d9ffa03 Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Mon, 23 Jul 2012 20:44:56 +0300 Subject: [PATCH 03/17] Add oldnode parameter to minetest.register_on_placenode callback --- builtin/item.lua | 5 +++-- doc/lua_api.txt | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/builtin/item.lua b/builtin/item.lua index 08b8d1c58a..e19fd559a2 100644 --- a/builtin/item.lua +++ b/builtin/item.lua @@ -152,7 +152,8 @@ function minetest.item_place_node(itemstack, placer, pointed_thing) minetest.log("action", placer:get_player_name() .. " places node " .. def.name .. " at " .. minetest.pos_to_string(place_to)) - + + local oldnode = minetest.env:get_node(place_to) local newnode = {name = def.name, param1 = 0, param2 = 0} -- Calculate direction for wall mounted stuff like torches and signs @@ -188,7 +189,7 @@ function minetest.item_place_node(itemstack, placer, pointed_thing) -- Run script hook (deprecated) local _, callback for _, callback in ipairs(minetest.registered_on_placenodes) do - callback(place_to, newnode, placer) + callback(place_to, newnode, placer, oldnode) end itemstack:take_item() diff --git a/doc/lua_api.txt b/doc/lua_api.txt index d0af5b4db2..176745a2d7 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -774,11 +774,11 @@ minetest.register_craft(recipe) Global callback registration functions: (Call these only at load time) minetest.register_globalstep(func(dtime)) ^ Called every server step, usually interval of 0.05s -minetest.register_on_placenode(func(pos, newnode, placer)) +minetest.register_on_placenode(func(pos, newnode, placer, oldnode)) ^ Called when a node has been placed ^ Deprecated: Use on_construct or after_place_node in node definition instead minetest.register_on_dignode(func(pos, oldnode, digger)) -^ Called when a node has been dug. digger can be nil. +^ Called when a node has been dug. ^ Deprecated: Use on_destruct or after_dig_node in node definition instead minetest.register_on_punchnode(func(pos, node, puncher)) ^ Called when a node is punched From 717ae6799542d000952c80d834bd3d9892bc9616 Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Tue, 24 Jul 2012 14:51:13 +0300 Subject: [PATCH 04/17] Add node timer test in minimal/experimental --- games/minimal/mods/experimental/init.lua | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/games/minimal/mods/experimental/init.lua b/games/minimal/mods/experimental/init.lua index 17b676f504..3f50263e02 100644 --- a/games/minimal/mods/experimental/init.lua +++ b/games/minimal/mods/experimental/init.lua @@ -443,7 +443,7 @@ minetest.register_abm({ })--]] minetest.register_node("experimental:tester_node_1", { - description = "Tester Node 1", + description = "Tester Node 1 (construct/destruct/timer)", tile_images = {"wieldhand.png"}, groups = {oddly_breakable_by_hand=2}, sounds = default.node_sound_wood_defaults(), @@ -455,6 +455,8 @@ minetest.register_node("experimental:tester_node_1", { experimental.print_to_everything("experimental:tester_node_1:on_construct("..minetest.pos_to_string(pos)..")") local meta = minetest.env:get_meta(pos) meta:set_string("mine", "test") + local timer = minetest.env:get_node_timer(pos) + timer:start(4, 3) end, after_place_node = function(pos, placer) @@ -478,6 +480,11 @@ minetest.register_node("experimental:tester_node_1", { after_dig_node = function(pos, oldnode, oldmetadata, digger) experimental.print_to_everything("experimental:tester_node_1:after_dig_node("..minetest.pos_to_string(pos)..")") end, + + on_timer = function(pos, elapsed) + experimental.print_to_everything("on_timer(): elapsed="..dump(elapsed)) + return true + end, }) minetest.register_craftitem("experimental:tester_tool_1", { From 5c31445117ea88061dc4ee60e0dec4d11c8c3ed7 Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Tue, 24 Jul 2012 14:56:32 +0300 Subject: [PATCH 05/17] Improve node timer format (map format version 25) and update mapformat.txt --- doc/mapformat.txt | 64 +++++++++++++++++++++++++++++++++------------ src/mapblock.cpp | 23 ++++++++++++---- src/nodetimer.cpp | 43 ++++++++++++++++++------------ src/nodetimer.h | 4 +-- src/serialization.h | 5 ++-- 5 files changed, 98 insertions(+), 41 deletions(-) diff --git a/doc/mapformat.txt b/doc/mapformat.txt index ef16118c54..89863ea043 100644 --- a/doc/mapformat.txt +++ b/doc/mapformat.txt @@ -1,11 +1,12 @@ ============================= -Minetest World Format 22...23 +Minetest World Format 22...25 ============================= This applies to a world format carrying the block serialization version -22...23, used at least in -- 0.4.dev-20120322 ... 0.4.dev-20120606 -- 0.4.0. +22...25, used at least in +- 0.4.dev-20120322 ... 0.4.dev-20120606 (22...23) +- 0.4.0 (23) +- 24 was never released as stable and existed for ~2 days The block serialization version does not fully specify every aspect of this format; if compliance with this format is to be checked, it needs to be @@ -262,17 +263,26 @@ u8 flags u8 content_width - Number of bytes in the content (param0) fields of nodes -- Always 1 +if map format version <= 23: + - Always 1 +if map format version >= 24: + - Always 2 u8 params_width - Number of bytes used for parameters per node - Always 2 zlib-compressed node data: -- content: - u8[4096]: param0 fields - u8[4096]: param1 fields - u8[4096]: param2 fields +if content_width == 1: + - content: + u8[4096]: param0 fields + u8[4096]: param1 fields + u8[4096]: param2 fields +if content_width == 2: + - content: + u16[4096]: param0 fields + u8[4096]: param1 fields + u8[4096]: param2 fields - The location of a node in each of those arrays is (z*16*16 + y*16 + x). zlib-compressed node metadata list @@ -285,9 +295,19 @@ zlib-compressed node metadata list u16 content_size u8[content_size] (content of metadata) -- unused node timers (version will be 24 when they are actually used): -if version == 23: +- Node timers +if map format version == 23: u8 unused version (always 0) +if map format version == 24: (NOTE: Not released as stable) + u8 nodetimer_version + if nodetimer_version == 0: + (nothing else) + if nodetimer_version == 1: + u16 num_of_timers + foreach num_of_timers: + u16 timer position (z*16*16 + y*16 + x) + s32 timeout*1000 + s32 elapsed*1000 u8 static object version: - Always 0 @@ -317,17 +337,29 @@ foreach num_name_id_mappings u16 name_len u8[name_len] name +- Node timers +if map format version == 25: + u8 length of the data of a single timer (always 2+4+4=10) + u16 num_of_timers + foreach num_of_timers: + u16 timer position (z*16*16 + y*16 + x) + s32 timeout*1000 + s32 elapsed*1000 + EOF. Format of nodes ---------------- A node is composed of the u8 fields param0, param1 and param2. -The content id of a node is determined as so: -- If param0 < 0x80, - content_id = param0 -- Otherwise - content_id = (param0<<4) + (param2>>4) +if map format version <= 23: + The content id of a node is determined as so: + - If param0 < 0x80, + content_id = param0 + - Otherwise + content_id = (param0<<4) + (param2>>4) +if map format version >= 24: + The content id of a node is param0. The purpose of param1 and param2 depend on the definition of the node. diff --git a/src/mapblock.cpp b/src/mapblock.cpp index c7c820d42e..b2da768f54 100644 --- a/src/mapblock.cpp +++ b/src/mapblock.cpp @@ -612,8 +612,10 @@ void MapBlock::serialize(std::ostream &os, u8 version, bool disk) */ if(disk) { - // Node timers - m_node_timers.serialize(os); + if(version <= 24){ + // Node timers + m_node_timers.serialize(os, version); + } // Static objects m_static_objects.serialize(os); @@ -623,6 +625,11 @@ void MapBlock::serialize(std::ostream &os, u8 version, bool disk) // Write block-specific node definition id mapping nimap.serialize(os); + + if(version >= 25){ + // Node timers + m_node_timers.serialize(os, version); + } } } @@ -696,10 +703,10 @@ void MapBlock::deSerialize(std::istream &is, u8 version, bool disk) // Read unused zero readU8(is); } - else if(version >= 24){ + if(version == 24){ TRACESTREAM(<<"MapBlock::deSerialize "<= 25){ + TRACESTREAM(<<"MapBlock::deSerialize "<=25)"<= 25){ + writeU8(os, 2+4+4); + writeU16(os, m_data.size()); + } for(std::map::const_iterator i = m_data.begin(); @@ -68,15 +71,23 @@ void NodeTimerList::serialize(std::ostream &os) const } } -void NodeTimerList::deSerialize(std::istream &is) +void NodeTimerList::deSerialize(std::istream &is, u8 map_format_version) { m_data.clear(); + + if(map_format_version == 24){ + u8 timer_version = readU8(is); + if(timer_version == 0) + return; + if(timer_version != 1) + throw SerializationError("unsupported NodeTimerList version"); + } - u8 version = readU8(is); - if(version == 0) - return; - if(version != 1) - throw SerializationError("unsupported NodeTimerList version"); + if(map_format_version >= 25){ + u8 timer_data_len = readU8(is); + if(timer_data_len != 2+4+4) + throw SerializationError("unsupported NodeTimer data length"); + } u16 count = readU16(is); diff --git a/src/nodetimer.h b/src/nodetimer.h index f8d3e1c579..c643ab888a 100644 --- a/src/nodetimer.h +++ b/src/nodetimer.h @@ -57,8 +57,8 @@ public: NodeTimerList() {} ~NodeTimerList() {} - void serialize(std::ostream &os) const; - void deSerialize(std::istream &is); + void serialize(std::ostream &os, u8 map_format_version) const; + void deSerialize(std::istream &is, u8 map_format_version); // Get timer NodeTimer get(v3s16 p){ diff --git a/src/serialization.h b/src/serialization.h index 0d74ccf48f..533ddc8c44 100644 --- a/src/serialization.h +++ b/src/serialization.h @@ -59,12 +59,13 @@ with this program; if not, write to the Free Software Foundation, Inc., 21: dynamic content type allocation 22: minerals removed, facedir & wallmounted changed 23: new node metadata format - 24: 16-bit node ids and node timers + 24: 16-bit node ids and node timers (never released as stable) + 25: Improved node timer format */ // This represents an uninitialized or invalid format #define SER_FMT_VER_INVALID 255 // Highest supported serialization version -#define SER_FMT_VER_HIGHEST 24 +#define SER_FMT_VER_HIGHEST 25 // Lowest supported serialization version #define SER_FMT_VER_LOWEST 0 From 558e284e25b5be14b700951269b027ac82a7b3ca Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Tue, 24 Jul 2012 15:16:49 +0300 Subject: [PATCH 06/17] Update minetestmapper.py to support ver. 24 and 25 --- util/minetestmapper.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/util/minetestmapper.py b/util/minetestmapper.py index 83ce716e97..9d364e1e64 100755 --- a/util/minetestmapper.py +++ b/util/minetestmapper.py @@ -324,7 +324,9 @@ def content_is_air(d): return d in [126, 127, 254, "air"] def read_content(mapdata, version, datapos): - if version >= 20: + if version >= 24: + return (mapdata[datapos*2] << 8) | (mapdata[datapos*2 + 1]) + elif version >= 20: if mapdata[datapos] < 0x80: return mapdata[datapos] else: @@ -387,6 +389,7 @@ def read_mapdata(mapdata, version, pixellist, water, day_night_differs, id_to_na #print("unknown node: %s/%s/%s x: %d y: %d z: %d block id: %x" # % (xhex, zhex, yhex, x, y, z, content)) + # Go through all sectors. for n in range(len(xlist)): #if n > 500: @@ -546,6 +549,14 @@ for n in range(len(xlist)): if version == 23: readU8(f) # Unused node timer version (always 0) + if version == 24: + ver = readU8(f) + if ver == 1: + num = readU16(f) + for i in range(0,num): + readU16(f) + readS32(f) + readS32(f) static_object_version = readU8(f) static_object_count = readU16(f) @@ -578,6 +589,15 @@ for n in range(len(xlist)): #print(str(node_id)+" = "+name) id_to_name[node_id] = name + # Node timers + if version >= 25: + timer_size = readU8(f) + num = readU16(f) + for i in range(0,num): + readU16(f) + readS32(f) + readS32(f) + read_mapdata(mapdata, version, pixellist, water, day_night_differs, id_to_name) # After finding all the pixels in the sector, we can move on to From 0cf1ed544c91a01b9c2098cd3e11a49c8f0c1ddb Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Tue, 24 Jul 2012 16:34:20 +0300 Subject: [PATCH 07/17] darkrose should work at a nuclear power plant. It'd take years to figure out what caused the accident. --- src/mapnode.cpp | 4 +++- src/server.cpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/mapnode.cpp b/src/mapnode.cpp index c616e01175..5dab93754a 100644 --- a/src/mapnode.cpp +++ b/src/mapnode.cpp @@ -234,8 +234,10 @@ u32 MapNode::serializedLength(u8 version) return 1; else if(version <= 9) return 2; - else + else if(version <= 23) return 3; + else + return 4; } void MapNode::serialize(u8 *dest, u8 version) { diff --git a/src/server.cpp b/src/server.cpp index 0e49864113..b3cbea6a44 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -4016,7 +4016,7 @@ void Server::SendBlocks(float dtime) RemoteClient *client = getClient(q.peer_id); - SendBlockNoLock(q.peer_id, block, 24);//client->serialization_version); + SendBlockNoLock(q.peer_id, block, client->serialization_version); client->SentBlock(q.pos); From 96eac87d47e4d9e815dff5c9f830326e515d4ea2 Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Tue, 24 Jul 2012 17:46:17 +0300 Subject: [PATCH 08/17] builtin/item.lua: callbacks with copies of positions and nodes rather than recycle the same ones, which callbacks can modify --- builtin/item.lua | 170 +++++++++++++++++++++++++---------------------- 1 file changed, 92 insertions(+), 78 deletions(-) diff --git a/builtin/item.lua b/builtin/item.lua index e19fd559a2..bd34efe798 100644 --- a/builtin/item.lua +++ b/builtin/item.lua @@ -124,76 +124,84 @@ end function minetest.item_place_node(itemstack, placer, pointed_thing) local item = itemstack:peek_item() local def = itemstack:get_definition() - if def.type == "node" and pointed_thing.type == "node" then - local under = pointed_thing.under - local oldnode_under = minetest.env:get_node(under) - local olddef_under = ItemStack({name=oldnode_under.name}):get_definition() - olddef_under = olddef_under or minetest.nodedef_default - local above = pointed_thing.above - local oldnode_above = minetest.env:get_node(above) - local olddef_above = ItemStack({name=oldnode_above.name}):get_definition() - olddef_above = olddef_above or minetest.nodedef_default - - if not olddef_above.buildable_to and not olddef_under.buildable_to then - minetest.log("info", placer:get_player_name() .. " tried to place" - .. " node in invalid position " .. minetest.pos_to_string(above) - .. ", replacing " .. oldnode_above.name) - return - end - - -- Place above pointed node - local place_to = {x = above.x, y = above.y, z = above.z} - - -- If node under is buildable_to, place into it instead (eg. snow) - if olddef_under.buildable_to then - minetest.log("info", "node under is buildable to") - place_to = {x = under.x, y = under.y, z = under.z} - end - - minetest.log("action", placer:get_player_name() .. " places node " - .. def.name .. " at " .. minetest.pos_to_string(place_to)) - - local oldnode = minetest.env:get_node(place_to) - local newnode = {name = def.name, param1 = 0, param2 = 0} - - -- Calculate direction for wall mounted stuff like torches and signs - if def.paramtype2 == 'wallmounted' then - local dir = { - x = under.x - above.x, - y = under.y - above.y, - z = under.z - above.z - } - newnode.param2 = minetest.dir_to_wallmounted(dir) - -- Calculate the direction for furnaces and chests and stuff - elseif def.paramtype2 == 'facedir' then - local placer_pos = placer:getpos() - if placer_pos then - local dir = { - x = above.x - placer_pos.x, - y = above.y - placer_pos.y, - z = above.z - placer_pos.z - } - newnode.param2 = minetest.dir_to_facedir(dir) - minetest.log("action", "facedir: " .. newnode.param2) - end - end - - -- Add node and update - minetest.env:add_node(place_to, newnode) - - -- Run callback - if def.after_place_node then - def.after_place_node(place_to, placer) - end - - -- Run script hook (deprecated) - local _, callback - for _, callback in ipairs(minetest.registered_on_placenodes) do - callback(place_to, newnode, placer, oldnode) - end - - itemstack:take_item() + if def.type ~= "node" or pointed_thing.type ~= "node" then + return itemstack end + + local under = pointed_thing.under + local oldnode_under = minetest.env:get_node(under) + local olddef_under = ItemStack({name=oldnode_under.name}):get_definition() + olddef_under = olddef_under or minetest.nodedef_default + local above = pointed_thing.above + local oldnode_above = minetest.env:get_node(above) + local olddef_above = ItemStack({name=oldnode_above.name}):get_definition() + olddef_above = olddef_above or minetest.nodedef_default + + if not olddef_above.buildable_to and not olddef_under.buildable_to then + minetest.log("info", placer:get_player_name() .. " tried to place" + .. " node in invalid position " .. minetest.pos_to_string(above) + .. ", replacing " .. oldnode_above.name) + return + end + + -- Place above pointed node + local place_to = {x = above.x, y = above.y, z = above.z} + + -- If node under is buildable_to, place into it instead (eg. snow) + if olddef_under.buildable_to then + minetest.log("info", "node under is buildable to") + place_to = {x = under.x, y = under.y, z = under.z} + end + + minetest.log("action", placer:get_player_name() .. " places node " + .. def.name .. " at " .. minetest.pos_to_string(place_to)) + + local oldnode = minetest.env:get_node(place_to) + local newnode = {name = def.name, param1 = 0, param2 = 0} + + -- Calculate direction for wall mounted stuff like torches and signs + if def.paramtype2 == 'wallmounted' then + local dir = { + x = under.x - above.x, + y = under.y - above.y, + z = under.z - above.z + } + newnode.param2 = minetest.dir_to_wallmounted(dir) + -- Calculate the direction for furnaces and chests and stuff + elseif def.paramtype2 == 'facedir' then + local placer_pos = placer:getpos() + if placer_pos then + local dir = { + x = above.x - placer_pos.x, + y = above.y - placer_pos.y, + z = above.z - placer_pos.z + } + newnode.param2 = minetest.dir_to_facedir(dir) + minetest.log("action", "facedir: " .. newnode.param2) + end + end + + -- Add node and update + minetest.env:add_node(place_to, newnode) + + -- Run callback + if def.after_place_node then + -- Copy place_to because callback can modify it + local place_to_copy = {x=place_to.x, y=place_to.y, z=place_to.z} + def.after_place_node(place_to_copy, placer) + end + + -- Run script hook + local _, callback + for _, callback in ipairs(minetest.registered_on_placenodes) do + -- Copy pos and node because callback can modify them + local place_to_copy = {x=place_to.x, y=place_to.y, z=place_to.z} + local newnode_copy = {name=newnode.name, param1=newnode.param1, param2=newnode.param2} + local oldnode_copy = {name=oldnode.name, param1=oldnode.param1, param2=oldnode.param2} + callback(place_to_copy, newnode_copy, placer, oldnode_copy) + end + + itemstack:take_item() return itemstack end @@ -243,9 +251,11 @@ function minetest.node_punch(pos, node, puncher) -- Run script hook local _, callback for _, callback in ipairs(minetest.registered_on_punchnodes) do - callback(pos, node, puncher) + -- Copy pos and node because callback can modify them + local pos_copy = {x=pos.x, y=pos.y, z=pos.z} + local node_copy = {name=node.name, param1=node.param1, param2=node.param2} + callback(pos_copy, node_copy, puncher) end - end function minetest.node_dig(pos, node, digger) @@ -268,8 +278,8 @@ function minetest.node_dig(pos, node, digger) local drops = minetest.get_node_drops(node.name, wielded:get_name()) -- Wear out tool - tp = wielded:get_tool_capabilities() - dp = minetest.get_dig_params(def.groups, tp) + local tp = wielded:get_tool_capabilities() + local dp = minetest.get_dig_params(def.groups, tp) wielded:add_wear(dp.wear) digger:set_wielded_item(wielded) @@ -282,10 +292,8 @@ function minetest.node_dig(pos, node, digger) end end - local oldnode = nil local oldmetadata = nil if def.after_dig_node then - oldnode = node; oldmetadata = minetest.env:get_meta(pos):to_table() end @@ -294,13 +302,19 @@ function minetest.node_dig(pos, node, digger) -- Run callback if def.after_dig_node then - def.after_dig_node(pos, oldnode, oldmetadata, digger) + -- Copy pos and node because callback can modify them + local pos_copy = {x=pos.x, y=pos.y, z=pos.z} + local node_copy = {name=node.name, param1=node.param1, param2=node.param2} + def.after_dig_node(pos_copy, node_copy, oldmetadata, digger) end - -- Run script hook (deprecated) + -- Run script hook local _, callback for _, callback in ipairs(minetest.registered_on_dignodes) do - callback(pos, node, digger) + -- Copy pos and node because callback can modify them + local pos_copy = {x=pos.x, y=pos.y, z=pos.z} + local node_copy = {name=node.name, param1=node.param1, param2=node.param2} + callback(pos_copy, node_copy, digger) end end From 2ac20982e0772b94b21d95b53519bd2164632d98 Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Tue, 24 Jul 2012 20:57:17 +0300 Subject: [PATCH 09/17] Detached inventories --- doc/lua_api.txt | 6 + games/minimal/mods/experimental/init.lua | 7 ++ src/client.cpp | 34 ++++++ src/client.h | 4 + src/clientserver.h | 9 ++ src/guiFormSpecMenu.cpp | 17 ++- src/guiFormSpecMenu.h | 6 +- src/inventorymanager.cpp | 40 +++---- src/inventorymanager.h | 16 ++- src/scriptapi.cpp | 18 +++ src/server.cpp | 137 ++++++++++++++--------- src/server.h | 13 +++ 12 files changed, 222 insertions(+), 85 deletions(-) diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 176745a2d7..c9fafd65fb 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -677,6 +677,7 @@ size[,] ^ deprecated: invsize[,;] list[;;,;,;] +list[;;,;,;] ^ Show an inventory list image[,;,;] @@ -726,10 +727,12 @@ image_button_exit[,;,;;;