1
0
mirror of https://github.com/Uberi/Minetest-WorldEdit.git synced 2025-07-15 06:10:27 +02:00

13 Commits

13 changed files with 282 additions and 27 deletions

View File

@ -121,14 +121,16 @@ Set the current WorldEdit region to `<node>`.
Set the param2 value of all nodes in the current WorldEdit region to `<param2>`.
### `//mix <node1> ...`
### `//mix <node1> [<count1>] <node2> [<count2>]...`
Fill the current WorldEdit region with a random mix of `<node1>`, `...`.
Fill the current WorldEdit region with a random mix of `<node1>`, `<node2>`, `...`. Weightings can be optionally specified via a number after a node name.
//mix air
//mix cactus stone glass sandstone
//mix Bronze
//mix default:cobble air
//mix stone 3 dirt 2
//mix cobblestone 8 stoneblock 2 stonebrick
### `//replace <search node> <replace node>`
@ -283,13 +285,13 @@ Stack the current WorldEdit region `<count>` times by offset `<x>`, `<y>`, `<z>`
//stack2 5 3 8 2
//stack2 1 -1 -1 -1
### `//scale <factor>`
### `//stretch <stretchx> <stretchy> <stretchz>`
Scale the current WorldEdit positions and region by a factor of positive integer `<factor>` with position 1 as the origin.
Scale the current WorldEdit positions and region by a factor of `<stretchx>`, `<stretchy>`, `<stretchz>` along the X, Y, and Z axes, repectively, with position 1 as the origin.
//scale 2
//scale 1
//scale 10
//stretch 2 2 2
//stretch 1 2 1
//stretch 10 20 1
### `//transpose x/y/z/? x/y/z/?`
@ -463,3 +465,14 @@ Contracts the selection in all directions by `<amount>`. If specified, the selec
or vertically in the y axis `[v]`.
//outset v 5
### `//brush none/<command> [parameters]`
Assigns the given `<command>` to the currently held brush item, it will be ran with the first pointed solid node (as determined via raycast) as
WorldEdit position 1 when using that specific brush item.
Passing `none` instead clears the command assigned to the currently held brush item.
Note that this functionality requires the `worldedit_brush` mod enabled.
//brush cube 8 8 8 Cobblestone
//brush spr 12 glass
//brush none

View File

@ -193,7 +193,7 @@ Returns the number of nodes restored.
Serialization
-------------
Contained in serialization.lua, this module allows regions of nodes to be serialized and deserialized to formats suitable for use outside MineTest.
Contained in serialization.lua, this module allows regions of nodes to be serialized and deserialized to formats suitable for use outside Minetest.
### version, extra_fields, content = worldedit.read_header(value)

View File

@ -42,7 +42,7 @@ load_module(path .. "/compatibility.lua")
load_module(path .. "/cuboid.lua")
if minetest.setting_getbool("log_mods") then
if minetest.settings:get_bool("log_mods") then
print("[WorldEdit] Loaded!")
end

View File

@ -301,7 +301,7 @@ function worldedit.stack(pos1, pos2, axis, count)
local amount = 0
local copy = worldedit.copy
local i = 1
function next_one()
local function next_one()
if i <= count then
i = i + 1
amount = amount + length

View File

@ -208,12 +208,13 @@ function worldedit.pyramid(pos, axis, height, node_name, hollow)
local other1, other2 = worldedit.get_axis_others(axis)
-- Set up voxel manipulator
local manip, area = mh.init_axis_radius(pos, axis,
height >= 0 and height or -height)
-- FIXME: passing negative <radius> causes mis-sorted pos to be passed
-- into mh.init() which is technically not allowed but works
local manip, area = mh.init_axis_radius(pos, axis, height)
local data = mh.get_empty_data(area)
-- Handle inverted pyramids
local start_axis, end_axis, step
local step
if height > 0 then
height = height - 1
step = 1

View File

@ -0,0 +1,2 @@
worldedit
worldedit_commands

161
worldedit_brush/init.lua Normal file
View File

