Added placement API, fixed crashes with cabinet sinks

This commit is contained in:
Andrey2470T 2023-11-01 18:37:40 +03:00
parent 079838cd31
commit 47b50ae152
14 changed files with 262 additions and 66 deletions

View File

@ -1,4 +1,4 @@
local default_on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
local default_bed_on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
local add_props = minetest.registered_nodes[node.name].add_properties
if not add_props then
@ -36,7 +36,13 @@ local default_on_rightclick = function(pos, node, clicker, itemstack, pointed_th
return itemstack
end
local default_can_dig = function(pos)
local default_bed_after_place = function(pos, placer, itemstack)
local leftover = multidecor.placement.check_for_placement(pos, placer)
return leftover
end
local default_bed_can_dig = function(pos)
local add_props = minetest.registered_nodes[minetest.get_node(pos).name].add_properties
if not add_props then
@ -69,14 +75,16 @@ function multidecor.register.register_bed(name, base_def, add_def, craft_def)
if def.callbacks then
def.callbacks.after_destruct = nil
def.callbacks.after_dig_node = nil
def.callbacks.on_rightclick = def.callbacks.on_rightclick or default_on_rightclick
def.callbacks.after_place_node = def.callbacks.after_place_node or default_bed_after_place
def.callbacks.on_rightclick = def.callbacks.on_rightclick or default_bed_on_rightclick
def.callbacks.on_destruct = def.callbacks.on_destruct or mtg_bed_def.on_destruct
def.callbacks.can_dig = def.callbacks.can_dig or default_can_dig
def.callbacks.can_dig = def.callbacks.can_dig or default_bed_can_dig
else
def.callbacks = {
after_place_node = default_bed_after_place,
on_rightclick = default_on_rightclick,
on_destruct = mtg_bed_def.on_destruct,
can_dig = default_can_dig
can_dig = default_bed_can_dig
}
end

View File

@ -12,18 +12,18 @@ function multidecor.helpers.get_dir(pos)
return dir
end
-- Rotates 'rel_pos' vertically relative to 'pos' of some node according to its facedir
-- Rotates 'rel_pos' vertically relative to 'pos' of some node according to its facedir
function multidecor.helpers.rotate_to_node_dir(pos, rel_pos)
local dir = multidecor.helpers.get_dir(pos)
if dir.x == 0 and dir.z == 0 then
return vector.zero()
end
local rot_y = vector.dir_to_rotation(dir).y
local new_rel_pos = vector.rotate_around_axis(rel_pos, vector.new(0, 1, 0), rot_y)
return new_rel_pos
end

View File

@ -146,7 +146,7 @@ function multidecor.curtains.move_curtains(pos, dir)
return res
end
function multidecor.curtains.default_after_place(pos)
function multidecor.curtains.default_after_place(pos, placer)
local name = minetest.get_node(pos).name
local val = multidecor.curtains.can_place(pos, name)
@ -155,6 +155,10 @@ function multidecor.curtains.default_after_place(pos)
minetest.remove_node(pos)
return true
end
local leftover = multidecor.check_for_placement(pos, placer)
return leftover
end
function multidecor.curtains.default_after_dig(pos, oldnode, oldmeta, digger)

View File

@ -150,6 +150,12 @@ function multidecor.doors.convert_from_entity(obj)
minetest.set_node(pos, {name=name, param2=param2})
end
local function default_door_after_place(pos, placer, itemstack)
local leftover = multidecor.placement.check_for_placement(pos, placer)
return leftover
end
local function default_door_on_rightclick(pos)
local door_data = minetest.registered_nodes[minetest.get_node(pos).name].add_properties.door
@ -227,11 +233,10 @@ function multidecor.register.register_door(name, base_def, add_def, craft_def)
c_def.add_properties.door.mode = "closed"
if c_def.callbacks then
c_def.callbacks.on_rightclick = c_def.callbacks.on_rightclick or default_door_on_rightclick
else
c_def.callbacks = {on_rightclick = default_door_on_rightclick}
end
c_def.callbacks = c_def.callbacks or {}
c_def.callbacks.after_place_node = c_def.callbacks.after_place_node or default_door_after_place
c_def.callbacks.on_rightclick = c_def.callbacks.on_rightclick or default_door_on_rightclick
multidecor.register.register_furniture_unit(name, c_def, craft_def)

View File

@ -2,6 +2,12 @@ local function default_on_construct_dir(pos)
multidecor.connecting.update_adjacent_nodes_connection(pos, "directional")
end
local function default_hedge_after_place(pos, placer, itemstack)
local leftover = multidecor.placement.check_for_placement(pos, placer)
return leftover
end
local function default_after_destruct_dir(pos, oldnode)
multidecor.connecting.update_adjacent_nodes_connection(pos, "directional", true, oldnode)
end
@ -29,23 +35,15 @@ function multidecor.register.register_hedge(name, base_def, add_def, craft_def)
end
end
if def.callbacks then
if add_def.connect_parts then
def.callbacks.after_dig_node = def.callbacks.after_dig_node or default_after_destruct_dir
def.callbacks = def.callbacks or {}
def.callbacks.on_construct = def.callbacks.on_construct or default_on_construct_dir
elseif add_def.double then
def.callbacks.on_construct = def.callbacks.on_construct or default_on_construct_pair
end
else
def.callbacks = {}
def.callbacks.after_place_node = def.callbacks.after_place_node or default_hedge_after_place
if add_def.connect_parts then
def.callbacks.after_dig_node = default_after_destruct_dir
def.callbacks.on_construct = default_on_construct_dir
elseif add_def.double then
def.callbacks.on_construct = default_on_construct_pair
end
if add_def.connect_parts then
def.callbacks.on_construct = def.callbacks.on_construct or default_on_construct_dir
def.callbacks.after_dig_node = def.callbacks.after_dig_node or default_after_destruct_dir
elseif add_def.double then
def.callbacks.on_construct = def.callbacks.on_construct or default_on_construct_pair
end
multidecor.register.register_furniture_unit(name, def, craft_def)

View File

@ -12,6 +12,7 @@ dofile(modpath .. "/door.lua")
dofile(modpath .. "/bed.lua")
dofile(modpath .. "/hedge.lua")
dofile(modpath .. "/lighting.lua")
dofile(modpath .. "/placement.lua")
dofile(modpath .. "/sitting.lua")
dofile(modpath .. "/seat.lua")
dofile(modpath .. "/shelves.lua")

113
decor_api/placement.lua Normal file
View File

@ -0,0 +1,113 @@
multidecor.placement = {}
function multidecor.placement.check_for_free_space(pos, size_bbox)
local free = true
for x = size_bbox[1], size_bbox[4] do
for y = size_bbox[2], size_bbox[5] do
for z = size_bbox[3], size_bbox[6] do
local shift_pos = pos + vector.new(x, y, z)
if not vector.equals(pos, shift_pos) then
local shift_node_def = minetest.registered_nodes[minetest.get_node(shift_pos).name]
if shift_node_def.drawtype ~= "airlike" or shift_node_def.walkable then
free = false
break
end
end
end
if not free then break end
end
if not free then break end
end
return free
end
function multidecor.placement.box_repair(box)
local rep_box = table.copy(box)
if rep_box[1] > rep_box[4] then
local x = rep_box[1]
rep_box[1] = rep_box[4]
rep_box[4] = x
end
if rep_box[2] > rep_box[5] then
local y = rep_box[2]
rep_box[2] = rep_box[5]
rep_box[5] = y
end
if rep_box[3] > rep_box[6] then
local z = rep_box[3]
rep_box[3] = rep_box[6]
rep_box[6] = z
end
return rep_box
end
function multidecor.placement.calc_place_space_size(bboxes)
local max_bbox = {0, 0, 0, 0, 0, 0}
for box_id, _ in ipairs(bboxes) do
local new_box = multidecor.placement.box_repair(bboxes[box_id])
for i, v in ipairs(new_box) do
if i < 4 then
max_bbox[i] = box_id == 1 and v or math.min(max_bbox[i], v)
else
max_bbox[i] = math.max(max_bbox[i], v)
end
end
end
for i, coord in ipairs(max_bbox) do
local int, frac = math.modf(coord)
max_bbox[i] = math.abs(frac) > 0.5 and math.ceil(math.abs(coord)) or math.floor(math.abs(coord))
end
return max_bbox
end
function multidecor.placement.check_for_placement(pos, placer)
local nodename = minetest.get_node(pos).name
local def = minetest.registered_nodes[nodename]
if def.drawtype ~= "mesh" and def.drawtype ~= "nodebox" then
return
end
local bboxes
if def.drawtype == "nodebox" then
bboxes = def.node_box.fixed
else
bboxes = def.collision_box.fixed
end
local max_bbox = multidecor.placement.calc_place_space_size(bboxes)
local rot_bbox = {}
rot_bbox.min = multidecor.helpers.rotate_to_node_dir(pos, vector.new(max_bbox[1], max_bbox[2], max_bbox[3]))
rot_bbox.max = multidecor.helpers.rotate_to_node_dir(pos, vector.new(max_bbox[4], max_bbox[5], max_bbox[6]))
max_bbox = multidecor.placement.box_repair({
rot_bbox.min.x, rot_bbox.min.y, rot_bbox.min.z,
rot_bbox.max.x, rot_bbox.max.y, rot_bbox.max.z
})
local can_be_placed = multidecor.placement.check_for_free_space(pos, max_bbox)
if not can_be_placed then
local return_item = ItemStack(nodename)
minetest.remove_node(pos)
placer:get_inventory():add_item("main", return_item)
return return_item
end
end

View File

@ -551,6 +551,7 @@ function multidecor.register.register_garniture(def)
common_name = def.common_name .. "_sink",
form_shelf_data("sink", "door", objects[1], def.components.sink.shelves_data.pos_trash, nil, nil, "left", "trash")
}
sink.add_properties.tap_data = def.components.sink.tap_data
multidecor.register.register_table(sink.add_properties.shelves_data.common_name, sink)
end

