Fix a number of crashes involving unknown nodes, also fix fishbuckets on_place (#3914)

Fixes: #3913 #3915

~~You can reproduce the crash by placing a fish bucket on top snow above an unknown node.

I also noticed that the code always uses pointed_thing.above so I fixed that and also added a function to mcl_utils to figure out where a node should be placed (either above or below). Looks like the rest of the code could also use improvement but at least it does not crash now.~~

Cora fixed a bunch of related crashes in Mineclona so I am replacing my commit and cherry picking all her commits here.
https://codeberg.org/mineclonia/mineclonia/pulls/549

Here is the list of fixes from that PR:
- Crash when placing snow layer on unknown nodes
- Crash when snow layers on unknown nodes are flooded
- Crash when placing fishbucket on snow on top of unknown nodes
- Crash when placing chorus flower and stem on unknown
- Crash when placing mob spawners on unknown
- The fishbucket on place to actually replace buildable_to

Co-authored-by: cora <coradelamouche@gmx.ch>
Reviewed-on: MineClone2/MineClone2#3914
Reviewed-by: ancientmarinerdev <ancientmariner_dev@proton.me>
Co-authored-by: 𝕵𝖔𝖍𝖆𝖓𝖓𝖊𝖘 𝕱𝖗𝖎𝖙𝖟 <mrrar@noreply.git.minetest.land>
Co-committed-by: 𝕵𝖔𝖍𝖆𝖓𝖓𝖊𝖘 𝕱𝖗𝖎𝖙𝖟 <mrrar@noreply.git.minetest.land>
This commit is contained in:
parent 178b24886f
commit a620d24ec8
5 changed files with 26 additions and 14 deletions

View File

@ -18,13 +18,21 @@ local function on_place_fish(itemstack, placer, pointed_thing)
return new_stack return new_stack
end end
local pos = pointed_thing.above or pointed_thing.under if pointed_thing.type ~= "node" then return end
if not pos then return end
local n = minetest.get_node_or_nil(pos) local pos = pointed_thing.above
if n.name and minetest.registered_nodes[n.name].buildable_to or n.name == "mcl_portals:portal" then local n = minetest.get_node(pointed_thing.above)
local fish = itemstack:get_name():gsub(fishbucket_prefix,"") local def = minetest.registered_nodes[minetest.get_node(pointed_thing.under).name]
if fish_names[fish] then
local o = minetest.add_entity(pos, "mobs_mc:" .. fish) if ( def and def.buildable_to ) or n.name == "mcl_portals:portal" then
pos = pointed_thing.under
n = minetest.get_node(pointed_thing.under)
end
local fish = itemstack:get_definition()._mcl_buckets_fish
if fish_names[fish] then
local o = minetest.add_entity(pos, "mobs_mc:" .. fish)
if o and o:get_pos() then
local props = itemstack:get_meta():get_string("properties") local props = itemstack:get_meta():get_string("properties")
if props ~= "" then if props ~= "" then
o:set_properties(minetest.deserialize(props)) o:set_properties(minetest.deserialize(props))
@ -60,6 +68,7 @@ for techname, fishname in pairs(fish_names) do
stack_max = 1, stack_max = 1,
groups = {bucket = 1, fish_bucket = 1}, groups = {bucket = 1, fish_bucket = 1},
liquids_pointable = false, liquids_pointable = false,
_mcl_buckets_fish = techname,
on_place = on_place_fish, on_place = on_place_fish,
on_secondary_use = on_place_fish, on_secondary_use = on_place_fish,
_on_dispense = function(stack, pos, droppos, dropnode, dropdir) _on_dispense = function(stack, pos, droppos, dropnode, dropdir)

View File

@ -1581,7 +1581,7 @@ end
-- MUST NOT be called if there is a snow cover node above pos. -- MUST NOT be called if there is a snow cover node above pos.
function mcl_core.clear_snow_dirt(pos, node) function mcl_core.clear_snow_dirt(pos, node)
local def = minetest.registered_nodes[node.name] local def = minetest.registered_nodes[node.name]
if def._mcl_snowless then if def and def._mcl_snowless then
minetest.swap_node(pos, {name = def._mcl_snowless, param2=node.param2}) minetest.swap_node(pos, {name = def._mcl_snowless, param2=node.param2})
end end
end end
@ -1602,7 +1602,7 @@ function mcl_core.on_snowable_construct(pos)
-- Make snowed if needed -- Make snowed if needed
if minetest.get_item_group(anode.name, "snow_cover") == 1 then if minetest.get_item_group(anode.name, "snow_cover") == 1 then
local def = minetest.registered_nodes[node.name] local def = minetest.registered_nodes[node.name]
if def._mcl_snowed then if def and def._mcl_snowed then
minetest.swap_node(pos, {name = def._mcl_snowed, param2=node.param2}) minetest.swap_node(pos, {name = def._mcl_snowed, param2=node.param2})
end end
end end
@ -1623,7 +1623,7 @@ function mcl_core.on_snow_construct(pos)
local npos = {x=pos.x, y=pos.y-1, z=pos.z} local npos = {x=pos.x, y=pos.y-1, z=pos.z}
local node = minetest.get_node(npos) local node = minetest.get_node(npos)
local def = minetest.registered_nodes[node.name] local def = minetest.registered_nodes[node.name]
if def._mcl_snowed then if def and def._mcl_snowed then
minetest.swap_node(npos, {name = def._mcl_snowed, param2=node.param2}) minetest.swap_node(npos, {name = def._mcl_snowed, param2=node.param2})
end end
end end

View File

@ -1038,7 +1038,7 @@ for i=1,8 do
-- Get position where snow would be placed -- Get position where snow would be placed
local target local target
if minetest.registered_nodes[unode.name].buildable_to then if def and def.buildable_to then
target = under target = under
else else
target = above target = above

View File

@ -155,7 +155,8 @@ minetest.register_node("mcl_end:chorus_flower", {
1) On top of end stone or chorus plant 1) On top of end stone or chorus plant
2) On top of air and horizontally adjacent to exactly 1 chorus plant ]] 2) On top of air and horizontally adjacent to exactly 1 chorus plant ]]
local pos local pos
if minetest.registered_nodes[node_under.name].buildable_to then local def = minetest.registered_nodes[node_under.name]
if def and def.buildable_to then
pos = pointed_thing.under pos = pointed_thing.under
else else
pos = pointed_thing.above pos = pointed_thing.above
@ -283,7 +284,8 @@ minetest.register_node("mcl_end:chorus_plant", {
condition is met: condition is met:
- placed on end stone or any chorus node ]] - placed on end stone or any chorus node ]]
local pos_place, node_check local pos_place, node_check
if minetest.registered_nodes[node_under.name].buildable_to then local def = minetest.registered_nodes[node_under.name]
if def and def.buildable_to then
pos_place = pointed_thing.under pos_place = pointed_thing.under
node_check = node_above node_check = node_above
else else

View File

@ -301,7 +301,8 @@ minetest.register_node("mcl_mobspawners:spawner", {
local new_itemstack, success = minetest.item_place(itemstack, placer, pointed_thing) local new_itemstack, success = minetest.item_place(itemstack, placer, pointed_thing)
if success then if success then
local placepos local placepos
if minetest.registered_nodes[node_under.name].buildable_to then local def = minetest.registered_nodes[node_under.name]
if def and def.buildable_to then
placepos = pointed_thing.under placepos = pointed_thing.under
else else
placepos = pointed_thing.above placepos = pointed_thing.above