add snapping to grid

This commit is contained in:
BuckarooBanzay 2024-03-09 12:07:13 +01:00
parent 6020a94ccf
commit 170d35b90d
3 changed files with 86 additions and 15 deletions

View File

@ -26,6 +26,7 @@ dofile(MP .. "/craft.lua")
dofile(MP .. "/record.lua")
dofile(MP .. "/playback.lua")
dofile(MP .. "/registry.lua")
dofile(MP .. "/snap.lua")
if minetest.get_modpath("mtt") and mtt.enabled then
dofile(MP .. "/configure.spec.lua")

View File

@ -3,19 +3,6 @@ local FORMSPEC_NAME = "pick_and_place:place"
local has_mapsync = minetest.get_modpath("mapsync")
local has_blockexchange = minetest.get_modpath("blockexchange")
local function get_pos(meta, player)
local size = minetest.string_to_pos(meta:get_string("size"))
local distance = vector.distance(vector.new(), size)
local radius = math.ceil(distance / 2)
local offset = vector.round(vector.divide(size, 2))
local pos1 = pick_and_place.get_pointed_position(player, radius + 2)
pos1 = vector.subtract(pos1, offset)
local pos2 = vector.add(pos1, vector.subtract(size, 1))
return pos1, pos2
end
-- notify supported mods of changes
local function notify_change(pos1, pos2)
if has_blockexchange then
@ -39,7 +26,8 @@ minetest.register_tool("pick_and_place:place", {
local controls = player:get_player_control()
local meta = itemstack:get_meta()
local pos1, pos2 = get_pos(meta, player)
local size = minetest.string_to_pos(meta:get_string("size"))
local pos1, pos2 = pick_and_place.get_placement_pos(size, player)
if controls.aux1 then
-- removal
@ -85,7 +73,8 @@ minetest.register_tool("pick_and_place:place", {
local controls = player:get_player_control()
local meta = itemstack:get_meta()
local pos1, pos2 = get_pos(meta, player)
local size = minetest.string_to_pos(meta:get_string("size"))
local pos1, pos2 = pick_and_place.get_placement_pos(size, player)
if controls.aux1 then
-- removal preview

81
snap.lua Normal file
View File

@ -0,0 +1,81 @@
-- playername -> pos
local origin_map = {}
-- playername -> size
local size_map = {}
-- TODO: persistence per player (load on join, save on set)
local function snap_axis(axis, origin, size, pos)
local half_size = math.ceil(size[axis] / 2)
-- delta from origin
local diff = pos[axis] - origin[axis]
local o = diff % size[axis]
if o >= half_size then
-- round up
pos[axis] = pos[axis] + (size[axis] - o)
elseif o > 0 then
-- round down
pos[axis] = pos[axis] - o
end
end
function pick_and_place.get_placement_pos(size, player)
local distance = vector.distance(vector.new(), size)
local radius = math.ceil(distance / 2)
local offset = vector.round(vector.divide(size, 2))
local playername = player:get_player_name()
local pos1 = pick_and_place.get_pointed_position(player, radius + 2)
pos1 = vector.subtract(pos1, offset)
local origin = origin_map[playername]
local snap_size = size_map[playername]
if origin and snap_size then
-- apply grid-snapping
snap_axis("x", origin, size, pos1)
snap_axis("y", origin, size, pos1)
snap_axis("z", origin, size, pos1)
end
local pos2 = vector.add(pos1, vector.subtract(size, 1))
return pos1, pos2
end
minetest.register_chatcommand("pnp_snap", {
params = "[on|off]",
description = "enable or disable grid snapping with the current placement tool dimensions and origin",
func = function(name, param)
if param == "on" then
-- enable grid
local player = minetest.get_player_by_name(name)
if not player then
return false, "player not found"
end
local itemstack = player:get_wielded_item()
if itemstack:get_name() ~= "pick_and_place:place" then
return false, "no placement tool selected"
end
local meta = itemstack:get_meta()
local size = minetest.string_to_pos(meta:get_string("size"))
local pos1 = pick_and_place.get_placement_pos(size, player)
origin_map[name] = pos1
size_map[name] = size
elseif param == "off" then
-- disable grid
origin_map[name] = nil
size_map[name] = nil
end
if origin_map[name] then
return true, "grid set with origin: " .. minetest.pos_to_string(origin_map[name]) ..
" and size: " .. minetest.pos_to_string(size_map[name])
else
return true, "grid disabled"
end
end
})