Add replace tool
This commit is contained in:
parent
dacddb58a1
commit
403a24e860
14
README.md
14
README.md
@ -21,6 +21,7 @@ This mod was inspired by the Fill Start and Fill End blocks in Manic Digger.
|
|||||||
| 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) |
|
||||||
|
| Replace | edit:replace | ![](textures/edit_replace.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) |
|
||||||
@ -48,11 +49,18 @@ When the copy tool is placed at opposite corners of an area, they select the are
|
|||||||
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.
|
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.
|
||||||
|
|
||||||
|
|
||||||
### Fill Node
|
### Fill Tool
|
||||||
|
|
||||||
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.
|
The fill tool is used to fill a 3D area with a certain item. Start by placing the fill tool two times at opposite corners of the desired area. The selected area includes the positions of the fill markers themselves as shown in the figure.
|
||||||
|
|
||||||
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 marker is placed, a dialog appears listing all items in the players inventory. A search field is also available to search all items. Clicking an item will cause it to be used used for filling the selected area. Clicking on a blank inventory slot will cause the selected area to be filled with air. To cancel the fill, press the "X".
|
||||||
|
|
||||||
|
|
||||||
|
### Replace Tool
|
||||||
|
|
||||||
|
The replace tool is used to replace certain nodes in a 3D area with a selected item. Start by placing the replace tool two times at opposite corners of the desired area. The selected area includes the positions of the replace markers themselves as shown in the figure.
|
||||||
|
|
||||||
|
Once a second replace marker is placed, a dialog appears listing all node types in the selected area. Check the nodes that should be replaced and then press the "OK" button to proceed with the next step. Next a dialog will pop up showing all the items in the players inventory. A search field is also available to search all items. Clicking an item will cause it to be used used to replace the nodes that were checked earlier. Clicking on a blank inventory slot will cause the checked nodes to be replaced with air. To cancel the replace, press the "X".
|
||||||
|
|
||||||
|
|
||||||
### Open Tool
|
### Open Tool
|
||||||
|
11
circle.lua
11
circle.lua
@ -1,7 +1,6 @@
|
|||||||
local function place_circle(player, pos, node)
|
local function place_circle(player, pos, node)
|
||||||
local player_data = edit.player_data[player]
|
local player_data = edit.player_data[player]
|
||||||
if
|
if
|
||||||
not player or
|
|
||||||
player:get_player_control().aux1 or
|
player:get_player_control().aux1 or
|
||||||
not player_data or
|
not player_data or
|
||||||
not player_data.circle_luaentity
|
not player_data.circle_luaentity
|
||||||
@ -70,15 +69,11 @@ end
|
|||||||
|
|
||||||
minetest.register_on_dignode(function(pos, oldnode, digger)
|
minetest.register_on_dignode(function(pos, oldnode, digger)
|
||||||
if not digger or not digger:is_player() then return end
|
if not digger or not digger:is_player() then return end
|
||||||
local player_data = edit.player_data[digger]
|
return place_circle(digger, pos, {name = "air"}) or true
|
||||||
if player_data.ignore_node_placement then return end
|
|
||||||
return place_circle(digger, pos, {name = "air"})
|
|
||||||
end)
|
end)
|
||||||
|
|
||||||
minetest.register_on_placenode(function(pos, newnode, placer, oldnode, itemstack, pointed_thing)
|
minetest.register_on_placenode(function(pos, newnode, placer, oldnode, itemstack, pointed_thing)
|
||||||
if not placer then return end
|
if not placer then return end
|
||||||
local player_data = edit.player_data[placer]
|
|
||||||
if player_data.ignore_node_placement then return end
|
|
||||||
return place_circle(placer, pos, newnode)
|
return place_circle(placer, pos, newnode)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
@ -108,8 +103,12 @@ minetest.register_tool("edit:circle",{
|
|||||||
tiles = {"edit_circle.png"},
|
tiles = {"edit_circle.png"},
|
||||||
inventory_image = "edit_circle.png",
|
inventory_image = "edit_circle.png",
|
||||||
range = 10,
|
range = 10,
|
||||||
|
groups = {edit_place_preview = 1,},
|
||||||
on_place = circle_tool_on_place,
|
on_place = circle_tool_on_place,
|
||||||
on_secondary_use = circle_tool_on_place,
|
on_secondary_use = circle_tool_on_place,
|
||||||
|
_edit_get_pointed_pos = function(player)
|
||||||
|
return edit.get_half_node_pointed_pos(player)
|
||||||
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_entity("edit:circle", {
|
minetest.register_entity("edit:circle", {
|
||||||
|
9
copy.lua
9
copy.lua
@ -45,10 +45,17 @@ 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},
|
|
||||||
range = 10,
|
range = 10,
|
||||||
|
groups = {edit_place_preview = 1,},
|
||||||
on_place = copy_on_place,
|
on_place = copy_on_place,
|
||||||
on_secondary_use = copy_on_place,
|
on_secondary_use = copy_on_place,
|
||||||
|
_edit_get_selection_points = function(player)
|
||||||
|
local d = edit.player_data[player]
|
||||||
|
return d.copy_luaentity1 and d.copy_luaentity1._pos
|
||||||
|
end,
|
||||||
|
_edit_get_pointed_pos = function(player)
|
||||||
|
return edit.get_pointed_thing_node(player).under
|
||||||
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_entity("edit:copy", {
|
minetest.register_entity("edit:copy", {
|
||||||
|
193
fill.lua
193
fill.lua
@ -1,120 +1,22 @@
|
|||||||
local function fill_on_place(itemstack, player, pointed_thing)
|
local function player_select_node_formspec(player)
|
||||||
if not edit.on_place_checks(player) then return end
|
edit.player_select_node(player, "Select item to use for fill", function(player, name)
|
||||||
|
|
||||||
if not pointed_thing.above then
|
|
||||||
pointed_thing = edit.get_pointed_thing_node(player)
|
|
||||||
end
|
|
||||||
|
|
||||||
local pos = edit.pointed_thing_to_pos(pointed_thing)
|
|
||||||
|
|
||||||
local player_data = edit.player_data[player]
|
|
||||||
if player_data.fill1 and pos then
|
|
||||||
player_data.fill2 = edit.add_marker("edit:fill", pos, player)
|
|
||||||
if not player_data.fill2 then return end
|
|
||||||
|
|
||||||
local diff = vector.subtract(player_data.fill1._pos, pos)
|
|
||||||
local size = vector.add(vector.apply(diff, math.abs), 1)
|
|
||||||
if size.x * size.y * size.z > edit.max_operation_volume then
|
|
||||||
edit.display_size_error(player)
|
|
||||||
player_data.fill1.object:remove()
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
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.fill1 = edit.add_marker("edit:fill", pos, player)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
minetest.register_tool("edit:fill", {
|
|
||||||
description = "Edit Fill",
|
|
||||||
tiles = {"edit_fill.png"},
|
|
||||||
inventory_image = "edit_fill.png",
|
|
||||||
range = 10,
|
|
||||||
on_place = fill_on_place,
|
|
||||||
on_secondary_use = fill_on_place,
|
|
||||||
})
|
|
||||||
|
|
||||||
minetest.register_entity("edit:fill", {
|
|
||||||
initial_properties = {
|
|
||||||
visual = "cube",
|
|
||||||
visual_size = { x = 1.1, y = 1.1 },
|
|
||||||
physical = false,
|
|
||||||
collide_with_objects = false,
|
|
||||||
static_save = false,
|
|
||||||
use_texture_alpha = true,
|
|
||||||
glow = -1,
|
|
||||||
backface_culling = false,
|
|
||||||
hp_max = 1,
|
|
||||||
textures = {
|
|
||||||
"edit_fill.png",
|
|
||||||
"edit_fill.png",
|
|
||||||
"edit_fill.png",
|
|
||||||
"edit_fill.png",
|
|
||||||
"edit_fill.png",
|
|
||||||
"edit_fill.png",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
on_deactivate = function(self)
|
|
||||||
local player_data = edit.player_data[self._placer]
|
|
||||||
self.remove_called = true
|
|
||||||
if player_data then
|
|
||||||
if player_data.fill1 and not player_data.fill1.remove_called then
|
|
||||||
player_data.fill1.object:remove()
|
|
||||||
end
|
|
||||||
if player_data.fill2 and not player_data.fill2.remove_called then
|
|
||||||
player_data.fill2.object:remove()
|
|
||||||
end
|
|
||||||
player_data.fill1 = nil
|
|
||||||
player_data.fill2 = nil
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
})
|
|
||||||
|
|
||||||
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
|
||||||
if formname ~= "edit:fill" then return false end
|
|
||||||
|
|
||||||
minetest.close_formspec(player:get_player_name(), "edit:fill")
|
|
||||||
|
|
||||||
local d = edit.player_data[player]
|
local d = edit.player_data[player]
|
||||||
|
|
||||||
if
|
if
|
||||||
not d.fill1 or not d.fill2 or
|
not d.fill1 or not d.fill2 or
|
||||||
not edit.has_privilege(player)
|
not edit.has_privilege(player)
|
||||||
then return true end
|
then return end
|
||||||
|
|
||||||
local p1 = d.fill1._pos
|
local p1 = d.fill1._pos
|
||||||
local p2 = d.fill2._pos
|
local p2 = d.fill2._pos
|
||||||
|
|
||||||
d.fill1.object:remove()
|
d.fill1.object:remove()
|
||||||
|
|
||||||
local name
|
if not name then return end
|
||||||
local def
|
|
||||||
for key, val in pairs(fields) do
|
|
||||||
if key == "quit" then return true end
|
|
||||||
if key == "" then key = "air" end
|
|
||||||
|
|
||||||
name = key
|
local def = minetest.registered_items[name]
|
||||||
def = minetest.registered_items[name]
|
|
||||||
|
|
||||||
if def then break end
|
if not def then return end
|
||||||
end
|
|
||||||
|
|
||||||
if not def then return true end
|
|
||||||
|
|
||||||
local is_node = minetest.registered_nodes[name]
|
local is_node = minetest.registered_nodes[name]
|
||||||
|
|
||||||
@ -125,8 +27,6 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
|||||||
param2 = minetest.dir_to_wallmounted(player:get_look_dir(), true)
|
param2 = minetest.dir_to_wallmounted(player:get_look_dir(), true)
|
||||||
end
|
end
|
||||||
|
|
||||||
local on_place = def.on_place or function() end
|
|
||||||
|
|
||||||
local start = vector.new(
|
local start = vector.new(
|
||||||
math.min(p1.x, p2.x),
|
math.min(p1.x, p2.x),
|
||||||
math.min(p1.y, p2.y),
|
math.min(p1.y, p2.y),
|
||||||
@ -174,5 +74,84 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return true
|
return
|
||||||
end)
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function fill_on_place(itemstack, player, pointed_thing)
|
||||||
|
if not edit.on_place_checks(player) then return end
|
||||||
|
|
||||||
|
if not pointed_thing.above then
|
||||||
|
pointed_thing = edit.get_pointed_thing_node(player)
|
||||||
|
end
|
||||||
|
|
||||||
|
local pos = edit.pointed_thing_to_pos(pointed_thing)
|
||||||
|
|
||||||
|
local player_data = edit.player_data[player]
|
||||||
|
if player_data.fill1 and pos then
|
||||||
|
player_data.fill2 = edit.add_marker("edit:fill", pos, player)
|
||||||
|
if not player_data.fill2 then return end
|
||||||
|
|
||||||
|
local diff = vector.subtract(player_data.fill1._pos, pos)
|
||||||
|
local volume = vector.add(vector.apply(diff, math.abs), 1)
|
||||||
|
if volume.x * volume.y * volume.z > edit.max_operation_volume then
|
||||||
|
edit.display_size_error(player)
|
||||||
|
player_data.fill1.object:remove()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
player_select_node_formspec(player)
|
||||||
|
elseif pos then
|
||||||
|
player_data.fill1 = edit.add_marker("edit:fill", pos, player)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_tool("edit:fill", {
|
||||||
|
description = "Edit Fill",
|
||||||
|
tiles = {"edit_fill.png"},
|
||||||
|
inventory_image = "edit_fill.png",
|
||||||
|
range = 10,
|
||||||
|
groups = {edit_place_preview = 1,},
|
||||||
|
on_place = fill_on_place,
|
||||||
|
on_secondary_use = fill_on_place,
|
||||||
|
_edit_get_selection_points = function(player)
|
||||||
|
local d = edit.player_data[player]
|
||||||
|
return d.fill1 and d.fill1._pos, d.fill2 and d.fill2._pos
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_entity("edit:fill", {
|
||||||
|
initial_properties = {
|
||||||
|
visual = "cube",
|
||||||
|
visual_size = { x = 1.1, y = 1.1 },
|
||||||
|
physical = false,
|
||||||
|
collide_with_objects = false,
|
||||||
|
static_save = false,
|
||||||
|
use_texture_alpha = true,
|
||||||
|
glow = -1,
|
||||||
|
backface_culling = false,
|
||||||
|
hp_max = 1,
|
||||||
|
textures = {
|
||||||
|
"edit_fill.png",
|
||||||
|
"edit_fill.png",
|
||||||
|
"edit_fill.png",
|
||||||
|
"edit_fill.png",
|
||||||
|
"edit_fill.png",
|
||||||
|
"edit_fill.png",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
on_deactivate = function(self)
|
||||||
|
local player_data = edit.player_data[self._placer]
|
||||||
|
self.remove_called = true
|
||||||
|
if player_data then
|
||||||
|
if player_data.fill1 and not player_data.fill1.remove_called then
|
||||||
|
player_data.fill1.object:remove()
|
||||||
|
end
|
||||||
|
if player_data.fill2 and not player_data.fill2.remove_called then
|
||||||
|
player_data.fill2.object:remove()
|
||||||
|
end
|
||||||
|
player_data.fill1 = nil
|
||||||
|
player_data.fill2 = nil
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
158
init.lua
158
init.lua
@ -50,25 +50,10 @@ minetest.register_on_joinplayer(function(player)
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
minetest.register_on_leaveplayer(function(player)
|
minetest.register_on_leaveplayer(function(player)
|
||||||
edit.delete_paste_preview(player)
|
for key, value in pairs(edit.player_data[player]) do
|
||||||
local d = edit.player_data[player]
|
if type(value) == "table" and value.object then
|
||||||
if d.select_preview then
|
value.object:remove()
|
||||||
d.select_preview:remove()
|
|
||||||
end
|
end
|
||||||
if d.place_preview then
|
|
||||||
d.place_preview:remove()
|
|
||||||
end
|
|
||||||
if d.copy_luaentity1 then
|
|
||||||
d.copy_luaentity1.object:remove()
|
|
||||||
end
|
|
||||||
if d.circle_luaentity then
|
|
||||||
d.circle_luaentity.object:remove()
|
|
||||||
end
|
|
||||||
if d.fill1 then
|
|
||||||
d.fill1.object:remove()
|
|
||||||
end
|
|
||||||
if d.fill2 then
|
|
||||||
d.fill2.object:remove()
|
|
||||||
end
|
end
|
||||||
edit.player_data[player] = nil
|
edit.player_data[player] = nil
|
||||||
end)
|
end)
|
||||||
@ -133,14 +118,14 @@ local old_register_on_dignode = minetest.register_on_dignode
|
|||||||
local registered_on_dignode = {}
|
local registered_on_dignode = {}
|
||||||
minetest.register_on_dignode = function(func)
|
minetest.register_on_dignode = function(func)
|
||||||
table.insert(registered_on_dignode, func)
|
table.insert(registered_on_dignode, func)
|
||||||
old_register_on_dignode(func)
|
return old_register_on_dignode(func)
|
||||||
end
|
end
|
||||||
|
|
||||||
local old_register_on_placenode = minetest.register_on_placenode
|
local old_register_on_placenode = minetest.register_on_placenode
|
||||||
local registered_on_placenode = {}
|
local registered_on_placenode = {}
|
||||||
minetest.register_on_placenode = function(func)
|
minetest.register_on_placenode = function(func)
|
||||||
table.insert(registered_on_placenode, func)
|
table.insert(registered_on_placenode, func)
|
||||||
old_register_on_placenode(func)
|
return old_register_on_placenode(func)
|
||||||
end
|
end
|
||||||
|
|
||||||
function edit.place_node_like_player(player, node, pos)
|
function edit.place_node_like_player(player, node, pos)
|
||||||
@ -188,6 +173,138 @@ function edit.add_marker(id, pos, player)
|
|||||||
return luaentity
|
return luaentity
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function player_select_node_formspec(player)
|
||||||
|
local d = edit.player_data[player]
|
||||||
|
local search_value = d.player_select_node_search_value
|
||||||
|
local doing_search = #search_value > 0
|
||||||
|
local inv = minetest.get_inventory({type = "player", name = player:get_player_name()})
|
||||||
|
local size = doing_search and 12 * 8 or inv:get_size("main")
|
||||||
|
local width = doing_search and 12 or inv:get_width("main")
|
||||||
|
if width <= 0 then width = 8 end
|
||||||
|
|
||||||
|
local formspec_width = math.max(width, 8) + 0.4
|
||||||
|
local formspec_height = math.ceil(size / width) + 3.4
|
||||||
|
|
||||||
|
local search_results = {}
|
||||||
|
if doing_search then
|
||||||
|
local search_words = {}
|
||||||
|
for word in search_value:gmatch("([^%s]+)") do
|
||||||
|
table.insert(search_words, word:lower())
|
||||||
|
end
|
||||||
|
|
||||||
|
local search_results_done = false
|
||||||
|
for id, def in pairs(minetest.registered_items) do
|
||||||
|
if minetest.get_item_group(id, "not_in_creative_inventory") == 0 then
|
||||||
|
local add_node_to_results = true
|
||||||
|
for i, word in pairs(search_words) do
|
||||||
|
local description = def.description:lower() or ""
|
||||||
|
if not description:find(word) and not id:find(word) then
|
||||||
|
add_node_to_results = false
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if add_node_to_results then
|
||||||
|
table.insert(search_results, id)
|
||||||
|
if #search_results > size then
|
||||||
|
search_results_done = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if search_results_done then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local title = doing_search and "Search Results:" or "Inventory:"
|
||||||
|
|
||||||
|
if #search_results > size then title = title .. " (some omited)" end
|
||||||
|
|
||||||
|
local formspec = "formspec_version[4]size[" .. formspec_width .. "," .. formspec_height .. "]" ..
|
||||||
|
"button[0,0;0,0;minetest_sucks;" .. math.random() .. "]" .. -- Force Minetest to show this formspec
|
||||||
|
"label[0.5,0.7;" .. d.player_select_node_message .. "]" ..
|
||||||
|
"button_exit[" .. formspec_width - 1.2 .. ",0.2;1,1;quit;X]" ..
|
||||||
|
"field_close_on_enter[search_field;false]" ..
|
||||||
|
"label[0.2,1.7;Search all items]" ..
|
||||||
|
"field[0.2,2;3.5,0.8;search_field;;" .. search_value .. "]" ..
|
||||||
|
"image_button[3.7,2;0.8,0.8;search.png^[resize:48x48;search_button;]" ..
|
||||||
|
"button[4.5,2;0.8,0.8;cancel_search;X]" ..
|
||||||
|
"label[5.6,2.8;" .. title .. "]"
|
||||||
|
|
||||||
|
for i = 1, size do
|
||||||
|
local name
|
||||||
|
if doing_search then
|
||||||
|
name = search_results[i]
|
||||||
|
else
|
||||||
|
name = inv:get_stack("main", i):get_name()
|
||||||
|
end
|
||||||
|
|
||||||
|
if not name then break end
|
||||||
|
|
||||||
|
if name == "" then name = "air" end
|
||||||
|
|
||||||
|
local index = i - 1
|
||||||
|
local x = 0.2 + index % width
|
||||||
|
local y = 3.2 + math.floor(index / width)
|
||||||
|
formspec =
|
||||||
|
formspec ..
|
||||||
|
"item_image_button[" ..
|
||||||
|
x .. "," ..
|
||||||
|
y .. ";1,1;" ..
|
||||||
|
name .. ";" ..
|
||||||
|
name .. ";]"
|
||||||
|
end
|
||||||
|
edit.reliable_show_formspec(player, "edit:player_select_node", formspec)
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
|
if formname ~= "edit:player_select_node" then return false end
|
||||||
|
local d = edit.player_data[player]
|
||||||
|
|
||||||
|
for key, val in pairs(fields) do
|
||||||
|
if key:find(":") or key == "air" then
|
||||||
|
if d.player_select_node_callback then
|
||||||
|
d.player_select_node_callback(player, key)
|
||||||
|
d.player_select_node_callback = nil
|
||||||
|
minetest.close_formspec(player:get_player_name(), "edit:player_select_node")
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if fields.quit then
|
||||||
|
if d.player_select_node_callback then
|
||||||
|
d.player_select_node_callback(player, nil)
|
||||||
|
d.player_select_node_callback = nil
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
elseif fields.cancel_search then
|
||||||
|
fields.search_field = ""
|
||||||
|
end
|
||||||
|
|
||||||
|
if
|
||||||
|
fields.search_field and
|
||||||
|
fields.search_field ~= d.player_select_node_search_value
|
||||||
|
then
|
||||||
|
d.player_select_node_search_value = fields.search_field
|
||||||
|
player_select_node_formspec(player)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end)
|
||||||
|
|
||||||
|
function edit.player_select_node(player, message, callback)
|
||||||
|
local d = edit.player_data[player]
|
||||||
|
if d.player_select_node_callback then
|
||||||
|
d.player_select_node_callback(player, nil)
|
||||||
|
end
|
||||||
|
d.player_select_node_callback = callback
|
||||||
|
d.player_select_node_search_value = d.player_select_node_search_value or ""
|
||||||
|
d.player_select_node_message = message
|
||||||
|
player_select_node_formspec(player)
|
||||||
|
end
|
||||||
|
|
||||||
edit.modpath = minetest.get_modpath("edit")
|
edit.modpath = minetest.get_modpath("edit")
|
||||||
dofile(edit.modpath .. "/copy.lua")
|
dofile(edit.modpath .. "/copy.lua")
|
||||||
dofile(edit.modpath .. "/fill.lua")
|
dofile(edit.modpath .. "/fill.lua")
|
||||||
@ -200,3 +317,4 @@ dofile(edit.modpath .. "/undo.lua")
|
|||||||
dofile(edit.modpath .. "/circle.lua")
|
dofile(edit.modpath .. "/circle.lua")
|
||||||
dofile(edit.modpath .. "/mirror.lua")
|
dofile(edit.modpath .. "/mirror.lua")
|
||||||
dofile(edit.modpath .. "/screwdriver.lua")
|
dofile(edit.modpath .. "/screwdriver.lua")
|
||||||
|
dofile(edit.modpath .. "/replace.lua")
|
||||||
|
26
mirror.lua
26
mirror.lua
@ -2,7 +2,6 @@ local function do_mirror(player, pos, node)
|
|||||||
local d = edit.player_data[player]
|
local d = edit.player_data[player]
|
||||||
|
|
||||||
if
|
if
|
||||||
not player or
|
|
||||||
player:get_player_control().aux1 or
|
player:get_player_control().aux1 or
|
||||||
not d or
|
not d or
|
||||||
not d.mirror_luaentity
|
not d.mirror_luaentity
|
||||||
@ -14,6 +13,12 @@ local function do_mirror(player, pos, node)
|
|||||||
local center = d.mirror_luaentity._pos
|
local center = d.mirror_luaentity._pos
|
||||||
local offset = vector.subtract(pos, center)
|
local offset = vector.subtract(pos, center)
|
||||||
|
|
||||||
|
-- Undo
|
||||||
|
local length = math.max(math.abs(offset.x), math.abs(offset.z))
|
||||||
|
local start = vector.subtract(center, vector.new(length, -offset.y, length))
|
||||||
|
local size = vector.new(length * 2 + 1, 1, length * 2 + 1)
|
||||||
|
d.undo_schematic = edit.schematic_from_map(start, size)
|
||||||
|
|
||||||
if d.mirror_mode == "x" then
|
if d.mirror_mode == "x" then
|
||||||
offset.x = -offset.x
|
offset.x = -offset.x
|
||||||
edit.place_node_like_player(player, node, vector.add(center, offset))
|
edit.place_node_like_player(player, node, vector.add(center, offset))
|
||||||
@ -42,20 +47,17 @@ local function do_mirror(player, pos, node)
|
|||||||
edit.place_node_like_player(player, node, vector.add(center, offset))
|
edit.place_node_like_player(player, node, vector.add(center, offset))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
d.ignore_node_placement = nil
|
d.ignore_node_placement = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
minetest.register_on_dignode(function(pos, oldnode, digger)
|
minetest.register_on_dignode(function(pos, oldnode, digger)
|
||||||
if not digger or not digger:is_player() then return end
|
if not digger or not digger:is_player() then return end
|
||||||
local player_data = edit.player_data[digger]
|
|
||||||
if player_data.ignore_node_placement then return end
|
|
||||||
return do_mirror(digger, pos, {name = "air"})
|
return do_mirror(digger, pos, {name = "air"})
|
||||||
end)
|
end)
|
||||||
|
|
||||||
minetest.register_on_placenode(function(pos, newnode, placer, oldnode, itemstack, pointed_thing)
|
minetest.register_on_placenode(function(pos, newnode, placer, oldnode, itemstack, pointed_thing)
|
||||||
if not placer or not placer:is_player() then return end
|
if not placer or not placer:is_player() then return end
|
||||||
local player_data = edit.player_data[placer]
|
|
||||||
if player_data.ignore_node_placement then return end
|
|
||||||
return do_mirror(placer, pos, newnode)
|
return do_mirror(placer, pos, newnode)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
@ -69,13 +71,8 @@ local function mirror_tool_on_place(itemstack, player, pointed_thing)
|
|||||||
|
|
||||||
local pos = edit.get_half_node_pointed_pos(player)
|
local pos = edit.get_half_node_pointed_pos(player)
|
||||||
|
|
||||||
local obj_ref = minetest.add_entity(pos, "edit:mirror")
|
d.mirror_luaentity = edit.add_marker("edit:mirror", pos, player)
|
||||||
if not obj_ref then return end
|
d.mirror_luaentity:_update_borders()
|
||||||
local luaentity = obj_ref:get_luaentity()
|
|
||||||
luaentity._pos = pos
|
|
||||||
luaentity._placer = player
|
|
||||||
luaentity:_update_borders()
|
|
||||||
d.mirror_luaentity = luaentity
|
|
||||||
|
|
||||||
d.mirror_hud = player:hud_add({
|
d.mirror_hud = player:hud_add({
|
||||||
hud_elem_type = "text",
|
hud_elem_type = "text",
|
||||||
@ -93,8 +90,12 @@ minetest.register_tool("edit:mirror", {
|
|||||||
tiles = {"edit_mirror.png"},
|
tiles = {"edit_mirror.png"},
|
||||||
inventory_image = "edit_mirror.png",
|
inventory_image = "edit_mirror.png",
|
||||||
range = 10,
|
range = 10,
|
||||||
|
groups = {edit_place_preview = 1,},
|
||||||
on_place = mirror_tool_on_place,
|
on_place = mirror_tool_on_place,
|
||||||
on_secondary_use = mirror_tool_on_place,
|
on_secondary_use = mirror_tool_on_place,
|
||||||
|
_edit_get_pointed_pos = function(player)
|
||||||
|
return edit.get_half_node_pointed_pos(player)
|
||||||
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_entity("edit:mirror_border", {
|
minetest.register_entity("edit:mirror_border", {
|
||||||
@ -106,7 +107,6 @@ minetest.register_entity("edit:mirror_border", {
|
|||||||
static_save = false,
|
static_save = false,
|
||||||
use_texture_alpha = true,
|
use_texture_alpha = true,
|
||||||
glow = -1,
|
glow = -1,
|
||||||
backface_culling = false,
|
|
||||||
hp_max = 1,
|
hp_max = 1,
|
||||||
pointable = false,
|
pointable = false,
|
||||||
backface_culling = true,
|
backface_culling = true,
|
||||||
|
114
preview.lua
114
preview.lua
@ -18,7 +18,7 @@ function edit.rotate_paste_preview(player)
|
|||||||
local d = edit.player_data[player]
|
local d = edit.player_data[player]
|
||||||
local rot = d.schematic._rotation
|
local rot = d.schematic._rotation
|
||||||
local offset
|
local offset
|
||||||
d.paste_preview:set_yaw(-math.rad(rot))
|
d.paste_preview.object:set_yaw(-math.rad(rot))
|
||||||
local size = d.schematic.size
|
local size = d.schematic.size
|
||||||
if rot == 90 or rot == 270 then
|
if rot == 90 or rot == 270 then
|
||||||
size = vector.new(size.z, size.y, size.x)
|
size = vector.new(size.z, size.y, size.x)
|
||||||
@ -98,24 +98,11 @@ local function create_paste_preview(player)
|
|||||||
objref:set_attach(base_objref, "", attach_pos, attach_rot)
|
objref:set_attach(base_objref, "", attach_pos, attach_rot)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
edit.player_data[player].paste_preview = base_objref
|
edit.player_data[player].paste_preview = base_objref:get_luaentity()
|
||||||
edit.player_data[player].schematic._rotation = 0
|
edit.player_data[player].schematic._rotation = 0
|
||||||
edit.rotate_paste_preview(player)
|
edit.rotate_paste_preview(player)
|
||||||
end
|
end
|
||||||
|
|
||||||
function edit.delete_paste_preview(player)
|
|
||||||
local paste_preview = edit.player_data[player].paste_preview
|
|
||||||
if not paste_preview or not paste_preview:get_pos() then return end
|
|
||||||
|
|
||||||
local objrefs = paste_preview:get_children()
|
|
||||||
for i, objref in pairs(objrefs) do
|
|
||||||
objref:remove()
|
|
||||||
end
|
|
||||||
edit.player_data[player].paste_preview:remove()
|
|
||||||
edit.player_data[player].paste_preview_visable = false
|
|
||||||
edit.player_data[player].paste_preview = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
minetest.register_entity("edit:select_preview", {
|
minetest.register_entity("edit:select_preview", {
|
||||||
initial_properties = {
|
initial_properties = {
|
||||||
visual = "cube",
|
visual = "cube",
|
||||||
@ -138,7 +125,13 @@ minetest.register_entity("edit:paste_preview_base", {
|
|||||||
static_save = false,
|
static_save = false,
|
||||||
visual_size = {x = 1, y = 1},
|
visual_size = {x = 1, y = 1},
|
||||||
textures = { "blank.png", "blank.png", "blank.png", "blank.png", "blank.png", "blank.png" },
|
textures = { "blank.png", "blank.png", "blank.png", "blank.png", "blank.png", "blank.png" },
|
||||||
}
|
},
|
||||||
|
on_deactivate = function(self)
|
||||||
|
local objrefs = self.object:get_children()
|
||||||
|
for i, objref in pairs(objrefs) do
|
||||||
|
objref:remove()
|
||||||
|
end
|
||||||
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_entity("edit:preview_node", {
|
minetest.register_entity("edit:preview_node", {
|
||||||
@ -159,20 +152,20 @@ local function hide_paste_preview(player)
|
|||||||
-- This does not work right.
|
-- This does not work right.
|
||||||
-- Some child entities do not become visable when you set is_visable back to true
|
-- Some child entities do not become visable when you set is_visable back to true
|
||||||
|
|
||||||
for _, objref in pairs(d.paste_preview:get_children()) do
|
for _, objref in pairs(d.paste_preview.object:get_children()) do
|
||||||
objref:set_properties({is_visible = false})
|
objref:set_properties({is_visible = false})
|
||||||
end
|
end
|
||||||
d.paste_preview:set_attach(player)
|
d.paste_preview.object:set_attach(player)
|
||||||
player:hud_remove(d.paste_preview_hud)
|
player:hud_remove(d.paste_preview_hud)
|
||||||
d.paste_preview_hud = nil
|
d.paste_preview_hud = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
local function show_paste_preview(player)
|
local function show_paste_preview(player)
|
||||||
local d = edit.player_data[player]
|
local d = edit.player_data[player]
|
||||||
for _, objref in pairs(d.paste_preview:get_children()) do
|
for _, objref in pairs(d.paste_preview.object:get_children()) do
|
||||||
objref:set_properties({is_visible = true})
|
objref:set_properties({is_visible = true})
|
||||||
end
|
end
|
||||||
d.paste_preview:set_detach()
|
d.paste_preview.object: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 = "Punch (left click) to rotate.",
|
text = "Punch (left click) to rotate.",
|
||||||
@ -188,15 +181,23 @@ local function show_paste_preview(player)
|
|||||||
local pos = objref:get_pos()
|
local pos = objref:get_pos()
|
||||||
if pos then objref:set_pos(pos) end
|
if pos then objref:set_pos(pos) end
|
||||||
end,
|
end,
|
||||||
d.paste_preview
|
d.paste_preview.object
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function edit.delete_paste_preview(player)
|
||||||
|
local d = edit.player_data[player]
|
||||||
|
if d.paste_preview then
|
||||||
|
d.paste_preview.object:remove()
|
||||||
|
d.paste_preview = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local function hide_select_preview(player)
|
local function hide_select_preview(player)
|
||||||
local d = edit.player_data[player]
|
local d = edit.player_data[player]
|
||||||
d.select_preview_shown = false
|
d.select_preview_shown = false
|
||||||
d.select_preview:set_properties({ is_visible = false })
|
d.select_preview.object:set_properties({ is_visible = false })
|
||||||
d.select_preview:set_attach(player)
|
d.select_preview.object:set_attach(player)
|
||||||
player:hud_remove(d.select_preview_hud)
|
player:hud_remove(d.select_preview_hud)
|
||||||
d.select_preview_hud = nil
|
d.select_preview_hud = nil
|
||||||
end
|
end
|
||||||
@ -204,16 +205,18 @@ end
|
|||||||
local function update_select_preview(player, pos, size)
|
local function update_select_preview(player, pos, size)
|
||||||
local d = edit.player_data[player]
|
local d = edit.player_data[player]
|
||||||
|
|
||||||
if not d.select_preview or not d.select_preview:get_pos() then
|
if not d.select_preview or not d.select_preview.object:get_pos() then
|
||||||
d.select_preview = minetest.add_entity(player:get_pos(), "edit:select_preview")
|
local obj_ref = minetest.add_entity(player:get_pos(), "edit:select_preview")
|
||||||
|
if not obj_ref then return end
|
||||||
|
d.select_preview = obj_ref:get_luaentity()
|
||||||
d.select_preview_shown = true
|
d.select_preview_shown = true
|
||||||
elseif not d.select_preview_shown then
|
elseif not d.select_preview_shown then
|
||||||
d.select_preview:set_detach()
|
d.select_preview.object:set_detach()
|
||||||
d.select_preview:set_properties({is_visible = true})
|
d.select_preview.object:set_properties({is_visible = true})
|
||||||
d.select_preview_shown = true
|
d.select_preview_shown = true
|
||||||
end
|
end
|
||||||
|
|
||||||
local preview = d.select_preview
|
local preview = d.select_preview.object
|
||||||
if vector.equals(pos, preview:get_pos()) then
|
if vector.equals(pos, preview:get_pos()) then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@ -295,18 +298,18 @@ minetest.register_globalstep(function(dtime)
|
|||||||
if item == "edit:paste" and d.schematic then
|
if item == "edit:paste" and d.schematic then
|
||||||
local pos = edit.pointed_thing_to_pos(edit.get_pointed_thing_node(player))
|
local pos = edit.pointed_thing_to_pos(edit.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.object:get_pos() then
|
||||||
create_paste_preview(player)
|
create_paste_preview(player)
|
||||||
end
|
end
|
||||||
|
|
||||||
if not d.paste_preview_hud then show_paste_preview(player) end
|
if not d.paste_preview_hud then show_paste_preview(player) end
|
||||||
|
|
||||||
local old_pos = d.paste_preview:get_pos()
|
local old_pos = d.paste_preview.object:get_pos()
|
||||||
pos = vector.add(pos, d.paste_preview_offset)
|
pos = vector.add(pos, d.paste_preview_offset)
|
||||||
set_schematic_offset(player)
|
set_schematic_offset(player)
|
||||||
pos = vector.add(pos, d.schematic_offset)
|
pos = vector.add(pos, d.schematic_offset)
|
||||||
if not vector.equals(old_pos, pos) then
|
if not vector.equals(old_pos, pos) then
|
||||||
d.paste_preview:set_pos(pos)
|
d.paste_preview.object:set_pos(pos)
|
||||||
end
|
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
|
||||||
@ -315,47 +318,36 @@ minetest.register_globalstep(function(dtime)
|
|||||||
local node1_pos
|
local node1_pos
|
||||||
local node2_pos
|
local node2_pos
|
||||||
local pointed_pos
|
local pointed_pos
|
||||||
local fill_selected = item == "edit:fill"
|
local tool_def = minetest.registered_items[item] or minetest.registered_items["air"]
|
||||||
local copy_selected = item == "edit:copy"
|
|
||||||
local circle_selected = item == "edit:circle"
|
if tool_def._edit_get_selection_points then
|
||||||
local mirror_selected = item == "edit:mirror"
|
node1_pos, node2_pos = tool_def._edit_get_selection_points(player)
|
||||||
if fill_selected then
|
|
||||||
if d.fill1 then
|
|
||||||
node1_pos = d.fill1._pos
|
|
||||||
end
|
|
||||||
if d.fill2 then
|
|
||||||
node2_pos = d.fill2._pos
|
|
||||||
end
|
|
||||||
elseif copy_selected then
|
|
||||||
if d.copy_luaentity1 then
|
|
||||||
node1_pos = d.copy_luaentity1._pos
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if not node2_pos or not node1_pos then
|
if not node2_pos or not node1_pos then
|
||||||
local pointed_thing = edit.get_pointed_thing_node(player)
|
if tool_def._edit_get_pointed_pos then
|
||||||
if circle_selected or mirror_selected then
|
pointed_pos = tool_def._edit_get_pointed_pos(player)
|
||||||
pointed_pos = edit.get_half_node_pointed_pos(player)
|
|
||||||
elseif copy_selected then
|
|
||||||
pointed_pos = pointed_thing.under
|
|
||||||
else
|
else
|
||||||
|
local pointed_thing = edit.get_pointed_thing_node(player)
|
||||||
pointed_pos = edit.pointed_thing_to_pos(pointed_thing)
|
pointed_pos = edit.pointed_thing_to_pos(pointed_thing)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if (fill_selected or copy_selected or circle_selected or mirror_selected) and not node2_pos and pointed_pos then
|
if minetest.get_item_group(item, "edit_place_preview") ~= 0 and not node2_pos and pointed_pos then
|
||||||
if not d.place_preview or not d.place_preview:get_pos() then
|
if not d.place_preview or not d.place_preview.object:get_pos() then
|
||||||
d.place_preview = minetest.add_entity(player:get_pos(), "edit:place_preview")
|
local obj_ref = minetest.add_entity(player:get_pos(), "edit:place_preview")
|
||||||
|
if not obj_ref then return end
|
||||||
|
d.place_preview = obj_ref:get_luaentity()
|
||||||
d.place_preview_shown = true
|
d.place_preview_shown = true
|
||||||
d.place_preview_item = nil
|
d.place_preview_item = nil
|
||||||
elseif not d.place_preview_shown then
|
elseif not d.place_preview_shown then
|
||||||
d.place_preview:set_properties({ is_visible = true })
|
d.place_preview.object:set_properties({ is_visible = true })
|
||||||
d.place_preview:set_detach()
|
d.place_preview.object:set_detach()
|
||||||
d.place_preview_shown = true
|
d.place_preview_shown = true
|
||||||
end
|
end
|
||||||
|
|
||||||
if not vector.equals(d.place_preview:get_pos(), pointed_pos) then
|
if not vector.equals(d.place_preview.object:get_pos(), pointed_pos) then
|
||||||
d.place_preview:set_pos(pointed_pos)
|
d.place_preview.object:set_pos(pointed_pos)
|
||||||
end
|
end
|
||||||
|
|
||||||
if d.place_preview_item ~= item then
|
if d.place_preview_item ~= item then
|
||||||
@ -363,13 +355,13 @@ minetest.register_globalstep(function(dtime)
|
|||||||
"^[opacity:150"
|
"^[opacity:150"
|
||||||
|
|
||||||
d.place_preview_item = item
|
d.place_preview_item = item
|
||||||
d.place_preview:set_properties({
|
d.place_preview.object:set_properties({
|
||||||
textures = { tex, tex, tex, tex, tex, tex }
|
textures = { tex, tex, tex, tex, tex, tex }
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
elseif d.place_preview_shown then
|
elseif d.place_preview_shown then
|
||||||
d.place_preview:set_properties({ is_visible = false })
|
d.place_preview.object:set_properties({ is_visible = false })
|
||||||
d.place_preview:set_attach(player)
|
d.place_preview.object:set_attach(player)
|
||||||
d.place_preview_shown = false
|
d.place_preview_shown = false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
244
replace.lua
Normal file
244
replace.lua
Normal file
@ -0,0 +1,244 @@
|
|||||||
|
local function show_select_source_nodes_formspec(player)
|
||||||
|
local player_data = edit.player_data[player]
|
||||||
|
|
||||||
|
local p1 = player_data.replace1._pos
|
||||||
|
local p2 = player_data.replace2._pos
|
||||||
|
|
||||||
|
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 > edit.max_operation_volume then
|
||||||
|
edit.display_size_error(player)
|
||||||
|
player_data.replace1.object:remove()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local all_nodes = {}
|
||||||
|
for x = start.x, _end.x do
|
||||||
|
for y = start.y, _end.y do
|
||||||
|
for z = start.z, _end.z do
|
||||||
|
local name = minetest.get_node(vector.new(x, y, z)).name
|
||||||
|
if all_nodes[name] then
|
||||||
|
all_nodes[name] = all_nodes[name] + 1
|
||||||
|
else
|
||||||
|
all_nodes[name] = 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if player_data.replace_source_nodes == "all" then
|
||||||
|
player_data.replace_source_nodes = all_nodes
|
||||||
|
elseif not player_data.replace_source_nodes then
|
||||||
|
player_data.replace_source_nodes = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
local formspec = "formspec_version[4]size[10.1,10.8]" ..
|
||||||
|
|
||||||
|
-- Formspecs are only sent if the first part of the formspec is different.
|
||||||
|
-- I mitigate this by placing an invizible button with a random
|
||||||
|
-- label at the beginning of the formspec.
|
||||||
|
"button[0,0;0,0;minetest_sucks;" .. math.random() .. "]" ..
|
||||||
|
"label[0.5,0.7;Select node types to replace]" ..
|
||||||
|
"button_exit[8.9,0.2;1,1;quit;X]" ..
|
||||||
|
"scroll_container[0.2,1.4;9,8;scrollbar;vertical]"
|
||||||
|
|
||||||
|
local index = 0
|
||||||
|
for name, count in pairs(all_nodes) do
|
||||||
|
local x = index % 9
|
||||||
|
local y = math.floor(index / 9)
|
||||||
|
local def = minetest.registered_nodes[name]
|
||||||
|
local description = def and def.description or name
|
||||||
|
local selected = player_data.replace_source_nodes[name] and "true" or ""
|
||||||
|
formspec = formspec ..
|
||||||
|
"item_image[" .. x .. "," .. y .. ";1,1;" .. name .. "]" ..
|
||||||
|
"checkbox[" .. x + 0.1 .. "," .. y + 0.3 .. ";" .. name .. ";;" .. selected .. "]" ..
|
||||||
|
"tooltip[" .. x .. "," .. y .. ";1,1;" .. description .. "]"
|
||||||
|
index = index + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
formspec = formspec ..
|
||||||
|
"scroll_container_end[]" ..
|
||||||
|
"scrollbaroptions[max=" .. (math.ceil(index / 9) - 8) * 10 .. "]" ..
|
||||||
|
"scrollbar[9.3,1.4;0.6,8;vertical;scrollbar;0]" ..
|
||||||
|
"button[0.2,9.6;3.5,0.8;select_all;Select All]" ..
|
||||||
|
"button[3.9,9.6;3.5,0.8;select_none;Select None]" ..
|
||||||
|
"button[7.9,9.6;2,1;continue;OK]"
|
||||||
|
|
||||||
|
minetest.show_formspec(player:get_player_name(), "edit:replace_source_nodes", formspec)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function replace_on_place(itemstack, player, pointed_thing)
|
||||||
|
if not edit.on_place_checks(player) then return end
|
||||||
|
|
||||||
|
if not pointed_thing.above then
|
||||||
|
pointed_thing = edit.get_pointed_thing_node(player)
|
||||||
|
end
|
||||||
|
|
||||||
|
local pos = pointed_thing.under
|
||||||
|
|
||||||
|
local player_data = edit.player_data[player]
|
||||||
|
if player_data.replace1 and pos then
|
||||||
|
player_data.replace2 = edit.add_marker("edit:replace", pos, player)
|
||||||
|
if not player_data.replace2 then return end
|
||||||
|
show_select_source_nodes_formspec(player)
|
||||||
|
elseif pos then
|
||||||
|
player_data.replace1 = edit.add_marker("edit:replace", pos, player)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_tool("edit:replace", {
|
||||||
|
description = "Edit Replace",
|
||||||
|
tiles = {"edit_replace.png"},
|
||||||
|
inventory_image = "edit_replace.png",
|
||||||
|
range = 10,
|
||||||
|
groups = {edit_place_preview = 1,},
|
||||||
|
on_place = replace_on_place,
|
||||||
|
on_secondary_use = replace_on_place,
|
||||||
|
_edit_get_selection_points = function(player)
|
||||||
|
local d = edit.player_data[player]
|
||||||
|
return d.replace1 and d.replace1._pos, d.replace2 and d.replace2._pos
|
||||||
|
end,
|
||||||
|
_edit_get_pointed_pos = function(player)
|
||||||
|
return edit.get_pointed_thing_node(player).under
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_entity("edit:replace", {
|
||||||
|
initial_properties = {
|
||||||
|
visual = "cube",
|
||||||
|
visual_size = { x = 1.1, y = 1.1 },
|
||||||
|
physical = false,
|
||||||
|
collide_with_objects = false,
|
||||||
|
static_save = false,
|
||||||
|
use_texture_alpha = true,
|
||||||
|
glow = -1,
|
||||||
|
backface_culling = false,
|
||||||
|
hp_max = 1,
|
||||||
|
textures = {
|
||||||
|
"edit_replace.png",
|
||||||
|
"edit_replace.png",
|
||||||
|
"edit_replace.png",
|
||||||
|
"edit_replace.png",
|
||||||
|
"edit_replace.png",
|
||||||
|
"edit_replace.png",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
on_deactivate = function(self)
|
||||||
|
local player_data = edit.player_data[self._placer]
|
||||||
|
self.remove_called = true
|
||||||
|
if player_data then
|
||||||
|
if player_data.replace1 and not player_data.replace1.remove_called then
|
||||||
|
player_data.replace1.object:remove()
|
||||||
|
end
|
||||||
|
if player_data.replace2 and not player_data.replace2.remove_called then
|
||||||
|
player_data.replace2.object:remove()
|
||||||
|
end
|
||||||
|
player_data.replace1 = nil
|
||||||
|
player_data.replace2 = nil
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
|
if formname ~= "edit:replace_source_nodes" then return false end
|
||||||
|
|
||||||
|
local d = edit.player_data[player]
|
||||||
|
|
||||||
|
if
|
||||||
|
not d.replace1 or not d.replace2 or
|
||||||
|
not edit.has_privilege(player)
|
||||||
|
then return true end
|
||||||
|
|
||||||
|
if fields.quit then
|
||||||
|
d.replace1.object:remove()
|
||||||
|
d.replace_source_nodes = nil
|
||||||
|
return true
|
||||||
|
elseif fields.select_all then
|
||||||
|
d.replace_source_nodes = "all"
|
||||||
|
show_select_source_nodes_formspec(player)
|
||||||
|
return true
|
||||||
|
elseif fields.select_none then
|
||||||
|
d.replace_source_nodes = nil
|
||||||
|
show_select_source_nodes_formspec(player)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
for key, value in pairs(fields) do
|
||||||
|
if key:find(":") or key == "air" then
|
||||||
|
if value == "true" then
|
||||||
|
d.replace_source_nodes[key] = true
|
||||||
|
else
|
||||||
|
d.replace_source_nodes[key] = nil
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if not fields.continue then return true end
|
||||||
|
|
||||||
|
edit.player_select_node(player, "Select item to replace nodes", function(player, name)
|
||||||
|
if
|
||||||
|
not d.replace1 or not d.replace2 or
|
||||||
|
not d.replace_source_nodes or
|
||||||
|
not edit.has_privilege(player)
|
||||||
|
then return end
|
||||||
|
|
||||||
|
local p1 = d.replace1._pos
|
||||||
|
local p2 = d.replace2._pos
|
||||||
|
|
||||||
|
d.replace1.object:remove()
|
||||||
|
local replace_source_nodes = d.replace_source_nodes
|
||||||
|
d.replace_source_nodes = nil
|
||||||
|
|
||||||
|
if not name then return end
|
||||||
|
|
||||||
|
local def = minetest.registered_items[name]
|
||||||
|
if not def then return end
|
||||||
|
|
||||||
|
local is_node = minetest.registered_nodes[name]
|
||||||
|
|
||||||
|
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)
|
||||||
|
d.undo_schematic = edit.schematic_from_map(start, size)
|
||||||
|
|
||||||
|
for x = start.x, _end.x do
|
||||||
|
for y = start.y, _end.y do
|
||||||
|
for z = start.z, _end.z do
|
||||||
|
local pos = vector.new(x, y, z)
|
||||||
|
local node = minetest.get_node(pos)
|
||||||
|
local old_name = node.name
|
||||||
|
node.name = name
|
||||||
|
if replace_source_nodes[old_name] then
|
||||||
|
if is_node then
|
||||||
|
minetest.swap_node(pos, node)
|
||||||
|
else
|
||||||
|
edit.place_node_like_player(player, node, pos)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
return true
|
||||||
|
end)
|
BIN
textures/edit_replace.png
Normal file
BIN
textures/edit_replace.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 169 B |
Loading…
x
Reference in New Issue
Block a user