},
node = {},
+ meta = {},
- set_node = function(self, node)
+ set_node = function(self, node, meta)
self.node = node
+ self.meta = meta or {}
self.object:set_properties({
is_visible = true,
textures = {node.name},
end,
get_staticdata = function(self)
- return core.serialize(self.node)
+ local ds = {
+ node = self.node,
+ meta = self.meta,
+ }
+ return core.serialize(ds)
end,
on_activate = function(self, staticdata)
self.object:set_armor_groups({immortal = 1})
-
- local node = core.deserialize(staticdata)
- if node then
- self:set_node(node)
+
+ local ds = core.deserialize(staticdata)
+ if ds and ds.node then
+ self:set_node(ds.node, ds.meta)
+ elseif ds then
+ self:set_node(ds)
elseif staticdata ~= "" then
self:set_node({name = staticdata})
end
on_step = function(self, dtime)
-- Set gravity
- local acceleration = self.object:getacceleration()
+ local acceleration = self.object:get_acceleration()
if not vector.equals(acceleration, {x = 0, y = -10, z = 0}) then
- self.object:setacceleration({x = 0, y = -10, z = 0})
+ self.object:set_acceleration({x = 0, y = -10, z = 0})
end
-- Turn to actual node when colliding with ground, or continue to move
- local pos = self.object:getpos()
+ local pos = self.object:get_pos()
-- Position of bottom center point
local bcp = {x = pos.x, y = pos.y - 0.7, z = pos.z}
- -- Avoid bugs caused by an unloaded node below
+ -- 'bcn' is nil for unloaded nodes
local bcn = core.get_node_or_nil(bcp)
+ -- Delete on contact with ignore at world edges
+ if bcn and bcn.name == "ignore" then
+ self.object:remove()
+ return
+ end
local bcd = bcn and core.registered_nodes[bcn.name]
if bcn and
(not bcd or bcd.walkable or
core.remove_node(np)
if nd and nd.buildable_to == false then
-- Add dropped items
- local drops = core.get_node_drops(n2.name, "")
+ local drops = core.get_node_drops(n2, "")
for _, dropped_item in pairs(drops) do
core.add_item(np, dropped_item)
end
end
end
-- Create node and remove entity
- if core.registered_nodes[self.node.name] then
+ local def = core.registered_nodes[self.node.name]
+ if def then
core.add_node(np, self.node)
+ if self.meta then
+ local meta = core.get_meta(np)
+ meta:from_table(self.meta)
+ end
+ if def.sounds and def.sounds.place then
+ core.sound_play(def.sounds.place, {pos = np})
+ end
end
self.object:remove()
core.check_for_falling(np)
return
end
- local vel = self.object:getvelocity()
+ local vel = self.object:get_velocity()
if vector.equals(vel, {x = 0, y = 0, z = 0}) then
- local npos = self.object:getpos()
- self.object:setpos(vector.round(npos))
+ local npos = self.object:get_pos()
+ self.object:set_pos(vector.round(npos))
end
end
})
-local function spawn_falling_node(p, node)
- local obj = core.add_entity(p, "__builtin:falling_node")
- if obj then
- obj:get_luaentity():set_node(node)
+local function convert_to_falling_node(pos, node)
+ local obj = core.add_entity(pos, "__builtin:falling_node")
+ if not obj then
+ return false
+ end
+ node.level = core.get_node_level(pos)
+ local meta = core.get_meta(pos)
+ local metatable = meta and meta:to_table() or {}
+
+ local def = core.registered_nodes[node.name]
+ if def and def.sounds and def.sounds.fall then
+ core.sound_play(def.sounds.fall, {pos = pos})
+ end
+
+ obj:get_luaentity():set_node(node, metatable)
+ core.remove_node(pos)
+ return true
+end
+
+function core.spawn_falling_node(pos)
+ local node = core.get_node(pos)
+ if node.name == "air" or node.name == "ignore" then
+ return false
end
+ return convert_to_falling_node(pos, node)
end
local function drop_attached_node(p)
- local nn = core.get_node(p).name
+ local n = core.get_node(p)
+ local drops = core.get_node_drops(n, "")
+ local def = core.registered_items[n.name]
+ if def and def.preserve_metadata then
+ local oldmeta = core.get_meta(p):to_table().fields
+ -- Copy pos and node because the callback can modify them.
+ local pos_copy = {x=p.x, y=p.y, z=p.z}
+ local node_copy = {name=n.name, param1=n.param1, param2=n.param2}
+ local drop_stacks = {}
+ for k, v in pairs(drops) do
+ drop_stacks[k] = ItemStack(v)
+ end
+ drops = drop_stacks
+ def.preserve_metadata(pos_copy, node_copy, oldmeta, drops)
+ end
+ if def and def.sounds and def.sounds.fall then
+ core.sound_play(def.sounds.fall, {pos = p})
+ end
core.remove_node(p)
- for _, item in pairs(core.get_node_drops(nn, "")) do
+ for _, item in pairs(drops) do
local pos = {
x = p.x + math.random()/2 - 0.25,
y = p.y + math.random()/2 - 0.25,
function builtin_shared.check_attached_node(p, n)
local def = core.registered_nodes[n.name]
local d = {x = 0, y = 0, z = 0}
- if def.paramtype2 == "wallmounted" then
+ if def.paramtype2 == "wallmounted" or
+ def.paramtype2 == "colorwallmounted" then
-- The fallback vector here is in case 'wallmounted to dir' is nil due
-- to voxelmanip placing a wallmounted node without resetting a
-- pre-existing param2 value that is out-of-range for wallmounted.
core.get_node_max_level(p_bottom))) and
(not d_bottom.walkable or d_bottom.buildable_to) then
- n.level = core.get_node_level(p)
- core.remove_node(p)
- spawn_falling_node(p, n)
+ convert_to_falling_node(p, n)
return true
end
end
core.check_for_falling(p)
end
core.register_on_punchnode(on_punchnode)
-
---
--- Globally exported functions
---
-
--- TODO remove this function after the 0.4.15 release
-function nodeupdate(p)
- core.log("deprecated", "nodeupdate: deprecated, please use core.check_for_falling instead")
- core.check_for_falling(p)
-end
-
--- TODO remove this function after the 0.4.15 release
-function nodeupdate_single(p)
- core.log("deprecated", "nodeupdate_single: deprecated, please use core.check_single_for_falling instead")
- core.check_single_for_falling(p)
-end