View File

@ -29,11 +29,12 @@ function multidecor.register.register_seat(name, base_def, add_def, craft_def)
end
def.callbacks = def.callbacks or {}
def.callbacks.after_place_node = def.callbacks.after_place_node or multidecor.sitting.default_after_place
def.callbacks.on_construct = def.callbacks.on_construct or multidecor.sitting.default_on_construct
def.callbacks.on_destruct = def.callbacks.on_destruct or multidecor.sitting.default_on_destruct
def.callbacks.on_rightclick = def.callbacks.on_rightclick or multidecor.sitting.default_on_rightclick
--[[if def.callbacks then
def.callbacks.on_construct = def.callbacks.on_construct or multidecor.sitting.default_on_construct
def.callbacks.on_destruct = def.callbacks.on_destruct or multidecor.sitting.default_on_destruct

View File

@ -166,6 +166,12 @@ player_api.register_model(multidecor.sitting.standard_model, {
}
})
multidecor.sitting.default_after_place = function(pos, placer, itemstack)
local leftover = multidecor.placement.check_for_placement(pos, placer)
return leftover
end
multidecor.sitting.default_on_construct = function(pos)
minetest.get_meta(pos):set_string("is_busy", "")
end

View File

@ -1,6 +1,6 @@
multidecor.tap = {}
function multidecor.tap.register_water_stream(pos, spawn_min_pos, spawn_max_pos, amount, velocity, direction, sound, check_for_sink)
--[[function multidecor.tap.register_water_stream(pos, spawn_min_pos, spawn_max_pos, amount, velocity, direction, sound, check_for_sink)
local meta = minetest.get_meta(pos)
meta:set_string("water_stream_info", minetest.serialize({
@ -12,7 +12,7 @@ function multidecor.tap.register_water_stream(pos, spawn_min_pos, spawn_max_pos,
water_sound = sound,
check_for_sink = check_for_sink
}))
end
end]]
function multidecor.tap.is_on(pos)
return minetest.get_meta(pos):get_string("water_stream_id") ~= ""
@ -25,7 +25,7 @@ function multidecor.tap.on(pos)
if id ~= "" then return end
local water_info = minetest.deserialize(meta:get_string("water_stream_info"))
local water_info = minetest.registered_nodes[minetest.get_node(pos).name].add_properties.tap_data
if water_info.check_for_sink then
local down_node = minetest.get_node({x=pos.x, y=pos.y-1, z=pos.z})
@ -36,12 +36,12 @@ function multidecor.tap.on(pos)
end
end
local rot_water_min_pos = multidecor.helpers.rotate_to_node_dir(pos, water_info.water_min_pos)
local rot_water_max_pos = multidecor.helpers.rotate_to_node_dir(pos, water_info.water_max_pos)
local rot_water_dir = multidecor.helpers.rotate_to_node_dir(pos, water_info.water_direction)
local rot_water_min_pos = multidecor.helpers.rotate_to_node_dir(pos, water_info.min_pos)
local rot_water_max_pos = multidecor.helpers.rotate_to_node_dir(pos, water_info.max_pos)
local rot_water_dir = multidecor.helpers.rotate_to_node_dir(pos, water_info.direction)
local id = minetest.add_particlespawner({
amount = water_info.water_amount,
amount = water_info.amount,
time = 0,
collisiondetection = true,
object_collision = true,
@ -49,8 +49,8 @@ function multidecor.tap.on(pos)
texture = "multidecor_water_drop.png",
minpos = pos+rot_water_min_pos+vector.new(-0.05, 0, -0.05),
maxpos = pos+rot_water_max_pos+vector.new(0.05, 0, 0.05),
minvel = rot_water_dir*water_info.water_velocity,
maxvel = rot_water_dir*water_info.water_velocity,
minvel = rot_water_dir*water_info.velocity,
maxvel = rot_water_dir*water_info.velocity,
minacc = vector.new(0, -9.8, 0),
maxacc = vector.new(0, -9.8, 0),
minsize = 0.8,
@ -59,7 +59,7 @@ function multidecor.tap.on(pos)
meta:set_string("water_stream_id", tostring(id))
local sound_handle = minetest.sound_play(water_info.water_sound, {pos=pos, fade=1.0, max_hear_distance=12, loop=true})
local sound_handle = minetest.sound_play(water_info.sound, {pos=pos, fade=1.0, max_hear_distance=12, loop=true})
meta:set_string("sound_handle", minetest.serialize(sound_handle))
end

View File

@ -166,15 +166,11 @@ for _, style in ipairs(bathroom_styles) do
on_construct = function(pos)
multidecor.shelves.set_shelves(pos)
multidecor.tap.register_water_stream(pos, {x=0.0, y=0.65, z=-0.1}, {x=0.0, y=0.65, z=-0.1}, 30, 2, {x=0, y=-1, z=0}, "multidecor_tap", false)
--multidecor.tap.register_water_stream(pos, {x=0.0, y=0.65, z=-0.1}, {x=0.0, y=0.65, z=-0.1}, 30, 2, {x=0, y=-1, z=0}, "multidecor_tap", false)
end,
can_dig = multidecor.shelves.default_can_dig,
on_rightclick = function(pos)
multidecor.tap.toggle(pos)
end,
on_destruct = function(pos)
multidecor.tap.off(pos)
end
on_rightclick = multidecor.tap.default_on_rightclick,
on_destruct = multidecor.tap.default_on_destruct
}
},
{
@ -193,6 +189,15 @@ for _, style in ipairs(bathroom_styles) do
close = "multidecor_squeaky_door_close"
}
}
},
tap_data = {
min_pos = {x=0.0, y=0.65, z=-0.1},
max_pos = {x=0.0, y=0.65, z=-0.1},
amount = 30,
velocity = 2,
direction = {x=0, y=-1, z=0},
sound = "multidecor_tap",
check_for_sink = false
}
},
{
@ -574,13 +579,24 @@ multidecor.register.register_furniture_unit("bathroom_tap_with_cap_flap", {
bounding_boxes = {{-0.3, -0.1, 0.0, 0.3, 0.2, 0.5}},
callbacks = {
on_construct = function(pos)
multidecor.tap.register_water_stream(pos, {x=0.0, y=-0.15, z=0.0}, {x=0.0, y=-0.15, z=0.0}, 80, 2, {x=0, y=-1, z=0}, "multidecor_tap", true)
--multidecor.tap.register_water_stream(pos, {x=0.0, y=-0.15, z=0.0}, {x=0.0, y=-0.15, z=0.0}, 80, 2, {x=0, y=-1, z=0}, "multidecor_tap", true)
minetest.get_node_timer(pos):start(1)
end,
on_rightclick = multidecor.tap.default_on_rightclick,
on_destruct = multidecor.tap.default_on_destruct,
on_timer = multidecor.tap.default_on_timer
},
add_properties = {
tap_data = {
min_pos = {x=0.0, y=-0.15, z=0.0},
max_pos = {x=0.0, y=-0.15, z=0.0},
amount = 80,
velocity = 2,
direction = {x=0, y=-1, z=0},
sound = "multidecor_tap",
check_for_sink = true
}
}
},
{
@ -601,13 +617,24 @@ multidecor.register.register_furniture_unit("bathroom_tap_with_side_flaps", {
bounding_boxes = {{-0.3, -0.2, 0.0, 0.3, 0.1, 0.5}},
callbacks = {
on_construct = function(pos)
multidecor.tap.register_water_stream(pos, {x=0.0, y=-0.275, z=-0.025}, {x=0.0, y=-0.275, z=-0.025}, 80, 2, {x=0, y=-1, z=0}, "multidecor_tap", true)
--multidecor.tap.register_water_stream(pos, {x=0.0, y=-0.275, z=-0.025}, {x=0.0, y=-0.275, z=-0.025}, 80, 2, {x=0, y=-1, z=0}, "multidecor_tap", true)
minetest.get_node_timer(pos):start(1)
end,
on_rightclick = multidecor.tap.default_on_rightclick,
on_destruct = multidecor.tap.default_on_destruct,
on_timer = multidecor.tap.default_on_timer
},
add_properties = {
tap_data = {
min_pos = {x=0.0, y=-0.275, z=-0.025},
max_pos = {x=0.0, y=-0.275, z=-0.025},
amount = 80,
velocity = 2,
direction = {x=0, y=-1, z=0},
sound = "multidecor_tap",
check_for_sink = true
}
}
},
{
@ -628,14 +655,25 @@ multidecor.register.register_furniture_unit("shower_head", {
bounding_boxes = {{-0.2, -0.5, -0.2, 0.2, 0.35, 0.5}},
callbacks = {
on_construct = function(pos)
multidecor.tap.register_water_stream(pos, {x=-0.15, y=0.05, z=0.0}, {x=0.15, y=0.2, z=0.0}, 150, 2,
vector.rotate_around_axis(vector.new(0, 1, 0), vector.new(1, 0, 0), -math.pi/3), "multidecor_tap", true)
--multidecor.tap.register_water_stream(pos, {x=-0.15, y=0.05, z=0.0}, {x=0.15, y=0.2, z=0.0}, 150, 2,
-- vector.rotate_around_axis(vector.new(0, 1, 0), vector.new(1, 0, 0), -math.pi/3), "multidecor_tap", true)
minetest.get_node_timer(pos):start(1)
end,
on_rightclick = multidecor.tap.default_on_rightclick,
on_destruct = multidecor.tap.default_on_destruct,
on_timer = multidecor.tap.default_on_timer
},
add_properties = {
tap_data = {
min_pos = {x=-0.15, y=0.05, z=0.0},
max_pos = {x=0.15, y=0.2, z=0.0},
amount = 150,
velocity = 2,
direction = vector.rotate_around_axis(vector.new(0, 1, 0), vector.new(1, 0, 0), -math.pi/3),
sound = "multidecor_tap",
check_for_sink = true
}
}
},
{
@ -667,13 +705,24 @@ multidecor.register.register_furniture_unit("crooked_shower_head", {
bounding_boxes = {{-0.2, -0.3, -0.3, 0.2, 0.3, 0.5}},
callbacks = {
on_construct = function(pos)
multidecor.tap.register_water_stream(pos, {x=-0.25, y=-0.35, z=-0.25}, {x=0.25, y=-0.35, z=0.25}, 250, 2, {x=0, y=-1, z=0}, "multidecor_tap", true)
--multidecor.tap.register_water_stream(pos, {x=-0.25, y=-0.35, z=-0.25}, {x=0.25, y=-0.35, z=0.25}, 250, 2, {x=0, y=-1, z=0}, "multidecor_tap", true)
minetest.get_node_timer(pos):start(1)
end,
on_rightclick = multidecor.tap.default_on_rightclick,
on_destruct = multidecor.tap.default_on_destruct,
on_timer = multidecor.tap.default_on_timer
},
add_properties = {
tap_data = {
min_pos = {x=-0.25, y=-0.35, z=-0.25},
max_pos = {x=0.25, y=-0.35, z=0.25},
amount = 250,
velocity = 2,
direction = {x=0, y=-1, z=0},
sound = "multidecor_tap",
check_for_sink = true
}
}
},
crooked_shower_head_recipe)

View File

@ -118,6 +118,15 @@ local cmpnts = {
pos_trash = {x=0.45, y=0, z=0.4},
side = "left"
},
tap_data = {
min_pos = tap_pos,
max_pos = tap_pos,
amount = 80,
velocity = 2,
direction = {x=0, y=-1, z=0},
sound = "multidecor_tap",
check_for_sink = false
},
craft = {
{"multidecor:board", "multidecor:board", "multidecor:board"},
{"multidecor:board", "multidecor:cabinet_door", "multidecor:steel_sheet"},
@ -126,14 +135,10 @@ local cmpnts = {
callbacks = {
on_construct = function(pos)
multidecor.shelves.set_shelves(pos)
multidecor.tap.register_water_stream(pos, tap_pos, tap_pos, 80, 2, {x=0, y=-1, z=0}, "multidecor_tap", false)
--multidecor.tap.register_water_stream(pos, tap_pos, tap_pos, 80, 2, {x=0, y=-1, z=0}, "multidecor_tap", false)
end,
on_rightclick = function(pos)
multidecor.tap.toggle(pos)
end,
on_destruct = function(pos)
multidecor.tap.off(pos)
end
on_rightclick = multidecor.tap.default_on_rightclick,
on_destruct = multidecor.tap.default_on_destruct
}
},
}

View File

@ -33,7 +33,7 @@ local silver_chain_bbox = {
fixed = {-0.1, -0.5, -0.1, 0.1, 0.5, 0.1}
}
local silver_chain_on_construct = function(pos)
local silver_chain_after_place_node = function(pos)
local up_node = minetest.get_node({x=pos.x, y=pos.y+1, z=pos.z})
local up_def = minetest.registered_nodes[up_node.name]
@ -44,11 +44,16 @@ local silver_chain_on_construct = function(pos)
end
end
local silver_chandelier_on_construct = function(pos)
local silver_chandelier_after_place_node = function(pos, placer)
local up_node = minetest.get_node({x=pos.x, y=pos.y+1, z=pos.z})
if minetest.get_item_group(up_node.name, "multidecor_silver_chain") == 0 then
local put_item = ItemStack(minetest.get_node(pos).name)
minetest.remove_node(pos)
placer:get_inventory():add_item("main", put_item)
return put_item
end
end
@ -64,7 +69,7 @@ minetest.register_node(":multidecor:silver_chain", {
sounds = default.node_sound_metal_defaults(),
collision_box = silver_chain_bbox,
selection_box = silver_chain_bbox,
on_construct = silver_chain_on_construct
after_place_node = silver_chain_after_place_node
})
minetest.register_node(":multidecor:silver_chain_tip", {
@ -164,7 +169,7 @@ multidecor.register.register_light("gold_chandelier_with_glass_candles_off", {
{-0.5, -0.5, -0.5, 0.5, 0, 0.5}
},
callbacks = {
on_construct = silver_chandelier_on_construct
after_place_node = silver_chandelier_after_place_node
}
},
{