diff --git a/ChatCommands.md b/ChatCommands.md index 256f941..d24ad42 100644 --- a/ChatCommands.md +++ b/ChatCommands.md @@ -100,7 +100,7 @@ Display the volume of the current WorldEdit region. ### `//deleteblocks` -Delete the MapBlocks (16x16x16 units) that contain the selected region. This means that mapgen will be invoked for that area. As only whole MapBlocks get removed, the deleted area is usually larger than the selected one. Also, mapgen can trigger mechanisms like mud reflow or cavegen, which affects nodes (up to 112 nodes away) outside the MapBlock, so dont use this near buildings. +Delete the MapBlocks (16x16x16 units) that contain the selected region. This means that mapgen will be invoked for that area. As only whole MapBlocks get removed, the deleted area is usually larger than the selected one. Also, mapgen can trigger mechanisms like mud reflow or cavegen, which affects nodes (up to 112 nodes away) outside the MapBlock, so dont use this near buildings. Note that active entities are not part of a MapBlock and do not get deleted. //deleteblocks diff --git a/WorldEdit API.md b/WorldEdit API.md index ce7c978..284b8f9 100644 --- a/WorldEdit API.md +++ b/WorldEdit API.md @@ -45,6 +45,12 @@ Copies the region defined by positions `pos1` and `pos2` along the `axis` axis ( Returns the number of nodes copied. +### count = worldedit.copy2(pos1, pos2, off) + +Copies the region defined by positions `pos1` and `pos2` by the offset vector `off`. + +Returns the number of nodes copied. + ### count = worldedit.move(pos1, pos2, axis, amount) Moves the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") by `amount` nodes. diff --git a/worldedit/init.lua b/worldedit/init.lua index 47a41eb..9d84824 100644 --- a/worldedit/init.lua +++ b/worldedit/init.lua @@ -36,6 +36,7 @@ load_module(path .. "/visualization.lua") load_module(path .. "/serialization.lua") load_module(path .. "/code.lua") load_module(path .. "/compatibility.lua") +load_module(path .. "/wand.lua") if minetest.setting_getbool("log_mods") then diff --git a/worldedit/manipulations.lua b/worldedit/manipulations.lua index a69e4a0..e7cef2d 100644 --- a/worldedit/manipulations.lua +++ b/worldedit/manipulations.lua @@ -147,7 +147,7 @@ function worldedit.stack2(pos1, pos2, direction, amount, finished) translated.x = translated.x + direction.x translated.y = translated.y + direction.y translated.z = translated.z + direction.z - worldedit.copy2(pos1, pos2, translated, volume) + worldedit.copy2(pos1, pos2, translated) minetest.after(0, next_one) else if finished then @@ -221,6 +221,38 @@ function worldedit.copy(pos1, pos2, axis, amount) return worldedit.volume(pos1, pos2) end +--- Copies a region by offset vector `off`. +-- @param pos1 +-- @param pos2 +-- @param off +-- @return The number of nodes copied. +function worldedit.copy2(pos1, pos2, off) + local pos1, pos2 = worldedit.sort_pos(pos1, pos2) + + worldedit.keep_loaded(pos1, pos2) + + local get_node, get_meta, set_node = minetest.get_node, + minetest.get_meta, minetest.set_node + local pos = {} + pos.x = pos2.x + while pos.x >= pos1.x do + pos.y = pos2.y + while pos.y >= pos1.y do + pos.z = pos2.z + while pos.z >= pos1.z do + local node = get_node(pos) -- Obtain current node + local meta = get_meta(pos):to_table() -- Get meta of current node + local newpos = vector.add(pos, off) -- Calculate new position + set_node(newpos, node) -- Copy node to new position + get_meta(newpos):from_table(meta) -- Set metadata of new node + pos.z = pos.z - 1 + end + pos.y = pos.y - 1 + end + pos.x = pos.x - 1 + end + return worldedit.volume(pos1, pos2) +end --- Moves a region along `axis` by `amount` nodes. -- @return The number of nodes moved. diff --git a/worldedit/primitives.lua b/worldedit/primitives.lua index 6d3b026..962a02f 100644 --- a/worldedit/primitives.lua +++ b/worldedit/primitives.lua @@ -157,7 +157,7 @@ function worldedit.pyramid(pos, axis, height, node_name) -- Set up voxel manipulator local manip, area = mh.init_axis_radius(pos, axis, height >= 0 and height or -height) - local data = mh.get_empty_data() + local data = mh.get_empty_data(area) -- Handle inverted pyramids local start_axis, end_axis, step @@ -177,7 +177,7 @@ function worldedit.pyramid(pos, axis, height, node_name) y = pos.y - area.MinEdge.y, z = pos.z - area.MinEdge.z, } - local size = height * step + local size = math.abs(height * step) local count = 0 -- For each level of the pyramid for index1 = 0, height, step do diff --git a/worldedit/serialization.lua b/worldedit/serialization.lua index 00d984d..a0848e2 100644 --- a/worldedit/serialization.lua +++ b/worldedit/serialization.lua @@ -144,9 +144,9 @@ local function load_schematic(value) "([^%s]+)%s+(%d+)%s+(%d+)[^\r\n]*[\r\n]*") do param1, param2 = tonumber(param1), tonumber(param2) table.insert(nodes, { - x = originx + tonumber(x), - y = originy + tonumber(y), - z = originz + tonumber(z), + x = tonumber(x), + y = tonumber(y), + z = tonumber(z), name = name, param1 = param1 ~= 0 and param1 or nil, param2 = param2 ~= 0 and param2 or nil, diff --git a/worldedit/textures/worldedit_wand.png b/worldedit/textures/worldedit_wand.png new file mode 100644 index 0000000..13eb121 Binary files /dev/null and b/worldedit/textures/worldedit_wand.png differ diff --git a/worldedit/wand.lua b/worldedit/wand.lua new file mode 100644 index 0000000..415e7ca --- /dev/null +++ b/worldedit/wand.lua @@ -0,0 +1,51 @@ +minetest.register_tool("worldedit:wand", { + description = "WorldEdit wand tool. Left-click to set the 1st position, Right-click to set the 2nd position.", + groups = {}, + inventory_image = "worldedit_wand.png", + wield_image = "", + wield_scale = {x=1,y=1,z=1}, + stack_max = 1, -- there is no need to have more than one + liquids_pointable = true, -- ground with only water on can be selected as well + -- the tool_capabilities are completely irrelevant here - no need to dig + tool_capabilities = { + full_punch_interval = 1.0, + max_drop_level=0, + groupcaps={ + fleshy={times={[2]=0.80, [3]=0.40}, maxwear=0.05, maxlevel=1}, + snappy={times={[2]=0.80, [3]=0.40}, maxwear=0.05, maxlevel=1}, + choppy={times={[3]=0.90}, maxwear=0.05, maxlevel=0} + } + }, + node_placement_prediction = nil, + + on_use = function(itemstack, placer, pointed_thing) + if placer ~= nil and pointed_thing ~= nil then + local name = placer:get_player_name() + local pos = minetest.get_pointed_thing_position( pointed_thing, false ) -- not above + + if not pos then + return itemstack + end + + worldedit.pos1[name] = pos + worldedit.mark_pos1(name) + + end + return itemstack -- nothing consumed, nothing changed + end, + + on_place = function(itemstack, placer, pointed_thing) -- Left Click + if placer ~= nil and pointed_thing ~= nil then + local name = placer:get_player_name() + local pos = minetest.get_pointed_thing_position( pointed_thing, false ) -- not above + + if not pos then + return itemstack + end + + worldedit.pos2[name] = pos + worldedit.mark_pos2(name) + end + return itemstack -- nothing consumed, nothing changed + end, +}) diff --git a/worldedit_gui/functionality.lua b/worldedit_gui/functionality.lua index fb6e9f3..021fb9b 100644 --- a/worldedit_gui/functionality.lua +++ b/worldedit_gui/functionality.lua @@ -286,6 +286,11 @@ worldedit.register_gui_handler("worldedit_gui_cylinder", function(name, fields) end return true end + if fields.worldedit_gui_cylinder_axis then + gui_axis1[name] = axis_indices[fields.worldedit_gui_cylinder_axis] + worldedit.show_page(name, "worldedit_gui_cylinder") + return true + end return false end) @@ -316,6 +321,11 @@ worldedit.register_gui_handler("worldedit_gui_pyramid", function(name, fields) end return true end + if fields.worldedit_gui_pyramid_axis then + gui_axis1[name] = axis_indices[fields.worldedit_gui_pyramid_axis] + worldedit.show_page(name, "worldedit_gui_pyramid") + return true + end return false end) @@ -376,6 +386,11 @@ worldedit.register_gui_handler("worldedit_gui_copy_move", function(name, fields) end return true end + if fields.worldedit_gui_copy_move_axis then + gui_axis1[name] = axis_indices[fields.worldedit_gui_copy_move_axis] or 4 + worldedit.show_page(name, "worldedit_gui_copy_move") + return true + end return false end) @@ -398,6 +413,11 @@ worldedit.register_gui_handler("worldedit_gui_stack", function(name, fields) minetest.chatcommands["/stack"].func(name, string.format("%s %s", axis_values[gui_axis1[name]], gui_count1[name])) return true end + if fields.worldedit_gui_stack_axis then + gui_axis1[name] = axis_indices[fields.worldedit_gui_stack_axis] + worldedit.show_page(name, "worldedit_gui_stack") + return true + end return false end) @@ -444,13 +464,23 @@ worldedit.register_gui_handler("worldedit_gui_transpose", function(name, fields) minetest.chatcommands["/transpose"].func(name, string.format("%s %s", axis_values[gui_axis1[name]], axis_values[gui_axis2[name]])) return true end + if fields.worldedit_gui_transpose_axis1 then + gui_axis1[name] = axis_indices[fields.worldedit_gui_transpose_axis1] + worldedit.show_page(name, "worldedit_gui_transpose") + return true + end + if fields.worldedit_gui_transpose_axis2 then + gui_axis2[name] = axis_indices[fields.worldedit_gui_transpose_axis2] + worldedit.show_page(name, "worldedit_gui_transpose") + return true + end return false end) worldedit.register_gui_function("worldedit_gui_flip", { name = "Flip", privs = minetest.chatcommands["/flip"].privs, get_formspec = function(name) - local axis = gui_axis2[name] + local axis = gui_axis1[name] return "size[5,3]" .. worldedit.get_formspec_header("worldedit_gui_flip") .. string.format("dropdown[0,1;2.5;worldedit_gui_flip_axis;X axis,Y axis,Z axis,Look direction;%d]", axis) .. "button_exit[0,2.5;3,0.8;worldedit_gui_flip_submit;Flip]" @@ -459,9 +489,14 @@ worldedit.register_gui_function("worldedit_gui_flip", { worldedit.register_gui_handler("worldedit_gui_flip", function(name, fields) if fields.worldedit_gui_flip_submit then - gui_axis2[name] = axis_indices[fields.worldedit_gui_flip_axis] + gui_axis1[name] = axis_indices[fields.worldedit_gui_flip_axis] + worldedit.show_page(name, "worldedit_gui_flip") + minetest.chatcommands["/flip"].func(name, axis_values[gui_axis1[name]]) + return true + end + if fields.worldedit_gui_flip_axis then + gui_axis1[name] = axis_indices[fields.worldedit_gui_flip_axis] worldedit.show_page(name, "worldedit_gui_flip") - minetest.chatcommands["/flip"].func(name, axis_values[gui_axis2[name]]) return true end return false @@ -486,6 +521,16 @@ worldedit.register_gui_handler("worldedit_gui_rotate", function(name, fields) minetest.chatcommands["/rotate"].func(name, string.format("%s %s", axis_values[gui_axis1[name]], angle_values[gui_angle[name]])) return true end + if fields.worldedit_gui_rotate_axis then + gui_axis1[name] = axis_indices[fields.worldedit_gui_rotate_axis] + worldedit.show_page(name, "worldedit_gui_rotate") + return true + end + if fields.worldedit_gui_rotate_angle then + gui_angle[name] = angle_indices[fields.worldedit_gui_rotate_angle] + worldedit.show_page(name, "worldedit_gui_rotate") + return true + end return false end) @@ -510,6 +555,21 @@ worldedit.register_gui_handler("worldedit_gui_orient", function(name, fields) minetest.chatcommands["/orient"].func(name, string.format("%s %s %s", operation_values[gui_operation[name]], axis_values[gui_axis1[name]], angle_values[gui_angle[name]])) return true end + if fields.worldedit_gui_orient_operation then + gui_operation[name] = axis_indices[fields.worldedit_gui_orient_operation] + worldedit.show_page(name, "worldedit_gui_orient") + return true + end + if fields.worldedit_gui_orient_axis then + gui_axis1[name] = axis_indices[fields.worldedit_gui_orient_axis] + worldedit.show_page(name, "worldedit_gui_orient") + return true + end + if fields.worldedit_gui_orient_angle then + gui_angle[name] = angle_indices[fields.worldedit_gui_orient_angle] + worldedit.show_page(name, "worldedit_gui_orient") + return true + end return false end) @@ -598,9 +658,9 @@ worldedit.register_gui_function("worldedit_gui_save_load", { end, }) -worldedit.register_gui_handler("worldedit_gui_save", function(name, fields) - if fields.worldedit_gui_save_load_submit_save or worldedit_gui_save_load_submit_allocate or worldedit_gui_save_load_submit_load then - gui_filename[name] = tostring(fields.worldedit_gui_save_axis) +worldedit.register_gui_handler("worldedit_gui_save_load", function(name, fields) + if fields.worldedit_gui_save_load_submit_save or fields.worldedit_gui_save_load_submit_allocate or fields.worldedit_gui_save_load_submit_load then + gui_filename[name] = tostring(fields.worldedit_gui_save_filename) worldedit.show_page(name, "worldedit_gui_save_load") if fields.worldedit_gui_save_load_submit_save then minetest.chatcommands["/save"].func(name, gui_filename[name]) diff --git a/worldedit_gui/init.lua b/worldedit_gui/init.lua index afd8c2c..c0a1d8f 100644 --- a/worldedit_gui/init.lua +++ b/worldedit_gui/init.lua @@ -67,7 +67,7 @@ local get_formspec = function(name, identifier) end --implement worldedit.show_page(name, page) in different ways depending on the available APIs -if unified_inventory then --unified inventory installed +if rawget(_G, "unified_inventory") then --unified inventory installed local old_func = worldedit.register_gui_function worldedit.register_gui_function = function(identifier, options) old_func(identifier, options) @@ -100,7 +100,7 @@ if unified_inventory then --unified inventory installed player:set_inventory_formspec(get_formspec(name, page)) end end -elseif inventory_plus then --inventory++ installed +elseif rawget(_G, "inventory_plus") then --inventory++ installed minetest.register_on_joinplayer(function(player) local can_worldedit = minetest.check_player_privs(player:get_player_name(), {worldedit=true}) if can_worldedit then @@ -143,8 +143,19 @@ else --fallback button if not player then --this is in case the player signs off while the media is loading return end - if (minetest.check_player_privs(name, {creative=true}) or minetest.setting_getbool("creative_mode")) and creative_inventory then --creative_inventory is active, add button to modified formspec - formspec = player:get_inventory_formspec() .. "image_button[6,0;1,1;inventory_plus_worldedit_gui.png;worldedit_gui;]" + if (minetest.check_player_privs(name, {creative=true}) or + minetest.setting_getbool("creative_mode")) and + creative_inventory then --creative_inventory is active, add button to modified formspec + local creative_formspec = player:get_inventory_formspec() + local tab_id = tonumber(creative_formspec:match("tabheader%[.*;(%d)%;.*%]")) + + if tab_id == 1 then + formspec = creative_formspec .. + "image_button[0,1;1,1;inventory_plus_worldedit_gui.png;worldedit_gui;]" + elseif not tab_id then + formspec = creative_formspec .. + "image_button[6,0;1,1;inventory_plus_worldedit_gui.png;worldedit_gui;]" + end else formspec = formspec .. "image_button[0,0;1,1;inventory_plus_worldedit_gui.png;worldedit_gui;]" end