1.1 update

This commit is contained in:
Johannes Fritz 2023-02-14 15:29:44 -06:00
parent 546c23f3db
commit 6d67c9a769
5 changed files with 267 additions and 293 deletions

View File

@ -8,7 +8,7 @@
This mod named `edit` allows copying, pasting, filling, deleting, opening and saving 3D areas. This mod named `edit` allows copying, pasting, filling, deleting, opening and saving 3D areas.
Schematics are loaded and saved from .mts files located in the world subfolder `schems`. Schematics are loaded and saved from .mts files located in the world sub folder `schems`.
This mod was inspired by the Fill Start and Fill End blocks in Manic Digger. This mod was inspired by the Fill Start and Fill End blocks in Manic Digger.
@ -16,12 +16,11 @@ This mod was inspired by the Fill Start and Fill End blocks in Manic Digger.
## Items ## Items
| Name | Node ID | Image | | Name | Item ID | Image |
| ------ | ----------- | ----------------------------- | | ------ | ----------- | ----------------------------- |
| Copy | edit:copy | ![](textures/edit_copy.png) | | Copy | edit:copy | ![](textures/edit_copy.png) |
| Paste | edit:paste | ![](textures/edit_paste.png) | | Paste | edit:paste | ![](textures/edit_paste.png) |
| Fill | edit:fill | ![](textures/edit_fill.png) | | Fill | edit:fill | ![](textures/edit_fill.png) |
| Delete | edit:delete | ![](textures/edit_delete.png) |
| Open | edit:open | ![](textures/edit_open.png) | | Open | edit:open | ![](textures/edit_open.png) |
| Save | edit:save | ![](textures/edit_save.png) | | Save | edit:save | ![](textures/edit_save.png) |
| Undo | edit:undo | ![](textures/edit_undo.png) | | Undo | edit:undo | ![](textures/edit_undo.png) |
@ -34,28 +33,21 @@ None
## Usage ## Usage
### Copy Node ### Copy Tool
![figure1.png](figure1.png) ![figure.png](figure.png)
When two copy nodes are placed at opposite corners of an area, they select the area as show in figure 1. When an area is selected, it is copied and the two copy nodes are deleted. When the copy tool is placed at opposite corners of an area, they select the area as show in the figure. The copy tool uses the location under the placed position. When the copy tool is placed for the first time, a marker entity is placed. To cancel the copy operation, punch the entity marker. When a copy tool is placed a second time, the selected area is copied and the entity marker is removed.
### Paste Node ### Paste Tool
The paste node is used for pasting the area copied by the copy node or a schematic loaded with the open node. When a paste node is placed, the copied area or schematic is placed at the corner of the paste node. In the case of a copied area, area is pasted relative to the position of the first placed copy node when it was copied. The copied area can be rotated when the paste preview is visible by pressing the sneak key and an arrow key. The paste tool is used for pasting the area copied by the copy tool or a schematic loaded with the open tool. When a paste tool is placed, the copied area or schematic is placed at the corner of the paste tool. The copied area can be rotated by punching while holding the paste tool.
### Delete Node
Delete nodes are used to delete a 3D area. When two delete nodes are placed at opposite corners of an area, they select the area as show in figure 1. When an area is selected, it is deleted and the two delete nodes are removed as well.
### Fill Node ### Fill Node
![figure2.png](figure2.png) Fill nodes are used to fill a 3D area with a certain item. Start by placing two fill nodes at opposite corners of the desired area. The selected area includes the positions of the fill nodes themselves as shown in the figure.
Fill nodes are used to fill a 3D area with a certain item. Start by placing two fill nodes at opposite corners of the desired area. The selected area includes the positions of the fill nodes themselves as shown in figure 2.
Once a second fill node is placed, a dialog appears listing all items in the players inventory. Clicking an item will cause it to be used used for filling the selected area. Clicking on a blank slot will cause the selected area to be filled with air. To cancel the fill, press the "X". Once a second fill node is placed, a dialog appears listing all items in the players inventory. Clicking an item will cause it to be used used for filling the selected area. Clicking on a blank slot will cause the selected area to be filled with air. To cancel the fill, press the "X".

