Add support for attached facedir/4dir nodes (#11432)

This commit is contained in:
Wuzzy 2022-11-24 23:56:07 +01:00 committed by GitHub
parent 1c10988d6a
commit 3c7f26d937
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 177 additions and 27 deletions

@ -466,15 +466,39 @@ local function drop_attached_node(p)
end end
end end
function builtin_shared.check_attached_node(p, n) function builtin_shared.check_attached_node(p, n, group_rating)
local def = core.registered_nodes[n.name] local def = core.registered_nodes[n.name]
local d = vector.zero() local d = vector.zero()
if def.paramtype2 == "wallmounted" or if group_rating == 3 then
-- always attach to floor
d.y = -1
elseif group_rating == 4 then
-- always attach to ceiling
d.y = 1
elseif group_rating == 2 then
-- attach to facedir or 4dir direction
if (def.paramtype2 == "facedir" or
def.paramtype2 == "colorfacedir") then
-- Attach to whatever facedir is "mounted to".
-- For facedir, this is where tile no. 5 point at.
-- The fallback vector here is in case 'facedir to dir' is nil due
-- to voxelmanip placing a wallmounted node without resetting a
-- pre-existing param2 value that is out-of-range for facedir.
-- The fallback vector corresponds to param2 = 0.
d = core.facedir_to_dir(n.param2) or vector.new(0, 0, 1)
elseif (def.paramtype2 == "4dir" or
def.paramtype2 == "color4dir") then
-- Similar to facedir handling
d = core.fourdir_to_dir(n.param2) or vector.new(0, 0, 1)
end
elseif def.paramtype2 == "wallmounted" or
def.paramtype2 == "colorwallmounted" then def.paramtype2 == "colorwallmounted" then
-- The fallback vector here is in case 'wallmounted to dir' is nil due -- Attach to whatever this node is "mounted to".
-- to voxelmanip placing a wallmounted node without resetting a -- This where tile no. 2 points at.
-- pre-existing param2 value that is out-of-range for wallmounted.
-- The fallback vector corresponds to param2 = 0. -- The fallback vector here is used for the same reason as
-- for facedir nodes.
d = core.wallmounted_to_dir(n.param2) or vector.new(0, 1, 0) d = core.wallmounted_to_dir(n.param2) or vector.new(0, 1, 0)
else else
d.y = -1 d.y = -1
@ -519,8 +543,9 @@ function core.check_single_for_falling(p)
end end
end end
if core.get_item_group(n.name, "attached_node") ~= 0 then local an = core.get_item_group(n.name, "attached_node")
if not builtin_shared.check_attached_node(p, n) then if an ~= 0 then
if not builtin_shared.check_attached_node(p, n, an) then
drop_attached_node(p) drop_attached_node(p)
return true return true
end end

@ -240,8 +240,9 @@ function core.item_place_node(itemstack, placer, pointed_thing, param2,
end end
-- Check if the node is attached and if it can be placed there -- Check if the node is attached and if it can be placed there
if core.get_item_group(def.name, "attached_node") ~= 0 and local an = core.get_item_group(def.name, "attached_node")
not builtin_shared.check_attached_node(place_to, newnode) then if an ~= 0 and
not builtin_shared.check_attached_node(place_to, newnode, an) then
log("action", "attached node " .. def.name .. log("action", "attached node " .. def.name ..
" cannot be placed at " .. core.pos_to_string(place_to)) " cannot be placed at " .. core.pos_to_string(place_to))
return itemstack, nil return itemstack, nil

@ -1890,9 +1890,16 @@ to games.
### Node-only groups ### Node-only groups
* `attached_node`: if the node under it is not a walkable block the node will be * `attached_node`: the node is 'attached' to a neighboring node. It checks
dropped as an item. If the node is wallmounted the wallmounted direction is whether the node it is attached to is walkable. If it
checked. isn't, the node will drop as an item.
* `1`: if the node is wallmounted, the node is attached in the wallmounted
direction. Otherwise, the node is attached to the node below.
* `2`: if the node is facedir or 4dir, the facedir or 4dir direction is checked.
No effect for other nodes.
Note: The "attaching face" of this node is tile no. 5 (back face).
* `3`: the node is always attached to the node below.
* `4`: the node is always attached to the node above.
* `bouncy`: value is bounce speed in percent. * `bouncy`: value is bounce speed in percent.
If positive, jump/sneak on floor impact will increase/decrease bounce height. If positive, jump/sneak on floor impact will increase/decrease bounce height.
Negative value is the same bounciness, but non-controllable. Negative value is the same bounciness, but non-controllable.

@ -57,7 +57,6 @@ minetest.register_node("testnodes:attached", {
}, },
groups = { attached_node = 1, dig_immediate = 3 }, groups = { attached_node = 1, dig_immediate = 3 },
}) })
-- This node attaches to the side of a node and drops as item -- This node attaches to the side of a node and drops as item
-- when the node it attaches to is gone. -- when the node it attaches to is gone.
minetest.register_node("testnodes:attached_wallmounted", { minetest.register_node("testnodes:attached_wallmounted", {
@ -73,6 +72,61 @@ minetest.register_node("testnodes:attached_wallmounted", {
groups = { attached_node = 1, dig_immediate = 3 }, 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"),
paramtype2 = "wallmounted",
tiles = {
"testnodes_attached_top.png",
"testnodes_attached_bottom.png",
"testnodes_attached_side.png",
},
groups = { attached_node = 3, dig_immediate = 3 },
color = "#FF8080",
})
-- 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"),
tiles = {
"testnodes_attached_bottom.png",
"testnodes_attached_top.png",
"testnodes_attached_side.png^[transformR180",
},
groups = { attached_node = 4, dig_immediate = 3 },
})
-- Same as wallmounted attached, but for facedir
minetest.register_node("testnodes:attached_facedir", {
description = S("Facedir Attached Node"),
paramtype2 = "facedir",
tiles = {
"testnodes_attachedf_side.png^[transformR180",
"testnodes_attachedf_side.png",
"testnodes_attachedf_side.png^[transformR90",
"testnodes_attachedf_side.png^[transformR270",
"testnodes_attachedf_bottom.png",
"testnodes_attachedf_top.png",
},
groups = { attached_node = 2, dig_immediate = 3 },
})
-- Same as facedir attached, but for 4dir
minetest.register_node("testnodes:attached_4dir", {
description = S("4dir Attached Node"),
paramtype2 = "4dir",
tiles = {
"testnodes_attached4_side.png^[transformR180",
"testnodes_attached4_side.png",
"testnodes_attached4_side.png^[transformR90",
"testnodes_attached4_side.png^[transformR270",
"testnodes_attached4_bottom.png",
"testnodes_attached4_top.png",
},
groups = { attached_node = 2, dig_immediate = 3 },
})
-- Jump disabled -- Jump disabled
minetest.register_node("testnodes:nojump", { minetest.register_node("testnodes:nojump", {
description = S("Non-jumping Node").."\n".. description = S("Non-jumping Node").."\n"..

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 B

@ -3585,22 +3585,30 @@ bool Game::nodePlacement(const ItemDefinition &selected_def,
} }
// Check attachment if node is in group attached_node // Check attachment if node is in group attached_node
if (itemgroup_get(predicted_f.groups, "attached_node") != 0) { int an = itemgroup_get(predicted_f.groups, "attached_node");
const static v3s16 wallmounted_dirs[8] = { if (an != 0) {
v3s16(0, 1, 0),
v3s16(0, -1, 0),
v3s16(1, 0, 0),
v3s16(-1, 0, 0),
v3s16(0, 0, 1),
v3s16(0, 0, -1),
};
v3s16 pp; v3s16 pp;
if (predicted_f.param_type_2 == CPT2_WALLMOUNTED || if (an == 3) {
predicted_f.param_type_2 == CPT2_COLORED_WALLMOUNTED)
pp = p + wallmounted_dirs[param2];
else
pp = p + v3s16(0, -1, 0); pp = p + v3s16(0, -1, 0);
} else if (an == 4) {
pp = p + v3s16(0, 1, 0);
} else if (an == 2) {
if (predicted_f.param_type_2 == CPT2_FACEDIR ||
predicted_f.param_type_2 == CPT2_COLORED_FACEDIR) {
pp = p + facedir_dirs[param2];
} else if (predicted_f.param_type_2 == CPT2_4DIR ||
predicted_f.param_type_2 == CPT2_COLORED_4DIR ) {
pp = p + fourdir_dirs[param2];
} else {
pp = p;
}
} else if (predicted_f.param_type_2 == CPT2_WALLMOUNTED ||
predicted_f.param_type_2 == CPT2_COLORED_WALLMOUNTED) {
pp = p + wallmounted_dirs[param2];
} else {
pp = p + v3s16(0, -1, 0);
}
if (!nodedef->get(map.getNode(pp)).walkable) { if (!nodedef->get(map.getNode(pp)).walkable) {
soundmaker->m_player_rightpunch_sound = selected_def.sound_place_failed; soundmaker->m_player_rightpunch_sound = selected_def.sound_place_failed;

@ -118,3 +118,52 @@ const u8 wallmounted_to_facedir[6] = {
8, 8,
4 + 2 4 + 2
}; };
const v3s16 wallmounted_dirs[8] = {
v3s16(0, 1, 0),
v3s16(0, -1, 0),
v3s16(1, 0, 0),
v3s16(-1, 0, 0),
v3s16(0, 0, 1),
v3s16(0, 0, -1),
};
const v3s16 facedir_dirs[32] = {
//0
v3s16(0, 0, 1),
v3s16(1, 0, 0),
v3s16(0, 0, -1),
v3s16(-1, 0, 0),
//4
v3s16(0, -1, 0),
v3s16(1, 0, 0),
v3s16(0, 1, 0),
v3s16(-1, 0, 0),
//8
v3s16(0, 1, 0),
v3s16(1, 0, 0),
v3s16(0, -1, 0),
v3s16(-1, 0, 0),
//12
v3s16(0, 0, 1),
v3s16(0, -1, 0),
v3s16(0, 0, -1),
v3s16(0, 1, 0),
//16
v3s16(0, 0, 1),
v3s16(0, 1, 0),
v3s16(0, 0, -1),
v3s16(0, -1, 0),
//20
v3s16(0, 0, 1),
v3s16(-1, 0, 0),
v3s16(0, 0, -1),
v3s16(1, 0, 0),
};
const v3s16 fourdir_dirs[4] = {
v3s16(0, 0, 1),
v3s16(1, 0, 0),
v3s16(0, 0, -1),
v3s16(-1, 0, 0),
};

@ -33,6 +33,12 @@ extern const v3s16 g_27dirs[27];
extern const u8 wallmounted_to_facedir[6]; extern const u8 wallmounted_to_facedir[6];
extern const v3s16 wallmounted_dirs[8];
extern const v3s16 facedir_dirs[32];
extern const v3s16 fourdir_dirs[4];
/// Direction in the 6D format. g_27dirs contains corresponding vectors. /// Direction in the 6D format. g_27dirs contains corresponding vectors.
/// Here P means Positive, N stands for Negative. /// Here P means Positive, N stands for Negative.
enum Direction6D { enum Direction6D {