@ -0,0 +1,161 @@
local modname = minetest.get_current_modname()
-- check compatibility
if minetest.raycast == nil then
function log_unavailable_error()
minetest.log("error",
"[MOD] " .. modname .. " is not compatible with current game version, " ..
"you can disable it in the game settings!"
)
minetest.log("verbose",
"[MOD] " .. modname .. " requires a suitable version of 0.4.16-dev or higher, " ..
"that includes support for minetest.raycast() [since 7th July 2017]"
)
end
if minetest.is_singleplayer() then
-- delay message until player is connected
minetest.register_on_joinplayer(log_unavailable_error)
else
log_unavailable_error()
end
-- exit here / do not load this mod
return
end
local BRUSH_MAX_DIST = 150
local BRUSH_ALLOWED_COMMANDS = {
-- basically everything that only needs pos1
"cube",
"cylinder",
"dome",
"hollowcube",
"hollowcylinder",
"hollowdome",
"hollowpyramid",
"hollowsphere",
"load",
"pyramid",
"sphere",
"spiral",
"cyl",
"do",
"hcube",
"hcyl",
"hdo",
"hpyr",
"hspr",
"l",
"pyr",
"spr",
"spl",
}
local brush_on_use = function(itemstack, placer)
local meta = itemstack:get_meta()
local name = placer:get_player_name()
local cmd = meta:get_string("command")
if cmd == "" then
worldedit.player_notify(name,
"This brush is not bound, use //brush to bind a command to it.")
return false
end
local cmddef = minetest.registered_chatcommands["/" .. cmd]
if cmddef == nil then return false end -- shouldn't happen as //brush checks this
local has_privs, missing_privs = minetest.check_player_privs(name, cmddef.privs)
if not has_privs then
worldedit.player_notify(name,
"Missing privileges: " .. table.concat(missing_privs, ", "))
return false
end
local raybegin = vector.add(placer:get_pos(), {x=0, y=2, z=0}) -- player head
local rayend = vector.add(raybegin, vector.multiply(placer:get_look_dir(), BRUSH_MAX_DIST))
local ray = minetest.raycast(raybegin, rayend, false, true)
local pointed_thing = ray:next()
if pointed_thing == nil then
worldedit.player_notify(name, "Too far away.")
return false
end
assert(pointed_thing.type == "node")
worldedit.pos1[name] = pointed_thing.under
worldedit.pos2[name] = nil
worldedit.mark_region(name)
-- is this a horrible hack? oh yes.
worldedit._override_safe_regions = true
local player_notify_old = worldedit.player_notify
worldedit.player_notify = function(name, msg)
if string.match(msg, "^%d") then return end -- discard "1234 nodes added."
return player_notify_old(name, msg)
end
minetest.log("action", string.format("%s uses WorldEdit brush (//%s) at %s",
name, cmd, minetest.pos_to_string(pointed_thing.under)))
cmddef.func(name, meta:get_string("params"))
worldedit._override_safe_regions = false
worldedit.player_notify = player_notify_old
return true
end
minetest.register_tool(":worldedit:brush", {
description = "WorldEdit Brush",
inventory_image = "worldedit_brush.png",
stack_max = 1, -- no need to stack these (metadata prevents this anyway)
range = 0,
on_use = function(itemstack, placer, pointed_thing)
brush_on_use(itemstack, placer)
return itemstack -- nothing consumed, nothing changed
end,
})
minetest.register_chatcommand("/brush", {
privs = {worldedit=true},
params = "none/<cmd> [parameters]",
description = "Assign command to WorldEdit brush item",
func = function(name, param)
local found, _, cmd, params = param:find("^([^%s]+)%s+(.+)$")
if not found then
params = ""
found, _, cmd = param:find("^(.+)$")
end
if not found then
worldedit.player_notify(name, "Invalid usage.")
return
end
local itemstack = minetest.get_player_by_name(name):get_wielded_item()
if itemstack == nil or itemstack:get_name() ~= "worldedit:brush" then
worldedit.player_notify(name, "Not holding brush item.")
return
end
cmd = cmd:lower()
local meta = itemstack:get_meta()
if cmd == "none" then
meta:from_table(nil)
worldedit.player_notify(name, "Brush assignment cleared.")
else
local cmddef
if table.indexof(BRUSH_ALLOWED_COMMANDS, cmd) ~= -1 then
cmddef = minetest.registered_chatcommands["/" .. cmd]
else
cmddef = nil
end
if cmddef == nil then
worldedit.player_notify(name, "Invalid command for brush use: //" .. cmd)
return
end
meta:set_string("command", cmd)
meta:set_string("params", params)
local fullcmd = "//" .. cmd .. " " .. params
meta:set_string("description",
minetest.registered_tools["worldedit:brush"].description .. ": " .. fullcmd)
worldedit.player_notify(name, "Brush assigned to command: " .. fullcmd)
end
minetest.get_player_by_name(name):set_wielded_item(itemstack)
end,
})

Binary file not shown.

After

Width:  |  Height:  |  Size: 337 B

View File

