Fix backwards rotation and add fast node filling

master
Johannes Fritz 2022-07-29 07:59:40 -05:00
parent 3e0ed1273b
commit 72457e934c
3 changed files with 100 additions and 36 deletions

View File

@ -27,7 +27,7 @@ This mod was inspired by the Fill Start and Fill End blocks in Manic Digger.
| Undo | edit:undo | ![](textures/edit_undo.png) |
## Dependences
## Dependencies
None
@ -43,17 +43,17 @@ When two copy nodes are placed at opposite corners of an area, they select the a
### Paste Node
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 visable by pressing the sneak key and an arrow key.
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.
### Delete Node
Delete nodes are used to delete an 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.
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
![figure1.png](figure2.png)
![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 figure 2.
@ -77,7 +77,30 @@ Use a second time to redo the undo.
Only the most resent world modification can be undone.
### License
## Settings
### edit_paste_preview_max_entities
If the copied area has a larger number of nodes, some nodes will be randomly excluded from the preview.
### edit_max_operation_volume
The maximum volume of any edit operation. Increase to allow larger operations.
### edit_use_fast_node_fill
Fast filling of nodes. This uses VoxelManip for fast node placement.
No node placement callbacks are called so some nodes might be broken.
## Privileges
Edit tools and nodes can only be used by players with `edit` privilege.
## License
CC0 by MrRar check [License](LICENSE) file, this mod was started by MrRar,
minetest-mods community.

View File

@ -4,8 +4,9 @@
local player_data = {}
local paste_preview_max_entities = tonumber(minetest.settings:get("paste_preview_max_entities") or 2000)
local max_operation_volume = tonumber(minetest.settings:get("max_operation_volume") or 20000)
local paste_preview_max_entities = tonumber(minetest.settings:get("edit_paste_preview_max_entities") or 2000)
local max_operation_volume = tonumber(minetest.settings:get("edit_max_operation_volume") or 20000)
local use_fast_node_fill = minetest.settings:get_bool("edit_use_fast_node_fill", false)
local function create_paste_preview(player)
local player_pos = player:get_pos()
@ -135,10 +136,15 @@ local function has_privilege(player)
end
end
local function display_size_error(player)
local msg = "Operation too large. The maximum operation volume can be changed in Minetest settings."
minetest.chat_send_player(player:get_player_name(), msg)
end
local function on_place_checks(player)
return player and
player:is_player() and
has_privilege(player)
player:is_player() and
has_privilege(player)
end
@ -200,7 +206,7 @@ minetest.register_node("edit:delete", {
)
local size = vector.add(vector.subtract(_end, start), 1)
if size.x * size.y * size.z > max_operation_volume then
minetest.chat_send_player(player:get_player_name(), "Delete operation too big.")
display_size_error(player)
return
end
player_data[player].undo_schematic = schematic_from_map(start, size)
@ -272,7 +278,7 @@ minetest.register_node("edit:copy",{
local size = vector.add(vector.subtract(_end, start), vector.new(1, 1, 1))
if size.x * size.y * size.z > max_operation_volume then
minetest.chat_send_player(player:get_player_name(), "Copy operation too big.")
display_size_error(player)
return
end
@ -444,6 +450,16 @@ minetest.register_node("edit:fill",{
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
@ -529,9 +545,9 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
local is_node = minetest.registered_nodes[name]
local param2
if def.paramtype2 == "facedir" then
if def.paramtype2 == "facedir" or def.paramtype2 == "colorfacedir" then
param2 = minetest.dir_to_facedir(player:get_look_dir())
elseif def.paramtype2 == "wallmounted" then
elseif def.paramtype2 == "wallmounted" or def.paramtype2 == "colorwallmounted" then
param2 = minetest.dir_to_wallmounted(player:get_look_dir(), true)
end
@ -549,27 +565,46 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
)
local size = vector.add(vector.subtract(_end, start), 1)
if size.x * size.y * size.z > max_operation_volume then
minetest.chat_send_player(player:get_player_name(), "Fill operation too large.")
return true
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
local pos = vector.new(x, y, z)
if is_node then
minetest.set_node(pos, {name = name, param2 = param2})
else
minetest.remove_node(pos)
end
if on_place then
local itemstack = ItemStack(name)
pointed_thing.intersection_point = vector.new(x + 0.5, y, z + 0.5)
pointed_thing.above = pos
pointed_thing.below = vector.new(x, y - 1, z)
on_place(itemstack, player, pointed_thing)
if is_node and use_fast_node_fill then
local voxel_manip = VoxelManip()
local vm_start, vm_end = voxel_manip:read_from_map(start, _end)
local param2s = voxel_manip:get_param2_data()
local content_ids = voxel_manip:get_data()
local content_id = minetest.get_content_id(name)
local ones = vector.new(1, 1, 1)
local vm_size = vector.add(vector.subtract(vm_end, vm_start), ones)
local voxel_area = VoxelArea:new({MinEdge = ones, MaxEdge = vm_size})
local va_start = vector.add(vector.subtract(start, vm_start), ones)
local va_end = vector.subtract(vector.add(va_start, size), ones)
for i in voxel_area:iterp(va_start, va_end) do
content_ids[i] = content_id
param2s[i] = param2
end
voxel_manip:set_data(content_ids)
voxel_manip:set_param2_data(param2s)
voxel_manip:write_to_map(true)
voxel_manip:update_liquids()
else
for x = start.x, _end.x, 1 do
for y = start.y, _end.y, 1 do
for z = start.z, _end.z, 1 do
local pos = vector.new(x, y, z)
if is_node then
minetest.set_node(pos, {name = name, param2 = param2})
else
minetest.remove_node(pos)
end
if on_place then
local itemstack = ItemStack(name)
pointed_thing.intersection_point = vector.new(x + 0.5, y, z + 0.5)
pointed_thing.above = pos
pointed_thing.below = vector.new(x, y - 1, z)
on_place(itemstack, player, pointed_thing)
end
end
end
end
@ -804,13 +839,13 @@ minetest.register_globalstep(function(dtime)
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)
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)
set_schematic_rotation(d.schematic, -90)
delete_paste_preview(player)
d.paste_preview_can_rotate = false
end

View File

@ -1,4 +1,10 @@
# The maximum number of entities used to construct the paste preview.
# If the copied area has a larger number of nodes, some nodes will be randomly excluded from the preview.
edit_paste_preview_max_entities (Paste preview max entities) int 2000
paste_preview_max_entities (Paste preview max entities) int 2000
# The maximum volume of any edit operation. Increase to allow larger operations.
edit_max_operation_volume (Max edit operation volume) int 20000
max_operation_volume (Max edit operation volume) int 20000
# Fast filling of nodes. This uses VoxelManip for fast node placement.
# No node placement callbacks are called so some nodes might be broken.
edit_use_fast_node_fill (Use fast node fill) bool false