BIN
figure.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

536
init.lua
View File

@ -1,5 +1,5 @@
------------------- -------------------
-- Edit Mod v1.0 -- -- Edit Mod v1.1 --
------------------- -------------------
local player_data = {} local player_data = {}
@ -71,12 +71,6 @@ local function set_schematic_rotation(schematic, angle)
if schematic._rotation == 90 or schematic._rotation == 270 then if schematic._rotation == 90 or schematic._rotation == 270 then
size = vector.new(size.z, size.y, size.x) size = vector.new(size.z, size.y, size.x)
end end
local sign = vector.apply(schematic._offset, math.sign)
schematic._offset = vector.apply(
vector.multiply(size, sign),
function(n) return n < 0 and n or 1 end
)
--[[local old_schematic = player_data[player].schematic --[[local old_schematic = player_data[player].schematic
local new_schematic = {data = {}} local new_schematic = {data = {}}
player_data[player].schematic = new_schematic player_data[player].schematic = new_schematic
@ -147,7 +141,6 @@ local function on_place_checks(player)
has_privilege(player) has_privilege(player)
end end
local function schematic_from_map(pos, size) local function schematic_from_map(pos, size)
local schematic = {data = {}} local schematic = {data = {}}
schematic.size = size schematic.size = size
@ -167,141 +160,103 @@ local function schematic_from_map(pos, size)
return schematic return schematic
end end
minetest.register_node("edit:delete", { local function get_pointed_thing_node(player)
description = "Edit Delete", local look_dir = player:get_look_dir()
inventory_image = "edit_delete.png", local pos1 = player:get_pos()
groups = {snappy = 2, oddly_breakable_by_hand = 3}, local eye_height = player:get_properties().eye_height
tiles = {"edit_delete.png"}, pos1.y = pos1.y + eye_height
range = 10, local pos2 = vector.add(pos1, vector.multiply(look_dir, 10))
on_place = function(itemstack, player, pointed_thing) local ray = minetest.raycast(pos1, pos2, false, false)
if not on_place_checks(player) then return end for pointed_thing in ray do
if pointed_thing.under then
local itemstack, pos = minetest.item_place_node(itemstack, player, pointed_thing) return pointed_thing
if player_data[player].delete_node1_pos and pos then
local p1 = player_data[player].delete_node1_pos
player_data[player].delete_node1_pos = nil
local p2 = pos
minetest.remove_node(p1)
minetest.remove_node(p2)
-- Is the volume of the selected area 0?
local test = vector.apply(vector.subtract(p2, p1), math.abs)
if test.x <= 1 or test.y <= 1 or test.z <= 1 then return end
local sign = vector.new(vector.apply(vector.subtract(p2, p1), math.sign))
p1 = vector.add(p1, sign)
p2 = vector.add(p2, vector.multiply(sign, -1))
local start = vector.new(
math.min(p1.x, p2.x),
math.min(p1.y, p2.y),
math.min(p1.z, p2.z)
)
local _end = vector.new(
math.max(p1.x, p2.x),
math.max(p1.y, p2.y),
math.max(p1.z, p2.z)
)
local size = vector.add(vector.subtract(_end, start), 1)
if size.x * size.y * size.z > max_operation_volume then
display_size_error(player)
return
end
player_data[player].undo_schematic = schematic_from_map(start, size)
for x = start.x, _end.x, 1 do
for y = start.y, _end.y, 1 do
for z = start.z, _end.z, 1 do
minetest.remove_node(vector.new(x, y, z))
end
end
end
elseif pos then
player_data[player].delete_node1_pos = pos
end
end,
on_destruct = function(pos)
for player, data in pairs(player_data) do
if
data.delete_node1_pos and
vector.equals(data.delete_node1_pos, pos)
then
data.delete_node1_pos = nil
break
end
end end
end end
}) local pos = vector.round(pos2)
return { type = "node", under = pos, above = pos }
end
minetest.register_node("edit:copy",{ local function copy_on_place(itemstack, player, pointed_thing)
if not on_place_checks(player) then return end
if not pointed_thing.under then
pointed_thing = get_pointed_thing_node(player)
end
local pos = pointed_thing.under
if player_data[player].copy_luaentity1 and pos then
local p1 = player_data[player].copy_luaentity1._pos
local p2 = pos
player_data[player].copy_luaentity1.object:remove()
player_data[player].copy_luaentity1 = nil
local start = vector.new(
math.min(p1.x, p2.x),
math.min(p1.y, p2.y),
math.min(p1.z, p2.z)
)
local _end = vector.new(
math.max(p1.x, p2.x),
math.max(p1.y, p2.y),
math.max(p1.z, p2.z)
)
local size = vector.add(vector.subtract(_end, start), vector.new(1, 1, 1))
if size.x * size.y * size.z > max_operation_volume then
display_size_error(player)
return
end
player_data[player].schematic = schematic_from_map(start, size)
player_data[player].schematic._offset = vector.new(0, 0, 0)
delete_paste_preview(player)
local function vector_to_string(v) return "(" .. v.x .. ", " .. v.y .. ", " .. v.z .. ")" end
minetest.chat_send_player(
player:get_player_name(),
vector_to_string(start) .. " to " .. vector_to_string(_end) .. " copied." )
else
local obj_ref = minetest.add_entity(pos, "edit:copy")
if not obj_ref then return end
local luaentity = obj_ref:get_luaentity()
luaentity._pos = pos
luaentity._placer = player
player_data[player].copy_luaentity1 = luaentity
end
end
minetest.register_tool("edit:copy",{
description = "Edit Copy", description = "Edit Copy",
tiles = {"edit_copy.png"}, tiles = {"edit_copy.png"},
inventory_image = "edit_copy.png", inventory_image = "edit_copy.png",
groups = {snappy = 2, oddly_breakable_by_hand = 3}, groups = {snappy = 2, oddly_breakable_by_hand = 3},
range = 10, range = 10,
on_place = function(itemstack, player, pointed_thing) on_place = copy_on_place,
if not on_place_checks(player) then return end on_secondary_use = copy_on_place,
})
local itemstack, pos = minetest.item_place_node(itemstack, player, pointed_thing)
minetest.register_entity("edit:copy", {
if player_data[player].copy_node1_pos and pos then initial_properties = {
local p1 = player_data[player].copy_node1_pos visual = "cube",
local p2 = pos visual_size = { x = 1.1, y = 1.1},
physical = false,
player_data[player].copy_node1_pos = nil collide_with_objects = false,
minetest.remove_node(p1) static_save = false,
minetest.remove_node(p2) use_texture_alpha = true,
glow = -1,
local diff = vector.subtract(p2, p1) backface_culling = false,
hp_max = 1,
-- Is the volume of the selected area 0? textures = {
local test = vector.apply(diff, math.abs) "edit_copy.png",
if test.x <= 1 or test.y <= 1 or test.z <= 1 then return itemstack end "edit_copy.png",
"edit_copy.png",
local sign = vector.apply(vector.subtract(p2, p1), math.sign) "edit_copy.png",
p1 = vector.add(p1, sign) "edit_copy.png",
p2 = vector.add(p2, vector.multiply(sign, -1)) "edit_copy.png",
},
local start = vector.new( },
math.min(p1.x, p2.x), on_death = function(self, killer)
math.min(p1.y, p2.y), player_data[self._placer].copy_luaentity1 = nil
math.min(p1.z, p2.z)
)
local _end = vector.new(
math.max(p1.x, p2.x),
math.max(p1.y, p2.y),
math.max(p1.z, p2.z)
)
local size = vector.add(vector.subtract(_end, start), vector.new(1, 1, 1))
if size.x * size.y * size.z > max_operation_volume then
display_size_error(player)
return
end
player_data[player].schematic = schematic_from_map(start, size)
player_data[player].schematic._offset = vector.apply(
diff,
function(n) return n < 0 and n + 1 or 1 end
)
delete_paste_preview(player)
elseif pos then
player_data[player].copy_node1_pos = pos
end
end, end,
on_destruct = function(pos)
for player, data in pairs(player_data) do
if
data.copy_node1_pos and
vector.equals(data.copy_node1_pos, pos)
then
data.copy_node1_pos = nil
break
end
end
end
}) })
local function pointed_thing_to_pos(pointed_thing) local function pointed_thing_to_pos(pointed_thing)
@ -320,33 +275,56 @@ local function pointed_thing_to_pos(pointed_thing)
end end
end end
local function paste_on_place(itemstack, player, pointed_thing)
if not on_place_checks(player) then return end
if not pointed_thing.above then
pointed_thing = get_pointed_thing_node(player)
end
if not player_data[player].schematic then
minetest.chat_send_player(player:get_player_name(), "Nothing to paste.")
return
end
local schematic = player_data[player].schematic
local pos = pointed_thing_to_pos(pointed_thing)
if not pos then return end
local pos = vector.add(pos, schematic._offset)
local size = schematic.size
if schematic._rotation == 90 or schematic._rotation == 270 then
size = vector.new(size.z, size.y, size.x)
end
player_data[player].undo_schematic = schematic_from_map(pos, size)
minetest.place_schematic(pos, schematic, tostring(schematic._rotation or 0), nil, true)
end
minetest.register_tool("edit:paste", { minetest.register_tool("edit:paste", {
description = "Edit Paste", description = "Edit Paste",
tiles = {"edit_paste.png"}, tiles = {"edit_paste.png"},
inventory_image = "edit_paste.png", inventory_image = "edit_paste.png",
groups = {snappy = 2, oddly_breakable_by_hand = 3}, groups = {snappy = 2, oddly_breakable_by_hand = 3},
range = 10, range = 10,
on_place = function(itemstack, player, pointed_thing) on_place = paste_on_place,
if not on_place_checks(player) then return end on_secondary_use = paste_on_place,
on_use = function(itemstack, player, pointed_thing)
if not player_data[player].schematic then local d = player_data[player]
minetest.chat_send_player(player:get_player_name(), "Nothing to paste.") if not d.schematic then return end
return set_schematic_rotation(d.schematic, 90)
end delete_paste_preview(player)
local schematic = player_data[player].schematic
local pos = pointed_thing_to_pos(pointed_thing)
if not pos then return end
local pos = vector.add(pos, schematic._offset)
local size = schematic.size
if schematic._rotation == 90 or schematic._rotation == 270 then
size = vector.new(size.z, size.y, size.x)
end
player_data[player].undo_schematic = schematic_from_map(pos, size)
minetest.place_schematic(pos, schematic, tostring(schematic._rotation or 0), nil, true)
end end
}) })
local function reliable_show_formspec(player, name, formspec)
-- We need to do this nonsense because there is bug in Minetest
-- Sometimes no formspec is shown if you call minetest.show_formspec
-- from minetest.register_on_player_receive_fields
minetest.after(0.1, function()
if not player or not player:is_player() then return end
minetest.show_formspec(player:get_player_name(), name, formspec)
end)
end
local function delete_schematics_dialog(player) local function delete_schematics_dialog(player)
local path = minetest.get_worldpath() .. "/schems" local path = minetest.get_worldpath() .. "/schems"
local dir_list = minetest.get_dir_list(path) local dir_list = minetest.get_dir_list(path)
@ -358,52 +336,48 @@ local function delete_schematics_dialog(player)
reliable_show_formspec(player, "edit:delete_schem", formspec) reliable_show_formspec(player, "edit:delete_schem", formspec)
end end
local function open_on_place(itemstack, player, pointed_thing)
if not on_place_checks(player) then return end
local path = minetest.get_worldpath() .. "/schems"
local dir_list = minetest.get_dir_list(path)
if #path > 40 then path = "..." .. path:sub(#path - 40, #path) end
local formspec = "size[10,10]label[0.5,0.5;Load a schematic into copy buffer from:\n" ..
minetest.formspec_escape(path) .. "]button_exit[9,0;1,1;quit;X]" ..
"textlist[0.5,2;9,7;schems;" .. table.concat(dir_list, ",") .. "]" ..
"button_exit[3,9.25;4,1;delete;Delete schematics...]"
minetest.show_formspec(player:get_player_name(), "edit:open", formspec)
end
minetest.register_tool("edit:open",{ minetest.register_tool("edit:open",{
description = "Edit Open", description = "Edit Open",
inventory_image = "edit_open.png", inventory_image = "edit_open.png",
range = 10, range = 10,
on_place = function(itemstack, player, pointed_thing) on_place = open_on_place,
if not on_place_checks(player) then return end on_secondary_use = open_on_place
local path = minetest.get_worldpath() .. "/schems"
local dir_list = minetest.get_dir_list(path)
if #path > 40 then path = "..." .. path:sub(#path - 40, #path) end
local formspec = "size[10,10]label[0.5,0.5;Load a schematic into copy buffer from:\n" ..
minetest.formspec_escape(path) .. "]button_exit[9,0;1,1;quit;X]" ..
"textlist[0.5,2;9,7;schems;" .. table.concat(dir_list, ",") .. "]" ..
"button_exit[3,9.25;4,1;delete;Delete schematics...]"
minetest.show_formspec(player:get_player_name(), "edit:open", formspec)
end
}) })
local function undo_on_place(itemstack, player, pointed_thing)
if not on_place_checks(player) then return end
local schem = player_data[player].undo_schematic
if schem then
player_data[player].undo_schematic = schematic_from_map(schem._pos, schem.size)
minetest.place_schematic(schem._pos, schem, nil, nil, true)
else
minetest.chat_send_player(player:get_player_name(), "Nothing to undo.")
end
end
minetest.register_tool("edit:undo",{ minetest.register_tool("edit:undo",{
description = "Edit Undo", description = "Edit Undo",
inventory_image = "edit_undo.png", inventory_image = "edit_undo.png",
range = 10, range = 10,
on_place = function(itemstack, player, pointed_thing) on_place = undo_on_place,
if not on_place_checks(player) then return end on_secondary_use = undo_on_place
local schem = player_data[player].undo_schematic
if schem then
player_data[player].undo_schematic = schematic_from_map(schem._pos, schem.size)
minetest.place_schematic(schem._pos, schem, nil, nil, true)
else
minetest.chat_send_player(player:get_player_name(), "Nothing to undo.")
end
end
}) })
function reliable_show_formspec(player, name, formspec)
-- We need to do this nonsense because there is bug in Minetest
-- Sometimes no formspec is shown if you call minetest.show_formspec
-- from minetest.register_on_player_receive_fields
minetest.after(0.1, function()
if not player or not player:is_player() then return end
minetest.show_formspec(player:get_player_name(), name, formspec)
end)
end
local function show_save_dialog(player, filename, save_error) local function show_save_dialog(player, filename, save_error)
if not player_data[player].schematic then if not player_data[player].schematic then
minetest.chat_send_player(player:get_player_name(), "Nothing to save.") minetest.chat_send_player(player:get_player_name(), "Nothing to save.")
@ -433,53 +407,63 @@ minetest.register_tool("edit:save",{
range = 10, range = 10,
on_place = function(itemstack, player, pointed_thing) on_place = function(itemstack, player, pointed_thing)
if on_place_checks(player) then show_save_dialog(player) end if on_place_checks(player) then show_save_dialog(player) end
end,
on_secondary_use = function(itemstack, player, pointed_thing)
if on_place_checks(player) then show_save_dialog(player) end
end end
}) })
local function fill_on_place(itemstack, player, pointed_thing)
if not on_place_checks(player) then return end
if not pointed_thing.above then
pointed_thing = get_pointed_thing_node(player)
end
local itemstack, pos = minetest.item_place_node(itemstack, player, pointed_thing)
if player_data[player].fill1_pos and pos then
local diff = vector.subtract(player_data[player].fill1_pos, pos)
local size = vector.add(vector.apply(diff, math.abs), 1)
if size.x * size.y * size.z > max_operation_volume then
display_size_error(player)
minetest.remove_node(player_data[player].fill1_pos)
player_data[player].fill1_pos = nil
minetest.remove_node(pos)
return
end
player_data[player].fill2_pos = pos
player_data[player].fill_pointed_thing = pointed_thing
local inv = minetest.get_inventory({type = "player", name = player:get_player_name()})
local formspec = "size[8,6]label[2,0.5;Select item for filling]button_exit[7,0;1,1;quit;X]"
for y = 1, 4 do
for x = 1, 8 do
local name = inv:get_stack("main", ((y - 1) * 8) + x):get_name()
formspec =
formspec ..
"item_image_button[" ..
(x - 1) .. "," ..
(y + 1) .. ";1,1;" ..
name .. ";" ..
name .. ";]"
end
end
minetest.show_formspec(player:get_player_name(), "edit:fill", formspec)
elseif pos then
player_data[player].fill1_pos = pos
end
end
minetest.register_node("edit:fill",{ minetest.register_node("edit:fill",{
description = "Edit Fill", description = "Edit Fill",
tiles = {"edit_fill.png"}, tiles = {"edit_fill.png"},
inventory_image = "edit_fill.png", inventory_image = "edit_fill.png",
groups = {snappy = 2, oddly_breakable_by_hand = 3}, groups = {snappy = 2, oddly_breakable_by_hand = 3, dig_immediate = 3},
range = 10, range = 10,
on_place = function(itemstack, player, pointed_thing) on_place = fill_on_place,
if not on_place_checks(player) then return end on_secondary_use = fill_on_place,
local itemstack, pos = minetest.item_place_node(itemstack, player, pointed_thing)
if player_data[player].fill1_pos and pos then
local diff = vector.subtract(player_data[player].fill1_pos, pos)
local size = vector.add(vector.apply(diff, math.abs), 1)
if size.x * size.y * size.z > max_operation_volume then
display_size_error(player)
minetest.remove_node(player_data[player].fill1_pos)
player_data[player].fill1_pos = nil
minetest.remove_node(pos)
return
end
player_data[player].fill2_pos = pos
player_data[player].fill_pointed_thing = pointed_thing
local inv = minetest.get_inventory({type = "player", name = player:get_player_name()})
local formspec = "size[8,6]label[2,0.5;Select item for filling]button_exit[7,0;1,1;quit;X]"
for y = 1, 4 do
for x = 1, 8 do
local name = inv:get_stack("main", ((y - 1) * 8) + x):get_name()
formspec =
formspec ..
"item_image_button[" ..
(x - 1) .. "," ..
(y + 1) .. ";1,1;" ..
name .. ";" ..
name .. ";]"
end
end
minetest.show_formspec(player:get_player_name(), "edit:fill", formspec)
elseif pos then
player_data[player].fill1_pos = pos
end
end,
on_destruct = function(pos) on_destruct = function(pos)
for player, data in pairs(player_data) do for player, data in pairs(player_data) do
local p1 = data.fill1_pos local p1 = data.fill1_pos
@ -526,7 +510,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
local def local def
for key, val in pairs(fields) do for key, val in pairs(fields) do
if key == "quit" then return true end if key == "quit" then return true end
if key == "" then item = "air" end if key == "" then key = "air" end
name = key name = key
def = minetest.registered_items[name] def = minetest.registered_items[name]
@ -632,8 +616,8 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
local schematic = minetest.read_schematic(file_path, {}) local schematic = minetest.read_schematic(file_path, {})
if not schematic then return true end if not schematic then return true end
player_data[player].schematic = schematic player_data[player].schematic = schematic
player_data[player].schematic._offset = vector.new(1, 1, 1) player_data[player].schematic._offset = vector.new(0, 0, 0)
minetest.chat_send_player(player:get_player_name(), dir_list[index] .. " loaded.") minetest.chat_send_player(player:get_player_name(), "\"" .. dir_list[index] .. "\" loaded.")
delete_paste_preview(player) delete_paste_preview(player)
end end
return true return true
@ -672,7 +656,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
end end
f:write(mts); f:write(mts);
f:close() f:close()
minetest.chat_send_player(player:get_player_name(), schem_filename .. " saved.") minetest.chat_send_player(player:get_player_name(), "\"" .. schem_filename .. "\" saved.")
return true return true
elseif formname == "edit:delete_schem" then elseif formname == "edit:delete_schem" then
if if
@ -720,14 +704,6 @@ minetest.register_entity("edit:select_preview", {
use_texture_alpha = true, use_texture_alpha = true,
glow = -1, glow = -1,
backface_culling = false, backface_culling = false,
textures = {
"edit_select_preview.png",
"edit_select_preview.png",
"edit_select_preview.png",
"edit_select_preview.png",
"edit_select_preview.png",
"edit_select_preview.png",
},
} }
}) })
@ -777,7 +753,7 @@ local function show_paste_preview(player)
d.paste_preview:set_detach() d.paste_preview:set_detach()
d.paste_preview_hud = player:hud_add({ d.paste_preview_hud = player:hud_add({
hud_elem_type = "text", hud_elem_type = "text",
text = "Press sneak + right or left to rotate.", text = "Punch (left click) to rotate.",
position = {x = 0.5, y = 0.8}, position = {x = 0.5, y = 0.8},
z_index = 100, z_index = 100,
number = 0xffffff number = 0xffffff
@ -794,18 +770,6 @@ local function show_paste_preview(player)
) )
end end
local function get_player_pointed_thing_pos(player)
local look_dir = player:get_look_dir()
local pos1 = player:get_pos()
local eye_height = player:get_properties().eye_height
pos1.y = pos1.y + eye_height
local pos2 = vector.add(pos1, vector.multiply(look_dir, 10))
local pointed_thing = minetest.raycast(pos1, pos2, false, false):next()
if pointed_thing then
return pointed_thing_to_pos(pointed_thing)
end
end
local function hide_select_preview(player) local function hide_select_preview(player)
local d = player_data[player] local d = player_data[player]
d.select_preview_shown = false d.select_preview_shown = false
@ -813,6 +777,37 @@ local function hide_select_preview(player)
d.select_preview:set_attach(player) d.select_preview:set_attach(player)
end end
local function set_select_preview_size(preview, size)
local preview_size = vector.add(size, vector.new(0.01, 0.01, 0.01))
local function combine(width, height)
local tex = ""
for x = 0, math.floor(width / 8) do
for y = 0, math.floor(height / 8) do
if #tex > 0 then tex = tex .. ":" end
tex = tex ..
(x * 8 * 16) ..
"," .. (y * 8 * 16) ..
"=edit_select_preview.png"
end
end
return "[combine:" .. (width * 16) .. "x" .. (height * 16) .. ":" .. tex
end
local x_tex = combine(size.z, size.y)
local y_tex = combine(size.x, size.z)
local z_tex = combine(size.x, size.y)
preview:set_properties({
visual_size = preview_size,
textures = {
y_tex, y_tex,
x_tex, x_tex,
z_tex, z_tex
}
})
end
minetest.register_globalstep(function(dtime) minetest.register_globalstep(function(dtime)
for _, player in pairs(minetest.get_connected_players()) do for _, player in pairs(minetest.get_connected_players()) do
local item = player:get_wielded_item():get_name() local item = player:get_wielded_item():get_name()
@ -820,7 +815,7 @@ minetest.register_globalstep(function(dtime)
-- Paste preview -- Paste preview
if item == "edit:paste" and d.schematic then if item == "edit:paste" and d.schematic then
local pos = get_player_pointed_thing_pos(player) local pos = pointed_thing_to_pos(get_pointed_thing_node(player))
if pos then if pos then
if not d.paste_preview or not d.paste_preview:get_pos() then if not d.paste_preview or not d.paste_preview:get_pos() then
create_paste_preview(player) create_paste_preview(player)
@ -832,52 +827,40 @@ minetest.register_globalstep(function(dtime)
if not vector.equals(old_pos, pos) then if not vector.equals(old_pos, pos) then
player_data[player].paste_preview:set_pos(pos) player_data[player].paste_preview:set_pos(pos)
end end
local control = player:get_player_control()
if control.sneak and control.left then
if d.paste_preview_can_rotate then
set_schematic_rotation(d.schematic, 90)
delete_paste_preview(player)
d.paste_preview_can_rotate = false
end
elseif control.sneak and control.right then
if d.paste_preview_can_rotate then
set_schematic_rotation(d.schematic, -90)
delete_paste_preview(player)
d.paste_preview_can_rotate = false
end
else d.paste_preview_can_rotate = true end
elseif d.paste_preview_hud then hide_paste_preview(player) end elseif d.paste_preview_hud then hide_paste_preview(player) end
elseif d.paste_preview_hud then hide_paste_preview(player) end elseif d.paste_preview_hud then hide_paste_preview(player) end
-- Select preview -- Select preview
local node1_pos local node1_pos
local node2_pos local node2_pos
local include_node_pos = false local use_under = false
if item == "edit:fill" and d.fill1_pos then if item == "edit:fill" and d.fill1_pos then
node1_pos = d.fill1_pos node1_pos = d.fill1_pos
if d.fill2_pos then node2_pos = d.fill2_pos end if d.fill2_pos then node2_pos = d.fill2_pos end
include_node_pos = true elseif item == "edit:copy" and d.copy_luaentity1 then
elseif item == "edit:copy" and d.copy_node1_pos then node1_pos = d.copy_luaentity1._pos
node1_pos = d.copy_node1_pos use_under = true
elseif item == "edit:delete" and d.delete_node1_pos then
node1_pos = d.delete_node1_pos
end end
if node1_pos then if node1_pos then
if not node2_pos then if not node2_pos then
node2_pos = get_player_pointed_thing_pos(player) local pointed_thing = get_pointed_thing_node(player)
if use_under then
node2_pos = pointed_thing.under
else
node2_pos = pointed_thing_to_pos(pointed_thing)
end
end end
if node2_pos then if node2_pos then
local diff = vector.subtract(node1_pos, node2_pos) local diff = vector.subtract(node1_pos, node2_pos)
local size = vector.apply(diff, math.abs) local size = vector.apply(diff, math.abs)
if include_node_pos then size = vector.add(size, vector.new(1, 1, 1)) size = vector.add(size, vector.new(1, 1, 1))
else size = vector.add(size, vector.new(-1, -1, -1)) end
local test = vector.apply(diff, math.abs) local test = vector.apply(diff, math.abs)
local has_volume = test.x > 1 and test.y > 1 and test.z > 1 local has_volume = test.x > 1 and test.y > 1 and test.z > 1
local size_too_big = size.x * size.y * size.z > max_operation_volume local size_too_big = size.x * size.y * size.z > max_operation_volume
if (include_node_pos or has_volume) and not size_too_big then if not size_too_big then
if not d.select_preview or not d.select_preview:get_pos() then if not d.select_preview or not d.select_preview:get_pos() then
d.select_preview = minetest.add_entity(node2_pos, "edit:select_preview") d.select_preview = minetest.add_entity(node2_pos, "edit:select_preview")
d.select_preview_shown = true d.select_preview_shown = true
@ -890,8 +873,7 @@ minetest.register_globalstep(function(dtime)
local preview = d.select_preview local preview = d.select_preview
if not vector.equals(preview_pos, preview:get_pos()) then if not vector.equals(preview_pos, preview:get_pos()) then
preview:set_pos(preview_pos) preview:set_pos(preview_pos)
local preview_size = vector.add(size, vector.new(0.01, 0.01, 0.01)) set_select_preview_size(preview, size)
preview:set_properties({visual_size = preview_size})
end end
elseif d.select_preview_shown then hide_select_preview(player) end elseif d.select_preview_shown then hide_select_preview(player) end
elseif d.select_preview_shown then hide_select_preview(player) end elseif d.select_preview_shown then hide_select_preview(player) end

Binary file not shown.

Before

Width:  |  Height:  |  Size: 209 KiB

After

Width:  |  Height:  |  Size: 202 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 B

After

Width:  |  Height:  |  Size: 353 B