@ -108,9 +108,9 @@ end
minetest.register_chatcommand("/about", {
params = "",
description = "Get information about the mod",
description = "Get information about the WorldEdit mod",
func = function(name, param)
worldedit.player_notify(name, "WorldEdit " .. worldedit.version_string .. " is available on this server. Type /help to get a list of commands, or get more information at https://github.com/Uberi/MineTest-WorldEdit/")
worldedit.player_notify(name, "WorldEdit " .. worldedit.version_string .. " is available on this server. Type /help to get a list of commands, or get more information at https://github.com/Uberi/Minetest-WorldEdit/")
end,
})
@ -203,7 +203,7 @@ minetest.register_on_punchnode(function(pos, node, puncher)
local name = puncher:get_player_name()
if worldedit.inspect[name] then
local axis, sign = worldedit.player_axis(name)
message = string.format("inspector: %s at %s (param1=%d, param2=%d, received light=%d) punched facing the %s axis",
local message = string.format("inspector: %s at %s (param1=%d, param2=%d, received light=%d) punched facing the %s axis",
node.name, minetest.pos_to_string(pos), node.param1, node.param2, get_node_rlight(pos), axis .. (sign > 0 and "+" or "-"))
worldedit.player_notify(name, message)
end
@ -425,15 +425,22 @@ minetest.register_chatcommand("/param2", {
})
minetest.register_chatcommand("/mix", {
params = "<node1> ...",
params = "<node1> [<weighting1>] [<node2> [<weighting2>]] ...",
description = "Fill the current WorldEdit region with a random mix of <node1>, ...",
privs = {worldedit=true},
func = safe_region(function(name, param)
local nodes = {}
for nodename in param:gmatch("[^%s]+") do
local node = get_node(name, nodename)
if not node then return end
nodes[#nodes + 1] = node
if tonumber(nodename) ~= nil and #nodes > 0 then
local last_node = nodes[#nodes]
for i = 1, tonumber(nodename) do
nodes[#nodes + 1] = last_node
end
else
local node = get_node(name, nodename)
if not node then return end
nodes[#nodes + 1] = node
end
end
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
@ -642,6 +649,7 @@ minetest.register_chatcommand("/hollowcylinder", {
end
length = tonumber(length)
if axis == "?" then
local sign
axis, sign = worldedit.player_axis(name)
length = length * sign
end
@ -665,6 +673,7 @@ minetest.register_chatcommand("/cylinder", {
end
length = tonumber(length)
if axis == "?" then
local sign
axis, sign = worldedit.player_axis(name)
length = length * sign
end
@ -698,6 +707,7 @@ minetest.register_chatcommand("/hollowpyramid", {
local found, _, axis, height, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(.+)$")
height = tonumber(height)
if axis == "?" then
local sign
axis, sign = worldedit.player_axis(name)
height = height * sign
end
@ -715,6 +725,7 @@ minetest.register_chatcommand("/pyramid", {
local found, _, axis, height, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(.+)$")
height = tonumber(height)
if axis == "?" then
local sign
axis, sign = worldedit.player_axis(name)
height = height * sign
end
@ -762,6 +773,7 @@ minetest.register_chatcommand("/copy", {
end
amount = tonumber(amount)
if axis == "?" then
local sign
axis, sign = worldedit.player_axis(name)
amount = amount * sign
end
@ -788,6 +800,7 @@ minetest.register_chatcommand("/move", {
end
amount = tonumber(amount)
if axis == "?" then
local sign
axis, sign = worldedit.player_axis(name)
amount = amount * sign
end
@ -810,6 +823,7 @@ minetest.register_chatcommand("/stack", {
local found, _, axis, repetitions = param:find("^([xyz%?])%s+([+-]?%d+)$")
repetitions = tonumber(repetitions)
if axis == "?" then
local sign
axis, sign = worldedit.player_axis(name)
repetitions = repetitions * sign
end
@ -891,9 +905,12 @@ minetest.register_chatcommand("/stretch", {
stretchx, stretchy, stretchz = tonumber(stretchx), tonumber(stretchy), tonumber(stretchz)
if stretchx == 0 or stretchy == 0 or stretchz == 0 then
worldedit.player_notify(name, "invalid scaling factors: " .. param)
return nil
end
local count = check_region(name, param)
if count then return tonumber(stretchx) * tonumber(stretchy) * tonumber(stretchz) * count end
if count then
return stretchx * stretchy * stretchz * count
end
return nil
end),
})

View File

@ -1,6 +1,8 @@
local safe_region_callback = {}
local safe_region_param = {}
worldedit._override_safe_regions = false -- internal use ONLY!
local function check_region(name, param)
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] --obtain positions
if pos1 == nil or pos2 == nil then
@ -20,7 +22,7 @@ local function safe_region(callback, nodes_needed)
--check if the operation applies to a safe number of nodes
local count = nodes_needed(name, param)
if count == nil then return end --invalid command
if count < 10000 then
if worldedit._override_safe_regions or count < 10000 then
return callback(name, param)
end
@ -44,20 +46,21 @@ minetest.register_chatcommand("/y", {
return
end
safe_region_callback[name], safe_region_param[name] = nil, nil --reset pending operation
reset_pending(name)
callback(name, param)
end,
})
minetest.register_chatcommand("/n", {
params = "",
description = "Confirm a pending operation",
description = "Abort a pending operation",
func = function(name)
if not safe_region_callback[name] then
worldedit.player_notify(name, "no operation pending")
return
end
safe_region_callback[name], safe_region_param[name] = nil, nil
reset_pending(name)
end,
})

View File

@ -1,3 +1,11 @@
local function above_or_under(placer, pointed_thing)
if placer:get_player_control().sneak then
return pointed_thing.above
else
return pointed_thing.under
end
end
minetest.register_tool(":worldedit:wand", {
description = "WorldEdit Wand tool, Left-click to set 1st position, right-click to set 2nd",
inventory_image = "worldedit_wand.png",
@ -7,7 +15,7 @@ minetest.register_tool(":worldedit:wand", {
on_use = function(itemstack, placer, pointed_thing)
if placer ~= nil and pointed_thing ~= nil and pointed_thing.type == "node" then
local name = placer:get_player_name()
worldedit.pos1[name] = pointed_thing.under
worldedit.pos1[name] = above_or_under(placer, pointed_thing)
worldedit.mark_pos1(name)
end
return itemstack -- nothing consumed, nothing changed
@ -16,7 +24,7 @@ minetest.register_tool(":worldedit:wand", {
on_place = function(itemstack, placer, pointed_thing) -- Left Click
if placer ~= nil and pointed_thing ~= nil and pointed_thing.type == "node" then
local name = placer:get_player_name()
worldedit.pos2[name] = pointed_thing.under
worldedit.pos2[name] = above_or_under(placer, pointed_thing)
worldedit.mark_pos2(name)
end
return itemstack -- nothing consumed, nothing changed

View File

@ -4,3 +4,4 @@ unified_inventory?
inventory_plus?
sfinv?
creative?
smart_inventory?

View File

@ -134,6 +134,55 @@ elseif rawget(_G, "inventory_plus") then --inventory++ installed
inventory_plus.set_inventory_formspec(player, get_formspec(name, page))
end
end
elseif rawget(_G, "smart_inventory") then -- smart_inventory installed
-- redefinition: Update the code element on inventory page to show the we-page
function worldedit.show_page(name, page)
local state = smart_inventory.get_page_state("worldedit_gui", name)
if state then
state:get("code"):set_we_formspec(page)
state.location.rootState:show() -- update inventory page
end
end
-- smart_inventory page callback. Contains just a "custom code" element
local function smart_worldedit_gui_callback(state)
local codebox = state:element("code", { name = "code", code = "" })
function codebox:set_we_formspec(we_page)
local new_formspec = get_formspec(state.location.rootState.location.player, we_page)
new_formspec = new_formspec:gsub('button_exit','button') --no inventory closing
self.data.code = "container[1,1]".. new_formspec .. "container_end[]"
end
codebox:set_we_formspec("worldedit_gui")
-- process input (the back button)
state:onInput(function(state, fields, player)
if fields.worldedit_gui then --main page
state:get("code"):set_we_formspec("worldedit_gui")
elseif fields.worldedit_gui_exit then --return to original page
state:get("code"):set_we_formspec("worldedit_gui")
state.location.parentState:get("crafting_button"):submit() -- switch to the crafting tab
end
end)
end
-- all handler should return false to force inventory UI update
local orig_register_gui_handler = worldedit.register_gui_handler
worldedit.register_gui_handler = function(identifier, handler)
local wrapper = function(...)
handler(...)
return false
end
orig_register_gui_handler(identifier, wrapper)
end
-- register the inventory button
smart_inventory.register_page({
name = "worldedit_gui",
tooltip = "Edit your World!",
icon = "inventory_plus_worldedit_gui.png",
smartfs_callback = smart_worldedit_gui_callback,
sequence = 99
})
elseif rawget(_G, "sfinv") then --sfinv installed (part of minetest_game since 0.4.15)
assert(sfinv.enabled)
local orig_get = sfinv.pages["sfinv:crafting"].get