diff --git a/builtin/common/item_s.lua b/builtin/common/item_s.lua index f848ef6d8..72a722ed1 100644 --- a/builtin/common/item_s.lua +++ b/builtin/common/item_s.lua @@ -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] diff --git a/builtin/game/falling.lua b/builtin/game/falling.lua index 717c0b748..ec9c56c29 100644 --- a/builtin/game/falling.lua +++ b/builtin/game/falling.lua @@ -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 diff --git a/builtin/game/features.lua b/builtin/game/features.lua index 67fe52289..727d90174 100644 --- a/builtin/game/features.lua +++ b/builtin/game/features.lua @@ -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) diff --git a/builtin/game/item.lua b/builtin/game/item.lua index 17d081f3d..498e5899f 100644 --- a/builtin/game/item.lua +++ b/builtin/game/item.lua @@ -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 diff --git a/doc/lua_api.md b/doc/lua_api.md index af1980cee..c7be3b0c3 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -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. diff --git a/games/devtest/mods/testnodes/drawtypes.lua b/games/devtest/mods/testnodes/drawtypes.lua index f354b4394..087d09eff 100644 --- a/games/devtest/mods/testnodes/drawtypes.lua +++ b/games/devtest/mods/testnodes/drawtypes.lua @@ -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", diff --git a/games/devtest/mods/testnodes/meshes.lua b/games/devtest/mods/testnodes/meshes.lua index e55c3eafd..88a59ad22 100644 --- a/games/devtest/mods/testnodes/meshes.lua +++ b/games/devtest/mods/testnodes/meshes.lua @@ -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"}, diff --git a/games/devtest/mods/testnodes/nodeboxes.lua b/games/devtest/mods/testnodes/nodeboxes.lua index bc36035c0..99623bdda 100644 --- a/games/devtest/mods/testnodes/nodeboxes.lua +++ b/games/devtest/mods/testnodes/nodeboxes.lua @@ -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 }, + }, +}) + diff --git a/games/devtest/mods/testnodes/param2.lua b/games/devtest/mods/testnodes/param2.lua index ffa390967..cece3df1a 100644 --- a/games/devtest/mods/testnodes/param2.lua +++ b/games/devtest/mods/testnodes/param2.lua @@ -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", diff --git a/games/devtest/mods/testnodes/properties.lua b/games/devtest/mods/testnodes/properties.lua index 938511b83..b93d0c73b 100644 --- a/games/devtest/mods/testnodes/properties.lua +++ b/games/devtest/mods/testnodes/properties.lua @@ -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", diff --git a/games/devtest/mods/testnodes/textures/testnodes_attachedfr_bottom.png b/games/devtest/mods/testnodes/textures/testnodes_attachedfr_bottom.png new file mode 100644 index 000000000..21ece33dc Binary files /dev/null and b/games/devtest/mods/testnodes/textures/testnodes_attachedfr_bottom.png differ diff --git a/games/devtest/mods/testnodes/textures/testnodes_attachedfr_side.png b/games/devtest/mods/testnodes/textures/testnodes_attachedfr_side.png new file mode 100644 index 000000000..1e6a69640 Binary files /dev/null and b/games/devtest/mods/testnodes/textures/testnodes_attachedfr_side.png differ diff --git a/games/devtest/mods/testnodes/textures/testnodes_attachedfr_top.png b/games/devtest/mods/testnodes/textures/testnodes_attachedfr_top.png new file mode 100644 index 000000000..feef55277 Binary files /dev/null and b/games/devtest/mods/testnodes/textures/testnodes_attachedfr_top.png differ diff --git a/games/devtest/mods/testnodes/textures/testnodes_attachedwr_bottom.png b/games/devtest/mods/testnodes/textures/testnodes_attachedwr_bottom.png new file mode 100644 index 000000000..1a2e1e90e Binary files /dev/null and b/games/devtest/mods/testnodes/textures/testnodes_attachedwr_bottom.png differ diff --git a/games/devtest/mods/testnodes/textures/testnodes_attachedwr_side.png b/games/devtest/mods/testnodes/textures/testnodes_attachedwr_side.png new file mode 100644 index 000000000..382e2dafa Binary files /dev/null and b/games/devtest/mods/testnodes/textures/testnodes_attachedwr_side.png differ diff --git a/games/devtest/mods/testnodes/textures/testnodes_attachedwr_top.png b/games/devtest/mods/testnodes/textures/testnodes_attachedwr_top.png new file mode 100644 index 000000000..39ea67b8b Binary files /dev/null and b/games/devtest/mods/testnodes/textures/testnodes_attachedwr_top.png differ diff --git a/games/devtest/mods/testnodes/textures/testnodes_sign3d.png b/games/devtest/mods/testnodes/textures/testnodes_sign3d.png new file mode 100644 index 000000000..e4ad9479f Binary files /dev/null and b/games/devtest/mods/testnodes/textures/testnodes_sign3d.png differ diff --git a/src/client/content_mapblock.cpp b/src/client/content_mapblock.cpp index f4670e2c7..297a07bcd 100644 --- a/src/client/content_mapblock.cpp +++ b/src/client/content_mapblock.cpp @@ -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); diff --git a/src/client/game.cpp b/src/client/game.cpp index ea9972e3d..1beeb418e 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -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 { diff --git a/src/itemdef.cpp b/src/itemdef.cpp index 07f07a53e..30e908fa4 100644 --- a/src/itemdef.cpp +++ b/src/itemdef.cpp @@ -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) {}; } diff --git a/src/itemdef.h b/src/itemdef.h index 8ce6a15cd..09d8a0af2 100644 --- a/src/itemdef.h +++ b/src/itemdef.h @@ -89,6 +89,7 @@ struct ItemDefinition // "" = no prediction std::string node_placement_prediction; std::optional place_param2; + bool wallmounted_rotate_vertical; /* Some helpful methods diff --git a/src/mapnode.cpp b/src/mapnode.cpp index 76c050e7f..33354b2d9 100644 --- a/src/mapnode.cpp +++ b/src/mapnode.cpp @@ -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 diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp index 97b651ce8..e48607152 100644 --- a/src/script/common/c_content.cpp +++ b/src/script/common/c_content.cpp @@ -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"); } /******************************************************************************/ diff --git a/src/util/directiontables.cpp b/src/util/directiontables.cpp index 297058c9c..69dfc8a8a 100644 --- a/src/util/directiontables.cpp +++ b/src/util/directiontables.cpp @@ -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] = { diff --git a/src/util/directiontables.h b/src/util/directiontables.h index 105a0ef27..5672fe628 100644 --- a/src/util/directiontables.h +++ b/src/util/directiontables.h @@ -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];