Add rotation support for wallmounted nodes in 'ceiling' or 'floor' mode (#11073)
@ -144,6 +144,8 @@ local wallmounted_to_dir = {
|
||||
vector.new(-1, 0, 0),
|
||||
vector.new( 0, 0, 1),
|
||||
vector.new( 0, 0, -1),
|
||||
vector.new( 0, 1, 0),
|
||||
vector.new( 0, -1, 0),
|
||||
}
|
||||
function core.wallmounted_to_dir(wallmounted)
|
||||
return wallmounted_to_dir[wallmounted % 8]
|
||||
|
@ -150,7 +150,12 @@ core.register_entity(":__builtin:falling_node", {
|
||||
|
||||
-- Rotate entity
|
||||
if def.drawtype == "torchlike" then
|
||||
self.object:set_yaw(math.pi*0.25)
|
||||
if (def.paramtype2 == "wallmounted" or def.paramtype2 == "colorwallmounted")
|
||||
and node.param2 % 8 == 7 then
|
||||
self.object:set_yaw(-math.pi*0.25)
|
||||
else
|
||||
self.object:set_yaw(math.pi*0.25)
|
||||
end
|
||||
elseif ((node.param2 ~= 0 or def.drawtype == "nodebox" or def.drawtype == "mesh")
|
||||
and (def.wield_image == "" or def.wield_image == nil))
|
||||
or def.drawtype == "signlike"
|
||||
@ -190,6 +195,10 @@ core.register_entity(":__builtin:falling_node", {
|
||||
pitch, yaw = 0, -math.pi/2
|
||||
elseif rot == 4 then
|
||||
pitch, yaw = 0, math.pi
|
||||
elseif rot == 6 then
|
||||
pitch, yaw = math.pi/2, 0
|
||||
elseif rot == 7 then
|
||||
pitch, yaw = -math.pi/2, math.pi
|
||||
end
|
||||
else
|
||||
if rot == 1 then
|
||||
@ -202,6 +211,10 @@ core.register_entity(":__builtin:falling_node", {
|
||||
pitch, yaw = math.pi/2, math.pi
|
||||
elseif rot == 5 then
|
||||
pitch, yaw = math.pi/2, 0
|
||||
elseif rot == 6 then
|
||||
pitch, yaw = math.pi, -math.pi/2
|
||||
elseif rot == 7 then
|
||||
pitch, yaw = 0, -math.pi/2
|
||||
end
|
||||
end
|
||||
if def.drawtype == "signlike" then
|
||||
@ -210,10 +223,20 @@ core.register_entity(":__builtin:falling_node", {
|
||||
yaw = yaw + math.pi/2
|
||||
elseif rot == 1 then
|
||||
yaw = yaw - math.pi/2
|
||||
elseif rot == 6 then
|
||||
yaw = yaw - math.pi/2
|
||||
pitch = pitch + math.pi
|
||||
elseif rot == 7 then
|
||||
yaw = yaw + math.pi/2
|
||||
pitch = pitch + math.pi
|
||||
end
|
||||
elseif def.drawtype == "mesh" or def.drawtype == "normal" or def.drawtype == "nodebox" then
|
||||
if rot >= 0 and rot <= 1 then
|
||||
if rot == 0 or rot == 1 then
|
||||
roll = roll + math.pi
|
||||
elseif rot == 6 or rot == 7 then
|
||||
if def.drawtype ~= "normal" then
|
||||
roll = roll - math.pi/2
|
||||
end
|
||||
else
|
||||
yaw = yaw + math.pi
|
||||
end
|
||||
|
@ -32,6 +32,7 @@ core.features = {
|
||||
hud_def_type_field = true,
|
||||
random_state_restore = true,
|
||||
after_order_expiry_registration = true,
|
||||
wallmounted_rotate = true,
|
||||
}
|
||||
|
||||
function core.has_feature(arg)
|
||||
|
@ -202,7 +202,40 @@ function core.item_place_node(itemstack, placer, pointed_thing, param2,
|
||||
elseif (def.paramtype2 == "wallmounted" or
|
||||
def.paramtype2 == "colorwallmounted") and not param2 then
|
||||
local dir = vector.subtract(under, above)
|
||||
-- If you change this code, also change src/client/game.cpp
|
||||
newnode.param2 = core.dir_to_wallmounted(dir)
|
||||
if def.wallmounted_rotate_vertical and
|
||||
(newnode.param2 == 0 or newnode.param2 == 1) then
|
||||
local placer_pos = placer and placer:get_pos()
|
||||
if placer_pos then
|
||||
local pdir = {
|
||||
x = above.x - placer_pos.x,
|
||||
y = dir.y,
|
||||
z = above.z - placer_pos.z
|
||||
}
|
||||
local rotate = false
|
||||
if def.drawtype == "torchlike" then
|
||||
if not ((pdir.x < 0 and pdir.z > 0) or
|
||||
(pdir.x > 0 and pdir.z < 0)) then
|
||||
rotate = true
|
||||
end
|
||||
if pdir.y > 0 then
|
||||
rotate = not rotate
|
||||
end
|
||||
elseif def.drawtype == "signlike" then
|
||||
if math.abs(pdir.x) < math.abs(pdir.z) then
|
||||
rotate = true
|
||||
end
|
||||
else
|
||||
if math.abs(pdir.x) > math.abs(pdir.z) then
|
||||
rotate = true
|
||||
end
|
||||
end
|
||||
if rotate then
|
||||
newnode.param2 = newnode.param2 + 6
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Calculate the direction for furnaces and chests and stuff
|
||||
elseif (def.paramtype2 == "facedir" or
|
||||
def.paramtype2 == "colorfacedir" or
|
||||
|
@ -1270,11 +1270,15 @@ The function of `param2` is determined by `paramtype2` in node definition.
|
||||
* The rotation of the node is stored in `param2`
|
||||
* Node is 'mounted'/facing towards one of 6 directions
|
||||
* You can make this value by using `minetest.dir_to_wallmounted()`
|
||||
* Values range 0 - 5
|
||||
* Values range 0 - 7
|
||||
* The value denotes at which direction the node is "mounted":
|
||||
0 = y+, 1 = y-, 2 = x+, 3 = x-, 4 = z+, 5 = z-
|
||||
6 = y+, but rotated by 90°
|
||||
7 = y-, but rotated by -90°
|
||||
* By default, on placement the param2 is automatically set to the
|
||||
appropriate rotation, depending on which side was pointed at
|
||||
appropriate rotation (0 to 5), depending on which side was
|
||||
pointed at. With the node field `wallmounted_rotate_vertical = true`,
|
||||
the param2 values 6 and 7 might additionally be set
|
||||
* `paramtype2 = "facedir"`
|
||||
* Supported drawtypes: "normal", "nodebox", "mesh"
|
||||
* The rotation of the node is stored in `param2`.
|
||||
@ -5291,6 +5295,9 @@ Utilities
|
||||
-- minetest.after guarantees that coexisting jobs are executed primarily
|
||||
-- in order of expiry and secondarily in order of registration (5.9.0)
|
||||
after_order_expiry_registration = true,
|
||||
-- wallmounted nodes mounted at floor or ceiling may additionally
|
||||
-- be rotated by 90° with special param2 values (5.9.0)
|
||||
wallmounted_rotate = true,
|
||||
}
|
||||
```
|
||||
|
||||
@ -8926,6 +8933,13 @@ Used by `minetest.register_node`.
|
||||
place_param2 = 0,
|
||||
-- Value for param2 that is set when player places node
|
||||
|
||||
wallmounted_rotate_vertical = false,
|
||||
-- If true, place_param2 is nil, and this is a wallmounted node,
|
||||
-- this node might use the special 90° rotation when placed
|
||||
-- on the floor or ceiling, depending on the direction.
|
||||
-- See the explanation about wallmounted for details.
|
||||
-- Otherwise, the rotation is always the same on vertical placement.
|
||||
|
||||
is_ground_content = true,
|
||||
-- If false, the cave generator and dungeon generator will not carve
|
||||
-- through this node.
|
||||
|
@ -163,7 +163,7 @@ minetest.register_node("testnodes:torchlike", {
|
||||
|
||||
minetest.register_node("testnodes:torchlike_wallmounted", {
|
||||
description = S("Wallmounted \"torchlike\" Drawtype Test Node").."\n"..
|
||||
S("param2 = wallmounted rotation (0..5)"),
|
||||
S("param2 = wallmounted rotation (0..7)"),
|
||||
drawtype = "torchlike",
|
||||
paramtype = "light",
|
||||
paramtype2 = "wallmounted",
|
||||
@ -179,6 +179,24 @@ minetest.register_node("testnodes:torchlike_wallmounted", {
|
||||
groups = { dig_immediate = 3 },
|
||||
})
|
||||
|
||||
minetest.register_node("testnodes:torchlike_wallmounted_rot", {
|
||||
description = S("Wallmounted Rotatable Torchlike Drawtype Test Node"),
|
||||
drawtype = "torchlike",
|
||||
paramtype = "light",
|
||||
paramtype2 = "wallmounted",
|
||||
wallmounted_rotate_vertical = true,
|
||||
tiles = {
|
||||
"testnodes_torchlike_floor.png^[colorize:#FFFF00:40",
|
||||
"testnodes_torchlike_ceiling.png^[colorize:#FFFF00:40",
|
||||
"testnodes_torchlike_wall.png^[colorize:#FFFF00:40",
|
||||
},
|
||||
|
||||
|
||||
walkable = false,
|
||||
sunlight_propagates = true,
|
||||
groups = { dig_immediate = 3 },
|
||||
})
|
||||
|
||||
minetest.register_node("testnodes:signlike", {
|
||||
description = S("Floor \"signlike\" Drawtype Test Node").."\n"..
|
||||
S("Always on floor"),
|
||||
@ -186,16 +204,14 @@ minetest.register_node("testnodes:signlike", {
|
||||
paramtype = "light",
|
||||
tiles = { "testnodes_signlike.png^[colorize:#FF0000:64" },
|
||||
|
||||
|
||||
walkable = false,
|
||||
groups = { dig_immediate = 3 },
|
||||
sunlight_propagates = true,
|
||||
groups = { dig_immediate = 3 },
|
||||
})
|
||||
|
||||
|
||||
minetest.register_node("testnodes:signlike_wallmounted", {
|
||||
description = S("Wallmounted \"signlike\" Drawtype Test Node").."\n"..
|
||||
S("param2 = wallmounted rotation (0..5)"),
|
||||
S("param2 = wallmounted rotation (0..7)"),
|
||||
drawtype = "signlike",
|
||||
paramtype = "light",
|
||||
paramtype2 = "wallmounted",
|
||||
@ -207,6 +223,22 @@ minetest.register_node("testnodes:signlike_wallmounted", {
|
||||
sunlight_propagates = true,
|
||||
})
|
||||
|
||||
minetest.register_node("testnodes:signlike_rot", {
|
||||
description = S("Wallmounted Rotatable Signlike Drawtype Test Node"),
|
||||
drawtype = "signlike",
|
||||
paramtype = "light",
|
||||
paramtype2 = "wallmounted",
|
||||
wallmounted_rotate_vertical = true,
|
||||
tiles = { "testnodes_signlike.png^[colorize:#FFFF00:40" },
|
||||
|
||||
|
||||
walkable = false,
|
||||
groups = { dig_immediate = 3 },
|
||||
sunlight_propagates = true,
|
||||
})
|
||||
|
||||
|
||||
|
||||
minetest.register_node("testnodes:plantlike", {
|
||||
description = S("\"plantlike\" Drawtype Test Node"),
|
||||
drawtype = "plantlike",
|
||||
@ -235,7 +267,7 @@ minetest.register_node("testnodes:plantlike_waving", {
|
||||
|
||||
minetest.register_node("testnodes:plantlike_wallmounted", {
|
||||
description = S("Wallmounted \"plantlike\" Drawtype Test Node").."\n"..
|
||||
S("param2 = wallmounted rotation (0..5)"),
|
||||
S("param2 = wallmounted rotation (0..7)"),
|
||||
drawtype = "plantlike",
|
||||
paramtype = "light",
|
||||
paramtype2 = "wallmounted",
|
||||
@ -366,7 +398,7 @@ minetest.register_node("testnodes:plantlike_rooted", {
|
||||
|
||||
minetest.register_node("testnodes:plantlike_rooted_wallmounted", {
|
||||
description = S("Wallmounted \"rooted_plantlike\" Drawtype Test Node").."\n"..
|
||||
S("param2 = wallmounted rotation (0..5)"),
|
||||
S("param2 = wallmounted rotation (0..7)"),
|
||||
drawtype = "plantlike_rooted",
|
||||
paramtype = "light",
|
||||
paramtype2 = "wallmounted",
|
||||
|
@ -92,7 +92,7 @@ minetest.register_node("testnodes:mesh_color4dir", {
|
||||
-- Wallmounted mesh: pyramid
|
||||
minetest.register_node("testnodes:mesh_wallmounted", {
|
||||
description = S("Wallmounted Mesh Test Node").."\n"..
|
||||
S("param2 = wallmounted rotation (0..5)"),
|
||||
S("param2 = wallmounted rotation (0..7)"),
|
||||
drawtype = "mesh",
|
||||
mesh = "testnodes_pyramid.obj",
|
||||
tiles = {"testnodes_mesh_stripes9.png"},
|
||||
@ -105,7 +105,7 @@ minetest.register_node("testnodes:mesh_wallmounted", {
|
||||
|
||||
minetest.register_node("testnodes:mesh_colorwallmounted", {
|
||||
description = S("Color Wallmounted Mesh Test Node").."\n"..
|
||||
S("param2 = color + wallmounted rotation (0..5, 8..13, ...)"),
|
||||
S("param2 = color + wallmounted rotation (0..7, 8..15, ...)"),
|
||||
drawtype = "mesh",
|
||||
mesh = "testnodes_pyramid.obj",
|
||||
tiles = {"testnodes_mesh_stripes10.png"},
|
||||
|
@ -180,3 +180,63 @@ minetest.register_node("testnodes:facedir_to_connect_to", {
|
||||
paramtype2 = "facedir",
|
||||
connect_sides = {"left", "top"},
|
||||
})
|
||||
|
||||
-- 3D sign and button:
|
||||
-- These are example nodes for more realistic example uses
|
||||
-- of wallmounted_rotate_vertical
|
||||
minetest.register_node("testnodes:sign3d", {
|
||||
description = S("Nodebox Sign, Nodebox Type \"fixed\""),
|
||||
drawtype = "nodebox",
|
||||
paramtype = "light",
|
||||
paramtype2 = "wallmounted",
|
||||
wallmounted_rotate_vertical = true,
|
||||
sunlight_propagates = true,
|
||||
walkable = false,
|
||||
tiles = {
|
||||
"testnodes_sign3d.png",
|
||||
},
|
||||
groups = { dig_immediate = 3 },
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {-0.4375, -0.5, -0.3125, 0.4375, -0.4375, 0.3125},
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_node("testnodes:sign3d_wallmounted", {
|
||||
description = S("Nodebox Sign, Nodebox Type \"wallmounted\""),
|
||||
drawtype = "nodebox",
|
||||
paramtype = "light",
|
||||
paramtype2 = "wallmounted",
|
||||
wallmounted_rotate_vertical = true,
|
||||
sunlight_propagates = true,
|
||||
walkable = false,
|
||||
tiles = {
|
||||
"testnodes_sign3d.png^[colorize:#ff0000:127",
|
||||
},
|
||||
groups = { dig_immediate = 3 },
|
||||
node_box = {
|
||||
type = "wallmounted",
|
||||
wall_top = {-0.4375, 0.4375, -0.3125, 0.4375, 0.5, 0.3125},
|
||||
wall_bottom = {-0.4375, -0.5, -0.3125, 0.4375, -0.4375, 0.3125},
|
||||
wall_side = {-0.5, -0.3125, -0.4375, -0.4375, 0.3125, 0.4375},
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_node("testnodes:button", {
|
||||
description = S("Button Nodebox Test Node"),
|
||||
drawtype = "nodebox",
|
||||
paramtype = "light",
|
||||
paramtype2 = "wallmounted",
|
||||
wallmounted_rotate_vertical = true,
|
||||
sunlight_propagates = true,
|
||||
walkable = false,
|
||||
tiles = {
|
||||
"testnodes_nodebox.png",
|
||||
},
|
||||
groups = { dig_immediate = 3 },
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = { -4/16, -8/16, -2/16, 4/16, -6/16, 2/16 },
|
||||
},
|
||||
})
|
||||
|
||||
|
@ -80,7 +80,7 @@ minetest.register_node("testnodes:4dir_nodebox", {
|
||||
|
||||
minetest.register_node("testnodes:wallmounted", {
|
||||
description = S("Wallmounted Test Node").."\n"..
|
||||
S("param2 = wallmounted rotation (0..5)"),
|
||||
S("param2 = wallmounted rotation (0..7)"),
|
||||
paramtype2 = "wallmounted",
|
||||
tiles = {
|
||||
"testnodes_1w.png",
|
||||
@ -94,9 +94,25 @@ minetest.register_node("testnodes:wallmounted", {
|
||||
groups = { dig_immediate = 3 },
|
||||
})
|
||||
|
||||
minetest.register_node("testnodes:wallmounted_rot", {
|
||||
description = S("Wallmounted Rotatable Test Node"),
|
||||
paramtype2 = "wallmounted",
|
||||
wallmounted_rotate_vertical = true,
|
||||
tiles = {
|
||||
"testnodes_1w.png^[colorize:#FFFF00:40",
|
||||
"testnodes_2w.png^[colorize:#FFFF00:40",
|
||||
"testnodes_3w.png^[colorize:#FFFF00:40",
|
||||
"testnodes_4w.png^[colorize:#FFFF00:40",
|
||||
"testnodes_5w.png^[colorize:#FFFF00:40",
|
||||
"testnodes_6w.png^[colorize:#FFFF00:40",
|
||||
},
|
||||
|
||||
groups = { dig_immediate = 3 },
|
||||
})
|
||||
|
||||
minetest.register_node("testnodes:wallmounted_nodebox", {
|
||||
description = S("Wallmounted Nodebox Test Node").."\n"..
|
||||
S("param2 = wallmounted rotation (0..5)"),
|
||||
S("param2 = wallmounted rotation (0..7)"),
|
||||
paramtype2 = "wallmounted",
|
||||
paramtype = "light",
|
||||
tiles = {
|
||||
@ -118,6 +134,30 @@ minetest.register_node("testnodes:wallmounted_nodebox", {
|
||||
groups = { dig_immediate = 3 },
|
||||
})
|
||||
|
||||
minetest.register_node("testnodes:wallmounted_nodebox_rot", {
|
||||
description = S("Wallmounted Rotatable Nodebox Test Node"),
|
||||
paramtype2 = "wallmounted",
|
||||
wallmounted_rotate_vertical = true,
|
||||
paramtype = "light",
|
||||
tiles = {
|
||||
"testnodes_1w.png^[colorize:#FFFF00:40",
|
||||
"testnodes_2w.png^[colorize:#FFFF00:40",
|
||||
"testnodes_3w.png^[colorize:#FFFF00:40",
|
||||
"testnodes_4w.png^[colorize:#FFFF00:40",
|
||||
"testnodes_5w.png^[colorize:#FFFF00:40",
|
||||
"testnodes_6w.png^[colorize:#FFFF00:40",
|
||||
},
|
||||
drawtype = "nodebox",
|
||||
node_box = {
|
||||
type = "wallmounted",
|
||||
wall_top = { -0.5, 0, -0.5, 0.5, 0.5, 0.5 },
|
||||
wall_bottom = { -0.5, -0.5, -0.5, 0.5, 0, 0.5 },
|
||||
wall_side = { -0.5, -0.5, -0.5, 0, 0.5, 0.5 },
|
||||
},
|
||||
|
||||
groups = { dig_immediate = 3 },
|
||||
})
|
||||
|
||||
minetest.register_node("testnodes:color", {
|
||||
description = S("Color Test Node").."\n"..
|
||||
S("param2 = color (0..255)"),
|
||||
@ -212,7 +252,7 @@ minetest.register_node("testnodes:color4dir_nodebox", {
|
||||
|
||||
minetest.register_node("testnodes:colorwallmounted", {
|
||||
description = S("Color Wallmounted Test Node").."\n"..
|
||||
S("param2 = color + wallmounted rotation (0..5, 8..13, ...)"),
|
||||
S("param2 = color + wallmounted rotation (0..7, 8..15, ...)"),
|
||||
paramtype2 = "colorwallmounted",
|
||||
paramtype = "light",
|
||||
palette = "testnodes_palette_wallmounted.png",
|
||||
@ -230,7 +270,7 @@ minetest.register_node("testnodes:colorwallmounted", {
|
||||
|
||||
minetest.register_node("testnodes:colorwallmounted_nodebox", {
|
||||
description = S("Color Wallmounted Nodebox Test Node").."\n"..
|
||||
S("param2 = color + wallmounted rotation (0..5, 8..13, ...)"),
|
||||
S("param2 = color + wallmounted rotation (0..7, 8..15, ...)"),
|
||||
paramtype2 = "colorwallmounted",
|
||||
paramtype = "light",
|
||||
palette = "testnodes_palette_wallmounted.png",
|
||||
|
@ -61,8 +61,8 @@ minetest.register_node("testnodes:attached", {
|
||||
-- when the node it attaches to is gone.
|
||||
minetest.register_node("testnodes:attached_wallmounted", {
|
||||
description = S("Wallmounted Attached Node").."\n"..
|
||||
S("Attaches to wall; drops as item if neighbor node is gone").."\n"..
|
||||
S("param2 = wallmounted rotation (0..5)"),
|
||||
S("Attaches to solid node it was placed on; drops as item if neighbor node is gone").."\n"..
|
||||
S("param2 = wallmounted rotation (0..7)"),
|
||||
paramtype2 = "wallmounted",
|
||||
tiles = {
|
||||
"testnodes_attachedw_top.png",
|
||||
@ -72,9 +72,29 @@ minetest.register_node("testnodes:attached_wallmounted", {
|
||||
groups = { attached_node = 1, dig_immediate = 3 },
|
||||
})
|
||||
|
||||
-- This node attaches to the side of a node and drops as item
|
||||
-- when the node it attaches to is gone.
|
||||
-- Also adds vertical 90° rotation variants.
|
||||
minetest.register_node("testnodes:attached_wallmounted_rot", {
|
||||
description = S("Rotatable Wallmounted Attached Node").."\n"..
|
||||
S("Attaches to solid node it was placed on; drops as item if neighbor node is gone").."\n"..
|
||||
S("param2 = wallmounted rotation (0..7)").."\n"..
|
||||
S("May be rotated by 90° if placed at floor or ceiling"),
|
||||
paramtype2 = "wallmounted",
|
||||
tiles = {
|
||||
"testnodes_attachedwr_top.png",
|
||||
"testnodes_attachedwr_bottom.png",
|
||||
"testnodes_attachedwr_side.png",
|
||||
},
|
||||
wallmounted_rotate_vertical = true,
|
||||
groups = { attached_node = 1, dig_immediate = 3 },
|
||||
})
|
||||
|
||||
-- Wallmounted node that always attaches to the floor
|
||||
minetest.register_node("testnodes:attached_wallmounted_floor", {
|
||||
description = S("Floor-Attached Wallmounted Node"),
|
||||
description = S("Floor-Attached Wallmounted Node").."\n"..
|
||||
S("Drops as item if no solid node below (regardless of rotation)").."\n"..
|
||||
S("param2 = wallmounted rotation (visual only) (0..7)"),
|
||||
paramtype2 = "wallmounted",
|
||||
tiles = {
|
||||
"testnodes_attached_top.png",
|
||||
@ -85,10 +105,28 @@ minetest.register_node("testnodes:attached_wallmounted_floor", {
|
||||
color = "#FF8080",
|
||||
})
|
||||
|
||||
-- Wallmounted node that always attaches to the floor.
|
||||
-- Also adds 90° rotation variants.
|
||||
minetest.register_node("testnodes:attached_wallmounted_floor_rot", {
|
||||
description = S("Rotatable Floor-Attached Wallmounted Node").."\n"..
|
||||
S("Drops as item if no solid node below (regardless of rotation)").."\n"..
|
||||
S("param2 = wallmounted rotation (visual only) (0..7)").."\n"..
|
||||
S("May be rotated by 90° if placed at floor or ceiling"),
|
||||
paramtype2 = "wallmounted",
|
||||
tiles = {
|
||||
"testnodes_attachedfr_top.png",
|
||||
"testnodes_attachedfr_bottom.png",
|
||||
"testnodes_attachedfr_side.png",
|
||||
},
|
||||
wallmounted_rotate_vertical = true,
|
||||
groups = { attached_node = 3, dig_immediate = 3 },
|
||||
})
|
||||
|
||||
-- This node attaches to the ceiling and drops as item
|
||||
-- when the ceiling is gone.
|
||||
minetest.register_node("testnodes:attached_top", {
|
||||
description = S("Ceiling-Attached Node"),
|
||||
description = S("Ceiling-Attached Node").."\n"..
|
||||
S("Drops as item if no solid node above"),
|
||||
tiles = {
|
||||
"testnodes_attached_bottom.png",
|
||||
"testnodes_attached_top.png",
|
||||
@ -99,7 +137,9 @@ minetest.register_node("testnodes:attached_top", {
|
||||
|
||||
-- Same as wallmounted attached, but for facedir
|
||||
minetest.register_node("testnodes:attached_facedir", {
|
||||
description = S("Facedir Attached Node"),
|
||||
description = S("Facedir Attached Node").."\n"..
|
||||
S("Attaches to a neighboring solid node; drops as item if that node is gone").."\n"..
|
||||
S("param2 = facedir rotation (0..23)"),
|
||||
paramtype2 = "facedir",
|
||||
tiles = {
|
||||
"testnodes_attachedf_side.png^[transformR180",
|
||||
@ -114,7 +154,9 @@ minetest.register_node("testnodes:attached_facedir", {
|
||||
|
||||
-- Same as facedir attached, but for 4dir
|
||||
minetest.register_node("testnodes:attached_4dir", {
|
||||
description = S("4dir Attached Node"),
|
||||
description = S("4dir Attached Node").."\n"..
|
||||
S("Attaches to the side of a solid node; drops as item if that node is gone").."\n"..
|
||||
S("param2 = 4dir rotation (0..3)"),
|
||||
paramtype2 = "4dir",
|
||||
tiles = {
|
||||
"testnodes_attached4_side.png^[transformR180",
|
||||
|
After Width: | Height: | Size: 106 B |
After Width: | Height: | Size: 103 B |
After Width: | Height: | Size: 93 B |
After Width: | Height: | Size: 265 B |
After Width: | Height: | Size: 173 B |
After Width: | Height: | Size: 153 B |
BIN
games/devtest/mods/testnodes/textures/testnodes_sign3d.png
Normal file
After Width: | Height: | Size: 214 B |
@ -1008,7 +1008,9 @@ void MapblockMeshGenerator::drawTorchlikeNode()
|
||||
switch (wall) {
|
||||
case DWM_YP: tileindex = 1; break; // ceiling
|
||||
case DWM_YN: tileindex = 0; break; // floor
|
||||
default: tileindex = 2; // side (or invalid—should we care?)
|
||||
case DWM_S1: tileindex = 1; break; // ceiling, but rotated
|
||||
case DWM_S2: tileindex = 0; break; // floor, but rotated
|
||||
default: tileindex = 2; // side (or invalid, shouldn't happen)
|
||||
}
|
||||
useTile(tileindex, MATERIAL_FLAG_CRACK_OVERLAY, MATERIAL_FLAG_BACKFACE_CULLING);
|
||||
|
||||
@ -1044,6 +1046,17 @@ void MapblockMeshGenerator::drawTorchlikeNode()
|
||||
case DWM_ZN:
|
||||
vertex.X += -size + BS/2;
|
||||
vertex.rotateXZBy(-90);
|
||||
break;
|
||||
case DWM_S1:
|
||||
// same as DWM_YP, but rotated 90°
|
||||
vertex.Y += -size + BS/2;
|
||||
vertex.rotateXZBy(45);
|
||||
break;
|
||||
case DWM_S2:
|
||||
// same as DWM_YN, but rotated -90°
|
||||
vertex.Y += size - BS/2;
|
||||
vertex.rotateXZBy(-45);
|
||||
break;
|
||||
}
|
||||
}
|
||||
drawQuad(vertices);
|
||||
@ -1077,6 +1090,10 @@ void MapblockMeshGenerator::drawSignlikeNode()
|
||||
vertex.rotateXZBy( 90); break;
|
||||
case DWM_ZN:
|
||||
vertex.rotateXZBy(-90); break;
|
||||
case DWM_S1:
|
||||
vertex.rotateXYBy( 90); vertex.rotateXZBy(90); break;
|
||||
case DWM_S2:
|
||||
vertex.rotateXYBy(-90); vertex.rotateXZBy(-90); break;
|
||||
}
|
||||
}
|
||||
drawQuad(vertices);
|
||||
|
@ -3704,7 +3704,36 @@ bool Game::nodePlacement(const ItemDefinition &selected_def,
|
||||
v3s16 dir = nodepos - neighborpos;
|
||||
|
||||
if (abs(dir.Y) > MYMAX(abs(dir.X), abs(dir.Z))) {
|
||||
predicted_node.setParam2(dir.Y < 0 ? 1 : 0);
|
||||
// If you change this code, also change builtin/game/item.lua
|
||||
u8 predicted_param2 = dir.Y < 0 ? 1 : 0;
|
||||
if (selected_def.wallmounted_rotate_vertical) {
|
||||
bool rotate90 = false;
|
||||
v3f fnodepos = v3f(neighborpos.X, neighborpos.Y, neighborpos.Z);
|
||||
v3f ppos = client->getEnv().getLocalPlayer()->getPosition() / BS;
|
||||
v3f pdir = fnodepos - ppos;
|
||||
switch (predicted_f.drawtype) {
|
||||
case NDT_TORCHLIKE: {
|
||||
rotate90 = !((pdir.X < 0 && pdir.Z > 0) ||
|
||||
(pdir.X > 0 && pdir.Z < 0));
|
||||
if (dir.Y > 0) {
|
||||
rotate90 = !rotate90;
|
||||
}
|
||||
break;
|
||||
};
|
||||
case NDT_SIGNLIKE: {
|
||||
rotate90 = abs(pdir.X) < abs(pdir.Z);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
rotate90 = abs(pdir.X) > abs(pdir.Z);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (rotate90) {
|
||||
predicted_param2 += 6;
|
||||
}
|
||||
}
|
||||
predicted_node.setParam2(predicted_param2);
|
||||
} else if (abs(dir.X) > abs(dir.Z)) {
|
||||
predicted_node.setParam2(dir.X < 0 ? 3 : 2);
|
||||
} else {
|
||||
|
@ -76,6 +76,7 @@ ItemDefinition& ItemDefinition::operator=(const ItemDefinition &def)
|
||||
groups = def.groups;
|
||||
node_placement_prediction = def.node_placement_prediction;
|
||||
place_param2 = def.place_param2;
|
||||
wallmounted_rotate_vertical = def.wallmounted_rotate_vertical;
|
||||
sound_place = def.sound_place;
|
||||
sound_place_failed = def.sound_place_failed;
|
||||
sound_use = def.sound_use;
|
||||
@ -124,6 +125,7 @@ void ItemDefinition::reset()
|
||||
range = -1;
|
||||
node_placement_prediction.clear();
|
||||
place_param2.reset();
|
||||
wallmounted_rotate_vertical = false;
|
||||
}
|
||||
|
||||
void ItemDefinition::serialize(std::ostream &os, u16 protocol_version) const
|
||||
@ -183,6 +185,7 @@ void ItemDefinition::serialize(std::ostream &os, u16 protocol_version) const
|
||||
os << (u8)place_param2.has_value(); // protocol_version >= 43
|
||||
if (place_param2)
|
||||
os << *place_param2;
|
||||
writeU8(os, wallmounted_rotate_vertical);
|
||||
}
|
||||
|
||||
void ItemDefinition::deSerialize(std::istream &is, u16 protocol_version)
|
||||
@ -251,6 +254,8 @@ void ItemDefinition::deSerialize(std::istream &is, u16 protocol_version)
|
||||
|
||||
if (readU8(is)) // protocol_version >= 43
|
||||
place_param2 = readU8(is);
|
||||
|
||||
wallmounted_rotate_vertical = readU8(is); // 0 if missing
|
||||
} catch(SerializationError &e) {};
|
||||
}
|
||||
|
||||
|
@ -89,6 +89,7 @@ struct ItemDefinition
|
||||
// "" = no prediction
|
||||
std::string node_placement_prediction;
|
||||
std::optional<u8> place_param2;
|
||||
bool wallmounted_rotate_vertical;
|
||||
|
||||
/*
|
||||
Some helpful methods
|
||||
|
@ -95,6 +95,8 @@ v3s16 MapNode::getWallMountedDir(const NodeDefManager *nodemgr) const
|
||||
case 3: return v3s16(-1,0,0);
|
||||
case 4: return v3s16(0,0,1);
|
||||
case 5: return v3s16(0,0,-1);
|
||||
case 6: return v3s16(0,1,0);
|
||||
case 7: return v3s16(0,-1,0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -323,16 +325,45 @@ void transformNodeBox(const MapNode &n, const NodeBox &nodebox,
|
||||
else if(nodebox.type == NODEBOX_WALLMOUNTED)
|
||||
{
|
||||
v3s16 dir = n.getWallMountedDir(nodemgr);
|
||||
u8 wall = n.getWallMounted(nodemgr);
|
||||
|
||||
// top
|
||||
if(dir == v3s16(0,1,0))
|
||||
{
|
||||
boxes.push_back(nodebox.wall_top);
|
||||
if (wall == DWM_S1) {
|
||||
v3f vertices[2] =
|
||||
{
|
||||
nodebox.wall_top.MinEdge,
|
||||
nodebox.wall_top.MaxEdge
|
||||
};
|
||||
for (v3f &vertex : vertices) {
|
||||
vertex.rotateXZBy(90);
|
||||
}
|
||||
aabb3f box = aabb3f(vertices[0]);
|
||||
box.addInternalPoint(vertices[1]);
|
||||
boxes.push_back(box);
|
||||
} else {
|
||||
boxes.push_back(nodebox.wall_top);
|
||||
}
|
||||
}
|
||||
// bottom
|
||||
else if(dir == v3s16(0,-1,0))
|
||||
{
|
||||
boxes.push_back(nodebox.wall_bottom);
|
||||
if (wall == DWM_S2) {
|
||||
v3f vertices[2] =
|
||||
{
|
||||
nodebox.wall_bottom.MinEdge,
|
||||
nodebox.wall_bottom.MaxEdge
|
||||
};
|
||||
for (v3f &vertex : vertices) {
|
||||
vertex.rotateXZBy(-90);
|
||||
}
|
||||
aabb3f box = aabb3f(vertices[0]);
|
||||
box.addInternalPoint(vertices[1]);
|
||||
boxes.push_back(box);
|
||||
} else {
|
||||
boxes.push_back(nodebox.wall_bottom);
|
||||
}
|
||||
}
|
||||
// side
|
||||
else
|
||||
|
@ -136,6 +136,8 @@ void read_item_definition(lua_State* L, int index,
|
||||
int place_param2;
|
||||
if (getintfield(L, index, "place_param2", place_param2))
|
||||
def.place_param2 = rangelim(place_param2, 0, U8_MAX);
|
||||
|
||||
getboolfield(L, index, "wallmounted_rotate_vertical", def.wallmounted_rotate_vertical);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
@ -195,6 +197,8 @@ void push_item_definition_full(lua_State *L, const ItemDefinition &i)
|
||||
lua_setfield(L, -2, "sound_place_failed");
|
||||
lua_pushstring(L, i.node_placement_prediction.c_str());
|
||||
lua_setfield(L, -2, "node_placement_prediction");
|
||||
lua_pushboolean(L, i.wallmounted_rotate_vertical);
|
||||
lua_setfield(L, -2, "wallmounted_rotate_vertical");
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -110,13 +110,15 @@ const v3s16 g_27dirs[27] =
|
||||
v3s16(0,0,0),
|
||||
};
|
||||
|
||||
const u8 wallmounted_to_facedir[6] = {
|
||||
const u8 wallmounted_to_facedir[8] = {
|
||||
20,
|
||||
0,
|
||||
16 + 1,
|
||||
12 + 3,
|
||||
8,
|
||||
4 + 2
|
||||
4 + 2,
|
||||
20 + 1, // special 1
|
||||
0 + 1 // special 2
|
||||
};
|
||||
|
||||
const v3s16 wallmounted_dirs[8] = {
|
||||
|
@ -69,16 +69,22 @@ enum Direction6D {
|
||||
/// Direction in the wallmounted format.
|
||||
/// P is Positive, N is Negative.
|
||||
enum DirectionWallmounted {
|
||||
// The 6 wallmounted directions
|
||||
DWM_YP,
|
||||
DWM_YN,
|
||||
DWM_XP,
|
||||
DWM_XN,
|
||||
DWM_ZP,
|
||||
DWM_ZN,
|
||||
DWM_COUNT,
|
||||
// There are 6 wallmounted directions, but 8 possible states (3 bits).
|
||||
// So we have 2 additional states, which drawtypes might use for
|
||||
// special ("S") behavior.
|
||||
DWM_S1,
|
||||
DWM_S2,
|
||||
DWM_COUNT
|
||||
};
|
||||
|
||||
extern const v3s16 g_6dirs[DWM_COUNT];
|
||||
extern const v3s16 g_6dirs[6];
|
||||
|
||||
extern const v3s16 g_7dirs[7];
|
||||
|
||||
@ -87,9 +93,9 @@ extern const v3s16 g_26dirs[26];
|
||||
// 26th is (0,0,0)
|
||||
extern const v3s16 g_27dirs[27];
|
||||
|
||||
extern const u8 wallmounted_to_facedir[6];
|
||||
extern const u8 wallmounted_to_facedir[DWM_COUNT];
|
||||
|
||||
extern const v3s16 wallmounted_dirs[8];
|
||||
extern const v3s16 wallmounted_dirs[DWM_COUNT];
|
||||
|
||||
extern const v3s16 facedir_dirs[32];
|
||||
|
||||
|